@otl-core/next-navigation 1.1.34 → 1.1.36
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/components/navigation/dropdown.js +1 -11
- package/dist/components/navigation/dropdown.js.map +1 -1
- package/dist/components/navigation/header.js +7 -11
- package/dist/components/navigation/header.js.map +1 -1
- package/dist/lib/navigation.utils.js +40 -1
- package/dist/lib/navigation.utils.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { getBreakpointValue } from "@otl-core/cms-utils";
|
|
4
3
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
4
|
import { CSSTransition } from "react-transition-group";
|
|
6
5
|
import { useNavigation } from "../../context/navigation-context";
|
|
@@ -140,16 +139,7 @@ function NavigationDropdown({
|
|
|
140
139
|
zIndex: getDropdownZIndex(
|
|
141
140
|
useSameLayerMode,
|
|
142
141
|
navigation.style?.dropdown?.layer
|
|
143
|
-
)
|
|
144
|
-
marginTop: navigation.style?.dropdown?.offset?.y ? getBreakpointValue(navigation.style.dropdown.offset.y, "base") : "0",
|
|
145
|
-
marginLeft: navigation.style?.dropdown?.offset?.left ? getBreakpointValue(
|
|
146
|
-
navigation.style.dropdown.offset.left,
|
|
147
|
-
"base"
|
|
148
|
-
) : "0",
|
|
149
|
-
marginRight: navigation.style?.dropdown?.offset?.right ? getBreakpointValue(
|
|
150
|
-
navigation.style.dropdown.offset.right,
|
|
151
|
-
"base"
|
|
152
|
-
) : "0"
|
|
142
|
+
)
|
|
153
143
|
},
|
|
154
144
|
children: /* @__PURE__ */ jsx(
|
|
155
145
|
"div",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/navigation/dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n Site,\n HeaderConfig,\n HeaderDropdownGroupConfig,\n HeaderNavigationItemConfig,\n HeaderNavigationItemDropdownConfig,\n} from \"@otl-core/cms-types\";\nimport { HeaderDropdownContent } from \"@otl-core/cms-types\";\nimport { getBreakpointValue } from \"@otl-core/cms-utils\";\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\nimport { useNavigation } from \"../../context/navigation-context\";\nimport { resolveBorderToCSS, resolveColorsToCSS } from \"@otl-core/style-utils\";\nimport { DropdownContentItem } from \"../items/dropdown-content-item\";\n\nfunction getDropdownTimeout(isMobileMenu: boolean): number {\n return isMobileMenu ? 300 : 200;\n}\n\nfunction getDropdownClassNames(isMobileMenu: boolean): string {\n return isMobileMenu ? \"mobile-menu\" : \"desktop-dropdown\";\n}\n\nfunction getDropdownZIndex(\n isSameLayer: boolean,\n layer?: string,\n): number | undefined {\n if (isSameLayer) return undefined;\n return layer === \"above\" ? 9999 : undefined;\n}\n\ninterface NavigationDropdownProps {\n itemId: string;\n config: HeaderNavigationItemConfig;\n navigation: HeaderConfig;\n resolvedColors: Record<string, string | undefined>;\n styles: React.CSSProperties;\n linkStyle: React.CSSProperties;\n dropdownId: string;\n site: Site;\n containerContent?: boolean;\n isSameLayer?: boolean;\n}\nexport function NavigationDropdown({\n itemId,\n config,\n navigation,\n resolvedColors,\n dropdownId,\n site,\n containerContent = false,\n isSameLayer = false,\n}: NavigationDropdownProps) {\n const { activeDropdown } = useNavigation();\n const [navigationStack, setNavigationStack] = useState<string[]>([]);\n const nodeRef = useRef(null);\n const backButtonRef = useRef<HTMLButtonElement>(null);\n\n const isMobileMenu = useMemo(\n () => itemId.startsWith(\"mobile-menu\"),\n [itemId],\n );\n const isOpen = useMemo(\n () => activeDropdown === itemId,\n [activeDropdown, itemId],\n );\n const content: HeaderDropdownContent[] = useMemo(\n () => (config as HeaderNavigationItemDropdownConfig).content || [],\n [config],\n );\n\n // Reset nested content when dropdown closes (derived during render, no effect needed)\n const prevIsOpen = useRef(isOpen);\n if (prevIsOpen.current && !isOpen) {\n setNavigationStack([]);\n }\n prevIsOpen.current = isOpen;\n\n // Focus back button when navigating to nested content (DOM side effect, needs useEffect)\n useEffect(() => {\n if (navigationStack.length > 0 && backButtonRef.current) {\n backButtonRef.current.focus();\n }\n }, [navigationStack.length]);\n\n const handleNavigate = (contentId: string) => {\n setNavigationStack((prev) => [...prev, contentId]);\n };\n\n const handleBack = () => {\n setNavigationStack((prev) => prev.slice(0, -1));\n };\n\n // Helper to recursively find a dropdown by ID in content (including inside sections)\n const findDropdownById = (\n contentArray: HeaderDropdownContent[],\n id: string,\n ): HeaderDropdownContent | undefined => {\n for (const item of contentArray) {\n if (item.id === id && item.type === \"dropdown\") {\n return item;\n }\n // Search inside sections\n if (item.type === \"section\") {\n const config = item.config as HeaderDropdownGroupConfig;\n const found = findDropdownById(config.content, id);\n if (found) return found;\n }\n }\n return undefined;\n };\n\n // Build the navigation panels based on the stack\n const buildNavigationPanels = () => {\n const panels: Array<{\n content: HeaderDropdownContent[];\n depth: number;\n }> = [];\n\n // Root panel\n panels.push({ content: content, depth: 0 });\n\n // Build nested panels\n let currentContent = content;\n for (let i = 0; i < navigationStack.length; i++) {\n const contentId = navigationStack[i];\n const dropdownItem = findDropdownById(currentContent, contentId);\n\n if (dropdownItem && dropdownItem.config) {\n const nestedContent = (\n dropdownItem.config as HeaderNavigationItemDropdownConfig\n ).content;\n panels.push({ content: nestedContent, depth: i + 1 });\n currentContent = nestedContent;\n } else {\n break;\n }\n }\n\n return panels;\n };\n\n const panels = buildNavigationPanels();\n\n // Use the same color resolution as the rest of the system\n const dropdownColors = resolveColorsToCSS({\n dropdownMenuBackground: navigation.style?.dropdown?.background,\n dropdownMenuLinkColor: navigation.style?.dropdown?.link?.color,\n dropdownMenuLinkHoverColor: navigation.style?.dropdown?.link?.hoverColor,\n dropdownMenuLinkHoverBackground:\n navigation.style?.dropdown?.link?.hoverBackground,\n dropdownMenuTextColor: navigation.style?.dropdown?.textColor,\n });\n\n const dropdownMenuBackground = dropdownColors.dropdownMenuBackground;\n const dropdownMenuLinkColor = dropdownColors.dropdownMenuLinkColor;\n const dropdownMenuLinkHoverColor = dropdownColors.dropdownMenuLinkHoverColor;\n const dropdownMenuLinkHoverBackground =\n dropdownColors.dropdownMenuLinkHoverBackground || \"transparent\";\n const dropdownMenuTextColor = dropdownColors.dropdownMenuTextColor;\n\n const dropdownMenuBorder = useMemo(() => {\n if (!navigation.style?.dropdown?.border) return undefined;\n return resolveBorderToCSS(navigation.style.dropdown.border);\n }, [navigation.style?.dropdown?.border]);\n\n // Shadow is now handled via responsive CSS generation (generateResponsiveSpacingCSS)\n\n // Early return AFTER all hooks\n if (content.length === 0) return null;\n\n // Enhanced resolved colors for dropdown, using dropdown-specific text color if available\n const dropdownResolvedColors = {\n ...resolvedColors,\n text: dropdownMenuTextColor || resolvedColors.text,\n dropdownMenuLinkColor,\n };\n\n const useSameLayerMode = isSameLayer && !isMobileMenu;\n\n const dropdownStyles: React.CSSProperties = {\n backgroundColor: useSameLayerMode ? undefined : dropdownMenuBackground,\n color: dropdownMenuTextColor || dropdownMenuLinkColor,\n ...(useSameLayerMode ? {} : dropdownMenuBorder),\n };\n\n const linkHoverStyle = {\n \"--dropdown-link-hover-color\": dropdownMenuLinkHoverColor,\n \"--dropdown-link-hover-background\": dropdownMenuLinkHoverBackground,\n } as React.CSSProperties;\n\n return (\n <>\n <CSSTransition\n in={isOpen}\n nodeRef={nodeRef}\n timeout={useSameLayerMode ? 250 : getDropdownTimeout(isMobileMenu)}\n classNames={\n useSameLayerMode\n ? \"same-layer-dropdown\"\n : getDropdownClassNames(isMobileMenu)\n }\n unmountOnExit={!useSameLayerMode}\n >\n <div\n ref={nodeRef}\n className={`relative w-full navigation-dropdown-${dropdownId}`}\n style={{\n ...dropdownStyles,\n ...(useSameLayerMode\n ? { display: \"grid\", overflow: \"hidden\" }\n : { overflow: \"hidden\" }),\n zIndex: getDropdownZIndex(\n useSameLayerMode,\n navigation.style?.dropdown?.layer,\n ),\n marginTop: navigation.style?.dropdown?.offset?.y\n ? getBreakpointValue(navigation.style.dropdown.offset.y, \"base\")\n : \"0\",\n marginLeft: navigation.style?.dropdown?.offset?.left\n ? getBreakpointValue(\n navigation.style.dropdown.offset.left,\n \"base\",\n )\n : \"0\",\n marginRight: navigation.style?.dropdown?.offset?.right\n ? getBreakpointValue(\n navigation.style.dropdown.offset.right,\n \"base\",\n )\n : \"0\",\n }}\n >\n <div\n style={\n useSameLayerMode\n ? { overflow: \"hidden\", minHeight: 0 }\n : undefined\n }\n >\n <div\n style={{\n display: \"flex\",\n width: \"100%\",\n transform: `translateX(-${navigationStack.length * 100}%)`,\n transition: \"transform 300ms ease-in-out\",\n }}\n >\n {panels.map((panel, panelIndex) => {\n const isActive = panelIndex === navigationStack.length;\n const isToRight = panelIndex > navigationStack.length;\n\n const panelContent = (\n <>\n {panel.depth > 0 && (\n <button\n ref={\n panelIndex === navigationStack.length\n ? backButtonRef\n : null\n }\n onClick={(e) => {\n e.preventDefault();\n handleBack();\n }}\n type=\"button\"\n data-navigation-internal=\"true\"\n className=\"flex items-center px-3 py-2 text-sm rounded-md transition-colors mb-2\"\n style={{\n color:\n resolvedColors.dropdownMenuLinkColor ||\n resolvedColors.linkColor,\n }}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n className=\"mr-2\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n Back\n </button>\n )}\n\n <div className=\"flex flex-wrap gap-4\">\n {panel.content?.map((item: HeaderDropdownContent) => {\n if (item.type === \"section\") {\n return (\n <div key={item.id} className=\"flex-1 min-w-[200px]\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n }\n return (\n <div key={item.id} className=\"w-full\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n })}\n </div>\n </>\n );\n\n return (\n <nav\n key={panelIndex}\n className={`flex flex-col p-2 dropdown-content-${dropdownId}`}\n style={{\n ...linkHoverStyle,\n width: \"100%\",\n flexShrink: 0,\n transform: isToRight\n ? \"translateX(30px)\"\n : \"translateX(0)\",\n opacity: isActive ? 1 : 0.95,\n transition:\n \"transform 300ms ease-in-out, opacity 300ms ease-in-out\",\n }}\n inert={!isActive ? true : undefined}\n >\n {containerContent ? (\n <div className=\"container mx-auto\">{panelContent}</div>\n ) : (\n panelContent\n )}\n </nav>\n );\n })}\n </div>\n </div>\n </div>\n </CSSTransition>\n </>\n );\n}\n"],"mappings":"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","names":["config","panels"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/navigation/dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n Site,\n HeaderConfig,\n HeaderDropdownGroupConfig,\n HeaderNavigationItemConfig,\n HeaderNavigationItemDropdownConfig,\n} from \"@otl-core/cms-types\";\nimport { HeaderDropdownContent } from \"@otl-core/cms-types\";\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\nimport { useNavigation } from \"../../context/navigation-context\";\nimport { resolveBorderToCSS, resolveColorsToCSS } from \"@otl-core/style-utils\";\nimport { DropdownContentItem } from \"../items/dropdown-content-item\";\n\nfunction getDropdownTimeout(isMobileMenu: boolean): number {\n return isMobileMenu ? 300 : 200;\n}\n\nfunction getDropdownClassNames(isMobileMenu: boolean): string {\n return isMobileMenu ? \"mobile-menu\" : \"desktop-dropdown\";\n}\n\nfunction getDropdownZIndex(\n isSameLayer: boolean,\n layer?: string,\n): number | undefined {\n if (isSameLayer) return undefined;\n return layer === \"above\" ? 9999 : undefined;\n}\n\ninterface NavigationDropdownProps {\n itemId: string;\n config: HeaderNavigationItemConfig;\n navigation: HeaderConfig;\n resolvedColors: Record<string, string | undefined>;\n styles: React.CSSProperties;\n linkStyle: React.CSSProperties;\n dropdownId: string;\n site: Site;\n containerContent?: boolean;\n isSameLayer?: boolean;\n}\nexport function NavigationDropdown({\n itemId,\n config,\n navigation,\n resolvedColors,\n dropdownId,\n site,\n containerContent = false,\n isSameLayer = false,\n}: NavigationDropdownProps) {\n const { activeDropdown } = useNavigation();\n const [navigationStack, setNavigationStack] = useState<string[]>([]);\n const nodeRef = useRef(null);\n const backButtonRef = useRef<HTMLButtonElement>(null);\n\n const isMobileMenu = useMemo(\n () => itemId.startsWith(\"mobile-menu\"),\n [itemId],\n );\n const isOpen = useMemo(\n () => activeDropdown === itemId,\n [activeDropdown, itemId],\n );\n const content: HeaderDropdownContent[] = useMemo(\n () => (config as HeaderNavigationItemDropdownConfig).content || [],\n [config],\n );\n\n // Reset nested content when dropdown closes (derived during render, no effect needed)\n const prevIsOpen = useRef(isOpen);\n if (prevIsOpen.current && !isOpen) {\n setNavigationStack([]);\n }\n prevIsOpen.current = isOpen;\n\n // Focus back button when navigating to nested content (DOM side effect, needs useEffect)\n useEffect(() => {\n if (navigationStack.length > 0 && backButtonRef.current) {\n backButtonRef.current.focus();\n }\n }, [navigationStack.length]);\n\n const handleNavigate = (contentId: string) => {\n setNavigationStack((prev) => [...prev, contentId]);\n };\n\n const handleBack = () => {\n setNavigationStack((prev) => prev.slice(0, -1));\n };\n\n // Helper to recursively find a dropdown by ID in content (including inside sections)\n const findDropdownById = (\n contentArray: HeaderDropdownContent[],\n id: string,\n ): HeaderDropdownContent | undefined => {\n for (const item of contentArray) {\n if (item.id === id && item.type === \"dropdown\") {\n return item;\n }\n // Search inside sections\n if (item.type === \"section\") {\n const config = item.config as HeaderDropdownGroupConfig;\n const found = findDropdownById(config.content, id);\n if (found) return found;\n }\n }\n return undefined;\n };\n\n // Build the navigation panels based on the stack\n const buildNavigationPanels = () => {\n const panels: Array<{\n content: HeaderDropdownContent[];\n depth: number;\n }> = [];\n\n // Root panel\n panels.push({ content: content, depth: 0 });\n\n // Build nested panels\n let currentContent = content;\n for (let i = 0; i < navigationStack.length; i++) {\n const contentId = navigationStack[i];\n const dropdownItem = findDropdownById(currentContent, contentId);\n\n if (dropdownItem && dropdownItem.config) {\n const nestedContent = (\n dropdownItem.config as HeaderNavigationItemDropdownConfig\n ).content;\n panels.push({ content: nestedContent, depth: i + 1 });\n currentContent = nestedContent;\n } else {\n break;\n }\n }\n\n return panels;\n };\n\n const panels = buildNavigationPanels();\n\n // Use the same color resolution as the rest of the system\n const dropdownColors = resolveColorsToCSS({\n dropdownMenuBackground: navigation.style?.dropdown?.background,\n dropdownMenuLinkColor: navigation.style?.dropdown?.link?.color,\n dropdownMenuLinkHoverColor: navigation.style?.dropdown?.link?.hoverColor,\n dropdownMenuLinkHoverBackground:\n navigation.style?.dropdown?.link?.hoverBackground,\n dropdownMenuTextColor: navigation.style?.dropdown?.textColor,\n });\n\n const dropdownMenuBackground = dropdownColors.dropdownMenuBackground;\n const dropdownMenuLinkColor = dropdownColors.dropdownMenuLinkColor;\n const dropdownMenuLinkHoverColor = dropdownColors.dropdownMenuLinkHoverColor;\n const dropdownMenuLinkHoverBackground =\n dropdownColors.dropdownMenuLinkHoverBackground || \"transparent\";\n const dropdownMenuTextColor = dropdownColors.dropdownMenuTextColor;\n\n const dropdownMenuBorder = useMemo(() => {\n if (!navigation.style?.dropdown?.border) return undefined;\n return resolveBorderToCSS(navigation.style.dropdown.border);\n }, [navigation.style?.dropdown?.border]);\n\n // Shadow is now handled via responsive CSS generation (generateResponsiveSpacingCSS)\n\n // Early return AFTER all hooks\n if (content.length === 0) return null;\n\n // Enhanced resolved colors for dropdown, using dropdown-specific text color if available\n const dropdownResolvedColors = {\n ...resolvedColors,\n text: dropdownMenuTextColor || resolvedColors.text,\n dropdownMenuLinkColor,\n };\n\n const useSameLayerMode = isSameLayer && !isMobileMenu;\n\n const dropdownStyles: React.CSSProperties = {\n backgroundColor: useSameLayerMode ? undefined : dropdownMenuBackground,\n color: dropdownMenuTextColor || dropdownMenuLinkColor,\n ...(useSameLayerMode ? {} : dropdownMenuBorder),\n };\n\n const linkHoverStyle = {\n \"--dropdown-link-hover-color\": dropdownMenuLinkHoverColor,\n \"--dropdown-link-hover-background\": dropdownMenuLinkHoverBackground,\n } as React.CSSProperties;\n\n return (\n <>\n <CSSTransition\n in={isOpen}\n nodeRef={nodeRef}\n timeout={useSameLayerMode ? 250 : getDropdownTimeout(isMobileMenu)}\n classNames={\n useSameLayerMode\n ? \"same-layer-dropdown\"\n : getDropdownClassNames(isMobileMenu)\n }\n unmountOnExit={!useSameLayerMode}\n >\n <div\n ref={nodeRef}\n className={`relative w-full navigation-dropdown-${dropdownId}`}\n style={{\n ...dropdownStyles,\n ...(useSameLayerMode\n ? { display: \"grid\", overflow: \"hidden\" }\n : { overflow: \"hidden\" }),\n zIndex: getDropdownZIndex(\n useSameLayerMode,\n navigation.style?.dropdown?.layer,\n ),\n }}\n >\n <div\n style={\n useSameLayerMode\n ? { overflow: \"hidden\", minHeight: 0 }\n : undefined\n }\n >\n <div\n style={{\n display: \"flex\",\n width: \"100%\",\n transform: `translateX(-${navigationStack.length * 100}%)`,\n transition: \"transform 300ms ease-in-out\",\n }}\n >\n {panels.map((panel, panelIndex) => {\n const isActive = panelIndex === navigationStack.length;\n const isToRight = panelIndex > navigationStack.length;\n\n const panelContent = (\n <>\n {panel.depth > 0 && (\n <button\n ref={\n panelIndex === navigationStack.length\n ? backButtonRef\n : null\n }\n onClick={(e) => {\n e.preventDefault();\n handleBack();\n }}\n type=\"button\"\n data-navigation-internal=\"true\"\n className=\"flex items-center px-3 py-2 text-sm rounded-md transition-colors mb-2\"\n style={{\n color:\n resolvedColors.dropdownMenuLinkColor ||\n resolvedColors.linkColor,\n }}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n className=\"mr-2\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n Back\n </button>\n )}\n\n <div className=\"flex flex-wrap gap-4\">\n {panel.content?.map((item: HeaderDropdownContent) => {\n if (item.type === \"section\") {\n return (\n <div key={item.id} className=\"flex-1 min-w-[200px]\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n }\n return (\n <div key={item.id} className=\"w-full\">\n <DropdownContentItem\n content={item}\n resolvedColors={dropdownResolvedColors}\n onNavigate={handleNavigate}\n navigation={navigation}\n site={site}\n />\n </div>\n );\n })}\n </div>\n </>\n );\n\n return (\n <nav\n key={panelIndex}\n className={`flex flex-col p-2 dropdown-content-${dropdownId}`}\n style={{\n ...linkHoverStyle,\n width: \"100%\",\n flexShrink: 0,\n transform: isToRight\n ? \"translateX(30px)\"\n : \"translateX(0)\",\n opacity: isActive ? 1 : 0.95,\n transition:\n \"transform 300ms ease-in-out, opacity 300ms ease-in-out\",\n }}\n inert={!isActive ? true : undefined}\n >\n {containerContent ? (\n <div className=\"container mx-auto\">{panelContent}</div>\n ) : (\n panelContent\n )}\n </nav>\n );\n })}\n </div>\n </div>\n </div>\n </CSSTransition>\n </>\n );\n}\n"],"mappings":"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","names":["config","panels"]}
|
|
@@ -40,8 +40,7 @@ const Header = ({
|
|
|
40
40
|
}) => {
|
|
41
41
|
const isFixed = navigation.style?.position === "fixed";
|
|
42
42
|
const containerBehavior = navigation.style?.container || "edged";
|
|
43
|
-
const
|
|
44
|
-
const safeZoneHeight = typeof safeZone === "object" && "base" in safeZone ? safeZone.base : safeZone || "0";
|
|
43
|
+
const hasSafeZone = !!navigation.style?.safeZone;
|
|
45
44
|
const estimatedWidth = calculateNavigationWidth(
|
|
46
45
|
navigation.sections || [],
|
|
47
46
|
site
|
|
@@ -89,7 +88,6 @@ const Header = ({
|
|
|
89
88
|
const linkStyle = {
|
|
90
89
|
...resolvedColors.linkColor && { color: resolvedColors.linkColor }
|
|
91
90
|
};
|
|
92
|
-
const marginValue = typeof navigation.style?.layout?.margin === "object" && "base" in navigation.style.layout.margin ? navigation.style.layout.margin.base : navigation.style?.layout?.margin || "0";
|
|
93
91
|
const sortedSections = [...navigation.sections || []].sort(
|
|
94
92
|
(a, b) => a.order - b.order
|
|
95
93
|
);
|
|
@@ -191,10 +189,10 @@ const Header = ({
|
|
|
191
189
|
NavigationHeaderWrapper,
|
|
192
190
|
{
|
|
193
191
|
className: cn(
|
|
192
|
+
`header-${id}`,
|
|
194
193
|
"relative",
|
|
195
194
|
isFixed ? "fixed top-0 left-0 right-0 z-50" : "absolute top-0 left-0 right-0 z-50"
|
|
196
195
|
),
|
|
197
|
-
style: { margin: marginValue },
|
|
198
196
|
"data-container": containerBehavior,
|
|
199
197
|
children: navbarWithContainer2
|
|
200
198
|
}
|
|
@@ -203,11 +201,10 @@ const Header = ({
|
|
|
203
201
|
styles && /* @__PURE__ */ jsx("style", { children: styles }),
|
|
204
202
|
/* @__PURE__ */ jsxs(NavigationProvider, { children: [
|
|
205
203
|
headerContent2,
|
|
206
|
-
|
|
204
|
+
hasSafeZone && /* @__PURE__ */ jsx(
|
|
207
205
|
"div",
|
|
208
206
|
{
|
|
209
|
-
className:
|
|
210
|
-
style: { height: safeZoneHeight },
|
|
207
|
+
className: `header-safe-zone-${id} bg-surface`,
|
|
211
208
|
"aria-hidden": "true"
|
|
212
209
|
}
|
|
213
210
|
)
|
|
@@ -276,10 +273,10 @@ const Header = ({
|
|
|
276
273
|
NavigationHeaderWrapper,
|
|
277
274
|
{
|
|
278
275
|
className: cn(
|
|
276
|
+
`header-${id}`,
|
|
279
277
|
"relative",
|
|
280
278
|
isFixed ? "fixed top-0 left-0 right-0 z-50" : "absolute top-0 left-0 right-0 z-50"
|
|
281
279
|
),
|
|
282
|
-
style: { margin: marginValue },
|
|
283
280
|
"data-container": containerBehavior,
|
|
284
281
|
children: navbarWithContainer
|
|
285
282
|
}
|
|
@@ -288,11 +285,10 @@ const Header = ({
|
|
|
288
285
|
styles && /* @__PURE__ */ jsx("style", { children: styles }),
|
|
289
286
|
/* @__PURE__ */ jsxs(NavigationProvider, { children: [
|
|
290
287
|
headerContent,
|
|
291
|
-
|
|
288
|
+
hasSafeZone && /* @__PURE__ */ jsx(
|
|
292
289
|
"div",
|
|
293
290
|
{
|
|
294
|
-
className:
|
|
295
|
-
style: { height: safeZoneHeight },
|
|
291
|
+
className: `header-safe-zone-${id} bg-surface`,
|
|
296
292
|
"aria-hidden": "true"
|
|
297
293
|
}
|
|
298
294
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/navigation/header.tsx"],"sourcesContent":["import {\n ColorReference,\n Site,\n HeaderConfig,\n HeaderNavigationItem,\n HeaderNavigationItemConfig,\n} from \"@otl-core/cms-types\";\nimport React from \"react\";\nimport { NavigationProvider } from \"../../context/navigation-context\";\nimport {\n cn,\n resolveColorToCSS,\n resolveColorsToCSS,\n} from \"@otl-core/style-utils\";\nimport {\n calculateNavigationWidth,\n generateNavigationCSS,\n getBreakpointForWidth,\n sectionsToDropdownContent,\n} from \"../../lib/navigation.utils\";\nimport { NavigationHeaderWrapper } from \"../mobile/navigation-header-wrapper\";\nimport { NavigationDropdown } from \"./dropdown\";\nimport { Navbar } from \"./navbar\";\n\nconst SHOW_CLASSES = {\n sm: \"hidden sm:flex\",\n md: \"hidden md:flex\",\n lg: \"hidden lg:flex\",\n xl: \"hidden xl:flex\",\n \"2xl\": \"hidden 2xl:flex\",\n} as const;\n\nconst HIDE_CLASSES = {\n sm: \"sm:hidden\",\n md: \"md:hidden\",\n lg: \"lg:hidden\",\n xl: \"xl:hidden\",\n \"2xl\": \"2xl:hidden\",\n} as const;\n\ninterface NavigationHeaderProps {\n navigation: HeaderConfig;\n site: Site;\n className?: string;\n siteName?: string;\n id?: string;\n}\n\nexport const Header: React.FC<NavigationHeaderProps> = ({\n navigation,\n site = {\n default_locale: \"en\",\n supported_locales: [\"en\"],\n } as Site,\n className = \"\",\n siteName: _siteName = \"Logo\",\n id = \"default\",\n}) => {\n const isFixed = navigation.style?.position === \"fixed\";\n const containerBehavior = navigation.style?.container || \"edged\";\n const safeZone = navigation.style?.safeZone;\n const safeZoneHeight =\n typeof safeZone === \"object\" && \"base\" in safeZone\n ? safeZone.base\n : safeZone || \"0\";\n\n const estimatedWidth = calculateNavigationWidth(\n navigation.sections || [],\n site,\n );\n const breakpoint = getBreakpointForWidth(estimatedWidth);\n\n const styleType = navigation.style?.type || \"default\";\n\n const showClass = breakpoint ? SHOW_CLASSES[breakpoint] : \"\";\n const hideClass = breakpoint ? HIDE_CLASSES[breakpoint] : \"\";\n\n const resolvedColors: Record<string, string | undefined> = navigation.style\n ? {\n ...resolveColorsToCSS(\n Object.fromEntries(\n Object.entries(navigation.style).filter(\n ([key]) =>\n key !== \"type\" &&\n key !== \"position\" &&\n key !== \"container\" &&\n key !== \"safeZone\" &&\n key !== \"layout\" &&\n key !== \"border\" &&\n key !== \"shadow\" &&\n key !== \"link\" &&\n key !== \"burger\" &&\n key !== \"dropdown\" &&\n key !== \"background\" &&\n key !== \"text\",\n ),\n ) as Record<string, ColorReference | undefined>,\n ),\n // Manually resolve background and text colors\n background: resolveColorToCSS(navigation.style.background),\n text: resolveColorToCSS(navigation.style.text),\n // Manually resolve link colors\n linkColor: resolveColorToCSS(navigation.style.link?.color),\n linkHoverColor: resolveColorToCSS(navigation.style.link?.hoverColor),\n // Manually resolve burger colors\n burgerButtonBackground: resolveColorToCSS(\n navigation.style.burger?.button?.background,\n ),\n burgerButtonBackgroundHover: resolveColorToCSS(\n navigation.style.burger?.button?.backgroundHover,\n ),\n burgerIconColor: resolveColorToCSS(\n navigation.style.burger?.icon?.color,\n ),\n burgerIconHover: resolveColorToCSS(\n navigation.style.burger?.icon?.hoverColor,\n ),\n }\n : {};\n\n const headerStyles: React.CSSProperties = {\n ...(resolvedColors.background && {\n backgroundColor: resolvedColors.background,\n }),\n ...(resolvedColors.text && {\n color: resolvedColors.text,\n }),\n };\n\n const linkStyle: React.CSSProperties = {\n ...(resolvedColors.linkColor && { color: resolvedColors.linkColor }),\n };\n\n // Extract margin for inline styles\n const marginValue =\n typeof navigation.style?.layout?.margin === \"object\" &&\n \"base\" in navigation.style.layout.margin\n ? navigation.style.layout.margin.base\n : navigation.style?.layout?.margin || \"0\";\n\n const sortedSections = [...(navigation.sections || [])].sort(\n (a, b) => a.order - b.order,\n );\n\n // Determine which section should have the toggler\n let togglerSectionId = navigation.togglerSectionId;\n\n // \"none\" means explicitly no mobile toggler at all\n if (togglerSectionId === \"none\") {\n togglerSectionId = \"\";\n } else if (!togglerSectionId) {\n // If no togglerSectionId specified, auto-assign to last non-logo section if there's content\n const hasContent = sortedSections.some((section) =>\n section.items?.some((item: HeaderNavigationItem) => item.type !== \"logo\"),\n );\n\n if (hasContent) {\n const nonLogoSections = sortedSections.filter(\n (section) =>\n !section.items?.some(\n (item: HeaderNavigationItem) => item.type === \"logo\",\n ),\n );\n\n if (nonLogoSections.length > 0) {\n togglerSectionId = nonLogoSections[nonLogoSections.length - 1].id;\n }\n }\n }\n\n const dropdownItems: Array<{\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }> = [];\n sortedSections.forEach((section) => {\n section.items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"dropdown\") {\n dropdownItems.push({\n item: item,\n config: item.config || {},\n });\n }\n });\n });\n\n // Collect all dropdown IDs for CSS generation (including mobile menu)\n const dropdownIds = [\n `mobile-menu-${id}`,\n ...(dropdownItems || []).map((d) => d.item.id),\n ];\n\n // Generate all CSS once at the header level\n const styles = generateNavigationCSS(\n id,\n navigation,\n resolvedColors,\n dropdownIds,\n );\n\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n if (styleType === \"minimal\") {\n // Minimal mode: All items render in navbar, but items without collapse:false get \"hidden\" class\n // This means only logo and collapse:false items are VISIBLE\n const navbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass=\"hidden\" // All items hidden by default in minimal mode\n togglerHideClass=\"\" // Always show toggler in minimal mode\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(({ item, config }) => (\n <NavigationDropdown\n key={item.id}\n itemId={item.id}\n config={config}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ))}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {navbarAndDropdowns}\n </div>\n ) : (\n navbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n style={{ margin: marginValue }}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {safeZoneHeight && safeZoneHeight !== \"0\" && (\n <div\n className=\"header-safe-zone bg-surface\"\n style={{ height: safeZoneHeight }}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n }\n\n const defaultNavbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass={showClass}\n togglerHideClass={hideClass}\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(\n ({\n item,\n config,\n }: {\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }) => (\n <NavigationDropdown\n config={config}\n key={item.id}\n itemId={item.id}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ),\n )}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {defaultNavbarAndDropdowns}\n </div>\n ) : (\n defaultNavbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n style={{ margin: marginValue }}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {safeZoneHeight && safeZoneHeight !== \"0\" && (\n <div\n className=\"header-safe-zone bg-surface\"\n style={{ height: safeZoneHeight }}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n};\n"],"mappings":"AA6MM,mBACE,KADF;AArMN,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,+BAA+B;AACxC,SAAS,0BAA0B;AACnC,SAAS,cAAc;AAEvB,MAAM,eAAe;AAAA,EACnB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AACT;AAEA,MAAM,eAAe;AAAA,EACnB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AACT;AAUO,MAAM,SAA0C,CAAC;AAAA,EACtD;AAAA,EACA,OAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,mBAAmB,CAAC,IAAI;AAAA,EAC1B;AAAA,EACA,YAAY;AAAA,EACZ,UAAU,YAAY;AAAA,EACtB,KAAK;AACP,MAAM;AACJ,QAAM,UAAU,WAAW,OAAO,aAAa;AAC/C,QAAM,oBAAoB,WAAW,OAAO,aAAa;AACzD,QAAM,WAAW,WAAW,OAAO;AACnC,QAAM,iBACJ,OAAO,aAAa,YAAY,UAAU,WACtC,SAAS,OACT,YAAY;AAElB,QAAM,iBAAiB;AAAA,IACrB,WAAW,YAAY,CAAC;AAAA,IACxB;AAAA,EACF;AACA,QAAM,aAAa,sBAAsB,cAAc;AAEvD,QAAM,YAAY,WAAW,OAAO,QAAQ;AAE5C,QAAM,YAAY,aAAa,aAAa,UAAU,IAAI;AAC1D,QAAM,YAAY,aAAa,aAAa,UAAU,IAAI;AAE1D,QAAM,iBAAqD,WAAW,QAClE;AAAA,IACE,GAAG;AAAA,MACD,OAAO;AAAA,QACL,OAAO,QAAQ,WAAW,KAAK,EAAE;AAAA,UAC/B,CAAC,CAAC,GAAG,MACH,QAAQ,UACR,QAAQ,cACR,QAAQ,eACR,QAAQ,cACR,QAAQ,YACR,QAAQ,YACR,QAAQ,YACR,QAAQ,UACR,QAAQ,YACR,QAAQ,cACR,QAAQ,gBACR,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAEA,YAAY,kBAAkB,WAAW,MAAM,UAAU;AAAA,IACzD,MAAM,kBAAkB,WAAW,MAAM,IAAI;AAAA;AAAA,IAE7C,WAAW,kBAAkB,WAAW,MAAM,MAAM,KAAK;AAAA,IACzD,gBAAgB,kBAAkB,WAAW,MAAM,MAAM,UAAU;AAAA;AAAA,IAEnE,wBAAwB;AAAA,MACtB,WAAW,MAAM,QAAQ,QAAQ;AAAA,IACnC;AAAA,IACA,6BAA6B;AAAA,MAC3B,WAAW,MAAM,QAAQ,QAAQ;AAAA,IACnC;AAAA,IACA,iBAAiB;AAAA,MACf,WAAW,MAAM,QAAQ,MAAM;AAAA,IACjC;AAAA,IACA,iBAAiB;AAAA,MACf,WAAW,MAAM,QAAQ,MAAM;AAAA,IACjC;AAAA,EACF,IACA,CAAC;AAEL,QAAM,eAAoC;AAAA,IACxC,GAAI,eAAe,cAAc;AAAA,MAC/B,iBAAiB,eAAe;AAAA,IAClC;AAAA,IACA,GAAI,eAAe,QAAQ;AAAA,MACzB,OAAO,eAAe;AAAA,IACxB;AAAA,EACF;AAEA,QAAM,YAAiC;AAAA,IACrC,GAAI,eAAe,aAAa,EAAE,OAAO,eAAe,UAAU;AAAA,EACpE;AAGA,QAAM,cACJ,OAAO,WAAW,OAAO,QAAQ,WAAW,YAC5C,UAAU,WAAW,MAAM,OAAO,SAC9B,WAAW,MAAM,OAAO,OAAO,OAC/B,WAAW,OAAO,QAAQ,UAAU;AAE1C,QAAM,iBAAiB,CAAC,GAAI,WAAW,YAAY,CAAC,CAAE,EAAE;AAAA,IACtD,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE;AAAA,EACxB;AAGA,MAAI,mBAAmB,WAAW;AAGlC,MAAI,qBAAqB,QAAQ;AAC/B,uBAAmB;AAAA,EACrB,WAAW,CAAC,kBAAkB;AAE5B,UAAM,aAAa,eAAe;AAAA,MAAK,CAAC,YACtC,QAAQ,OAAO,KAAK,CAAC,SAA+B,KAAK,SAAS,MAAM;AAAA,IAC1E;AAEA,QAAI,YAAY;AACd,YAAM,kBAAkB,eAAe;AAAA,QACrC,CAAC,YACC,CAAC,QAAQ,OAAO;AAAA,UACd,CAAC,SAA+B,KAAK,SAAS;AAAA,QAChD;AAAA,MACJ;AAEA,UAAI,gBAAgB,SAAS,GAAG;AAC9B,2BAAmB,gBAAgB,gBAAgB,SAAS,CAAC,EAAE;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,gBAGD,CAAC;AACN,iBAAe,QAAQ,CAAC,YAAY;AAClC,YAAQ,OAAO,QAAQ,CAAC,SAA+B;AACrD,UAAI,KAAK,SAAS,YAAY;AAC5B,sBAAc,KAAK;AAAA,UACjB;AAAA,UACA,QAAQ,KAAK,UAAU,CAAC;AAAA,QAC1B,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAGD,QAAM,cAAc;AAAA,IAClB,eAAe,EAAE;AAAA,IACjB,IAAI,iBAAiB,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE;AAAA,EAC/C;AAGA,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,cAAc,WAAW,OAAO,UAAU,UAAU;AAE1D,MAAI,cAAc,WAAW;AAG3B,UAAM,qBACJ,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,cAAc,cAAc,CAAC,IAAI;AAAA,UACjC;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB,oBAAoB;AAAA,UACtC,gBAAe;AAAA,UACf,kBAAiB;AAAA,UACjB;AAAA,UACA,cAAc,eAAe,EAAE;AAAA,UAC/B,kBAAkB,sBAAsB;AAAA,UACxC;AAAA;AAAA,MACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,QAAQ,eAAe,EAAE;AAAA,UACzB,QAAQ,EAAE,SAAS,0BAA0B,cAAc,EAAE;AAAA,UAC7D;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA,YAAY,eAAe,EAAE;AAAA,UAC7B;AAAA,UACA,kBAAkB,sBAAsB;AAAA,UACxC;AAAA;AAAA,MACF;AAAA,MACC,eAAe,IAAI,CAAC,EAAE,MAAM,OAAO,MAClC;AAAA,QAAC;AAAA;AAAA,UAEC,QAAQ,KAAK;AAAA,UACb;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA,YAAY,KAAK;AAAA,UACjB;AAAA,UACA,kBAAkB,sBAAsB;AAAA,UACxC;AAAA;AAAA,QAVK,KAAK;AAAA,MAWZ,CACD;AAAA,OACH;AAGF,UAAMA,iBAAgB,cACpB,oBAAC,SAAI,WAAW,kBAAkB,EAAE,IAAI,OAAO,cAC5C,8BACH,IAEA;AAGF,UAAMC,uBACJ,sBAAsB,UACpB,oBAAC,SAAI,WAAU,qBAAqB,UAAAD,gBAAc,IAElDA;AAGJ,UAAME,iBACJ;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,UACI,oCACA;AAAA,QACN;AAAA,QACA,OAAO,EAAE,QAAQ,YAAY;AAAA,QAC7B,kBAAgB;AAAA,QAEf,UAAAD;AAAA;AAAA,IACH;AAGF,WACE,iCACG;AAAA,gBAAU,oBAAC,WAAO,kBAAO;AAAA,MAC1B,qBAAC,sBACE;AAAA,QAAAC;AAAA,QACA,kBAAkB,mBAAmB,OACpC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,QAAQ,eAAe;AAAA,YAChC,eAAY;AAAA;AAAA,QACd;AAAA,SAEJ;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,4BACJ,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,cAAc,cAAc,CAAC,IAAI;AAAA,QACjC;AAAA,QACA;AAAA,QACA;AAAA,QACA,kBAAkB,oBAAoB;AAAA,QACtC,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,QAClB;AAAA,QACA,cAAc,eAAe,EAAE;AAAA,QAC/B,kBAAkB,sBAAsB;AAAA,QACxC;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,eAAe,EAAE;AAAA,QACzB,QAAQ,EAAE,SAAS,0BAA0B,cAAc,EAAE;AAAA,QAC7D;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA,YAAY,eAAe,EAAE;AAAA,QAC7B;AAAA,QACA,kBAAkB,sBAAsB;AAAA,QACxC;AAAA;AAAA,IACF;AAAA,IACC,eAAe;AAAA,MACd,CAAC;AAAA,QACC;AAAA,QACA;AAAA,MACF,MAIE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UAEA,QAAQ,KAAK;AAAA,UACb;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA,YAAY,KAAK;AAAA,UACjB;AAAA,UACA,kBAAkB,sBAAsB;AAAA,UACxC;AAAA;AAAA,QATK,KAAK;AAAA,MAUZ;AAAA,IAEJ;AAAA,KACF;AAGF,QAAM,gBAAgB,cACpB,oBAAC,SAAI,WAAW,kBAAkB,EAAE,IAAI,OAAO,cAC5C,qCACH,IAEA;AAGF,QAAM,sBACJ,sBAAsB,UACpB,oBAAC,SAAI,WAAU,qBAAqB,yBAAc,IAElD;AAGJ,QAAM,gBACJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,UACI,oCACA;AAAA,MACN;AAAA,MACA,OAAO,EAAE,QAAQ,YAAY;AAAA,MAC7B,kBAAgB;AAAA,MAEf;AAAA;AAAA,EACH;AAGF,SACE,iCACG;AAAA,cAAU,oBAAC,WAAO,kBAAO;AAAA,IAC1B,qBAAC,sBACE;AAAA;AAAA,MACA,kBAAkB,mBAAmB,OACpC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,QAAQ,eAAe;AAAA,UAChC,eAAY;AAAA;AAAA,MACd;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":["navbarContent","navbarWithContainer","headerContent"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/navigation/header.tsx"],"sourcesContent":["import {\n ColorReference,\n Site,\n HeaderConfig,\n HeaderNavigationItem,\n HeaderNavigationItemConfig,\n} from \"@otl-core/cms-types\";\nimport React from \"react\";\nimport { NavigationProvider } from \"../../context/navigation-context\";\nimport {\n cn,\n resolveColorToCSS,\n resolveColorsToCSS,\n} from \"@otl-core/style-utils\";\nimport {\n calculateNavigationWidth,\n generateNavigationCSS,\n getBreakpointForWidth,\n sectionsToDropdownContent,\n} from \"../../lib/navigation.utils\";\nimport { NavigationHeaderWrapper } from \"../mobile/navigation-header-wrapper\";\nimport { NavigationDropdown } from \"./dropdown\";\nimport { Navbar } from \"./navbar\";\n\nconst SHOW_CLASSES = {\n sm: \"hidden sm:flex\",\n md: \"hidden md:flex\",\n lg: \"hidden lg:flex\",\n xl: \"hidden xl:flex\",\n \"2xl\": \"hidden 2xl:flex\",\n} as const;\n\nconst HIDE_CLASSES = {\n sm: \"sm:hidden\",\n md: \"md:hidden\",\n lg: \"lg:hidden\",\n xl: \"xl:hidden\",\n \"2xl\": \"2xl:hidden\",\n} as const;\n\ninterface NavigationHeaderProps {\n navigation: HeaderConfig;\n site: Site;\n className?: string;\n siteName?: string;\n id?: string;\n}\n\nexport const Header: React.FC<NavigationHeaderProps> = ({\n navigation,\n site = {\n default_locale: \"en\",\n supported_locales: [\"en\"],\n } as Site,\n className = \"\",\n siteName: _siteName = \"Logo\",\n id = \"default\",\n}) => {\n const isFixed = navigation.style?.position === \"fixed\";\n const containerBehavior = navigation.style?.container || \"edged\";\n const hasSafeZone = !!navigation.style?.safeZone;\n\n const estimatedWidth = calculateNavigationWidth(\n navigation.sections || [],\n site,\n );\n const breakpoint = getBreakpointForWidth(estimatedWidth);\n\n const styleType = navigation.style?.type || \"default\";\n\n const showClass = breakpoint ? SHOW_CLASSES[breakpoint] : \"\";\n const hideClass = breakpoint ? HIDE_CLASSES[breakpoint] : \"\";\n\n const resolvedColors: Record<string, string | undefined> = navigation.style\n ? {\n ...resolveColorsToCSS(\n Object.fromEntries(\n Object.entries(navigation.style).filter(\n ([key]) =>\n key !== \"type\" &&\n key !== \"position\" &&\n key !== \"container\" &&\n key !== \"safeZone\" &&\n key !== \"layout\" &&\n key !== \"border\" &&\n key !== \"shadow\" &&\n key !== \"link\" &&\n key !== \"burger\" &&\n key !== \"dropdown\" &&\n key !== \"background\" &&\n key !== \"text\",\n ),\n ) as Record<string, ColorReference | undefined>,\n ),\n // Manually resolve background and text colors\n background: resolveColorToCSS(navigation.style.background),\n text: resolveColorToCSS(navigation.style.text),\n // Manually resolve link colors\n linkColor: resolveColorToCSS(navigation.style.link?.color),\n linkHoverColor: resolveColorToCSS(navigation.style.link?.hoverColor),\n // Manually resolve burger colors\n burgerButtonBackground: resolveColorToCSS(\n navigation.style.burger?.button?.background,\n ),\n burgerButtonBackgroundHover: resolveColorToCSS(\n navigation.style.burger?.button?.backgroundHover,\n ),\n burgerIconColor: resolveColorToCSS(\n navigation.style.burger?.icon?.color,\n ),\n burgerIconHover: resolveColorToCSS(\n navigation.style.burger?.icon?.hoverColor,\n ),\n }\n : {};\n\n const headerStyles: React.CSSProperties = {\n ...(resolvedColors.background && {\n backgroundColor: resolvedColors.background,\n }),\n ...(resolvedColors.text && {\n color: resolvedColors.text,\n }),\n };\n\n const linkStyle: React.CSSProperties = {\n ...(resolvedColors.linkColor && { color: resolvedColors.linkColor }),\n };\n\n const sortedSections = [...(navigation.sections || [])].sort(\n (a, b) => a.order - b.order,\n );\n\n // Determine which section should have the toggler\n let togglerSectionId = navigation.togglerSectionId;\n\n // \"none\" means explicitly no mobile toggler at all\n if (togglerSectionId === \"none\") {\n togglerSectionId = \"\";\n } else if (!togglerSectionId) {\n // If no togglerSectionId specified, auto-assign to last non-logo section if there's content\n const hasContent = sortedSections.some((section) =>\n section.items?.some((item: HeaderNavigationItem) => item.type !== \"logo\"),\n );\n\n if (hasContent) {\n const nonLogoSections = sortedSections.filter(\n (section) =>\n !section.items?.some(\n (item: HeaderNavigationItem) => item.type === \"logo\",\n ),\n );\n\n if (nonLogoSections.length > 0) {\n togglerSectionId = nonLogoSections[nonLogoSections.length - 1].id;\n }\n }\n }\n\n const dropdownItems: Array<{\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }> = [];\n sortedSections.forEach((section) => {\n section.items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"dropdown\") {\n dropdownItems.push({\n item: item,\n config: item.config || {},\n });\n }\n });\n });\n\n // Collect all dropdown IDs for CSS generation (including mobile menu)\n const dropdownIds = [\n `mobile-menu-${id}`,\n ...(dropdownItems || []).map((d) => d.item.id),\n ];\n\n // Generate all CSS once at the header level\n const styles = generateNavigationCSS(\n id,\n navigation,\n resolvedColors,\n dropdownIds,\n );\n\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n if (styleType === \"minimal\") {\n // Minimal mode: All items render in navbar, but items without collapse:false get \"hidden\" class\n // This means only logo and collapse:false items are VISIBLE\n const navbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass=\"hidden\" // All items hidden by default in minimal mode\n togglerHideClass=\"\" // Always show toggler in minimal mode\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(({ item, config }) => (\n <NavigationDropdown\n key={item.id}\n itemId={item.id}\n config={config}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ))}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {navbarAndDropdowns}\n </div>\n ) : (\n navbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n `header-${id}`,\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {hasSafeZone && (\n <div\n className={`header-safe-zone-${id} bg-surface`}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n }\n\n const defaultNavbarAndDropdowns = (\n <>\n <Navbar\n id={id}\n className={className}\n headerStyles={isSameLayer ? {} : headerStyles}\n sortedSections={sortedSections}\n navigation={navigation}\n resolvedColors={resolvedColors}\n togglerSectionId={togglerSectionId || \"navbar\"}\n itemsShowClass={showClass}\n togglerHideClass={hideClass}\n site={site}\n mobileMenuId={`mobile-menu-${id}`}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n <NavigationDropdown\n itemId={`mobile-menu-${id}`}\n config={{ content: sectionsToDropdownContent(sortedSections) }}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={`mobile-menu-${id}`}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n {dropdownItems?.map(\n ({\n item,\n config,\n }: {\n item: HeaderNavigationItem;\n config: HeaderNavigationItemConfig;\n }) => (\n <NavigationDropdown\n config={config}\n key={item.id}\n itemId={item.id}\n navigation={navigation}\n resolvedColors={resolvedColors}\n styles={headerStyles}\n linkStyle={linkStyle}\n dropdownId={item.id}\n site={site}\n containerContent={containerBehavior === \"edged\"}\n isSameLayer={isSameLayer}\n />\n ),\n )}\n </>\n );\n\n const navbarContent = isSameLayer ? (\n <div className={`navbar-wrapper-${id}`} style={headerStyles}>\n {defaultNavbarAndDropdowns}\n </div>\n ) : (\n defaultNavbarAndDropdowns\n );\n\n const navbarWithContainer =\n containerBehavior === \"boxed\" ? (\n <div className=\"container mx-auto\">{navbarContent}</div>\n ) : (\n navbarContent\n );\n\n const headerContent = (\n <NavigationHeaderWrapper\n className={cn(\n `header-${id}`,\n \"relative\",\n isFixed\n ? \"fixed top-0 left-0 right-0 z-50\"\n : \"absolute top-0 left-0 right-0 z-50\",\n )}\n data-container={containerBehavior}\n >\n {navbarWithContainer}\n </NavigationHeaderWrapper>\n );\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <NavigationProvider>\n {headerContent}\n {hasSafeZone && (\n <div\n className={`header-safe-zone-${id} bg-surface`}\n aria-hidden=\"true\"\n />\n )}\n </NavigationProvider>\n </>\n );\n};\n"],"mappings":"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","names":["navbarContent","navbarWithContainer","headerContent"]}
|
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
generateSameLayerDropdownAnimations,
|
|
7
7
|
generateScrollbarStyles,
|
|
8
8
|
generateToggleIconAnimations,
|
|
9
|
-
minifyCSS
|
|
9
|
+
minifyCSS,
|
|
10
|
+
normalizeResponsiveValue
|
|
10
11
|
} from "@otl-core/style-utils";
|
|
11
12
|
function shadowConfigToCSS(shadow) {
|
|
12
13
|
const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;
|
|
@@ -102,6 +103,18 @@ function generateNavigationCSS(id, navigation, resolvedColors, dropdownIds = [])
|
|
|
102
103
|
const cssBlocks = [];
|
|
103
104
|
const isSameLayer = navigation.style?.dropdown?.layer === "same";
|
|
104
105
|
cssBlocks.push(...generateLogoCSS(id, navigation));
|
|
106
|
+
if (navigation.style?.layout?.margin) {
|
|
107
|
+
const headerMarginCSS = generateResponsiveSpacingCSS(`header-${id}`, {
|
|
108
|
+
margin: navigation.style.layout.margin
|
|
109
|
+
});
|
|
110
|
+
if (headerMarginCSS) cssBlocks.push(headerMarginCSS);
|
|
111
|
+
}
|
|
112
|
+
if (navigation.style?.safeZone) {
|
|
113
|
+
const safeZoneCSS = generateResponsiveSpacingCSS(`header-safe-zone-${id}`, {
|
|
114
|
+
height: navigation.style.safeZone
|
|
115
|
+
});
|
|
116
|
+
if (safeZoneCSS) cssBlocks.push(safeZoneCSS);
|
|
117
|
+
}
|
|
105
118
|
if (navigation.style) {
|
|
106
119
|
if (isSameLayer) {
|
|
107
120
|
const wrapperCSS = generateResponsiveSpacingCSS(`navbar-wrapper-${id}`, {
|
|
@@ -134,6 +147,32 @@ function generateNavigationCSS(id, navigation, resolvedColors, dropdownIds = [])
|
|
|
134
147
|
);
|
|
135
148
|
}
|
|
136
149
|
}
|
|
150
|
+
if (navigation.style?.dropdown?.offset) {
|
|
151
|
+
const offset = navigation.style.dropdown.offset;
|
|
152
|
+
const yNorm = normalizeResponsiveValue(offset.y);
|
|
153
|
+
const leftNorm = normalizeResponsiveValue(offset.left);
|
|
154
|
+
const rightNorm = normalizeResponsiveValue(offset.right);
|
|
155
|
+
const breakpoints = ["base", "sm", "md", "lg", "xl", "2xl"];
|
|
156
|
+
const compositeMargin = {};
|
|
157
|
+
for (const bp of breakpoints) {
|
|
158
|
+
const top = yNorm[bp] || (bp === "base" ? "0" : void 0);
|
|
159
|
+
const left = leftNorm[bp] || (bp === "base" ? "0" : void 0);
|
|
160
|
+
const right = rightNorm[bp] || (bp === "base" ? "0" : void 0);
|
|
161
|
+
if (top !== void 0 || left !== void 0 || right !== void 0) {
|
|
162
|
+
compositeMargin[bp] = `${top || "0"} ${right || "0"} 0 ${left || "0"}`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (Object.keys(compositeMargin).length > 0) {
|
|
166
|
+
const marginValue = compositeMargin.base ? Object.keys(compositeMargin).length === 1 ? compositeMargin.base : compositeMargin : compositeMargin;
|
|
167
|
+
dropdownIds.forEach((dropdownId) => {
|
|
168
|
+
const offsetCSS = generateResponsiveSpacingCSS(
|
|
169
|
+
`navigation-dropdown-${dropdownId}`,
|
|
170
|
+
{ margin: marginValue }
|
|
171
|
+
);
|
|
172
|
+
if (offsetCSS) cssBlocks.push(offsetCSS);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
137
176
|
if (navigation.style && dropdownIds.length > 0) {
|
|
138
177
|
dropdownIds.forEach((dropdownId) => {
|
|
139
178
|
if (isSameLayer) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/navigation.utils.ts"],"sourcesContent":["import {\n Site,\n HeaderConfig,\n HeaderDropdownButtonConfig,\n HeaderDropdownContent,\n HeaderDropdownNavigationItemConfig,\n HeaderNavigationItem,\n HeaderNavigationItemButtonConfig,\n HeaderNavigationItemDropdownConfig,\n HeaderNavigationItemImageConfig,\n HeaderNavigationItemLinkConfig,\n HeaderNavigationItemMarkdownConfig,\n HeaderSection,\n LocalizedString,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { marked } from \"marked\";\nimport {\n generateDesktopDropdownAnimations,\n generateMobileMenuAnimations,\n generateResponsiveSpacingCSS,\n generateSameLayerDropdownAnimations,\n generateScrollbarStyles,\n generateToggleIconAnimations,\n minifyCSS,\n} from \"@otl-core/style-utils\";\n\n/**\n * Convert ShadowConfig to CSS box-shadow string\n */\nexport function shadowConfigToCSS(shadow: ShadowConfig): string {\n const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;\n const parts = [offsetX, offsetY, blurRadius, spreadRadius, color];\n if (inset) {\n return `inset ${parts.join(\" \")}`;\n }\n return parts.join(\" \");\n}\n\nexport function calculateNavigationWidth(\n sections: HeaderSection[],\n site?: Site,\n): number {\n let totalWidth = 150;\n\n for (const section of sections) {\n for (const item of section?.items || []) {\n if (item.type === \"logo\") continue;\n\n const label =\n typeof item.label === \"string\"\n ? item.label\n : getLocalizedString(item.label, site) || \"\";\n const labelLength = label.length;\n\n if (item.type === \"button\") {\n totalWidth += labelLength * 8 + 48;\n } else if (\n item.type === \"link\" ||\n item.type === \"dropdown\" ||\n item.type === \"markdown\"\n ) {\n totalWidth += labelLength * 8 + 24;\n } else if (item.type === \"image\") {\n const imgConfig = item.config as { width?: string };\n const imgWidth = imgConfig?.width\n ? parseInt(imgConfig.width, 10) || 100\n : 100;\n totalWidth += imgWidth + 16;\n }\n }\n }\n\n return totalWidth;\n}\n\nexport type Breakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | null;\n\nexport function getBreakpointForWidth(estimatedWidth: number): Breakpoint {\n const MAX_USABLE_WIDTH = 1400;\n\n if (estimatedWidth > MAX_USABLE_WIDTH) return null;\n\n if (estimatedWidth <= 640) return \"sm\";\n if (estimatedWidth <= 768) return \"md\";\n if (estimatedWidth <= 1024) return \"lg\";\n if (estimatedWidth <= 1280) return \"xl\";\n return \"2xl\";\n}\n\nconst RESPONSIVE_BREAKPOINTS = [\n { key: \"sm\", minWidth: \"640px\" },\n { key: \"md\", minWidth: \"768px\" },\n { key: \"lg\", minWidth: \"1024px\" },\n { key: \"xl\", minWidth: \"1280px\" },\n] as const;\n\nfunction generateResponsiveCustomProps(\n className: string,\n props: Record<string, ResponsiveValue<string> | undefined>,\n): string[] {\n const css: string[] = [];\n const baseVars: string[] = [];\n const bpVars: Record<string, string[]> = {};\n\n for (const [prop, value] of Object.entries(props)) {\n if (!value) continue;\n if (typeof value === \"string\") {\n baseVars.push(`${prop}:${value}`);\n } else {\n if (value.base) baseVars.push(`${prop}:${value.base}`);\n for (const { key } of RESPONSIVE_BREAKPOINTS) {\n const bpVal = value[key as keyof typeof value];\n if (bpVal && typeof bpVal === \"string\") {\n if (!bpVars[key]) bpVars[key] = [];\n bpVars[key].push(`${prop}:${bpVal}`);\n }\n }\n }\n }\n\n const target = `.${className}`;\n if (baseVars.length > 0) {\n css.push(`${target}{${baseVars.join(\";\")}}`);\n }\n for (const { key, minWidth } of RESPONSIVE_BREAKPOINTS) {\n if (bpVars[key]?.length) {\n css.push(\n `@media(min-width:${minWidth}){${target}{${bpVars[key].join(\";\")}}}`,\n );\n }\n }\n return css;\n}\n\n/**\n * Normalize a logo size value (responsive, plain string, or legacy\n * numeric pixels) into a ResponsiveValue<string>.\n */\nfunction normalizeLogoSize(\n value: ResponsiveValue<string> | number | undefined,\n): ResponsiveValue<string> | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"number\") return { base: `${value}px` };\n if (typeof value === \"string\") return { base: value };\n return value;\n}\n\nfunction generateLogoCSS(id: string, navigation: HeaderConfig): string[] {\n if (!navigation.logo?.url) return [];\n const width = normalizeLogoSize(navigation.logo.width) ?? { base: \"auto\" };\n const height = normalizeLogoSize(navigation.logo.height) ?? { base: \"40px\" };\n return generateResponsiveCustomProps(`navbar-${id} .navigation-logo-img`, {\n width,\n height,\n });\n}\n\nexport function generateNavigationCSS(\n id: string,\n navigation: HeaderConfig,\n resolvedColors: Record<string, string | undefined>,\n dropdownIds: string[] = [],\n): string {\n const cssBlocks: (string | null)[] = [];\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n cssBlocks.push(...generateLogoCSS(id, navigation));\n\n // Margins are now applied inline, no CSS generation needed\n\n if (navigation.style) {\n if (isSameLayer) {\n // Same layer: navbar wrapper gets border/padding/shadow, navbar itself only gets inner styles\n const wrapperCSS = generateResponsiveSpacingCSS(`navbar-wrapper-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (wrapperCSS) cssBlocks.push(wrapperCSS);\n } else {\n const navbarCSS = generateResponsiveSpacingCSS(`navbar-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (navbarCSS) cssBlocks.push(navbarCSS);\n }\n\n const navbarInnerCSS = generateResponsiveSpacingCSS(`navbar-inner-${id}`, {\n gap: navigation.style.layout?.sectionGap,\n fontSize: navigation.style.fontSize?.navbar,\n });\n if (navbarInnerCSS) cssBlocks.push(navbarInnerCSS);\n\n const btnFontSize = navigation.style.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`navbar-inner-${id}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n }\n\n if (navigation.style && dropdownIds.length > 0) {\n dropdownIds.forEach((dropdownId) => {\n if (isSameLayer) {\n // Same layer: dropdown only gets gap/fontSize, no border/padding/shadow (inherited from wrapper)\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n } else {\n const dropdownCSS = generateResponsiveSpacingCSS(\n `navigation-dropdown-${dropdownId}`,\n {\n padding: navigation.style?.dropdown?.padding,\n border: navigation.style?.dropdown?.border,\n shadow: navigation.style?.dropdown?.shadow,\n },\n );\n if (dropdownCSS) cssBlocks.push(dropdownCSS);\n\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n }\n\n const btnFontSize = navigation.style?.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`dropdown-content-${dropdownId}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n });\n }\n\n if (resolvedColors.burgerButtonBackgroundHover) {\n cssBlocks.push(\n `.mobile-menu-toggle-${id}:hover{background-color:${resolvedColors.burgerButtonBackgroundHover}!important}`,\n );\n }\n\n if (\n resolvedColors.dropdownMenuLinkHoverColor ||\n resolvedColors.dropdownMenuLinkHoverBackground\n ) {\n const hoverStyles: string[] = [];\n if (resolvedColors.dropdownMenuLinkHoverBackground) {\n hoverStyles.push(\n `background-color:${resolvedColors.dropdownMenuLinkHoverBackground}!important`,\n );\n }\n if (resolvedColors.dropdownMenuLinkHoverColor) {\n hoverStyles.push(\n `color:${resolvedColors.dropdownMenuLinkHoverColor}!important`,\n );\n }\n cssBlocks.push(\n `#mobile-menu-dropdown-${id} a:hover{${hoverStyles.join(\";\")}}`,\n );\n }\n\n cssBlocks.push(...generateToggleIconAnimations());\n cssBlocks.push(...generateMobileMenuAnimations());\n cssBlocks.push(...generateScrollbarStyles());\n cssBlocks.push(...generateDesktopDropdownAnimations());\n if (isSameLayer) {\n cssBlocks.push(...generateSameLayerDropdownAnimations());\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\nexport function sectionsToDropdownContent(\n sections: HeaderSection[],\n): HeaderDropdownContent[] {\n const result: HeaderDropdownContent[] = [];\n let lastSectionHadContent = false;\n\n sections.forEach((section: HeaderSection, index: number) => {\n const items = section?.items?.filter((item: HeaderNavigationItem) => {\n if (item.type === \"logo\") return false;\n if (resolveItemVisibility(item) === \"navbar-only\") return false;\n return true;\n });\n\n if (items?.length === 0) {\n return; // Skip this section, don't update lastSectionHadContent\n }\n\n // Add divider if the previous section had content and this isn't the first section with content\n if (lastSectionHadContent && result.length > 0) {\n result.push({\n id: `divider-${sections[index - 1].id}`,\n type: \"divider\",\n config: {},\n });\n }\n\n items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"link\") {\n const config = item.config as HeaderNavigationItemLinkConfig;\n const navConfig: HeaderDropdownNavigationItemConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n };\n result.push({\n id: item.id,\n type: \"navigation-item\",\n config: navConfig,\n });\n } else if (item.type === \"button\") {\n const config = item.config as HeaderNavigationItemButtonConfig;\n const btnConfig: HeaderDropdownButtonConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n variant: config.variant,\n size: config.size,\n };\n result.push({\n id: item.id,\n type: \"button\",\n config: btnConfig,\n });\n } else if (item.type === \"dropdown\") {\n const config = item.config as HeaderNavigationItemDropdownConfig;\n result.push({\n id: item.id,\n type: \"dropdown\",\n label: item.label || \"\",\n config,\n });\n } else if (item.type === \"markdown\") {\n const config = item.config as HeaderNavigationItemMarkdownConfig;\n result.push({\n id: item.id,\n type: \"markdown\",\n config: { content: config.content || item.label || \"\" },\n });\n } else if (item.type === \"image\") {\n const config = item.config as HeaderNavigationItemImageConfig;\n result.push({\n id: item.id,\n type: \"image\",\n config: {\n src: config.src,\n alt: config.alt,\n width: config.width ? { base: config.width } : { base: \"100%\" },\n height: config.height ? { base: config.height } : { base: \"auto\" },\n objectFit: config.objectFit,\n href: config.href,\n },\n });\n }\n });\n\n lastSectionHadContent = true;\n });\n\n return result;\n}\n\nexport function resolveDropdownColor(\n colorRef: { type: string; value: string } | undefined,\n resolvedColors: Record<string, string | undefined>,\n fallback?: string,\n): string | undefined {\n if (!colorRef) return fallback;\n\n if (colorRef.type === \"custom\") {\n return colorRef.value;\n }\n\n if (colorRef.type === \"theme\") {\n return resolvedColors[colorRef.value] || fallback;\n }\n\n if (colorRef.type === \"variable\") {\n // For variables, construct the CSS variable reference\n return `var(--color-${colorRef.value})`;\n }\n\n return fallback;\n}\n\nfunction getBrowserPreferredLocales(options = {}) {\n const defaultOptions = {\n languageCodeOnly: false,\n };\n const opt = {\n ...defaultOptions,\n ...options,\n };\n const browserLocales =\n navigator.languages === undefined\n ? [navigator.language]\n : navigator.languages;\n if (!browserLocales) {\n return undefined;\n }\n return browserLocales.map((locale) => {\n const trimmedLocale = locale.trim();\n return opt.languageCodeOnly ? trimmedLocale.split(/-|_/)[0] : trimmedLocale;\n });\n}\n\nexport function getLocalizedString(\n value: string | LocalizedString | null | undefined,\n options?:\n | Site\n | {\n preferredLocale?: string;\n defaultLocale?: string;\n supportedLocales?: string[];\n },\n): string {\n // Handle null/undefined\n if (value === null || value === undefined) return \"\";\n\n // If it's already a string, return it\n if (typeof value === \"string\") return value;\n\n // Normalize options to handle both Site and simple options object\n const preferredLocale =\n options && \"preferredLocale\" in options\n ? options.preferredLocale\n : undefined;\n function getDefaultLocale(): string | undefined {\n if (options && \"defaultLocale\" in options) return options.defaultLocale;\n if (options && \"default_locale\" in options) return options.default_locale;\n return undefined;\n }\n function getSupportedLocales(): string[] | undefined {\n if (options && \"supportedLocales\" in options)\n return options.supportedLocales;\n if (options && \"supported_locales\" in options)\n return options.supported_locales;\n return undefined;\n }\n const defaultLocale = getDefaultLocale();\n const supportedLocales = getSupportedLocales();\n\n // Try preferred locale first (if explicitly provided)\n if (preferredLocale && preferredLocale in value && value[preferredLocale]) {\n return value[preferredLocale];\n }\n\n // Try browser locales if no explicit preferred locale\n if (!preferredLocale) {\n const browserLocales = getBrowserPreferredLocales();\n if (browserLocales) {\n for (const locale of browserLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n }\n\n // Try default locale\n if (defaultLocale && defaultLocale in value && value[defaultLocale]) {\n return value[defaultLocale];\n }\n\n // Try 'en' as fallback\n if (\"en\" in value && value.en) {\n return value.en;\n }\n\n // Try any supported locale\n if (supportedLocales) {\n for (const locale of supportedLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n\n // Return first available value as last resort\n const keys = Object.keys(value);\n if (keys.length > 0 && value[keys[0]]) {\n return value[keys[0]];\n }\n\n return \"\";\n}\n\n/**\n * Resolve the effective visibility for a navigation item.\n * Supports the new `visibility` field and the legacy `collapse` field.\n * collapse: false → \"navbar-only\", collapse: true/undefined → \"responsive\"\n */\nexport function resolveItemVisibility(\n item: HeaderNavigationItem,\n): HeaderNavigationItem[\"visibility\"] {\n if (item.visibility) return item.visibility;\n const legacy = (item as unknown as Record<string, unknown>).collapse;\n if (legacy === false) return \"navbar-only\";\n return undefined;\n}\n\nconst VISIBILITY_CLASSES: Record<string, string> = {\n \"navbar-only\": \"flex\",\n \"mobile-only\": \"hidden\",\n both: \"flex\",\n};\n\n/**\n * Get the CSS class for an item's visibility, falling back to the\n * responsive breakpoint class when no explicit visibility is set.\n */\nexport function getVisibilityClass(\n item: HeaderNavigationItem,\n fallback?: string,\n): string {\n const vis = resolveItemVisibility(item);\n return (vis && VISIBILITY_CLASSES[vis]) || fallback || \"\";\n}\n\nexport function parseMarkdownToHTML(markdown: string): string {\n // Parse markdown to HTML\n const html = marked.parse(markdown, { async: false }) as string;\n\n // Transform h1-h6 elements to divs with corresponding classes\n return html\n .replace(/<h1>/g, '<div class=\"h1\">')\n .replace(/<\\/h1>/g, \"</div>\")\n .replace(/<h2>/g, '<div class=\"h2\">')\n .replace(/<\\/h2>/g, \"</div>\")\n .replace(/<h3>/g, '<div class=\"h3\">')\n .replace(/<\\/h3>/g, \"</div>\")\n .replace(/<h4>/g, '<div class=\"h4\">')\n .replace(/<\\/h4>/g, \"</div>\")\n .replace(/<h5>/g, '<div class=\"h5\">')\n .replace(/<\\/h5>/g, \"</div>\")\n .replace(/<h6>/g, '<div class=\"h6\">')\n .replace(/<\\/h6>/g, \"</div>\");\n}\n"],"mappings":"AAiBA,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAKA,SAAS,kBAAkB,QAA8B;AAC9D,QAAM,EAAE,SAAS,SAAS,YAAY,cAAc,OAAO,MAAM,IAAI;AACrE,QAAM,QAAQ,CAAC,SAAS,SAAS,YAAY,cAAc,KAAK;AAChE,MAAI,OAAO;AACT,WAAO,SAAS,MAAM,KAAK,GAAG,CAAC;AAAA,EACjC;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAEO,SAAS,yBACd,UACA,MACQ;AACR,MAAI,aAAa;AAEjB,aAAW,WAAW,UAAU;AAC9B,eAAW,QAAQ,SAAS,SAAS,CAAC,GAAG;AACvC,UAAI,KAAK,SAAS,OAAQ;AAE1B,YAAM,QACJ,OAAO,KAAK,UAAU,WAClB,KAAK,QACL,mBAAmB,KAAK,OAAO,IAAI,KAAK;AAC9C,YAAM,cAAc,MAAM;AAE1B,UAAI,KAAK,SAAS,UAAU;AAC1B,sBAAc,cAAc,IAAI;AAAA,MAClC,WACE,KAAK,SAAS,UACd,KAAK,SAAS,cACd,KAAK,SAAS,YACd;AACA,sBAAc,cAAc,IAAI;AAAA,MAClC,WAAW,KAAK,SAAS,SAAS;AAChC,cAAM,YAAY,KAAK;AACvB,cAAM,WAAW,WAAW,QACxB,SAAS,UAAU,OAAO,EAAE,KAAK,MACjC;AACJ,sBAAc,WAAW;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAIO,SAAS,sBAAsB,gBAAoC;AACxE,QAAM,mBAAmB;AAEzB,MAAI,iBAAiB,iBAAkB,QAAO;AAE9C,MAAI,kBAAkB,IAAK,QAAO;AAClC,MAAI,kBAAkB,IAAK,QAAO;AAClC,MAAI,kBAAkB,KAAM,QAAO;AACnC,MAAI,kBAAkB,KAAM,QAAO;AACnC,SAAO;AACT;AAEA,MAAM,yBAAyB;AAAA,EAC7B,EAAE,KAAK,MAAM,UAAU,QAAQ;AAAA,EAC/B,EAAE,KAAK,MAAM,UAAU,QAAQ;AAAA,EAC/B,EAAE,KAAK,MAAM,UAAU,SAAS;AAAA,EAChC,EAAE,KAAK,MAAM,UAAU,SAAS;AAClC;AAEA,SAAS,8BACP,WACA,OACU;AACV,QAAM,MAAgB,CAAC;AACvB,QAAM,WAAqB,CAAC;AAC5B,QAAM,SAAmC,CAAC;AAE1C,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AACjD,QAAI,CAAC,MAAO;AACZ,QAAI,OAAO,UAAU,UAAU;AAC7B,eAAS,KAAK,GAAG,IAAI,IAAI,KAAK,EAAE;AAAA,IAClC,OAAO;AACL,UAAI,MAAM,KAAM,UAAS,KAAK,GAAG,IAAI,IAAI,MAAM,IAAI,EAAE;AACrD,iBAAW,EAAE,IAAI,KAAK,wBAAwB;AAC5C,cAAM,QAAQ,MAAM,GAAyB;AAC7C,YAAI,SAAS,OAAO,UAAU,UAAU;AACtC,cAAI,CAAC,OAAO,GAAG,EAAG,QAAO,GAAG,IAAI,CAAC;AACjC,iBAAO,GAAG,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,EAAE;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,IAAI,SAAS;AAC5B,MAAI,SAAS,SAAS,GAAG;AACvB,QAAI,KAAK,GAAG,MAAM,IAAI,SAAS,KAAK,GAAG,CAAC,GAAG;AAAA,EAC7C;AACA,aAAW,EAAE,KAAK,SAAS,KAAK,wBAAwB;AACtD,QAAI,OAAO,GAAG,GAAG,QAAQ;AACvB,UAAI;AAAA,QACF,oBAAoB,QAAQ,KAAK,MAAM,IAAI,OAAO,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,kBACP,OACqC;AACrC,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,EAAE,MAAM,GAAG,KAAK,KAAK;AAC3D,MAAI,OAAO,UAAU,SAAU,QAAO,EAAE,MAAM,MAAM;AACpD,SAAO;AACT;AAEA,SAAS,gBAAgB,IAAY,YAAoC;AACvE,MAAI,CAAC,WAAW,MAAM,IAAK,QAAO,CAAC;AACnC,QAAM,QAAQ,kBAAkB,WAAW,KAAK,KAAK,KAAK,EAAE,MAAM,OAAO;AACzE,QAAM,SAAS,kBAAkB,WAAW,KAAK,MAAM,KAAK,EAAE,MAAM,OAAO;AAC3E,SAAO,8BAA8B,UAAU,EAAE,yBAAyB;AAAA,IACxE;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEO,SAAS,sBACd,IACA,YACA,gBACA,cAAwB,CAAC,GACjB;AACR,QAAM,YAA+B,CAAC;AACtC,QAAM,cAAc,WAAW,OAAO,UAAU,UAAU;AAE1D,YAAU,KAAK,GAAG,gBAAgB,IAAI,UAAU,CAAC;AAIjD,MAAI,WAAW,OAAO;AACpB,QAAI,aAAa;AAEf,YAAM,aAAa,6BAA6B,kBAAkB,EAAE,IAAI;AAAA,QACtE,QAAQ,WAAW,MAAM;AAAA,QACzB,SAAS,WAAW,MAAM,QAAQ;AAAA,QAClC,QAAQ,WAAW,MAAM;AAAA,MAC3B,CAAC;AACD,UAAI,WAAY,WAAU,KAAK,UAAU;AAAA,IAC3C,OAAO;AACL,YAAM,YAAY,6BAA6B,UAAU,EAAE,IAAI;AAAA,QAC7D,QAAQ,WAAW,MAAM;AAAA,QACzB,SAAS,WAAW,MAAM,QAAQ;AAAA,QAClC,QAAQ,WAAW,MAAM;AAAA,MAC3B,CAAC;AACD,UAAI,UAAW,WAAU,KAAK,SAAS;AAAA,IACzC;AAEA,UAAM,iBAAiB,6BAA6B,gBAAgB,EAAE,IAAI;AAAA,MACxE,KAAK,WAAW,MAAM,QAAQ;AAAA,MAC9B,UAAU,WAAW,MAAM,UAAU;AAAA,IACvC,CAAC;AACD,QAAI,eAAgB,WAAU,KAAK,cAAc;AAEjD,UAAM,cAAc,WAAW,MAAM,UAAU;AAC/C,QAAI,aAAa;AACf,gBAAU;AAAA,QACR,GAAG,8BAA8B,gBAAgB,EAAE,IAAI;AAAA,UACrD,iBAAiB,YAAY;AAAA,UAC7B,iBAAiB,YAAY;AAAA,UAC7B,iBAAiB,YAAY;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,MAAI,WAAW,SAAS,YAAY,SAAS,GAAG;AAC9C,gBAAY,QAAQ,CAAC,eAAe;AAClC,UAAI,aAAa;AAEf,cAAM,qBAAqB;AAAA,UACzB,oBAAoB,UAAU;AAAA,UAC9B;AAAA,YACE,KAAK,WAAW,OAAO,UAAU;AAAA,YACjC,UAAU,WAAW,OAAO,UAAU;AAAA,UACxC;AAAA,QACF;AACA,YAAI,mBAAoB,WAAU,KAAK,kBAAkB;AAAA,MAC3D,OAAO;AACL,cAAM,cAAc;AAAA,UAClB,uBAAuB,UAAU;AAAA,UACjC;AAAA,YACE,SAAS,WAAW,OAAO,UAAU;AAAA,YACrC,QAAQ,WAAW,OAAO,UAAU;AAAA,YACpC,QAAQ,WAAW,OAAO,UAAU;AAAA,UACtC;AAAA,QACF;AACA,YAAI,YAAa,WAAU,KAAK,WAAW;AAE3C,cAAM,qBAAqB;AAAA,UACzB,oBAAoB,UAAU;AAAA,UAC9B;AAAA,YACE,KAAK,WAAW,OAAO,UAAU;AAAA,YACjC,UAAU,WAAW,OAAO,UAAU;AAAA,UACxC;AAAA,QACF;AACA,YAAI,mBAAoB,WAAU,KAAK,kBAAkB;AAAA,MAC3D;AAEA,YAAM,cAAc,WAAW,OAAO,UAAU;AAChD,UAAI,aAAa;AACf,kBAAU;AAAA,UACR,GAAG,8BAA8B,oBAAoB,UAAU,IAAI;AAAA,YACjE,iBAAiB,YAAY;AAAA,YAC7B,iBAAiB,YAAY;AAAA,YAC7B,iBAAiB,YAAY;AAAA,UAC/B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,eAAe,6BAA6B;AAC9C,cAAU;AAAA,MACR,uBAAuB,EAAE,2BAA2B,eAAe,2BAA2B;AAAA,IAChG;AAAA,EACF;AAEA,MACE,eAAe,8BACf,eAAe,iCACf;AACA,UAAM,cAAwB,CAAC;AAC/B,QAAI,eAAe,iCAAiC;AAClD,kBAAY;AAAA,QACV,oBAAoB,eAAe,+BAA+B;AAAA,MACpE;AAAA,IACF;AACA,QAAI,eAAe,4BAA4B;AAC7C,kBAAY;AAAA,QACV,SAAS,eAAe,0BAA0B;AAAA,MACpD;AAAA,IACF;AACA,cAAU;AAAA,MACR,yBAAyB,EAAE,YAAY,YAAY,KAAK,GAAG,CAAC;AAAA,IAC9D;AAAA,EACF;AAEA,YAAU,KAAK,GAAG,6BAA6B,CAAC;AAChD,YAAU,KAAK,GAAG,6BAA6B,CAAC;AAChD,YAAU,KAAK,GAAG,wBAAwB,CAAC;AAC3C,YAAU,KAAK,GAAG,kCAAkC,CAAC;AACrD,MAAI,aAAa;AACf,cAAU,KAAK,GAAG,oCAAoC,CAAC;AAAA,EACzD;AAEA,SAAO,UAAU,UAAU,OAAO,OAAO,EAAE,KAAK,EAAE,CAAC;AACrD;AAEO,SAAS,0BACd,UACyB;AACzB,QAAM,SAAkC,CAAC;AACzC,MAAI,wBAAwB;AAE5B,WAAS,QAAQ,CAAC,SAAwB,UAAkB;AAC1D,UAAM,QAAQ,SAAS,OAAO,OAAO,CAAC,SAA+B;AACnE,UAAI,KAAK,SAAS,OAAQ,QAAO;AACjC,UAAI,sBAAsB,IAAI,MAAM,cAAe,QAAO;AAC1D,aAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,GAAG;AACvB;AAAA,IACF;AAGA,QAAI,yBAAyB,OAAO,SAAS,GAAG;AAC9C,aAAO,KAAK;AAAA,QACV,IAAI,WAAW,SAAS,QAAQ,CAAC,EAAE,EAAE;AAAA,QACrC,MAAM;AAAA,QACN,QAAQ,CAAC;AAAA,MACX,CAAC;AAAA,IACH;AAEA,WAAO,QAAQ,CAAC,SAA+B;AAC7C,UAAI,KAAK,SAAS,QAAQ;AACxB,cAAM,SAAS,KAAK;AACpB,cAAM,YAAgD;AAAA,UACpD,OAAO,KAAK,SAAS;AAAA,UACrB,MAAM,OAAO;AAAA,UACb,MAAM,OAAO;AAAA,UACb,UAAU,OAAO;AAAA,QACnB;AACA,eAAO,KAAK;AAAA,UACV,IAAI,KAAK;AAAA,UACT,MAAM;AAAA,UACN,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,WAAW,KAAK,SAAS,UAAU;AACjC,cAAM,SAAS,KAAK;AACpB,cAAM,YAAwC;AAAA,UAC5C,OAAO,KAAK,SAAS;AAAA,UACrB,MAAM,OAAO;AAAA,UACb,MAAM,OAAO;AAAA,UACb,UAAU,OAAO;AAAA,UACjB,SAAS,OAAO;AAAA,UAChB,MAAM,OAAO;AAAA,QACf;AACA,eAAO,KAAK;AAAA,UACV,IAAI,KAAK;AAAA,UACT,MAAM;AAAA,UACN,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,WAAW,KAAK,SAAS,YAAY;AACnC,cAAM,SAAS,KAAK;AACpB,eAAO,KAAK;AAAA,UACV,IAAI,KAAK;AAAA,UACT,MAAM;AAAA,UACN,OAAO,KAAK,SAAS;AAAA,UACrB;AAAA,QACF,CAAC;AAAA,MACH,WAAW,KAAK,SAAS,YAAY;AACnC,cAAM,SAAS,KAAK;AACpB,eAAO,KAAK;AAAA,UACV,IAAI,KAAK;AAAA,UACT,MAAM;AAAA,UACN,QAAQ,EAAE,SAAS,OAAO,WAAW,KAAK,SAAS,GAAG;AAAA,QACxD,CAAC;AAAA,MACH,WAAW,KAAK,SAAS,SAAS;AAChC,cAAM,SAAS,KAAK;AACpB,eAAO,KAAK;AAAA,UACV,IAAI,KAAK;AAAA,UACT,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,KAAK,OAAO;AAAA,YACZ,KAAK,OAAO;AAAA,YACZ,OAAO,OAAO,QAAQ,EAAE,MAAM,OAAO,MAAM,IAAI,EAAE,MAAM,OAAO;AAAA,YAC9D,QAAQ,OAAO,SAAS,EAAE,MAAM,OAAO,OAAO,IAAI,EAAE,MAAM,OAAO;AAAA,YACjE,WAAW,OAAO;AAAA,YAClB,MAAM,OAAO;AAAA,UACf;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,4BAAwB;AAAA,EAC1B,CAAC;AAED,SAAO;AACT;AAEO,SAAS,qBACd,UACA,gBACA,UACoB;AACpB,MAAI,CAAC,SAAU,QAAO;AAEtB,MAAI,SAAS,SAAS,UAAU;AAC9B,WAAO,SAAS;AAAA,EAClB;AAEA,MAAI,SAAS,SAAS,SAAS;AAC7B,WAAO,eAAe,SAAS,KAAK,KAAK;AAAA,EAC3C;AAEA,MAAI,SAAS,SAAS,YAAY;AAEhC,WAAO,eAAe,SAAS,KAAK;AAAA,EACtC;AAEA,SAAO;AACT;AAEA,SAAS,2BAA2B,UAAU,CAAC,GAAG;AAChD,QAAM,iBAAiB;AAAA,IACrB,kBAAkB;AAAA,EACpB;AACA,QAAM,MAAM;AAAA,IACV,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AACA,QAAM,iBACJ,UAAU,cAAc,SACpB,CAAC,UAAU,QAAQ,IACnB,UAAU;AAChB,MAAI,CAAC,gBAAgB;AACnB,WAAO;AAAA,EACT;AACA,SAAO,eAAe,IAAI,CAAC,WAAW;AACpC,UAAM,gBAAgB,OAAO,KAAK;AAClC,WAAO,IAAI,mBAAmB,cAAc,MAAM,KAAK,EAAE,CAAC,IAAI;AAAA,EAChE,CAAC;AACH;AAEO,SAAS,mBACd,OACA,SAOQ;AAER,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAGlD,MAAI,OAAO,UAAU,SAAU,QAAO;AAGtC,QAAM,kBACJ,WAAW,qBAAqB,UAC5B,QAAQ,kBACR;AACN,WAAS,mBAAuC;AAC9C,QAAI,WAAW,mBAAmB,QAAS,QAAO,QAAQ;AAC1D,QAAI,WAAW,oBAAoB,QAAS,QAAO,QAAQ;AAC3D,WAAO;AAAA,EACT;AACA,WAAS,sBAA4C;AACnD,QAAI,WAAW,sBAAsB;AACnC,aAAO,QAAQ;AACjB,QAAI,WAAW,uBAAuB;AACpC,aAAO,QAAQ;AACjB,WAAO;AAAA,EACT;AACA,QAAM,gBAAgB,iBAAiB;AACvC,QAAM,mBAAmB,oBAAoB;AAG7C,MAAI,mBAAmB,mBAAmB,SAAS,MAAM,eAAe,GAAG;AACzE,WAAO,MAAM,eAAe;AAAA,EAC9B;AAGA,MAAI,CAAC,iBAAiB;AACpB,UAAM,iBAAiB,2BAA2B;AAClD,QAAI,gBAAgB;AAClB,iBAAW,UAAU,gBAAgB;AACnC,YAAI,UAAU,SAAS,MAAM,MAAM,GAAG;AACpC,iBAAO,MAAM,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,iBAAiB,SAAS,MAAM,aAAa,GAAG;AACnE,WAAO,MAAM,aAAa;AAAA,EAC5B;AAGA,MAAI,QAAQ,SAAS,MAAM,IAAI;AAC7B,WAAO,MAAM;AAAA,EACf;AAGA,MAAI,kBAAkB;AACpB,eAAW,UAAU,kBAAkB;AACrC,UAAI,UAAU,SAAS,MAAM,MAAM,GAAG;AACpC,eAAO,MAAM,MAAM;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,OAAO,OAAO,KAAK,KAAK;AAC9B,MAAI,KAAK,SAAS,KAAK,MAAM,KAAK,CAAC,CAAC,GAAG;AACrC,WAAO,MAAM,KAAK,CAAC,CAAC;AAAA,EACtB;AAEA,SAAO;AACT;AAOO,SAAS,sBACd,MACoC;AACpC,MAAI,KAAK,WAAY,QAAO,KAAK;AACjC,QAAM,SAAU,KAA4C;AAC5D,MAAI,WAAW,MAAO,QAAO;AAC7B,SAAO;AACT;AAEA,MAAM,qBAA6C;AAAA,EACjD,eAAe;AAAA,EACf,eAAe;AAAA,EACf,MAAM;AACR;AAMO,SAAS,mBACd,MACA,UACQ;AACR,QAAM,MAAM,sBAAsB,IAAI;AACtC,SAAQ,OAAO,mBAAmB,GAAG,KAAM,YAAY;AACzD;AAEO,SAAS,oBAAoB,UAA0B;AAE5D,QAAM,OAAO,OAAO,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AAGpD,SAAO,KACJ,QAAQ,SAAS,kBAAkB,EACnC,QAAQ,WAAW,QAAQ,EAC3B,QAAQ,SAAS,kBAAkB,EACnC,QAAQ,WAAW,QAAQ,EAC3B,QAAQ,SAAS,kBAAkB,EACnC,QAAQ,WAAW,QAAQ,EAC3B,QAAQ,SAAS,kBAAkB,EACnC,QAAQ,WAAW,QAAQ,EAC3B,QAAQ,SAAS,kBAAkB,EACnC,QAAQ,WAAW,QAAQ,EAC3B,QAAQ,SAAS,kBAAkB,EACnC,QAAQ,WAAW,QAAQ;AAChC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/navigation.utils.ts"],"sourcesContent":["import {\n Site,\n HeaderConfig,\n HeaderDropdownButtonConfig,\n HeaderDropdownContent,\n HeaderDropdownNavigationItemConfig,\n HeaderNavigationItem,\n HeaderNavigationItemButtonConfig,\n HeaderNavigationItemDropdownConfig,\n HeaderNavigationItemImageConfig,\n HeaderNavigationItemLinkConfig,\n HeaderNavigationItemMarkdownConfig,\n HeaderSection,\n LocalizedString,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { marked } from \"marked\";\nimport {\n generateDesktopDropdownAnimations,\n generateMobileMenuAnimations,\n generateResponsiveSpacingCSS,\n generateSameLayerDropdownAnimations,\n generateScrollbarStyles,\n generateToggleIconAnimations,\n minifyCSS,\n normalizeResponsiveValue,\n} from \"@otl-core/style-utils\";\n\n/**\n * Convert ShadowConfig to CSS box-shadow string\n */\nexport function shadowConfigToCSS(shadow: ShadowConfig): string {\n const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;\n const parts = [offsetX, offsetY, blurRadius, spreadRadius, color];\n if (inset) {\n return `inset ${parts.join(\" \")}`;\n }\n return parts.join(\" \");\n}\n\nexport function calculateNavigationWidth(\n sections: HeaderSection[],\n site?: Site,\n): number {\n let totalWidth = 150;\n\n for (const section of sections) {\n for (const item of section?.items || []) {\n if (item.type === \"logo\") continue;\n\n const label =\n typeof item.label === \"string\"\n ? item.label\n : getLocalizedString(item.label, site) || \"\";\n const labelLength = label.length;\n\n if (item.type === \"button\") {\n totalWidth += labelLength * 8 + 48;\n } else if (\n item.type === \"link\" ||\n item.type === \"dropdown\" ||\n item.type === \"markdown\"\n ) {\n totalWidth += labelLength * 8 + 24;\n } else if (item.type === \"image\") {\n const imgConfig = item.config as { width?: string };\n const imgWidth = imgConfig?.width\n ? parseInt(imgConfig.width, 10) || 100\n : 100;\n totalWidth += imgWidth + 16;\n }\n }\n }\n\n return totalWidth;\n}\n\nexport type Breakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | null;\n\nexport function getBreakpointForWidth(estimatedWidth: number): Breakpoint {\n const MAX_USABLE_WIDTH = 1400;\n\n if (estimatedWidth > MAX_USABLE_WIDTH) return null;\n\n if (estimatedWidth <= 640) return \"sm\";\n if (estimatedWidth <= 768) return \"md\";\n if (estimatedWidth <= 1024) return \"lg\";\n if (estimatedWidth <= 1280) return \"xl\";\n return \"2xl\";\n}\n\nconst RESPONSIVE_BREAKPOINTS = [\n { key: \"sm\", minWidth: \"640px\" },\n { key: \"md\", minWidth: \"768px\" },\n { key: \"lg\", minWidth: \"1024px\" },\n { key: \"xl\", minWidth: \"1280px\" },\n] as const;\n\nfunction generateResponsiveCustomProps(\n className: string,\n props: Record<string, ResponsiveValue<string> | undefined>,\n): string[] {\n const css: string[] = [];\n const baseVars: string[] = [];\n const bpVars: Record<string, string[]> = {};\n\n for (const [prop, value] of Object.entries(props)) {\n if (!value) continue;\n if (typeof value === \"string\") {\n baseVars.push(`${prop}:${value}`);\n } else {\n if (value.base) baseVars.push(`${prop}:${value.base}`);\n for (const { key } of RESPONSIVE_BREAKPOINTS) {\n const bpVal = value[key as keyof typeof value];\n if (bpVal && typeof bpVal === \"string\") {\n if (!bpVars[key]) bpVars[key] = [];\n bpVars[key].push(`${prop}:${bpVal}`);\n }\n }\n }\n }\n\n const target = `.${className}`;\n if (baseVars.length > 0) {\n css.push(`${target}{${baseVars.join(\";\")}}`);\n }\n for (const { key, minWidth } of RESPONSIVE_BREAKPOINTS) {\n if (bpVars[key]?.length) {\n css.push(\n `@media(min-width:${minWidth}){${target}{${bpVars[key].join(\";\")}}}`,\n );\n }\n }\n return css;\n}\n\n/**\n * Normalize a logo size value (responsive, plain string, or legacy\n * numeric pixels) into a ResponsiveValue<string>.\n */\nfunction normalizeLogoSize(\n value: ResponsiveValue<string> | number | undefined,\n): ResponsiveValue<string> | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"number\") return { base: `${value}px` };\n if (typeof value === \"string\") return { base: value };\n return value;\n}\n\nfunction generateLogoCSS(id: string, navigation: HeaderConfig): string[] {\n if (!navigation.logo?.url) return [];\n const width = normalizeLogoSize(navigation.logo.width) ?? { base: \"auto\" };\n const height = normalizeLogoSize(navigation.logo.height) ?? { base: \"40px\" };\n return generateResponsiveCustomProps(`navbar-${id} .navigation-logo-img`, {\n width,\n height,\n });\n}\n\nexport function generateNavigationCSS(\n id: string,\n navigation: HeaderConfig,\n resolvedColors: Record<string, string | undefined>,\n dropdownIds: string[] = [],\n): string {\n const cssBlocks: (string | null)[] = [];\n const isSameLayer = navigation.style?.dropdown?.layer === \"same\";\n\n cssBlocks.push(...generateLogoCSS(id, navigation));\n\n if (navigation.style?.layout?.margin) {\n const headerMarginCSS = generateResponsiveSpacingCSS(`header-${id}`, {\n margin: navigation.style.layout.margin,\n });\n if (headerMarginCSS) cssBlocks.push(headerMarginCSS);\n }\n\n if (navigation.style?.safeZone) {\n const safeZoneCSS = generateResponsiveSpacingCSS(`header-safe-zone-${id}`, {\n height: navigation.style.safeZone,\n });\n if (safeZoneCSS) cssBlocks.push(safeZoneCSS);\n }\n\n if (navigation.style) {\n if (isSameLayer) {\n // Same layer: navbar wrapper gets border/padding/shadow, navbar itself only gets inner styles\n const wrapperCSS = generateResponsiveSpacingCSS(`navbar-wrapper-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (wrapperCSS) cssBlocks.push(wrapperCSS);\n } else {\n const navbarCSS = generateResponsiveSpacingCSS(`navbar-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n shadow: navigation.style.shadow,\n });\n if (navbarCSS) cssBlocks.push(navbarCSS);\n }\n\n const navbarInnerCSS = generateResponsiveSpacingCSS(`navbar-inner-${id}`, {\n gap: navigation.style.layout?.sectionGap,\n fontSize: navigation.style.fontSize?.navbar,\n });\n if (navbarInnerCSS) cssBlocks.push(navbarInnerCSS);\n\n const btnFontSize = navigation.style.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`navbar-inner-${id}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n }\n\n // Generate responsive offset margin for all dropdowns\n if (navigation.style?.dropdown?.offset) {\n const offset = navigation.style.dropdown.offset;\n const yNorm = normalizeResponsiveValue(offset.y);\n const leftNorm = normalizeResponsiveValue(offset.left);\n const rightNorm = normalizeResponsiveValue(offset.right);\n const breakpoints = [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\"] as const;\n const compositeMargin: Record<string, string> = {};\n for (const bp of breakpoints) {\n const top = yNorm[bp] || (bp === \"base\" ? \"0\" : undefined);\n const left = leftNorm[bp] || (bp === \"base\" ? \"0\" : undefined);\n const right = rightNorm[bp] || (bp === \"base\" ? \"0\" : undefined);\n if (top !== undefined || left !== undefined || right !== undefined) {\n compositeMargin[bp] = `${top || \"0\"} ${right || \"0\"} 0 ${left || \"0\"}`;\n }\n }\n if (Object.keys(compositeMargin).length > 0) {\n const marginValue = compositeMargin.base\n ? Object.keys(compositeMargin).length === 1\n ? compositeMargin.base\n : compositeMargin\n : compositeMargin;\n dropdownIds.forEach((dropdownId) => {\n const offsetCSS = generateResponsiveSpacingCSS(\n `navigation-dropdown-${dropdownId}`,\n { margin: marginValue as ResponsiveValue<string> },\n );\n if (offsetCSS) cssBlocks.push(offsetCSS);\n });\n }\n }\n\n if (navigation.style && dropdownIds.length > 0) {\n dropdownIds.forEach((dropdownId) => {\n if (isSameLayer) {\n // Same layer: dropdown only gets gap/fontSize, no border/padding/shadow (inherited from wrapper)\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n } else {\n const dropdownCSS = generateResponsiveSpacingCSS(\n `navigation-dropdown-${dropdownId}`,\n {\n padding: navigation.style?.dropdown?.padding,\n border: navigation.style?.dropdown?.border,\n shadow: navigation.style?.dropdown?.shadow,\n },\n );\n if (dropdownCSS) cssBlocks.push(dropdownCSS);\n\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n fontSize: navigation.style?.fontSize?.dropdown,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n }\n\n const btnFontSize = navigation.style?.fontSize?.buttonFontSize;\n if (btnFontSize) {\n cssBlocks.push(\n ...generateResponsiveCustomProps(`dropdown-content-${dropdownId}`, {\n \"--btn-font-sm\": btnFontSize.sm,\n \"--btn-font-md\": btnFontSize.md,\n \"--btn-font-lg\": btnFontSize.lg,\n }),\n );\n }\n });\n }\n\n if (resolvedColors.burgerButtonBackgroundHover) {\n cssBlocks.push(\n `.mobile-menu-toggle-${id}:hover{background-color:${resolvedColors.burgerButtonBackgroundHover}!important}`,\n );\n }\n\n if (\n resolvedColors.dropdownMenuLinkHoverColor ||\n resolvedColors.dropdownMenuLinkHoverBackground\n ) {\n const hoverStyles: string[] = [];\n if (resolvedColors.dropdownMenuLinkHoverBackground) {\n hoverStyles.push(\n `background-color:${resolvedColors.dropdownMenuLinkHoverBackground}!important`,\n );\n }\n if (resolvedColors.dropdownMenuLinkHoverColor) {\n hoverStyles.push(\n `color:${resolvedColors.dropdownMenuLinkHoverColor}!important`,\n );\n }\n cssBlocks.push(\n `#mobile-menu-dropdown-${id} a:hover{${hoverStyles.join(\";\")}}`,\n );\n }\n\n cssBlocks.push(...generateToggleIconAnimations());\n cssBlocks.push(...generateMobileMenuAnimations());\n cssBlocks.push(...generateScrollbarStyles());\n cssBlocks.push(...generateDesktopDropdownAnimations());\n if (isSameLayer) {\n cssBlocks.push(...generateSameLayerDropdownAnimations());\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\nexport function sectionsToDropdownContent(\n sections: HeaderSection[],\n): HeaderDropdownContent[] {\n const result: HeaderDropdownContent[] = [];\n let lastSectionHadContent = false;\n\n sections.forEach((section: HeaderSection, index: number) => {\n const items = section?.items?.filter((item: HeaderNavigationItem) => {\n if (item.type === \"logo\") return false;\n if (resolveItemVisibility(item) === \"navbar-only\") return false;\n return true;\n });\n\n if (items?.length === 0) {\n return; // Skip this section, don't update lastSectionHadContent\n }\n\n // Add divider if the previous section had content and this isn't the first section with content\n if (lastSectionHadContent && result.length > 0) {\n result.push({\n id: `divider-${sections[index - 1].id}`,\n type: \"divider\",\n config: {},\n });\n }\n\n items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"link\") {\n const config = item.config as HeaderNavigationItemLinkConfig;\n const navConfig: HeaderDropdownNavigationItemConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n };\n result.push({\n id: item.id,\n type: \"navigation-item\",\n config: navConfig,\n });\n } else if (item.type === \"button\") {\n const config = item.config as HeaderNavigationItemButtonConfig;\n const btnConfig: HeaderDropdownButtonConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n variant: config.variant,\n size: config.size,\n };\n result.push({\n id: item.id,\n type: \"button\",\n config: btnConfig,\n });\n } else if (item.type === \"dropdown\") {\n const config = item.config as HeaderNavigationItemDropdownConfig;\n result.push({\n id: item.id,\n type: \"dropdown\",\n label: item.label || \"\",\n config,\n });\n } else if (item.type === \"markdown\") {\n const config = item.config as HeaderNavigationItemMarkdownConfig;\n result.push({\n id: item.id,\n type: \"markdown\",\n config: { content: config.content || item.label || \"\" },\n });\n } else if (item.type === \"image\") {\n const config = item.config as HeaderNavigationItemImageConfig;\n result.push({\n id: item.id,\n type: \"image\",\n config: {\n src: config.src,\n alt: config.alt,\n width: config.width ? { base: config.width } : { base: \"100%\" },\n height: config.height ? { base: config.height } : { base: \"auto\" },\n objectFit: config.objectFit,\n href: config.href,\n },\n });\n }\n });\n\n lastSectionHadContent = true;\n });\n\n return result;\n}\n\nexport function resolveDropdownColor(\n colorRef: { type: string; value: string } | undefined,\n resolvedColors: Record<string, string | undefined>,\n fallback?: string,\n): string | undefined {\n if (!colorRef) return fallback;\n\n if (colorRef.type === \"custom\") {\n return colorRef.value;\n }\n\n if (colorRef.type === \"theme\") {\n return resolvedColors[colorRef.value] || fallback;\n }\n\n if (colorRef.type === \"variable\") {\n // For variables, construct the CSS variable reference\n return `var(--color-${colorRef.value})`;\n }\n\n return fallback;\n}\n\nfunction getBrowserPreferredLocales(options = {}) {\n const defaultOptions = {\n languageCodeOnly: false,\n };\n const opt = {\n ...defaultOptions,\n ...options,\n };\n const browserLocales =\n navigator.languages === undefined\n ? [navigator.language]\n : navigator.languages;\n if (!browserLocales) {\n return undefined;\n }\n return browserLocales.map((locale) => {\n const trimmedLocale = locale.trim();\n return opt.languageCodeOnly ? trimmedLocale.split(/-|_/)[0] : trimmedLocale;\n });\n}\n\nexport function getLocalizedString(\n value: string | LocalizedString | null | undefined,\n options?:\n | Site\n | {\n preferredLocale?: string;\n defaultLocale?: string;\n supportedLocales?: string[];\n },\n): string {\n // Handle null/undefined\n if (value === null || value === undefined) return \"\";\n\n // If it's already a string, return it\n if (typeof value === \"string\") return value;\n\n // Normalize options to handle both Site and simple options object\n const preferredLocale =\n options && \"preferredLocale\" in options\n ? options.preferredLocale\n : undefined;\n function getDefaultLocale(): string | undefined {\n if (options && \"defaultLocale\" in options) return options.defaultLocale;\n if (options && \"default_locale\" in options) return options.default_locale;\n return undefined;\n }\n function getSupportedLocales(): string[] | undefined {\n if (options && \"supportedLocales\" in options)\n return options.supportedLocales;\n if (options && \"supported_locales\" in options)\n return options.supported_locales;\n return undefined;\n }\n const defaultLocale = getDefaultLocale();\n const supportedLocales = getSupportedLocales();\n\n // Try preferred locale first (if explicitly provided)\n if (preferredLocale && preferredLocale in value && value[preferredLocale]) {\n return value[preferredLocale];\n }\n\n // Try browser locales if no explicit preferred locale\n if (!preferredLocale) {\n const browserLocales = getBrowserPreferredLocales();\n if (browserLocales) {\n for (const locale of browserLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n }\n\n // Try default locale\n if (defaultLocale && defaultLocale in value && value[defaultLocale]) {\n return value[defaultLocale];\n }\n\n // Try 'en' as fallback\n if (\"en\" in value && value.en) {\n return value.en;\n }\n\n // Try any supported locale\n if (supportedLocales) {\n for (const locale of supportedLocales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n\n // Return first available value as last resort\n const keys = Object.keys(value);\n if (keys.length > 0 && value[keys[0]]) {\n return value[keys[0]];\n }\n\n return \"\";\n}\n\n/**\n * Resolve the effective visibility for a navigation item.\n * Supports the new `visibility` field and the legacy `collapse` field.\n * collapse: false → \"navbar-only\", collapse: true/undefined → \"responsive\"\n */\nexport function resolveItemVisibility(\n item: HeaderNavigationItem,\n): HeaderNavigationItem[\"visibility\"] {\n if (item.visibility) return item.visibility;\n const legacy = (item as unknown as Record<string, unknown>).collapse;\n if (legacy === false) return \"navbar-only\";\n return undefined;\n}\n\nconst VISIBILITY_CLASSES: Record<string, string> = {\n \"navbar-only\": \"flex\",\n \"mobile-only\": \"hidden\",\n both: \"flex\",\n};\n\n/**\n * Get the CSS class for an item's visibility, falling back to the\n * responsive breakpoint class when no explicit visibility is set.\n */\nexport function getVisibilityClass(\n item: HeaderNavigationItem,\n fallback?: string,\n): string {\n const vis = resolveItemVisibility(item);\n return (vis && VISIBILITY_CLASSES[vis]) || fallback || \"\";\n}\n\nexport function parseMarkdownToHTML(markdown: string): string {\n // Parse markdown to HTML\n const html = marked.parse(markdown, { async: false }) as string;\n\n // Transform h1-h6 elements to divs with corresponding classes\n return html\n .replace(/<h1>/g, '<div class=\"h1\">')\n .replace(/<\\/h1>/g, \"</div>\")\n .replace(/<h2>/g, '<div class=\"h2\">')\n .replace(/<\\/h2>/g, \"</div>\")\n .replace(/<h3>/g, '<div class=\"h3\">')\n .replace(/<\\/h3>/g, \"</div>\")\n .replace(/<h4>/g, '<div class=\"h4\">')\n .replace(/<\\/h4>/g, \"</div>\")\n .replace(/<h5>/g, '<div class=\"h5\">')\n .replace(/<\\/h5>/g, \"</div>\")\n .replace(/<h6>/g, '<div class=\"h6\">')\n .replace(/<\\/h6>/g, \"</div>\");\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otl-core/next-navigation",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Reusable navigation components for OTL CMS",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -48,13 +48,13 @@
|
|
|
48
48
|
"tailwind-merge": "^3.3.1"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@otl-core/cms-utils": "^1.1.
|
|
52
|
-
"@otl-core/style-utils": "^1.1.
|
|
51
|
+
"@otl-core/cms-utils": "^1.1.36",
|
|
52
|
+
"@otl-core/style-utils": "^1.1.36"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@eslint/eslintrc": "^3.3.1",
|
|
56
|
-
"@otl-core/cms-types": "^1.1.
|
|
57
|
-
"@otl-core/cms-utils": "^1.1.
|
|
56
|
+
"@otl-core/cms-types": "^1.1.36",
|
|
57
|
+
"@otl-core/cms-utils": "^1.1.36",
|
|
58
58
|
"@radix-ui/react-focus-scope": "^1.1.7",
|
|
59
59
|
"@radix-ui/react-slot": "^1.2.3",
|
|
60
60
|
"@testing-library/jest-dom": "^6.9.1",
|