Skip to content

Commit

Permalink
Merge branch 'preview'
Browse files Browse the repository at this point in the history
  • Loading branch information
pdelfan committed Oct 30, 2024
2 parents 078a509 + 31d89cb commit 624548b
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 36 deletions.
14 changes: 14 additions & 0 deletions src/app/dashboard/topics/[topic]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Metadata } from "next";

export const metadata: Metadata = {
title: "Topic",
description: "Topic",
};

export default async function TopicsLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}
20 changes: 20 additions & 0 deletions src/app/dashboard/topics/[topic]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import TopicHeader from "@/components/contentDisplay/topicHeader/TopicHeader";
import TopicContainer from "@/containers/posts/TopicContainer";

interface Props {
params: {
topic: string;
};
}

export default function Page(props: Props) {
const { params } = props;
const url = decodeURIComponent(params.topic);

return (
<>
<TopicHeader url={url} />
<TopicContainer url={url} />
</>
);
}
15 changes: 15 additions & 0 deletions src/app/dashboard/topics/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Layout from "@/containers/Layout";
import type { Metadata } from "next";

export const metadata: Metadata = {
title: "Topics",
description: "Topics",
};

export default async function TopicsLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}
2 changes: 1 addition & 1 deletion src/components/contentDisplay/feedHeader/FeedHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default function FeedHeader(props: Props) {
{isFetchingFeedInfo && <FeedHeaderSkeleton />}
{!isFetchingFeedInfo && feedInfo && (
<>
<article className="border-skin-base flex flex-col gap-2 border border-x-0 border-t-0 p-3 md:rounded-t-2xl md:border ">
<article className="border-skin-base flex flex-col gap-2 border border-x-0 border-t-0 p-3 md:rounded-t-2xl md:border">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="flex flex-wrap items-center gap-3">
<Image
Expand Down
62 changes: 62 additions & 0 deletions src/components/contentDisplay/topicHeader/TopicHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use client";

import useGetLinkMeta from "@/lib/hooks/useGetLinkMeta";
import Image from "next/image";
import { SiGooglemessages } from "react-icons/si";
import TopicHeaderSkeleton from "./TopicHeaderSkeleton";
import FeedAlert from "@/components/feedback/feedAlert/FeedAlert";
import { useState } from "react";

interface Props {
url: string;
}

export default function TopicHeader(props: Props) {
const { url } = props;
const { status, data, error, isLoading, isFetching } = useGetLinkMeta(url);
const [hideImage, setHideImage] = useState(false);

if (isLoading && !data) return <TopicHeaderSkeleton />;

return (
<article className="border-skin-base flex flex-col gap-2 border border-x-0 border-t-0 p-3 md:border md:rounded-t-2xl">
{error && (
<FeedAlert
variant="badResponse"
message="Something went wrong"
standalone
/>
)}

{data?.image && !hideImage && (
<Image
src={data.image}
alt={`Image from ${url}`}
width={900}
height={500}
className="rounded-lg"
onError={() => setHideImage(true)}
/>
)}

{data && (
<>
<div className="flex flex-wrap items-center gap-2 text-skin-secondary mt-2">
<SiGooglemessages className="text-2xl" />
<span className="font-medium text-lg">Topic</span>
</div>
<div className="flex flex-col gap-1 mt-1">
{data?.title && (
<h3 className="text-skin-base break-words text-xl font-medium">
{data.title}
</h3>
)}
{data?.description && (
<p className="text-skin-secondary">{data.description}</p>
)}
</div>
</>
)}
</article>
);
}
18 changes: 18 additions & 0 deletions src/components/contentDisplay/topicHeader/TopicHeaderSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function TopicHeaderSkeleton() {
return (
<article className="border-skin-base flex flex-col gap-2 border border-x-0 border-y-0 p-3 md:rounded-t-2xl md:border-x md:border-t">
<div className="bg-skin-muted h-80 w-full animate-pulse rounded-lg" />

<div className="flex flex-wrap items-center gap-2 mt-2">
<div className="bg-skin-muted h-8 w-8 animate-pulse rounded-full" />
<div className="bg-skin-muted h-5 w-16 animate-pulse rounded" />
</div>

<div className="flex flex-col gap-1 mt-1">
<div className="bg-skin-muted h-6 w-3/4 animate-pulse rounded" />
<div className="bg-skin-muted h-3 w-1/2 animate-pulse rounded mt-2" />
<div className="bg-skin-muted h-3 w-1/3 animate-pulse rounded" />
</div>
</article>
);
}
77 changes: 48 additions & 29 deletions src/components/dataDisplay/postEmbed/ExternalEmbed.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { getHostname } from "@/lib/utils/text";
import { AppBskyEmbedExternal } from "@atproto/api";
import { SiGooglemessages } from "react-icons/si";
import Image from "next/image";
import Link from "next/link";
import { BiRightArrowAlt } from "react-icons/bi";

interface Props {
embed: AppBskyEmbedExternal.View;
Expand All @@ -13,36 +15,53 @@ export default function ExternalEmbed(props: Props) {
return (
<>
{depth < 2 && (
<article className="bg-skin-base border-skin-base mt-2 rounded-lg border hover:brightness-95">
<Link
href={embed.external.uri}
target="blank"
onClick={(e) => e.stopPropagation()}
>
{embed.external.thumb && (
<Image
src={embed.external.thumb}
alt={embed.external.description}
width={900}
height={500}
priority
className="border-b-skin-base rounded-t-lg border-b aspect-auto max-h-96 object-cover"
/>
)}
<div className="flex flex-col p-3">
<span className="text-skin-tertiary break-all text-sm">
{getHostname(embed.external.uri)}
</span>
<span className="text-skin-base font-medium [overflow-wrap:anywhere]">
{embed.external.title}
</span>
{embed.external.description && (
<span className="text-skin-secondary text-sm line-clamp-2">
{embed.external.description}
</span>
<article className="border border-skin-base mt-2 rounded-lg group">
<div className="bg-skin-base hover:bg-skin-secondary">
<Link
href={embed.external.uri}
target="blank"
onClick={(e) => e.stopPropagation()}
>
{embed.external.thumb && (
<Image
src={embed.external.thumb}
alt={embed.external.description}
width={900}
height={500}
priority
className="border-b-skin-base rounded-t-lg border-b aspect-auto max-h-96 object-cover group-hover:brightness-95"
/>
)}
</div>
</Link>
<div className="flex flex-col p-3">
<span className="text-skin-tertiary break-all text-sm">
{getHostname(embed.external.uri)}
</span>
<span className="text-skin-base font-medium [overflow-wrap:anywhere]">
{embed.external.title}
</span>
{embed.external.description && (
<span className="text-skin-secondary text-sm line-clamp-2">
{embed.external.description}
</span>
)}
</div>
</Link>
</div>
<div className="bg-skin-base border-t border-skin-base rounded-b-lg hover:bg-skin-secondary">
<Link
href={`/dashboard/topics/${encodeURIComponent(
embed.external.uri
)}`}
onClick={(e) => e.stopPropagation()}
className="flex flex-wrap items-center gap-2 text-skin-tertiary px-3 py-2 hover:text-skin-secondary"
>
<SiGooglemessages className="text-lg" />
<div className="flex flex-wrap items-center">
<span className="font-medium text-sm">View topic</span>
<BiRightArrowAlt className="text-lg" />
</div>
</Link>
</div>
</article>
)}
</>
Expand Down
2 changes: 1 addition & 1 deletion src/components/dataDisplay/postEmbed/FeedEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function FeedEmbed(props: Props) {
onClick={(e) => {
e.stopPropagation();
}}
className="border-skin-base bg-skin-base mt-2 flex flex-col gap-2 rounded-2xl border p-3 hover:brightness-95"
className="border-skin-base bg-skin-base mt-2 flex flex-col gap-2 rounded-2xl border p-3 hover:bg-skin-secondary"
>
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="flex flex-wrap items-center gap-3">
Expand Down
2 changes: 1 addition & 1 deletion src/components/dataDisplay/postEmbed/ListEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function ListEmbed(props: Props) {
onClick={(e) => {
e.stopPropagation();
}}
className="border-skin-base bg-skin-base mt-2 block cursor-pointer rounded-xl border p-3 hover:brightness-95"
className="border-skin-base bg-skin-base mt-2 block cursor-pointer rounded-xl border p-3 hover:bg-skin-secondary"
>
<div className="flex items-start gap-2">
<div className="bg-primary rounded-lg p-2.5">{selectedIcon}</div>
Expand Down
45 changes: 45 additions & 0 deletions src/containers/posts/TopicContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use client";

import { useState } from "react";
import TabItem from "@/components/navigational/tabs/TabItem";
import Tabs from "@/components/navigational/tabs/Tabs";
import PostSearchContainer from "../search/PostSearchContainer";

interface Props {
url: string;
}

export default function TopicContainer(props: Props) {
const { url } = props;
const [currentTab, setCurrentTab] = useState<"top" | "latest">("top");

const handleTabChange = (tab: "top" | "latest") => {
setCurrentTab(tab);
};

return (
<section>
<Tabs className="md:border-x border-skin-base">
<TabItem
asButton
onClick={() => handleTabChange("top")}
label="Top"
isActive={currentTab === "top"}
/>
<TabItem
asButton
onClick={() => handleTabChange("latest")}
label="Latest"
isActive={currentTab === "latest"}
/>
</Tabs>

{currentTab === "latest" && (
<PostSearchContainer query={url} sort={currentTab} />
)}
{currentTab === "top" && (
<PostSearchContainer query={url} sort={currentTab} />
)}
</section>
);
}
7 changes: 3 additions & 4 deletions src/containers/search/PostSearchContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import { searchPosts } from "@/lib/api/bsky/actor";
import useAgent from "@/lib/hooks/bsky/useAgent";
import { useInfiniteQuery } from "@tanstack/react-query";
Expand Down Expand Up @@ -64,10 +66,7 @@ export default function PostSearchContainer(props: Props) {
{isFetching && !isFetchingNextPage && <FeedPostSkeleton />}
{isEmpty && !hasNextPage && (
<div className="border-skin-base border-t">
<FeedAlert
variant="empty"
message={`No posts found for ${query}`}
/>
<FeedAlert variant="empty" message={`No posts found`} />
</div>
)}
{error && (
Expand Down

0 comments on commit 624548b

Please sign in to comment.