@shipsite.dev/components 0.2.43 → 0.2.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/layout/Header.d.ts.map +1 -1
- package/dist/layout/Header.js +2 -1
- package/dist/layout/Header.js.map +1 -1
- package/dist/marketing/FAQ.d.ts.map +1 -1
- package/dist/marketing/FAQ.js +3 -4
- package/dist/marketing/FAQ.js.map +1 -1
- package/dist/ui/client-only.d.ts +10 -0
- package/dist/ui/client-only.d.ts.map +1 -0
- package/dist/ui/client-only.js +12 -0
- package/dist/ui/client-only.js.map +1 -0
- package/dist/ui/locale-switcher.d.ts.map +1 -1
- package/dist/ui/locale-switcher.js +12 -2
- package/dist/ui/locale-switcher.js.map +1 -1
- package/package.json +1 -1
- package/src/layout/Header.tsx +34 -27
- package/src/marketing/FAQ.tsx +12 -16
- package/src/ui/client-only.tsx +13 -0
- package/src/ui/locale-switcher.tsx +12 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/layout/Header.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/layout/Header.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,MAAM,4CAoFrB"}
|
package/dist/layout/Header.js
CHANGED
|
@@ -6,10 +6,11 @@ import { Button } from '../ui/button';
|
|
|
6
6
|
import { Navbar, NavbarLeft, NavbarRight } from '../ui/navbar';
|
|
7
7
|
import { Sheet, SheetTrigger, SheetContent, SheetTitle, } from '../ui/sheet';
|
|
8
8
|
import { ThemeToggle } from '../ui/theme-toggle';
|
|
9
|
+
import { ClientOnly } from '../ui/client-only';
|
|
9
10
|
export function Header() {
|
|
10
11
|
const { siteName, logo, navigation, locale, defaultLocale } = useShipSite();
|
|
11
12
|
const resolveHref = useResolveHref();
|
|
12
13
|
const logoSrc = typeof logo === 'string' ? logo : logo?.light;
|
|
13
|
-
return (_jsx("header", { className: "sticky top-0 z-50 bg-background/80 backdrop-blur-lg border-b border-border", children: _jsx("div", { className: "container-main", children: _jsxs(Navbar, { children: [_jsx(NavbarLeft, { children: _jsxs("a", { href: locale === defaultLocale ? '/' : `/${locale}`, className: "flex items-center gap-2", children: [logoSrc && (_jsx("img", { src: logoSrc, alt: siteName, className: "h-8 w-auto" })), _jsx("span", { className: "font-semibold text-lg text-foreground", children: siteName })] }) }), _jsxs(NavbarRight, { className: "hidden md:flex", children: [navigation.items.map((item) => (_jsx("a", { href: resolveHref(item.href), className: "text-sm font-medium text-muted-foreground hover:text-foreground transition-colors", children: item.label }, item.href))), _jsx(ThemeToggle, {}), navigation.cta && (_jsx(Button, { asChild: true, size: "sm", children: _jsx("a", { href: navigation.cta.href, children: navigation.cta.label }) }))] }), _jsx("div", { className: "md:hidden", children: _jsxs(Sheet, { children: [_jsx(SheetTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Toggle menu", children: _jsx(Menu, { className: "size-5" }) }) }), _jsxs(SheetContent, { side: "right", children: [_jsx(SheetTitle, { className: "sr-only", children: "Navigation" }), _jsxs("nav", { className: "flex flex-col gap-4 mt-8", children: [navigation.items.map((item) => (_jsx("a", { href: resolveHref(item.href), className: "text-sm font-medium text-muted-foreground hover:text-foreground transition-colors", children: item.label }, item.href))), navigation.cta && (_jsx(Button, { asChild: true, className: "mt-2", children: _jsx("a", { href: navigation.cta.href, children: navigation.cta.label }) }))] })] })] }) })] }) }) }));
|
|
14
|
+
return (_jsx("header", { className: "sticky top-0 z-50 bg-background/80 backdrop-blur-lg border-b border-border", children: _jsx("div", { className: "container-main", children: _jsxs(Navbar, { children: [_jsx(NavbarLeft, { children: _jsxs("a", { href: locale === defaultLocale ? '/' : `/${locale}`, className: "flex items-center gap-2", children: [logoSrc && (_jsx("img", { src: logoSrc, alt: siteName, className: "h-8 w-auto" })), _jsx("span", { className: "font-semibold text-lg text-foreground", children: siteName })] }) }), _jsxs(NavbarRight, { className: "hidden md:flex", children: [navigation.items.map((item) => (_jsx("a", { href: resolveHref(item.href), className: "text-sm font-medium text-muted-foreground hover:text-foreground transition-colors", children: item.label }, item.href))), _jsx(ThemeToggle, {}), navigation.cta && (_jsx(Button, { asChild: true, size: "sm", children: _jsx("a", { href: navigation.cta.href, children: navigation.cta.label }) }))] }), _jsx("div", { className: "md:hidden", children: _jsx(ClientOnly, { fallback: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Toggle menu", children: _jsx(Menu, { className: "size-5" }) }), children: _jsxs(Sheet, { children: [_jsx(SheetTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Toggle menu", children: _jsx(Menu, { className: "size-5" }) }) }), _jsxs(SheetContent, { side: "right", children: [_jsx(SheetTitle, { className: "sr-only", children: "Navigation" }), _jsxs("nav", { className: "flex flex-col gap-4 mt-8", children: [navigation.items.map((item) => (_jsx("a", { href: resolveHref(item.href), className: "text-sm font-medium text-muted-foreground hover:text-foreground transition-colors", children: item.label }, item.href))), navigation.cta && (_jsx(Button, { asChild: true, className: "mt-2", children: _jsx("a", { href: navigation.cta.href, children: navigation.cta.label }) }))] })] })] }) }) })] }) }) }));
|
|
14
15
|
}
|
|
15
16
|
//# sourceMappingURL=Header.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/layout/Header.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE1E,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EACL,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/layout/Header.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FAQ.d.ts","sourceRoot":"","sources":["../../src/marketing/FAQ.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FAQ.d.ts","sourceRoot":"","sources":["../../src/marketing/FAQ.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,YAAY,2CAY3D;AAED,UAAU,QAAQ;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,QAAQ,2CAgBjE"}
|
package/dist/marketing/FAQ.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
'use client';
|
|
2
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDownIcon } from 'lucide-react';
|
|
3
3
|
import { Section } from '../ui/section';
|
|
4
|
-
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent, } from '../ui/accordion';
|
|
5
4
|
export function FAQItem({ question, children }) {
|
|
6
|
-
return (_jsxs(
|
|
5
|
+
return (_jsxs("details", { className: "border-border dark:border-border/15 border-b group", children: [_jsxs("summary", { className: "flex flex-1 items-center justify-between py-4 text-left text-md font-medium transition-all hover:underline cursor-pointer list-none [&::-webkit-details-marker]:hidden", children: [question, _jsx(ChevronDownIcon, { className: "text-muted-foreground pointer-events-none size-4 shrink-0 transition-transform duration-200 group-open:rotate-180" })] }), _jsx("div", { className: "pb-4 text-sm text-muted-foreground leading-relaxed", children: children })] }));
|
|
7
6
|
}
|
|
8
7
|
export function FAQ({ id, title, description, children }) {
|
|
9
|
-
return (_jsx(Section, { id: id, children: _jsxs("div", { className: "container-main max-w-3xl", children: [(title || description) && (_jsxs("div", { className: "text-center mb-12", children: [title && _jsx("h2", { className: "text-3xl md:text-4xl font-bold text-foreground mb-4", children: title }), description && _jsx("p", { className: "text-lg text-muted-foreground", children: description })] })), _jsx(
|
|
8
|
+
return (_jsx(Section, { id: id, children: _jsxs("div", { className: "container-main max-w-3xl", children: [(title || description) && (_jsxs("div", { className: "text-center mb-12", children: [title && _jsx("h2", { className: "text-3xl md:text-4xl font-bold text-foreground mb-4", children: title }), description && _jsx("p", { className: "text-lg text-muted-foreground", children: description })] })), _jsx("div", { "data-slot": "accordion", "data-orientation": "vertical", children: children })] }) }));
|
|
10
9
|
}
|
|
11
10
|
//# sourceMappingURL=FAQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FAQ.js","sourceRoot":"","sources":["../../src/marketing/FAQ.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FAQ.js","sourceRoot":"","sources":["../../src/marketing/FAQ.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAOxC,MAAM,UAAU,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAgB;IAC1D,OAAO,CACL,mBAAS,SAAS,EAAC,oDAAoD,aACrE,mBAAS,SAAS,EAAC,wKAAwK,aACxL,QAAQ,EACT,KAAC,eAAe,IAAC,SAAS,EAAC,mHAAmH,GAAG,IACzI,EACV,cAAK,SAAS,EAAC,oDAAoD,YAChE,QAAQ,GACL,IACE,CACX,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAY;IAChE,OAAO,CACL,KAAC,OAAO,IAAC,EAAE,EAAE,EAAE,YACb,eAAK,SAAS,EAAC,0BAA0B,aACtC,CAAC,KAAK,IAAI,WAAW,CAAC,IAAI,CACzB,eAAK,SAAS,EAAC,mBAAmB,aAC/B,KAAK,IAAI,aAAI,SAAS,EAAC,qDAAqD,YAAE,KAAK,GAAM,EACzF,WAAW,IAAI,YAAG,SAAS,EAAC,+BAA+B,YAAE,WAAW,GAAK,IAC1E,CACP,EACD,2BAAe,WAAW,sBAAkB,UAAU,YACnD,QAAQ,GACL,IACF,GACE,CACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Renders children only on the client after hydration.
|
|
4
|
+
* Prevents Radix UI useId() hydration mismatches between server and client.
|
|
5
|
+
*/
|
|
6
|
+
export declare function ClientOnly({ children, fallback }: {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
fallback?: ReactNode;
|
|
9
|
+
}): ReactNode;
|
|
10
|
+
//# sourceMappingURL=client-only.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-only.d.ts","sourceRoot":"","sources":["../../src/ui/client-only.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5D;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,QAAe,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,aAItG"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Renders children only on the client after hydration.
|
|
5
|
+
* Prevents Radix UI useId() hydration mismatches between server and client.
|
|
6
|
+
*/
|
|
7
|
+
export function ClientOnly({ children, fallback = null }) {
|
|
8
|
+
const [mounted, setMounted] = useState(false);
|
|
9
|
+
useEffect(() => setMounted(true), []);
|
|
10
|
+
return mounted ? children : fallback;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=client-only.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-only.js","sourceRoot":"","sources":["../../src/ui/client-only.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAkB,MAAM,OAAO,CAAC;AAE5D;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,EAAiD;IACrG,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale-switcher.d.ts","sourceRoot":"","sources":["../../src/ui/locale-switcher.tsx"],"names":[],"mappings":"AAMA,wBAAgB,cAAc,
|
|
1
|
+
{"version":3,"file":"locale-switcher.d.ts","sourceRoot":"","sources":["../../src/ui/locale-switcher.tsx"],"names":[],"mappings":"AAMA,wBAAgB,cAAc,mDAuD7B"}
|
|
@@ -4,15 +4,25 @@ import React from 'react';
|
|
|
4
4
|
import { usePathname } from 'next/navigation';
|
|
5
5
|
import { useShipSite, useAlternateLinks } from '../context/ShipSiteProvider';
|
|
6
6
|
export function LocaleSwitcher() {
|
|
7
|
-
const { locale, locales } = useShipSite();
|
|
7
|
+
const { locale, locales, defaultLocale } = useShipSite();
|
|
8
8
|
const alternatePathMap = useAlternateLinks();
|
|
9
9
|
const pathname = usePathname();
|
|
10
10
|
if (locales.length <= 1)
|
|
11
11
|
return null;
|
|
12
|
+
// Normalize pathname: with localePrefix:"as-needed", usePathname() may
|
|
13
|
+
// include the default locale prefix on the server (e.g. /en or /en/page)
|
|
14
|
+
// but alternatePathMap uses paths without it (e.g. / or /page).
|
|
15
|
+
let normalizedPathname = pathname;
|
|
16
|
+
if (pathname === `/${defaultLocale}`) {
|
|
17
|
+
normalizedPathname = '/';
|
|
18
|
+
}
|
|
19
|
+
else if (pathname.startsWith(`/${defaultLocale}/`)) {
|
|
20
|
+
normalizedPathname = pathname.slice(defaultLocale.length + 1);
|
|
21
|
+
}
|
|
12
22
|
// Find the alternatePathMap entry where the current locale's path matches
|
|
13
23
|
let alternates;
|
|
14
24
|
for (const entry of Object.values(alternatePathMap)) {
|
|
15
|
-
if (entry[locale] ===
|
|
25
|
+
if (entry[locale] === normalizedPathname) {
|
|
16
26
|
alternates = entry;
|
|
17
27
|
break;
|
|
18
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale-switcher.js","sourceRoot":"","sources":["../../src/ui/locale-switcher.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE7E,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"locale-switcher.js","sourceRoot":"","sources":["../../src/ui/locale-switcher.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE7E,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,WAAW,EAAE,CAAC;IACzD,MAAM,gBAAgB,GAAG,iBAAiB,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,uEAAuE;IACvE,yEAAyE;IACzE,gEAAgE;IAChE,IAAI,kBAAkB,GAAG,QAAQ,CAAC;IAClC,IAAI,QAAQ,KAAK,IAAI,aAAa,EAAE,EAAE,CAAC;QACrC,kBAAkB,GAAG,GAAG,CAAC;IAC3B,CAAC;SAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACrD,kBAAkB,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,0EAA0E;IAC1E,IAAI,UAA8C,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,kBAAkB,EAAE,CAAC;YACzC,UAAU,GAAG,KAAK,CAAC;YACnB,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,CACL,cAAK,SAAS,EAAC,mCAAmC,YAC/C,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YACtB,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;YAC5C,MAAM,QAAQ,GAAG,GAAG,KAAK,MAAM,CAAC;YAEhC,OAAO,CACL,MAAC,KAAK,CAAC,QAAQ,eACZ,CAAC,GAAG,CAAC,IAAI,eAAM,SAAS,EAAC,uBAAuB,uBAAS,EACzD,QAAQ,CAAC,CAAC,CAAC,CACV,eAAM,SAAS,EAAC,yCAAyC,YACtD,GAAG,GACC,CACR,CAAC,CAAC,CAAC,CACF,YACE,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,GAAG,EAAE;4BACZ,QAAQ,CAAC,MAAM,GAAG,eAAe,GAAG,0CAA0C,CAAC;wBACjF,CAAC,EACD,SAAS,EAAC,yEAAyE,YAElF,GAAG,GACF,CACL,KAhBkB,GAAG,CAiBP,CAClB,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
package/src/layout/Header.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
SheetTitle,
|
|
14
14
|
} from '../ui/sheet';
|
|
15
15
|
import { ThemeToggle } from '../ui/theme-toggle';
|
|
16
|
+
import { ClientOnly } from '../ui/client-only';
|
|
16
17
|
|
|
17
18
|
export function Header() {
|
|
18
19
|
const { siteName, logo, navigation, locale, defaultLocale } = useShipSite();
|
|
@@ -59,34 +60,40 @@ export function Header() {
|
|
|
59
60
|
</NavbarRight>
|
|
60
61
|
|
|
61
62
|
<div className="md:hidden">
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{navigation.cta.label}
|
|
63
|
+
<ClientOnly fallback={
|
|
64
|
+
<Button variant="ghost" size="icon" aria-label="Toggle menu">
|
|
65
|
+
<Menu className="size-5" />
|
|
66
|
+
</Button>
|
|
67
|
+
}>
|
|
68
|
+
<Sheet>
|
|
69
|
+
<SheetTrigger asChild>
|
|
70
|
+
<Button variant="ghost" size="icon" aria-label="Toggle menu">
|
|
71
|
+
<Menu className="size-5" />
|
|
72
|
+
</Button>
|
|
73
|
+
</SheetTrigger>
|
|
74
|
+
<SheetContent side="right">
|
|
75
|
+
<SheetTitle className="sr-only">Navigation</SheetTitle>
|
|
76
|
+
<nav className="flex flex-col gap-4 mt-8">
|
|
77
|
+
{navigation.items.map((item) => (
|
|
78
|
+
<a
|
|
79
|
+
key={item.href}
|
|
80
|
+
href={resolveHref(item.href)}
|
|
81
|
+
className="text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
|
|
82
|
+
>
|
|
83
|
+
{item.label}
|
|
84
84
|
</a>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
))}
|
|
86
|
+
{navigation.cta && (
|
|
87
|
+
<Button asChild className="mt-2">
|
|
88
|
+
<a href={navigation.cta.href}>
|
|
89
|
+
{navigation.cta.label}
|
|
90
|
+
</a>
|
|
91
|
+
</Button>
|
|
92
|
+
)}
|
|
93
|
+
</nav>
|
|
94
|
+
</SheetContent>
|
|
95
|
+
</Sheet>
|
|
96
|
+
</ClientOnly>
|
|
90
97
|
</div>
|
|
91
98
|
</Navbar>
|
|
92
99
|
</div>
|
package/src/marketing/FAQ.tsx
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import React from 'react';
|
|
2
|
+
import { ChevronDownIcon } from 'lucide-react';
|
|
4
3
|
import { Section } from '../ui/section';
|
|
5
|
-
import {
|
|
6
|
-
Accordion,
|
|
7
|
-
AccordionItem,
|
|
8
|
-
AccordionTrigger,
|
|
9
|
-
AccordionContent,
|
|
10
|
-
} from '../ui/accordion';
|
|
11
4
|
|
|
12
5
|
interface FAQItemProps {
|
|
13
6
|
question: string;
|
|
@@ -16,12 +9,15 @@ interface FAQItemProps {
|
|
|
16
9
|
|
|
17
10
|
export function FAQItem({ question, children }: FAQItemProps) {
|
|
18
11
|
return (
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
<
|
|
23
|
-
</
|
|
24
|
-
|
|
12
|
+
<details className="border-border dark:border-border/15 border-b group">
|
|
13
|
+
<summary className="flex flex-1 items-center justify-between py-4 text-left text-md font-medium transition-all hover:underline cursor-pointer list-none [&::-webkit-details-marker]:hidden">
|
|
14
|
+
{question}
|
|
15
|
+
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 transition-transform duration-200 group-open:rotate-180" />
|
|
16
|
+
</summary>
|
|
17
|
+
<div className="pb-4 text-sm text-muted-foreground leading-relaxed">
|
|
18
|
+
{children}
|
|
19
|
+
</div>
|
|
20
|
+
</details>
|
|
25
21
|
);
|
|
26
22
|
}
|
|
27
23
|
|
|
@@ -42,9 +38,9 @@ export function FAQ({ id, title, description, children }: FAQProps) {
|
|
|
42
38
|
{description && <p className="text-lg text-muted-foreground">{description}</p>}
|
|
43
39
|
</div>
|
|
44
40
|
)}
|
|
45
|
-
<
|
|
41
|
+
<div data-slot="accordion" data-orientation="vertical">
|
|
46
42
|
{children}
|
|
47
|
-
</
|
|
43
|
+
</div>
|
|
48
44
|
</div>
|
|
49
45
|
</Section>
|
|
50
46
|
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, type ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renders children only on the client after hydration.
|
|
7
|
+
* Prevents Radix UI useId() hydration mismatches between server and client.
|
|
8
|
+
*/
|
|
9
|
+
export function ClientOnly({ children, fallback = null }: { children: ReactNode; fallback?: ReactNode }) {
|
|
10
|
+
const [mounted, setMounted] = useState(false);
|
|
11
|
+
useEffect(() => setMounted(true), []);
|
|
12
|
+
return mounted ? children : fallback;
|
|
13
|
+
}
|
|
@@ -5,16 +5,26 @@ import { usePathname } from 'next/navigation';
|
|
|
5
5
|
import { useShipSite, useAlternateLinks } from '../context/ShipSiteProvider';
|
|
6
6
|
|
|
7
7
|
export function LocaleSwitcher() {
|
|
8
|
-
const { locale, locales } = useShipSite();
|
|
8
|
+
const { locale, locales, defaultLocale } = useShipSite();
|
|
9
9
|
const alternatePathMap = useAlternateLinks();
|
|
10
10
|
const pathname = usePathname();
|
|
11
11
|
|
|
12
12
|
if (locales.length <= 1) return null;
|
|
13
13
|
|
|
14
|
+
// Normalize pathname: with localePrefix:"as-needed", usePathname() may
|
|
15
|
+
// include the default locale prefix on the server (e.g. /en or /en/page)
|
|
16
|
+
// but alternatePathMap uses paths without it (e.g. / or /page).
|
|
17
|
+
let normalizedPathname = pathname;
|
|
18
|
+
if (pathname === `/${defaultLocale}`) {
|
|
19
|
+
normalizedPathname = '/';
|
|
20
|
+
} else if (pathname.startsWith(`/${defaultLocale}/`)) {
|
|
21
|
+
normalizedPathname = pathname.slice(defaultLocale.length + 1);
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
// Find the alternatePathMap entry where the current locale's path matches
|
|
15
25
|
let alternates: Record<string, string> | undefined;
|
|
16
26
|
for (const entry of Object.values(alternatePathMap)) {
|
|
17
|
-
if (entry[locale] ===
|
|
27
|
+
if (entry[locale] === normalizedPathname) {
|
|
18
28
|
alternates = entry;
|
|
19
29
|
break;
|
|
20
30
|
}
|