@shellui/core 0.0.4 → 0.0.5

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.
Files changed (32) hide show
  1. package/dist/{CookiePreferencesView-MhO9FO-4.js → CookiePreferencesView-CIXBJWNt.js} +3 -3
  2. package/dist/{CookiePreferencesView-MhO9FO-4.js.map → CookiePreferencesView-CIXBJWNt.js.map} +1 -1
  3. package/dist/{DefaultLayout-Dbb3uJED.js → DefaultLayout-Bztmv2c_.js} +74 -62
  4. package/dist/DefaultLayout-Bztmv2c_.js.map +1 -0
  5. package/dist/{FullscreenLayout-1SgPHWw-.js → FullscreenLayout-DiX6dbkf.js} +3 -3
  6. package/dist/{FullscreenLayout-1SgPHWw-.js.map → FullscreenLayout-DiX6dbkf.js.map} +1 -1
  7. package/dist/{HomeView-DYU-O_Il.js → HomeView-C610YU6V.js} +2 -2
  8. package/dist/{HomeView-DYU-O_Il.js.map → HomeView-C610YU6V.js.map} +1 -1
  9. package/dist/{NotFoundView-CeYjJNg0.js → NotFoundView-D00gYlq-.js} +2 -2
  10. package/dist/{NotFoundView-CeYjJNg0.js.map → NotFoundView-D00gYlq-.js.map} +1 -1
  11. package/dist/{OverlayShell-pzbqQW25.js → OverlayShell-CGjN4rTu.js} +2 -2
  12. package/dist/{OverlayShell-pzbqQW25.js.map → OverlayShell-CGjN4rTu.js.map} +1 -1
  13. package/dist/{SettingsView-Bndrta44.js → SettingsView-2QMtfS71.js} +4 -4
  14. package/dist/{SettingsView-Bndrta44.js.map → SettingsView-2QMtfS71.js.map} +1 -1
  15. package/dist/{WindowsLayout-CXGNPKoY.js → WindowsLayout-DkSNQDSb.js} +3 -3
  16. package/dist/{WindowsLayout-CXGNPKoY.js.map → WindowsLayout-DkSNQDSb.js.map} +1 -1
  17. package/dist/components/ui/sidebar.d.ts.map +1 -1
  18. package/dist/features/layouts/DefaultLayout.d.ts.map +1 -1
  19. package/dist/{index-lmRk5L6z.js → index-PsePV0Ng.js} +8 -8
  20. package/dist/{index-lmRk5L6z.js.map → index-PsePV0Ng.js.map} +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/{sidebar-ClIeZ2zb.js → sidebar-Cvm_uv4l.js} +123 -90
  23. package/dist/sidebar-Cvm_uv4l.js.map +1 -0
  24. package/dist/style.css +1 -1
  25. package/dist/{switch-8SzUJz7Q.js → switch-BjkiJBIa.js} +2 -2
  26. package/dist/{switch-8SzUJz7Q.js.map → switch-BjkiJBIa.js.map} +1 -1
  27. package/package.json +4 -3
  28. package/src/components/ui/sidebar.tsx +43 -5
  29. package/src/features/layouts/DefaultLayout.tsx +22 -6
  30. package/src/index.css +5 -0
  31. package/dist/DefaultLayout-Dbb3uJED.js.map +0 -1
  32. package/dist/sidebar-ClIeZ2zb.js.map +0 -1
