@brandlab-digital/site-next 3.14.0 → 3.15.0
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/analytics.d.ts +1 -1
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +2 -0
- package/dist/analytics.js.map +1 -1
- package/dist/navigation/constants.d.ts +11 -2
- package/dist/navigation/constants.d.ts.map +1 -1
- package/dist/navigation/constants.js +11 -2
- package/dist/navigation/constants.js.map +1 -1
- package/dist/navigation/index.d.ts +1 -1
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +1 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/navigation/use-back-to-top.d.ts.map +1 -1
- package/dist/navigation/use-back-to-top.js +12 -4
- package/dist/navigation/use-back-to-top.js.map +1 -1
- package/dist/navigation/use-header-metrics.d.ts +1 -1
- package/dist/navigation/use-header-metrics.js +1 -1
- package/dist/navigation/use-header-metrics.js.map +1 -1
- package/dist/navigation/use-sticky-call-bar.d.ts +2 -1
- package/dist/navigation/use-sticky-call-bar.d.ts.map +1 -1
- package/dist/navigation/use-sticky-call-bar.js +11 -2
- package/dist/navigation/use-sticky-call-bar.js.map +1 -1
- package/dist/ui-kit/brandlab-skin.d.ts +26 -0
- package/dist/ui-kit/brandlab-skin.d.ts.map +1 -1
- package/dist/ui-kit/brandlab-skin.js.map +1 -1
- package/dist/ui-kit/prefetch.d.ts +19 -10
- package/dist/ui-kit/prefetch.d.ts.map +1 -1
- package/dist/ui-kit/prefetch.js +23 -10
- package/dist/ui-kit/prefetch.js.map +1 -1
- package/dist/ui-kit/primitives/index.d.ts +1 -1
- package/dist/ui-kit/primitives/index.d.ts.map +1 -1
- package/dist/ui-kit/primitives/index.js.map +1 -1
- package/dist/ui-kit/primitives/links.js +1 -1
- package/dist/ui-kit/primitives/links.js.map +1 -1
- package/dist/ui-kit/primitives/lists.d.ts +9 -1
- package/dist/ui-kit/primitives/lists.d.ts.map +1 -1
- package/dist/ui-kit/primitives/lists.js +1 -1
- package/dist/ui-kit/primitives/lists.js.map +1 -1
- package/dist/ui-kit/primitives/quote-button.d.ts +25 -2
- package/dist/ui-kit/primitives/quote-button.d.ts.map +1 -1
- package/dist/ui-kit/primitives/quote-button.js +25 -3
- package/dist/ui-kit/primitives/quote-button.js.map +1 -1
- package/dist/ui-kit/repeated-slots.d.ts +32 -0
- package/dist/ui-kit/repeated-slots.d.ts.map +1 -1
- package/dist/ui-kit/repeated-slots.js +16 -0
- package/dist/ui-kit/repeated-slots.js.map +1 -1
- package/dist/ui-kit/sections/area-map.d.ts +64 -0
- package/dist/ui-kit/sections/area-map.d.ts.map +1 -0
- package/dist/ui-kit/sections/area-map.js +142 -0
- package/dist/ui-kit/sections/area-map.js.map +1 -0
- package/dist/ui-kit/sections/before-after.d.ts +59 -0
- package/dist/ui-kit/sections/before-after.d.ts.map +1 -0
- package/dist/ui-kit/sections/before-after.js +42 -0
- package/dist/ui-kit/sections/before-after.js.map +1 -0
- package/dist/ui-kit/sections/council-rules.d.ts +64 -0
- package/dist/ui-kit/sections/council-rules.d.ts.map +1 -0
- package/dist/ui-kit/sections/council-rules.js +46 -0
- package/dist/ui-kit/sections/council-rules.js.map +1 -0
- package/dist/ui-kit/sections/coverage.d.ts +53 -0
- package/dist/ui-kit/sections/coverage.d.ts.map +1 -0
- package/dist/ui-kit/sections/coverage.js +57 -0
- package/dist/ui-kit/sections/coverage.js.map +1 -0
- package/dist/ui-kit/sections/emergency-band.d.ts +60 -0
- package/dist/ui-kit/sections/emergency-band.d.ts.map +1 -0
- package/dist/ui-kit/sections/emergency-band.js +43 -0
- package/dist/ui-kit/sections/emergency-band.js.map +1 -0
- package/dist/ui-kit/sections/gallery.d.ts +60 -0
- package/dist/ui-kit/sections/gallery.d.ts.map +1 -0
- package/dist/ui-kit/sections/gallery.js +39 -0
- package/dist/ui-kit/sections/gallery.js.map +1 -0
- package/dist/ui-kit/sections/hero.d.ts +5 -0
- package/dist/ui-kit/sections/hero.d.ts.map +1 -1
- package/dist/ui-kit/sections/hero.js +1 -1
- package/dist/ui-kit/sections/hero.js.map +1 -1
- package/dist/ui-kit/sections/index.d.ts +14 -1
- package/dist/ui-kit/sections/index.d.ts.map +1 -1
- package/dist/ui-kit/sections/index.js +14 -1
- package/dist/ui-kit/sections/index.js.map +1 -1
- package/dist/ui-kit/sections/licences.d.ts +72 -0
- package/dist/ui-kit/sections/licences.d.ts.map +1 -0
- package/dist/ui-kit/sections/licences.js +46 -0
- package/dist/ui-kit/sections/licences.js.map +1 -0
- package/dist/ui-kit/sections/local-facts.d.ts +78 -0
- package/dist/ui-kit/sections/local-facts.d.ts.map +1 -0
- package/dist/ui-kit/sections/local-facts.js +32 -0
- package/dist/ui-kit/sections/local-facts.js.map +1 -0
- package/dist/ui-kit/sections/nearby-areas.d.ts +50 -0
- package/dist/ui-kit/sections/nearby-areas.d.ts.map +1 -0
- package/dist/ui-kit/sections/nearby-areas.js +49 -0
- package/dist/ui-kit/sections/nearby-areas.js.map +1 -0
- package/dist/ui-kit/sections/nearby-jobs.d.ts +66 -0
- package/dist/ui-kit/sections/nearby-jobs.d.ts.map +1 -0
- package/dist/ui-kit/sections/nearby-jobs.js +49 -0
- package/dist/ui-kit/sections/nearby-jobs.js.map +1 -0
- package/dist/ui-kit/sections/projects.d.ts +79 -0
- package/dist/ui-kit/sections/projects.d.ts.map +1 -0
- package/dist/ui-kit/sections/projects.js +69 -0
- package/dist/ui-kit/sections/projects.js.map +1 -0
- package/dist/ui-kit/sections/quote-checklist.d.ts +43 -0
- package/dist/ui-kit/sections/quote-checklist.d.ts.map +1 -0
- package/dist/ui-kit/sections/quote-checklist.js +19 -0
- package/dist/ui-kit/sections/quote-checklist.js.map +1 -0
- package/dist/ui-kit/sections/related-services.d.ts +41 -0
- package/dist/ui-kit/sections/related-services.d.ts.map +1 -0
- package/dist/ui-kit/sections/related-services.js +52 -0
- package/dist/ui-kit/sections/related-services.js.map +1 -0
- package/dist/ui-kit/sections/reviews-band.d.ts +11 -0
- package/dist/ui-kit/sections/reviews-band.d.ts.map +1 -1
- package/dist/ui-kit/sections/reviews-band.js +11 -0
- package/dist/ui-kit/sections/reviews-band.js.map +1 -1
- package/dist/ui-kit/sections/services-grid.js +1 -1
- package/dist/ui-kit/sections/services-grid.js.map +1 -1
- package/dist/ui-kit/sections/work-photos.d.ts +15 -0
- package/dist/ui-kit/sections/work-photos.d.ts.map +1 -0
- package/dist/ui-kit/sections/work-photos.js +24 -0
- package/dist/ui-kit/sections/work-photos.js.map +1 -0
- package/dist/ui-kit/shell/back-to-top.js +1 -1
- package/dist/ui-kit/shell/back-to-top.js.map +1 -1
- package/dist/ui-kit/shell/current-link.d.ts +21 -5
- package/dist/ui-kit/shell/current-link.d.ts.map +1 -1
- package/dist/ui-kit/shell/current-link.js +16 -5
- package/dist/ui-kit/shell/current-link.js.map +1 -1
- package/dist/ui-kit/shell/drawer-client.js +1 -1
- package/dist/ui-kit/shell/drawer-client.js.map +1 -1
- package/dist/ui-kit/shell/intent-prefetch.d.ts.map +1 -1
- package/dist/ui-kit/shell/intent-prefetch.js +3 -2
- package/dist/ui-kit/shell/intent-prefetch.js.map +1 -1
- package/dist/ui-kit/shell/mobile-call-bar.d.ts +6 -1
- package/dist/ui-kit/shell/mobile-call-bar.d.ts.map +1 -1
- package/dist/ui-kit/shell/mobile-call-bar.js +6 -3
- package/dist/ui-kit/shell/mobile-call-bar.js.map +1 -1
- package/dist/ui-kit/shell/mobile-drawer.js +2 -2
- package/dist/ui-kit/shell/mobile-drawer.js.map +1 -1
- package/dist/ui-kit/shell/shell-quote.d.ts +10 -0
- package/dist/ui-kit/shell/shell-quote.d.ts.map +1 -0
- package/dist/ui-kit/shell/shell-quote.js +13 -0
- package/dist/ui-kit/shell/shell-quote.js.map +1 -0
- package/dist/ui-kit/shell/site-header.d.ts +1 -1
- package/dist/ui-kit/shell/site-header.js +4 -4
- package/dist/ui-kit/shell/site-header.js.map +1 -1
- package/dist/ui-kit/structure.css +410 -7
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent-prefetch.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/intent-prefetch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ
|
|
1
|
+
{"version":3,"file":"intent-prefetch.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/intent-prefetch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAEzD,MAAM,aAAa,GAAG,CAAC,cAAc,EAAE,SAAS,EAAE,YAAY,CAAU,CAAA;AAExE,sGAAsG;AACtG,MAAM,UAAU,oBAAoB,CAAC,IAAmB;IACtD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC1C,OAAO,MAAM,IAAI,IAAI,CAAA;AACvB,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc,EAAE,QAAkB;IAClD,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAA;IAChE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;QACpC,MAAM,QAAQ,GAAG,CAAC,KAAY,EAAE,EAAE;YAChC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;YACrE,MAAM,IAAI,GAAG,OAAO,EAAE,OAAO,CAAoB,wBAAwB,CAAC,CAAA;YAC1E,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAA;YACvE,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC;gBAAE,OAAM;YAClF,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACtB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QACzB,CAAC,CAAA;QACD,8GAA8G;QAC9G,MAAM,OAAO,GAA4B,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACzE,KAAK,MAAM,IAAI,IAAI,aAAa;YAAE,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACpF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,IAAI,IAAI,aAAa;gBAAE,QAAQ,CAAC,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACzF,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["'use client'\n\n/**\n * `IntentPrefetch`: prefetches a top-level header link (from 3.15.0) or an in-content card link when a visitor shows\n * intent, not when it scrolls into view. Links with `prefetch=\"intent\"` (ButtonLink, TextLink, QuoteButton and the\n * SiteHeader's top-level links) render `prefetch={false}` and\n * `data-prefetch=\"intent\"`; this island holds one document listener for pointer entry, focus and touch, and calls\n * `router.prefetch(href)` for the one link the visitor points at, focuses or touches, once per page address. A touch\n * prefetches only the touched link, never the list around it; the current page and links to other sites are never\n * prefetched.\n *\n * Mount it once, in the root layout, beside the header:\n *\n * // src/app/layout.tsx\n * import { IntentPrefetch } from '@brandlab-digital/site-next/ui-kit/shell'\n * <body>\n * <SiteHeader … />\n * <IntentPrefetch />\n * …\n * </body>\n *\n * It renders nothing; without scripts the links still work and simply do not prefetch.\n */\nimport { useRouter } from 'next/navigation'\nimport { useEffect } from 'react'\nimport { INTENT_PREFETCH_SELECTOR } from '../prefetch.js'\n\nconst INTENT_EVENTS = ['pointerenter', 'focusin', 'touchstart'] as const\n\n/** The site path an intent link points to, without its fragment; null for another site or no href. */\nexport function intentPrefetchTarget(href: string | null): string | null {\n if (!href || !href.startsWith('/') || href.startsWith('//')) return null\n const target = href.split('#', 1)[0] ?? ''\n return target || null\n}\n\nfunction samePage(target: string, location: Location) {\n const path = (value: string) => value.replace(/\\/+$/, '') || '/'\n return path(target.split('?', 1)[0] ?? '') === path(location.pathname)\n}\n\nexport function IntentPrefetch(): null {\n const router = useRouter()\n\n useEffect(() => {\n const prefetched = new Set<string>()\n const onIntent = (event: Event) => {\n const element = event.target instanceof Element ? event.target : null\n const link = element?.closest<HTMLAnchorElement>(INTENT_PREFETCH_SELECTOR)\n const target = intentPrefetchTarget(link?.getAttribute('href') ?? null)\n if (!target || prefetched.has(target) || samePage(target, window.location)) return\n prefetched.add(target)\n router.prefetch(target)\n }\n // Capture, so pointerenter (which does not bubble) reaches the document; passive, so touch never waits on it.\n const options: AddEventListenerOptions = { capture: true, passive: true }\n for (const type of INTENT_EVENTS) document.addEventListener(type, onIntent, options)\n return () => {\n for (const type of INTENT_EVENTS) document.removeEventListener(type, onIntent, options)\n }\n }, [router])\n\n return null\n}\n"]}
|
|
@@ -11,6 +11,11 @@ export interface MobileCallBarProps extends MobileCallBarSkin {
|
|
|
11
11
|
/** Words before the number, for example "Call". The button's name always includes the number. */
|
|
12
12
|
readonly phoneLabel?: string | undefined;
|
|
13
13
|
readonly quote: ShellQuote;
|
|
14
|
+
/**
|
|
15
|
+
* A shorter quote label for phones narrower than 420 px, for example "Free quote" for "Get a Free Quote". It must be
|
|
16
|
+
* part of the quote label; the button's text and name stay the full label.
|
|
17
|
+
*/
|
|
18
|
+
readonly compactLabel?: string | undefined;
|
|
14
19
|
}
|
|
15
|
-
export declare function MobileCallBar({ phone, phoneLabel, quote, variant, classes }: MobileCallBarProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare function MobileCallBar({ phone, phoneLabel, quote, compactLabel, variant, classes }: MobileCallBarProps): import("react/jsx-runtime").JSX.Element;
|
|
16
21
|
//# sourceMappingURL=mobile-call-bar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-call-bar.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mobile-call-bar.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AACzD,eAAO,MAAM,wBAAwB,2BAA4B,CAAA;AACjE,wDAAwD;AACxD,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA;AAC5E,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAA;AAElF,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC3C;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,OAAe,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CAOrH"}
|
|
@@ -4,12 +4,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
* hero's own call and quote buttons (`data-bl-call-path`) have scrolled out, and hides over the footer, the drawer, a
|
|
5
5
|
* dialog, any call path and while a form field has focus. Call reports placement `fab`; the quote button sends
|
|
6
6
|
* `lead_cta_click` with placement `floating`. Render it once, after the page's `<main>`.
|
|
7
|
+
*
|
|
8
|
+
* Both buttons stay on one line down to 360 px (3.15.0): the number never wraps or truncates; below 420 px the verb
|
|
9
|
+
* ("Call") is visually hidden (the link's name keeps it) and the quote button shows `compactLabel` when given.
|
|
7
10
|
*/
|
|
8
11
|
import { PhoneLink } from '../primitives/links.js';
|
|
9
|
-
import {
|
|
12
|
+
import { ShellQuoteButton } from './shell-quote.js';
|
|
10
13
|
import { CallBarController } from './call-bar-client.js';
|
|
11
14
|
export const MOBILE_CALL_BAR_VARIANTS = ['bar', 'float'];
|
|
12
|
-
export function MobileCallBar({ phone, phoneLabel, quote, variant = 'bar', classes }) {
|
|
13
|
-
return (_jsxs(CallBarController, { variant: variant, className: classes?.root, children: [_jsx(PhoneLink, { phone: phone, placement: "fab", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(
|
|
15
|
+
export function MobileCallBar({ phone, phoneLabel, quote, compactLabel, variant = 'bar', classes }) {
|
|
16
|
+
return (_jsxs(CallBarController, { variant: variant, className: classes?.root, children: [_jsx(PhoneLink, { phone: phone, placement: "fab", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(ShellQuoteButton, { label: quote.label, href: quote.href, placement: "floating", ctaId: "quote-callbar", compactLabel: compactLabel, classes: { root: classes?.quote } })] }));
|
|
14
17
|
}
|
|
15
18
|
//# sourceMappingURL=mobile-call-bar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-call-bar.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"mobile-call-bar.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAIxD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE,OAAO,CAAU,CAAA;AAiBjE,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,EAAsB;IACpH,OAAO,CACL,MAAC,iBAAiB,IAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,aAC3D,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAC,KAAK,EAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,QAAC,OAAO,EAAC,QAAQ,EAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAI,EAC1H,KAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAC,UAAU,EAAC,KAAK,EAAC,eAAe,EAAC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAI,IAClJ,CACrB,CAAA;AACH,CAAC","sourcesContent":["/**\n * F6: the phone call bar (server component). Call and quote always one tap away below 1024 px: it shows once the\n * hero's own call and quote buttons (`data-bl-call-path`) have scrolled out, and hides over the footer, the drawer, a\n * dialog, any call path and while a form field has focus. Call reports placement `fab`; the quote button sends\n * `lead_cta_click` with placement `floating`. Render it once, after the page's `<main>`.\n *\n * Both buttons stay on one line down to 360 px (3.15.0): the number never wraps or truncates; below 420 px the verb\n * (\"Call\") is visually hidden (the link's name keeps it) and the quote button shows `compactLabel` when given.\n */\nimport { PhoneLink } from '../primitives/links.js'\nimport { ShellQuoteButton } from './shell-quote.js'\nimport type { SkinEntry } from '../skin.js'\nimport type { UiPhone } from '../types.js'\nimport { CallBarController } from './call-bar-client.js'\nimport type { ShellQuote } from './mobile-drawer.js'\n\nexport type MobileCallBarSlot = 'root' | 'call' | 'quote'\nexport const MOBILE_CALL_BAR_VARIANTS = ['bar', 'float'] as const\n/** `bar`: full width; `float`: two pills at the end. */\nexport type MobileCallBarVariant = (typeof MOBILE_CALL_BAR_VARIANTS)[number]\nexport type MobileCallBarSkin = SkinEntry<MobileCallBarSlot, MobileCallBarVariant>\n\nexport interface MobileCallBarProps extends MobileCallBarSkin {\n readonly phone: UiPhone\n /** Words before the number, for example \"Call\". The button's name always includes the number. */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n /**\n * A shorter quote label for phones narrower than 420 px, for example \"Free quote\" for \"Get a Free Quote\". It must be\n * part of the quote label; the button's text and name stay the full label.\n */\n readonly compactLabel?: string | undefined\n}\n\nexport function MobileCallBar({ phone, phoneLabel, quote, compactLabel, variant = 'bar', classes }: MobileCallBarProps) {\n return (\n <CallBarController variant={variant} className={classes?.root}>\n <PhoneLink phone={phone} placement=\"fab\" label={phoneLabel} showIcon variant=\"button\" classes={{ root: classes?.call }} />\n <ShellQuoteButton label={quote.label} href={quote.href} placement=\"floating\" ctaId=\"quote-callbar\" compactLabel={compactLabel} classes={{ root: classes?.quote }} />\n </CallBarController>\n )\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Icon } from '../icons.js';
|
|
3
3
|
import { PhoneLink } from '../primitives/links.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ShellQuoteButton } from './shell-quote.js';
|
|
5
5
|
import { repeatedSlot, slot } from '../skin.js';
|
|
6
6
|
import { CurrentLink } from './current-link.js';
|
|
7
7
|
import { DrawerController } from './drawer-client.js';
|
|
@@ -32,7 +32,7 @@ export function MobileDrawer({ navigation, phone, phoneLabel, quote, socials = [
|
|
|
32
32
|
close: classes?.close,
|
|
33
33
|
title: classes?.title,
|
|
34
34
|
logo: classes?.logo,
|
|
35
|
-
}, logo: logo, menuIcon: _jsx(Icon, { name: "menu" }), closeIcon: _jsx(Icon, { name: "close" }), children: [_jsx("nav", { "aria-label": "Main", ...slot(classes, 'nav'), children: runs.map((run) => Array.isArray(run) ? (_jsx("ul", { ...slot(classes, 'links'), children: run.map((link) => (_jsx("li", { children: _jsx(CurrentLink, { href: link.href, slot: "link", prefetch: false, children: link.label }) }, link.id))) }, `links-${run[0].id}`)) : (_jsx(GroupAccordion, { group: run, name: `${id}-groups` }, run.id))) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(
|
|
35
|
+
}, logo: logo, menuIcon: _jsx(Icon, { name: "menu" }), closeIcon: _jsx(Icon, { name: "close" }), children: [_jsx("nav", { "aria-label": "Main", ...slot(classes, 'nav'), children: runs.map((run) => Array.isArray(run) ? (_jsx("ul", { ...slot(classes, 'links'), children: run.map((link) => (_jsx("li", { children: _jsx(CurrentLink, { href: link.href, slot: "link", prefetch: false, children: link.label }) }, link.id))) }, `links-${run[0].id}`)) : (_jsx(GroupAccordion, { group: run, name: `${id}-groups` }, run.id))) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(ShellQuoteButton, { label: quote.label, href: quote.href, placement: "navigation", ctaId: "quote-menu", classes: { root: classes?.quote } })] }), _jsx(SocialLinks, { socials: socials, slotName: "social", className: classes?.social })] }));
|
|
36
36
|
}
|
|
37
37
|
/** One dropdown as an accordion: its hub link first, the featured card's page, then its links. */
|
|
38
38
|
function GroupAccordion({ group, name }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-drawer.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-drawer.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mobile-drawer.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-drawer.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * F4: the phone and compact-band menu (server component). A modal dialog named \"Menu\", sliding in at\n * `min(100%, 420px)`: the close button first, then the menu in the desktop order (F1, 3.14.0), each dropdown an\n * accordion where it stands (one open at a time) and each run of plain links one list, then full-width Call and quote\n * buttons, and the social links. Every link is in the server HTML. `SiteHeader` renders it;\n * render it on its own only inside a recorded bespoke header.\n */\nimport type { BrandlabNavigation, BrandlabNavLinkItem, BrandlabNavMenuItem } from '@brandlab-digital/site-core/navigation'\nimport type { ReactNode } from 'react'\nimport { Icon } from '../icons.js'\nimport { PhoneLink } from '../primitives/links.js'\nimport { ShellQuoteButton } from './shell-quote.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { repeatedSlot, slot, type SkinEntry } from '../skin.js'\nimport type { UiPhone, UiSocial } from '../types.js'\nimport { CurrentLink } from './current-link.js'\nimport { DrawerController } from './drawer-client.js'\nimport { SocialLinks } from './social-links.js'\n\nexport type MobileDrawerSlot =\n | 'root'\n | 'menuButton'\n | 'menuLabel'\n | 'panel'\n | 'top'\n | 'close'\n | 'title'\n | 'logo'\n | 'nav'\n | 'group'\n | 'groupTrigger'\n | 'groupLinks'\n | 'groupLink'\n | 'links'\n | 'link'\n | 'actions'\n | 'call'\n | 'quote'\n | 'social'\n | 'socialLink'\nexport const MOBILE_DRAWER_VARIANTS = ['side', 'full'] as const\nexport type MobileDrawerVariant = (typeof MOBILE_DRAWER_VARIANTS)[number]\nexport interface MobileDrawerLayout {\n /** The side the panel slides from (`side` variant). */\n readonly side?: 'end' | 'start'\n}\n/** Rendered once per group, link or social profile: styled from the skin stylesheet, never by class (3.14.0). */\nexport type MobileDrawerRepeatedSlot = RepeatedSlotOf<'mobileDrawer'>\nexport type MobileDrawerSkin = SkinEntry<MobileDrawerSlot, MobileDrawerVariant, MobileDrawerLayout, MobileDrawerRepeatedSlot>\n\n/** The quote action. `href` is the quote form it falls back to without scripts, for example `/contact#quote`. */\nexport interface ShellQuote {\n readonly label: string\n readonly href: string\n}\n\nexport interface MobileDrawerProps extends MobileDrawerSkin {\n readonly navigation: BrandlabNavigation\n readonly phone: UiPhone\n /** Words before the number on the Call button, for example \"Call\". */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n readonly socials?: readonly UiSocial[] | undefined\n /** An optional logo in the drawer's top bar (decorative there). */\n readonly logo?: ReactNode\n /** Prefix for element ids; one per header on the page. */\n readonly idPrefix?: string | undefined\n}\n\nexport function MobileDrawer({\n navigation,\n phone,\n phoneLabel,\n quote,\n socials = [],\n logo,\n idPrefix = 'bl-header',\n variant = 'side',\n layout,\n classes,\n}: MobileDrawerProps) {\n const id = `${idPrefix}-drawer`\n // The drawer keeps the desktop menu's order (F1): a dropdown becomes an accordion where it stands, and each run of\n // plain links between dropdowns is one list.\n const runs: (BrandlabNavMenuItem | BrandlabNavLinkItem[])[] = []\n for (const item of navigation.items) {\n if (item.kind === 'menu') runs.push(item)\n else {\n const last = runs[runs.length - 1]\n if (Array.isArray(last)) last.push(item)\n else runs.push([item])\n }\n }\n return (\n <DrawerController\n id={id}\n variant={variant}\n side={layout?.side ?? 'end'}\n classes={{\n root: classes?.root,\n menuButton: classes?.menuButton,\n menuLabel: classes?.menuLabel,\n panel: classes?.panel,\n top: classes?.top,\n close: classes?.close,\n title: classes?.title,\n logo: classes?.logo,\n }}\n logo={logo}\n menuIcon={<Icon name=\"menu\" />}\n closeIcon={<Icon name=\"close\" />}\n >\n <nav aria-label=\"Main\" {...slot(classes, 'nav')}>\n {runs.map((run) =>\n Array.isArray(run) ? (\n <ul key={`links-${run[0]!.id}`} {...slot(classes, 'links')}>\n {run.map((link) => (\n <li key={link.id}>\n <CurrentLink href={link.href} slot=\"link\" prefetch={false}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n ) : (\n <GroupAccordion key={run.id} group={run} name={`${id}-groups`} />\n ),\n )}\n </nav>\n <div {...slot(classes, 'actions')}>\n <PhoneLink phone={phone} placement=\"header\" label={phoneLabel} showIcon variant=\"button\" classes={{ root: classes?.call }} />\n <ShellQuoteButton label={quote.label} href={quote.href} placement=\"navigation\" ctaId=\"quote-menu\" classes={{ root: classes?.quote }} />\n </div>\n <SocialLinks socials={socials} slotName=\"social\" className={classes?.social} />\n </DrawerController>\n )\n}\n\n/** One dropdown as an accordion: its hub link first, the featured card's page, then its links. */\nfunction GroupAccordion({ group, name }: { readonly group: BrandlabNavMenuItem; readonly name: string }) {\n return (\n <details name={name} {...repeatedSlot('group')}>\n <summary {...repeatedSlot('groupTrigger')}>\n <span>{group.label}</span>\n <Icon name=\"chevron\" />\n </summary>\n <ul {...repeatedSlot('groupLinks')}>\n <li>\n <CurrentLink href={group.href} slot=\"groupLink\" prefetch={false} hub>\n {group.hubLabel}\n </CurrentLink>\n </li>\n {group.featured && !group.links.some((link) => link.href === group.featured?.href) ? (\n <li>\n <CurrentLink href={group.featured.href} slot=\"groupLink\" prefetch={false}>\n {group.featured.label}\n </CurrentLink>\n </li>\n ) : null}\n {group.links.map((link) => (\n <li key={link.href}>\n <CurrentLink href={link.href} slot=\"groupLink\" prefetch={false}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n </details>\n )\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The quote button the shell renders in the header, the drawer and the call bar (internal). The same DOM as
|
|
3
|
+
* `QuoteButton`, through `PageLink`, so it keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`) everywhere
|
|
4
|
+
* but on its own page: on `/contact` the `/contact#quote` button never prefetches the page the visitor is on (W2).
|
|
5
|
+
*/
|
|
6
|
+
import { type QuoteButtonProps } from '../primitives/quote-button.js';
|
|
7
|
+
export declare function ShellQuoteButton({ compactLabel, ...props }: QuoteButtonProps & {
|
|
8
|
+
readonly compactLabel?: string | undefined;
|
|
9
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=shell-quote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-quote.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/shell-quote.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAGvF,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,GAAG;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,2CAO7H"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The quote button the shell renders in the header, the drawer and the call bar (internal). The same DOM as
|
|
4
|
+
* `QuoteButton`, through `PageLink`, so it keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`) everywhere
|
|
5
|
+
* but on its own page: on `/contact` the `/contact#quote` button never prefetches the page the visitor is on (W2).
|
|
6
|
+
*/
|
|
7
|
+
import { quoteButtonParts } from '../primitives/quote-button.js';
|
|
8
|
+
import { PageLink } from './current-link.js';
|
|
9
|
+
export function ShellQuoteButton({ compactLabel, ...props }) {
|
|
10
|
+
const { href, hooks, children } = quoteButtonParts(props, { compactLabel });
|
|
11
|
+
return (_jsx(PageLink, { href: href, prefetch: props.prefetch, hooks: hooks, children: children }));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=shell-quote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-quote.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/shell-quote.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,OAAO,EAAE,gBAAgB,EAAyB,MAAM,+BAA+B,CAAA;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE5C,MAAM,UAAU,gBAAgB,CAAC,EAAE,YAAY,EAAE,GAAG,KAAK,EAAqE;IAC5H,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,EAAE,YAAY,EAAE,CAAC,CAAA;IAC3E,OAAO,CACL,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,YACzD,QAAQ,GACA,CACZ,CAAA;AACH,CAAC","sourcesContent":["/**\n * The quote button the shell renders in the header, the drawer and the call bar (internal). The same DOM as\n * `QuoteButton`, through `PageLink`, so it keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`) everywhere\n * but on its own page: on `/contact` the `/contact#quote` button never prefetches the page the visitor is on (W2).\n */\nimport { quoteButtonParts, type QuoteButtonProps } from '../primitives/quote-button.js'\nimport { PageLink } from './current-link.js'\n\nexport function ShellQuoteButton({ compactLabel, ...props }: QuoteButtonProps & { readonly compactLabel?: string | undefined }) {\n const { href, hooks, children } = quoteButtonParts(props, { compactLabel })\n return (\n <PageLink href={href} prefetch={props.prefetch} hooks={hooks}>\n {children}\n </PageLink>\n )\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* F2: the header shell (server component). The same structure on every site: the skip link, the optional utility
|
|
3
3
|
* bar, then a sticky, solid `<header>` holding the logo, the menu, the phone and the quote button. Layout follows the
|
|
4
|
-
* header's own width (container queries): from
|
|
4
|
+
* header's own width (container queries): from 1200 px the full menu; from 1024 to 1199 px a compact band with the
|
|
5
5
|
* phone and its number, the quote button and a Menu button; below 1024 px the logo, a 44 px call button and a 44 px
|
|
6
6
|
* Menu button. Every menu, hub and panel link is an `<a href>` in the server HTML (F3); client leaves only change
|
|
7
7
|
* state.
|
|
@@ -4,7 +4,7 @@ import { SkipLink } from '../../ui.js';
|
|
|
4
4
|
import { MAIN_CONTENT_ID } from '../../navigation/constants.js';
|
|
5
5
|
import { Icon } from '../icons.js';
|
|
6
6
|
import { PhoneLink } from '../primitives/links.js';
|
|
7
|
-
import {
|
|
7
|
+
import { ShellQuoteButton } from './shell-quote.js';
|
|
8
8
|
import { cx, repeatedSlot, slot } from '../skin.js';
|
|
9
9
|
import { CurrentLink, LogoLink } from './current-link.js';
|
|
10
10
|
import { HeaderRoot, NavController, NavItem, NavPanel, NavTrigger } from './header-client.js';
|
|
@@ -12,14 +12,14 @@ import { MobileDrawer } from './mobile-drawer.js';
|
|
|
12
12
|
export const SITE_HEADER_VARIANTS = ['standard', 'call-first'];
|
|
13
13
|
export function SiteHeader({ navigation, brandName, homeHref, logo, phone, phoneLabel, quote, socials, skipLabel, utility, drawer, drawerLogo, idPrefix = 'bl-header', variant = 'standard', layout, classes, }) {
|
|
14
14
|
const callFirst = variant === 'call-first';
|
|
15
|
-
return (_jsxs(_Fragment, { children: [_jsx(SkipLink, { targetId: MAIN_CONTENT_ID, "data-bl": "skip", className: classes?.skip, children: skipLabel }), utility, _jsx(HeaderRoot, { variant: variant, navAlign: layout?.navAlign ?? 'center', compactAfterScroll: layout?.compactAfterScroll ?? false, className: classes?.root, children: _jsx("div", { ...slot(classes, 'bar'), children: _jsxs("div", { ...slot(classes, 'inner'), children: [_jsx(LogoLink, { href: homeHref, label: brandName, slot: "logo", className: classes?.logo, children: logo }), _jsx(NavController, { label: "Main", className: classes?.nav, children: _jsx("ul", { ...slot(classes, 'list'), children: navigation.items.map((item) => item.kind === 'link' ? (_jsx(LinkItem, { item: item }, item.id)) : (_jsx(MenuItem, { item: item, panelId: `${idPrefix}-panel-${item.id}` }, item.id))) }) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: callFirst ? 'button' : 'text', classes: { root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber } }), _jsx(
|
|
15
|
+
return (_jsxs(_Fragment, { children: [_jsx(SkipLink, { targetId: MAIN_CONTENT_ID, "data-bl": "skip", className: classes?.skip, children: skipLabel }), utility, _jsx(HeaderRoot, { variant: variant, navAlign: layout?.navAlign ?? 'center', compactAfterScroll: layout?.compactAfterScroll ?? false, className: classes?.root, children: _jsx("div", { ...slot(classes, 'bar'), children: _jsxs("div", { ...slot(classes, 'inner'), children: [_jsx(LogoLink, { href: homeHref, label: brandName, slot: "logo", className: classes?.logo, children: logo }), _jsx(NavController, { label: "Main", className: classes?.nav, children: _jsx("ul", { ...slot(classes, 'list'), children: navigation.items.map((item) => item.kind === 'link' ? (_jsx(LinkItem, { item: item }, item.id)) : (_jsx(MenuItem, { item: item, panelId: `${idPrefix}-panel-${item.id}` }, item.id))) }) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: callFirst ? 'button' : 'text', classes: { root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber } }), _jsx(ShellQuoteButton, { label: quote.label, href: quote.href, placement: "header", ctaId: "quote-header", classes: { root: classes?.quote, label: classes?.quoteLabel, icon: classes?.quoteIcon } }), _jsx(MobileDrawer, { ...drawer, classes: {
|
|
16
16
|
...drawer?.classes,
|
|
17
17
|
menuButton: cx(drawer?.classes?.menuButton, classes?.menuButton),
|
|
18
18
|
menuLabel: cx(drawer?.classes?.menuLabel, classes?.menuLabel),
|
|
19
19
|
}, navigation: navigation, phone: phone, phoneLabel: phoneLabel, quote: quote, socials: socials, logo: drawerLogo, idPrefix: idPrefix })] })] }) }) })] }));
|
|
20
20
|
}
|
|
21
21
|
function LinkItem({ item }) {
|
|
22
|
-
return (_jsx(NavItem, { paths: [item.href, ...(item.activePaths ?? [])], children: _jsx(CurrentLink, { href: item.href, slot: "link", children: item.label }) }));
|
|
22
|
+
return (_jsx(NavItem, { paths: [item.href, ...(item.activePaths ?? [])], children: _jsx(CurrentLink, { href: item.href, slot: "link", prefetch: "intent", children: item.label }) }));
|
|
23
23
|
}
|
|
24
24
|
function MenuItem({ item, panelId }) {
|
|
25
25
|
const groups = item.panel === 'columns' && item.groups && item.groups.length > 0 ? item.groups : undefined;
|
|
@@ -27,7 +27,7 @@ function MenuItem({ item, panelId }) {
|
|
|
27
27
|
const grouped = new Set(groups?.flatMap((group) => group.links.map((link) => link.href)));
|
|
28
28
|
const ungrouped = groups ? item.links.filter((link) => !grouped.has(link.href)) : [];
|
|
29
29
|
const columnCount = groups ? groups.length + (ungrouped.length > 0 ? 1 : 0) : 0;
|
|
30
|
-
return (_jsxs(NavItem, { menuId: item.id, paths: [item.href, ...(item.activePaths ?? [])], children: [_jsxs("span", { ...repeatedSlot('itemRow'), children: [_jsx(CurrentLink, { href: item.href, slot: "link", children: item.label }), _jsx(NavTrigger, { menuId: item.id, panelId: panelId, label: item.label, children: _jsx(Icon, { name: "chevron" }) })] }), _jsx(NavPanel, { menuId: item.id, panelId: panelId, variant: item.panel, columns: groups ? Math.min(3, Math.max(2, columnCount)) : undefined, children: _jsxs("div", { ...repeatedSlot('panelBody'), children: [item.panel === 'featured' && item.featured ? (_jsxs(CurrentLink, { href: item.featured.href, slot: "featured", prefetch: false, children: [_jsx("span", { ...repeatedSlot('featuredMedia'), children: _jsx(Image, { src: item.featured.image.src, alt: item.featured.image.alt, width: item.featured.image.width, height: item.featured.image.height, sizes: "240px" }) }), _jsx("span", { ...repeatedSlot('featuredLabel'), children: item.featured.label }), _jsx("span", { ...repeatedSlot('featuredText'), children: item.featured.description })] })) : null, _jsxs("ul", { ...repeatedSlot('panelList'), children: [_jsx("li", { children: _jsxs(CurrentLink, { href: item.href, slot: "panelLink", hub: true, prefetch: false, children: [_jsx("span", { ...repeatedSlot('panelLabel'), children: item.hubLabel }), _jsx(Icon, { name: "arrow" })] }) }), groups ? null : item.links.map((link) => _jsx(PanelLink, { link: link }, link.href))] }), groups?.map((group) => (_jsxs("div", { ...repeatedSlot('panelGroup'), children: [_jsx("p", { ...repeatedSlot('panelHeading'), children: group.heading }), _jsx("ul", { ...repeatedSlot('panelList'), children: group.links.map((link) => (_jsx(PanelLink, { link: link }, link.href))) })] }, group.heading))), ungrouped.length > 0 ? (_jsx("div", { ...repeatedSlot('panelGroup'), children: _jsx("ul", { ...repeatedSlot('panelList'), children: ungrouped.map((link) => (_jsx(PanelLink, { link: link }, link.href))) }) })) : null] }) })] }));
|
|
30
|
+
return (_jsxs(NavItem, { menuId: item.id, paths: [item.href, ...(item.activePaths ?? [])], children: [_jsxs("span", { ...repeatedSlot('itemRow'), children: [_jsx(CurrentLink, { href: item.href, slot: "link", prefetch: "intent", children: item.label }), _jsx(NavTrigger, { menuId: item.id, panelId: panelId, label: item.label, children: _jsx(Icon, { name: "chevron" }) })] }), _jsx(NavPanel, { menuId: item.id, panelId: panelId, variant: item.panel, columns: groups ? Math.min(3, Math.max(2, columnCount)) : undefined, children: _jsxs("div", { ...repeatedSlot('panelBody'), children: [item.panel === 'featured' && item.featured ? (_jsxs(CurrentLink, { href: item.featured.href, slot: "featured", prefetch: false, children: [_jsx("span", { ...repeatedSlot('featuredMedia'), children: _jsx(Image, { src: item.featured.image.src, alt: item.featured.image.alt, width: item.featured.image.width, height: item.featured.image.height, sizes: "240px" }) }), _jsx("span", { ...repeatedSlot('featuredLabel'), children: item.featured.label }), _jsx("span", { ...repeatedSlot('featuredText'), children: item.featured.description })] })) : null, _jsxs("ul", { ...repeatedSlot('panelList'), children: [_jsx("li", { children: _jsxs(CurrentLink, { href: item.href, slot: "panelLink", hub: true, prefetch: false, children: [_jsx("span", { ...repeatedSlot('panelLabel'), children: item.hubLabel }), _jsx(Icon, { name: "arrow" })] }) }), groups ? null : item.links.map((link) => _jsx(PanelLink, { link: link }, link.href))] }), groups?.map((group) => (_jsxs("div", { ...repeatedSlot('panelGroup'), children: [_jsx("p", { ...repeatedSlot('panelHeading'), children: group.heading }), _jsx("ul", { ...repeatedSlot('panelList'), children: group.links.map((link) => (_jsx(PanelLink, { link: link }, link.href))) })] }, group.heading))), ungrouped.length > 0 ? (_jsx("div", { ...repeatedSlot('panelGroup'), children: _jsx("ul", { ...repeatedSlot('panelList'), children: ungrouped.map((link) => (_jsx(PanelLink, { link: link }, link.href))) }) })) : null] }) })] }));
|
|
31
31
|
}
|
|
32
32
|
function PanelLink({ link }) {
|
|
33
33
|
return (_jsx("li", { children: _jsxs(CurrentLink, { href: link.href, slot: "panelLink", prefetch: false, children: [_jsx("span", { ...repeatedSlot('panelLabel'), children: link.label }), link.description ? _jsx("span", { ...repeatedSlot('panelText'), children: link.description }) : null] }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site-header.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/site-header.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * F2: the header shell (server component). The same structure on every site: the skip link, the optional utility\n * bar, then a sticky, solid `<header>` holding the logo, the menu, the phone and the quote button. Layout follows the\n * header's own width (container queries): from 1280 px the full menu; from 1024 to 1279 px a compact band with the\n * phone and its number, the quote button and a Menu button; below 1024 px the logo, a 44 px call button and a 44 px\n * Menu button. Every menu, hub and panel link is an `<a href>` in the server HTML (F3); client leaves only change\n * state.\n */\nimport type { BrandlabNavigation, BrandlabNavLinkItem, BrandlabNavMenuItem } from '@brandlab-digital/site-core/navigation'\nimport Image from 'next/image'\nimport type { ReactNode } from 'react'\nimport { SkipLink } from '../../ui.js'\nimport { MAIN_CONTENT_ID } from '../../navigation/constants.js'\nimport { Icon } from '../icons.js'\nimport { PhoneLink } from '../primitives/links.js'\nimport { QuoteButton } from '../primitives/quote-button.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { cx, repeatedSlot, slot, type SkinEntry } from '../skin.js'\nimport type { UiPhone, UiSocial } from '../types.js'\nimport { CurrentLink, LogoLink } from './current-link.js'\nimport { HeaderRoot, NavController, NavItem, NavPanel, NavTrigger } from './header-client.js'\nimport { MobileDrawer, type MobileDrawerSkin, type ShellQuote } from './mobile-drawer.js'\n\nexport type SiteHeaderSlot =\n | 'skip'\n | 'root'\n | 'bar'\n | 'inner'\n | 'logo'\n | 'nav'\n | 'list'\n | 'item'\n | 'itemRow'\n | 'link'\n | 'trigger'\n | 'panel'\n | 'panelBody'\n | 'panelList'\n | 'panelGroup'\n | 'panelHeading'\n | 'panelLink'\n | 'panelLabel'\n | 'panelText'\n | 'featured'\n | 'featuredMedia'\n | 'featuredLabel'\n | 'featuredText'\n | 'actions'\n | 'phone'\n | 'phoneIcon'\n | 'phoneLabel'\n | 'phoneNumber'\n | 'quote'\n | 'quoteLabel'\n | 'quoteIcon'\n | 'menuButton'\n | 'menuLabel'\nexport const SITE_HEADER_VARIANTS = ['standard', 'call-first'] as const\n/**\n * `call-first` (recorded exceptions, v1 §9.10): the phone is the primary action (a button with its number at every\n * width); the quote button still follows it, as on `standard`.\n */\nexport type SiteHeaderVariant = (typeof SITE_HEADER_VARIANTS)[number]\nexport interface SiteHeaderLayout {\n /** Where the menu sits between the logo and the actions. */\n readonly navAlign?: 'center' | 'end'\n /** Compact the header (`data-compact=\"true\"`) once the page has scrolled 80 px. It never hides. */\n readonly compactAfterScroll?: boolean\n}\n/** Rendered once per menu item or panel link: styled from the skin stylesheet, never by class (3.14.0). */\nexport type SiteHeaderRepeatedSlot = RepeatedSlotOf<'siteHeader'>\nexport type SiteHeaderSkin = SkinEntry<SiteHeaderSlot, SiteHeaderVariant, SiteHeaderLayout, SiteHeaderRepeatedSlot>\n\nexport interface SiteHeaderProps extends SiteHeaderSkin {\n readonly navigation: BrandlabNavigation\n /** The logo link's accessible name. */\n readonly brandName: string\n readonly homeHref: string\n readonly logo: ReactNode\n /** From the derived business facts, never typed by hand. */\n readonly phone: UiPhone\n /** The small line above the number, for example \"Call us\". Also leads the drawer's Call button. */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n readonly socials?: readonly UiSocial[] | undefined\n /** The site's skip-link text, for example \"Skip to main content\". It targets `#main`. */\n readonly skipLabel: string\n /** The optional utility bar (`<UtilityBar>`), placed between the skip link and the header. */\n readonly utility?: ReactNode\n /** The site's `mobileDrawer` skin entry. */\n readonly drawer?: MobileDrawerSkin | undefined\n /** An optional logo for the drawer's top bar. */\n readonly drawerLogo?: ReactNode\n /** Prefix for element ids; one per header on the page. */\n readonly idPrefix?: string | undefined\n}\n\nexport function SiteHeader({\n navigation,\n brandName,\n homeHref,\n logo,\n phone,\n phoneLabel,\n quote,\n socials,\n skipLabel,\n utility,\n drawer,\n drawerLogo,\n idPrefix = 'bl-header',\n variant = 'standard',\n layout,\n classes,\n}: SiteHeaderProps) {\n const callFirst = variant === 'call-first'\n return (\n <>\n <SkipLink targetId={MAIN_CONTENT_ID} data-bl=\"skip\" className={classes?.skip}>\n {skipLabel}\n </SkipLink>\n {utility}\n <HeaderRoot\n variant={variant}\n navAlign={layout?.navAlign ?? 'center'}\n compactAfterScroll={layout?.compactAfterScroll ?? false}\n className={classes?.root}\n >\n <div {...slot(classes, 'bar')}>\n <div {...slot(classes, 'inner')}>\n <LogoLink href={homeHref} label={brandName} slot=\"logo\" className={classes?.logo}>\n {logo}\n </LogoLink>\n <NavController label=\"Main\" className={classes?.nav}>\n <ul {...slot(classes, 'list')}>\n {navigation.items.map((item) =>\n item.kind === 'link' ? (\n <LinkItem key={item.id} item={item} />\n ) : (\n <MenuItem key={item.id} item={item} panelId={`${idPrefix}-panel-${item.id}`} />\n ),\n )}\n </ul>\n </NavController>\n <div {...slot(classes, 'actions')}>\n {/* The phone sits beside the quote button with its icon on the left; its name is its visible text. */}\n <PhoneLink\n phone={phone}\n placement=\"header\"\n label={phoneLabel}\n showIcon\n variant={callFirst ? 'button' : 'text'}\n classes={{ root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber }}\n />\n <QuoteButton\n label={quote.label}\n href={quote.href}\n placement=\"header\"\n ctaId=\"quote-header\"\n classes={{ root: classes?.quote, label: classes?.quoteLabel, icon: classes?.quoteIcon }}\n />\n <MobileDrawer\n {...drawer}\n classes={{\n ...drawer?.classes,\n menuButton: cx(drawer?.classes?.menuButton, classes?.menuButton),\n menuLabel: cx(drawer?.classes?.menuLabel, classes?.menuLabel),\n }}\n navigation={navigation}\n phone={phone}\n phoneLabel={phoneLabel}\n quote={quote}\n socials={socials}\n logo={drawerLogo}\n idPrefix={idPrefix}\n />\n </div>\n </div>\n </div>\n </HeaderRoot>\n </>\n )\n}\n\nfunction LinkItem({ item }: { item: BrandlabNavLinkItem }) {\n return (\n <NavItem paths={[item.href, ...(item.activePaths ?? [])]}>\n <CurrentLink href={item.href} slot=\"link\">\n {item.label}\n </CurrentLink>\n </NavItem>\n )\n}\n\nfunction MenuItem({ item, panelId }: { item: BrandlabNavMenuItem; panelId: string }) {\n const groups = item.panel === 'columns' && item.groups && item.groups.length > 0 ? item.groups : undefined\n // A columns panel never drops a link: links outside every group follow in a last group without a heading.\n const grouped = new Set(groups?.flatMap((group) => group.links.map((link) => link.href)))\n const ungrouped = groups ? item.links.filter((link) => !grouped.has(link.href)) : []\n const columnCount = groups ? groups.length + (ungrouped.length > 0 ? 1 : 0) : 0\n return (\n <NavItem menuId={item.id} paths={[item.href, ...(item.activePaths ?? [])]}>\n <span {...repeatedSlot('itemRow')}>\n <CurrentLink href={item.href} slot=\"link\">\n {item.label}\n </CurrentLink>\n <NavTrigger menuId={item.id} panelId={panelId} label={item.label}>\n <Icon name=\"chevron\" />\n </NavTrigger>\n </span>\n <NavPanel\n menuId={item.id}\n panelId={panelId}\n variant={item.panel}\n columns={groups ? Math.min(3, Math.max(2, columnCount)) : undefined}\n \n >\n <div {...repeatedSlot('panelBody')}>\n {item.panel === 'featured' && item.featured ? (\n <CurrentLink href={item.featured.href} slot=\"featured\" prefetch={false}>\n <span {...repeatedSlot('featuredMedia')}>\n <Image\n src={item.featured.image.src}\n alt={item.featured.image.alt}\n width={item.featured.image.width}\n height={item.featured.image.height}\n sizes=\"240px\"\n />\n </span>\n <span {...repeatedSlot('featuredLabel')}>{item.featured.label}</span>\n <span {...repeatedSlot('featuredText')}>{item.featured.description}</span>\n </CurrentLink>\n ) : null}\n {/* Every panel repeats its hub link first. */}\n <ul {...repeatedSlot('panelList')}>\n <li>\n <CurrentLink href={item.href} slot=\"panelLink\" hub prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{item.hubLabel}</span>\n <Icon name=\"arrow\" />\n </CurrentLink>\n </li>\n {groups ? null : item.links.map((link) => <PanelLink key={link.href} link={link} />)}\n </ul>\n {groups?.map((group) => (\n <div key={group.heading} {...repeatedSlot('panelGroup')}>\n <p {...repeatedSlot('panelHeading')}>{group.heading}</p>\n <ul {...repeatedSlot('panelList')}>\n {group.links.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ))}\n {ungrouped.length > 0 ? (\n <div {...repeatedSlot('panelGroup')}>\n <ul {...repeatedSlot('panelList')}>\n {ungrouped.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ) : null}\n </div>\n </NavPanel>\n </NavItem>\n )\n}\n\nfunction PanelLink({ link }: { link: BrandlabNavMenuItem['links'][number] }) {\n return (\n <li>\n <CurrentLink href={link.href} slot=\"panelLink\" prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{link.label}</span>\n {link.description ? <span {...repeatedSlot('panelText')}>{link.description}</span> : null}\n </CurrentLink>\n </li>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"site-header.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/site-header.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * F2: the header shell (server component). The same structure on every site: the skip link, the optional utility\n * bar, then a sticky, solid `<header>` holding the logo, the menu, the phone and the quote button. Layout follows the\n * header's own width (container queries): from 1200 px the full menu; from 1024 to 1199 px a compact band with the\n * phone and its number, the quote button and a Menu button; below 1024 px the logo, a 44 px call button and a 44 px\n * Menu button. Every menu, hub and panel link is an `<a href>` in the server HTML (F3); client leaves only change\n * state.\n */\nimport type { BrandlabNavigation, BrandlabNavLinkItem, BrandlabNavMenuItem } from '@brandlab-digital/site-core/navigation'\nimport Image from 'next/image'\nimport type { ReactNode } from 'react'\nimport { SkipLink } from '../../ui.js'\nimport { MAIN_CONTENT_ID } from '../../navigation/constants.js'\nimport { Icon } from '../icons.js'\nimport { PhoneLink } from '../primitives/links.js'\nimport { ShellQuoteButton } from './shell-quote.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { cx, repeatedSlot, slot, type SkinEntry } from '../skin.js'\nimport type { UiPhone, UiSocial } from '../types.js'\nimport { CurrentLink, LogoLink } from './current-link.js'\nimport { HeaderRoot, NavController, NavItem, NavPanel, NavTrigger } from './header-client.js'\nimport { MobileDrawer, type MobileDrawerSkin, type ShellQuote } from './mobile-drawer.js'\n\nexport type SiteHeaderSlot =\n | 'skip'\n | 'root'\n | 'bar'\n | 'inner'\n | 'logo'\n | 'nav'\n | 'list'\n | 'item'\n | 'itemRow'\n | 'link'\n | 'trigger'\n | 'panel'\n | 'panelBody'\n | 'panelList'\n | 'panelGroup'\n | 'panelHeading'\n | 'panelLink'\n | 'panelLabel'\n | 'panelText'\n | 'featured'\n | 'featuredMedia'\n | 'featuredLabel'\n | 'featuredText'\n | 'actions'\n | 'phone'\n | 'phoneIcon'\n | 'phoneLabel'\n | 'phoneNumber'\n | 'quote'\n | 'quoteLabel'\n | 'quoteIcon'\n | 'menuButton'\n | 'menuLabel'\nexport const SITE_HEADER_VARIANTS = ['standard', 'call-first'] as const\n/**\n * `call-first` (recorded exceptions, v1 §9.10): the phone is the primary action (a button with its number at every\n * width); the quote button still follows it, as on `standard`.\n */\nexport type SiteHeaderVariant = (typeof SITE_HEADER_VARIANTS)[number]\nexport interface SiteHeaderLayout {\n /** Where the menu sits between the logo and the actions. */\n readonly navAlign?: 'center' | 'end'\n /** Compact the header (`data-compact=\"true\"`) once the page has scrolled 80 px. It never hides. */\n readonly compactAfterScroll?: boolean\n}\n/** Rendered once per menu item or panel link: styled from the skin stylesheet, never by class (3.14.0). */\nexport type SiteHeaderRepeatedSlot = RepeatedSlotOf<'siteHeader'>\nexport type SiteHeaderSkin = SkinEntry<SiteHeaderSlot, SiteHeaderVariant, SiteHeaderLayout, SiteHeaderRepeatedSlot>\n\nexport interface SiteHeaderProps extends SiteHeaderSkin {\n readonly navigation: BrandlabNavigation\n /** The logo link's accessible name. */\n readonly brandName: string\n readonly homeHref: string\n readonly logo: ReactNode\n /** From the derived business facts, never typed by hand. */\n readonly phone: UiPhone\n /** The small line above the number, for example \"Call us\". Also leads the drawer's Call button. */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n readonly socials?: readonly UiSocial[] | undefined\n /** The site's skip-link text, for example \"Skip to main content\". It targets `#main`. */\n readonly skipLabel: string\n /** The optional utility bar (`<UtilityBar>`), placed between the skip link and the header. */\n readonly utility?: ReactNode\n /** The site's `mobileDrawer` skin entry. */\n readonly drawer?: MobileDrawerSkin | undefined\n /** An optional logo for the drawer's top bar. */\n readonly drawerLogo?: ReactNode\n /** Prefix for element ids; one per header on the page. */\n readonly idPrefix?: string | undefined\n}\n\nexport function SiteHeader({\n navigation,\n brandName,\n homeHref,\n logo,\n phone,\n phoneLabel,\n quote,\n socials,\n skipLabel,\n utility,\n drawer,\n drawerLogo,\n idPrefix = 'bl-header',\n variant = 'standard',\n layout,\n classes,\n}: SiteHeaderProps) {\n const callFirst = variant === 'call-first'\n return (\n <>\n <SkipLink targetId={MAIN_CONTENT_ID} data-bl=\"skip\" className={classes?.skip}>\n {skipLabel}\n </SkipLink>\n {utility}\n <HeaderRoot\n variant={variant}\n navAlign={layout?.navAlign ?? 'center'}\n compactAfterScroll={layout?.compactAfterScroll ?? false}\n className={classes?.root}\n >\n <div {...slot(classes, 'bar')}>\n <div {...slot(classes, 'inner')}>\n <LogoLink href={homeHref} label={brandName} slot=\"logo\" className={classes?.logo}>\n {logo}\n </LogoLink>\n <NavController label=\"Main\" className={classes?.nav}>\n <ul {...slot(classes, 'list')}>\n {navigation.items.map((item) =>\n item.kind === 'link' ? (\n <LinkItem key={item.id} item={item} />\n ) : (\n <MenuItem key={item.id} item={item} panelId={`${idPrefix}-panel-${item.id}`} />\n ),\n )}\n </ul>\n </NavController>\n <div {...slot(classes, 'actions')}>\n {/* The phone sits beside the quote button with its icon on the left; its name is its visible text. */}\n <PhoneLink\n phone={phone}\n placement=\"header\"\n label={phoneLabel}\n showIcon\n variant={callFirst ? 'button' : 'text'}\n classes={{ root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber }}\n />\n <ShellQuoteButton\n label={quote.label}\n href={quote.href}\n placement=\"header\"\n ctaId=\"quote-header\"\n classes={{ root: classes?.quote, label: classes?.quoteLabel, icon: classes?.quoteIcon }}\n />\n <MobileDrawer\n {...drawer}\n classes={{\n ...drawer?.classes,\n menuButton: cx(drawer?.classes?.menuButton, classes?.menuButton),\n menuLabel: cx(drawer?.classes?.menuLabel, classes?.menuLabel),\n }}\n navigation={navigation}\n phone={phone}\n phoneLabel={phoneLabel}\n quote={quote}\n socials={socials}\n logo={drawerLogo}\n idPrefix={idPrefix}\n />\n </div>\n </div>\n </div>\n </HeaderRoot>\n </>\n )\n}\n\nfunction LinkItem({ item }: { item: BrandlabNavLinkItem }) {\n return (\n <NavItem paths={[item.href, ...(item.activePaths ?? [])]}>\n <CurrentLink href={item.href} slot=\"link\" prefetch=\"intent\">\n {item.label}\n </CurrentLink>\n </NavItem>\n )\n}\n\nfunction MenuItem({ item, panelId }: { item: BrandlabNavMenuItem; panelId: string }) {\n const groups = item.panel === 'columns' && item.groups && item.groups.length > 0 ? item.groups : undefined\n // A columns panel never drops a link: links outside every group follow in a last group without a heading.\n const grouped = new Set(groups?.flatMap((group) => group.links.map((link) => link.href)))\n const ungrouped = groups ? item.links.filter((link) => !grouped.has(link.href)) : []\n const columnCount = groups ? groups.length + (ungrouped.length > 0 ? 1 : 0) : 0\n return (\n <NavItem menuId={item.id} paths={[item.href, ...(item.activePaths ?? [])]}>\n <span {...repeatedSlot('itemRow')}>\n <CurrentLink href={item.href} slot=\"link\" prefetch=\"intent\">\n {item.label}\n </CurrentLink>\n <NavTrigger menuId={item.id} panelId={panelId} label={item.label}>\n <Icon name=\"chevron\" />\n </NavTrigger>\n </span>\n <NavPanel\n menuId={item.id}\n panelId={panelId}\n variant={item.panel}\n columns={groups ? Math.min(3, Math.max(2, columnCount)) : undefined}\n \n >\n <div {...repeatedSlot('panelBody')}>\n {item.panel === 'featured' && item.featured ? (\n <CurrentLink href={item.featured.href} slot=\"featured\" prefetch={false}>\n <span {...repeatedSlot('featuredMedia')}>\n <Image\n src={item.featured.image.src}\n alt={item.featured.image.alt}\n width={item.featured.image.width}\n height={item.featured.image.height}\n sizes=\"240px\"\n />\n </span>\n <span {...repeatedSlot('featuredLabel')}>{item.featured.label}</span>\n <span {...repeatedSlot('featuredText')}>{item.featured.description}</span>\n </CurrentLink>\n ) : null}\n {/* Every panel repeats its hub link first. */}\n <ul {...repeatedSlot('panelList')}>\n <li>\n <CurrentLink href={item.href} slot=\"panelLink\" hub prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{item.hubLabel}</span>\n <Icon name=\"arrow\" />\n </CurrentLink>\n </li>\n {groups ? null : item.links.map((link) => <PanelLink key={link.href} link={link} />)}\n </ul>\n {groups?.map((group) => (\n <div key={group.heading} {...repeatedSlot('panelGroup')}>\n <p {...repeatedSlot('panelHeading')}>{group.heading}</p>\n <ul {...repeatedSlot('panelList')}>\n {group.links.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ))}\n {ungrouped.length > 0 ? (\n <div {...repeatedSlot('panelGroup')}>\n <ul {...repeatedSlot('panelList')}>\n {ungrouped.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ) : null}\n </div>\n </NavPanel>\n </NavItem>\n )\n}\n\nfunction PanelLink({ link }: { link: BrandlabNavMenuItem['links'][number] }) {\n return (\n <li>\n <CurrentLink href={link.href} slot=\"panelLink\" prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{link.label}</span>\n {link.description ? <span {...repeatedSlot('panelText')}>{link.description}</span> : null}\n </CurrentLink>\n </li>\n )\n}\n"]}
|