@creezio/shell-ui 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/README.md +336 -0
  2. package/dist/adapters/nav-shell.d.ts +54 -0
  3. package/dist/adapters/nav-shell.d.ts.map +1 -0
  4. package/dist/adapters/nav-shell.js +112 -0
  5. package/dist/adapters/nav-shell.js.map +1 -0
  6. package/dist/brand.d.ts +64 -0
  7. package/dist/brand.d.ts.map +1 -0
  8. package/dist/brand.js +59 -0
  9. package/dist/brand.js.map +1 -0
  10. package/dist/core-nav.d.ts +17 -0
  11. package/dist/core-nav.d.ts.map +1 -0
  12. package/dist/core-nav.js +40 -0
  13. package/dist/core-nav.js.map +1 -0
  14. package/dist/index.d.ts +29 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +24 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/lib/api-scopes.d.ts +24 -0
  19. package/dist/lib/api-scopes.d.ts.map +1 -0
  20. package/dist/lib/api-scopes.js +78 -0
  21. package/dist/lib/api-scopes.js.map +1 -0
  22. package/dist/lib/catalog-suspense-key.d.ts +3 -0
  23. package/dist/lib/catalog-suspense-key.d.ts.map +1 -0
  24. package/dist/lib/catalog-suspense-key.js +12 -0
  25. package/dist/lib/catalog-suspense-key.js.map +1 -0
  26. package/dist/lib/data-changed.d.ts +51 -0
  27. package/dist/lib/data-changed.d.ts.map +1 -0
  28. package/dist/lib/data-changed.js +227 -0
  29. package/dist/lib/data-changed.js.map +1 -0
  30. package/dist/lib/desktop-home-path.d.ts +14 -0
  31. package/dist/lib/desktop-home-path.d.ts.map +1 -0
  32. package/dist/lib/desktop-home-path.js +29 -0
  33. package/dist/lib/desktop-home-path.js.map +1 -0
  34. package/dist/lib/geo-distance.d.ts +6 -0
  35. package/dist/lib/geo-distance.d.ts.map +1 -0
  36. package/dist/lib/geo-distance.js +27 -0
  37. package/dist/lib/geo-distance.js.map +1 -0
  38. package/dist/lib/img.d.ts +2 -0
  39. package/dist/lib/img.d.ts.map +1 -0
  40. package/dist/lib/img.js +40 -0
  41. package/dist/lib/img.js.map +1 -0
  42. package/dist/lib/keepalive-eviction.d.ts +14 -0
  43. package/dist/lib/keepalive-eviction.d.ts.map +1 -0
  44. package/dist/lib/keepalive-eviction.js +44 -0
  45. package/dist/lib/keepalive-eviction.js.map +1 -0
  46. package/dist/lib/ops-track.d.ts +29 -0
  47. package/dist/lib/ops-track.d.ts.map +1 -0
  48. package/dist/lib/ops-track.js +37 -0
  49. package/dist/lib/ops-track.js.map +1 -0
  50. package/dist/lib/optimize-cover-url.d.ts +10 -0
  51. package/dist/lib/optimize-cover-url.d.ts.map +1 -0
  52. package/dist/lib/optimize-cover-url.js +80 -0
  53. package/dist/lib/optimize-cover-url.js.map +1 -0
  54. package/dist/lib/page-trails.d.ts +9 -0
  55. package/dist/lib/page-trails.d.ts.map +1 -0
  56. package/dist/lib/page-trails.js +20 -0
  57. package/dist/lib/page-trails.js.map +1 -0
  58. package/dist/lib/public-origin.d.ts +32 -0
  59. package/dist/lib/public-origin.d.ts.map +1 -0
  60. package/dist/lib/public-origin.js +125 -0
  61. package/dist/lib/public-origin.js.map +1 -0
  62. package/dist/lib/server-incident.d.ts +12 -0
  63. package/dist/lib/server-incident.d.ts.map +1 -0
  64. package/dist/lib/server-incident.js +72 -0
  65. package/dist/lib/server-incident.js.map +1 -0
  66. package/dist/lib/tab-document-url.d.ts +13 -0
  67. package/dist/lib/tab-document-url.d.ts.map +1 -0
  68. package/dist/lib/tab-document-url.js +60 -0
  69. package/dist/lib/tab-document-url.js.map +1 -0
  70. package/dist/lib/utils.d.ts +20 -0
  71. package/dist/lib/utils.d.ts.map +1 -0
  72. package/dist/lib/utils.js +87 -0
  73. package/dist/lib/utils.js.map +1 -0
  74. package/dist/nav-catalog.d.ts +97 -0
  75. package/dist/nav-catalog.d.ts.map +1 -0
  76. package/dist/nav-catalog.js +282 -0
  77. package/dist/nav-catalog.js.map +1 -0
  78. package/dist/registry.d.ts +11 -0
  79. package/dist/registry.d.ts.map +1 -0
  80. package/dist/registry.js +60 -0
  81. package/dist/registry.js.map +1 -0
  82. package/dist/types.d.ts +22 -0
  83. package/dist/types.d.ts.map +1 -0
  84. package/dist/types.js +2 -0
  85. package/dist/types.js.map +1 -0
  86. package/dist-cjs/adapters/nav-shell.js +115 -0
  87. package/dist-cjs/adapters/nav-shell.js.map +1 -0
  88. package/dist-cjs/brand.js +66 -0
  89. package/dist-cjs/brand.js.map +1 -0
  90. package/dist-cjs/core-nav.js +43 -0
  91. package/dist-cjs/core-nav.js.map +1 -0
  92. package/dist-cjs/index.js +95 -0
  93. package/dist-cjs/index.js.map +1 -0
  94. package/dist-cjs/lib/api-scopes.js +86 -0
  95. package/dist-cjs/lib/api-scopes.js.map +1 -0
  96. package/dist-cjs/lib/catalog-suspense-key.js +15 -0
  97. package/dist-cjs/lib/catalog-suspense-key.js.map +1 -0
  98. package/dist-cjs/lib/data-changed.js +236 -0
  99. package/dist-cjs/lib/data-changed.js.map +1 -0
  100. package/dist-cjs/lib/desktop-home-path.js +34 -0
  101. package/dist-cjs/lib/desktop-home-path.js.map +1 -0
  102. package/dist-cjs/lib/geo-distance.js +30 -0
  103. package/dist-cjs/lib/geo-distance.js.map +1 -0
  104. package/dist-cjs/lib/img.js +43 -0
  105. package/dist-cjs/lib/img.js.map +1 -0
  106. package/dist-cjs/lib/keepalive-eviction.js +49 -0
  107. package/dist-cjs/lib/keepalive-eviction.js.map +1 -0
  108. package/dist-cjs/lib/ops-track.js +41 -0
  109. package/dist-cjs/lib/ops-track.js.map +1 -0
  110. package/dist-cjs/lib/optimize-cover-url.js +83 -0
  111. package/dist-cjs/lib/optimize-cover-url.js.map +1 -0
  112. package/dist-cjs/lib/page-trails.js +25 -0
  113. package/dist-cjs/lib/page-trails.js.map +1 -0
  114. package/dist-cjs/lib/public-origin.js +130 -0
  115. package/dist-cjs/lib/public-origin.js.map +1 -0
  116. package/dist-cjs/lib/server-incident.js +75 -0
  117. package/dist-cjs/lib/server-incident.js.map +1 -0
  118. package/dist-cjs/lib/tab-document-url.js +65 -0
  119. package/dist-cjs/lib/tab-document-url.js.map +1 -0
  120. package/dist-cjs/lib/utils.js +97 -0
  121. package/dist-cjs/lib/utils.js.map +1 -0
  122. package/dist-cjs/nav-catalog.js +293 -0
  123. package/dist-cjs/nav-catalog.js.map +1 -0
  124. package/dist-cjs/package.json +3 -0
  125. package/dist-cjs/registry.js +64 -0
  126. package/dist-cjs/registry.js.map +1 -0
  127. package/dist-cjs/types.js +3 -0
  128. package/dist-cjs/types.js.map +1 -0
  129. package/package.json +163 -0
  130. package/ui/app-error-boundary.tsx +59 -0
  131. package/ui/data-table.tsx +121 -0
  132. package/ui/desktop/auth-window-chrome.tsx +51 -0
  133. package/ui/desktop/desktop-bridge.tsx +87 -0
  134. package/ui/desktop/external-site-slot.tsx +313 -0
  135. package/ui/desktop/external-site-surface.ts +58 -0
  136. package/ui/desktop/site-link.tsx +105 -0
  137. package/ui/desktop/window-chrome-controls.tsx +5 -0
  138. package/ui/desktop-types.ts +30 -0
  139. package/ui/faceted-filters.tsx +119 -0
  140. package/ui/global-search-host.ts +20 -0
  141. package/ui/global-search.tsx +66 -0
  142. package/ui/index.ts +178 -0
  143. package/ui/kit.ts +30 -0
  144. package/ui/layout/app-shell.tsx +58 -0
  145. package/ui/layout/desktop-update-banner.tsx +100 -0
  146. package/ui/layout/entity-header.tsx +44 -0
  147. package/ui/layout/native-os-nav.ts +104 -0
  148. package/ui/layout/nav-catalog-loader.tsx +98 -0
  149. package/ui/layout/nav-icons.ts +67 -0
  150. package/ui/layout/page-chrome.tsx +90 -0
  151. package/ui/layout/page-toolbar-context.tsx +82 -0
  152. package/ui/layout/sandbox-banner.tsx +38 -0
  153. package/ui/layout/section-view-shell.tsx +73 -0
  154. package/ui/layout/sidebar-host.ts +144 -0
  155. package/ui/layout/sidebar.tsx +1150 -0
  156. package/ui/lib/ai-screencast-hub.ts +127 -0
  157. package/ui/lib/ai-workspace-client.ts +46 -0
  158. package/ui/lib/aid.ts +22 -0
  159. package/ui/lib/desktop-host.ts +114 -0
  160. package/ui/lib/fleet-tracker-client.ts +237 -0
  161. package/ui/lib/hermes-ui.ts +114 -0
  162. package/ui/lib/n8n-ui.ts +115 -0
  163. package/ui/lib/use-creezio-resource.tsx +121 -0
  164. package/ui/lib/use-shell-ui-brand.ts +22 -0
  165. package/ui/list-toolbar.tsx +309 -0
  166. package/ui/os-pages/desktop-settings-page.tsx +158 -0
  167. package/ui/os-pages/index.ts +8 -0
  168. package/ui/page-loading/entity-page-loading.tsx +59 -0
  169. package/ui/page-loading/list-page-loading.tsx +61 -0
  170. package/ui/pagination.tsx +56 -0
  171. package/ui/primitives/avatar.tsx +33 -0
  172. package/ui/primitives/badge.tsx +36 -0
  173. package/ui/primitives/breadcrumb.tsx +93 -0
  174. package/ui/primitives/button.tsx +44 -0
  175. package/ui/primitives/card.tsx +44 -0
  176. package/ui/primitives/chart.tsx +317 -0
  177. package/ui/primitives/command.tsx +111 -0
  178. package/ui/primitives/dialog.tsx +100 -0
  179. package/ui/primitives/dropdown-menu.tsx +187 -0
  180. package/ui/primitives/input.tsx +19 -0
  181. package/ui/primitives/label.tsx +17 -0
  182. package/ui/primitives/resizable.tsx +45 -0
  183. package/ui/primitives/scroll-area.tsx +41 -0
  184. package/ui/primitives/select.tsx +73 -0
  185. package/ui/primitives/separator.tsx +26 -0
  186. package/ui/primitives/sheet.tsx +90 -0
  187. package/ui/primitives/skeleton.tsx +7 -0
  188. package/ui/primitives/sonner.tsx +22 -0
  189. package/ui/primitives/tabs.tsx +51 -0
  190. package/ui/primitives/textarea.tsx +22 -0
  191. package/ui/primitives/tooltip.tsx +31 -0
  192. package/ui/pwa/client-error-reporter.tsx +62 -0
  193. package/ui/pwa/register-sw.tsx +50 -0
  194. package/ui/range-filters.tsx +174 -0
  195. package/ui/search/global-search-config.ts +32 -0
  196. package/ui/search/global-search-provider.tsx +528 -0
  197. package/ui/search/search-history.ts +74 -0
  198. package/ui/search-input.tsx +146 -0
  199. package/ui/settings/account-settings.tsx +140 -0
  200. package/ui/settings/agent-profile-settings.tsx +184 -0
  201. package/ui/settings/api-keys-settings.tsx +349 -0
  202. package/ui/settings/desktop-background-settings.tsx +128 -0
  203. package/ui/settings/desktop-connection-settings.tsx +251 -0
  204. package/ui/settings/desktop-embed-env-panel.tsx +257 -0
  205. package/ui/settings/desktop-fleet-telemetry-settings.tsx +269 -0
  206. package/ui/settings/desktop-hermes-settings.tsx +341 -0
  207. package/ui/settings/desktop-llm-keys.tsx +192 -0
  208. package/ui/settings/desktop-n8n-settings.tsx +306 -0
  209. package/ui/settings/desktop-tunnel.tsx +264 -0
  210. package/ui/settings/desktop-update-settings.tsx +175 -0
  211. package/ui/settings/factory-reset-settings.tsx +89 -0
  212. package/ui/settings/host-only-settings.tsx +62 -0
  213. package/ui/settings/locked-config-field.tsx +30 -0
  214. package/ui/settings/ops-diagnostic-settings.tsx +242 -0
  215. package/ui/settings/search-reindex-settings.tsx +158 -0
  216. package/ui/settings/server-mode-cards.tsx +801 -0
  217. package/ui/theme/tailwind-preset.cjs +82 -0
  218. package/ui/theme/theme.css +328 -0
  219. package/ui/workspace/ai-activity-panel-host.tsx +19 -0
  220. package/ui/workspace/ai-workspace-agent-host.tsx +54 -0
  221. package/ui/workspace/ai-workspace-banner.tsx +168 -0
  222. package/ui/workspace/impersonation-banner.tsx +39 -0
  223. package/ui/workspace/keep-alive.tsx +220 -0
  224. package/ui/workspace/tab-workspace-context.tsx +1172 -0
  225. package/ui/workspace/tab-workspace-host.ts +89 -0
  226. package/ui/workspace/types.ts +500 -0
  227. package/ui/workspace/use-location-search.tsx +50 -0
  228. package/ui/workspace/window-chrome-controls.tsx +116 -0
  229. package/ui/workspace/workspace-config.ts +47 -0
  230. package/ui/workspace/workspace-root.tsx +147 -0
  231. package/ui/workspace/workspace-shell.tsx +292 -0
  232. package/ui/workspace/workspace-tab-bar.tsx +572 -0
