@hgdc/ui 0.65.0 → 0.66.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/dist/app-shell.js +1 -1
- package/dist/module-bar-store.d.ts +4 -2
- package/dist/module-bar-store.js +6 -2
- package/dist/module-bar.js +2 -0
- package/dist/product-bar.d.ts +8 -1
- package/dist/product-bar.js +62 -2
- package/package.json +1 -1
package/dist/app-shell.js
CHANGED
|
@@ -44,7 +44,7 @@ export function AppShell({ product, organization, productRail: productRailOption
|
|
|
44
44
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
45
45
|
const preference = useProductBarPreference();
|
|
46
46
|
// Relu chez Account seulement par un produit passé aux deux vues (il donne `view`, ADR 0014).
|
|
47
|
-
useProductBarSync(productRailOption
|
|
47
|
+
useProductBarSync(productRailOption !== false);
|
|
48
48
|
const productRail = productRailOption ?? (viewOption === undefined || productBarShown(viewOption, preference));
|
|
49
49
|
const [navLevel, setNavLevel] = useState("tabs");
|
|
50
50
|
useToggleShortcut();
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type ModuleWord } from "./modules.ts";
|
|
2
2
|
/**
|
|
3
|
-
* L'ordre et le choix des modules de la barre, propres à chaque personne
|
|
4
|
-
*
|
|
3
|
+
* L'ordre et le choix des modules de la barre, propres à chaque personne : Account les garde
|
|
4
|
+
* (`product-bar.ts`), et chaque origine en retient la dernière valeur, pour s'afficher sans attendre.
|
|
5
5
|
*/
|
|
6
6
|
export declare const MODULE_BAR_KEY = "hgdc-shell:modules";
|
|
7
7
|
export declare function saveModuleBar(order: ReadonlyArray<ModuleWord>): void;
|
|
8
|
+
/** L'ordre retenu dans cette origine, lu hors de React. */
|
|
9
|
+
export declare function storedModuleBar(): ReadonlyArray<ModuleWord>;
|
|
8
10
|
/** L'ordre retenu ; celui par défaut au rendu serveur. */
|
|
9
11
|
export declare function useModuleBar(): ReadonlyArray<ModuleWord>;
|
package/dist/module-bar-store.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useSyncExternalStore } from "react";
|
|
2
2
|
import { DEFAULT_MODULE_BAR, parseModuleBar } from "./modules.js";
|
|
3
3
|
/**
|
|
4
|
-
* L'ordre et le choix des modules de la barre, propres à chaque personne
|
|
5
|
-
*
|
|
4
|
+
* L'ordre et le choix des modules de la barre, propres à chaque personne : Account les garde
|
|
5
|
+
* (`product-bar.ts`), et chaque origine en retient la dernière valeur, pour s'afficher sans attendre.
|
|
6
6
|
*/
|
|
7
7
|
export const MODULE_BAR_KEY = "hgdc-shell:modules";
|
|
8
8
|
const EVENT = "hgdc-module-bar";
|
|
@@ -50,6 +50,10 @@ export function saveModuleBar(order) {
|
|
|
50
50
|
}
|
|
51
51
|
window.dispatchEvent(new Event(EVENT));
|
|
52
52
|
}
|
|
53
|
+
/** L'ordre retenu dans cette origine, lu hors de React. */
|
|
54
|
+
export function storedModuleBar() {
|
|
55
|
+
return read();
|
|
56
|
+
}
|
|
53
57
|
/** L'ordre retenu ; celui par défaut au rendu serveur. */
|
|
54
58
|
export function useModuleBar() {
|
|
55
59
|
return useSyncExternalStore(subscribe, read, () => DEFAULT_MODULE_BAR);
|
package/dist/module-bar.js
CHANGED
|
@@ -11,6 +11,7 @@ import { useState, useSyncExternalStore } from "react";
|
|
|
11
11
|
import { Button } from "./button.js";
|
|
12
12
|
import { cn } from "./cn.js";
|
|
13
13
|
import { saveModuleBar, useModuleBar } from "./module-bar-store.js";
|
|
14
|
+
import { pushModuleBar } from "./product-bar.js";
|
|
14
15
|
import { hiddenModules, moduleByWord, moveModule, shownModules } from "./modules.js";
|
|
15
16
|
import { ProductBadge } from "./product-badge.js";
|
|
16
17
|
import { PRODUCT_PRERENDER_ATTRIBUTE } from "./product-switch.js";
|
|
@@ -86,6 +87,7 @@ export function ShellNavigation({ product, nav, accountHref, level, onLevelChang
|
|
|
86
87
|
const { products, account } = shellProductEntries({ current: product, accountHref, pageOrigin });
|
|
87
88
|
return (_jsxs("div", { "data-slot": "shell-navigation", className: "flex min-h-0 flex-1 flex-col", children: [_jsxs("div", { "data-slot": "shell-manager", className: "shrink-0 px-3 pt-1", children: [_jsx("ul", { children: _jsx(ShellEntryLink, { entry: account, icon: UserGroupIcon }) }), _jsx("div", { "aria-hidden": true, className: "mx-2 mt-2 h-px bg-foreground/8" })] }), level === "modules" ? (_jsx(ModuleList, { entries: products, order: shownModules(order, product).filter((word) => !projectModules || word === product || projectModules.includes(word)), onOpenCurrent: () => onLevelChange("tabs"), onCustomize: () => onLevelChange("edit") })) : level === "edit" ? (_jsx(ModuleBarEditor, { order: order, onSave: (next) => {
|
|
88
89
|
saveModuleBar(next);
|
|
90
|
+
void pushModuleBar(next);
|
|
89
91
|
onLevelChange("modules");
|
|
90
92
|
}, onCancel: () => onLevelChange("modules") })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "shrink-0 px-3 pt-2", children: [_jsx("ul", { children: _jsx(SidebarNavBack, { label: "Retour aux modules", keepMenuOpen: true, render: _jsx("button", { type: "button", className: "w-full", onClick: () => onLevelChange("modules") }) }) }), _jsxs("div", { "data-slot": "shell-module-title", className: "flex min-h-9 items-center gap-2.5 px-3 text-sm font-semibold lg:text-shell-foreground lg:rail:hidden", children: [_jsx(ProductBadge, { product: product, className: "size-[1.125rem] shrink-0" }), _jsx("span", { className: "truncate font-heading", children: familyProductName(product) })] })] }), nav] }))] }));
|
|
91
93
|
}
|
package/dist/product-bar.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProductView } from "./addresses.ts";
|
|
2
|
+
import { type ModuleWord } from "./modules.ts";
|
|
2
3
|
/**
|
|
3
4
|
* Réglage « Barre des produits » (ADR 0014 de la famille), choisi dans Account :
|
|
4
5
|
* - `auto` : la barre sous `app.hgdc.ch`, pas sur `<mot>.hgdc.ch` ;
|
|
@@ -13,7 +14,7 @@ export type ProductBarPreference = "auto" | "always" | "never";
|
|
|
13
14
|
export declare const PRODUCT_BAR_PREFERENCES: ReadonlyArray<ProductBarPreference>;
|
|
14
15
|
/** Libellés du réglage, dans l'ordre d'affichage. */
|
|
15
16
|
export declare const PRODUCT_BAR_LABELS: Readonly<Record<ProductBarPreference, string>>;
|
|
16
|
-
/**
|
|
17
|
+
/** Réglages chez Account : `{ productBar, moduleBar }`, rien d'autre. */
|
|
17
18
|
export declare const ACCOUNT_PREFERENCES_URL = "https://account.hgdc.ch/api/preferences";
|
|
18
19
|
/** Valeur reçue (Account, stockage) : un réglage connu, sinon `auto`. */
|
|
19
20
|
export declare function parseProductBar(value: unknown): ProductBarPreference;
|
|
@@ -25,5 +26,11 @@ export declare function rememberProductBar(preference: ProductBarPreference): vo
|
|
|
25
26
|
export declare function useProductBarPreference(): ProductBarPreference;
|
|
26
27
|
/** Relit le réglage chez Account une fois par chargement de page ; une erreur garde la dernière valeur. */
|
|
27
28
|
export declare function syncProductBar(fetchImpl?: typeof fetch): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Enregistre la barre des modules chez Account, pour la retrouver sur un autre appareil. Un échec n'est
|
|
31
|
+
* pas signalé : la barre reste réglée dans cette origine, et repart au prochain chargement.
|
|
32
|
+
* `keepalive` : un clic sur un autre module recharge la page, l'envoi doit y survivre.
|
|
33
|
+
*/
|
|
34
|
+
export declare function pushModuleBar(order: ReadonlyArray<ModuleWord>, fetchImpl?: typeof fetch): Promise<void>;
|
|
28
35
|
/** À monter une fois (la coque le fait) : relecture du réglage après l'hydratation. */
|
|
29
36
|
export declare function useProductBarSync(enabled?: boolean): void;
|
package/dist/product-bar.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { useEffect, useSyncExternalStore } from "react";
|
|
2
|
+
import { saveModuleBar, storedModuleBar } from "./module-bar-store.js";
|
|
3
|
+
import { parseModuleBar } from "./modules.js";
|
|
2
4
|
export const PRODUCT_BAR_PREFERENCES = ["auto", "always", "never"];
|
|
3
5
|
/** Libellés du réglage, dans l'ordre d'affichage. */
|
|
4
6
|
export const PRODUCT_BAR_LABELS = {
|
|
@@ -6,10 +8,12 @@ export const PRODUCT_BAR_LABELS = {
|
|
|
6
8
|
always: "Toujours",
|
|
7
9
|
never: "Jamais",
|
|
8
10
|
};
|
|
9
|
-
/**
|
|
11
|
+
/** Réglages chez Account : `{ productBar, moduleBar }`, rien d'autre. */
|
|
10
12
|
export const ACCOUNT_PREFERENCES_URL = "https://account.hgdc.ch/api/preferences";
|
|
11
13
|
const STORAGE_KEY = "hgdc-product-bar";
|
|
12
14
|
const EVENT = "hgdc-product-bar";
|
|
15
|
+
/** Présent tant qu'Account n'a pas confirmé la barre des modules réglée ici : elle ne doit pas être écrasée. */
|
|
16
|
+
const MODULE_BAR_UNSENT_KEY = "hgdc-shell:modules-unsent";
|
|
13
17
|
/** Valeur reçue (Account, stockage) : un réglage connu, sinon `auto`. */
|
|
14
18
|
export function parseProductBar(value) {
|
|
15
19
|
return PRODUCT_BAR_PREFERENCES.includes(value) ? value : "auto";
|
|
@@ -62,13 +66,69 @@ export async function syncProductBar(fetchImpl = fetch) {
|
|
|
62
66
|
if (!response.ok)
|
|
63
67
|
return;
|
|
64
68
|
const body = await response.json();
|
|
65
|
-
if (typeof body
|
|
69
|
+
if (typeof body !== "object" || body === null)
|
|
70
|
+
return;
|
|
71
|
+
if ("productBar" in body)
|
|
66
72
|
rememberProductBar(parseProductBar(body.productBar));
|
|
73
|
+
if (moduleBarUnsent()) {
|
|
74
|
+
await pushModuleBar(storedModuleBar(), fetchImpl);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Absente : la personne n'a encore rien réglé, cette origine garde ce qu'elle a.
|
|
78
|
+
if ("moduleBar" in body) {
|
|
79
|
+
const order = parseModuleBar(body.moduleBar);
|
|
80
|
+
if (order)
|
|
81
|
+
saveModuleBar(order);
|
|
82
|
+
}
|
|
67
83
|
}
|
|
68
84
|
catch {
|
|
69
85
|
// Account injoignable ou hors ligne : rien ne change.
|
|
70
86
|
}
|
|
71
87
|
}
|
|
88
|
+
function moduleBarUnsent() {
|
|
89
|
+
try {
|
|
90
|
+
return window.localStorage.getItem(MODULE_BAR_UNSENT_KEY) !== null;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function markModuleBarUnsent(unsent) {
|
|
97
|
+
try {
|
|
98
|
+
if (unsent)
|
|
99
|
+
window.localStorage.setItem(MODULE_BAR_UNSENT_KEY, "1");
|
|
100
|
+
else
|
|
101
|
+
window.localStorage.removeItem(MODULE_BAR_UNSENT_KEY);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Stockage bloqué : la prochaine relecture reprendra la valeur d'Account.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Enregistre la barre des modules chez Account, pour la retrouver sur un autre appareil. Un échec n'est
|
|
109
|
+
* pas signalé : la barre reste réglée dans cette origine, et repart au prochain chargement.
|
|
110
|
+
* `keepalive` : un clic sur un autre module recharge la page, l'envoi doit y survivre.
|
|
111
|
+
*/
|
|
112
|
+
export async function pushModuleBar(order, fetchImpl = fetch) {
|
|
113
|
+
// Account n'accepte que les consoles de `hgdc.ch` : en local, en test, rien à envoyer.
|
|
114
|
+
if (!window.location.hostname.endsWith(".hgdc.ch"))
|
|
115
|
+
return;
|
|
116
|
+
markModuleBarUnsent(true);
|
|
117
|
+
try {
|
|
118
|
+
const response = await fetchImpl(ACCOUNT_PREFERENCES_URL, {
|
|
119
|
+
method: "PUT",
|
|
120
|
+
credentials: "include",
|
|
121
|
+
keepalive: true,
|
|
122
|
+
headers: { "content-type": "application/json" },
|
|
123
|
+
body: JSON.stringify({ moduleBar: order }),
|
|
124
|
+
});
|
|
125
|
+
if (response.ok)
|
|
126
|
+
markModuleBarUnsent(false);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Account injoignable ou hors ligne.
|
|
130
|
+
}
|
|
131
|
+
}
|
|
72
132
|
let synced = false;
|
|
73
133
|
/** À monter une fois (la coque le fait) : relecture du réglage après l'hydratation. */
|
|
74
134
|
export function useProductBarSync(enabled = true) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hgdc/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.66.0",
|
|
4
4
|
"description": "Interface de la H Collection : jetons de la DA, thèmes, polices et composants.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://github.com/hugogebel-boop/hgdc-kit/tree/main/packages/ui#readme",
|