Revert "Revert "Fix: hydration errors (#45)""

This reverts commit a737463115.
This commit is contained in:
mr0x50
2025-02-15 21:07:31 +01:00
parent 212aa669fa
commit f7187ce2b2
7 changed files with 84 additions and 56 deletions

View File

@@ -3,38 +3,42 @@
import { BellIcon, GlobeIcon, HomeIcon, RowsIcon, UploadIcon } from "@radix-ui/react-icons"
import Link from "next/link"
import { FormEvent, JSX, SVGProps, useEffect, useState } from "react"
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"
import { useRouter, usePathname } from 'next/navigation'
import { SearchIcon, Upload } from "lucide-react";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
import { Button } from "./ui/button";
import { Textarea } from "./ui/textarea";
import { useNostr } from "nostr-react";
import { SearchIcon } from "lucide-react";
export default function BottomBar() {
const router = useRouter();
const [pubkey, setPubkey] = useState<null | string>(null);
const [mounted, setMounted] = useState(false);
const pathname = usePathname();
useEffect(() => {
if (typeof window !== 'undefined') {
setPubkey(window.localStorage.getItem('pubkey') ?? null);
}
setMounted(true);
setPubkey(window.localStorage.getItem('pubkey'));
}, []);
if (typeof window === 'undefined') return null;
const isActive = (path: string, currentPath: string) => currentPath === path ? 'text-purple-500' : '';
// Render minimal navigation during SSR and hydration
if (!mounted) {
return (
<nav className="fixed inset-x-0 bottom-0 h-14 flex flex-row shrink-0 items-center justify-between border-t bg-background/90 shadow-up-4 z-50 backdrop-blur">
<Link className={`flex flex-col items-center justify-center w-full text-xs gap-1 px-4 ${isActive('/', pathname)}`} href="/">
<HomeIcon className={`h-6 w-6`} />
<span className="sr-only">Home</span>
</Link>
<Link className={`flex flex-col items-center justify-center w-full text-xs gap-1 px-4 ${isActive('/global', pathname)}`} href="/global">
<GlobeIcon className={`h-6 w-6`} />
<span className="sr-only">Global</span>
</Link>
<Link className={`flex flex-col items-center justify-center w-full text-xs gap-1 px-4 ${isActive('/search', pathname)}`} href="/search">
<SearchIcon className={`h-6 w-6`} />
<span className="sr-only">Search</span>
</Link>
</nav>
);
}
return (
<nav className="fixed inset-x-0 bottom-0 h-14 flex flex-row shrink-0 items-center justify-between border-t bg-background/90 shadow-up-4 z-50 backdrop-blur">
<Link className={`flex flex-col items-center justify-center w-full text-xs gap-1 px-4 ${isActive('/', pathname)}`} href="/">

View File

@@ -97,7 +97,6 @@ const ProfileInfoCard: React.FC<ProfileInfoCardProps> = React.memo(({ pubkey })
<div>
<NIP05 nip05={nip05?.toString() ?? ''} pubkey={pubkey} />
<div className='py-6 grid grid-cols-5 gap-4'>
{/* <Button className='w-full'>Follow</Button> */}
<div className='col-span-2'>
<FollowButton pubkey={pubkey} userPubkey={userPubkey}></FollowButton>
</div>
@@ -105,7 +104,7 @@ const ProfileInfoCard: React.FC<ProfileInfoCardProps> = React.memo(({ pubkey })
<Button className='w-full' variant="outline">View Statistics</Button>
</Link>
<Drawer>
<DrawerTrigger>
<DrawerTrigger asChild>
<Button className='w-full' variant="outline"><Share1Icon /></Button>
</DrawerTrigger>
<DrawerContent>
@@ -114,7 +113,6 @@ const ProfileInfoCard: React.FC<ProfileInfoCardProps> = React.memo(({ pubkey })
<DrawerDescription>Share this Profile with others.</DrawerDescription>
</DrawerHeader>
<div className="px-2">
{/* <h1>URL</h1> */}
<div className="flex items-center mb-4">
<Input value={host+"/profile/"+nip19.npubEncode(pubkey)} disabled className="mr-2" />
<Button variant="outline" onClick={handleCopyLink}>Copy Link</Button>
@@ -125,8 +123,10 @@ const ProfileInfoCard: React.FC<ProfileInfoCardProps> = React.memo(({ pubkey })
</div>
</div>
<DrawerFooter>
<DrawerClose>
<Button variant="outline">Close</Button>
<DrawerClose asChild>
<div>
<Button variant="outline">Close</Button>
</div>
</DrawerClose>
</DrawerFooter>
</DrawerContent>

View File

@@ -82,7 +82,7 @@ export default function ReactionButton({ event }: { event: any }) {
return (
<Drawer>
<DrawerTrigger>
<DrawerTrigger asChild>
<Button variant={liked ? "default" : "outline"}>
{isLoading ? (
<>
@@ -125,8 +125,10 @@ export default function ReactionButton({ event }: { event: any }) {
<hr className="my-4" />
<ReactionButtonReactionList filteredEvents={filteredEvents} />
<DrawerFooter>
<DrawerClose>
<Button variant={"secondary"}>Close</Button>
<DrawerClose asChild>
<div>
<Button variant={"secondary"}>Close</Button>
</div>
</DrawerClose>
</DrawerFooter>
</DrawerContent>

View File

@@ -60,7 +60,7 @@ export default function ViewCopyButton({ event }: ViewCopyButtonProps) {
return (
<Drawer>
<DrawerTrigger>
<DrawerTrigger asChild>
<Button variant="outline"><Share1Icon /></Button>
</DrawerTrigger>
<DrawerContent>
@@ -80,12 +80,13 @@ export default function ViewCopyButton({ event }: ViewCopyButtonProps) {
</div>
</div>
<DrawerFooter>
<DrawerClose>
<Button variant="outline">Close</Button>
<DrawerClose asChild>
<div>
<Button variant="outline">Close</Button>
</div>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
}

View File

@@ -20,7 +20,7 @@ interface ViewRawButtonProps {
export default function ViewRawButton({ event }: ViewRawButtonProps) {
return (
<Drawer>
<DrawerTrigger>
<DrawerTrigger asChild>
<Button variant="outline"><CodeIcon /></Button>
</DrawerTrigger>
<DrawerContent>
@@ -30,8 +30,10 @@ export default function ViewRawButton({ event }: ViewRawButtonProps) {
</DrawerHeader>
<Textarea rows={20} disabled>{JSON.stringify(event, null, 2)}</Textarea>
<DrawerFooter>
<DrawerClose>
<Button variant="outline">Close</Button>
<DrawerClose asChild>
<div>
<Button variant="outline">Close</Button>
</div>
</DrawerClose>
</DrawerFooter>
</DrawerContent>

View File

@@ -85,12 +85,10 @@ export default function ZapButton({ event }: { event: any }) {
return (
<Drawer>
<DrawerTrigger>
{/* <Button variant="default" onClick={onPost}>{events.length} Reactions</Button> */}
<DrawerTrigger asChild>
{isLoading ? (
<Button variant="outline"><ReloadIcon className="mr-2 h-4 w-4 animate-spin" /> </Button>
) : (
// <Button variant="outline">{events.length} ⚡️ ({sats} sats)</Button>
<Button variant="outline">{sats} sats </Button>
)}
</DrawerTrigger>
@@ -110,8 +108,10 @@ export default function ZapButton({ event }: { event: any }) {
<hr className="my-4" />
<ZapButtonList events={events} />
<DrawerFooter>
<DrawerClose>
<Button variant={"outline"}>Close</Button>
<DrawerClose asChild>
<div>
<Button variant={"outline"}>Close</Button>
</div>
</DrawerClose>
</DrawerFooter>
</DrawerContent>

View File

@@ -11,27 +11,46 @@ import RegisterButton from "./RegisterButton";
export function TopNavigation() {
const [pubkey, setPubkey] = useState<string | null>(null);
const [mounted, setMounted] = useState(false);
useEffect(() => {
if (typeof window !== 'undefined') {
setPubkey(window.localStorage.getItem('pubkey'));
}
setMounted(true);
setPubkey(window.localStorage.getItem('pubkey'));
}, []);
// Prevent hydration mismatch by not rendering auth-dependent content until mounted
if (!mounted) {
return (
<nav>
<header className="bg-background/80 sticky top-0 z-40 w-full border-b backdrop-blur">
<div className="container flex h-16 items-center space-x-4 sm:justify-between sm:space-x-0">
<TopNavigationItems items={siteConfig.mainNav} />
<div className="flex flex-1 items-center justify-end space-x-4">
<nav className="flex items-center space-x-2">
<DropdownThemeMode />
</nav>
</div>
</div>
</header>
</nav>
);
}
return (
<header className="bg-background/80 sticky top-0 z-40 w-full border-b backdrop-blur">
<div className="container flex h-16 items-center space-x-4 sm:justify-between sm:space-x-0">
<TopNavigationItems items={siteConfig.mainNav} />
<div className="flex flex-1 items-center justify-end space-x-4">
<nav className="flex items-center space-x-2">
<DropdownThemeMode />
{pubkey === null ? <RegisterButton /> : null}
{pubkey === null ? <LoginButton /> : null}
{/* {pubkey !== null ? <Button variant="secondary" onClick={() => { localStorage.removeItem('pubkey'); window.location.reload(); }}>Logout</Button> : null} */}
{pubkey !== null ? <AvatarDropdown /> : null}
</nav>
<nav>
<header className="bg-background/80 sticky top-0 z-40 w-full border-b backdrop-blur">
<div className="container flex h-16 items-center space-x-4 sm:justify-between sm:space-x-0">
<TopNavigationItems items={siteConfig.mainNav} />
<div className="flex flex-1 items-center justify-end space-x-4">
<nav className="flex items-center space-x-2">
<DropdownThemeMode />
{pubkey === null ? <RegisterButton /> : null}
{pubkey === null ? <LoginButton /> : null}
{pubkey !== null ? <AvatarDropdown /> : null}
</nav>
</div>
</div>
</div>
</header>
</header>
</nav>
)
}