@@ -3,8 +3,8 @@ import { useMemo as b, useState as B, useRef as T, useEffect as H, useCallback a
3
3
  import { useTranslation as $ } from "react-i18next";
4
4
  import { useLocation as F } from "react-router";
5
5
  import { shellui as y } from "@shellui/sdk";
6
- import { u as I, a as U, r as G, B as S } from "./index-lmRk5L6z.js";
7
- import { S as w } from "./switch-8SzUJz7Q.js";
6
+ import { u as I, a as U, r as G, B as S } from "./index-PsePV0Ng.js";
7
+ import { S as w } from "./switch-BjkiJBIa.js";
8
8
  const V = [
9
9
  "strict_necessary",
10
10
  "functional_performance",
@@ -210,4 +210,4 @@ function te() {
210
210
  export {
211
211
  te as CookiePreferencesView
212
212
  };
213
- //# sourceMappingURL=CookiePreferencesView-MhO9FO-4.js.map
213
+ //# sourceMappingURL=CookiePreferencesView-CIXBJWNt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CookiePreferencesView-MhO9FO-4.js","sources":["../src/features/cookieConsent/CookiePreferencesView.tsx"],"sourcesContent":["import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useLocation } from 'react-router';\nimport { shellui } from '@shellui/sdk';\nimport { Button } from '@/components/ui/button';\nimport { Switch } from '@/components/ui/switch';\nimport { useConfig } from '../config/useConfig';\nimport { useSettings } from '../settings/hooks/useSettings';\nimport { resolveLocalizedString } from '../layouts/utils';\nimport type { CookieConsentCategory, CookieDefinition } from '../config/types';\n\n/** Category display order and labels */\nconst CATEGORY_ORDER: CookieConsentCategory[] = [\n 'strict_necessary',\n 'functional_performance',\n 'targeting',\n 'social_media_embedded',\n];\n\n/** Format duration in human-readable format */\nfunction formatDuration(\n seconds: number,\n t: (key: string, options?: Record<string, unknown>) => string,\n): string {\n if (seconds < 60) return t('preferences.duration.seconds', { count: seconds });\n if (seconds < 3600) return t('preferences.duration.minutes', { count: Math.floor(seconds / 60) });\n if (seconds < 86400)\n return t('preferences.duration.hours', { count: Math.floor(seconds / 3600) });\n if (seconds < 31536000)\n return t('preferences.duration.days', { count: Math.floor(seconds / 86400) });\n return t('preferences.duration.years', { count: Math.floor(seconds / 31536000) });\n}\n\nexport function CookiePreferencesView() {\n const { t, i18n } = useTranslation('cookieConsent');\n const { config } = useConfig();\n const { settings, updateSetting } = useSettings();\n const location = useLocation();\n const searchParams = new URLSearchParams(location.search);\n const isInitialConsent = searchParams.get('initial') === 'true';\n const currentLanguage = i18n.language || 'en';\n\n const cookies = config?.cookieConsent?.cookies ?? [];\n const allHosts = useMemo(() => cookies.map((c) => c.host), [cookies]);\n\n // Strictly necessary hosts are always enabled\n const strictNecessaryHosts = useMemo(\n () => cookies.filter((c) => c.category === 'strict_necessary').map((c) => c.host),\n [cookies],\n );\n\n const currentAcceptedHosts = settings?.cookieConsent?.acceptedHosts ?? [];\n\n // Local state for unsaved changes (always include strict necessary)\n const [localAcceptedHosts, setLocalAcceptedHosts] = useState<string[]>(() => [\n ...new Set([...currentAcceptedHosts, ...strictNecessaryHosts]),\n ]);\n\n // Track if save/accept/reject was clicked to avoid rejecting on intentional close\n const actionClickedRef = useRef(false);\n\n // Reset local state when drawer opens (when URL changes to include initial param)\n useEffect(() => {\n if (isInitialConsent) {\n // Always include strict necessary hosts\n setLocalAcceptedHosts([...new Set([...currentAcceptedHosts, ...strictNecessaryHosts])]);\n }\n }, [isInitialConsent, currentAcceptedHosts, strictNecessaryHosts]);\n\n // Handle drawer close without saving during initial consent\n useEffect(() => {\n if (!isInitialConsent) return;\n\n const handleDrawerClose = () => {\n // If closing without saving during initial consent, reject all except strict necessary\n // Check if user has never consented and no action was clicked\n const neverConsented = (settings?.cookieConsent?.consentedCookieHosts ?? []).length === 0;\n if (neverConsented && !actionClickedRef.current) {\n updateSetting('cookieConsent', {\n acceptedHosts: strictNecessaryHosts,\n consentedCookieHosts: allHosts,\n });\n }\n };\n\n const cleanup = shellui.addMessageListener('SHELLUI_CLOSE_DRAWER', handleDrawerClose);\n return cleanup;\n }, [isInitialConsent, strictNecessaryHosts, allHosts, updateSetting, settings]);\n\n // Cleanup on unmount: if initial consent and drawer closes without save, reject all\n useEffect(() => {\n return () => {\n if (isInitialConsent && !actionClickedRef.current) {\n // Check if user has never consented\n const neverConsented = (settings?.cookieConsent?.consentedCookieHosts ?? []).length === 0;\n if (neverConsented) {\n updateSetting('cookieConsent', {\n acceptedHosts: strictNecessaryHosts,\n consentedCookieHosts: allHosts,\n });\n }\n }\n };\n }, [isInitialConsent, strictNecessaryHosts, allHosts, updateSetting, settings]);\n\n // Group cookies by category\n const cookiesByCategory = useMemo(() => {\n const grouped = new Map<CookieConsentCategory, CookieDefinition[]>();\n for (const cookie of cookies) {\n const existing = grouped.get(cookie.category) ?? [];\n grouped.set(cookie.category, [...existing, cookie]);\n }\n return grouped;\n }, [cookies]);\n\n // Toggle individual cookie\n const toggleCookie = useCallback((host: string, enabled: boolean) => {\n setLocalAcceptedHosts((prev) => (enabled ? [...prev, host] : prev.filter((h) => h !== host)));\n }, []);\n\n // Toggle entire category\n const toggleCategory = useCallback(\n (category: CookieConsentCategory, enabled: boolean) => {\n const categoryHosts = cookiesByCategory.get(category)?.map((c) => c.host) ?? [];\n setLocalAcceptedHosts((prev) => {\n if (enabled) {\n return [...new Set([...prev, ...categoryHosts])];\n } else {\n const hostsSet = new Set(categoryHosts);\n return prev.filter((h) => !hostsSet.has(h));\n }\n });\n },\n [cookiesByCategory],\n );\n\n // Check if category is fully or partially enabled\n const getCategoryState = useCallback(\n (category: CookieConsentCategory): 'all' | 'some' | 'none' => {\n const categoryHosts = cookiesByCategory.get(category)?.map((c) => c.host) ?? [];\n if (categoryHosts.length === 0) return 'none';\n const enabledCount = categoryHosts.filter((h) => localAcceptedHosts.includes(h)).length;\n if (enabledCount === categoryHosts.length) return 'all';\n if (enabledCount > 0) return 'some';\n return 'none';\n },\n [cookiesByCategory, localAcceptedHosts],\n );\n\n // Accept all\n const handleAcceptAll = useCallback(() => {\n actionClickedRef.current = true;\n updateSetting('cookieConsent', {\n acceptedHosts: allHosts,\n consentedCookieHosts: allHosts,\n });\n shellui.closeDrawer();\n }, [allHosts, updateSetting]);\n\n // Reject all except strict necessary (which are always enabled)\n const handleRejectAll = useCallback(() => {\n actionClickedRef.current = true;\n updateSetting('cookieConsent', {\n acceptedHosts: strictNecessaryHosts,\n consentedCookieHosts: allHosts,\n });\n shellui.closeDrawer();\n }, [strictNecessaryHosts, allHosts, updateSetting]);\n\n // Save custom preferences (always include strict necessary)\n const handleSave = useCallback(() => {\n actionClickedRef.current = true;\n const hostsToSave = [...new Set([...localAcceptedHosts, ...strictNecessaryHosts])];\n updateSetting('cookieConsent', {\n acceptedHosts: hostsToSave,\n consentedCookieHosts: allHosts,\n });\n shellui.closeDrawer();\n }, [localAcceptedHosts, strictNecessaryHosts, allHosts, updateSetting]);\n\n // Check if preferences have changed\n const hasChanges = useMemo(() => {\n if (localAcceptedHosts.length !== currentAcceptedHosts.length) return true;\n const sortedLocal = [...localAcceptedHosts].sort();\n const sortedCurrent = [...currentAcceptedHosts].sort();\n return sortedLocal.some((h, i) => h !== sortedCurrent[i]);\n }, [localAcceptedHosts, currentAcceptedHosts]);\n\n if (cookies.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full p-6\">\n <p className=\"text-muted-foreground\">{t('preferences.noCookies')}</p>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full bg-background\">\n {/* Header */}\n <div className=\"flex flex-col space-y-2 border-b border-border/60 px-6 pt-5 pb-4\">\n <h2\n className=\"text-lg font-semibold leading-none tracking-tight\"\n style={{ fontFamily: 'var(--heading-font-family, inherit)' }}\n >\n {t('preferences.title')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{t('preferences.description')}</p>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto px-6 py-4\">\n {CATEGORY_ORDER.map((category) => {\n const categoryCookies = cookiesByCategory.get(category);\n if (!categoryCookies || categoryCookies.length === 0) return null;\n\n const categoryState = getCategoryState(category);\n const isStrictNecessary = category === 'strict_necessary';\n\n return (\n <div\n key={category}\n className=\"mb-6 last:mb-0\"\n >\n {/* Category header with toggle */}\n <div className=\"flex items-center justify-between mb-3\">\n <div className=\"flex-1 min-w-0\">\n <h3\n className=\"text-sm font-semibold\"\n style={{ fontFamily: 'var(--heading-font-family, inherit)' }}\n >\n {t(`preferences.categories.${category}.title`)}\n </h3>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {t(`preferences.categories.${category}.description`)}\n </p>\n </div>\n <div className=\"ml-4 flex items-center gap-2\">\n {!isStrictNecessary && categoryState === 'some' && (\n <span className=\"text-xs text-muted-foreground\">\n {t('preferences.partial')}\n </span>\n )}\n {isStrictNecessary ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('preferences.alwaysOn')}\n </span>\n ) : (\n <Switch\n checked={categoryState === 'all'}\n onCheckedChange={(checked) => toggleCategory(category, checked)}\n aria-label={t(`preferences.categories.${category}.title`)}\n />\n )}\n </div>\n </div>\n\n {/* Individual cookies - only show for non-strictly-necessary categories */}\n {!isStrictNecessary && (\n <div className=\"space-y-2 pl-2 border-l-2 border-border ml-1\">\n {categoryCookies.map((cookie) => {\n const isEnabled = localAcceptedHosts.includes(cookie.host);\n return (\n <div\n key={cookie.host}\n className=\"flex items-start justify-between gap-3 py-2 px-3 rounded-md bg-muted/30\"\n >\n <div className=\"flex-1 min-w-0\">\n <span className=\"text-sm font-medium truncate\">{cookie.name}</span>\n {cookie.description && (\n <p className=\"text-xs text-muted-foreground mt-0.5 line-clamp-2\">\n {resolveLocalizedString(cookie.description, currentLanguage)}\n </p>\n )}\n <div className=\"flex items-center gap-3 mt-1 text-[10px] text-muted-foreground/70\">\n <span>{cookie.host}</span>\n <span>•</span>\n <span>{formatDuration(cookie.durationSeconds, t)}</span>\n <span>•</span>\n <span className=\"capitalize\">{cookie.type.replace('_', ' ')}</span>\n </div>\n </div>\n <Switch\n checked={isEnabled}\n onCheckedChange={(checked) => toggleCookie(cookie.host, checked)}\n aria-label={cookie.name}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n })}\n </div>\n\n {/* Footer */}\n <div className=\"mt-auto flex flex-col gap-2 border-t border-border px-6 py-4\">\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRejectAll}\n className=\"flex-1\"\n >\n {t('preferences.rejectAll')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleAcceptAll}\n className=\"flex-1\"\n >\n {t('preferences.acceptAll')}\n </Button>\n </div>\n <Button\n size=\"sm\"\n onClick={handleSave}\n disabled={!hasChanges && !isInitialConsent}\n className=\"w-full\"\n >\n {t('preferences.save')}\n </Button>\n </div>\n </div>\n );\n}\n"],"names":["CATEGORY_ORDER","formatDuration","seconds","t","CookiePreferencesView","i18n","useTranslation","config","useConfig","settings","updateSetting","useSettings","location","useLocation","isInitialConsent","currentLanguage","cookies","allHosts","useMemo","c","strictNecessaryHosts","currentAcceptedHosts","localAcceptedHosts","setLocalAcceptedHosts","useState","actionClickedRef","useRef","useEffect","handleDrawerClose","shellui","cookiesByCategory","grouped","cookie","existing","toggleCookie","useCallback","host","enabled","prev","h","toggleCategory","category","categoryHosts","hostsSet","getCategoryState","enabledCount","handleAcceptAll","handleRejectAll","handleSave","hostsToSave","hasChanges","sortedLocal","sortedCurrent","i","jsx","jsxs","categoryCookies","categoryState","isStrictNecessary","Switch","checked","isEnabled","resolveLocalizedString","Button"],"mappings":"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"}
1
+ {"version":3,"file":"CookiePreferencesView-CIXBJWNt.js","sources":["../src/features/cookieConsent/CookiePreferencesView.tsx"],"sourcesContent":["import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useLocation } from 'react-router';\nimport { shellui } from '@shellui/sdk';\nimport { Button } from '@/components/ui/button';\nimport { Switch } from '@/components/ui/switch';\nimport { useConfig } from '../config/useConfig';\nimport { useSettings } from '../settings/hooks/useSettings';\nimport { resolveLocalizedString } from '../layouts/utils';\nimport type { CookieConsentCategory, CookieDefinition } from '../config/types';\n\n/** Category display order and labels */\nconst CATEGORY_ORDER: CookieConsentCategory[] = [\n 'strict_necessary',\n 'functional_performance',\n 'targeting',\n 'social_media_embedded',\n];\n\n/** Format duration in human-readable format */\nfunction formatDuration(\n seconds: number,\n t: (key: string, options?: Record<string, unknown>) => string,\n): string {\n if (seconds < 60) return t('preferences.duration.seconds', { count: seconds });\n if (seconds < 3600) return t('preferences.duration.minutes', { count: Math.floor(seconds / 60) });\n if (seconds < 86400)\n return t('preferences.duration.hours', { count: Math.floor(seconds / 3600) });\n if (seconds < 31536000)\n return t('preferences.duration.days', { count: Math.floor(seconds / 86400) });\n return t('preferences.duration.years', { count: Math.floor(seconds / 31536000) });\n}\n\nexport function CookiePreferencesView() {\n const { t, i18n } = useTranslation('cookieConsent');\n const { config } = useConfig();\n const { settings, updateSetting } = useSettings();\n const location = useLocation();\n const searchParams = new URLSearchParams(location.search);\n const isInitialConsent = searchParams.get('initial') === 'true';\n const currentLanguage = i18n.language || 'en';\n\n const cookies = config?.cookieConsent?.cookies ?? [];\n const allHosts = useMemo(() => cookies.map((c) => c.host), [cookies]);\n\n // Strictly necessary hosts are always enabled\n const strictNecessaryHosts = useMemo(\n () => cookies.filter((c) => c.category === 'strict_necessary').map((c) => c.host),\n [cookies],\n );\n\n const currentAcceptedHosts = settings?.cookieConsent?.acceptedHosts ?? [];\n\n // Local state for unsaved changes (always include strict necessary)\n const [localAcceptedHosts, setLocalAcceptedHosts] = useState<string[]>(() => [\n ...new Set([...currentAcceptedHosts, ...strictNecessaryHosts]),\n ]);\n\n // Track if save/accept/reject was clicked to avoid rejecting on intentional close\n const actionClickedRef = useRef(false);\n\n // Reset local state when drawer opens (when URL changes to include initial param)\n useEffect(() => {\n if (isInitialConsent) {\n // Always include strict necessary hosts\n setLocalAcceptedHosts([...new Set([...currentAcceptedHosts, ...strictNecessaryHosts])]);\n }\n }, [isInitialConsent, currentAcceptedHosts, strictNecessaryHosts]);\n\n // Handle drawer close without saving during initial consent\n useEffect(() => {\n if (!isInitialConsent) return;\n\n const handleDrawerClose = () => {\n // If closing without saving during initial consent, reject all except strict necessary\n // Check if user has never consented and no action was clicked\n const neverConsented = (settings?.cookieConsent?.consentedCookieHosts ?? []).length === 0;\n if (neverConsented && !actionClickedRef.current) {\n updateSetting('cookieConsent', {\n acceptedHosts: strictNecessaryHosts,\n consentedCookieHosts: allHosts,\n });\n }\n };\n\n const cleanup = shellui.addMessageListener('SHELLUI_CLOSE_DRAWER', handleDrawerClose);\n return cleanup;\n }, [isInitialConsent, strictNecessaryHosts, allHosts, updateSetting, settings]);\n\n // Cleanup on unmount: if initial consent and drawer closes without save, reject all\n useEffect(() => {\n return () => {\n if (isInitialConsent && !actionClickedRef.current) {\n // Check if user has never consented\n const neverConsented = (settings?.cookieConsent?.consentedCookieHosts ?? []).length === 0;\n if (neverConsented) {\n updateSetting('cookieConsent', {\n acceptedHosts: strictNecessaryHosts,\n consentedCookieHosts: allHosts,\n });\n }\n }\n };\n }, [isInitialConsent, strictNecessaryHosts, allHosts, updateSetting, settings]);\n\n // Group cookies by category\n const cookiesByCategory = useMemo(() => {\n const grouped = new Map<CookieConsentCategory, CookieDefinition[]>();\n for (const cookie of cookies) {\n const existing = grouped.get(cookie.category) ?? [];\n grouped.set(cookie.category, [...existing, cookie]);\n }\n return grouped;\n }, [cookies]);\n\n // Toggle individual cookie\n const toggleCookie = useCallback((host: string, enabled: boolean) => {\n setLocalAcceptedHosts((prev) => (enabled ? [...prev, host] : prev.filter((h) => h !== host)));\n }, []);\n\n // Toggle entire category\n const toggleCategory = useCallback(\n (category: CookieConsentCategory, enabled: boolean) => {\n const categoryHosts = cookiesByCategory.get(category)?.map((c) => c.host) ?? [];\n setLocalAcceptedHosts((prev) => {\n if (enabled) {\n return [...new Set([...prev, ...categoryHosts])];\n } else {\n const hostsSet = new Set(categoryHosts);\n return prev.filter((h) => !hostsSet.has(h));\n }\n });\n },\n [cookiesByCategory],\n );\n\n // Check if category is fully or partially enabled\n const getCategoryState = useCallback(\n (category: CookieConsentCategory): 'all' | 'some' | 'none' => {\n const categoryHosts = cookiesByCategory.get(category)?.map((c) => c.host) ?? [];\n if (categoryHosts.length === 0) return 'none';\n const enabledCount = categoryHosts.filter((h) => localAcceptedHosts.includes(h)).length;\n if (enabledCount === categoryHosts.length) return 'all';\n if (enabledCount > 0) return 'some';\n return 'none';\n },\n [cookiesByCategory, localAcceptedHosts],\n );\n\n // Accept all\n const handleAcceptAll = useCallback(() => {\n actionClickedRef.current = true;\n updateSetting('cookieConsent', {\n acceptedHosts: allHosts,\n consentedCookieHosts: allHosts,\n });\n shellui.closeDrawer();\n }, [allHosts, updateSetting]);\n\n // Reject all except strict necessary (which are always enabled)\n const handleRejectAll = useCallback(() => {\n actionClickedRef.current = true;\n updateSetting('cookieConsent', {\n acceptedHosts: strictNecessaryHosts,\n consentedCookieHosts: allHosts,\n });\n shellui.closeDrawer();\n }, [strictNecessaryHosts, allHosts, updateSetting]);\n\n // Save custom preferences (always include strict necessary)\n const handleSave = useCallback(() => {\n actionClickedRef.current = true;\n const hostsToSave = [...new Set([...localAcceptedHosts, ...strictNecessaryHosts])];\n updateSetting('cookieConsent', {\n acceptedHosts: hostsToSave,\n consentedCookieHosts: allHosts,\n });\n shellui.closeDrawer();\n }, [localAcceptedHosts, strictNecessaryHosts, allHosts, updateSetting]);\n\n // Check if preferences have changed\n const hasChanges = useMemo(() => {\n if (localAcceptedHosts.length !== currentAcceptedHosts.length) return true;\n const sortedLocal = [...localAcceptedHosts].sort();\n const sortedCurrent = [...currentAcceptedHosts].sort();\n return sortedLocal.some((h, i) => h !== sortedCurrent[i]);\n }, [localAcceptedHosts, currentAcceptedHosts]);\n\n if (cookies.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full p-6\">\n <p className=\"text-muted-foreground\">{t('preferences.noCookies')}</p>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full bg-background\">\n {/* Header */}\n <div className=\"flex flex-col space-y-2 border-b border-border/60 px-6 pt-5 pb-4\">\n <h2\n className=\"text-lg font-semibold leading-none tracking-tight\"\n style={{ fontFamily: 'var(--heading-font-family, inherit)' }}\n >\n {t('preferences.title')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{t('preferences.description')}</p>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto px-6 py-4\">\n {CATEGORY_ORDER.map((category) => {\n const categoryCookies = cookiesByCategory.get(category);\n if (!categoryCookies || categoryCookies.length === 0) return null;\n\n const categoryState = getCategoryState(category);\n const isStrictNecessary = category === 'strict_necessary';\n\n return (\n <div\n key={category}\n className=\"mb-6 last:mb-0\"\n >\n {/* Category header with toggle */}\n <div className=\"flex items-center justify-between mb-3\">\n <div className=\"flex-1 min-w-0\">\n <h3\n className=\"text-sm font-semibold\"\n style={{ fontFamily: 'var(--heading-font-family, inherit)' }}\n >\n {t(`preferences.categories.${category}.title`)}\n </h3>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {t(`preferences.categories.${category}.description`)}\n </p>\n </div>\n <div className=\"ml-4 flex items-center gap-2\">\n {!isStrictNecessary && categoryState === 'some' && (\n <span className=\"text-xs text-muted-foreground\">\n {t('preferences.partial')}\n </span>\n )}\n {isStrictNecessary ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('preferences.alwaysOn')}\n </span>\n ) : (\n <Switch\n checked={categoryState === 'all'}\n onCheckedChange={(checked) => toggleCategory(category, checked)}\n aria-label={t(`preferences.categories.${category}.title`)}\n />\n )}\n </div>\n </div>\n\n {/* Individual cookies - only show for non-strictly-necessary categories */}\n {!isStrictNecessary && (\n <div className=\"space-y-2 pl-2 border-l-2 border-border ml-1\">\n {categoryCookies.map((cookie) => {\n const isEnabled = localAcceptedHosts.includes(cookie.host);\n return (\n <div\n key={cookie.host}\n className=\"flex items-start justify-between gap-3 py-2 px-3 rounded-md bg-muted/30\"\n >\n <div className=\"flex-1 min-w-0\">\n <span className=\"text-sm font-medium truncate\">{cookie.name}</span>\n {cookie.description && (\n <p className=\"text-xs text-muted-foreground mt-0.5 line-clamp-2\">\n {resolveLocalizedString(cookie.description, currentLanguage)}\n </p>\n )}\n <div className=\"flex items-center gap-3 mt-1 text-[10px] text-muted-foreground/70\">\n <span>{cookie.host}</span>\n <span>•</span>\n <span>{formatDuration(cookie.durationSeconds, t)}</span>\n <span>•</span>\n <span className=\"capitalize\">{cookie.type.replace('_', ' ')}</span>\n </div>\n </div>\n <Switch\n checked={isEnabled}\n onCheckedChange={(checked) => toggleCookie(cookie.host, checked)}\n aria-label={cookie.name}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n })}\n </div>\n\n {/* Footer */}\n <div className=\"mt-auto flex flex-col gap-2 border-t border-border px-6 py-4\">\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRejectAll}\n className=\"flex-1\"\n >\n {t('preferences.rejectAll')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleAcceptAll}\n className=\"flex-1\"\n >\n {t('preferences.acceptAll')}\n </Button>\n </div>\n <Button\n size=\"sm\"\n onClick={handleSave}\n disabled={!hasChanges && !isInitialConsent}\n className=\"w-full\"\n >\n {t('preferences.save')}\n </Button>\n </div>\n </div>\n );\n}\n"],"names":["CATEGORY_ORDER","formatDuration","seconds","t","CookiePreferencesView","i18n","useTranslation","config","useConfig","settings","updateSetting","useSettings","location","useLocation","isInitialConsent","currentLanguage","cookies","allHosts","useMemo","c","strictNecessaryHosts","currentAcceptedHosts","localAcceptedHosts","setLocalAcceptedHosts","useState","actionClickedRef","useRef","useEffect","handleDrawerClose","shellui","cookiesByCategory","grouped","cookie","existing","toggleCookie","useCallback","host","enabled","prev","h","toggleCategory","category","categoryHosts","hostsSet","getCategoryState","enabledCount","handleAcceptAll","handleRejectAll","handleSave","hostsToSave","hasChanges","sortedLocal","sortedCurrent","i","jsx","jsxs","categoryCookies","categoryState","isStrictNecessary","Switch","checked","isEnabled","resolveLocalizedString","Button"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { jsx as e, jsxs as h, Fragment as O } from "react/jsx-runtime";
2
2
  import { useLocation as M, Outlet as F, Link as I } from "react-router";
3
- import { useMemo as _, useEffect as P, useState as C, useRef as G, useLayoutEffect as H } from "react";
3
+ import { useMemo as j, useEffect as P, useState as C, useRef as G, useLayoutEffect as H } from "react";
4
4
  import { useTranslation as R } from "react-i18next";
5
- import { shellui as S } from "@shellui/sdk";
6
- import { S as U, a as V, b as X, c as Z, d as q, e as J, f as K, g as Q, h as T, i as B, j as Y } from "./sidebar-ClIeZ2zb.js";
7
- import { f as z, s as ee, b as $, d as ne, c as p, Z as te, r as re } from "./index-lmRk5L6z.js";
8
- import { L as oe, O as se } from "./OverlayShell-pzbqQW25.js";
5
+ import { shellui as L } from "@shellui/sdk";
6
+ import { S as V, a as U, b as X, c as Z, d as q, e as J, f as K, g as Q, h as T, i as B, j as Y } from "./sidebar-Cvm_uv4l.js";
7
+ import { f as z, s as ee, b as $, d as ne, c as u, Z as te, r as re } from "./index-PsePV0Ng.js";
8
+ import { L as oe, O as se } from "./OverlayShell-CGjN4rTu.js";
9
9
  const W = (n) => {
10
10
  try {
11
11
  const o = new URL(n).hostname;
@@ -13,34 +13,26 @@ const W = (n) => {
13
13
  } catch {
14
14
  return null;
15
15
  }
16
- }, A = ({
16
+ }, E = ({
17
17
  navigation: n
18
18
  }) => {
19
- const a = M(), { i18n: o } = R(), s = o.language || "en", b = (t, l) => typeof t == "string" ? t : t[l] || t.en || t.fr || Object.values(t)[0] || "", f = _(() => n.some((t) => "title" in t && "items" in t ? t.items.some((l) => !!l.icon) : !!t.icon), [n]), c = (t) => "title" in t && "items" in t, d = (t) => {
20
- const l = `/${t.path}`, m = t.openIn === "modal" || t.openIn === "drawer", u = t.openIn === "external", r = !m && !u && (a.pathname === l || a.pathname.startsWith(`${l}/`)), i = b(t.label, s), g = u && !t.icon ? W(t.url) : null, x = t.icon ?? g ?? null, v = x ? /* @__PURE__ */ e(
19
+ const a = M(), { i18n: o } = R(), s = o.language || "en", b = (t, l) => typeof t == "string" ? t : t[l] || t.en || t.fr || Object.values(t)[0] || "", f = j(() => n.some((t) => "title" in t && "items" in t ? t.items.some((l) => !!l.icon) : !!t.icon), [n]), c = (t) => "title" in t && "items" in t, d = (t) => {
20
+ const l = `/${t.path}`, m = t.openIn === "modal" || t.openIn === "drawer", p = t.openIn === "external", r = !m && !p && (a.pathname === l || a.pathname.startsWith(`${l}/`)), i = b(t.label, s), g = p && !t.icon ? W(t.url) : null, x = t.icon ?? g ?? null, v = x ? /* @__PURE__ */ e(
21
21
  "img",
22
22
  {
23
23
  src: x,
24
24
  alt: "",
25
- className: p("h-4 w-4", "shrink-0")
25
+ className: u("h-4 w-4", "shrink-0")
26
26
  }
27
27
  ) : f ? /* @__PURE__ */ e("span", { className: "h-4 w-4 shrink-0" }) : null, w = /* @__PURE__ */ h(O, { children: [
28
28
  v,
29
29
  /* @__PURE__ */ e("span", { className: "truncate", children: i }),
30
- u ? /* @__PURE__ */ e(
31
- "img",
32
- {
33
- src: "/icons/external-link.svg",
34
- alt: "",
35
- className: "ml-auto h-4 w-4 shrink-0 opacity-70",
36
- "aria-hidden": !0
37
- }
38
- ) : null
30
+ p ? /* @__PURE__ */ e(pe, { className: "ml-auto h-4 w-4 shrink-0 opacity-70" }) : null
39
31
  ] }), N = t.openIn === "modal" ? /* @__PURE__ */ e(
40
32
  "button",
41
33
  {
42
34
  type: "button",
43
- onClick: () => S.openModal(t.url),
35
+ onClick: () => L.openModal(t.url),
44
36
  className: "flex items-center gap-2 w-full cursor-pointer text-left",
45
37
  children: w
46
38
  }
@@ -48,7 +40,7 @@ const W = (n) => {
48
40
  "button",
49
41
  {
50
42
  type: "button",
51
- onClick: () => S.openDrawer({ url: t.url, position: t.drawerPosition }),
43
+ onClick: () => L.openDrawer({ url: t.url, position: t.drawerPosition }),
52
44
  className: "flex items-center gap-2 w-full cursor-pointer text-left",
53
45
  children: w
54
46
  }
@@ -74,7 +66,7 @@ const W = (n) => {
74
66
  {
75
67
  asChild: !0,
76
68
  isActive: r,
77
- className: p("w-full", r && "bg-sidebar-accent text-sidebar-accent-foreground"),
69
+ className: u("w-full", r && "bg-sidebar-accent text-sidebar-accent-foreground"),
78
70
  children: N
79
71
  }
80
72
  );
@@ -124,13 +116,13 @@ const W = (n) => {
124
116
  ) : n ? /* @__PURE__ */ e("span", { className: "leading-none", children: n }) : null
125
117
  }
126
118
  ) }),
127
- /* @__PURE__ */ e(Z, { className: "gap-1", children: /* @__PURE__ */ e(A, { navigation: o }) }),
128
- s.length > 0 && /* @__PURE__ */ e(q, { children: /* @__PURE__ */ e(A, { navigation: s }) })
119
+ /* @__PURE__ */ e(Z, { className: "gap-1", children: /* @__PURE__ */ e(E, { navigation: o }) }),
120
+ s.length > 0 && /* @__PURE__ */ e(q, { children: /* @__PURE__ */ e(E, { navigation: s }) })
129
121
  ] });
130
122
  function ie(n, a) {
131
123
  return typeof n == "string" ? n : n[a] || n.en || n.fr || Object.values(n)[0] || "";
132
124
  }
133
- const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he = ({
125
+ const le = 64, A = 4, ce = 12, de = 6, he = (n) => n.startsWith("/icons/"), ue = ({
134
126
  item: n,
135
127
  label: a,
136
128
  isActive: o,
@@ -143,14 +135,14 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
143
135
  {
144
136
  src: s,
145
137
  alt: "",
146
- className: p(
138
+ className: u(
147
139
  "size-4 shrink-0 rounded-sm object-cover",
148
140
  b && "opacity-90 dark:opacity-100 dark:invert"
149
141
  )
150
142
  }
151
143
  ) : /* @__PURE__ */ e("span", { className: "size-4 shrink-0 rounded-sm bg-muted" }),
152
144
  /* @__PURE__ */ e("span", { className: "text-[11px] leading-tight truncate w-full min-w-0 text-center block", children: a })
153
- ] }), d = p(
145
+ ] }), d = u(
154
146
  "flex flex-col items-center justify-center rounded-md py-1.5 px-2 min-w-0 max-w-full transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
155
147
  o ? "bg-accent text-accent-foreground [&_span]:text-accent-foreground" : "text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground [&_span]:inherit"
156
148
  );
@@ -158,7 +150,7 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
158
150
  "button",
159
151
  {
160
152
  type: "button",
161
- onClick: () => S.openModal(n.url),
153
+ onClick: () => L.openModal(n.url),
162
154
  className: d,
163
155
  children: c
164
156
  }
@@ -166,7 +158,7 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
166
158
  "button",
167
159
  {
168
160
  type: "button",
169
- onClick: () => S.openDrawer({ url: n.url, position: n.drawerPosition }),
161
+ onClick: () => L.openDrawer({ url: n.url, position: n.drawerPosition }),
170
162
  className: d,
171
163
  children: c
172
164
  }
@@ -187,7 +179,7 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
187
179
  children: c
188
180
  }
189
181
  );
190
- }, pe = ({ className: n }) => /* @__PURE__ */ e(
182
+ }, pe = ({ className: n }) => /* @__PURE__ */ h(
191
183
  "svg",
192
184
  {
193
185
  xmlns: "http://www.w3.org/2000/svg",
@@ -199,9 +191,13 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
199
191
  strokeWidth: "2",
200
192
  strokeLinecap: "round",
201
193
  strokeLinejoin: "round",
202
- className: p("shrink-0", n),
194
+ className: u("shrink-0", n),
203
195
  "aria-hidden": !0,
204
- children: /* @__PURE__ */ e("path", { d: "m18 15-6-6-6 6" })
196
+ children: [
197
+ /* @__PURE__ */ e("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
198
+ /* @__PURE__ */ e("polyline", { points: "15 3 21 3 21 9" }),
199
+ /* @__PURE__ */ e("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
200
+ ]
205
201
  }
206
202
  ), fe = ({ className: n }) => /* @__PURE__ */ e(
207
203
  "svg",
@@ -215,11 +211,27 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
215
211
  strokeWidth: "2",
216
212
  strokeLinecap: "round",
217
213
  strokeLinejoin: "round",
218
- className: p("shrink-0", n),
214
+ className: u("shrink-0", n),
215
+ "aria-hidden": !0,
216
+ children: /* @__PURE__ */ e("path", { d: "m18 15-6-6-6 6" })
217
+ }
218
+ ), me = ({ className: n }) => /* @__PURE__ */ e(
219
+ "svg",
220
+ {
221
+ xmlns: "http://www.w3.org/2000/svg",
222
+ width: "24",
223
+ height: "24",
224
+ viewBox: "0 0 24 24",
225
+ fill: "none",
226
+ stroke: "currentColor",
227
+ strokeWidth: "2",
228
+ strokeLinecap: "round",
229
+ strokeLinejoin: "round",
230
+ className: u("shrink-0", n),
219
231
  "aria-hidden": !0,
220
232
  children: /* @__PURE__ */ e("path", { d: "m6 9 6 6 6-6" })
221
233
  }
222
- ), me = ({ className: n }) => /* @__PURE__ */ h(
234
+ ), ge = ({ className: n }) => /* @__PURE__ */ h(
223
235
  "svg",
224
236
  {
225
237
  xmlns: "http://www.w3.org/2000/svg",
@@ -231,14 +243,14 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
231
243
  strokeWidth: "2",
232
244
  strokeLinecap: "round",
233
245
  strokeLinejoin: "round",
234
- className: p("shrink-0", n),
246
+ className: u("shrink-0", n),
235
247
  "aria-hidden": !0,
236
248
  children: [
237
249
  /* @__PURE__ */ e("path", { d: "m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }),
238
250
  /* @__PURE__ */ e("polyline", { points: "9 22 9 12 15 12 15 22" })
239
251
  ]
240
252
  }
241
- ), ge = ({
253
+ ), be = ({
242
254
  items: n,
243
255
  currentLanguage: a
244
256
  }) => {
@@ -252,21 +264,21 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
252
264
  });
253
265
  return i.observe(r), d(r.getBoundingClientRect().width), () => i.disconnect();
254
266
  }, []);
255
- const { rowItems: t, overflowItems: l, hasMore: m } = _(() => {
256
- const r = n.slice(), i = Math.max(0, c - ce * 2), g = le + E, x = c > 0 ? Math.floor((i + E) / g) : 5, v = Math.min(Math.max(0, x), de), k = v - 1, N = r.length <= k ? r.length : Math.max(0, v - 2), y = r.slice(0, N), D = new Set(y.map((L) => L.path)), j = r.filter((L) => !D.has(L.path));
267
+ const { rowItems: t, overflowItems: l, hasMore: m } = j(() => {
268
+ const r = n.slice(), i = Math.max(0, c - ce * 2), g = le + A, x = c > 0 ? Math.floor((i + A) / g) : 5, v = Math.min(Math.max(0, x), de), k = v - 1, N = r.length <= k ? r.length : Math.max(0, v - 2), y = r.slice(0, N), D = new Set(y.map((S) => S.path)), _ = r.filter((S) => !D.has(S.path));
257
269
  return {
258
270
  rowItems: y,
259
- overflowItems: j,
260
- hasMore: j.length > 0
271
+ overflowItems: _,
272
+ hasMore: _.length > 0
261
273
  };
262
274
  }, [n, c]);
263
275
  P(() => {
264
276
  b(!1);
265
277
  }, [o.pathname]);
266
- const u = (r, i) => {
267
- const g = `/${r.path}`, v = !(r.openIn === "modal" || r.openIn === "drawer" || r.openIn === "external") && (o.pathname === g || o.pathname.startsWith(`${g}/`)), k = re(r.label, a), w = r.openIn === "external" && !r.icon ? W(r.url) : null, N = r.icon ?? w ?? null, y = N ? ue(N) : !1;
278
+ const p = (r, i) => {
279
+ const g = `/${r.path}`, v = !(r.openIn === "modal" || r.openIn === "drawer" || r.openIn === "external") && (o.pathname === g || o.pathname.startsWith(`${g}/`)), k = re(r.label, a), w = r.openIn === "external" && !r.icon ? W(r.url) : null, N = r.icon ?? w ?? null, y = N ? he(N) : !1;
268
280
  return /* @__PURE__ */ e(
269
- he,
281
+ ue,
270
282
  {
271
283
  item: r,
272
284
  label: k,
@@ -292,31 +304,31 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
292
304
  I,
293
305
  {
294
306
  to: "/",
295
- className: p(
307
+ className: u(
296
308
  "flex flex-col items-center justify-center gap-1 rounded-md py-1.5 px-2 min-w-0 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
297
309
  o.pathname === "/" || o.pathname === "" ? "bg-sidebar-accent text-sidebar-accent-foreground [&_span]:text-sidebar-accent-foreground" : "text-sidebar-foreground/80 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground [&_span]:inherit"
298
310
  ),
299
311
  "aria-label": "Home",
300
312
  children: [
301
- /* @__PURE__ */ e("span", { className: "size-4 shrink-0 flex items-center justify-center [&_svg]:text-current", children: /* @__PURE__ */ e(me, { className: "size-4" }) }),
313
+ /* @__PURE__ */ e("span", { className: "size-4 shrink-0 flex items-center justify-center [&_svg]:text-current", children: /* @__PURE__ */ e(ge, { className: "size-4" }) }),
302
314
  /* @__PURE__ */ e("span", { className: "text-[11px] leading-tight", children: "Home" })
303
315
  ]
304
316
  }
305
317
  ),
306
- t.map((r, i) => u(r, i)),
318
+ t.map((r, i) => p(r, i)),
307
319
  m && /* @__PURE__ */ h(
308
320
  "button",
309
321
  {
310
322
  type: "button",
311
323
  onClick: () => b((r) => !r),
312
- className: p(
324
+ className: u(
313
325
  "flex flex-col items-center justify-center gap-1 rounded-md py-1.5 px-2 min-w-0 transition-colors cursor-pointer",
314
326
  "text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
315
327
  ),
316
328
  "aria-expanded": s,
317
329
  "aria-label": s ? "Show less" : "Show more",
318
330
  children: [
319
- /* @__PURE__ */ e("span", { className: "size-4 shrink-0 flex items-center justify-center", children: s ? /* @__PURE__ */ e(fe, { className: "size-4" }) : /* @__PURE__ */ e(pe, { className: "size-4" }) }),
331
+ /* @__PURE__ */ e("span", { className: "size-4 shrink-0 flex items-center justify-center", children: s ? /* @__PURE__ */ e(me, { className: "size-4" }) : /* @__PURE__ */ e(fe, { className: "size-4" }) }),
320
332
  /* @__PURE__ */ e("span", { className: "text-[11px] leading-tight", children: s ? "Less" : "More" })
321
333
  ]
322
334
  }
@@ -325,19 +337,19 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
325
337
  /* @__PURE__ */ e(
326
338
  "div",
327
339
  {
328
- className: p(
340
+ className: u(
329
341
  "grid transition-[grid-template-rows] duration-300 ease-out",
330
342
  s ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
331
343
  ),
332
- children: /* @__PURE__ */ e("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ e("div", { className: "px-4 pt-3 pb-2 border-t border-sidebar-border/50 mt-1", children: /* @__PURE__ */ e("div", { className: "grid grid-cols-5 gap-2 justify-items-center max-w-xs mx-auto", children: s ? l.map((r, i) => u(r, i)) : null }) }) })
344
+ children: /* @__PURE__ */ e("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ e("div", { className: "px-4 pt-3 pb-2 border-t border-sidebar-border/50 mt-1", children: /* @__PURE__ */ e("div", { className: "grid grid-cols-5 gap-2 justify-items-center max-w-xs mx-auto", children: s ? l.map((r, i) => p(r, i)) : null }) }) })
333
345
  }
334
346
  )
335
347
  ]
336
348
  }
337
349
  );
338
- }, be = ({ title: n, logo: a, navigation: o }) => {
339
- const s = M(), { i18n: b } = R(), f = b.language || "en", { startNav: c, endItems: d, navigationItems: t, mobileNavItems: l } = _(() => {
340
- const m = z(o, "desktop"), u = z(o, "mobile"), { start: r, end: i } = ee(m), g = $(m), x = $(u);
350
+ }, xe = ({ title: n, logo: a, navigation: o }) => {
351
+ const s = M(), { i18n: b } = R(), f = b.language || "en", { startNav: c, endItems: d, navigationItems: t, mobileNavItems: l } = j(() => {
352
+ const m = z(o, "desktop"), p = z(o, "mobile"), { start: r, end: i } = ee(m), g = $(m), x = $(p);
341
353
  return {
342
354
  startNav: ne(r),
343
355
  endItems: i,
@@ -347,20 +359,20 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
347
359
  }, [o]);
348
360
  return P(() => {
349
361
  if (!n) return;
350
- const u = (s.pathname.replace(/^\/+|\/+$/g, "") || "").split("/")[0];
351
- if (!u) {
362
+ const p = (s.pathname.replace(/^\/+|\/+$/g, "") || "").split("/")[0];
363
+ if (!p) {
352
364
  document.title = n;
353
365
  return;
354
366
  }
355
- const r = t.find((i) => i.path === u);
367
+ const r = t.find((i) => i.path === p);
356
368
  if (r) {
357
369
  const i = ie(r.label, f);
358
370
  document.title = `${i} | ${n}`;
359
371
  } else
360
372
  document.title = n;
361
- }, [s.pathname, n, t, f]), /* @__PURE__ */ e(oe, { children: /* @__PURE__ */ e(U, { children: /* @__PURE__ */ h(se, { navigationItems: t, children: [
373
+ }, [s.pathname, n, t, f]), /* @__PURE__ */ e(oe, { children: /* @__PURE__ */ e(V, { children: /* @__PURE__ */ h(se, { navigationItems: t, children: [
362
374
  /* @__PURE__ */ h("div", { className: "flex h-screen overflow-hidden", children: [
363
- /* @__PURE__ */ e(V, { className: p("hidden md:flex shrink-0"), children: /* @__PURE__ */ e(
375
+ /* @__PURE__ */ e(U, { className: u("hidden md:flex shrink-0"), children: /* @__PURE__ */ e(
364
376
  ae,
365
377
  {
366
378
  title: n,
@@ -372,15 +384,15 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
372
384
  /* @__PURE__ */ e("main", { className: "flex-1 flex flex-col overflow-hidden bg-background relative min-w-0", children: /* @__PURE__ */ e("div", { className: "flex-1 flex flex-col overflow-auto pb-16 md:pb-0", children: /* @__PURE__ */ e(F, {}) }) })
373
385
  ] }),
374
386
  /* @__PURE__ */ e(
375
- ge,
387
+ be,
376
388
  {
377
389
  items: l,
378
390
  currentLanguage: f
379
391
  }
380
392
  )
381
393
  ] }) }) });
382
- }, Le = ({ title: n, appIcon: a, logo: o, navigation: s }) => /* @__PURE__ */ e(
383
- be,
394
+ }, Oe = ({ title: n, appIcon: a, logo: o, navigation: s }) => /* @__PURE__ */ e(
395
+ xe,
384
396
  {
385
397
  title: n,
386
398
  appIcon: a,
@@ -389,6 +401,6 @@ const le = 64, E = 4, ce = 12, de = 6, ue = (n) => n.startsWith("/icons/"), he =
389
401
  }
390
402
  );
391
403
  export {
392
- Le as DefaultLayout
404
+ Oe as DefaultLayout
393
405
  };
394
- //# sourceMappingURL=DefaultLayout-Dbb3uJED.js.map
406
+ //# sourceMappingURL=DefaultLayout-Bztmv2c_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultLayout-Bztmv2c_.js","sources":["../src/features/layouts/DefaultLayout.tsx"],"sourcesContent":["import { Link, useLocation, Outlet } from 'react-router';\nimport { useMemo, useEffect, useState, useRef, useLayoutEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { shellui } from '@shellui/sdk';\nimport type { NavigationItem, NavigationGroup } from '../config/types';\nimport {\n Sidebar,\n SidebarProvider,\n SidebarHeader,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupLabel,\n SidebarGroupContent,\n SidebarMenu,\n SidebarMenuItem,\n SidebarMenuButton,\n} from '@/components/ui/sidebar';\nimport { cn } from '@/lib/utils';\nimport { Z_INDEX } from '@/lib/z-index';\nimport {\n filterNavigationByViewport,\n filterNavigationForSidebar,\n flattenNavigationItems,\n resolveLocalizedString as resolveNavLabel,\n splitNavigationByPosition,\n} from './utils';\nimport { LayoutProviders } from './LayoutProviders';\nimport { OverlayShell } from './OverlayShell';\n\ninterface DefaultLayoutProps {\n title?: string;\n appIcon?: string;\n logo?: string;\n navigation: (NavigationItem | NavigationGroup)[];\n}\n\n// DuckDuckGo favicon URL for a given page URL (used when openIn === 'external' and no icon is set)\nconst getExternalFaviconUrl = (url: string): string | null => {\n try {\n const parsed = new URL(url);\n const hostname = parsed.hostname;\n if (!hostname) return null;\n return `https://icons.duckduckgo.com/ip3/${hostname}.ico`;\n } catch {\n return null;\n }\n};\n\nconst NavigationContent = ({\n navigation,\n}: {\n navigation: (NavigationItem | NavigationGroup)[];\n}) => {\n const location = useLocation();\n const { i18n } = useTranslation();\n const currentLanguage = i18n.language || 'en';\n\n // Helper function to resolve localized strings\n const resolveLocalizedString = (\n value: string | { en: string; fr: string; [key: string]: string },\n lang: string,\n ): string => {\n if (typeof value === 'string') {\n return value;\n }\n // Try current language first, then English as fallback\n return value[lang] || value.en || value.fr || Object.values(value)[0] || '';\n };\n\n // Check if at least one navigation item has an icon\n const hasAnyIcons = useMemo(() => {\n return navigation.some((item) => {\n if ('title' in item && 'items' in item) {\n // It's a group\n return (item as NavigationGroup).items.some((navItem) => !!navItem.icon);\n }\n // It's a standalone item\n return !!(item as NavigationItem).icon;\n });\n }, [navigation]);\n\n // Helper to check if an item is a group\n const isGroup = (item: NavigationItem | NavigationGroup): item is NavigationGroup => {\n return 'title' in item && 'items' in item;\n };\n\n // Render a single nav item link or modal/drawer trigger\n const renderNavItem = (navItem: NavigationItem) => {\n const pathPrefix = `/${navItem.path}`;\n const isOverlay = navItem.openIn === 'modal' || navItem.openIn === 'drawer';\n const isExternal = navItem.openIn === 'external';\n const isActive =\n !isOverlay &&\n !isExternal &&\n (location.pathname === pathPrefix || location.pathname.startsWith(`${pathPrefix}/`));\n const itemLabel = resolveLocalizedString(navItem.label, currentLanguage);\n const faviconUrl = isExternal && !navItem.icon ? getExternalFaviconUrl(navItem.url) : null;\n const iconSrc = navItem.icon ?? faviconUrl ?? null;\n const iconEl = iconSrc ? (\n <img\n src={iconSrc}\n alt=\"\"\n className={cn('h-4 w-4', 'shrink-0')}\n />\n ) : hasAnyIcons ? (\n <span className=\"h-4 w-4 shrink-0\" />\n ) : null;\n const externalIcon = isExternal ? (\n <ExternalLinkIcon className=\"ml-auto h-4 w-4 shrink-0 opacity-70\" />\n ) : null;\n const content = (\n <>\n {iconEl}\n <span className=\"truncate\">{itemLabel}</span>\n {externalIcon}\n </>\n );\n const linkOrTrigger =\n navItem.openIn === 'modal' ? (\n <button\n type=\"button\"\n onClick={() => shellui.openModal(navItem.url)}\n className=\"flex items-center gap-2 w-full cursor-pointer text-left\"\n >\n {content}\n </button>\n ) : navItem.openIn === 'drawer' ? (\n <button\n type=\"button\"\n onClick={() => shellui.openDrawer({ url: navItem.url, position: navItem.drawerPosition })}\n className=\"flex items-center gap-2 w-full cursor-pointer text-left\"\n >\n {content}\n </button>\n ) : navItem.openIn === 'external' ? (\n <a\n href={navItem.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-2 w-full\"\n >\n {content}\n </a>\n ) : (\n <Link\n to={`/${navItem.path}`}\n className=\"flex items-center gap-2 w-full\"\n >\n {content}\n </Link>\n );\n return (\n <SidebarMenuButton\n asChild\n isActive={isActive}\n className={cn('w-full', isActive && 'bg-sidebar-accent text-sidebar-accent-foreground')}\n >\n {linkOrTrigger}\n </SidebarMenuButton>\n );\n };\n\n // Render navigation items - handle both groups and standalone items\n return (\n <>\n {navigation.map((item) => {\n if (isGroup(item)) {\n // Render as a group\n const groupTitle = resolveLocalizedString(item.title, currentLanguage);\n return (\n <SidebarGroup\n key={groupTitle}\n className=\"mt-0\"\n >\n <SidebarGroupLabel className=\"mb-1\">{groupTitle}</SidebarGroupLabel>\n <SidebarGroupContent>\n <SidebarMenu className=\"gap-0.5\">\n {item.items.map((navItem) => (\n <SidebarMenuItem key={navItem.path}>{renderNavItem(navItem)}</SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n } else {\n // Render as a standalone item\n return (\n <SidebarMenu\n key={item.path}\n className=\"gap-0.5\"\n >\n <SidebarMenuItem>{renderNavItem(item)}</SidebarMenuItem>\n </SidebarMenu>\n );\n }\n })}\n </>\n );\n};\n\n/** Reusable sidebar inner: header, main nav, footer. Used in desktop Sidebar and mobile Drawer. */\nconst SidebarInner = ({\n title,\n logo,\n startNav,\n endItems,\n}: {\n title?: string;\n logo?: string;\n startNav: (NavigationItem | NavigationGroup)[];\n endItems: (NavigationItem | NavigationGroup)[];\n}) => (\n <>\n <SidebarHeader className=\"border-b border-sidebar-border pb-4\">\n {(title || logo) && (\n <Link\n to=\"/\"\n className=\"flex items-center pl-1 pr-3 py-2 text-lg font-semibold text-sidebar-foreground hover:text-sidebar-foreground/80 transition-colors\"\n >\n {logo && logo.trim() ? (\n <img\n src={logo}\n alt={title || 'Logo'}\n className=\"h-5 w-auto shrink-0 object-contain sidebar-logo\"\n />\n ) : title ? (\n <span className=\"leading-none\">{title}</span>\n ) : null}\n </Link>\n )}\n </SidebarHeader>\n <SidebarContent className=\"gap-1\">\n <NavigationContent navigation={startNav} />\n </SidebarContent>\n {endItems.length > 0 && (\n <SidebarFooter>\n <NavigationContent navigation={endItems} />\n </SidebarFooter>\n )}\n </>\n);\n\nfunction resolveLocalizedLabel(\n value: string | { en: string; fr: string; [key: string]: string },\n lang: string,\n): string {\n if (typeof value === 'string') return value;\n return value[lang] || value.en || value.fr || Object.values(value)[0] || '';\n}\n\n/** Approximate width per slot (icon + label + padding) and gap for dynamic slot count. */\nconst BOTTOM_NAV_SLOT_WIDTH = 64;\nconst BOTTOM_NAV_GAP = 4;\nconst BOTTOM_NAV_PX = 12;\n/** Max slots in the row (Home + nav + optional More) to avoid overflow/duplicated wrap. */\nconst BOTTOM_NAV_MAX_SLOTS = 6;\n\n/** True when the icon is a local app icon (/icons/); external images (avatars, favicons) are shown as-is. */\nconst isAppIcon = (src: string) => src.startsWith('/icons/');\n\n/** Single nav item for bottom bar: icon + label, link or action. */\nconst BottomNavItem = ({\n item,\n label,\n isActive,\n iconSrc,\n applyIconTheme,\n}: {\n item: NavigationItem;\n label: string;\n isActive: boolean;\n iconSrc: string | null;\n applyIconTheme: boolean;\n}) => {\n const pathPrefix = `/${item.path}`;\n const content = (\n <span className=\"flex flex-col items-center justify-center gap-1 w-full min-w-0 max-w-full overflow-hidden\">\n {iconSrc ? (\n <img\n src={iconSrc}\n alt=\"\"\n className={cn(\n 'size-4 shrink-0 rounded-sm object-cover',\n applyIconTheme && 'opacity-90 dark:opacity-100 dark:invert',\n )}\n />\n ) : (\n <span className=\"size-4 shrink-0 rounded-sm bg-muted\" />\n )}\n <span className=\"text-[11px] leading-tight truncate w-full min-w-0 text-center block\">\n {label}\n </span>\n </span>\n );\n const baseClass = cn(\n 'flex flex-col items-center justify-center rounded-md py-1.5 px-2 min-w-0 max-w-full transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n isActive\n ? 'bg-accent text-accent-foreground [&_span]:text-accent-foreground'\n : 'text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground [&_span]:inherit',\n );\n if (item.openIn === 'modal') {\n return (\n <button\n type=\"button\"\n onClick={() => shellui.openModal(item.url)}\n className={baseClass}\n >\n {content}\n </button>\n );\n }\n if (item.openIn === 'drawer') {\n return (\n <button\n type=\"button\"\n onClick={() => shellui.openDrawer({ url: item.url, position: item.drawerPosition })}\n className={baseClass}\n >\n {content}\n </button>\n );\n }\n if (item.openIn === 'external') {\n return (\n <a\n href={item.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={baseClass}\n >\n {content}\n </a>\n );\n }\n return (\n <Link\n to={pathPrefix}\n className={baseClass}\n >\n {content}\n </Link>\n );\n};\n\n/** Inline SVG: external-link icon. Bundled so consumers don't need to serve static SVGs. */\nconst ExternalLinkIcon = ({ className }: { className?: string }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn('shrink-0', className)}\n aria-hidden\n >\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n);\n\n/** Caret up: expand (show second line). */\nconst CaretUpIcon = ({ className }: { className?: string }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn('shrink-0', className)}\n aria-hidden\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n);\n\n/** Caret down: collapse (hide second line). */\nconst CaretDownIcon = ({ className }: { className?: string }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn('shrink-0', className)}\n aria-hidden\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n);\n\n/** Home icon for mobile bottom bar (same as sidebar logo action). */\nconst HomeIcon = ({ className }: { className?: string }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn('shrink-0', className)}\n aria-hidden\n >\n <path d=\"m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\" />\n <polyline points=\"9 22 9 12 15 12 15 22\" />\n </svg>\n);\n\n/** Mobile bottom nav: Home + nav items; More only when not all fit. Dynamic from width. */\nconst MobileBottomNav = ({\n items,\n currentLanguage,\n}: {\n items: NavigationItem[];\n currentLanguage: string;\n}) => {\n const location = useLocation();\n const [expanded, setExpanded] = useState(false);\n const navRef = useRef<HTMLElement>(null);\n const [rowWidth, setRowWidth] = useState(0);\n\n useLayoutEffect(() => {\n const el = navRef.current;\n if (!el) return;\n const ro = new ResizeObserver((entries) => {\n const w = entries[0]?.contentRect.width ?? 0;\n setRowWidth(w);\n });\n ro.observe(el);\n setRowWidth(el.getBoundingClientRect().width);\n return () => ro.disconnect();\n }, []);\n\n const { rowItems, overflowItems, hasMore } = useMemo(() => {\n const list = items.slice();\n const contentWidth = Math.max(0, rowWidth - BOTTOM_NAV_PX * 2);\n const slotTotal = BOTTOM_NAV_SLOT_WIDTH + BOTTOM_NAV_GAP;\n const computedSlots =\n rowWidth > 0 ? Math.floor((contentWidth + BOTTOM_NAV_GAP) / slotTotal) : 5;\n const totalSlots = Math.min(Math.max(0, computedSlots), BOTTOM_NAV_MAX_SLOTS);\n const slotsForNav = totalSlots - 1;\n const allFit = list.length <= slotsForNav;\n const maxInRow = allFit ? list.length : Math.max(0, totalSlots - 2);\n const row = list.slice(0, maxInRow);\n const rowPaths = new Set(row.map((i) => i.path));\n const overflow = list.filter((item) => !rowPaths.has(item.path));\n return {\n rowItems: row,\n overflowItems: overflow,\n hasMore: overflow.length > 0,\n };\n }, [items, rowWidth]);\n\n useEffect(() => {\n setExpanded(false);\n }, [location.pathname]);\n\n const renderItem = (item: NavigationItem, index: number) => {\n const pathPrefix = `/${item.path}`;\n const isOverlayOrExternal =\n item.openIn === 'modal' || item.openIn === 'drawer' || item.openIn === 'external';\n const isActive =\n !isOverlayOrExternal &&\n (location.pathname === pathPrefix || location.pathname.startsWith(`${pathPrefix}/`));\n const label = resolveNavLabel(item.label, currentLanguage);\n const faviconUrl =\n item.openIn === 'external' && !item.icon ? getExternalFaviconUrl(item.url) : null;\n const iconSrc = item.icon ?? faviconUrl ?? null;\n const applyIconTheme = iconSrc ? isAppIcon(iconSrc) : false;\n return (\n <BottomNavItem\n key={`${item.path}-${item.url}-${index}`}\n item={item}\n label={label}\n isActive={isActive}\n iconSrc={iconSrc}\n applyIconTheme={applyIconTheme}\n />\n );\n };\n\n return (\n <nav\n ref={navRef}\n className=\"fixed bottom-0 left-0 right-0 z-[9999] md:hidden border-t border-sidebar-border bg-sidebar-background overflow-hidden pt-2\"\n style={{\n zIndex: Z_INDEX.SIDEBAR_TRIGGER,\n paddingBottom: 'calc(0.5rem + env(safe-area-inset-bottom, 0px))',\n }}\n >\n {/* Top row: Home + nav items + More/Less — single row, no wrap */}\n <div className=\"flex flex-row flex-nowrap items-center justify-center gap-1 px-3 overflow-x-hidden\">\n <Link\n to=\"/\"\n className={cn(\n 'flex flex-col items-center justify-center gap-1 rounded-md py-1.5 px-2 min-w-0 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n location.pathname === '/' || location.pathname === ''\n ? 'bg-sidebar-accent text-sidebar-accent-foreground [&_span]:text-sidebar-accent-foreground'\n : 'text-sidebar-foreground/80 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground [&_span]:inherit',\n )}\n aria-label=\"Home\"\n >\n <span className=\"size-4 shrink-0 flex items-center justify-center [&_svg]:text-current\">\n <HomeIcon className=\"size-4\" />\n </span>\n <span className=\"text-[11px] leading-tight\">Home</span>\n </Link>\n {rowItems.map((item, i) => renderItem(item, i))}\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setExpanded((e) => !e)}\n className={cn(\n 'flex flex-col items-center justify-center gap-1 rounded-md py-1.5 px-2 min-w-0 transition-colors cursor-pointer',\n 'text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n )}\n aria-expanded={expanded}\n aria-label={expanded ? 'Show less' : 'Show more'}\n >\n <span className=\"size-4 shrink-0 flex items-center justify-center\">\n {expanded ? <CaretDownIcon className=\"size-4\" /> : <CaretUpIcon className=\"size-4\" />}\n </span>\n <span className=\"text-[11px] leading-tight\">{expanded ? 'Less' : 'More'}</span>\n </button>\n )}\n </div>\n\n {/* Expanded: only overflow items — render list only when expanded so it clears when collapsed */}\n <div\n className={cn(\n 'grid transition-[grid-template-rows] duration-300 ease-out',\n expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',\n )}\n >\n <div className=\"min-h-0 overflow-hidden\">\n <div className=\"px-4 pt-3 pb-2 border-t border-sidebar-border/50 mt-1\">\n <div className=\"grid grid-cols-5 gap-2 justify-items-center max-w-xs mx-auto\">\n {expanded ? overflowItems.map((item, i) => renderItem(item, i)) : null}\n </div>\n </div>\n </div>\n </div>\n </nav>\n );\n};\n\nconst DefaultLayoutContent = ({ title, logo, navigation }: DefaultLayoutProps) => {\n const location = useLocation();\n const { i18n } = useTranslation();\n const currentLanguage = i18n.language || 'en';\n\n const { startNav, endItems, navigationItems, mobileNavItems } = useMemo(() => {\n const desktopNav = filterNavigationByViewport(navigation, 'desktop');\n const mobileNav = filterNavigationByViewport(navigation, 'mobile');\n const { start, end } = splitNavigationByPosition(desktopNav);\n const flat = flattenNavigationItems(desktopNav);\n const mobileFlat = flattenNavigationItems(mobileNav);\n return {\n startNav: filterNavigationForSidebar(start),\n endItems: end,\n navigationItems: flat,\n mobileNavItems: mobileFlat,\n };\n }, [navigation]);\n\n useEffect(() => {\n if (!title) return;\n const pathname = location.pathname.replace(/^\\/+|\\/+$/g, '') || '';\n const segment = pathname.split('/')[0];\n if (!segment) {\n document.title = title;\n return;\n }\n const navItem = navigationItems.find((item) => item.path === segment);\n if (navItem) {\n const label = resolveLocalizedLabel(navItem.label, currentLanguage);\n document.title = `${label} | ${title}`;\n } else {\n document.title = title;\n }\n }, [location.pathname, title, navigationItems, currentLanguage]);\n\n return (\n <LayoutProviders>\n <SidebarProvider>\n <OverlayShell navigationItems={navigationItems}>\n <div className=\"flex h-screen overflow-hidden\">\n {/* Desktop sidebar: visible from md up */}\n <Sidebar className={cn('hidden md:flex shrink-0')}>\n <SidebarInner\n title={title}\n logo={logo}\n startNav={startNav}\n endItems={endItems}\n />\n </Sidebar>\n\n <main className=\"flex-1 flex flex-col overflow-hidden bg-background relative min-w-0\">\n <div className=\"flex-1 flex flex-col overflow-auto pb-16 md:pb-0\">\n <Outlet />\n </div>\n </main>\n </div>\n\n {/* Mobile bottom nav: visible only below md */}\n <MobileBottomNav\n items={mobileNavItems}\n currentLanguage={currentLanguage}\n />\n </OverlayShell>\n </SidebarProvider>\n </LayoutProviders>\n );\n};\n\nexport const DefaultLayout = ({ title, appIcon, logo, navigation }: DefaultLayoutProps) => {\n return (\n <DefaultLayoutContent\n title={title}\n appIcon={appIcon}\n logo={logo}\n navigation={navigation}\n />\n );\n};\n"],"names":["getExternalFaviconUrl","url","hostname","NavigationContent","navigation","location","useLocation","i18n","useTranslation","currentLanguage","resolveLocalizedString","value","lang","hasAnyIcons","useMemo","item","navItem","isGroup","renderNavItem","pathPrefix","isOverlay","isExternal","isActive","itemLabel","faviconUrl","iconSrc","iconEl","jsx","cn","content","jsxs","Fragment","ExternalLinkIcon","linkOrTrigger","shellui","Link","SidebarMenuButton","groupTitle","SidebarGroup","SidebarGroupLabel","SidebarGroupContent","SidebarMenu","SidebarMenuItem","SidebarInner","title","logo","startNav","endItems","SidebarHeader","SidebarContent","SidebarFooter","resolveLocalizedLabel","BOTTOM_NAV_SLOT_WIDTH","BOTTOM_NAV_GAP","BOTTOM_NAV_PX","BOTTOM_NAV_MAX_SLOTS","isAppIcon","src","BottomNavItem","label","applyIconTheme","baseClass","className","CaretUpIcon","CaretDownIcon","HomeIcon","MobileBottomNav","items","expanded","setExpanded","useState","navRef","useRef","rowWidth","setRowWidth","useLayoutEffect","el","ro","entries","w","rowItems","overflowItems","hasMore","list","contentWidth","slotTotal","computedSlots","totalSlots","slotsForNav","maxInRow","row","rowPaths","i","overflow","useEffect","renderItem","index","resolveNavLabel","Z_INDEX","e","DefaultLayoutContent","navigationItems","mobileNavItems","desktopNav","filterNavigationByViewport","mobileNav","start","end","splitNavigationByPosition","flat","flattenNavigationItems","mobileFlat","filterNavigationForSidebar","segment","LayoutProviders","SidebarProvider","OverlayShell","Sidebar","Outlet","DefaultLayout","appIcon"],"mappings":"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"}
@@ -2,8 +2,8 @@ import { jsx as t } from "react/jsx-runtime";
2
2
  import { useMemo as l, useEffect as f } from "react";
3
3
  import { useLocation as u, Outlet as p } from "react-router";
4
4
  import { useTranslation as d } from "react-i18next";
5
- import { b as h } from "./index-lmRk5L6z.js";
6
- import { L as g, O as b } from "./OverlayShell-pzbqQW25.js";
5
+ import { b as h } from "./index-PsePV0Ng.js";
6
+ import { L as g, O as b } from "./OverlayShell-CGjN4rTu.js";
7
7
  function L(e, n) {
8
8
  return typeof e == "string" ? e : e[n] || e.en || e.fr || Object.values(e)[0] || "";
9
9
  }
@@ -27,4 +27,4 @@ function w({ title: e, navigation: n }) {
27
27
  export {
28
28
  w as FullscreenLayout
29
29
  };
30
- //# sourceMappingURL=FullscreenLayout-1SgPHWw-.js.map
30
+ //# sourceMappingURL=FullscreenLayout-DiX6dbkf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FullscreenLayout-1SgPHWw-.js","sources":["../src/features/layouts/FullscreenLayout.tsx"],"sourcesContent":["import { useMemo, useEffect } from 'react';\nimport { Outlet, useLocation } from 'react-router';\nimport { useTranslation } from 'react-i18next';\nimport type { NavigationItem, NavigationGroup } from '../config/types';\nimport { flattenNavigationItems } from './utils';\nimport { LayoutProviders } from './LayoutProviders';\nimport { OverlayShell } from './OverlayShell';\n\ninterface FullscreenLayoutProps {\n title?: string;\n navigation: (NavigationItem | NavigationGroup)[];\n}\n\nfunction resolveLocalizedLabel(\n value: string | { en: string; fr: string; [key: string]: string },\n lang: string,\n): string {\n if (typeof value === 'string') return value;\n return value[lang] || value.en || value.fr || Object.values(value)[0] || '';\n}\n\n/** Full-width layout with no sidebar or navigation; only content area. Modal, drawer and providers are still active. */\nexport function FullscreenLayout({ title, navigation }: FullscreenLayoutProps) {\n const location = useLocation();\n const { i18n } = useTranslation();\n const currentLanguage = i18n.language || 'en';\n const navigationItems = useMemo(() => flattenNavigationItems(navigation), [navigation]);\n\n useEffect(() => {\n if (!title) return;\n const pathname = location.pathname.replace(/^\\/+|\\/+$/g, '') || '';\n const segment = pathname.split('/')[0];\n if (!segment) {\n document.title = title;\n return;\n }\n const navItem = navigationItems.find((item) => item.path === segment);\n if (navItem) {\n const label = resolveLocalizedLabel(navItem.label, currentLanguage);\n document.title = `${label} | ${title}`;\n } else {\n document.title = title;\n }\n }, [location.pathname, title, navigationItems, currentLanguage]);\n\n return (\n <LayoutProviders>\n <OverlayShell navigationItems={navigationItems}>\n <main className=\"flex flex-col w-full h-screen overflow-hidden bg-background\">\n <Outlet />\n </main>\n </OverlayShell>\n </LayoutProviders>\n );\n}\n"],"names":["resolveLocalizedLabel","value","lang","FullscreenLayout","title","navigation","location","useLocation","i18n","useTranslation","currentLanguage","navigationItems","useMemo","flattenNavigationItems","useEffect","segment","navItem","item","label","jsx","LayoutProviders","OverlayShell","Outlet"],"mappings":";;;;;;AAaA,SAASA,EACPC,GACAC,GACQ;AACR,SAAI,OAAOD,KAAU,WAAiBA,IAC/BA,EAAMC,CAAI,KAAKD,EAAM,MAAMA,EAAM,MAAM,OAAO,OAAOA,CAAK,EAAE,CAAC,KAAK;AAC3E;AAGO,SAASE,EAAiB,EAAE,OAAAC,GAAO,YAAAC,KAAqC;AAC7E,QAAMC,IAAWC,EAAA,GACX,EAAE,MAAAC,EAAA,IAASC,EAAA,GACXC,IAAkBF,EAAK,YAAY,MACnCG,IAAkBC,EAAQ,MAAMC,EAAuBR,CAAU,GAAG,CAACA,CAAU,CAAC;AAEtF,SAAAS,EAAU,MAAM;AACd,QAAI,CAACV,EAAO;AAEZ,UAAMW,KADWT,EAAS,SAAS,QAAQ,cAAc,EAAE,KAAK,IACvC,MAAM,GAAG,EAAE,CAAC;AACrC,QAAI,CAACS,GAAS;AACZ,eAAS,QAAQX;AACjB;AAAA,IACF;AACA,UAAMY,IAAUL,EAAgB,KAAK,CAACM,MAASA,EAAK,SAASF,CAAO;AACpE,QAAIC,GAAS;AACX,YAAME,IAAQlB,EAAsBgB,EAAQ,OAAON,CAAe;AAClE,eAAS,QAAQ,GAAGQ,CAAK,MAAMd,CAAK;AAAA,IACtC;AACE,eAAS,QAAQA;AAAA,EAErB,GAAG,CAACE,EAAS,UAAUF,GAAOO,GAAiBD,CAAe,CAAC,GAG7D,gBAAAS,EAACC,GAAA,EACC,UAAA,gBAAAD,EAACE,GAAA,EAAa,iBAAAV,GACZ,UAAA,gBAAAQ,EAAC,QAAA,EAAK,WAAU,+DACd,UAAA,gBAAAA,EAACG,GAAA,EAAO,EAAA,CACV,GACF,GACF;AAEJ;"}
1
+ {"version":3,"file":"FullscreenLayout-DiX6dbkf.js","sources":["../src/features/layouts/FullscreenLayout.tsx"],"sourcesContent":["import { useMemo, useEffect } from 'react';\nimport { Outlet, useLocation } from 'react-router';\nimport { useTranslation } from 'react-i18next';\nimport type { NavigationItem, NavigationGroup } from '../config/types';\nimport { flattenNavigationItems } from './utils';\nimport { LayoutProviders } from './LayoutProviders';\nimport { OverlayShell } from './OverlayShell';\n\ninterface FullscreenLayoutProps {\n title?: string;\n navigation: (NavigationItem | NavigationGroup)[];\n}\n\nfunction resolveLocalizedLabel(\n value: string | { en: string; fr: string; [key: string]: string },\n lang: string,\n): string {\n if (typeof value === 'string') return value;\n return value[lang] || value.en || value.fr || Object.values(value)[0] || '';\n}\n\n/** Full-width layout with no sidebar or navigation; only content area. Modal, drawer and providers are still active. */\nexport function FullscreenLayout({ title, navigation }: FullscreenLayoutProps) {\n const location = useLocation();\n const { i18n } = useTranslation();\n const currentLanguage = i18n.language || 'en';\n const navigationItems = useMemo(() => flattenNavigationItems(navigation), [navigation]);\n\n useEffect(() => {\n if (!title) return;\n const pathname = location.pathname.replace(/^\\/+|\\/+$/g, '') || '';\n const segment = pathname.split('/')[0];\n if (!segment) {\n document.title = title;\n return;\n }\n const navItem = navigationItems.find((item) => item.path === segment);\n if (navItem) {\n const label = resolveLocalizedLabel(navItem.label, currentLanguage);\n document.title = `${label} | ${title}`;\n } else {\n document.title = title;\n }\n }, [location.pathname, title, navigationItems, currentLanguage]);\n\n return (\n <LayoutProviders>\n <OverlayShell navigationItems={navigationItems}>\n <main className=\"flex flex-col w-full h-screen overflow-hidden bg-background\">\n <Outlet />\n </main>\n </OverlayShell>\n </LayoutProviders>\n );\n}\n"],"names":["resolveLocalizedLabel","value","lang","FullscreenLayout","title","navigation","location","useLocation","i18n","useTranslation","currentLanguage","navigationItems","useMemo","flattenNavigationItems","useEffect","segment","navItem","item","label","jsx","LayoutProviders","OverlayShell","Outlet"],"mappings":";;;;;;AAaA,SAASA,EACPC,GACAC,GACQ;AACR,SAAI,OAAOD,KAAU,WAAiBA,IAC/BA,EAAMC,CAAI,KAAKD,EAAM,MAAMA,EAAM,MAAM,OAAO,OAAOA,CAAK,EAAE,CAAC,KAAK;AAC3E;AAGO,SAASE,EAAiB,EAAE,OAAAC,GAAO,YAAAC,KAAqC;AAC7E,QAAMC,IAAWC,EAAA,GACX,EAAE,MAAAC,EAAA,IAASC,EAAA,GACXC,IAAkBF,EAAK,YAAY,MACnCG,IAAkBC,EAAQ,MAAMC,EAAuBR,CAAU,GAAG,CAACA,CAAU,CAAC;AAEtF,SAAAS,EAAU,MAAM;AACd,QAAI,CAACV,EAAO;AAEZ,UAAMW,KADWT,EAAS,SAAS,QAAQ,cAAc,EAAE,KAAK,IACvC,MAAM,GAAG,EAAE,CAAC;AACrC,QAAI,CAACS,GAAS;AACZ,eAAS,QAAQX;AACjB;AAAA,IACF;AACA,UAAMY,IAAUL,EAAgB,KAAK,CAACM,MAASA,EAAK,SAASF,CAAO;AACpE,QAAIC,GAAS;AACX,YAAME,IAAQlB,EAAsBgB,EAAQ,OAAON,CAAe;AAClE,eAAS,QAAQ,GAAGQ,CAAK,MAAMd,CAAK;AAAA,IACtC;AACE,eAAS,QAAQA;AAAA,EAErB,GAAG,CAACE,EAAS,UAAUF,GAAOO,GAAiBD,CAAe,CAAC,GAG7D,gBAAAS,EAACC,GAAA,EACC,UAAA,gBAAAD,EAACE,GAAA,EAAa,iBAAAV,GACZ,UAAA,gBAAAQ,EAAC,QAAA,EAAK,WAAU,+DACd,UAAA,gBAAAA,EAACG,GAAA,EAAO,EAAA,CACV,GACF,GACF;AAEJ;"}
@@ -1,6 +1,6 @@
1
1
  import { jsxs as r, jsx as e } from "react/jsx-runtime";
2
2
  import { useTranslation as i } from "react-i18next";
3
- import { u as l } from "./index-lmRk5L6z.js";
3
+ import { u as l } from "./index-PsePV0Ng.js";
4
4
  const c = () => {
5
5
  const { t } = i("common"), { config: o } = l();
6
6
  return /* @__PURE__ */ r("div", { className: "flex flex-col items-center justify-center h-full p-8 md:p-10", children: [
@@ -18,4 +18,4 @@ const c = () => {
18
18
  export {
19
19
  c as HomeView
20
20
  };
21
- //# sourceMappingURL=HomeView-DYU-O_Il.js.map
21
+ //# sourceMappingURL=HomeView-C610YU6V.js.map