diff --git a/thoughts-frontend/app/layout.tsx b/thoughts-frontend/app/layout.tsx index bb40665..8e9b0ed 100644 --- a/thoughts-frontend/app/layout.tsx +++ b/thoughts-frontend/app/layout.tsx @@ -16,8 +16,8 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Thoughts", + description: "A social network for sharing thoughts", }; export default function RootLayout({ diff --git a/thoughts-frontend/app/page.tsx b/thoughts-frontend/app/page.tsx index c5c1a33..219a1fd 100644 --- a/thoughts-frontend/app/page.tsx +++ b/thoughts-frontend/app/page.tsx @@ -1,15 +1,13 @@ -// app/page.tsx import { cookies } from "next/headers"; -import { getFeed, getMe, getUserProfile, Me, Thought } from "@/lib/api"; -import { ThoughtCard } from "@/components/thought-card"; +import { getFeed, getMe, getUserProfile, Me, User } from "@/lib/api"; import { PostThoughtForm } from "@/components/post-thought-form"; import { Button } from "@/components/ui/button"; import Link from "next/link"; import { PopularTags } from "@/components/popular-tags"; import { ThoughtThread } from "@/components/thought-thread"; import { buildThoughtThreads } from "@/lib/utils"; +import { TopFriends } from "@/components/top-friends"; -// This is now an async Server Component export default async function Home() { const token = (await cookies()).get("auth_token")?.value ?? null; @@ -21,50 +19,66 @@ export default async function Home() { } async function FeedPage({ token }: { token: string }) { - const feedData = await getFeed(token); - const me = (await getMe(token).catch(() => null)) as Me | null; + const [feedData, me] = await Promise.all([ + getFeed(token), + getMe(token).catch(() => null) as Promise, + ]); + const authors = [...new Set(feedData.thoughts.map((t) => t.authorUsername))]; const userProfiles = await Promise.all( authors.map((username) => getUserProfile(username, token).catch(() => null)) ); - const authorDetails = new Map( + const authorDetails = new Map( userProfiles - .filter(Boolean) - .map((user) => [user!.username, { avatarUrl: user!.avatarUrl }]) + .filter((u): u is User => !!u) + .map((user) => [user.username, { avatarUrl: user.avatarUrl }]) ); - const allThoughts = feedData.thoughts; - const { topLevelThoughts, repliesByParentId } = - buildThoughtThreads(allThoughts); + const { topLevelThoughts, repliesByParentId } = buildThoughtThreads( + feedData.thoughts + ); return ( -
-
-
-

Your Feed

-
- -
- {topLevelThoughts.map((thought) => ( - - ))} - {topLevelThoughts.length === 0 && ( -

- Your feed is empty. Follow some users to see their thoughts here! -

- )} +
+
+ + +
+
+

Your Feed

+
+ +
+ {topLevelThoughts.map((thought) => ( + + ))} + {topLevelThoughts.length === 0 && ( +

+ Your feed is empty. Follow some users to see their thoughts! +

+ )} +
-
- + + +
); } diff --git a/thoughts-frontend/app/users/[username]/page.tsx b/thoughts-frontend/app/users/[username]/page.tsx index d1d4769..69a1f2b 100644 --- a/thoughts-frontend/app/users/[username]/page.tsx +++ b/thoughts-frontend/app/users/[username]/page.tsx @@ -62,69 +62,75 @@ export default async function ProfilePage({ params }: ProfilePageProps) { }} /> -
- -
- -
-
-
- +
+ {/* Left Sidebar (Profile Card & Top Friends) */} + + + {/* Main Content (Thoughts Feed) */} +
+ {topLevelThoughts.map((thought) => ( + + ))} + {topLevelThoughts.length === 0 && ( + +

+ This user hasn't posted any public thoughts yet. +

+
+ )}
diff --git a/thoughts-frontend/components/header.tsx b/thoughts-frontend/components/header.tsx index d595099..805b18d 100644 --- a/thoughts-frontend/components/header.tsx +++ b/thoughts-frontend/components/header.tsx @@ -1,37 +1,39 @@ -// components/header.tsx "use client"; import { useAuth } from "@/hooks/use-auth"; import Link from "next/link"; import { Button } from "./ui/button"; import { UserNav } from "./user-nav"; +import { MainNav } from "./main-nav"; +import { ThemeToggle } from "./theme-toggle"; +import { Wind } from "lucide-react"; export function Header() { const { token } = useAuth(); return (
-
-
- - Thoughts +
+
+ + Thoughts +
-
- +
+ + {token ? ( + + ) : ( + <> + + + + )}
diff --git a/thoughts-frontend/components/main-nav.tsx b/thoughts-frontend/components/main-nav.tsx new file mode 100644 index 0000000..a29058f --- /dev/null +++ b/thoughts-frontend/components/main-nav.tsx @@ -0,0 +1,22 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { cn } from "@/lib/utils"; + +export function MainNav() { + const pathname = usePathname(); + return ( + + ); +} diff --git a/thoughts-frontend/components/theme-provider.tsx b/thoughts-frontend/components/theme-provider.tsx new file mode 100644 index 0000000..e97c458 --- /dev/null +++ b/thoughts-frontend/components/theme-provider.tsx @@ -0,0 +1,11 @@ +"use client"; + +import * as React from "react"; +import { + ThemeProvider as NextThemesProvider, + ThemeProviderProps, +} from "next-themes"; + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return {children}; +} diff --git a/thoughts-frontend/components/theme-toggle.tsx b/thoughts-frontend/components/theme-toggle.tsx new file mode 100644 index 0000000..8f39542 --- /dev/null +++ b/thoughts-frontend/components/theme-toggle.tsx @@ -0,0 +1,40 @@ +"use client"; + +import * as React from "react"; +import { Moon, Sun } from "lucide-react"; +import { useTheme } from "next-themes"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +export function ThemeToggle() { + const { setTheme } = useTheme(); + + return ( + + + + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ); +}