@shellui/core 0.0.11 → 0.0.13

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 (172) hide show
  1. package/README.md +0 -11
  2. package/dist/ContentView-CZG-ro_B.js +146 -0
  3. package/dist/ContentView-CZG-ro_B.js.map +1 -0
  4. package/dist/CookiePreferencesView-Bb3hFqw1.js +213 -0
  5. package/dist/CookiePreferencesView-Bb3hFqw1.js.map +1 -0
  6. package/dist/DefaultLayout-D3IpgS4j.js +406 -0
  7. package/dist/DefaultLayout-D3IpgS4j.js.map +1 -0
  8. package/dist/FullscreenLayout-Do9vAfl8.js +30 -0
  9. package/dist/FullscreenLayout-Do9vAfl8.js.map +1 -0
  10. package/dist/HomeView-DwckTuxz.js +21 -0
  11. package/dist/HomeView-DwckTuxz.js.map +1 -0
  12. package/dist/NotFoundView-DD7azhz-.js +52 -0
  13. package/dist/NotFoundView-DD7azhz-.js.map +1 -0
  14. package/dist/OverlayShell-kDY56DaN.js +642 -0
  15. package/dist/OverlayShell-kDY56DaN.js.map +1 -0
  16. package/dist/SettingsView-Bt4I-KDT.js +2207 -0
  17. package/dist/SettingsView-Bt4I-KDT.js.map +1 -0
  18. package/dist/ViewRoute-ChSPabOy.js +32 -0
  19. package/dist/ViewRoute-ChSPabOy.js.map +1 -0
  20. package/dist/WindowsLayout-CEqkRKyk.js +633 -0
  21. package/dist/WindowsLayout-CEqkRKyk.js.map +1 -0
  22. package/dist/app.d.ts +3 -0
  23. package/dist/app.d.ts.map +1 -0
  24. package/dist/components/ContentView.d.ts +10 -0
  25. package/dist/components/ContentView.d.ts.map +1 -0
  26. package/dist/components/HomeView.d.ts +2 -0
  27. package/dist/components/HomeView.d.ts.map +1 -0
  28. package/dist/components/LoadingOverlay.d.ts +2 -0
  29. package/dist/components/LoadingOverlay.d.ts.map +1 -0
  30. package/dist/components/NotFoundView.d.ts +2 -0
  31. package/dist/components/NotFoundView.d.ts.map +1 -0
  32. package/dist/components/RouteErrorBoundary.d.ts +2 -0
  33. package/dist/components/RouteErrorBoundary.d.ts.map +1 -0
  34. package/dist/components/ViewRoute.d.ts +7 -0
  35. package/dist/components/ViewRoute.d.ts.map +1 -0
  36. package/dist/components/ui/alert-dialog.d.ts +32 -0
  37. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  38. package/dist/components/ui/breadcrumb.d.ts +20 -0
  39. package/dist/components/ui/breadcrumb.d.ts.map +1 -0
  40. package/dist/components/ui/button-group.d.ts +7 -0
  41. package/dist/components/ui/button-group.d.ts.map +1 -0
  42. package/dist/components/ui/button.d.ts +12 -0
  43. package/dist/components/ui/button.d.ts.map +1 -0
  44. package/dist/components/ui/dialog.d.ts +24 -0
  45. package/dist/components/ui/dialog.d.ts.map +1 -0
  46. package/dist/components/ui/drawer.d.ts +38 -0
  47. package/dist/components/ui/drawer.d.ts.map +1 -0
  48. package/dist/components/ui/select.d.ts +5 -0
  49. package/dist/components/ui/select.d.ts.map +1 -0
  50. package/dist/components/ui/sidebar.d.ts +46 -0
  51. package/dist/components/ui/sidebar.d.ts.map +1 -0
  52. package/dist/components/ui/sonner.d.ts +6 -0
  53. package/dist/components/ui/sonner.d.ts.map +1 -0
  54. package/dist/components/ui/switch.d.ts +8 -0
  55. package/dist/components/ui/switch.d.ts.map +1 -0
  56. package/dist/constants/urls.d.ts +6 -0
  57. package/dist/constants/urls.d.ts.map +1 -0
  58. package/dist/constants/urls.js +8 -0
  59. package/dist/constants/urls.js.map +1 -0
  60. package/dist/features/alertDialog/DialogContext.d.ts +12 -0
  61. package/dist/features/alertDialog/DialogContext.d.ts.map +1 -0
  62. package/dist/features/config/ConfigProvider.d.ts +15 -0
  63. package/dist/features/config/ConfigProvider.d.ts.map +1 -0
  64. package/dist/features/config/types.d.ts +177 -0
  65. package/dist/features/config/types.d.ts.map +1 -0
  66. package/dist/features/config/useConfig.d.ts +8 -0
  67. package/dist/features/config/useConfig.d.ts.map +1 -0
  68. package/dist/features/cookieConsent/CookieConsentModal.d.ts +6 -0
  69. package/dist/features/cookieConsent/CookieConsentModal.d.ts.map +1 -0
  70. package/dist/features/cookieConsent/CookiePreferencesView.d.ts +2 -0
  71. package/dist/features/cookieConsent/CookiePreferencesView.d.ts.map +1 -0
  72. package/dist/features/cookieConsent/cookieConsent.d.ts +22 -0
  73. package/dist/features/cookieConsent/cookieConsent.d.ts.map +1 -0
  74. package/dist/features/cookieConsent/useCookieConsent.d.ts +15 -0
  75. package/dist/features/cookieConsent/useCookieConsent.d.ts.map +1 -0
  76. package/dist/features/drawer/DrawerContext.d.ts +24 -0
  77. package/dist/features/drawer/DrawerContext.d.ts.map +1 -0
  78. package/dist/features/layouts/AppLayout.d.ts +12 -0
  79. package/dist/features/layouts/AppLayout.d.ts.map +1 -0
  80. package/dist/features/layouts/DefaultLayout.d.ts +10 -0
  81. package/dist/features/layouts/DefaultLayout.d.ts.map +1 -0
  82. package/dist/features/layouts/FullscreenLayout.d.ts +9 -0
  83. package/dist/features/layouts/FullscreenLayout.d.ts.map +1 -0
  84. package/dist/features/layouts/LayoutProviders.d.ts +9 -0
  85. package/dist/features/layouts/LayoutProviders.d.ts.map +1 -0
  86. package/dist/features/layouts/OverlayShell.d.ts +10 -0
  87. package/dist/features/layouts/OverlayShell.d.ts.map +1 -0
  88. package/dist/features/layouts/WindowsLayout.d.ts +24 -0
  89. package/dist/features/layouts/WindowsLayout.d.ts.map +1 -0
  90. package/dist/features/layouts/utils.d.ts +16 -0
  91. package/dist/features/layouts/utils.d.ts.map +1 -0
  92. package/dist/features/modal/ModalContext.d.ts +20 -0
  93. package/dist/features/modal/ModalContext.d.ts.map +1 -0
  94. package/dist/features/sentry/initSentry.d.ts +14 -0
  95. package/dist/features/sentry/initSentry.d.ts.map +1 -0
  96. package/dist/features/settings/SettingsContext.d.ts +10 -0
  97. package/dist/features/settings/SettingsContext.d.ts.map +1 -0
  98. package/dist/features/settings/SettingsIcons.d.ts +22 -0
  99. package/dist/features/settings/SettingsIcons.d.ts.map +1 -0
  100. package/dist/features/settings/SettingsProvider.d.ts +5 -0
  101. package/dist/features/settings/SettingsProvider.d.ts.map +1 -0
  102. package/dist/features/settings/SettingsRoutes.d.ts +7 -0
  103. package/dist/features/settings/SettingsRoutes.d.ts.map +1 -0
  104. package/dist/features/settings/SettingsView.d.ts +2 -0
  105. package/dist/features/settings/SettingsView.d.ts.map +1 -0
  106. package/dist/features/settings/components/Advanced.d.ts +2 -0
  107. package/dist/features/settings/components/Advanced.d.ts.map +1 -0
  108. package/dist/features/settings/components/Appearance.d.ts +2 -0
  109. package/dist/features/settings/components/Appearance.d.ts.map +1 -0
  110. package/dist/features/settings/components/DataPrivacy.d.ts +2 -0
  111. package/dist/features/settings/components/DataPrivacy.d.ts.map +1 -0
  112. package/dist/features/settings/components/Develop.d.ts +2 -0
  113. package/dist/features/settings/components/Develop.d.ts.map +1 -0
  114. package/dist/features/settings/components/LanguageAndRegion.d.ts +2 -0
  115. package/dist/features/settings/components/LanguageAndRegion.d.ts.map +1 -0
  116. package/dist/features/settings/components/ServiceWorker.d.ts +2 -0
  117. package/dist/features/settings/components/ServiceWorker.d.ts.map +1 -0
  118. package/dist/features/settings/components/UpdateApp.d.ts +2 -0
  119. package/dist/features/settings/components/UpdateApp.d.ts.map +1 -0
  120. package/dist/features/settings/components/develop/DialogTestButtons.d.ts +2 -0
  121. package/dist/features/settings/components/develop/DialogTestButtons.d.ts.map +1 -0
  122. package/dist/features/settings/components/develop/DrawerTestButtons.d.ts +2 -0
  123. package/dist/features/settings/components/develop/DrawerTestButtons.d.ts.map +1 -0
  124. package/dist/features/settings/components/develop/ModalTestButtons.d.ts +2 -0
  125. package/dist/features/settings/components/develop/ModalTestButtons.d.ts.map +1 -0
  126. package/dist/features/settings/components/develop/ToastTestButtons.d.ts +2 -0
  127. package/dist/features/settings/components/develop/ToastTestButtons.d.ts.map +1 -0
  128. package/dist/features/settings/hooks/useSettings.d.ts +2 -0
  129. package/dist/features/settings/hooks/useSettings.d.ts.map +1 -0
  130. package/dist/features/sonner/SonnerContext.d.ts +29 -0
  131. package/dist/features/sonner/SonnerContext.d.ts.map +1 -0
  132. package/dist/features/theme/ThemeProvider.d.ts +11 -0
  133. package/dist/features/theme/ThemeProvider.d.ts.map +1 -0
  134. package/dist/features/theme/themes.d.ts +114 -0
  135. package/dist/features/theme/themes.d.ts.map +1 -0
  136. package/dist/features/theme/useTheme.d.ts +10 -0
  137. package/dist/features/theme/useTheme.d.ts.map +1 -0
  138. package/dist/i18n/I18nProvider.d.ts +9 -0
  139. package/dist/i18n/I18nProvider.d.ts.map +1 -0
  140. package/dist/i18n/config.d.ts +23 -0
  141. package/dist/i18n/config.d.ts.map +1 -0
  142. package/dist/i18n/translations/en/common.json.d.ts +19 -0
  143. package/dist/i18n/translations/en/cookieConsent.json.d.ts +53 -0
  144. package/dist/i18n/translations/en/settings.json.d.ts +358 -0
  145. package/dist/i18n/translations/fr/common.json.d.ts +19 -0
  146. package/dist/i18n/translations/fr/cookieConsent.json.d.ts +53 -0
  147. package/dist/i18n/translations/fr/settings.json.d.ts +358 -0
  148. package/dist/index-CfvdAI_Y.js +2168 -0
  149. package/dist/index-CfvdAI_Y.js.map +1 -0
  150. package/dist/index.d.ts +7 -0
  151. package/dist/index.d.ts.map +1 -0
  152. package/dist/index.js +12 -0
  153. package/dist/index.js.map +1 -0
  154. package/dist/lib/utils.d.ts +3 -0
  155. package/dist/lib/utils.d.ts.map +1 -0
  156. package/dist/lib/z-index.d.ts +29 -0
  157. package/dist/lib/z-index.d.ts.map +1 -0
  158. package/dist/router/router.d.ts +3 -0
  159. package/dist/router/router.d.ts.map +1 -0
  160. package/dist/router/routes.d.ts +4 -0
  161. package/dist/router/routes.d.ts.map +1 -0
  162. package/dist/sidebar-Dt-gibIZ.js +336 -0
  163. package/dist/sidebar-Dt-gibIZ.js.map +1 -0
  164. package/dist/style.css +1 -0
  165. package/dist/switch-CuKXfl3x.js +44 -0
  166. package/dist/switch-CuKXfl3x.js.map +1 -0
  167. package/dist/types.js +2 -0
  168. package/dist/types.js.map +1 -0
  169. package/package.json +16 -14
  170. package/src/features/config/ConfigProvider.ts +20 -5
  171. package/src/features/config/useConfig.ts +14 -1
  172. package/src/index.ts +2 -2
