@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.
- package/README.md +336 -0
- package/dist/adapters/nav-shell.d.ts +54 -0
- package/dist/adapters/nav-shell.d.ts.map +1 -0
- package/dist/adapters/nav-shell.js +112 -0
- package/dist/adapters/nav-shell.js.map +1 -0
- package/dist/brand.d.ts +64 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +59 -0
- package/dist/brand.js.map +1 -0
- package/dist/core-nav.d.ts +17 -0
- package/dist/core-nav.d.ts.map +1 -0
- package/dist/core-nav.js +40 -0
- package/dist/core-nav.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-scopes.d.ts +24 -0
- package/dist/lib/api-scopes.d.ts.map +1 -0
- package/dist/lib/api-scopes.js +78 -0
- package/dist/lib/api-scopes.js.map +1 -0
- package/dist/lib/catalog-suspense-key.d.ts +3 -0
- package/dist/lib/catalog-suspense-key.d.ts.map +1 -0
- package/dist/lib/catalog-suspense-key.js +12 -0
- package/dist/lib/catalog-suspense-key.js.map +1 -0
- package/dist/lib/data-changed.d.ts +51 -0
- package/dist/lib/data-changed.d.ts.map +1 -0
- package/dist/lib/data-changed.js +227 -0
- package/dist/lib/data-changed.js.map +1 -0
- package/dist/lib/desktop-home-path.d.ts +14 -0
- package/dist/lib/desktop-home-path.d.ts.map +1 -0
- package/dist/lib/desktop-home-path.js +29 -0
- package/dist/lib/desktop-home-path.js.map +1 -0
- package/dist/lib/geo-distance.d.ts +6 -0
- package/dist/lib/geo-distance.d.ts.map +1 -0
- package/dist/lib/geo-distance.js +27 -0
- package/dist/lib/geo-distance.js.map +1 -0
- package/dist/lib/img.d.ts +2 -0
- package/dist/lib/img.d.ts.map +1 -0
- package/dist/lib/img.js +40 -0
- package/dist/lib/img.js.map +1 -0
- package/dist/lib/keepalive-eviction.d.ts +14 -0
- package/dist/lib/keepalive-eviction.d.ts.map +1 -0
- package/dist/lib/keepalive-eviction.js +44 -0
- package/dist/lib/keepalive-eviction.js.map +1 -0
- package/dist/lib/ops-track.d.ts +29 -0
- package/dist/lib/ops-track.d.ts.map +1 -0
- package/dist/lib/ops-track.js +37 -0
- package/dist/lib/ops-track.js.map +1 -0
- package/dist/lib/optimize-cover-url.d.ts +10 -0
- package/dist/lib/optimize-cover-url.d.ts.map +1 -0
- package/dist/lib/optimize-cover-url.js +80 -0
- package/dist/lib/optimize-cover-url.js.map +1 -0
- package/dist/lib/page-trails.d.ts +9 -0
- package/dist/lib/page-trails.d.ts.map +1 -0
- package/dist/lib/page-trails.js +20 -0
- package/dist/lib/page-trails.js.map +1 -0
- package/dist/lib/public-origin.d.ts +32 -0
- package/dist/lib/public-origin.d.ts.map +1 -0
- package/dist/lib/public-origin.js +125 -0
- package/dist/lib/public-origin.js.map +1 -0
- package/dist/lib/server-incident.d.ts +12 -0
- package/dist/lib/server-incident.d.ts.map +1 -0
- package/dist/lib/server-incident.js +72 -0
- package/dist/lib/server-incident.js.map +1 -0
- package/dist/lib/tab-document-url.d.ts +13 -0
- package/dist/lib/tab-document-url.d.ts.map +1 -0
- package/dist/lib/tab-document-url.js +60 -0
- package/dist/lib/tab-document-url.js.map +1 -0
- package/dist/lib/utils.d.ts +20 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +87 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/nav-catalog.d.ts +97 -0
- package/dist/nav-catalog.d.ts.map +1 -0
- package/dist/nav-catalog.js +282 -0
- package/dist/nav-catalog.js.map +1 -0
- package/dist/registry.d.ts +11 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +60 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist-cjs/adapters/nav-shell.js +115 -0
- package/dist-cjs/adapters/nav-shell.js.map +1 -0
- package/dist-cjs/brand.js +66 -0
- package/dist-cjs/brand.js.map +1 -0
- package/dist-cjs/core-nav.js +43 -0
- package/dist-cjs/core-nav.js.map +1 -0
- package/dist-cjs/index.js +95 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/lib/api-scopes.js +86 -0
- package/dist-cjs/lib/api-scopes.js.map +1 -0
- package/dist-cjs/lib/catalog-suspense-key.js +15 -0
- package/dist-cjs/lib/catalog-suspense-key.js.map +1 -0
- package/dist-cjs/lib/data-changed.js +236 -0
- package/dist-cjs/lib/data-changed.js.map +1 -0
- package/dist-cjs/lib/desktop-home-path.js +34 -0
- package/dist-cjs/lib/desktop-home-path.js.map +1 -0
- package/dist-cjs/lib/geo-distance.js +30 -0
- package/dist-cjs/lib/geo-distance.js.map +1 -0
- package/dist-cjs/lib/img.js +43 -0
- package/dist-cjs/lib/img.js.map +1 -0
- package/dist-cjs/lib/keepalive-eviction.js +49 -0
- package/dist-cjs/lib/keepalive-eviction.js.map +1 -0
- package/dist-cjs/lib/ops-track.js +41 -0
- package/dist-cjs/lib/ops-track.js.map +1 -0
- package/dist-cjs/lib/optimize-cover-url.js +83 -0
- package/dist-cjs/lib/optimize-cover-url.js.map +1 -0
- package/dist-cjs/lib/page-trails.js +25 -0
- package/dist-cjs/lib/page-trails.js.map +1 -0
- package/dist-cjs/lib/public-origin.js +130 -0
- package/dist-cjs/lib/public-origin.js.map +1 -0
- package/dist-cjs/lib/server-incident.js +75 -0
- package/dist-cjs/lib/server-incident.js.map +1 -0
- package/dist-cjs/lib/tab-document-url.js +65 -0
- package/dist-cjs/lib/tab-document-url.js.map +1 -0
- package/dist-cjs/lib/utils.js +97 -0
- package/dist-cjs/lib/utils.js.map +1 -0
- package/dist-cjs/nav-catalog.js +293 -0
- package/dist-cjs/nav-catalog.js.map +1 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/registry.js +64 -0
- package/dist-cjs/registry.js.map +1 -0
- package/dist-cjs/types.js +3 -0
- package/dist-cjs/types.js.map +1 -0
- package/package.json +163 -0
- package/ui/app-error-boundary.tsx +59 -0
- package/ui/data-table.tsx +121 -0
- package/ui/desktop/auth-window-chrome.tsx +51 -0
- package/ui/desktop/desktop-bridge.tsx +87 -0
- package/ui/desktop/external-site-slot.tsx +313 -0
- package/ui/desktop/external-site-surface.ts +58 -0
- package/ui/desktop/site-link.tsx +105 -0
- package/ui/desktop/window-chrome-controls.tsx +5 -0
- package/ui/desktop-types.ts +30 -0
- package/ui/faceted-filters.tsx +119 -0
- package/ui/global-search-host.ts +20 -0
- package/ui/global-search.tsx +66 -0
- package/ui/index.ts +178 -0
- package/ui/kit.ts +30 -0
- package/ui/layout/app-shell.tsx +58 -0
- package/ui/layout/desktop-update-banner.tsx +100 -0
- package/ui/layout/entity-header.tsx +44 -0
- package/ui/layout/native-os-nav.ts +104 -0
- package/ui/layout/nav-catalog-loader.tsx +98 -0
- package/ui/layout/nav-icons.ts +67 -0
- package/ui/layout/page-chrome.tsx +90 -0
- package/ui/layout/page-toolbar-context.tsx +82 -0
- package/ui/layout/sandbox-banner.tsx +38 -0
- package/ui/layout/section-view-shell.tsx +73 -0
- package/ui/layout/sidebar-host.ts +144 -0
- package/ui/layout/sidebar.tsx +1150 -0
- package/ui/lib/ai-screencast-hub.ts +127 -0
- package/ui/lib/ai-workspace-client.ts +46 -0
- package/ui/lib/aid.ts +22 -0
- package/ui/lib/desktop-host.ts +114 -0
- package/ui/lib/fleet-tracker-client.ts +237 -0
- package/ui/lib/hermes-ui.ts +114 -0
- package/ui/lib/n8n-ui.ts +115 -0
- package/ui/lib/use-creezio-resource.tsx +121 -0
- package/ui/lib/use-shell-ui-brand.ts +22 -0
- package/ui/list-toolbar.tsx +309 -0
- package/ui/os-pages/desktop-settings-page.tsx +158 -0
- package/ui/os-pages/index.ts +8 -0
- package/ui/page-loading/entity-page-loading.tsx +59 -0
- package/ui/page-loading/list-page-loading.tsx +61 -0
- package/ui/pagination.tsx +56 -0
- package/ui/primitives/avatar.tsx +33 -0
- package/ui/primitives/badge.tsx +36 -0
- package/ui/primitives/breadcrumb.tsx +93 -0
- package/ui/primitives/button.tsx +44 -0
- package/ui/primitives/card.tsx +44 -0
- package/ui/primitives/chart.tsx +317 -0
- package/ui/primitives/command.tsx +111 -0
- package/ui/primitives/dialog.tsx +100 -0
- package/ui/primitives/dropdown-menu.tsx +187 -0
- package/ui/primitives/input.tsx +19 -0
- package/ui/primitives/label.tsx +17 -0
- package/ui/primitives/resizable.tsx +45 -0
- package/ui/primitives/scroll-area.tsx +41 -0
- package/ui/primitives/select.tsx +73 -0
- package/ui/primitives/separator.tsx +26 -0
- package/ui/primitives/sheet.tsx +90 -0
- package/ui/primitives/skeleton.tsx +7 -0
- package/ui/primitives/sonner.tsx +22 -0
- package/ui/primitives/tabs.tsx +51 -0
- package/ui/primitives/textarea.tsx +22 -0
- package/ui/primitives/tooltip.tsx +31 -0
- package/ui/pwa/client-error-reporter.tsx +62 -0
- package/ui/pwa/register-sw.tsx +50 -0
- package/ui/range-filters.tsx +174 -0
- package/ui/search/global-search-config.ts +32 -0
- package/ui/search/global-search-provider.tsx +528 -0
- package/ui/search/search-history.ts +74 -0
- package/ui/search-input.tsx +146 -0
- package/ui/settings/account-settings.tsx +140 -0
- package/ui/settings/agent-profile-settings.tsx +184 -0
- package/ui/settings/api-keys-settings.tsx +349 -0
- package/ui/settings/desktop-background-settings.tsx +128 -0
- package/ui/settings/desktop-connection-settings.tsx +251 -0
- package/ui/settings/desktop-embed-env-panel.tsx +257 -0
- package/ui/settings/desktop-fleet-telemetry-settings.tsx +269 -0
- package/ui/settings/desktop-hermes-settings.tsx +341 -0
- package/ui/settings/desktop-llm-keys.tsx +192 -0
- package/ui/settings/desktop-n8n-settings.tsx +306 -0
- package/ui/settings/desktop-tunnel.tsx +264 -0
- package/ui/settings/desktop-update-settings.tsx +175 -0
- package/ui/settings/factory-reset-settings.tsx +89 -0
- package/ui/settings/host-only-settings.tsx +62 -0
- package/ui/settings/locked-config-field.tsx +30 -0
- package/ui/settings/ops-diagnostic-settings.tsx +242 -0
- package/ui/settings/search-reindex-settings.tsx +158 -0
- package/ui/settings/server-mode-cards.tsx +801 -0
- package/ui/theme/tailwind-preset.cjs +82 -0
- package/ui/theme/theme.css +328 -0
- package/ui/workspace/ai-activity-panel-host.tsx +19 -0
- package/ui/workspace/ai-workspace-agent-host.tsx +54 -0
- package/ui/workspace/ai-workspace-banner.tsx +168 -0
- package/ui/workspace/impersonation-banner.tsx +39 -0
- package/ui/workspace/keep-alive.tsx +220 -0
- package/ui/workspace/tab-workspace-context.tsx +1172 -0
- package/ui/workspace/tab-workspace-host.ts +89 -0
- package/ui/workspace/types.ts +500 -0
- package/ui/workspace/use-location-search.tsx +50 -0
- package/ui/workspace/window-chrome-controls.tsx +116 -0
- package/ui/workspace/workspace-config.ts +47 -0
- package/ui/workspace/workspace-root.tsx +147 -0
- package/ui/workspace/workspace-shell.tsx +292 -0
- 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
|
+
}
|