top-bar.tsx 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. "use client";
  2. import Link from "next/link";
  3. import { IdentityConsumer } from "@/components/auth/identity-gate";
  4. import { MenuIcon } from "@/components/icons/menu";
  5. import { SearchIcon } from "@/components/icons/search";
  6. import { WalletIcon } from "@/components/icons/wallet";
  7. import { Button, buttonVariants } from "@/components/ui/button";
  8. import { Input } from "@/components/ui/input";
  9. import { NETWORK_STATUS } from "@/lib/mock";
  10. import { cn } from "@/lib/utils";
  11. interface TopBarProps {
  12. onMenuClick: () => void;
  13. }
  14. export function TopBar({ onMenuClick }: TopBarProps) {
  15. return (
  16. <header className="sticky top-0 z-20 flex h-14 items-center gap-2 border-b border-border bg-background/80 px-3 pt-[env(safe-area-inset-top)] backdrop-blur sm:gap-3 sm:px-4 lg:px-6">
  17. <Button
  18. variant="ghost"
  19. size="icon"
  20. className="min-h-11 min-w-11 shrink-0 lg:hidden"
  21. onClick={onMenuClick}
  22. aria-label="Open navigation"
  23. >
  24. <MenuIcon size={18} />
  25. </Button>
  26. <div className="relative hidden min-w-0 max-w-md flex-1 md:block">
  27. <SearchIcon
  28. size={15}
  29. className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
  30. />
  31. <Input
  32. type="search"
  33. placeholder="Search blocks, transactions…"
  34. className="pl-9"
  35. aria-label="Search"
  36. />
  37. </div>
  38. <div className="ml-auto flex min-w-0 items-center gap-2 sm:gap-3">
  39. <span className="hidden items-center gap-2 rounded-full border border-border bg-card px-3 py-1 text-xs text-muted-foreground lg:inline-flex">
  40. <span className="relative flex h-2 w-2">
  41. <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-confirmed opacity-60" />
  42. <span className="relative inline-flex h-2 w-2 rounded-full bg-confirmed" />
  43. </span>
  44. {NETWORK_STATUS.label}
  45. </span>
  46. <IdentityConsumer>
  47. {(identity) =>
  48. identity.isSignedIn ? (
  49. <Link
  50. href="/portal/dashboard"
  51. className={cn(
  52. buttonVariants({ variant: "outline", size: "sm" }),
  53. "min-h-10 max-w-[9rem] truncate sm:max-w-[12rem]",
  54. )}
  55. title={identity.label ?? "Account"}
  56. >
  57. {identity.label ?? "Account"}
  58. </Link>
  59. ) : (
  60. <>
  61. <Link
  62. href="/portal/sign-in"
  63. className={cn(
  64. buttonVariants({ variant: "outline", size: "sm" }),
  65. "min-h-10",
  66. )}
  67. >
  68. Sign in
  69. </Link>
  70. <Link
  71. href="/portal/sign-in"
  72. className={cn(
  73. buttonVariants({ size: "sm" }),
  74. "min-h-10 gap-2",
  75. )}
  76. >
  77. <WalletIcon size={15} />
  78. <span className="hidden xs:inline sm:inline">Wallet</span>
  79. </Link>
  80. </>
  81. )
  82. }
  83. </IdentityConsumer>
  84. </div>
  85. </header>
  86. );
  87. }