package/README.md CHANGED
@@ -12,17 +12,6 @@ npm install @shellui/core
12
12
 
13
13
  This package contains the core React application for ShellUI. It's typically used by `@shellui/cli` and `@shellui/sdk`.
14
14
 
15
- ## Package Structure
16
-
17
- This package exports **source TypeScript files directly** - no build step is required before publishing or using the package. Modern bundlers (like Vite) can process TypeScript files directly.
18
-
19
- - Main entry: `src/index.ts`
20
- - Types: `src/features/config/types.ts`
21
- - Constants: `src/constants/urls.ts`
22
- - Styles: `src/index.css` (imported via `@shellui/core/style.css`)
23
-
24
- The `build` script is optional and only needed if you want to generate `dist` artifacts for compatibility with older tooling.
25
-
26
15
  ## License
27
16
 
28
17
  MIT
@@ -0,0 +1,146 @@
1
+ import { jsx as l, jsxs as W } from "react/jsx-runtime";
2
+ import { addIframe as D, removeIframe as T, shellui as S, getLogger as F } from "@shellui/sdk";
3
+ import { useRef as b, useState as $, useEffect as a } from "react";
4
+ import { useNavigate as _ } from "react-router";
5
+ function k() {
6
+ return /* @__PURE__ */ l("div", { className: "absolute inset-0 z-10 flex flex-col bg-background", children: /* @__PURE__ */ l("div", { className: "h-1 w-full overflow-hidden bg-muted/30", children: /* @__PURE__ */ l(
7
+ "div",
8
+ {
9
+ className: "h-full w-0 bg-muted-foreground/50",
10
+ style: { animation: "loading-bar-slide 400ms linear infinite" }
11
+ }
12
+ ) }) });
13
+ }
14
+ const N = F("shellcore"), M = ({
15
+ url: c,
16
+ pathPrefix: u,
17
+ ignoreMessages: P = !1,
18
+ navItem: p
19
+ }) => {
20
+ const g = _(), n = b(null), h = b(!1), [y] = $(c), [f, m] = $(!0);
21
+ return a(() => {
22
+ if (!n.current)
23
+ return;
24
+ const e = D(n.current);
25
+ return () => {
26
+ T(e);
27
+ };
28
+ }, []), a(() => {
29
+ const e = S.addMessageListener(
30
+ "SHELLUI_URL_CHANGED",
31
+ (r, t) => {
32
+ if (P || t.source !== n.current?.contentWindow)
33
+ return;
34
+ const { pathname: s, search: i, hash: v } = r.payload;
35
+ let o = s.startsWith(p.url) ? s.slice(p.url.length) : s;
36
+ o = o.startsWith("/") ? o.slice(1) : o, o = o.replace(/\/+$/, "");
37
+ let d = o ? `/${u}/${o}${i}${v}` : `/${u}${i}${v}`;
38
+ const w = d.match(/^([^?#]*)([?#].*)?$/);
39
+ if (w) {
40
+ const C = w[1].replace(/\/+$/, "") || "/", x = w[2] || "";
41
+ d = C + x;
42
+ }
43
+ const E = (window.location.pathname.replace(/\/+$/, "") || "/") + window.location.search + window.location.hash, L = d.match(/^([^?#]*)([?#].*)?$/), I = (L?.[1]?.replace(/\/+$/, "") || "/") + (L?.[2] || "");
44
+ E !== I && (h.current = !0, g(d, { replace: !0 }), setTimeout(() => {
45
+ h.current = !1;
46
+ }, 100));
47
+ }
48
+ );
49
+ return () => {
50
+ e();
51
+ };
52
+ }, [u, g]), a(() => {
53
+ const e = S.addMessageListener(
54
+ "SHELLUI_INITIALIZED",
55
+ (r, t) => {
56
+ t.source === n.current?.contentWindow && m(!1);
57
+ }
58
+ );
59
+ return () => e();
60
+ }, []), a(() => {
61
+ if (!f) return;
62
+ const e = setTimeout(() => {
63
+ N.info("ContentView: Timeout expired, hiding loading overlay"), m(!1);
64
+ }, 400);
65
+ return () => clearTimeout(e);
66
+ }, [f]), a(() => {
67
+ n.current && !h.current && n.current.src !== c && (n.current.src = c, m(!0));
68
+ }, [c]), a(() => {
69
+ const e = n.current;
70
+ if (!e) return;
71
+ const r = () => {
72
+ try {
73
+ const t = e.contentWindow, s = e.contentDocument || t?.document;
74
+ if (!s || !t) return;
75
+ const i = s.createElement("script");
76
+ i.textContent = `
77
+ (function() {
78
+ // Wait for all stylesheets to load
79
+ function waitForStylesheets() {
80
+ const styleSheets = Array.from(document.styleSheets);
81
+ const pendingSheets = styleSheets.filter(function(sheet) {
82
+ try {
83
+ return sheet.cssRules === null;
84
+ } catch (e) {
85
+ return false; // Cross-origin stylesheets, assume loaded
86
+ }
87
+ });
88
+
89
+ if (pendingSheets.length === 0) {
90
+ // All stylesheets loaded
91
+ return;
92
+ }
93
+
94
+ // Check again after a short delay
95
+ setTimeout(waitForStylesheets, 10);
96
+ }
97
+
98
+ // Start checking after DOM is ready
99
+ if (document.readyState === 'complete') {
100
+ waitForStylesheets();
101
+ } else {
102
+ window.addEventListener('load', waitForStylesheets);
103
+ }
104
+ })();
105
+ `, s.head.appendChild(i);
106
+ } catch (t) {
107
+ N.debug("Could not inject stylesheet wait script:", { error: t });
108
+ }
109
+ };
110
+ return e.addEventListener("load", r), e.contentDocument?.readyState === "complete" && r(), () => {
111
+ e.removeEventListener("load", r);
112
+ };
113
+ }, [y]), a(() => {
114
+ if (process.env.NODE_ENV === "development") {
115
+ const e = console.warn;
116
+ return console.warn = (...r) => {
117
+ const t = String(r[0] ?? "");
118
+ t.includes("allow-scripts") && t.includes("allow-same-origin") && t.includes("sandbox") || t.includes("Layout was forced") && t.includes("before the page was fully loaded") || e.apply(console, r);
119
+ }, () => {
120
+ console.warn = e;
121
+ };
122
+ }
123
+ }, []), /* @__PURE__ */ W("div", { style: { width: "100%", height: "100%", display: "flex", position: "relative" }, children: [
124
+ /* @__PURE__ */ l(
125
+ "iframe",
126
+ {
127
+ ref: n,
128
+ src: y,
129
+ style: {
130
+ width: "100%",
131
+ height: "100%",
132
+ border: "none",
133
+ display: "block"
134
+ },
135
+ title: "Content Frame",
136
+ sandbox: "allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox",
137
+ referrerPolicy: "no-referrer-when-downgrade"
138
+ }
139
+ ),
140
+ f && /* @__PURE__ */ l(k, {})
141
+ ] });
142
+ };
143
+ export {
144
+ M as C
145
+ };
146
+ //# sourceMappingURL=ContentView-CZG-ro_B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContentView-CZG-ro_B.js","sources":["../src/components/LoadingOverlay.tsx","../src/components/ContentView.tsx"],"sourcesContent":["export function LoadingOverlay() {\n return (\n <div className=\"absolute inset-0 z-10 flex flex-col bg-background\">\n <div className=\"h-1 w-full overflow-hidden bg-muted/30\">\n <div\n className=\"h-full w-0 bg-muted-foreground/50\"\n style={{ animation: 'loading-bar-slide 400ms linear infinite' }}\n />\n </div>\n </div>\n );\n}\n","/* eslint-disable no-console */\nimport type { NavigationItem } from '@/features/config/types';\nimport {\n addIframe,\n removeIframe,\n shellui,\n getLogger,\n type ShellUIUrlPayload,\n type ShellUIMessage,\n} from '@shellui/sdk';\nimport { useEffect, useRef, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { LoadingOverlay } from './LoadingOverlay';\n\nconst logger = getLogger('shellcore');\n\ninterface ContentViewProps {\n url: string;\n pathPrefix: string;\n ignoreMessages?: boolean;\n navItem: NavigationItem;\n}\n\nexport const ContentView = ({\n url,\n pathPrefix,\n ignoreMessages = false,\n navItem,\n}: ContentViewProps) => {\n const navigate = useNavigate();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const isInternalNavigation = useRef(false);\n const [initialUrl] = useState(url);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n if (!iframeRef.current) {\n return;\n }\n const iframeId = addIframe(iframeRef.current);\n return () => {\n removeIframe(iframeId);\n };\n }, []);\n\n // Sync parent URL when iframe notifies us of a change\n useEffect(() => {\n const cleanup = shellui.addMessageListener(\n 'SHELLUI_URL_CHANGED',\n (data: ShellUIMessage, event: MessageEvent) => {\n if (ignoreMessages) {\n return;\n }\n\n // Ignore URL CHANGE from other than ContentView iframe\n if (event.source !== iframeRef.current?.contentWindow) {\n return;\n }\n\n const { pathname, search, hash } = data.payload as ShellUIUrlPayload;\n // Remove leading slash and trailing slashes from iframe pathname\n let cleanPathname = pathname.startsWith(navItem.url)\n ? pathname.slice(navItem.url.length)\n : pathname;\n cleanPathname = cleanPathname.startsWith('/') ? cleanPathname.slice(1) : cleanPathname;\n cleanPathname = cleanPathname.replace(/\\/+$/, ''); // Remove trailing slashes\n // Construct the new path without trailing slashes\n let newShellPath = cleanPathname\n ? `/${pathPrefix}/${cleanPathname}${search}${hash}`\n : `/${pathPrefix}${search}${hash}`;\n\n // Normalize: remove trailing slashes from pathname part only (preserve query/hash)\n const urlParts = newShellPath.match(/^([^?#]*)([?#].*)?$/);\n if (urlParts) {\n const pathnamePart = urlParts[1].replace(/\\/+$/, '') || '/';\n const queryHashPart = urlParts[2] || '';\n newShellPath = pathnamePart + queryHashPart;\n }\n\n // Normalize current path for comparison (remove trailing slashes from pathname)\n const currentPathname = window.location.pathname.replace(/\\/+$/, '') || '/';\n const currentPath = currentPathname + window.location.search + window.location.hash;\n\n // Normalize new path for comparison\n const newPathParts = newShellPath.match(/^([^?#]*)([?#].*)?$/);\n const normalizedNewPathname = newPathParts?.[1]?.replace(/\\/+$/, '') || '/';\n const normalizedNewPath = normalizedNewPathname + (newPathParts?.[2] || '');\n\n if (currentPath !== normalizedNewPath) {\n // Mark this navigation as internal so we don't try to \"push\" it back to the iframe\n isInternalNavigation.current = true;\n navigate(newShellPath, { replace: true });\n\n // Reset the flag after a short delay to allow the render cycle to complete\n setTimeout(() => {\n isInternalNavigation.current = false;\n }, 100);\n }\n },\n );\n\n return () => {\n cleanup();\n };\n }, [pathPrefix, navigate]);\n\n // Hide loading overlay when iframe sends SHELLUI_INITIALIZED\n useEffect(() => {\n const cleanup = shellui.addMessageListener(\n 'SHELLUI_INITIALIZED',\n (_data: ShellUIMessage, event: MessageEvent) => {\n if (event.source === iframeRef.current?.contentWindow) {\n setIsLoading(false);\n }\n },\n );\n return () => cleanup();\n }, []);\n\n // Fallback: hide overlay after 400ms if SHELLUI_INITIALIZED was not received\n useEffect(() => {\n if (!isLoading) return;\n const timeoutId = setTimeout(() => {\n logger.info('ContentView: Timeout expired, hiding loading overlay');\n setIsLoading(false);\n }, 400);\n return () => clearTimeout(timeoutId);\n }, [isLoading]);\n\n // Handle external URL changes (e.g. from Sidebar)\n useEffect(() => {\n if (iframeRef.current && !isInternalNavigation.current) {\n // Only update iframe src if it's actually different from its current src\n // to avoid unnecessary reloads\n if (iframeRef.current.src !== url) {\n iframeRef.current.src = url;\n setIsLoading(true);\n }\n }\n }, [url]);\n\n // Inject script to prevent \"Layout was forced\" warning by deferring layout until stylesheets load\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return;\n\n const handleLoad = () => {\n try {\n const iframeWindow = iframe.contentWindow;\n const iframeDoc = iframe.contentDocument || iframeWindow?.document;\n if (!iframeDoc || !iframeWindow) return;\n\n // Inject a script that waits for stylesheets before allowing layout calculations\n const script = iframeDoc.createElement('script');\n script.textContent = `\n (function() {\n // Wait for all stylesheets to load\n function waitForStylesheets() {\n const styleSheets = Array.from(document.styleSheets);\n const pendingSheets = styleSheets.filter(function(sheet) {\n try {\n return sheet.cssRules === null;\n } catch (e) {\n return false; // Cross-origin stylesheets, assume loaded\n }\n });\n \n if (pendingSheets.length === 0) {\n // All stylesheets loaded\n return;\n }\n \n // Check again after a short delay\n setTimeout(waitForStylesheets, 10);\n }\n \n // Start checking after DOM is ready\n if (document.readyState === 'complete') {\n waitForStylesheets();\n } else {\n window.addEventListener('load', waitForStylesheets);\n }\n })();\n `;\n iframeDoc.head.appendChild(script);\n } catch (error) {\n // Cross-origin or other errors - ignore (this is expected for some iframes)\n logger.debug('Could not inject stylesheet wait script:', { error });\n }\n };\n\n // Wait for iframe to load before injecting script\n iframe.addEventListener('load', handleLoad);\n\n // Also try immediately if already loaded\n if (iframe.contentDocument?.readyState === 'complete') {\n handleLoad();\n }\n\n return () => {\n iframe.removeEventListener('load', handleLoad);\n };\n }, [initialUrl]);\n\n // Suppress browser warnings that are expected and acceptable\n useEffect(() => {\n if (process.env.NODE_ENV === 'development') {\n const originalWarn = console.warn;\n console.warn = (...args: unknown[]) => {\n const message = String(args[0] ?? '');\n // Suppress the specific sandbox warning\n if (\n message.includes('allow-scripts') &&\n message.includes('allow-same-origin') &&\n message.includes('sandbox')\n ) {\n return;\n }\n // Suppress \"Layout was forced\" warning from iframe content\n // This is a performance warning that occurs when iframe content calculates layout before stylesheets load\n // It's harmless and common in iframe scenarios, especially with React apps\n if (\n message.includes('Layout was forced') &&\n message.includes('before the page was fully loaded')\n ) {\n return;\n }\n originalWarn.apply(console, args);\n };\n return () => {\n console.warn = originalWarn;\n };\n }\n }, []);\n\n return (\n <div style={{ width: '100%', height: '100%', display: 'flex', position: 'relative' }}>\n {/* Note: allow-same-origin is required for same-origin iframe content (e.g., Vite dev server, cookies, localStorage).\n While this allows the iframe to remove its own sandboxing, it's acceptable here because the iframe content\n is trusted microfrontend content from the same application origin.\n Browser security warnings about this combination cannot be suppressed programmatically. */}\n <iframe\n ref={iframeRef}\n src={initialUrl}\n style={{\n width: '100%',\n height: '100%',\n border: 'none',\n display: 'block',\n }}\n title=\"Content Frame\"\n sandbox=\"allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox\"\n referrerPolicy=\"no-referrer-when-downgrade\"\n />\n {isLoading && <LoadingOverlay />}\n </div>\n );\n};\n"],"names":["LoadingOverlay","jsx","logger","getLogger","ContentView","url","pathPrefix","ignoreMessages","navItem","navigate","useNavigate","iframeRef","useRef","isInternalNavigation","initialUrl","useState","isLoading","setIsLoading","useEffect","iframeId","addIframe","removeIframe","cleanup","shellui","data","event","pathname","search","hash","cleanPathname","newShellPath","urlParts","pathnamePart","queryHashPart","currentPath","newPathParts","normalizedNewPath","_data","timeoutId","iframe","handleLoad","iframeWindow","iframeDoc","script","error","originalWarn","args","message","jsxs"],"mappings":"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"}
@@ -0,0 +1,213 @@
1
+ import { jsx as n, jsxs as l } from "react/jsx-runtime";
2
+ import { useMemo as b, useState as B, useRef as T, useEffect as H, useCallback as g } from "react";
3
+ import { useTranslation as $ } from "react-i18next";
4
+ import { useLocation as F } from "react-router";
5
+ import { shellui as y } from "@shellui/sdk";
6
+ import { u as I, a as U, r as G, B as S } from "./index-CfvdAI_Y.js";
7
+ import { S as w } from "./switch-CuKXfl3x.js";
8
+ const V = [
9
+ "strict_necessary",
10
+ "functional_performance",
11
+ "targeting",
12
+ "social_media_embedded"
13
+ ];
14
+ function W(t, f) {
15
+ return t < 60 ? f("preferences.duration.seconds", { count: t }) : t < 3600 ? f("preferences.duration.minutes", { count: Math.floor(t / 60) }) : t < 86400 ? f("preferences.duration.hours", { count: Math.floor(t / 3600) }) : t < 31536e3 ? f("preferences.duration.days", { count: Math.floor(t / 86400) }) : f("preferences.duration.years", { count: Math.floor(t / 31536e3) });
16
+ }
17
+ function te() {
18
+ const { t, i18n: f } = $("cookieConsent"), { config: A } = I(), { settings: x, updateSetting: d } = U(), L = F(), m = new URLSearchParams(L.search).get("initial") === "true", _ = f.language || "en", p = A?.cookieConsent?.cookies ?? [], a = b(() => p.map((e) => e.host), [p]), i = b(
19
+ () => p.filter((e) => e.category === "strict_necessary").map((e) => e.host),
20
+ [p]
21
+ ), h = x?.cookieConsent?.acceptedHosts ?? [], [u, k] = B(() => [
22
+ .../* @__PURE__ */ new Set([...h, ...i])
23
+ ]), C = T(!1);
24
+ H(() => {
25
+ m && k([.../* @__PURE__ */ new Set([...h, ...i])]);
26
+ }, [m, h, i]), H(() => {
27
+ if (!m) return;
28
+ const e = () => {
29
+ (x?.cookieConsent?.consentedCookieHosts ?? []).length === 0 && !C.current && d("cookieConsent", {
30
+ acceptedHosts: i,
31
+ consentedCookieHosts: a
32
+ });
33
+ };
34
+ return y.addMessageListener("SHELLUI_CLOSE_DRAWER", e);
35
+ }, [m, i, a, d, x]), H(() => () => {
36
+ m && !C.current && (x?.cookieConsent?.consentedCookieHosts ?? []).length === 0 && d("cookieConsent", {
37
+ acceptedHosts: i,
38
+ consentedCookieHosts: a
39
+ });
40
+ }, [m, i, a, d, x]);
41
+ const N = b(() => {
42
+ const e = /* @__PURE__ */ new Map();
43
+ for (const s of p) {
44
+ const r = e.get(s.category) ?? [];
45
+ e.set(s.category, [...r, s]);
46
+ }
47
+ return e;
48
+ }, [p]), R = g((e, s) => {
49
+ k((r) => s ? [...r, e] : r.filter((o) => o !== e));
50
+ }, []), j = g(
51
+ (e, s) => {
52
+ const r = N.get(e)?.map((o) => o.host) ?? [];
53
+ k((o) => {
54
+ if (s)
55
+ return [.../* @__PURE__ */ new Set([...o, ...r])];
56
+ {
57
+ const c = new Set(r);
58
+ return o.filter((v) => !c.has(v));
59
+ }
60
+ });
61
+ },
62
+ [N]
63
+ ), D = g(
64
+ (e) => {
65
+ const s = N.get(e)?.map((o) => o.host) ?? [];
66
+ if (s.length === 0) return "none";
67
+ const r = s.filter((o) => u.includes(o)).length;
68
+ return r === s.length ? "all" : r > 0 ? "some" : "none";
69
+ },
70
+ [N, u]
71
+ ), E = g(() => {
72
+ C.current = !0, d("cookieConsent", {
73
+ acceptedHosts: a,
74
+ consentedCookieHosts: a
75
+ }), y.closeDrawer();
76
+ }, [a, d]), M = g(() => {
77
+ C.current = !0, d("cookieConsent", {
78
+ acceptedHosts: i,
79
+ consentedCookieHosts: a
80
+ }), y.closeDrawer();
81
+ }, [i, a, d]), z = g(() => {
82
+ C.current = !0;
83
+ const e = [.../* @__PURE__ */ new Set([...u, ...i])];
84
+ d("cookieConsent", {
85
+ acceptedHosts: e,
86
+ consentedCookieHosts: a
87
+ }), y.closeDrawer();
88
+ }, [u, i, a, d]), O = b(() => {
89
+ if (u.length !== h.length) return !0;
90
+ const e = [...u].sort(), s = [...h].sort();
91
+ return e.some((r, o) => r !== s[o]);
92
+ }, [u, h]);
93
+ return p.length === 0 ? /* @__PURE__ */ n("div", { className: "flex items-center justify-center h-full p-6", children: /* @__PURE__ */ n("p", { className: "text-muted-foreground", children: t("preferences.noCookies") }) }) : /* @__PURE__ */ l("div", { className: "flex flex-col h-full bg-background", children: [
94
+ /* @__PURE__ */ l("div", { className: "flex flex-col space-y-2 border-b border-border/60 px-6 pt-5 pb-4", children: [
95
+ /* @__PURE__ */ n(
96
+ "h2",
97
+ {
98
+ className: "text-lg font-semibold leading-none tracking-tight",
99
+ style: { fontFamily: "var(--heading-font-family, inherit)" },
100
+ children: t("preferences.title")
101
+ }
102
+ ),
103
+ /* @__PURE__ */ n("p", { className: "text-sm text-muted-foreground", children: t("preferences.description") })
104
+ ] }),
105
+ /* @__PURE__ */ n("div", { className: "flex-1 overflow-y-auto px-6 py-4", children: V.map((e) => {
106
+ const s = N.get(e);
107
+ if (!s || s.length === 0) return null;
108
+ const r = D(e), o = e === "strict_necessary";
109
+ return /* @__PURE__ */ l(
110
+ "div",
111
+ {
112
+ className: "mb-6 last:mb-0",
113
+ children: [
114
+ /* @__PURE__ */ l("div", { className: "flex items-center justify-between mb-3", children: [
115
+ /* @__PURE__ */ l("div", { className: "flex-1 min-w-0", children: [
116
+ /* @__PURE__ */ n(
117
+ "h3",
118
+ {
119
+ className: "text-sm font-semibold",
120
+ style: { fontFamily: "var(--heading-font-family, inherit)" },
121
+ children: t(`preferences.categories.${e}.title`)
122
+ }
123
+ ),
124
+ /* @__PURE__ */ n("p", { className: "text-xs text-muted-foreground mt-0.5", children: t(`preferences.categories.${e}.description`) })
125
+ ] }),
126
+ /* @__PURE__ */ l("div", { className: "ml-4 flex items-center gap-2", children: [
127
+ !o && r === "some" && /* @__PURE__ */ n("span", { className: "text-xs text-muted-foreground", children: t("preferences.partial") }),
128
+ o ? /* @__PURE__ */ n("span", { className: "text-xs text-muted-foreground", children: t("preferences.alwaysOn") }) : /* @__PURE__ */ n(
129
+ w,
130
+ {
131
+ checked: r === "all",
132
+ onCheckedChange: (c) => j(e, c),
133
+ "aria-label": t(`preferences.categories.${e}.title`)
134
+ }
135
+ )
136
+ ] })
137
+ ] }),
138
+ !o && /* @__PURE__ */ n("div", { className: "space-y-2 pl-2 border-l-2 border-border ml-1", children: s.map((c) => {
139
+ const v = u.includes(c.host);
140
+ return /* @__PURE__ */ l(
141
+ "div",
142
+ {
143
+ className: "flex items-start justify-between gap-3 py-2 px-3 rounded-md bg-muted/30",
144
+ children: [
145
+ /* @__PURE__ */ l("div", { className: "flex-1 min-w-0", children: [
146
+ /* @__PURE__ */ n("span", { className: "text-sm font-medium truncate", children: c.name }),
147
+ c.description && /* @__PURE__ */ n("p", { className: "text-xs text-muted-foreground mt-0.5 line-clamp-2", children: G(c.description, _) }),
148
+ /* @__PURE__ */ l("div", { className: "flex items-center gap-3 mt-1 text-[10px] text-muted-foreground/70", children: [
149
+ /* @__PURE__ */ n("span", { children: c.host }),
150
+ /* @__PURE__ */ n("span", { children: "•" }),
151
+ /* @__PURE__ */ n("span", { children: W(c.durationSeconds, t) }),
152
+ /* @__PURE__ */ n("span", { children: "•" }),
153
+ /* @__PURE__ */ n("span", { className: "capitalize", children: c.type.replace("_", " ") })
154
+ ] })
155
+ ] }),
156
+ /* @__PURE__ */ n(
157
+ w,
158
+ {
159
+ checked: v,
160
+ onCheckedChange: (P) => R(c.host, P),
161
+ "aria-label": c.name
162
+ }
163
+ )
164
+ ]
165
+ },
166
+ c.host
167
+ );
168
+ }) })
169
+ ]
170
+ },
171
+ e
172
+ );
173
+ }) }),
174
+ /* @__PURE__ */ l("div", { className: "mt-auto flex flex-col gap-2 border-t border-border px-6 py-4", children: [
175
+ /* @__PURE__ */ l("div", { className: "flex gap-2", children: [
176
+ /* @__PURE__ */ n(
177
+ S,
178
+ {
179
+ variant: "outline",
180
+ size: "sm",
181
+ onClick: M,
182
+ className: "flex-1",
183
+ children: t("preferences.rejectAll")
184
+ }
185
+ ),
186
+ /* @__PURE__ */ n(
187
+ S,
188
+ {
189
+ variant: "outline",
190
+ size: "sm",
191
+ onClick: E,
192
+ className: "flex-1",
193
+ children: t("preferences.acceptAll")
194
+ }
195
+ )
196
+ ] }),
197
+ /* @__PURE__ */ n(
198
+ S,
199
+ {
200
+ size: "sm",
201
+ onClick: z,
202
+ disabled: !O && !m,
203
+ className: "w-full",
204
+ children: t("preferences.save")
205
+ }
206
+ )
207
+ ] })
208
+ ] });
209
+ }
210
+ export {
211
+ te as CookiePreferencesView
212
+ };
213
+ //# sourceMappingURL=CookiePreferencesView-Bb3hFqw1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CookiePreferencesView-Bb3hFqw1.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":";;;;;;;AAYA,MAAMA,IAA0C;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,SAASC,EACPC,GACAC,GACQ;AACR,SAAID,IAAU,KAAWC,EAAE,gCAAgC,EAAE,OAAOD,GAAS,IACzEA,IAAU,OAAaC,EAAE,gCAAgC,EAAE,OAAO,KAAK,MAAMD,IAAU,EAAE,EAAA,CAAG,IAC5FA,IAAU,QACLC,EAAE,8BAA8B,EAAE,OAAO,KAAK,MAAMD,IAAU,IAAI,GAAG,IAC1EA,IAAU,UACLC,EAAE,6BAA6B,EAAE,OAAO,KAAK,MAAMD,IAAU,KAAK,GAAG,IACvEC,EAAE,8BAA8B,EAAE,OAAO,KAAK,MAAMD,IAAU,OAAQ,GAAG;AAClF;AAEO,SAASE,KAAwB;AACtC,QAAM,EAAE,GAAG,MAAAC,MAASC,EAAe,eAAe,GAC5C,EAAE,QAAAC,EAAA,IAAWC,EAAA,GACb,EAAE,UAAAC,GAAU,eAAAC,EAAA,IAAkBC,EAAA,GAC9BC,IAAWC,EAAA,GAEXC,IADe,IAAI,gBAAgBF,EAAS,MAAM,EAClB,IAAI,SAAS,MAAM,QACnDG,IAAkBV,EAAK,YAAY,MAEnCW,IAAUT,GAAQ,eAAe,WAAW,CAAA,GAC5CU,IAAWC,EAAQ,MAAMF,EAAQ,IAAI,CAACG,MAAMA,EAAE,IAAI,GAAG,CAACH,CAAO,CAAC,GAG9DI,IAAuBF;AAAA,IAC3B,MAAMF,EAAQ,OAAO,CAACG,MAAMA,EAAE,aAAa,kBAAkB,EAAE,IAAI,CAACA,MAAMA,EAAE,IAAI;AAAA,IAChF,CAACH,CAAO;AAAA,EAAA,GAGJK,IAAuBZ,GAAU,eAAe,iBAAiB,CAAA,GAGjE,CAACa,GAAoBC,CAAqB,IAAIC,EAAmB,MAAM;AAAA,IAC3E,uBAAO,IAAI,CAAC,GAAGH,GAAsB,GAAGD,CAAoB,CAAC;AAAA,EAAA,CAC9D,GAGKK,IAAmBC,EAAO,EAAK;AAGrC,EAAAC,EAAU,MAAM;AACd,IAAIb,KAEFS,EAAsB,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAGF,GAAsB,GAAGD,CAAoB,CAAC,CAAC,CAAC;AAAA,EAE1F,GAAG,CAACN,GAAkBO,GAAsBD,CAAoB,CAAC,GAGjEO,EAAU,MAAM;AACd,QAAI,CAACb,EAAkB;AAEvB,UAAMc,IAAoB,MAAM;AAI9B,OADwBnB,GAAU,eAAe,wBAAwB,CAAA,GAAI,WAAW,KAClE,CAACgB,EAAiB,WACtCf,EAAc,iBAAiB;AAAA,QAC7B,eAAeU;AAAA,QACf,sBAAsBH;AAAA,MAAA,CACvB;AAAA,IAEL;AAGA,WADgBY,EAAQ,mBAAmB,wBAAwBD,CAAiB;AAAA,EAEtF,GAAG,CAACd,GAAkBM,GAAsBH,GAAUP,GAAeD,CAAQ,CAAC,GAG9EkB,EAAU,MACD,MAAM;AACX,IAAIb,KAAoB,CAACW,EAAiB,YAEhBhB,GAAU,eAAe,wBAAwB,CAAA,GAAI,WAAW,KAEtFC,EAAc,iBAAiB;AAAA,MAC7B,eAAeU;AAAA,MACf,sBAAsBH;AAAA,IAAA,CACvB;AAAA,EAGP,GACC,CAACH,GAAkBM,GAAsBH,GAAUP,GAAeD,CAAQ,CAAC;AAG9E,QAAMqB,IAAoBZ,EAAQ,MAAM;AACtC,UAAMa,wBAAc,IAAA;AACpB,eAAWC,KAAUhB,GAAS;AAC5B,YAAMiB,IAAWF,EAAQ,IAAIC,EAAO,QAAQ,KAAK,CAAA;AACjD,MAAAD,EAAQ,IAAIC,EAAO,UAAU,CAAC,GAAGC,GAAUD,CAAM,CAAC;AAAA,IACpD;AACA,WAAOD;AAAA,EACT,GAAG,CAACf,CAAO,CAAC,GAGNkB,IAAeC,EAAY,CAACC,GAAcC,MAAqB;AACnE,IAAAd,EAAsB,CAACe,MAAUD,IAAU,CAAC,GAAGC,GAAMF,CAAI,IAAIE,EAAK,OAAO,CAACC,MAAMA,MAAMH,CAAI,CAAE;AAAA,EAC9F,GAAG,CAAA,CAAE,GAGCI,IAAiBL;AAAA,IACrB,CAACM,GAAiCJ,MAAqB;AACrD,YAAMK,IAAgBZ,EAAkB,IAAIW,CAAQ,GAAG,IAAI,CAACtB,MAAMA,EAAE,IAAI,KAAK,CAAA;AAC7E,MAAAI,EAAsB,CAACe,MAAS;AAC9B,YAAID;AACF,iBAAO,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAGC,GAAM,GAAGI,CAAa,CAAC,CAAC;AAC1C;AACL,gBAAMC,IAAW,IAAI,IAAID,CAAa;AACtC,iBAAOJ,EAAK,OAAO,CAACC,MAAM,CAACI,EAAS,IAAIJ,CAAC,CAAC;AAAA,QAC5C;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAACT,CAAiB;AAAA,EAAA,GAIdc,IAAmBT;AAAA,IACvB,CAACM,MAA6D;AAC5D,YAAMC,IAAgBZ,EAAkB,IAAIW,CAAQ,GAAG,IAAI,CAACtB,MAAMA,EAAE,IAAI,KAAK,CAAA;AAC7E,UAAIuB,EAAc,WAAW,EAAG,QAAO;AACvC,YAAMG,IAAeH,EAAc,OAAO,CAACH,MAAMjB,EAAmB,SAASiB,CAAC,CAAC,EAAE;AACjF,aAAIM,MAAiBH,EAAc,SAAe,QAC9CG,IAAe,IAAU,SACtB;AAAA,IACT;AAAA,IACA,CAACf,GAAmBR,CAAkB;AAAA,EAAA,GAIlCwB,IAAkBX,EAAY,MAAM;AACxC,IAAAV,EAAiB,UAAU,IAC3Bf,EAAc,iBAAiB;AAAA,MAC7B,eAAeO;AAAA,MACf,sBAAsBA;AAAA,IAAA,CACvB,GACDY,EAAQ,YAAA;AAAA,EACV,GAAG,CAACZ,GAAUP,CAAa,CAAC,GAGtBqC,IAAkBZ,EAAY,MAAM;AACxC,IAAAV,EAAiB,UAAU,IAC3Bf,EAAc,iBAAiB;AAAA,MAC7B,eAAeU;AAAA,MACf,sBAAsBH;AAAA,IAAA,CACvB,GACDY,EAAQ,YAAA;AAAA,EACV,GAAG,CAACT,GAAsBH,GAAUP,CAAa,CAAC,GAG5CsC,IAAab,EAAY,MAAM;AACnC,IAAAV,EAAiB,UAAU;AAC3B,UAAMwB,IAAc,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG3B,GAAoB,GAAGF,CAAoB,CAAC,CAAC;AACjF,IAAAV,EAAc,iBAAiB;AAAA,MAC7B,eAAeuC;AAAA,MACf,sBAAsBhC;AAAA,IAAA,CACvB,GACDY,EAAQ,YAAA;AAAA,EACV,GAAG,CAACP,GAAoBF,GAAsBH,GAAUP,CAAa,CAAC,GAGhEwC,IAAahC,EAAQ,MAAM;AAC/B,QAAII,EAAmB,WAAWD,EAAqB,OAAQ,QAAO;AACtE,UAAM8B,IAAc,CAAC,GAAG7B,CAAkB,EAAE,KAAA,GACtC8B,IAAgB,CAAC,GAAG/B,CAAoB,EAAE,KAAA;AAChD,WAAO8B,EAAY,KAAK,CAACZ,GAAGc,MAAMd,MAAMa,EAAcC,CAAC,CAAC;AAAA,EAC1D,GAAG,CAAC/B,GAAoBD,CAAoB,CAAC;AAE7C,SAAIL,EAAQ,WAAW,IAEnB,gBAAAsC,EAAC,OAAA,EAAI,WAAU,+CACb,UAAA,gBAAAA,EAAC,KAAA,EAAE,WAAU,yBAAyB,UAAA,EAAE,uBAAuB,EAAA,CAAE,GACnE,IAKF,gBAAAC,EAAC,OAAA,EAAI,WAAU,sCAEb,UAAA;AAAA,IAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,oEACb,UAAA;AAAA,MAAA,gBAAAD;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,YAAY,sCAAA;AAAA,UAEpB,YAAE,mBAAmB;AAAA,QAAA;AAAA,MAAA;AAAA,wBAEvB,KAAA,EAAE,WAAU,iCAAiC,UAAA,EAAE,yBAAyB,EAAA,CAAE;AAAA,IAAA,GAC7E;AAAA,sBAGC,OAAA,EAAI,WAAU,oCACZ,UAAAtD,EAAe,IAAI,CAACyC,MAAa;AAChC,YAAMe,IAAkB1B,EAAkB,IAAIW,CAAQ;AACtD,UAAI,CAACe,KAAmBA,EAAgB,WAAW,EAAG,QAAO;AAE7D,YAAMC,IAAgBb,EAAiBH,CAAQ,GACzCiB,IAAoBjB,MAAa;AAEvC,aACE,gBAAAc;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,WAAU;AAAA,UAGV,UAAA;AAAA,YAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,0CACb,UAAA;AAAA,cAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,kBACb,UAAA;AAAA,gBAAA,gBAAAD;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO,EAAE,YAAY,sCAAA;AAAA,oBAEpB,UAAA,EAAE,0BAA0Bb,CAAQ,QAAQ;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAE/C,gBAAAa,EAAC,OAAE,WAAU,wCACV,YAAE,0BAA0Bb,CAAQ,cAAc,EAAA,CACrD;AAAA,cAAA,GACF;AAAA,cACA,gBAAAc,EAAC,OAAA,EAAI,WAAU,gCACZ,UAAA;AAAA,gBAAA,CAACG,KAAqBD,MAAkB,UACvC,gBAAAH,EAAC,UAAK,WAAU,iCACb,UAAA,EAAE,qBAAqB,EAAA,CAC1B;AAAA,gBAEDI,sBACE,QAAA,EAAK,WAAU,iCACb,UAAA,EAAE,sBAAsB,GAC3B,IAEA,gBAAAJ;AAAA,kBAACK;AAAA,kBAAA;AAAA,oBACC,SAASF,MAAkB;AAAA,oBAC3B,iBAAiB,CAACG,MAAYpB,EAAeC,GAAUmB,CAAO;AAAA,oBAC9D,cAAY,EAAE,0BAA0BnB,CAAQ,QAAQ;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAC1D,EAAA,CAEJ;AAAA,YAAA,GACF;AAAA,YAGC,CAACiB,KACA,gBAAAJ,EAAC,OAAA,EAAI,WAAU,gDACZ,UAAAE,EAAgB,IAAI,CAACxB,MAAW;AAC/B,oBAAM6B,IAAYvC,EAAmB,SAASU,EAAO,IAAI;AACzD,qBACE,gBAAAuB;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,WAAU;AAAA,kBAEV,UAAA;AAAA,oBAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,kBACb,UAAA;AAAA,sBAAA,gBAAAD,EAAC,QAAA,EAAK,WAAU,gCAAgC,UAAAtB,EAAO,MAAK;AAAA,sBAC3DA,EAAO,eACN,gBAAAsB,EAAC,KAAA,EAAE,WAAU,qDACV,UAAAQ,EAAuB9B,EAAO,aAAajB,CAAe,EAAA,CAC7D;AAAA,sBAEF,gBAAAwC,EAAC,OAAA,EAAI,WAAU,qEACb,UAAA;AAAA,wBAAA,gBAAAD,EAAC,QAAA,EAAM,YAAO,KAAA,CAAK;AAAA,wBACnB,gBAAAA,EAAC,UAAK,UAAA,IAAA,CAAC;AAAA,0CACN,QAAA,EAAM,UAAArD,EAAe+B,EAAO,iBAAiB,CAAC,GAAE;AAAA,wBACjD,gBAAAsB,EAAC,UAAK,UAAA,IAAA,CAAC;AAAA,wBACP,gBAAAA,EAAC,UAAK,WAAU,cAAc,YAAO,KAAK,QAAQ,KAAK,GAAG,EAAA,CAAE;AAAA,sBAAA,EAAA,CAC9D;AAAA,oBAAA,GACF;AAAA,oBACA,gBAAAA;AAAA,sBAACK;AAAA,sBAAA;AAAA,wBACC,SAASE;AAAA,wBACT,iBAAiB,CAACD,MAAY1B,EAAaF,EAAO,MAAM4B,CAAO;AAAA,wBAC/D,cAAY5B,EAAO;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACrB;AAAA,gBAAA;AAAA,gBAtBKA,EAAO;AAAA,cAAA;AAAA,YAyBlB,CAAC,EAAA,CACH;AAAA,UAAA;AAAA,QAAA;AAAA,QArEGS;AAAA,MAAA;AAAA,IAyEX,CAAC,EAAA,CACH;AAAA,IAGA,gBAAAc,EAAC,OAAA,EAAI,WAAU,gEACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,cACb,UAAA;AAAA,QAAA,gBAAAD;AAAA,UAACS;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAShB;AAAA,YACT,WAAU;AAAA,YAET,YAAE,uBAAuB;AAAA,UAAA;AAAA,QAAA;AAAA,QAE5B,gBAAAO;AAAA,UAACS;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAASjB;AAAA,YACT,WAAU;AAAA,YAET,YAAE,uBAAuB;AAAA,UAAA;AAAA,QAAA;AAAA,MAC5B,GACF;AAAA,MACA,gBAAAQ;AAAA,QAACS;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAASf;AAAA,UACT,UAAU,CAACE,KAAc,CAACpC;AAAA,UAC1B,WAAU;AAAA,UAET,YAAE,kBAAkB;AAAA,QAAA;AAAA,MAAA;AAAA,IACvB,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}