diff --git a/app/(root)/(with-right-sidebar)/page.tsx b/app/(root)/(with-right-sidebar)/page.tsx
index 4aa7c66..6bd8036 100644
--- a/app/(root)/(with-right-sidebar)/page.tsx
+++ b/app/(root)/(with-right-sidebar)/page.tsx
@@ -3,7 +3,7 @@ const Home = () => (
Hello Root page with heading H1
{/* Header boundary marker */}
- HEADER: {"words ".repeat(50)}
+ {"words ".repeat(50)}
{/* Flexbox demo: grow vs flex-none */}
@@ -24,7 +24,71 @@ const Home = () => (
{/* Footer boundary marker */}
- FOOTER: {"words ".repeat(50)}
+ {"words ".repeat(50)}
+
+ {/* Question boxes for testing sticky sidebar scroll */}
+
+ {[1, 2, 3, 4].map((num) => (
+
+
+
+ Question #{num}
+
+
+ Asked {num} hours ago
+
+
+
+
+ How to implement a sticky sidebar in Next.js with Tailwind CSS?
+
+
+
+ I'm building a dashboard layout and need the sidebar to remain
+ visible while scrolling the main content. The sidebar should stick
+ below the navbar and scroll independently if its content overflows.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
+ eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+ {/* Tags */}
+
+ {["next.js", "tailwindcss", "react", "css"].map((tag) => (
+
+ {tag}
+
+ ))}
+
+
+ {/* Stats */}
+
+
+ {num * 7} {" "}
+ votes
+
+
+ {num * 3} {" "}
+ answers
+
+
+ {num * 47} {" "}
+ views
+
+
+
+ ))}
+
+ {/* End marker */}
+
+ You've reached the end — sidebar should still be sticky!
+
+
>
);
diff --git a/app/(root)/layout.tsx b/app/(root)/layout.tsx
index 4892922..b4916a3 100644
--- a/app/(root)/layout.tsx
+++ b/app/(root)/layout.tsx
@@ -1,11 +1,18 @@
+import { LeftSidebar } from "@/components/navigation/left-sidebar";
import { Navbar } from "@/components/navigation/navbar";
+import { SidebarProvider } from "@/components/sidebar-provider";
const RootLayout = ({ children }: { children: React.ReactNode }) => {
return (
- <>
-
- {children}
- >
+
+
+
);
};
diff --git a/app/globals.css b/app/globals.css
index 80cc9ff..47a5b4a 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -29,7 +29,6 @@
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
- --color-mobile-nav: var(--mobile-nav);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
@@ -51,18 +50,15 @@
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
+
+ /* NOT SHADCN VARIABLES */
+ --color-mobile-nav: var(--mobile-nav);
+ --color-overlay: var(--overlay);
}
:root {
/* Creates CSS variables available to all elements (no utility generation) */
- /* Only defined in root, not .dark */
--radius: 0.625rem;
- --primary-gradient-to: oklch(0.7434 0.115 58.23); /* #E2995F */
- --gradient-primary: linear-gradient(
- 93.22deg,
- var(--primary) -13.95%,
- var(--primary-gradient-to) 99.54%
- );
--background: oklch(0.994 0 0); /* #FDFDFD */
--foreground: oklch(0.129 0.042 264.695);
@@ -95,9 +91,16 @@
--sidebar-accent-foreground: oklch(0.208 0.042 265.755);
--sidebar-border: oklch(0.929 0.013 255.508);
--sidebar-ring: oklch(0.704 0.04 256.788);
- --mobile-nav: oklch(1 0 0); /* #FFFFFF */
- /* Centralised logo theming */
+ /* NOT SHADCN VARIABLES */
+ --primary-gradient-to: oklch(0.7434 0.115 58.23); /* #E2995F */
+ --gradient-primary: linear-gradient(
+ 93.22deg,
+ var(--primary) -13.95%,
+ var(--primary-gradient-to) 99.54%
+ );
+ --mobile-nav: oklch(1 0 0); /* #FFFFFF */
+ --overlay: oklch(0 0 0); /* black, both modes */
--logo-full-themed: url("/images/logo-light.svg");
--auth-bg: url("/images/auth-bg-light.webp");
}
@@ -135,9 +138,10 @@
--sidebar-accent-foreground: oklch(0.984 0.003 247.858);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.551 0.027 264.364);
- --mobile-nav: oklch(0.1288 0.0406 264.7); /* #07080b */
- /* Centralised logo theming (dark) */
+ /* NOT SHADCN VARIABLES */
+ --mobile-nav: oklch(0.1288 0.0406 264.7); /* #07080b */
+ --overlay: oklch(0 0 0); /* black, both modes */
--logo-full-themed: url("/images/logo-dark.svg");
--auth-bg: url("/images/auth-bg-dark.webp");
}
diff --git a/biome.json b/biome.json
index cf56d75..8d34e5c 100644
--- a/biome.json
+++ b/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
@@ -31,6 +31,14 @@
"enabled": true,
"rules": {
"recommended": true,
+ "style": {
+ "useConsistentTypeDefinitions": {
+ "level": "error",
+ "options": {
+ "style": "type"
+ }
+ }
+ },
"suspicious": {
"noUnknownAtRules": "off"
}
diff --git a/components/clerk-provider.tsx b/components/clerk-provider.tsx
index cb37d25..3765916 100644
--- a/components/clerk-provider.tsx
+++ b/components/clerk-provider.tsx
@@ -21,6 +21,7 @@ export function ClerkProvider({
formButtonPrimary:
"bg-[image:var(--gradient-primary)] text-white hover:opacity-90",
footer: "bg-card",
+ avatarBox: "size-8",
},
...appearance,
}}
diff --git a/components/navigation/full-logo.tsx b/components/navigation/full-logo.tsx
index 0c663a0..41c5735 100644
--- a/components/navigation/full-logo.tsx
+++ b/components/navigation/full-logo.tsx
@@ -4,9 +4,9 @@ import { cn } from "@/lib/utils";
const LOGO_WIDTH = 137;
const LOGO_HEIGHT = 23;
-interface ThemeLogoProps {
+type ThemeLogoProps = {
className?: string;
-}
+};
/**
* Theme-aware logo that switches between light/dark variants via CSS variable.
diff --git a/components/navigation/left-sidebar.tsx b/components/navigation/left-sidebar.tsx
new file mode 100644
index 0000000..a596b72
--- /dev/null
+++ b/components/navigation/left-sidebar.tsx
@@ -0,0 +1,59 @@
+"use client";
+
+import { SignedIn, UserButton } from "@clerk/nextjs";
+import { NavLink } from "@/components/navigation/nav-link";
+import { NAV_LINKS } from "@/components/navigation/nav-links.constants";
+import { SidebarToggle } from "@/components/navigation/sidebar-toggle";
+import { useSidebar } from "@/components/sidebar-provider";
+import { cn } from "@/lib/utils";
+
+// Navbar height minus overlap to hide shadow-sm
+const SIDEBAR_TOP_OFFSET = 72; // 73px navbar - 1px overlap
+
+export function LeftSidebar() {
+ const { isCollapsed } = useSidebar();
+
+ return (
+
+ {/* Top: Navigation Links */}
+
+ {NAV_LINKS.map((link) => (
+
+ ))}
+
+
+ {/* Bottom: User Avatar + Toggle */}
+
+
+
+
+
+
+
+ );
+}
diff --git a/components/navigation/mobile-nav.tsx b/components/navigation/mobile-nav.tsx
index 947fd6e..736608e 100644
--- a/components/navigation/mobile-nav.tsx
+++ b/components/navigation/mobile-nav.tsx
@@ -4,15 +4,15 @@ import {
SignedIn,
SignedOut,
SignInButton,
- SignOutButton,
SignUpButton,
+ UserButton,
} from "@clerk/nextjs";
-import { LogOut, Menu, X } from "lucide-react";
+import { Menu, X } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
-import { NAV_LINKS } from "@/components/navigation/constants";
import { ThemeLogo } from "@/components/navigation/full-logo";
import { NavLink } from "@/components/navigation/nav-link";
+import { NAV_LINKS } from "@/components/navigation/nav-links.constants";
import { Button } from "@/components/ui/button";
import {
Sheet,
@@ -22,91 +22,107 @@ import {
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
+import { cn } from "@/lib/utils";
+
+const MOBILE_NAV_MAX_WIDTH = "max-w-[320px]";
export function MobileNav() {
const [open, setOpen] = useState(false);
return (
-
-
-
+ {/* Tap-to-dismiss overlay: modal={false} allows Clerk popups to work (they render
+ outside Sheet), but disables SheetOverlay dismiss. See authenticated.mobile.spec.ts */}
+ {open && (
+ setOpen(false)}
+ data-slot="sheet-overlay"
+ aria-label="Dismiss menu"
+ />
+ )}
+
+
+
+ {open ? : }
+
+
+
- {open ? : }
-
-
-
- {/* Visually hidden title and description for accessibility */}
- Navigation menu
-
- Browse site pages and manage your account
-
+ {/* Visually hidden title and description for accessibility */}
+ Navigation menu
+
+ Browse site pages and manage your account
+
- {/* Logo */}
-
-
-
-
-
+ {/* Logo */}
+
+
+
+
+
- {/* Navigation Links */}
-
- {NAV_LINKS.map((link) => (
-
-
-
- ))}
-
+ {/* Navigation Links */}
+
+ {NAV_LINKS.map((link) => (
+
+
+
+ ))}
+
- {/* Sign out - Only when signed in */}
-
-
-
-
-
-
- Sign out
-
-
-
-
-
+ {/* Avatar - Only when signed in */}
+
+
+
+
+
- {/* Auth Buttons - Only when signed out */}
-
-
-
+ {/* Auth Buttons - Only when signed out */}
+
+
-
+ setOpen(false)}
+ >
Sign in
-
-
-
+ setOpen(false)}
+ >
Sign up
-
-
-
-
-
+
+
+
+
+ >
);
}
diff --git a/components/navigation/nav-link.tsx b/components/navigation/nav-link.tsx
index 6cc5698..b9cb35f 100644
--- a/components/navigation/nav-link.tsx
+++ b/components/navigation/nav-link.tsx
@@ -1,41 +1,63 @@
"use client";
-import type { Route } from "next";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
-import type { NavLink as NavLinkType } from "@/components/navigation/constants";
+import type { NavLink as NavLinkType } from "@/components/navigation/nav-links.constants";
+import { useSidebar } from "@/components/sidebar-provider";
import { cn } from "@/lib/utils";
type NavLinkProps = NavLinkType & {
- // Passed by SheetClose asChild to close the sheet on click
+ /** Passed by SheetClose asChild to close the sheet on click */
onClick?: () => void;
+ /**
+ * - "rail": Sidebar nav — icon-only when collapsed, icon + label when expanded
+ * - "mobile": Touch-optimised — always full with generous padding (px-4 py-3)
+ */
+ variant?: "rail" | "mobile";
};
-export function NavLink({ imgURL, route, label, onClick }: NavLinkProps) {
+export function NavLink({
+ imgURL,
+ route,
+ label,
+ onClick,
+ variant = "mobile",
+}: NavLinkProps) {
const pathname = usePathname();
- const isActive =
- (pathname.startsWith(route) && route.length > 1) || pathname === route;
+ const { isCollapsed } = useSidebar();
+ const isActive = pathname === route || pathname.startsWith(`${route}/`);
+
+ const isRail = variant === "rail";
+ // For rail variant, show icon-only if collapsed, icon+label if expanded
+ const showIconOnly = isRail && isCollapsed;
return (
- {label}
+ {label}
);
}
diff --git a/components/navigation/constants.ts b/components/navigation/nav-links.constants.ts
similarity index 86%
rename from components/navigation/constants.ts
rename to components/navigation/nav-links.constants.ts
index 1a66ff9..026a389 100644
--- a/components/navigation/constants.ts
+++ b/components/navigation/nav-links.constants.ts
@@ -1,6 +1,8 @@
+import type { Route } from "next";
+
export type NavLink = {
imgURL: string;
- route: string;
+ route: Route;
label: string;
};
@@ -15,5 +17,4 @@ export const NAV_LINKS = [
route: "/ask-question",
label: "Ask a question",
},
- { imgURL: "/icons/user.svg", route: "/profile", label: "Profile" },
] as const satisfies readonly NavLink[];
diff --git a/components/navigation/navbar.tsx b/components/navigation/navbar.tsx
index 1bc00a3..ad27520 100644
--- a/components/navigation/navbar.tsx
+++ b/components/navigation/navbar.tsx
@@ -1,11 +1,4 @@
-import {
- SignedIn,
- SignedOut,
- SignInButton,
- SignUpButton,
- UserButton,
-} from "@clerk/nextjs";
-import Image from "next/image";
+import { SignedOut, SignInButton, SignUpButton } from "@clerk/nextjs";
import Link from "next/link";
import { ThemeLogo } from "@/components/navigation/full-logo";
import { MobileNav } from "@/components/navigation/mobile-nav";
@@ -15,17 +8,16 @@ import { Button } from "@/components/ui/button";
export const Navbar = () => (
{/* Left: Logo (responsive) */}
{/* Mobile: icon only */}
-
{/* Desktop: full themed logo */}
@@ -39,20 +31,17 @@ export const Navbar = () => (
{/* Right: Theme toggle + Auth + Mobile nav */}
- {/* Desktop auth - removed from flex flow on mobile */}
-
-
+ {/* Desktop auth - only shown when signed out (avatar in sidebar when signed in) */}
+
+
Sign in
Sign up
-
-
-
-
-
+
+
{/* Mobile hamburger - visible only on mobile */}
diff --git a/components/navigation/sidebar-toggle.tsx b/components/navigation/sidebar-toggle.tsx
new file mode 100644
index 0000000..49ca41c
--- /dev/null
+++ b/components/navigation/sidebar-toggle.tsx
@@ -0,0 +1,39 @@
+"use client";
+
+import { ChevronsLeft, ChevronsRight } from "lucide-react";
+import { useEffect, useState } from "react";
+import { useSidebar } from "@/components/sidebar-provider";
+import { Button } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
+
+export function SidebarToggle() {
+ const { isCollapsed, toggle } = useSidebar();
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => setMounted(true), []);
+
+ // Render placeholder during SSR to prevent hydration mismatch
+ if (!mounted) {
+ return
;
+ }
+
+ return (
+
+ {isCollapsed ? (
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/components/sidebar-provider.tsx b/components/sidebar-provider.tsx
new file mode 100644
index 0000000..337a029
--- /dev/null
+++ b/components/sidebar-provider.tsx
@@ -0,0 +1,54 @@
+"use client";
+
+import { createContext, useContext, useEffect, useState } from "react";
+
+type SidebarContextType = {
+ isCollapsed: boolean;
+ toggle: () => void;
+};
+
+const SidebarContext = createContext(undefined);
+
+const STORAGE_KEY = "devflow-sidebar-collapsed";
+const LG_BREAKPOINT = 1024; // Tailwind's lg breakpoint
+
+export function SidebarProvider({ children }: { children: React.ReactNode }) {
+ // Default to expanded (false) - same as server render
+ const [isCollapsed, setIsCollapsed] = useState(false);
+
+ // Set initial state after mount: user preference > responsive default
+ useEffect(() => {
+ const stored = localStorage.getItem(STORAGE_KEY);
+
+ if (stored !== null) {
+ // User preference takes priority
+ setIsCollapsed(stored === "true");
+ } else {
+ // No preference: collapse on smaller screens, expand on lg+
+ setIsCollapsed(window.innerWidth < LG_BREAKPOINT);
+ }
+ }, []);
+
+ const toggle = () => {
+ setIsCollapsed((prev) => {
+ const next = !prev;
+ localStorage.setItem(STORAGE_KEY, String(next));
+ return next;
+ });
+ };
+
+ // Always render children - SSR renders with default state (expanded)
+ return (
+
+ {children}
+
+ );
+}
+
+export function useSidebar() {
+ const context = useContext(SidebarContext);
+ if (context === undefined) {
+ throw new Error("useSidebar must be used within SidebarProvider");
+ }
+ return context;
+}
diff --git a/e2e/auth.spec.ts b/e2e/auth.spec.ts
deleted file mode 100644
index 453fd44..0000000
--- a/e2e/auth.spec.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { setupClerkTestingToken } from "@clerk/testing/playwright";
-import { expect, test } from "@playwright/test";
-
-const TEST_EMAIL = process.env.E2E_TEST_EMAIL || "";
-const TEST_PASSWORD = process.env.E2E_TEST_PASSWORD || "";
-const TEST_OTP = process.env.E2E_TEST_OTP || "424242";
-
-test.describe("Auth Smoke Test", () => {
- // Skip on Mobile Safari - WebKit has timing issues with Clerk's OTP modal
- test.skip(({ browserName }) => browserName === "webkit", "WebKit flaky");
-
- test("user can sign in and sign out", async ({ page }) => {
- await setupClerkTestingToken({ page });
-
- // Navigate to homepage
- await page.goto("/");
- await expect(page.getByRole("button", { name: "Sign in" })).toBeVisible();
-
- // Sign in
- await page.getByRole("button", { name: "Sign in" }).click();
- await page.getByRole("textbox", { name: "Email address" }).fill(TEST_EMAIL);
- await page.getByRole("textbox", { name: "Password" }).fill(TEST_PASSWORD);
- await page.getByRole("button", { name: "Continue", exact: true }).click();
-
- // Handle email verification if required (new device verification)
- // Wait for either the OTP screen or the authenticated state
- const otpHeading = page.getByRole("heading", { name: "Check your email" });
- const userMenu = page.getByRole("button", { name: "Open user menu" });
-
- // Check which state we're in (longer timeout for slower browsers)
- await expect(otpHeading.or(userMenu)).toBeVisible({ timeout: 10000 });
-
- if (await otpHeading.isVisible()) {
- // Type OTP code using keyboard (Clerk auto-advances through fields)
- // Clerk auto-submits after all 6 digits are entered, no need to click Continue
- // First click the OTP input to ensure it has focus
- await page.getByRole("textbox").first().click();
- await page.keyboard.type(TEST_OTP);
- }
-
- // Verify authenticated state (longer timeout for redirect after OTP)
- await expect(
- page.getByRole("button", { name: "Open user menu" }),
- ).toBeVisible({ timeout: 15000 });
-
- // Sign out
- await page.getByRole("button", { name: "Open user menu" }).click();
- await page.getByRole("menuitem", { name: "Sign out" }).click();
-
- // Verify unauthenticated state
- await expect(page.getByRole("button", { name: "Sign in" })).toBeVisible();
- });
-});
diff --git a/e2e/authenticated.desktop.spec.ts b/e2e/authenticated.desktop.spec.ts
new file mode 100644
index 0000000..dac6c84
--- /dev/null
+++ b/e2e/authenticated.desktop.spec.ts
@@ -0,0 +1,76 @@
+import { setupClerkTestingToken } from "@clerk/testing/playwright";
+import { expect, test } from "@playwright/test";
+import { VIEWPORTS } from "@/e2e/viewports";
+
+const TEST_EMAIL = process.env.E2E_TEST_EMAIL;
+const TEST_PASSWORD = process.env.E2E_TEST_PASSWORD;
+const TEST_OTP = process.env.E2E_TEST_OTP;
+
+if (!TEST_EMAIL || !TEST_PASSWORD || !TEST_OTP) {
+ throw new Error(
+ "E2E_TEST_EMAIL, E2E_TEST_PASSWORD, and E2E_TEST_OTP environment variables must be set",
+ );
+}
+
+test.describe("Authenticated User Flow - Desktop", () => {
+ test.use({ viewport: VIEWPORTS.XL }); // Sidebar expanded
+
+ test("user can sign in, manage account, and sign out", async ({ page }) => {
+ await setupClerkTestingToken({ page });
+ await page.goto("/");
+
+ // Verify unauthenticated state - Sign in button visible
+ await expect(page.getByRole("button", { name: "Sign in" })).toBeVisible();
+
+ // === SIGN IN ===
+ await page.getByRole("button", { name: "Sign in" }).click();
+ await page.getByRole("textbox", { name: "Email address" }).fill(TEST_EMAIL);
+ await page.getByRole("textbox", { name: "Password" }).fill(TEST_PASSWORD);
+ await page.getByRole("button", { name: "Continue", exact: true }).click();
+
+ // Handle OTP/2FA if required
+ // - "Check your email" = new device verification (email OTP)
+ // - "Two-step verification" or URL contains "factor-two" = 2FA/TOTP
+ const emailOtpHeading = page.getByRole("heading", {
+ name: "Check your email",
+ });
+ const twoFactorHeading = page.getByRole("heading", {
+ name: /verification|two-step/i,
+ });
+ const userMenu = page.getByRole("button", { name: "Open user menu" });
+ await expect(
+ emailOtpHeading.or(twoFactorHeading).or(userMenu),
+ ).toBeVisible();
+
+ // Handle email OTP or 2FA - both use the same OTP input pattern
+ if (
+ (await emailOtpHeading.isVisible()) ||
+ (await twoFactorHeading.isVisible())
+ ) {
+ await page.getByRole("textbox").first().click();
+ await page.keyboard.type(TEST_OTP);
+ }
+
+ // Verify authenticated state - UserButton visible in left sidebar
+ await expect(userMenu).toBeVisible();
+
+ // === MANAGE ACCOUNT ===
+ await userMenu.click();
+ await page.getByRole("menuitem", { name: "Manage account" }).click();
+
+ // Verify modal opens (Clerk renders user profile modal with "Account" heading)
+ const accountHeading = page.getByRole("heading", { name: "Account" });
+ await expect(accountHeading).toBeVisible();
+
+ // Close modal with Escape key
+ await page.keyboard.press("Escape");
+ await expect(accountHeading).not.toBeVisible();
+
+ // === SIGN OUT ===
+ await userMenu.click();
+ await page.getByRole("menuitem", { name: "Sign out" }).click();
+
+ // Verify unauthenticated state
+ await expect(page.getByRole("button", { name: "Sign in" })).toBeVisible();
+ });
+});
diff --git a/e2e/authenticated.mobile.spec.ts b/e2e/authenticated.mobile.spec.ts
new file mode 100644
index 0000000..2fd5c3a
--- /dev/null
+++ b/e2e/authenticated.mobile.spec.ts
@@ -0,0 +1,105 @@
+import { setupClerkTestingToken } from "@clerk/testing/playwright";
+import { expect, test } from "@playwright/test";
+import { VIEWPORTS } from "@/e2e/viewports";
+
+const TEST_EMAIL = process.env.E2E_TEST_EMAIL;
+const TEST_PASSWORD = process.env.E2E_TEST_PASSWORD;
+const TEST_OTP = process.env.E2E_TEST_OTP;
+
+if (!TEST_EMAIL || !TEST_PASSWORD || !TEST_OTP) {
+ throw new Error(
+ "E2E_TEST_EMAIL, E2E_TEST_PASSWORD, and E2E_TEST_OTP environment variables must be set",
+ );
+}
+
+test.describe("Authenticated User Flow - Mobile", () => {
+ test.use({ viewport: VIEWPORTS.MOBILE }); // Hamburger menu visible
+
+ test("user can sign in, manage account, and sign out via mobile menu", async ({
+ page,
+ }) => {
+ await setupClerkTestingToken({ page });
+ await page.goto("/");
+
+ // === SIGN IN VIA MOBILE MENU ===
+ // Open hamburger menu
+ await page.getByRole("button", { name: /open navigation/i }).click();
+
+ // Click Sign in button in mobile menu
+ await page.getByRole("button", { name: "Sign in" }).click();
+
+ // Complete sign in flow
+ await page.getByRole("textbox", { name: "Email address" }).fill(TEST_EMAIL);
+ await page.getByRole("textbox", { name: "Password" }).fill(TEST_PASSWORD);
+ await page.getByRole("button", { name: "Continue", exact: true }).click();
+
+ // Handle OTP/2FA if required
+ // - "Check your email" = new device verification (email OTP)
+ // - "Two-step verification" or URL contains "factor-two" = 2FA/TOTP
+ const emailOtpHeading = page.getByRole("heading", {
+ name: "Check your email",
+ });
+ const twoFactorHeading = page.getByRole("heading", {
+ name: /verification|two-step/i,
+ });
+ const hamburgerButton = page.getByRole("button", {
+ name: /open navigation/i,
+ });
+ await expect(
+ emailOtpHeading.or(twoFactorHeading).or(hamburgerButton),
+ ).toBeVisible();
+
+ // Handle email OTP or 2FA - both use the same OTP input pattern
+ if (
+ (await emailOtpHeading.isVisible()) ||
+ (await twoFactorHeading.isVisible())
+ ) {
+ await page.getByRole("textbox").first().click();
+ await page.keyboard.type(TEST_OTP);
+ }
+
+ // Wait for redirect to home after auth
+ await expect(page).toHaveURL("/");
+
+ // === MANAGE ACCOUNT VIA MOBILE MENU ===
+ // Open hamburger menu
+ await page.getByRole("button", { name: /open navigation/i }).click();
+
+ // UserButton should be visible at bottom of mobile menu
+ const userMenu = page.getByRole("button", { name: "Open user menu" });
+ await expect(userMenu).toBeVisible();
+
+ // Click UserButton and select "Manage account"
+ await userMenu.click();
+ await page.getByRole("menuitem", { name: "Manage account" }).click();
+
+ // Verify modal opens (Clerk on mobile shows "Profile details" as the main heading)
+ // If this fails with "pointer events intercepted", check Sheet modal={false} in mobile-nav.tsx
+ const profileHeading = page.getByRole("heading", {
+ name: "Profile details",
+ });
+ await expect(
+ profileHeading,
+ "Clerk 'Manage account' modal should open - if blocked, ensure Sheet uses modal={false} to allow Clerk popups",
+ ).toBeVisible();
+
+ // Close modal with Clerk's close button
+ await page.getByRole("button", { name: "Close modal" }).click();
+ await expect(profileHeading).not.toBeVisible();
+
+ // === SIGN OUT VIA MOBILE MENU ===
+ // Reopen hamburger menu
+ await page.getByRole("button", { name: /open navigation/i }).click();
+
+ // Click UserButton and sign out
+ await userMenu.click();
+ await page.getByRole("menuitem", { name: "Sign out" }).click();
+
+ // Verify signed out - open menu and check for Sign in button
+ await page.getByRole("button", { name: /open navigation/i }).click();
+ await expect(
+ page.getByRole("button", { name: "Sign in" }),
+ "User should be signed out - Sign in button should be visible in mobile menu",
+ ).toBeVisible();
+ });
+});
diff --git a/e2e/mobile-nav-user-flow.spec.ts b/e2e/mobile-nav-user-flow.spec.ts
deleted file mode 100644
index 1f19256..0000000
--- a/e2e/mobile-nav-user-flow.spec.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { expect, test } from "@playwright/test";
-import { NAV_LINKS } from "@/components/navigation/constants";
-
-test.describe("Mobile navigation user flow", () => {
- test.use({ viewport: { width: 375, height: 667 } }); // iPhone SE
-
- test("user can open mobile menu and navigate to each page", async ({
- page,
- }) => {
- await page.goto("/");
-
- for (const link of NAV_LINKS) {
- // Open mobile menu
- await page.getByRole("button", { name: /open navigation/i }).click();
-
- // Verify link is visible in menu
- const navLink = page.getByRole("link", { name: link.label });
- await expect(navLink).toBeVisible();
-
- // Click link and verify navigation
- await navLink.click();
- await expect(page).toHaveURL(link.route);
-
- // Menu should close after navigation
- await expect(navLink).not.toBeVisible();
- }
- });
-
- test("mobile menu closes when user clicks outside", async ({ page }) => {
- await page.goto("/");
-
- // Open menu
- await page.getByRole("button", { name: /open navigation/i }).click();
- await expect(page.getByRole("link", { name: "Home" })).toBeVisible();
-
- // Close by clicking the overlay (far right, outside the sheet)
- const viewport = page.viewportSize();
- if (!viewport) throw new Error("Viewport size not available");
- await page
- .locator('[data-slot="sheet-overlay"]')
- .click({ position: { x: viewport.width - 10, y: 300 } });
- await expect(page.getByRole("link", { name: "Home" })).not.toBeVisible();
- });
-});
diff --git a/e2e/navigation.spec.ts b/e2e/navigation.spec.ts
new file mode 100644
index 0000000..5b6cced
--- /dev/null
+++ b/e2e/navigation.spec.ts
@@ -0,0 +1,71 @@
+import { expect, test } from "@playwright/test";
+import { NAV_LINKS } from "@/components/navigation/nav-links.constants";
+import { VIEWPORTS } from "@/e2e/viewports";
+
+test.describe("Navigation - Desktop", () => {
+ test.use({ viewport: VIEWPORTS.XL }); // Sidebar expanded
+
+ test("user can navigate to each page via left sidebar", async ({ page }) => {
+ await page.goto("/");
+
+ for (const link of NAV_LINKS) {
+ // Desktop sidebar links are always visible
+ const navLink = page.getByRole("link", { name: link.label });
+ await navLink.click();
+ await expect(page).toHaveURL(link.route);
+ }
+ });
+});
+
+test.describe("Navigation - Mobile", () => {
+ test.use({ viewport: VIEWPORTS.MOBILE }); // Hamburger menu visible
+
+ test("user can open mobile menu and navigate to each page", async ({
+ page,
+ }) => {
+ await page.goto("/");
+
+ for (const link of NAV_LINKS) {
+ // Open mobile menu
+ await page.getByRole("button", { name: /open navigation/i }).click();
+
+ // Verify link is visible in menu
+ const navLink = page.getByRole("link", { name: link.label });
+ await expect(navLink).toBeVisible();
+
+ // Click link and verify navigation
+ await navLink.click();
+ await expect(page).toHaveURL(link.route);
+
+ // Menu should close after navigation (SheetClose wraps links)
+ await expect(navLink).not.toBeVisible();
+ }
+ });
+
+ test("mobile menu closes when user clicks close button", async ({ page }) => {
+ await page.goto("/");
+
+ // Open menu
+ await page.getByRole("button", { name: /open navigation/i }).click();
+ await expect(page.getByRole("link", { name: "Home" })).toBeVisible();
+
+ // Close via Sheet's built-in X button (sr-only "Close", top-right inside sheet)
+ await page.getByRole("button", { name: "Close", exact: true }).click();
+ await expect(page.getByRole("link", { name: "Home" })).not.toBeVisible();
+ });
+
+ test("mobile menu closes when user taps overlay", async ({ page }) => {
+ await page.goto("/");
+
+ // Open menu
+ await page.getByRole("button", { name: /open navigation/i }).click();
+ await expect(page.getByRole("link", { name: "Home" })).toBeVisible();
+
+ // Close by clicking the overlay (aria-label="Dismiss menu")
+ // Use force:true as the sheet content can intercept pointer events on some browsers
+ await page
+ .getByRole("button", { name: "Dismiss menu" })
+ .click({ force: true });
+ await expect(page.getByRole("link", { name: "Home" })).not.toBeVisible();
+ });
+});
diff --git a/e2e/homepage.spec.ts b/e2e/smoke.spec.ts
similarity index 100%
rename from e2e/homepage.spec.ts
rename to e2e/smoke.spec.ts
diff --git a/e2e/viewports.ts b/e2e/viewports.ts
new file mode 100644
index 0000000..3aedff6
--- /dev/null
+++ b/e2e/viewports.ts
@@ -0,0 +1,29 @@
+/**
+ * Viewport presets aligned with Tailwind CSS breakpoints.
+ * Use in tests via: test.use({ viewport: VIEWPORTS.MOBILE })
+ *
+ * Tailwind breakpoints: sm=640, md=768, lg=1024, xl=1280, 2xl=1536
+ */
+
+const MOBILE_HEIGHT = 700;
+const DESKTOP_HEIGHT = 900;
+
+export const VIEWPORTS = {
+ /** Below sm breakpoint — mobile hamburger menu visible */
+ MOBILE: { width: 400, height: MOBILE_HEIGHT },
+
+ /** sm breakpoint (640px) — sidebar appears, collapsed (rail mode) */
+ SM: { width: 640, height: DESKTOP_HEIGHT },
+
+ /** md breakpoint (768px) — sidebar still collapsed */
+ MD: { width: 768, height: DESKTOP_HEIGHT },
+
+ /** lg breakpoint (1024px) — sidebar expands to full width */
+ LG: { width: 1024, height: DESKTOP_HEIGHT },
+
+ /** xl breakpoint (1280px) — standard desktop */
+ XL: { width: 1280, height: DESKTOP_HEIGHT },
+
+ /** 2xl breakpoint (1536px) — large desktop */
+ XXL: { width: 1536, height: DESKTOP_HEIGHT },
+} as const;
diff --git a/lefthook.yml b/lefthook.yml
index 18c667b..daea565 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -49,10 +49,12 @@ pre-push:
playwright-tests:
# Playwright: E2E tests (when matching files change).
+ # CI=true ensures tests run against production build (npm start),
+ # matching CI behaviour and avoiding dev overlay issues.
glob:
- "**/*.{ts,tsx,css}" # code in folders
- "!**/*.{test,spec}.{ts,tsx}" # Exclude unit tests
- "package-lock.json" # Dependency changes
- "postcss.config.mjs" # CSS processing
- "playwright.config.ts" # Config
- run: npx playwright test
\ No newline at end of file
+ run: CI=true npx playwright test
diff --git a/next.config.ts b/next.config.ts
index 29f7f63..5c3d0a8 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -3,6 +3,11 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
reactCompiler: true,
+ // Position dev indicator (route type, cache status) away from left sidebar
+ devIndicators: {
+ position: "bottom-right",
+ },
+
// Enables "use cache" directive, cacheLife(), cacheTag(), and Partial Prerendering.
// Routes are dynamic by default; use "use cache" to opt into caching.
cacheComponents: true,
diff --git a/package-lock.json b/package-lock.json
index 68720f3..4fc03fe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,43 +8,44 @@
"name": "nextjs-base",
"version": "0.1.0",
"dependencies": {
- "@clerk/nextjs": "^6.36.1",
- "@clerk/themes": "^2.4.43",
+ "@clerk/nextjs": "^6.36.5",
+ "@clerk/themes": "^2.4.46",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-slot": "^1.2.4",
"@vercel/analytics": "^1.6.1",
"@vercel/speed-insights": "^1.3.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
- "lucide-react": "^0.561.0",
- "next": "^16.0.10",
+ "lucide-react": "^0.562.0",
+ "next": "^16.1.1",
"next-themes": "^0.4.6",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"tailwind-merge": "^3.4.0"
},
"devDependencies": {
- "@biomejs/biome": "^2.3.8",
- "@clerk/testing": "^1.13.22",
+ "@biomejs/biome": "^2.3.10",
+ "@clerk/testing": "^1.13.26",
"@playwright/test": "^1.57.0",
"@tailwindcss/postcss": "^4",
"@testing-library/jest-dom": "^6.9.1",
- "@testing-library/react": "^16.3.0",
+ "@testing-library/react": "^16.3.1",
"@testing-library/user-event": "^14.6.1",
- "@types/node": "^25.0.2",
+ "@types/node": "^25.0.3",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^5.1.2",
"babel-plugin-react-compiler": "1.0.0",
- "baseline-browser-mapping": "^2.9.5",
+ "baseline-browser-mapping": "^2.9.11",
+ "dotenv": "^17.2.3",
"jsdom": "^27.3.0",
- "lefthook": "^2.0.9",
+ "lefthook": "^2.0.12",
"markdownlint-cli2": "^0.20.0",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "5.9.3",
- "vite-tsconfig-paths": "^6.0.0",
- "vitest": "^4.0.15"
+ "vite-tsconfig-paths": "^6.0.3",
+ "vitest": "^4.0.16"
}
},
"node_modules/@acemir/cssom": {
@@ -75,9 +76,9 @@
}
},
"node_modules/@asamuzakjp/css-color": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz",
- "integrity": "sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz",
+ "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -85,7 +86,7 @@
"@csstools/css-color-parser": "^3.1.0",
"@csstools/css-parser-algorithms": "^3.0.5",
"@csstools/css-tokenizer": "^3.0.4",
- "lru-cache": "^11.2.2"
+ "lru-cache": "^11.2.4"
}
},
"node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
@@ -422,9 +423,9 @@
}
},
"node_modules/@biomejs/biome": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.8.tgz",
- "integrity": "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.10.tgz",
+ "integrity": "sha512-/uWSUd1MHX2fjqNLHNL6zLYWBbrJeG412/8H7ESuK8ewoRoMPUgHDebqKrPTx/5n6f17Xzqc9hdg3MEqA5hXnQ==",
"dev": true,
"license": "MIT OR Apache-2.0",
"bin": {
@@ -438,20 +439,20 @@
"url": "https://opencollective.com/biome"
},
"optionalDependencies": {
- "@biomejs/cli-darwin-arm64": "2.3.8",
- "@biomejs/cli-darwin-x64": "2.3.8",
- "@biomejs/cli-linux-arm64": "2.3.8",
- "@biomejs/cli-linux-arm64-musl": "2.3.8",
- "@biomejs/cli-linux-x64": "2.3.8",
- "@biomejs/cli-linux-x64-musl": "2.3.8",
- "@biomejs/cli-win32-arm64": "2.3.8",
- "@biomejs/cli-win32-x64": "2.3.8"
+ "@biomejs/cli-darwin-arm64": "2.3.10",
+ "@biomejs/cli-darwin-x64": "2.3.10",
+ "@biomejs/cli-linux-arm64": "2.3.10",
+ "@biomejs/cli-linux-arm64-musl": "2.3.10",
+ "@biomejs/cli-linux-x64": "2.3.10",
+ "@biomejs/cli-linux-x64-musl": "2.3.10",
+ "@biomejs/cli-win32-arm64": "2.3.10",
+ "@biomejs/cli-win32-x64": "2.3.10"
}
},
"node_modules/@biomejs/cli-darwin-arm64": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.8.tgz",
- "integrity": "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.10.tgz",
+ "integrity": "sha512-M6xUjtCVnNGFfK7HMNKa593nb7fwNm43fq1Mt71kpLpb+4mE7odO8W/oWVDyBVO4ackhresy1ZYO7OJcVo/B7w==",
"cpu": [
"arm64"
],
@@ -466,9 +467,9 @@
}
},
"node_modules/@biomejs/cli-darwin-x64": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.8.tgz",
- "integrity": "sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.10.tgz",
+ "integrity": "sha512-Vae7+V6t/Avr8tVbFNjnFSTKZogZHFYl7MMH62P/J1kZtr0tyRQ9Fe0onjqjS2Ek9lmNLmZc/VR5uSekh+p1fg==",
"cpu": [
"x64"
],
@@ -483,9 +484,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.8.tgz",
- "integrity": "sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.10.tgz",
+ "integrity": "sha512-hhPw2V3/EpHKsileVOFynuWiKRgFEV48cLe0eA+G2wO4SzlwEhLEB9LhlSrVeu2mtSn205W283LkX7Fh48CaxA==",
"cpu": [
"arm64"
],
@@ -500,9 +501,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64-musl": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.8.tgz",
- "integrity": "sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.10.tgz",
+ "integrity": "sha512-B9DszIHkuKtOH2IFeeVkQmSMVUjss9KtHaNXquYYWCjH8IstNgXgx5B0aSBQNr6mn4RcKKRQZXn9Zu1rM3O0/A==",
"cpu": [
"arm64"
],
@@ -517,9 +518,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.8.tgz",
- "integrity": "sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.10.tgz",
+ "integrity": "sha512-wwAkWD1MR95u+J4LkWP74/vGz+tRrIQvr8kfMMJY8KOQ8+HMVleREOcPYsQX82S7uueco60L58Wc6M1I9WA9Dw==",
"cpu": [
"x64"
],
@@ -534,9 +535,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64-musl": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.8.tgz",
- "integrity": "sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.10.tgz",
+ "integrity": "sha512-QTfHZQh62SDFdYc2nfmZFuTm5yYb4eO1zwfB+90YxUumRCR171tS1GoTX5OD0wrv4UsziMPmrePMtkTnNyYG3g==",
"cpu": [
"x64"
],
@@ -551,9 +552,9 @@
}
},
"node_modules/@biomejs/cli-win32-arm64": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.8.tgz",
- "integrity": "sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.10.tgz",
+ "integrity": "sha512-o7lYc9n+CfRbHvkjPhm8s9FgbKdYZu5HCcGVMItLjz93EhgJ8AM44W+QckDqLA9MKDNFrR8nPbO4b73VC5kGGQ==",
"cpu": [
"arm64"
],
@@ -568,9 +569,9 @@
}
},
"node_modules/@biomejs/cli-win32-x64": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.8.tgz",
- "integrity": "sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w==",
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.10.tgz",
+ "integrity": "sha512-pHEFgq7dUEsKnqG9mx9bXihxGI49X+ar+UBrEIj3Wqj3UCZp1rNgV+OoyjFgcXsjCWpuEAF4VJdkZr3TrWdCbQ==",
"cpu": [
"x64"
],
@@ -585,13 +586,13 @@
}
},
"node_modules/@clerk/backend": {
- "version": "2.27.0",
- "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-2.27.0.tgz",
- "integrity": "sha512-e3xdLV/dAp40eFg2eo5tPs/wF942WfJoQA0NLlKHUPYiBD1K+DD8WcX5Fv/kvXUlpoTGiMalexHz42rpx9TJBQ==",
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-2.29.0.tgz",
+ "integrity": "sha512-cw4CK6ZHgeFROirlIOawelqRBxZAyH6v3GPSYZEEzYAL0WWUHx7cMXzoQcTMruH7w6UM7s3Ox+uUcINESWkQPA==",
"license": "MIT",
"dependencies": {
- "@clerk/shared": "^3.39.0",
- "@clerk/types": "^4.101.6",
+ "@clerk/shared": "^3.41.1",
+ "@clerk/types": "^4.101.9",
"cookie": "1.0.2",
"standardwebhooks": "^1.0.0",
"tslib": "2.8.1"
@@ -601,32 +602,32 @@
}
},
"node_modules/@clerk/clerk-react": {
- "version": "5.58.1",
- "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.58.1.tgz",
- "integrity": "sha512-jN6mfuqwZakm99CKRQlTahMZEa8qLOpr3Z4lG6XtyJfIcyADleOdRxuOXYoN9sV8ZhNfDDAs+eKjUeusIzPpbg==",
+ "version": "5.59.2",
+ "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.59.2.tgz",
+ "integrity": "sha512-vFZ4LWPenbNnui4GqGGkicH/3SL7KhS9egTMv/m0Dj/sS7mUgmLqAFpqWkhbzN8s8/rybuvJsMyIU7M0kx8+Cw==",
"license": "MIT",
"dependencies": {
- "@clerk/shared": "^3.39.0",
+ "@clerk/shared": "^3.41.1",
"tslib": "2.8.1"
},
"engines": {
"node": ">=18.17.0"
},
"peerDependencies": {
- "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
- "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
+ "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0",
+ "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0"
}
},
"node_modules/@clerk/nextjs": {
- "version": "6.36.2",
- "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-6.36.2.tgz",
- "integrity": "sha512-1ovNi+Xxjq1ZGg8gp++5cp8FYiwkUX5OB5KH7t0bCFkvHTBu48Fdbucmw38AhEqwLnNg9St4GNSKZmyGvVwh6Q==",
+ "version": "6.36.5",
+ "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-6.36.5.tgz",
+ "integrity": "sha512-qHNNbxhAZMHanv47DKc08Xc+y0gbsoQBFVYA+WRzwii5OWOoWmLlydTGKaqukqNw9km9IN9b2KWSAvs1oklp2g==",
"license": "MIT",
"dependencies": {
- "@clerk/backend": "^2.27.0",
- "@clerk/clerk-react": "^5.58.1",
- "@clerk/shared": "^3.39.0",
- "@clerk/types": "^4.101.6",
+ "@clerk/backend": "^2.29.0",
+ "@clerk/clerk-react": "^5.59.2",
+ "@clerk/shared": "^3.41.1",
+ "@clerk/types": "^4.101.9",
"server-only": "0.0.1",
"tslib": "2.8.1"
},
@@ -635,14 +636,14 @@
},
"peerDependencies": {
"next": "^13.5.7 || ^14.2.25 || ^15.2.3 || ^16",
- "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
- "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
+ "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0",
+ "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0"
}
},
"node_modules/@clerk/shared": {
- "version": "3.39.0",
- "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.39.0.tgz",
- "integrity": "sha512-9kqqXGMPAdMQ7SXo5ZwUhbzbLLQeLp/1jdb8FQS5qlhmL0S0bAYKcyDjcmMB8xZPXNc7vZJRT72QHsGSlUAJxw==",
+ "version": "3.41.1",
+ "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.41.1.tgz",
+ "integrity": "sha512-BCbT7Xodk2rndA2nV/lW8X5LMNTvFP5UG2wNN9cYuAcTaI6hYZP18/z2zef2gG4xIrK7WAEjGVzHscikqNtzFQ==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -657,8 +658,8 @@
"node": ">=18.17.0"
},
"peerDependencies": {
- "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
- "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
+ "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0",
+ "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0"
},
"peerDependenciesMeta": {
"react": {
@@ -670,15 +671,15 @@
}
},
"node_modules/@clerk/testing": {
- "version": "1.13.23",
- "resolved": "https://registry.npmjs.org/@clerk/testing/-/testing-1.13.23.tgz",
- "integrity": "sha512-Z/uSgc9aJ++dmi2cX5hcZ/pzAVvXBtKIhNwCMdFI2unsAGE3b4ZJu6cJVAYMIpIFdUiLGe0SKbOuPY50Oau0cw==",
+ "version": "1.13.26",
+ "resolved": "https://registry.npmjs.org/@clerk/testing/-/testing-1.13.26.tgz",
+ "integrity": "sha512-+sxwG4UM0LcUcKaMsGB4CT5vjYyCNTNG7psW7Z7NR8/8TZWD+whNVtoBQm0yjr0m5fFoCemVY62YaWa+jCXCKA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@clerk/backend": "^2.27.0",
- "@clerk/shared": "^3.39.0",
- "@clerk/types": "^4.101.6",
+ "@clerk/backend": "^2.29.0",
+ "@clerk/shared": "^3.41.1",
+ "@clerk/types": "^4.101.9",
"dotenv": "17.2.2"
},
"engines": {
@@ -697,13 +698,26 @@
}
}
},
+ "node_modules/@clerk/testing/node_modules/dotenv": {
+ "version": "17.2.2",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz",
+ "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/@clerk/themes": {
- "version": "2.4.43",
- "resolved": "https://registry.npmjs.org/@clerk/themes/-/themes-2.4.43.tgz",
- "integrity": "sha512-xIIRF63O3r+I/FcUtwTONE7gkhHrUNG+jAuSW2bRkeV2wxCWT2wAsZaY1w0qPrXpdXA4JKw2mWL9mRz/tCmJNA==",
+ "version": "2.4.46",
+ "resolved": "https://registry.npmjs.org/@clerk/themes/-/themes-2.4.46.tgz",
+ "integrity": "sha512-26U+aInnWJwYHrT/LYX7sGRrLJwLk4NvfEoUyVc5EXUl7ue/TZ88r7ZiKDv0KutBTNopaz+p+7KD6F1j72nodA==",
"license": "MIT",
"dependencies": {
- "@clerk/shared": "^3.39.0",
+ "@clerk/shared": "^3.41.1",
"tslib": "2.8.1"
},
"engines": {
@@ -711,12 +725,12 @@
}
},
"node_modules/@clerk/types": {
- "version": "4.101.6",
- "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.101.6.tgz",
- "integrity": "sha512-Ah6R65loy5Aq1jBpWo3x01IOlYJfgVn4LVAkSXKVQDtehn8w1bT2uJ7BTa2zH72A8F4K2HivkmMQa+v/37tLFA==",
+ "version": "4.101.9",
+ "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.101.9.tgz",
+ "integrity": "sha512-RO00JqqmkIoI1o0XCtvudjaLpqEoe8PRDHlLS1r/aNZazUQCO0TT6nZOx1F3X+QJDjqYVY7YmYl3mtO2QVEk1g==",
"license": "MIT",
"dependencies": {
- "@clerk/shared": "^3.39.0"
+ "@clerk/shared": "^3.41.1"
},
"engines": {
"node": ">=18.17.0"
@@ -818,9 +832,9 @@
}
},
"node_modules/@csstools/css-syntax-patches-for-csstree": {
- "version": "1.0.14",
- "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz",
- "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==",
+ "version": "1.0.22",
+ "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz",
+ "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==",
"dev": true,
"funding": [
{
@@ -835,9 +849,6 @@
"license": "MIT-0",
"engines": {
"node": ">=18"
- },
- "peerDependencies": {
- "postcss": "^8.4"
}
},
"node_modules/@csstools/css-tokenizer": {
@@ -871,9 +882,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
- "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
+ "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
"cpu": [
"ppc64"
],
@@ -888,9 +899,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
- "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
+ "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
"cpu": [
"arm"
],
@@ -905,9 +916,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
- "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
+ "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
"cpu": [
"arm64"
],
@@ -922,9 +933,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
- "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
+ "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
"cpu": [
"x64"
],
@@ -939,9 +950,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
- "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
+ "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
"cpu": [
"arm64"
],
@@ -956,9 +967,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
- "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
+ "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
"cpu": [
"x64"
],
@@ -973,9 +984,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
- "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
"cpu": [
"arm64"
],
@@ -990,9 +1001,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
- "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
+ "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
"cpu": [
"x64"
],
@@ -1007,9 +1018,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
- "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
+ "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
"cpu": [
"arm"
],
@@ -1024,9 +1035,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
- "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
+ "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
"cpu": [
"arm64"
],
@@ -1041,9 +1052,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
- "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
+ "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
"cpu": [
"ia32"
],
@@ -1058,9 +1069,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
- "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
+ "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
"cpu": [
"loong64"
],
@@ -1075,9 +1086,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
- "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
+ "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
"cpu": [
"mips64el"
],
@@ -1092,9 +1103,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
- "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
+ "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
"cpu": [
"ppc64"
],
@@ -1109,9 +1120,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
- "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
+ "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
"cpu": [
"riscv64"
],
@@ -1126,9 +1137,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
- "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
+ "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
"cpu": [
"s390x"
],
@@ -1143,9 +1154,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
- "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
+ "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
"cpu": [
"x64"
],
@@ -1160,9 +1171,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
- "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
"cpu": [
"arm64"
],
@@ -1177,9 +1188,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
- "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
"cpu": [
"x64"
],
@@ -1194,9 +1205,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
- "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
"cpu": [
"arm64"
],
@@ -1211,9 +1222,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
- "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
"cpu": [
"x64"
],
@@ -1228,9 +1239,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
- "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
+ "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
"cpu": [
"arm64"
],
@@ -1245,9 +1256,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
- "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
+ "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
"cpu": [
"x64"
],
@@ -1262,9 +1273,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
- "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
+ "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
"cpu": [
"arm64"
],
@@ -1279,9 +1290,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
- "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
+ "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
"cpu": [
"ia32"
],
@@ -1296,9 +1307,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
- "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
+ "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
"cpu": [
"x64"
],
@@ -1829,15 +1840,15 @@
}
},
"node_modules/@next/env": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz",
- "integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz",
+ "integrity": "sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==",
"license": "MIT"
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.10.tgz",
- "integrity": "sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.1.tgz",
+ "integrity": "sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==",
"cpu": [
"arm64"
],
@@ -1851,9 +1862,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz",
- "integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.1.tgz",
+ "integrity": "sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==",
"cpu": [
"x64"
],
@@ -1867,9 +1878,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz",
- "integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.1.tgz",
+ "integrity": "sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==",
"cpu": [
"arm64"
],
@@ -1883,9 +1894,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz",
- "integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.1.tgz",
+ "integrity": "sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==",
"cpu": [
"arm64"
],
@@ -1899,9 +1910,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz",
- "integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.1.tgz",
+ "integrity": "sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==",
"cpu": [
"x64"
],
@@ -1915,9 +1926,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz",
- "integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.1.tgz",
+ "integrity": "sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==",
"cpu": [
"x64"
],
@@ -1931,9 +1942,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz",
- "integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.1.tgz",
+ "integrity": "sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==",
"cpu": [
"arm64"
],
@@ -1947,9 +1958,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz",
- "integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.1.tgz",
+ "integrity": "sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==",
"cpu": [
"x64"
],
@@ -2391,9 +2402,9 @@
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
- "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz",
+ "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==",
"cpu": [
"arm"
],
@@ -2405,9 +2416,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
- "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz",
+ "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==",
"cpu": [
"arm64"
],
@@ -2419,9 +2430,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
- "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz",
+ "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==",
"cpu": [
"arm64"
],
@@ -2433,9 +2444,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
- "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz",
+ "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==",
"cpu": [
"x64"
],
@@ -2447,9 +2458,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
- "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz",
+ "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==",
"cpu": [
"arm64"
],
@@ -2461,9 +2472,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
- "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz",
+ "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==",
"cpu": [
"x64"
],
@@ -2475,9 +2486,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
- "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz",
+ "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==",
"cpu": [
"arm"
],
@@ -2489,9 +2500,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
- "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz",
+ "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==",
"cpu": [
"arm"
],
@@ -2503,9 +2514,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
- "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz",
+ "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==",
"cpu": [
"arm64"
],
@@ -2517,9 +2528,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
- "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz",
+ "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==",
"cpu": [
"arm64"
],
@@ -2531,9 +2542,9 @@
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
- "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz",
+ "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==",
"cpu": [
"loong64"
],
@@ -2545,9 +2556,9 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
- "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz",
+ "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==",
"cpu": [
"ppc64"
],
@@ -2559,9 +2570,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
- "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz",
+ "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==",
"cpu": [
"riscv64"
],
@@ -2573,9 +2584,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
- "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz",
+ "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==",
"cpu": [
"riscv64"
],
@@ -2587,9 +2598,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
- "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz",
+ "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==",
"cpu": [
"s390x"
],
@@ -2601,9 +2612,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
- "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz",
+ "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==",
"cpu": [
"x64"
],
@@ -2615,9 +2626,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
- "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz",
+ "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==",
"cpu": [
"x64"
],
@@ -2629,9 +2640,9 @@
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
- "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz",
+ "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==",
"cpu": [
"arm64"
],
@@ -2643,9 +2654,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
- "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz",
+ "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==",
"cpu": [
"arm64"
],
@@ -2657,9 +2668,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
- "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz",
+ "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==",
"cpu": [
"ia32"
],
@@ -2671,9 +2682,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
- "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz",
+ "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==",
"cpu": [
"x64"
],
@@ -2685,9 +2696,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
- "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz",
+ "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==",
"cpu": [
"x64"
],
@@ -2718,9 +2729,9 @@
"license": "MIT"
},
"node_modules/@standard-schema/spec": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
- "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
"dev": true,
"license": "MIT"
},
@@ -3053,9 +3064,9 @@
"license": "MIT"
},
"node_modules/@testing-library/react": {
- "version": "16.3.0",
- "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz",
- "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==",
+ "version": "16.3.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.1.tgz",
+ "integrity": "sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3197,9 +3208,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "25.0.2",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.2.tgz",
- "integrity": "sha512-gWEkeiyYE4vqjON/+Obqcoeffmk0NF15WSBwSs7zwVA2bAbTaE0SJ7P0WNGoJn8uE7fiaV5a7dKYIJriEqOrmA==",
+ "version": "25.0.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
+ "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3334,16 +3345,16 @@
}
},
"node_modules/@vitest/expect": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.15.tgz",
- "integrity": "sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.16.tgz",
+ "integrity": "sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@standard-schema/spec": "^1.0.0",
"@types/chai": "^5.2.2",
- "@vitest/spy": "4.0.15",
- "@vitest/utils": "4.0.15",
+ "@vitest/spy": "4.0.16",
+ "@vitest/utils": "4.0.16",
"chai": "^6.2.1",
"tinyrainbow": "^3.0.3"
},
@@ -3352,13 +3363,13 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.15.tgz",
- "integrity": "sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.16.tgz",
+ "integrity": "sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "4.0.15",
+ "@vitest/spy": "4.0.16",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.21"
},
@@ -3379,9 +3390,9 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.15.tgz",
- "integrity": "sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.16.tgz",
+ "integrity": "sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3392,13 +3403,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.15.tgz",
- "integrity": "sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.16.tgz",
+ "integrity": "sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "4.0.15",
+ "@vitest/utils": "4.0.16",
"pathe": "^2.0.3"
},
"funding": {
@@ -3406,13 +3417,13 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.15.tgz",
- "integrity": "sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.16.tgz",
+ "integrity": "sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.0.15",
+ "@vitest/pretty-format": "4.0.16",
"magic-string": "^0.30.21",
"pathe": "^2.0.3"
},
@@ -3421,9 +3432,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.15.tgz",
- "integrity": "sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.16.tgz",
+ "integrity": "sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw==",
"dev": true,
"license": "MIT",
"funding": {
@@ -3431,13 +3442,13 @@
}
},
"node_modules/@vitest/utils": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.15.tgz",
- "integrity": "sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.16.tgz",
+ "integrity": "sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.0.15",
+ "@vitest/pretty-format": "4.0.16",
"tinyrainbow": "^3.0.3"
},
"funding": {
@@ -3529,10 +3540,9 @@
}
},
"node_modules/baseline-browser-mapping": {
- "version": "2.9.7",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz",
- "integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==",
- "dev": true,
+ "version": "2.9.11",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz",
+ "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==",
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
@@ -3596,9 +3606,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001760",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz",
- "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==",
+ "version": "1.0.30001761",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz",
+ "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==",
"funding": [
{
"type": "opencollective",
@@ -3616,9 +3626,9 @@
"license": "CC-BY-4.0"
},
"node_modules/chai": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz",
- "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
+ "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3733,14 +3743,14 @@
"license": "MIT"
},
"node_modules/cssstyle": {
- "version": "5.3.4",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.4.tgz",
- "integrity": "sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==",
+ "version": "5.3.5",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.5.tgz",
+ "integrity": "sha512-GlsEptulso7Jg0VaOZ8BXQi3AkYM5BOJKEO/rjMidSCq70FkIC5y0eawrCXeYzxgt3OCf4Ls+eoxN+/05vN0Ag==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@asamuzakjp/css-color": "^4.1.0",
- "@csstools/css-syntax-patches-for-csstree": "1.0.14",
+ "@asamuzakjp/css-color": "^4.1.1",
+ "@csstools/css-syntax-patches-for-csstree": "^1.0.21",
"css-tree": "^3.1.0"
},
"engines": {
@@ -3854,9 +3864,9 @@
"peer": true
},
"node_modules/dotenv": {
- "version": "17.2.2",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz",
- "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==",
+ "version": "17.2.3",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
+ "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
@@ -3908,9 +3918,9 @@
"license": "MIT"
},
"node_modules/esbuild": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
- "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
+ "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -3921,32 +3931,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.12",
- "@esbuild/android-arm": "0.25.12",
- "@esbuild/android-arm64": "0.25.12",
- "@esbuild/android-x64": "0.25.12",
- "@esbuild/darwin-arm64": "0.25.12",
- "@esbuild/darwin-x64": "0.25.12",
- "@esbuild/freebsd-arm64": "0.25.12",
- "@esbuild/freebsd-x64": "0.25.12",
- "@esbuild/linux-arm": "0.25.12",
- "@esbuild/linux-arm64": "0.25.12",
- "@esbuild/linux-ia32": "0.25.12",
- "@esbuild/linux-loong64": "0.25.12",
- "@esbuild/linux-mips64el": "0.25.12",
- "@esbuild/linux-ppc64": "0.25.12",
- "@esbuild/linux-riscv64": "0.25.12",
- "@esbuild/linux-s390x": "0.25.12",
- "@esbuild/linux-x64": "0.25.12",
- "@esbuild/netbsd-arm64": "0.25.12",
- "@esbuild/netbsd-x64": "0.25.12",
- "@esbuild/openbsd-arm64": "0.25.12",
- "@esbuild/openbsd-x64": "0.25.12",
- "@esbuild/openharmony-arm64": "0.25.12",
- "@esbuild/sunos-x64": "0.25.12",
- "@esbuild/win32-arm64": "0.25.12",
- "@esbuild/win32-ia32": "0.25.12",
- "@esbuild/win32-x64": "0.25.12"
+ "@esbuild/aix-ppc64": "0.27.2",
+ "@esbuild/android-arm": "0.27.2",
+ "@esbuild/android-arm64": "0.27.2",
+ "@esbuild/android-x64": "0.27.2",
+ "@esbuild/darwin-arm64": "0.27.2",
+ "@esbuild/darwin-x64": "0.27.2",
+ "@esbuild/freebsd-arm64": "0.27.2",
+ "@esbuild/freebsd-x64": "0.27.2",
+ "@esbuild/linux-arm": "0.27.2",
+ "@esbuild/linux-arm64": "0.27.2",
+ "@esbuild/linux-ia32": "0.27.2",
+ "@esbuild/linux-loong64": "0.27.2",
+ "@esbuild/linux-mips64el": "0.27.2",
+ "@esbuild/linux-ppc64": "0.27.2",
+ "@esbuild/linux-riscv64": "0.27.2",
+ "@esbuild/linux-s390x": "0.27.2",
+ "@esbuild/linux-x64": "0.27.2",
+ "@esbuild/netbsd-arm64": "0.27.2",
+ "@esbuild/netbsd-x64": "0.27.2",
+ "@esbuild/openbsd-arm64": "0.27.2",
+ "@esbuild/openbsd-x64": "0.27.2",
+ "@esbuild/openharmony-arm64": "0.27.2",
+ "@esbuild/sunos-x64": "0.27.2",
+ "@esbuild/win32-arm64": "0.27.2",
+ "@esbuild/win32-ia32": "0.27.2",
+ "@esbuild/win32-x64": "0.27.2"
}
},
"node_modules/escalade": {
@@ -4003,9 +4013,9 @@
"license": "Unlicense"
},
"node_modules/fastq": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
- "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -4417,9 +4427,9 @@
}
},
"node_modules/lefthook": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook/-/lefthook-2.0.11.tgz",
- "integrity": "sha512-/91k4dt9MRNkzeSr1iMjNi/z8dNuh+XvNfXrWA6PV+M1ZxiNY6uN6bGnr13n+j7N89f4h7YWBhCqhzhK33M5cA==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook/-/lefthook-2.0.12.tgz",
+ "integrity": "sha512-I2FdA9cdnq1icwlNz4RADs7exuqe47q1N9+p2LmcP/WfchWh16mvTB82OAD7w7zK9GxblS9GpF7pASaOSl4c7A==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -4427,22 +4437,22 @@
"lefthook": "bin/index.js"
},
"optionalDependencies": {
- "lefthook-darwin-arm64": "2.0.11",
- "lefthook-darwin-x64": "2.0.11",
- "lefthook-freebsd-arm64": "2.0.11",
- "lefthook-freebsd-x64": "2.0.11",
- "lefthook-linux-arm64": "2.0.11",
- "lefthook-linux-x64": "2.0.11",
- "lefthook-openbsd-arm64": "2.0.11",
- "lefthook-openbsd-x64": "2.0.11",
- "lefthook-windows-arm64": "2.0.11",
- "lefthook-windows-x64": "2.0.11"
+ "lefthook-darwin-arm64": "2.0.12",
+ "lefthook-darwin-x64": "2.0.12",
+ "lefthook-freebsd-arm64": "2.0.12",
+ "lefthook-freebsd-x64": "2.0.12",
+ "lefthook-linux-arm64": "2.0.12",
+ "lefthook-linux-x64": "2.0.12",
+ "lefthook-openbsd-arm64": "2.0.12",
+ "lefthook-openbsd-x64": "2.0.12",
+ "lefthook-windows-arm64": "2.0.12",
+ "lefthook-windows-x64": "2.0.12"
}
},
"node_modules/lefthook-darwin-arm64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-darwin-arm64/-/lefthook-darwin-arm64-2.0.11.tgz",
- "integrity": "sha512-RfpdcJJQXstdgDiIBDRffncayKiXx+0LyMUCunIxDEO2JMXPpYK2hIdpUU0rkitzptAADchG7u1OXJ31rrtIAA==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-darwin-arm64/-/lefthook-darwin-arm64-2.0.12.tgz",
+ "integrity": "sha512-tuBz1sNLien+nKKb8BDopKjS6EnbXU8rQzhMVBY+bnVfsTiYDfbBr4wo/IzA5TcwoTL/b5somCJhljEw6DvSyg==",
"cpu": [
"arm64"
],
@@ -4454,9 +4464,9 @@
]
},
"node_modules/lefthook-darwin-x64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-darwin-x64/-/lefthook-darwin-x64-2.0.11.tgz",
- "integrity": "sha512-D013UNKQa4FKgpxDMqdaU109U2/Pidtrt9CobQoq8te4eGUglcwxMzuYVTgaYnenz0FgKxSfVaCZsZgwqeMWqA==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-darwin-x64/-/lefthook-darwin-x64-2.0.12.tgz",
+ "integrity": "sha512-FnuUMPPRMJyTEPXg6PotSrFJ8qf8FDLhhD1zLh74D+9Cye5j9n3lcrCQEjXubPT8du/GZLxMBjjffRbcZ8eYDA==",
"cpu": [
"x64"
],
@@ -4468,9 +4478,9 @@
]
},
"node_modules/lefthook-freebsd-arm64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-2.0.11.tgz",
- "integrity": "sha512-mgfNqG1tiJkCuGNwPG0LEfnAHGJA+Qzl6KidOtX/Zhxmj/sM+6hxiP4LOeEAhCnaZF5kuPtQgbFzShFHc2BK6A==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-2.0.12.tgz",
+ "integrity": "sha512-DXElB0qR5e6a8cXkFNYakhwCieypbfh6Y4QG39pzMnLsG03g/nhe093o6owfiUZ4mUFyDM6+0xmy0steOooF2g==",
"cpu": [
"arm64"
],
@@ -4482,9 +4492,9 @@
]
},
"node_modules/lefthook-freebsd-x64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-freebsd-x64/-/lefthook-freebsd-x64-2.0.11.tgz",
- "integrity": "sha512-rnHOlQbJfLGCibr7yHM44kPNgf/tFpEbj/cWVHRhjRdbgYSCAjJk0uKd/EVo3v/vjfId2na0AhWbLvO/aY3wQQ==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-freebsd-x64/-/lefthook-freebsd-x64-2.0.12.tgz",
+ "integrity": "sha512-iJN1ZxFeaDi4Fi3b9jcW9wgyNl19LOv2NaVOaAi/tG6mlIn196cmSdXkOA3+943ZbqbdfV9I+bBcIKwneXDA3Q==",
"cpu": [
"x64"
],
@@ -4496,9 +4506,9 @@
]
},
"node_modules/lefthook-linux-arm64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-linux-arm64/-/lefthook-linux-arm64-2.0.11.tgz",
- "integrity": "sha512-1XjDo2/4fM0TbJBwxZh8w+WMOFueg9oYHkryM8vc3vp8wTajdWBazg1K37JIS3FUco3tcOs+eWHQg0ekVjpWoA==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-linux-arm64/-/lefthook-linux-arm64-2.0.12.tgz",
+ "integrity": "sha512-byvmO4Iri6P0COwM8c3lGgeCV3Q0hh1XJpRfrcZDr4Wslq9O63t6J3T6i87oOtY+UjC9pXLl6xGk6hlUcHZ3BQ==",
"cpu": [
"arm64"
],
@@ -4510,9 +4520,9 @@
]
},
"node_modules/lefthook-linux-x64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-linux-x64/-/lefthook-linux-x64-2.0.11.tgz",
- "integrity": "sha512-OKOcfEvozXhO7+y2xgUzvc2kkqfhluql/sjQSzd8Ka+iK3hM4KCfbfgYx9q61Pjr34a0+i03cuH5DF2dlq/rrg==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-linux-x64/-/lefthook-linux-x64-2.0.12.tgz",
+ "integrity": "sha512-KBaiinmf336rA+/dmYs7H7TTeAOByB0CyLA7k8IecTCuaiuKr6ez7ktSjht19poa5G+V0mts4GgEGcx6HViR0w==",
"cpu": [
"x64"
],
@@ -4524,9 +4534,9 @@
]
},
"node_modules/lefthook-openbsd-arm64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-2.0.11.tgz",
- "integrity": "sha512-n1KEx196M3SKaWVNTQXGgxzBsiYAsdAy6Of6I6TAZwPhG7yoRrKGkQrhOlPgMzYl36udG1Lk4D+mfY9T0oOUYQ==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-2.0.12.tgz",
+ "integrity": "sha512-1QBMXX1UW5rtgC4TB52OKWB7Rz/kCBRB+bKKLT/gDD79aPzLgJANTitQQzgFNIWoa7aM9UvzvIAJzOo6FcFIbg==",
"cpu": [
"arm64"
],
@@ -4538,9 +4548,9 @@
]
},
"node_modules/lefthook-openbsd-x64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-openbsd-x64/-/lefthook-openbsd-x64-2.0.11.tgz",
- "integrity": "sha512-WAEtKpYUVvuJMVLA38IBoaPnTNSiaEzvUYxjTBlYTLHJwn7HC2GG6P1cnvoua8rfxb9/Bfi7C3D3IPa9VmB33Q==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-openbsd-x64/-/lefthook-openbsd-x64-2.0.12.tgz",
+ "integrity": "sha512-zPcvUzs65GexRA37UHmaZqWuEGSU/zpBaPIY98MybXzzcJfCIf+O0oUQe2riMllwYGvNW0B1y3NOYRziDNe/vA==",
"cpu": [
"x64"
],
@@ -4552,9 +4562,9 @@
]
},
"node_modules/lefthook-windows-arm64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-windows-arm64/-/lefthook-windows-arm64-2.0.11.tgz",
- "integrity": "sha512-HBqW1qfAnmmbpet7gSWatB6H5YIFdGxCqzolMCLwY/0o8oPFiMwdNE5RGp5JMmhZdz/h3XlbaUlIhnxoW8dk5g==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-windows-arm64/-/lefthook-windows-arm64-2.0.12.tgz",
+ "integrity": "sha512-kgwxguS2GssoHM4SMTp+ArD/Gjg9q5MinD6iI5vSFpuJygD13ZWiXQQfESMHq9y/v1XkD0BdHTJej49dx8P+Vw==",
"cpu": [
"arm64"
],
@@ -4566,9 +4576,9 @@
]
},
"node_modules/lefthook-windows-x64": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/lefthook-windows-x64/-/lefthook-windows-x64-2.0.11.tgz",
- "integrity": "sha512-e5TYmV5cBZfRrhPVFCqjauegLI5CjdAd8exyAbMzGHkiwp3ZK145Su/pntgEP3d+ayS9mpgYPJmXYOSL7WHlyg==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/lefthook-windows-x64/-/lefthook-windows-x64-2.0.12.tgz",
+ "integrity": "sha512-Tf/VtSOtF3rBTc9dzRWROa+HuhqaiIV+Xp+1gzlx5+uCueLM0m87Rz6yd4IN5mL7TrDaNkiRXI3FvjCp0dUE4Q==",
"cpu": [
"x64"
],
@@ -4861,9 +4871,9 @@
}
},
"node_modules/lucide-react": {
- "version": "0.561.0",
- "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.561.0.tgz",
- "integrity": "sha512-Y59gMY38tl4/i0qewcqohPdEbieBy7SovpBL9IFebhc2mDd8x4PZSOsiFRkpPcOq6bj1r/mjH/Rk73gSlIJP2A==",
+ "version": "0.562.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.562.0.tgz",
+ "integrity": "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -5580,13 +5590,14 @@
}
},
"node_modules/next": {
- "version": "16.0.10",
- "resolved": "https://registry.npmjs.org/next/-/next-16.0.10.tgz",
- "integrity": "sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==",
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz",
+ "integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==",
"license": "MIT",
"dependencies": {
- "@next/env": "16.0.10",
+ "@next/env": "16.1.1",
"@swc/helpers": "0.5.15",
+ "baseline-browser-mapping": "^2.8.3",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
"styled-jsx": "5.1.6"
@@ -5598,14 +5609,14 @@
"node": ">=20.9.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "16.0.10",
- "@next/swc-darwin-x64": "16.0.10",
- "@next/swc-linux-arm64-gnu": "16.0.10",
- "@next/swc-linux-arm64-musl": "16.0.10",
- "@next/swc-linux-x64-gnu": "16.0.10",
- "@next/swc-linux-x64-musl": "16.0.10",
- "@next/swc-win32-arm64-msvc": "16.0.10",
- "@next/swc-win32-x64-msvc": "16.0.10",
+ "@next/swc-darwin-arm64": "16.1.1",
+ "@next/swc-darwin-x64": "16.1.1",
+ "@next/swc-linux-arm64-gnu": "16.1.1",
+ "@next/swc-linux-arm64-musl": "16.1.1",
+ "@next/swc-linux-x64-gnu": "16.1.1",
+ "@next/swc-linux-x64-musl": "16.1.1",
+ "@next/swc-win32-arm64-msvc": "16.1.1",
+ "@next/swc-win32-x64-msvc": "16.1.1",
"sharp": "^0.34.4"
},
"peerDependencies": {
@@ -6034,9 +6045,9 @@
}
},
"node_modules/rollup": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
- "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
+ "version": "4.54.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz",
+ "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6050,28 +6061,28 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.53.3",
- "@rollup/rollup-android-arm64": "4.53.3",
- "@rollup/rollup-darwin-arm64": "4.53.3",
- "@rollup/rollup-darwin-x64": "4.53.3",
- "@rollup/rollup-freebsd-arm64": "4.53.3",
- "@rollup/rollup-freebsd-x64": "4.53.3",
- "@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
- "@rollup/rollup-linux-arm-musleabihf": "4.53.3",
- "@rollup/rollup-linux-arm64-gnu": "4.53.3",
- "@rollup/rollup-linux-arm64-musl": "4.53.3",
- "@rollup/rollup-linux-loong64-gnu": "4.53.3",
- "@rollup/rollup-linux-ppc64-gnu": "4.53.3",
- "@rollup/rollup-linux-riscv64-gnu": "4.53.3",
- "@rollup/rollup-linux-riscv64-musl": "4.53.3",
- "@rollup/rollup-linux-s390x-gnu": "4.53.3",
- "@rollup/rollup-linux-x64-gnu": "4.53.3",
- "@rollup/rollup-linux-x64-musl": "4.53.3",
- "@rollup/rollup-openharmony-arm64": "4.53.3",
- "@rollup/rollup-win32-arm64-msvc": "4.53.3",
- "@rollup/rollup-win32-ia32-msvc": "4.53.3",
- "@rollup/rollup-win32-x64-gnu": "4.53.3",
- "@rollup/rollup-win32-x64-msvc": "4.53.3",
+ "@rollup/rollup-android-arm-eabi": "4.54.0",
+ "@rollup/rollup-android-arm64": "4.54.0",
+ "@rollup/rollup-darwin-arm64": "4.54.0",
+ "@rollup/rollup-darwin-x64": "4.54.0",
+ "@rollup/rollup-freebsd-arm64": "4.54.0",
+ "@rollup/rollup-freebsd-x64": "4.54.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.54.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.54.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.54.0",
+ "@rollup/rollup-linux-arm64-musl": "4.54.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.54.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.54.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.54.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.54.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.54.0",
+ "@rollup/rollup-linux-x64-gnu": "4.54.0",
+ "@rollup/rollup-linux-x64-musl": "4.54.0",
+ "@rollup/rollup-openharmony-arm64": "4.54.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.54.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.54.0",
+ "@rollup/rollup-win32-x64-gnu": "4.54.0",
+ "@rollup/rollup-win32-x64-msvc": "4.54.0",
"fsevents": "~2.3.2"
}
},
@@ -6597,9 +6608,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz",
- "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"dev": true,
"funding": [
{
@@ -6680,13 +6691,13 @@
}
},
"node_modules/vite": {
- "version": "7.2.7",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.7.tgz",
- "integrity": "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==",
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz",
+ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "esbuild": "^0.25.0",
+ "esbuild": "^0.27.0",
"fdir": "^6.5.0",
"picomatch": "^4.0.3",
"postcss": "^8.5.6",
@@ -6755,9 +6766,9 @@
}
},
"node_modules/vite-tsconfig-paths": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-6.0.0.tgz",
- "integrity": "sha512-0lGkM62rud1ShKWLbJpbTHPoJuZIL9QW1ecCueDhqxWrStIRsyHapBQ4eV05tBqrW9z6jkp9ybBVgLSWp+Mv1A==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-6.0.3.tgz",
+ "integrity": "sha512-7bL7FPX/DSviaZGYUKowWF1AiDVWjMjxNbE8lyaVGDezkedWqfGhlnQ4BZXre0ZN5P4kAgIJfAlgFDVyjrCIyg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6821,19 +6832,19 @@
}
},
"node_modules/vitest": {
- "version": "4.0.15",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.15.tgz",
- "integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==",
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.16.tgz",
+ "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/expect": "4.0.15",
- "@vitest/mocker": "4.0.15",
- "@vitest/pretty-format": "4.0.15",
- "@vitest/runner": "4.0.15",
- "@vitest/snapshot": "4.0.15",
- "@vitest/spy": "4.0.15",
- "@vitest/utils": "4.0.15",
+ "@vitest/expect": "4.0.16",
+ "@vitest/mocker": "4.0.16",
+ "@vitest/pretty-format": "4.0.16",
+ "@vitest/runner": "4.0.16",
+ "@vitest/snapshot": "4.0.16",
+ "@vitest/spy": "4.0.16",
+ "@vitest/utils": "4.0.16",
"es-module-lexer": "^1.7.0",
"expect-type": "^1.2.2",
"magic-string": "^0.30.21",
@@ -6861,10 +6872,10 @@
"@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0",
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
- "@vitest/browser-playwright": "4.0.15",
- "@vitest/browser-preview": "4.0.15",
- "@vitest/browser-webdriverio": "4.0.15",
- "@vitest/ui": "4.0.15",
+ "@vitest/browser-playwright": "4.0.16",
+ "@vitest/browser-preview": "4.0.16",
+ "@vitest/browser-webdriverio": "4.0.16",
+ "@vitest/ui": "4.0.16",
"happy-dom": "*",
"jsdom": "*"
},
diff --git a/package.json b/package.json
index 79202c3..49fded4 100644
--- a/package.json
+++ b/package.json
@@ -22,42 +22,43 @@
"test": "npm run test:unit && npm run test:e2e"
},
"dependencies": {
- "@clerk/nextjs": "^6.36.1",
- "@clerk/themes": "^2.4.43",
+ "@clerk/nextjs": "^6.36.5",
+ "@clerk/themes": "^2.4.46",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-slot": "^1.2.4",
"@vercel/analytics": "^1.6.1",
"@vercel/speed-insights": "^1.3.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
- "lucide-react": "^0.561.0",
- "next": "^16.0.10",
+ "lucide-react": "^0.562.0",
+ "next": "^16.1.1",
"next-themes": "^0.4.6",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"tailwind-merge": "^3.4.0"
},
"devDependencies": {
- "@biomejs/biome": "^2.3.8",
- "@clerk/testing": "^1.13.22",
+ "@biomejs/biome": "^2.3.10",
+ "@clerk/testing": "^1.13.26",
"@playwright/test": "^1.57.0",
"@tailwindcss/postcss": "^4",
"@testing-library/jest-dom": "^6.9.1",
- "@testing-library/react": "^16.3.0",
+ "@testing-library/react": "^16.3.1",
"@testing-library/user-event": "^14.6.1",
- "@types/node": "^25.0.2",
+ "@types/node": "^25.0.3",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^5.1.2",
"babel-plugin-react-compiler": "1.0.0",
- "baseline-browser-mapping": "^2.9.5",
+ "baseline-browser-mapping": "^2.9.11",
+ "dotenv": "^17.2.3",
"jsdom": "^27.3.0",
- "lefthook": "^2.0.9",
+ "lefthook": "^2.0.12",
"markdownlint-cli2": "^0.20.0",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "5.9.3",
- "vite-tsconfig-paths": "^6.0.0",
- "vitest": "^4.0.15"
+ "vite-tsconfig-paths": "^6.0.3",
+ "vitest": "^4.0.16"
}
}
diff --git a/playwright.config.ts b/playwright.config.ts
index f42f6b0..00670b1 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -1,12 +1,13 @@
-import { defineConfig, devices } from "@playwright/test";
-
+import path from "node:path";
+import { defineConfig } from "@playwright/test";
/**
- * Read environment variables from file.
+ * Read environment variables from file (local development only).
+ * In CI/Vercel, env vars are set directly — dotenv is a no-op when files don't exist.
* https://github.com/motdotla/dotenv
*/
-// import dotenv from 'dotenv';
-// import path from 'path';
-// dotenv.config({ path: path.resolve(__dirname, '.env') });
+import dotenv from "dotenv";
+
+dotenv.config({ path: path.resolve(__dirname, ".env.local") });
// Use process.env.PORT by default and fallback to port 3000
const PORT = process.env.PORT || 3000;
@@ -32,9 +33,10 @@ export default defineConfig({
workers: process.env.CI ? 1 : undefined, // Playwright recommends 1
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ // open: "never" prevents blocking terminal; run `npx playwright show-report` to view
reporter: process.env.CI
? [["html", { outputFolder: HTML_REPORT, open: "never" }], ["github"]]
- : [["html", { outputFolder: HTML_REPORT }]], // Default: serves report only on failure
+ : [["html", { outputFolder: HTML_REPORT, open: "never" }]],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
@@ -54,53 +56,30 @@ export default defineConfig({
}),
},
- /* Configure projects for major browsers */
+ /*
+ * Browser projects — each test runs on all active browsers.
+ * Viewport is set per-test via test.use(), not here.
+ * This separates browser testing (cross-browser bugs) from viewport testing (responsive design).
+ */
projects: [
// Global setup for Clerk Testing Token (runs once before all tests)
{ name: "setup", testMatch: /global\.setup\.ts/ },
{
name: "chromium",
- use: { ...devices["Desktop Chrome"] },
+ use: { browserName: "chromium" },
dependencies: ["setup"],
},
- // {
- // name: "firefox",
- // use: { ...devices["Desktop Firefox"] },
- // dependencies: ["setup"],
- // },
-
- // Desktop Webkit removed - redundant with Mobile Safari for Safari engine coverage.
- // Mobile Safari tests the same Webkit engine with mobile viewport (iPhone).
- // Uncomment if you specifically need macOS Desktop Safari testing:
- // {
- // name: "webkit",
- // use: { ...devices["Desktop Safari"] },
- // dependencies: ["setup"],
- // },
-
- /* Test against mobile viewports. */
- // {
- // name: "Mobile Chrome",
- // use: { ...devices["Pixel 5"] },
- // dependencies: ["setup"],
- // },
{
- name: "Mobile Safari",
- use: { ...devices["iPhone 12"] },
+ name: "webkit",
+ use: { browserName: "webkit" },
dependencies: ["setup"],
},
- /* Test against branded browsers. */
// {
- // name: 'Microsoft Edge',
- // use: { ...devices['Desktop Edge'], channel: 'msedge' },
- // dependencies: ["setup"],
- // },
- // {
- // name: 'Google Chrome',
- // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
+ // name: "firefox",
+ // use: { browserName: "firefox" },
// dependencies: ["setup"],
// },
],
diff --git a/sidebar.md b/sidebar.md
new file mode 100644
index 0000000..0c0dfb1
--- /dev/null
+++ b/sidebar.md
@@ -0,0 +1,110 @@
+# Desktop navigation: Persistent Left Sidebar Navigation (>= `sm`)
+
+## Figma Visual Reference
+
+PLEASE ANALYSE VISUALLY: `x_docs/figma/nav-over-breakpoints.jpg`
+
+Sidebar visual details:
+
+
+
+### Screenshot 3: Icon-Only Sidebar (640–1023px)
+
+- **Persistent rail navigation** (narrow vertical bar)
+- Icons only, no labels visible
+- **Interaction**: When user clicks an icon in the rail (screenshot 3), it navigates directly, no tooltip/popover
+- **Top bar** now shows full logo ("DevOverflow") + search field
+- Two-column layout: rail + main content
+
+### Screenshot 4: Full Sidebar (1024–1279px)
+
+- **Persistent sidebar** with icons + labels
+- Fixed width (appears ~220px / `w-56`)
+- Same nav items as mobile sheet
+- Two-column layout: sidebar + main content
+
+### Screenshot 5: Three-Column (≥ 1280px)
+
+- Full left sidebar (unchanged)
+- Main content (centre)
+- **Right sidebar** with contextual widgets e.g. "Top Questions" in screenshot (5)
+- Three-column layout
+- Pages requiring right sidebar: root, ask-question, collections.
+
+
+
+Breakpoint analysis:
+
+
+
+```markdown
+| # | Breakpoint | Range | Layout |
+|:--|:-----------|:------|:-------|
+| 1 | `< sm` | 0–639px | Mobile, nav closed |
+| 2 | `< sm` | 0–639px | Mobile, nav open (sheet) |
+| 3 | `sm` to `lg` | 640–1023px | Icon-only sidebar |
+| 4 | `lg` to `xl` | 1024–1279px | Full sidebar |
+| 5 | `≥ xl` | 1280px+ | Full sidebar + right sidebar |
+```
+
+
+
+## Important Implementation Notes
+
+
+
+This sidebar is the desktop version of `components/mobile-nav`:
+
+- Applies to all pages
+- The links used must mirror what is already implemented
+- The buttons must be the same too - "Sign in", "Sign up", "Sign out"
+- Links are positioned at the top, whilst buttons are aligned at the bottom. Essentially, two groups placed in different positions.
+ - ❓🔥 Does `mobile-nav.tsx` need to be refactored?
+- Active state of route - mirror `mobile-nav.tsx`
+- Styling - centralised theming like `mobile-nav.tsx` EXCEPT use `background` shadcn/ui semantic colour.
+- Mobile-first approach: Tailwind uses mobile-first breakpoints. Unprefixed utilities apply to all screens; prefixed utilities (e.g., `sm:`, `md:`, `lg:` etc.) apply at that breakpoint *and above*.
+
+
+Current Route Structure:
+
+```text
+app/(root)
+├── (with-right-sidebar)
+│ ├── layout.tsx ← includes Future RightSidebar
+│ ├── page.tsx ← home
+│ ├── ask-question
+│ │ └── page.tsx
+│ └── collections
+│ └── page.tsx
+├── (without-right-sidebar)
+│ ├── community
+│ │ └── page.tsx
+│ ├── jobs
+│ │ └── page.tsx
+│ ├── profile
+│ │ └── page.tsx
+│ └── tags
+│ └── page.tsx
+└── layout.tsx ← shared: Navbar + LeftSidebar
+```
+
+## Flex Properties
+
+Various flex properties that could be helpful
+
+
+
+| Property | Docs | Description | Applicable? |
+|:---------|:-----|:------------|:------------|
+| [Flex Direction](https://tailwindcss.com/docs/flex-direction) | `flex-col` | Sets item direction in container (row, column, row-reverse, column-reverse) | ✅ Core — use `flex-col` to stack nav groups vertically |
+| [Justify Content](https://tailwindcss.com/docs/justify-content) | `justify-between` | Positions items along main axis; spreads items to container edges | ✅ Critical — use `justify-between` to push top 6 links up, bottom 2 down |
+| [Align Items](https://tailwindcss.com/docs/align-items) | `items-center` | Aligns items along cross-axis (perpendicular to main) | ✅ Useful — centre-align icons/labels horizontally within sidebar width |
+| [Flex Grow](https://tailwindcss.com/docs/flex-grow) | `grow` | Defines how items grow to fill available space proportionally | ⚠️ Optional — useful for spacer elements if you need more than two groups |
+| [Flex Shrink](https://tailwindcss.com/docs/flex-shrink) | `shrink-0` | Prevents items from shrinking when space is limited | ⚠️ Optional — use `shrink-0` on nav links to maintain consistent dimensions |
+| [Flex Basis](https://tailwindcss.com/docs/flex-basis) | `basis-16` | Sets initial size of item before growing/shrinking | ⚠️ Optional — could set sidebar width at breakpoints (e.g., icon-only rail) |
+| [Flex](https://tailwindcss.com/docs/flex) | `flex-1` | Shorthand for grow + shrink + basis together | ⚠️ Optional — `flex-1` on spacer if using spacer approach (prefer `justify-between`) |
+| [Align Self](https://tailwindcss.com/docs/align-self) | `self-end` | Overrides container alignment for a specific item | ⚠️ Low — only if individual items need different cross-axis alignment |
+
+
+
+Remember, analyse `mobile-nav.tsx` - does it use `flex` already, and if not, should we refactor?
diff --git a/x_docs/mine/nav_mobile_sidebar-and-rail.md b/x_docs/mine/nav_mobile_sidebar-and-rail.md
index 464d752..6455e39 100644
--- a/x_docs/mine/nav_mobile_sidebar-and-rail.md
+++ b/x_docs/mine/nav_mobile_sidebar-and-rail.md
@@ -9,10 +9,10 @@ This document explains how the navigation system works across breakpoints, and h
The app has **three navigation contexts** that share the same nav items but render differently:
| Context | Breakpoint | Container | NavLink Variant |
-|---------|------------|-----------|-----------------|
-| Mobile Nav | `` | `icon-only` |
-| Left Sidebar | `≥lg` (1024px+) | Persistent `` | `full` (default) |
+| --------- | ------------ | ----------- | ----------------- |
+| Mobile Nav | `` | `rail` (icon-only) |
+| Left Sidebar | `≥lg` (1024px+) | Persistent `` | `rail` (icon + label) |
---
@@ -23,7 +23,7 @@ The app has **three navigation contexts** that share the same nav items but rend
│ │
│ MOBILE (<640px) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
-│ │ Navbar: [Logo] [Theme] [Hamburger] │ │
+│ │ Navbar: [Logo] [Theme] [Hamburger] │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ │ When hamburger tapped → Sheet slides in from left │ │
@@ -31,15 +31,18 @@ The app has **three navigation contexts** that share the same nav items but rend
│ │ ┌──────────────────┐ │ │
│ │ │ Sheet (overlay) │ │ │
│ │ │ ┌──────────────┐ │ │ │
-│ │ │ │ 🏠 Home │ │ ← NavLink (full) │ │
-│ │ │ │ 👥 Community │ │ ← NavLink (full) │ │
-│ │ │ │ ⭐ Collections│ │ ← NavLink (full) │ │
-│ │ │ │ 💼 Find Jobs │ │ ← NavLink (full) │ │
-│ │ │ │ 🏷️ Tags │ │ ← NavLink (full) │ │
-│ │ │ │ ❓ Ask │ │ ← NavLink (full) │ │
+│ │ │ │ 🏠 Home │ │ ← NavLink (mobile) │ │
+│ │ │ │ 👥 Community │ │ ← NavLink (mobile) │ │
+│ │ │ │ ⭐ Collections│ │ ← NavLink (mobile) │ │
+│ │ │ │ 💼 Find Jobs │ │ ← NavLink (mobile) │ │
+│ │ │ │ 🏷️ Tags │ │ ← NavLink (mobile) │ │
+│ │ │ │ ❓ Ask │ │ ← NavLink (mobile) │ │
+│ │ │ └──────────────┘ │ │ │
+│ │ │ │ │ │
+│ │ │ ┌──────────────┐ │ ← SignedOut: auth buttons │ │
+│ │ │ │ [Sign in] │ │ ← SignedIn: UserButton avatar │ │
+│ │ │ │ [Sign up] │ │ │ │
│ │ │ └──────────────┘ │ │ │
-│ │ │ [Sign in] │ │ │
-│ │ │ [Sign up] │ │ │
│ │ └──────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
@@ -50,377 +53,203 @@ The app has **three navigation contexts** that share the same nav items but rend
│ │
│ TABLET (640px - 1023px) - Icon-only Rail │
│ ┌─────────────────────────────────────────────────────────────────┐ │
-│ │ Navbar: [Logo] [Search] [Theme] [Auth] │ │
+│ │ Navbar: [Logo] [Search] [Theme] [Auth] (SignedOut) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ┌────────┬────────────────────────────────────────────────────────┐ │
│ │ Rail │ │ │
│ │ ~64px │ Main Content │ │
│ │ │ │ │
-│ │ 🏠 │ ← NavLink (icon-only) │ │
-│ │ 👥 │ ← NavLink (icon-only) │ │
-│ │ ⭐ │ ← NavLink (icon-only) │ │
-│ │ 💼 │ ← NavLink (icon-only) │ │
-│ │ 🏷️ │ ← NavLink (icon-only) │ │
-│ │ ❓ │ ← NavLink (icon-only) │ │
+│ │ 🏠 │ ← NavLink (rail) icon-only │ │
+│ │ 👥 │ │ │
+│ │ ⭐ │ │ │
+│ │ 💼 │ │ │
+│ │ 🏷️ │ │ │
+│ │ ❓ │ │ │
│ │ │ │ │
+│ │ 👤 │ ← UserButton (SignedIn only) │ │
│ └────────┴────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ │
-│ DESKTOP (1024px - 1279px) - Full Sidebar │
+│ DESKTOP (≥1024px) - Full Sidebar │
│ ┌─────────────────────────────────────────────────────────────────┐ │
-│ │ Navbar: [Logo] [Search] [Theme] [Auth] │ │
+│ │ Navbar: [Logo] [Search] [Theme] [Auth] (SignedOut) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ┌────────────────┬────────────────────────────────────────────────┐ │
│ │ Sidebar ~220px │ │ │
│ │ │ Main Content │ │
│ │ 🏠 Home │ │ │
-│ │ 👥 Community │ ← NavLink (full) - SAME as mobile sheet │ │
+│ │ 👥 Community │ ← NavLink (rail) with labels at lg+ │ │
│ │ ⭐ Collections │ │ │
│ │ 💼 Find Jobs │ │ │
│ │ 🏷️ Tags │ │ │
│ │ ❓ Ask │ │ │
│ │ │ │ │
+│ │ 👤 UserButton │ ← UserButton (SignedIn only) │ │
│ └────────────────┴────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
-
-┌─────────────────────────────────────────────────────────────────────────┐
-│ │
-│ WIDE DESKTOP (≥1280px) - Full Sidebar + Right Sidebar │
-│ ┌─────────────────────────────────────────────────────────────────┐ │
-│ │ Navbar: [Logo] [Search] [Theme] [Auth] │ │
-│ └─────────────────────────────────────────────────────────────────┘ │
-│ ┌────────────────┬──────────────────────────────┬─────────────────┐ │
-│ │ Sidebar ~220px │ │ Right ~300px │ │
-│ │ │ Main Content │ │ │
-│ │ 🏠 Home │ │ Top Questions │ │
-│ │ 👥 Community │ │ Popular Tags │ │
-│ │ ⭐ Collections │ │ │ │
-│ │ 💼 Find Jobs │ │ │ │
-│ │ 🏷️ Tags │ │ │ │
-│ │ ❓ Ask │ │ │ │
-│ │ │ │ │ │
-│ └────────────────┴──────────────────────────────┴─────────────────┘ │
-│ │
-└─────────────────────────────────────────────────────────────────────────┘
-```
-
-## Key Insights — CRITICAL: this section must be evaluated for consistency against rest of doc
-
-### Containers & Components
-
-NavLink doesn't know what container it's in. It just renders itself.
-
-```text
- ┌─────────────────────────────────────────────────────────────────┐
- │ │
- │ THREE different CONTAINERS, using NavLink inside: │
- │ │
- │ 1. MobileNav (Sheet) ← Container is │
- │ └── ← Same NavLink component │
- │ │
- │ 2. LeftSidebar (icon rail) ← Container is persistent │
- │ └── │
- │ │
- │ 3. LeftSidebar (full) ← Container is persistent │ │ │ │
-│ └─────────────────┘ └─────────────────┘ │
+│ SAME NavLink component, DIFFERENT containers & variants: │
│ │
-│ Icon Rail (persistent) │
-│ ┌─────────────────┐ │
-│ │ │ │
-│ │ ← Different variant │
-│ │ │
-│ │ │
-│ │ │ │
-│ └─────────────────┘ │
+│ MobileNav (Sheet) LeftSidebar (persistent) │
+│ ┌─────────────────┐ ┌─────────────────┐ │
+│ │ │ │ │ │
+│ │ │ ← mobile │ │ (default)│ variant= │ (responsive)
+│ │ │ │ "rail" /> │ │
+│ │ │ │ │ │
+│ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
-### NavLink Variants
-
-Only **TWO variants** needed:
-
-```tsx
-// components/navigation/nav-link.tsx
-
-type NavLinkProps = NavLinkType & {
- onClick?: () => void;
- variant?: "full" | "icon-only"; // Add this
-};
-
-export function NavLink({
- imgURL,
- route,
- label,
- onClick,
- variant = "full" // Default to full (icon + label)
-}: NavLinkProps) {
- // ... active state logic stays the same ...
-
- return (
-
-
- {variant === "full" && {label} } {/* Conditionally show label */}
-
- );
-}
-```
+### Containers & Components
-### Usage in Different Contexts
+| Component | Container Type | When Visible | NavLink Variant | Auth Section |
+| :--------- | :-------------- | :------------ | :--------------- | :------------- |
+| MobileNav | Sheet (overlay) | ` | ≥sm | `rail` (responsive) | SignedIn only (UserButton) |
-```tsx
-// MobileNav - uses default "full" variant
-
+### Variants
-// LeftSidebar at lg+ - uses default "full" variant
-
+Two variants, but `"rail"` is **responsive** — it handles its own breakpoint transformation internally via Tailwind classes.
-// LeftSidebar at sm-lg - uses "icon-only" variant
-
+```text
+┌────────────────────────────────────────────────────────────────┐
+│ │
+│ NavLink variants: │
+│ │
+│ 1. "mobile" (default) 2. "rail" (responsive) │
+│ ┌──────────────────┐ ┌─────────┐ ┌──────────────────┐ │
+│ │ 🏠 Home │ │ 🏠 │ → │ 🏠 Home │ │
+│ └──────────────────┘ └─────────┘ └──────────────────┘ │
+│ Always icon + label sm-lg: icon lg+: icon + label │
+│ Generous padding (py-3) Compact (40px) Tight padding (p-2) │
+│ │
+│ Used in: Used in: │
+│ • Mobile sheet • LeftSidebar (handles both states) │
+│ │
+└────────────────────────────────────────────────────────────────┘
```
---
## File Structure
-### Current Structure
-
```text
components/navigation/
-├── constants.ts ← NAV_LINKS array (shared data)
-├── navbar.tsx ← Top bar with logo, search, auth
-├── mobile-nav.tsx ← Sheet drawer for mobile
-├── nav-link.tsx ← Reusable nav link component
-├── full-logo.tsx ← Theme-aware logo
-└── theme-toggle.tsx ← Dark/light mode toggle
-```
-
-### After Adding LeftSidebar
-
-```text
-components/navigation/
-├── constants.ts ← NAV_LINKS array (shared data)
-├── navbar.tsx ← Top bar
-├── mobile-nav.tsx ← Sheet drawer for mobile (
- {/* Contains MobileNav hamburger */}
- {children}
->
```
-
-### Future Layout (with LeftSidebar)
-
-```tsx
-// app/(root)/layout.tsx
-<>
-
-
- {/* Hidden on mobile */}
- {children}
-
->
-```
-
-The LeftSidebar handles its own responsive behaviour internally:
-
-- `sm` to `lg`: Shows icon-only rail
-- `≥lg`: Shows full sidebar with labels
-
-```tsx
-// Simplified LeftSidebar concept
-export function LeftSidebar() {
- return (
-
- {NAV_LINKS.map((link) => (
-
- ))}
-
- );
-}
+┌─────────────────────────────────┐
+│ Navbar (sticky top) │
+├──────────┬──────────────────────┤
+│LeftSidebar│ {children} │
+│ (sticky) │ │
+└──────────┴──────────────────────┘
```
-> **Note**: The exact responsive variant switching can be done via:
->
-> - CSS classes that show/hide label
-> - A hook that detects breakpoint
-> - Render both and use CSS to toggle visibility
+The LeftSidebar handles its own visibility — no props needed from layout.
---
-## Implementation Order
+## Why nav-links.constants.ts is Separate
-Recommended sequence:
-
-1. ✅ **MobileNav** - Already working
-2. 🔲 **Polish MobileNav styling** - Perfect the look
-3. 🔲 **Add `variant` prop to NavLink** - Small change (~15 lines)
-4. 🔲 **Create LeftSidebar** - Uses same NavLink, same constants
-5. 🔲 **Wire up in layout** - Add to `(root)/layout.tsx`
+The `NAV_LINKS` array is in its own file because:
-**Why this order?** The styling you perfect in MobileNav transfers directly to LeftSidebar (full mode) since they use the same NavLink component.
+1. **Single source of truth** — update nav items once, all components update
+2. **Multiple consumers** — used by MobileNav and LeftSidebar
+3. **No "use client"** — pure data, can be imported by server components
+4. **No circular imports** — avoids issues if components import from each other
---
## Summary
| Concept | Explanation |
-|---------|-------------|
-| **NavLink** | Reusable component with `full` and `icon-only` variants |
-| **constants.ts** | Single source of truth for nav items |
-| **MobileNav** | Sheet overlay, uses NavLink (full) |
-| **LeftSidebar** | Persistent aside, uses NavLink (icon-only at sm-lg, full at lg+) |
-| **Container agnostic** | NavLink doesn't know if it's in a Sheet or sidebar |
+| --------- | ------------- |
+| **NavLink** | Reusable component with `mobile` and `rail` variants |
+| **nav-links.constants.ts** | Single source of truth for nav items |
+| **MobileNav** | Sheet overlay, uses NavLink (`mobile` variant, default) |
+| **LeftSidebar** | Persistent aside, uses NavLink (`rail` variant — responsive) |
+| **Container agnostic** | NavLink doesn't know whether it's in a Sheet or sidebar |
+| **Auth flow** | Navbar (SignedOut), Sidebar (SignedIn), Mobile (both) |