@@ -0,0 +1,62 @@
1
+ "use client";
2
+
3
+ import { useEffect } from "react";
4
+
5
+ /**
6
+ * Remonte les exceptions client (erreurs non catchées + promesses rejetées)
7
+ * vers /api/client-log — indispensable pour diagnostiquer les crashs mobiles
8
+ * (« Application error: a client-side exception has occurred ») où la
9
+ * console navigateur n'est pas accessible.
10
+ */
11
+ export function report(kind: string, message: string, stack?: string, digest?: string) {
12
+ try {
13
+ const body = JSON.stringify({
14
+ kind,
15
+ message,
16
+ stack,
17
+ digest,
18
+ url: typeof location !== "undefined" ? location.href : undefined,
19
+ });
20
+ if (typeof navigator !== "undefined" && navigator.sendBeacon) {
21
+ navigator.sendBeacon("/api/client-log", new Blob([body], { type: "application/json" }));
22
+ } else {
23
+ void fetch("/api/client-log", {
24
+ method: "POST",
25
+ headers: { "Content-Type": "application/json" },
26
+ body,
27
+ keepalive: true,
28
+ }).catch(() => {});
29
+ }
30
+ } catch {
31
+ /* le reporter ne doit jamais casser l'app */
32
+ }
33
+ }
34
+
35
+ export function ClientErrorReporter() {
36
+ useEffect(() => {
37
+ const onError = (e: ErrorEvent) => {
38
+ const stack =
39
+ e.error && typeof e.error.stack === "string" ? e.error.stack : undefined;
40
+ report(
41
+ "window.onerror",
42
+ `${e.message} @ ${e.filename || "?"}:${e.lineno || 0}:${e.colno || 0}`,
43
+ stack,
44
+ );
45
+ };
46
+ const onRejection = (e: PromiseRejectionEvent) => {
47
+ const reason = e.reason;
48
+ const message =
49
+ reason instanceof Error ? reason.message : String(reason ?? "(vide)");
50
+ const stack = reason instanceof Error ? reason.stack : undefined;
51
+ report("unhandledrejection", message, stack);
52
+ };
53
+ window.addEventListener("error", onError);
54
+ window.addEventListener("unhandledrejection", onRejection);
55
+ return () => {
56
+ window.removeEventListener("error", onError);
57
+ window.removeEventListener("unhandledrejection", onRejection);
58
+ };
59
+ }, []);
60
+
61
+ return null;
62
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ import { useEffect } from "react";
4
+
5
+ /**
6
+ * Enregistrement client du SW custom (`public/sw.js`).
7
+ * Pas de next-pwa : compatible Next 14 App Router + standalone Docker.
8
+ * Au boot : purge les vieux caches HTML (tf2-shell-v1) qui causaient
9
+ * des « Application error » après redeploy.
10
+ */
11
+ export function RegisterServiceWorker() {
12
+ useEffect(() => {
13
+ if (typeof window === "undefined") return;
14
+ if (!("serviceWorker" in navigator)) return;
15
+ // Dev local : ne pas polluer le HMR
16
+ if (process.env.NODE_ENV !== "production") return;
17
+
18
+ let cancelled = false;
19
+
20
+ (async () => {
21
+ try {
22
+ const keys = await caches.keys();
23
+ await Promise.all(
24
+ keys
25
+ .filter((k) => k.startsWith("tf2-shell-") && k !== "tf2-shell-v2")
26
+ .map((k) => caches.delete(k)),
27
+ );
28
+ } catch {
29
+ /* ignore */
30
+ }
31
+ if (cancelled) return;
32
+
33
+ navigator.serviceWorker
34
+ .register("/sw.js", { scope: "/" })
35
+ .then((reg) => {
36
+ if (cancelled) return;
37
+ reg.update().catch(() => {});
38
+ })
39
+ .catch(() => {
40
+ /* silencieux : PWA optionnelle */
41
+ });
42
+ })();
43
+
44
+ return () => {
45
+ cancelled = true;
46
+ };
47
+ }, []);
48
+
49
+ return null;
50
+ }
@@ -0,0 +1,174 @@
1
+ "use client";
2
+
3
+ import { FormEvent, useEffect, useState, useTransition } from "react";
4
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
5
+ import { Button } from "./primitives/button";
6
+ import { Input } from "./primitives/input";
7
+
8
+ /**
9
+ * Filtres comparateur prix (min/max) + plage de dates (dateFrom/dateTo).
10
+ * Application explicite via bouton (pas de debounce) pour éviter les allers-retours.
11
+ */
12
+ export function RangeFilters({
13
+ priceMinKey = "priceMin",
14
+ priceMaxKey = "priceMax",
15
+ dateFromKey = "dateFrom",
16
+ dateToKey = "dateTo",
17
+ amountLabel = "Prix",
18
+ dateFromLabel = "Création du",
19
+ dateHint = "Filtre sur la date de création",
20
+ showAmount = true,
21
+ clearLabel = "Effacer montant/dates",
22
+ }: {
23
+ priceMinKey?: string;
24
+ priceMaxKey?: string;
25
+ dateFromKey?: string;
26
+ dateToKey?: string;
27
+ /** Libellé commun aux deux bornes (Prix, Montant…). */
28
+ amountLabel?: string;
29
+ dateFromLabel?: string;
30
+ dateHint?: string;
31
+ /** Masque les bornes montant lorsque la page ne filtre que les dates. */
32
+ showAmount?: boolean;
33
+ clearLabel?: string;
34
+ }) {
35
+ const router = useRouter();
36
+ const pathname = usePathname();
37
+ const params = useSearchParams();
38
+ const [, startTransition] = useTransition();
39
+
40
+ const [priceMin, setPriceMin] = useState(params.get(priceMinKey) || "");
41
+ const [priceMax, setPriceMax] = useState(params.get(priceMaxKey) || "");
42
+ const [dateFrom, setDateFrom] = useState(params.get(dateFromKey) || "");
43
+ const [dateTo, setDateTo] = useState(params.get(dateToKey) || "");
44
+
45
+ useEffect(() => {
46
+ setPriceMin(params.get(priceMinKey) || "");
47
+ setPriceMax(params.get(priceMaxKey) || "");
48
+ setDateFrom(params.get(dateFromKey) || "");
49
+ setDateTo(params.get(dateToKey) || "");
50
+ }, [params, priceMinKey, priceMaxKey, dateFromKey, dateToKey]);
51
+
52
+ function apply(e?: FormEvent) {
53
+ e?.preventDefault();
54
+ const next = new URLSearchParams(params.toString());
55
+ const setOrDel = (key: string, value: string) => {
56
+ const v = value.trim();
57
+ if (v) next.set(key, v);
58
+ else next.delete(key);
59
+ };
60
+ setOrDel(priceMinKey, priceMin);
61
+ setOrDel(priceMaxKey, priceMax);
62
+ setOrDel(dateFromKey, dateFrom);
63
+ setOrDel(dateToKey, dateTo);
64
+ next.delete("page");
65
+ next.delete("preset");
66
+ // Plage custom prioritaire : on retire le raccourci période
67
+ if (dateFrom.trim() || dateTo.trim()) next.delete("period");
68
+ const qs = next.toString();
69
+ const href = qs ? `${pathname}?${qs}` : pathname;
70
+ startTransition(() => {
71
+ router.push(href);
72
+ router.refresh();
73
+ });
74
+ }
75
+
76
+ function clearRanges() {
77
+ setPriceMin("");
78
+ setPriceMax("");
79
+ setDateFrom("");
80
+ setDateTo("");
81
+ const next = new URLSearchParams(params.toString());
82
+ [priceMinKey, priceMaxKey, dateFromKey, dateToKey, "preset"].forEach((k) =>
83
+ next.delete(k),
84
+ );
85
+ next.delete("page");
86
+ const qs = next.toString();
87
+ const href = qs ? `${pathname}?${qs}` : pathname;
88
+ startTransition(() => {
89
+ router.push(href);
90
+ router.refresh();
91
+ });
92
+ }
93
+
94
+ const hasAny =
95
+ Boolean(params.get(priceMinKey)) ||
96
+ Boolean(params.get(priceMaxKey)) ||
97
+ Boolean(params.get(dateFromKey)) ||
98
+ Boolean(params.get(dateToKey));
99
+
100
+ return (
101
+ <form
102
+ onSubmit={apply}
103
+ className="flex flex-wrap items-end gap-3 rounded-xl border border-slate-200 bg-white p-3 shadow-sm"
104
+ >
105
+ {showAmount ? (
106
+ <>
107
+ <div className="space-y-1">
108
+ <label className="text-[11px] font-medium uppercase tracking-wide text-slate-500">
109
+ {amountLabel} min
110
+ </label>
111
+ <Input
112
+ type="number"
113
+ inputMode="decimal"
114
+ step="1"
115
+ placeholder="ex. 300"
116
+ value={priceMin}
117
+ onChange={(e) => setPriceMin(e.target.value)}
118
+ className="w-28"
119
+ />
120
+ </div>
121
+ <div className="space-y-1">
122
+ <label className="text-[11px] font-medium uppercase tracking-wide text-slate-500">
123
+ {amountLabel} max
124
+ </label>
125
+ <Input
126
+ type="number"
127
+ inputMode="decimal"
128
+ step="1"
129
+ placeholder="ex. 800"
130
+ value={priceMax}
131
+ onChange={(e) => setPriceMax(e.target.value)}
132
+ className="w-28"
133
+ />
134
+ </div>
135
+ </>
136
+ ) : null}
137
+ <div className="space-y-1">
138
+ <label className="text-[11px] font-medium uppercase tracking-wide text-slate-500">
139
+ {dateFromLabel}
140
+ </label>
141
+ <Input
142
+ type="date"
143
+ value={dateFrom}
144
+ onChange={(e) => setDateFrom(e.target.value)}
145
+ className="w-40"
146
+ title={dateHint}
147
+ />
148
+ </div>
149
+ <div className="space-y-1">
150
+ <label className="text-[11px] font-medium uppercase tracking-wide text-slate-500">
151
+ au
152
+ </label>
153
+ <Input
154
+ type="date"
155
+ value={dateTo}
156
+ onChange={(e) => setDateTo(e.target.value)}
157
+ className="w-40"
158
+ title={dateHint}
159
+ />
160
+ </div>
161
+ <div className="flex flex-wrap gap-2">
162
+ <Button type="submit" size="sm">
163
+ Appliquer
164
+ </Button>
165
+ {hasAny ? (
166
+ <Button type="button" size="sm" variant="secondary" onClick={clearRanges}>
167
+ {clearLabel}
168
+ </Button>
169
+ ) : null}
170
+ </div>
171
+ <p className="w-full text-[11px] text-slate-400">{dateHint}</p>
172
+ </form>
173
+ );
174
+ }
@@ -0,0 +1,32 @@
1
+ export type GlobalSearchHit = {
2
+ index: string;
3
+ id: string;
4
+ title: string;
5
+ subtitle?: string;
6
+ href: string;
7
+ };
8
+
9
+ export type GlobalSearchConfig = {
10
+ placeholder?: string;
11
+ indexLabels?: Record<string, string>;
12
+ storageKey?: string;
13
+ /** Fetch hits for query - brand app decides Meili/fallback strategy. */
14
+ search: (query: string, signal?: AbortSignal) => Promise<GlobalSearchHit[]>;
15
+ /** Prefer catalogue soft-ctx when navigating to this href. */
16
+ preferCatalogueHref?: (href: string) => boolean;
17
+ /** Optional analytics. */
18
+ onTrack?: (event: string, payload?: Record<string, unknown>) => void;
19
+ };
20
+
21
+ let cfg: GlobalSearchConfig | null = null;
22
+
23
+ export function configureGlobalSearch(next: GlobalSearchConfig): void {
24
+ cfg = next;
25
+ }
26
+
27
+ export function getGlobalSearchConfig(): GlobalSearchConfig {
28
+ if (!cfg?.search) {
29
+ throw new Error("@creezio/shell-ui: configureGlobalSearch() requis");
30
+ }
31
+ return cfg;
32
+ }