@hgdc/ui 0.40.0 → 0.42.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 +17 -16
- package/dist/addresses.d.ts +64 -0
- package/dist/addresses.js +73 -0
- package/dist/choice-cards.d.ts +28 -0
- package/dist/choice-cards.js +18 -0
- package/dist/products.d.ts +3 -7
- package/dist/products.js +5 -15
- package/dist/steps.d.ts +18 -0
- package/dist/steps.js +16 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,22 +44,23 @@ Primitives déjà là : `avatar` `badge` `button` `dialog` `drawer` `dropdown-me
|
|
|
44
44
|
|
|
45
45
|
## Coque des consoles
|
|
46
46
|
|
|
47
|
-
| Import | Exemple
|
|
48
|
-
| ------------------ |
|
|
49
|
-
| `app-shell` | `<AppShell product="mail" organization={<OrgSwitcher …/>} nav={<SidebarNav label="Projet">…</SidebarNav>} links={{ documentation: "/docs", settings: { render: <Link to="/settings" /> } }} account={<AccountMenu …/>} onSearch={() => setOpen(true)} assistant={{ open, onOpenChange: setOpen, panel: <Conversation /> }}>` : Documentation, Réglages et État du service (la page de statut par défaut) juste au-dessus du compte ; bouton Assistant à côté de la recherche, panneau dans une colonne à droite (la page se rétrécit, vue dédiée sous 1280 px, Échap ferme, `shortcut: "j"` facultatif). `sidebarFooter` est déprécié
|
|
50
|
-
| | `<SidebarNavItem icon={Rocket01Icon} label="Déploiements" render={<Link to="/deployments" />} />`
|
|
51
|
-
| | Navigation imbriquée (l'espace d'une page, d'un projet) : `<SidebarNavBack label="Retour aux pages" render={<Link to="/pages" />} />` en tête, puis `<SidebarNavGroup label="Suivi">…</SidebarNavGroup>` (titre muet, trait en rail), ou `<SidebarNavGroup label="Réglages" collapsible icon={…} active={…}>` (entrée à flèche qui déroule ses rubriques, fermée par défaut, ouverte sur une rubrique active, mémorisée par navigateur)
|
|
52
|
-
| `org-switcher` | `<OrgSwitcher organizations={orgs} activeId={org.id} onSelect={go} createHref="/organisations/nouvelle" />`
|
|
53
|
-
| `project-switcher` | `<ProjectSwitcher projects={projects} activeId={project?.id} activeName={params.project} allHref="/o/acme" createHref="/o/acme/new" renderLink={(href) => <Link to={href} />} />` : projet actif ou « Tous les projets », marque du projet (`ProjectMark`), « Nouveau projet »
|
|
54
|
-
| `account-menu` | `<AccountMenu user={user} onProfile={…} onSecurity={…} onSignOut={signOut} product="Mail" />` : Account et les produits ouverts du catalogue, Mail coché. Dans l'ordre : identité, Profil, Sécurité, Thème (Système, Clair, Sombre, `ThemeSwitch`), entrées du produit, Se déconnecter. Ni « État du service » ni raccourcis : la coque pose le premier au-dessus du compte, l'aide garde sa touche `?`
|
|
55
|
-
| `command-menu` | `<CommandMenu groups={[{ label: "Aller à", items }, { label: "Créer", items }, { label: "Changer", items }]} />` (`Ctrl+K`), `<CommandMenuButton compact="mobile" …/>`
|
|
56
|
-
| `products` | `HGDC_PRODUCTS` (mot, nom, sous-domaine, phrase, pastille `badge`, icône, état, `entryHref`), `HGDC_ACCOUNT`, `productMenuEntries({ current: "Mail" })` : chaque produit du menu pointe vers son entrée `/auth/hgdc` (ADR 0010)
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `page-header` | `<
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
47
|
+
| Import | Exemple |
|
|
48
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `app-shell` | `<AppShell product="mail" organization={<OrgSwitcher …/>} nav={<SidebarNav label="Projet">…</SidebarNav>} links={{ documentation: "/docs", settings: { render: <Link to="/settings" /> } }} account={<AccountMenu …/>} onSearch={() => setOpen(true)} assistant={{ open, onOpenChange: setOpen, panel: <Conversation /> }}>` : Documentation, Réglages et État du service (la page de statut par défaut) juste au-dessus du compte ; bouton Assistant à côté de la recherche, panneau dans une colonne à droite (la page se rétrécit, vue dédiée sous 1280 px, Échap ferme, `shortcut: "j"` facultatif). `sidebarFooter` est déprécié |
|
|
50
|
+
| | `<SidebarNavItem icon={Rocket01Icon} label="Déploiements" render={<Link to="/deployments" />} />` |
|
|
51
|
+
| | Navigation imbriquée (l'espace d'une page, d'un projet) : `<SidebarNavBack label="Retour aux pages" render={<Link to="/pages" />} />` en tête, puis `<SidebarNavGroup label="Suivi">…</SidebarNavGroup>` (titre muet, trait en rail), ou `<SidebarNavGroup label="Réglages" collapsible icon={…} active={…}>` (entrée à flèche qui déroule ses rubriques, fermée par défaut, ouverte sur une rubrique active, mémorisée par navigateur) |
|
|
52
|
+
| `org-switcher` | `<OrgSwitcher organizations={orgs} activeId={org.id} onSelect={go} createHref="/organisations/nouvelle" />` |
|
|
53
|
+
| `project-switcher` | `<ProjectSwitcher projects={projects} activeId={project?.id} activeName={params.project} allHref="/o/acme" createHref="/o/acme/new" renderLink={(href) => <Link to={href} />} />` : projet actif ou « Tous les projets », marque du projet (`ProjectMark`), « Nouveau projet » |
|
|
54
|
+
| `account-menu` | `<AccountMenu user={user} onProfile={…} onSecurity={…} onSignOut={signOut} product="Mail" />` : Account et les produits ouverts du catalogue, Mail coché. Dans l'ordre : identité, Profil, Sécurité, Thème (Système, Clair, Sombre, `ThemeSwitch`), entrées du produit, Se déconnecter. Ni « État du service » ni raccourcis : la coque pose le premier au-dessus du compte, l'aide garde sa touche `?` |
|
|
55
|
+
| `command-menu` | `<CommandMenu groups={[{ label: "Aller à", items }, { label: "Créer", items }, { label: "Changer", items }]} />` (`Ctrl+K`), `<CommandMenuButton compact="mobile" …/>` |
|
|
56
|
+
| `products` | `HGDC_PRODUCTS` (mot, nom, sous-domaine, phrase, pastille `badge`, icône, état, `entryHref`), `HGDC_ACCOUNT`, `productMenuEntries({ current: "Mail" })` : chaque produit du menu pointe vers son entrée `/auth/hgdc` (ADR 0010) |
|
|
57
|
+
| `addresses` | Adresses d'un produit déduites de son mot, sans React (lisible par `vite.config.ts` et Convex) : `productAddresses("mail", import.meta.env)` rend `basePath`, `appOrigin`, `appUrl` (`https://app.hgdc.ch/mail`), `convexUrl` (`https://convex.mail.hgdc.ch`), `convexSiteUrl`, `withBase`. `productBasePath("mail", { override: process.env.HGDC_BASE_PATH, command })` donne la base du build : `/mail` pour `vite build`, la racine pour `vite dev` et Vitest. `APP_PRODUCTS` : produits servis sous `app.hgdc.ch` (d'où `PRODUCT_ORIGINS`). Surcharges : `HGDC_BASE_PATH` (`/` : racine), `VITE_CONVEX_URL`, `VITE_CONVEX_SITE_URL` |
|
|
58
|
+
| `service-status` | Bandeau d'incident ou de maintenance posé par `AppShell` en tête du contenu (ADR 0018) : `useServiceStatus(pageUrl)`, `ServiceStatusBanner`. `statusPage={false}` pour ne rien lire |
|
|
59
|
+
| `kbd` | `<KbdGroup><Kbd>Ctrl</Kbd><Kbd>K</Kbd></KbdGroup>` |
|
|
60
|
+
| `page-header` | `<PageHeader title="Domaines" breadcrumbs={[{ label: "Acme", render: <Link to="/o/acme" /> }, { label: "Domaines" }]} actions={<Button>Ajouter</Button>} />` |
|
|
61
|
+
| `page-header` | `<Page title="Réglages">…</Page>` (colonne de lecture de 768 px), `<Page title="Projets" wide actions={…}>…</Page>` (tableaux, listes, tableaux de bord) |
|
|
62
|
+
| `member-item` | `<ResourceList><MemberItem name={m.name} email={m.email} orgRole={m.role} isMe={m.isMe} /></ResourceList>` : avatar à initiales, « (toi) », `RoleBadge` |
|
|
63
|
+
| `initials` | `initials("Test vérif")` donne « TV » : la même règle pour une personne et une organisation (`OrgMark`, `AccountMenu`, `MemberItem`) ; `avatarTone(email)` donne la teinte stable (1 à 7) de l'avatar |
|
|
63
64
|
|
|
64
65
|
Le menu « Produits » et la palette (`badge` d'une commande) montrent la pastille de chaque produit.
|
|
65
66
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adresses d'un produit de la H Collection, déduites de son mot (ADR 0001 et 0005 de la famille) :
|
|
3
|
+
* console sous `https://app.hgdc.ch/<mot>`, Convex sur `https://convex.<mot>.hgdc.ch` et
|
|
4
|
+
* `https://actions.<mot>.hgdc.ch`. Écrites une fois ici, au lieu de variables posées sur Host et
|
|
5
|
+
* Vercel puis recopiées dans chaque produit. Une surcharge reste possible : développement local
|
|
6
|
+
* (Convex de dev, app à la racine), bacs à sable, Status et ses deux builds.
|
|
7
|
+
*
|
|
8
|
+
* Sans dépendance ni React : lisible par `vite.config.ts`, le serveur, le navigateur et Convex.
|
|
9
|
+
*/
|
|
10
|
+
/** Hôte commun des produits relayés par la passerelle. */
|
|
11
|
+
export declare const APP_ORIGIN = "https://app.hgdc.ch";
|
|
12
|
+
/**
|
|
13
|
+
* Produits servis sous `https://app.hgdc.ch/<mot>` (consoles relayées par la passerelle, ADR 0005).
|
|
14
|
+
* Account (fournisseur d'identité) et Portal (pas encore relayé) gardent leur hôte. Status : la
|
|
15
|
+
* console seule, `status.hgdc.ch` garde les pages publiques et la console de secours. Vérifiée contre
|
|
16
|
+
* le manifeste privé de la famille (`famille check`) : un produit relayé s'ajoute ici et là.
|
|
17
|
+
*/
|
|
18
|
+
export declare const APP_PRODUCTS: readonly ["analytics", "mail", "host", "docs", "status"];
|
|
19
|
+
/** Vrai si le produit est servi sous `app.hgdc.ch`. */
|
|
20
|
+
export declare function isAppProduct(product: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Base de chemin normalisée : `""` (racine) ou `/segment`, sans barre finale. Même règle que
|
|
23
|
+
* `normalizeBasePath` de `@hgdc/auth` : lève sur tout ce qui n'est pas un chemin de segments simples.
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeProductBasePath(value: string | null | undefined): string;
|
|
26
|
+
/**
|
|
27
|
+
* Base de chemin du build, pour `vite.config.ts` : `/<mot>` pour `vite build` d'un produit servi
|
|
28
|
+
* sous app.hgdc.ch, la racine pour `vite dev` et Vitest (`command` = `serve`) et pour les autres
|
|
29
|
+
* produits. `override` (la variable `HGDC_BASE_PATH`, si elle est posée) l'emporte : `/` force la
|
|
30
|
+
* racine (build de `status.hgdc.ch`).
|
|
31
|
+
*/
|
|
32
|
+
export declare function productBasePath(product: string, options?: {
|
|
33
|
+
override?: string | undefined;
|
|
34
|
+
command?: "build" | "serve" | undefined;
|
|
35
|
+
}): string;
|
|
36
|
+
/** Surcharges lues dans `import.meta.env` de Vite : absentes ou vides, la convention s'applique. */
|
|
37
|
+
export type AddressOverrides = {
|
|
38
|
+
/** Base du build telle que Vite la pose (`/mail/`, `/` à la racine). */
|
|
39
|
+
BASE_URL?: string | undefined;
|
|
40
|
+
/** Convex de développement (écrit par `convex dev` dans `.env.local`) ou d'un bac à sable. */
|
|
41
|
+
VITE_CONVEX_URL?: string | undefined;
|
|
42
|
+
VITE_CONVEX_SITE_URL?: string | undefined;
|
|
43
|
+
};
|
|
44
|
+
export type ProductAddresses = {
|
|
45
|
+
/** Base de chemin : `/mail`, ou `""` à la racine. */
|
|
46
|
+
basePath: string;
|
|
47
|
+
/** Origine publique de l'app : `https://app.hgdc.ch`, ou `https://<mot>.hgdc.ch` à la racine. */
|
|
48
|
+
appOrigin: string;
|
|
49
|
+
/** Adresse publique de l'app, sans barre finale : `https://app.hgdc.ch/mail`. */
|
|
50
|
+
appUrl: string;
|
|
51
|
+
/** Client Convex : `https://convex.<mot>.hgdc.ch`. */
|
|
52
|
+
convexUrl: string;
|
|
53
|
+
/** Actions HTTP de Convex : `https://actions.<mot>.hgdc.ch`. */
|
|
54
|
+
convexSiteUrl: string;
|
|
55
|
+
/** `withBase("/o/acme")` : `/mail/o/acme` sous la base, `/o/acme` à la racine. */
|
|
56
|
+
withBase: (path: string) => string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Adresses d'un produit, d'après son mot. Dans l'app : `productAddresses("mail", import.meta.env)`
|
|
60
|
+
* (la base vient alors du build, `BASE_URL`, et un Convex de dev de `.env.local`). Sans `env` : la
|
|
61
|
+
* production. Les adresses publiques sont des constantes, jamais tirées d'une requête (`Host`,
|
|
62
|
+
* `x-forwarded-host` valent l'origine relayée).
|
|
63
|
+
*/
|
|
64
|
+
export declare function productAddresses(product: string, env?: AddressOverrides): ProductAddresses;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adresses d'un produit de la H Collection, déduites de son mot (ADR 0001 et 0005 de la famille) :
|
|
3
|
+
* console sous `https://app.hgdc.ch/<mot>`, Convex sur `https://convex.<mot>.hgdc.ch` et
|
|
4
|
+
* `https://actions.<mot>.hgdc.ch`. Écrites une fois ici, au lieu de variables posées sur Host et
|
|
5
|
+
* Vercel puis recopiées dans chaque produit. Une surcharge reste possible : développement local
|
|
6
|
+
* (Convex de dev, app à la racine), bacs à sable, Status et ses deux builds.
|
|
7
|
+
*
|
|
8
|
+
* Sans dépendance ni React : lisible par `vite.config.ts`, le serveur, le navigateur et Convex.
|
|
9
|
+
*/
|
|
10
|
+
/** Hôte commun des produits relayés par la passerelle. */
|
|
11
|
+
export const APP_ORIGIN = "https://app.hgdc.ch";
|
|
12
|
+
/**
|
|
13
|
+
* Produits servis sous `https://app.hgdc.ch/<mot>` (consoles relayées par la passerelle, ADR 0005).
|
|
14
|
+
* Account (fournisseur d'identité) et Portal (pas encore relayé) gardent leur hôte. Status : la
|
|
15
|
+
* console seule, `status.hgdc.ch` garde les pages publiques et la console de secours. Vérifiée contre
|
|
16
|
+
* le manifeste privé de la famille (`famille check`) : un produit relayé s'ajoute ici et là.
|
|
17
|
+
*/
|
|
18
|
+
export const APP_PRODUCTS = ["analytics", "mail", "host", "docs", "status"];
|
|
19
|
+
/** Vrai si le produit est servi sous `app.hgdc.ch`. */
|
|
20
|
+
export function isAppProduct(product) {
|
|
21
|
+
return APP_PRODUCTS.includes(product.toLowerCase());
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Base de chemin normalisée : `""` (racine) ou `/segment`, sans barre finale. Même règle que
|
|
25
|
+
* `normalizeBasePath` de `@hgdc/auth` : lève sur tout ce qui n'est pas un chemin de segments simples.
|
|
26
|
+
*/
|
|
27
|
+
export function normalizeProductBasePath(value) {
|
|
28
|
+
if (value === undefined || value === null || value === "" || value === "/")
|
|
29
|
+
return "";
|
|
30
|
+
const trimmed = value.endsWith("/") ? value.slice(0, -1) : value;
|
|
31
|
+
const segments = trimmed.split("/");
|
|
32
|
+
const valid = segments[0] === "" &&
|
|
33
|
+
segments.length > 1 &&
|
|
34
|
+
segments.slice(1).every((segment) => /^[A-Za-z0-9._~-]+$/.test(segment) && segment !== "." && segment !== "..");
|
|
35
|
+
if (!valid)
|
|
36
|
+
throw new Error(`@hgdc/ui/addresses : base invalide (${JSON.stringify(value)}), attendu « /produit ».`);
|
|
37
|
+
return trimmed;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Base de chemin du build, pour `vite.config.ts` : `/<mot>` pour `vite build` d'un produit servi
|
|
41
|
+
* sous app.hgdc.ch, la racine pour `vite dev` et Vitest (`command` = `serve`) et pour les autres
|
|
42
|
+
* produits. `override` (la variable `HGDC_BASE_PATH`, si elle est posée) l'emporte : `/` force la
|
|
43
|
+
* racine (build de `status.hgdc.ch`).
|
|
44
|
+
*/
|
|
45
|
+
export function productBasePath(product, options = {}) {
|
|
46
|
+
if (options.override !== undefined && options.override !== "")
|
|
47
|
+
return normalizeProductBasePath(options.override);
|
|
48
|
+
if (options.command === "serve" || !isAppProduct(product))
|
|
49
|
+
return "";
|
|
50
|
+
return `/${product.toLowerCase()}`;
|
|
51
|
+
}
|
|
52
|
+
const nonEmpty = (value) => (value ? value : undefined);
|
|
53
|
+
/**
|
|
54
|
+
* Adresses d'un produit, d'après son mot. Dans l'app : `productAddresses("mail", import.meta.env)`
|
|
55
|
+
* (la base vient alors du build, `BASE_URL`, et un Convex de dev de `.env.local`). Sans `env` : la
|
|
56
|
+
* production. Les adresses publiques sont des constantes, jamais tirées d'une requête (`Host`,
|
|
57
|
+
* `x-forwarded-host` valent l'origine relayée).
|
|
58
|
+
*/
|
|
59
|
+
export function productAddresses(product, env = {}) {
|
|
60
|
+
const word = product.toLowerCase();
|
|
61
|
+
if (!/^[a-z]+$/.test(word))
|
|
62
|
+
throw new Error(`@hgdc/ui/addresses : produit invalide « ${product} »`);
|
|
63
|
+
const basePath = env.BASE_URL !== undefined ? normalizeProductBasePath(env.BASE_URL) : productBasePath(word);
|
|
64
|
+
const appOrigin = basePath ? APP_ORIGIN : `https://${word}.hgdc.ch`;
|
|
65
|
+
return {
|
|
66
|
+
basePath,
|
|
67
|
+
appOrigin,
|
|
68
|
+
appUrl: `${appOrigin}${basePath}`,
|
|
69
|
+
convexUrl: nonEmpty(env.VITE_CONVEX_URL) ?? `https://convex.${word}.hgdc.ch`,
|
|
70
|
+
convexSiteUrl: nonEmpty(env.VITE_CONVEX_SITE_URL) ?? `https://actions.${word}.hgdc.ch`,
|
|
71
|
+
withBase: (path) => `${basePath}${path}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
type ChoiceCardsProps<T extends string> = {
|
|
2
|
+
value: T | null;
|
|
3
|
+
onValueChange: (value: T) => void;
|
|
4
|
+
options: Array<{
|
|
5
|
+
value: T;
|
|
6
|
+
title: string;
|
|
7
|
+
/** Une ligne sous le titre : ce que recouvre le choix. */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Logo ou icône, 24 px environ. */
|
|
10
|
+
icon?: React.ReactNode;
|
|
11
|
+
}>;
|
|
12
|
+
/** Nom du groupe pour les technologies d'assistance. */
|
|
13
|
+
label: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Un choix parmi quelques options riches, présentées en tuiles : l'outil à brancher, un
|
|
18
|
+
* modèle de départ. Deux colonnes sur téléphone, trois au-delà ; chaque tuile garde une cible
|
|
19
|
+
* de 44 px au moins. Sémantique de groupe radio : les flèches passent d'une tuile à l'autre,
|
|
20
|
+
* Tab sort du groupe.
|
|
21
|
+
*
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <ChoiceCards label="Outil" value={tool} onValueChange={setTool}
|
|
24
|
+
* options={[{ value: "grafana", title: "Grafana", description: "Contact point Webhook" }]} />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function ChoiceCards<T extends string>({ value, onValueChange, options, label, className, }: ChoiceCardsProps<T>): React.JSX.Element;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Radio as RadioPrimitive } from "@base-ui/react/radio";
|
|
3
|
+
import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";
|
|
4
|
+
import { cn } from "./cn.js";
|
|
5
|
+
/**
|
|
6
|
+
* Un choix parmi quelques options riches, présentées en tuiles : l'outil à brancher, un
|
|
7
|
+
* modèle de départ. Deux colonnes sur téléphone, trois au-delà ; chaque tuile garde une cible
|
|
8
|
+
* de 44 px au moins. Sémantique de groupe radio : les flèches passent d'une tuile à l'autre,
|
|
9
|
+
* Tab sort du groupe.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <ChoiceCards label="Outil" value={tool} onValueChange={setTool}
|
|
13
|
+
* options={[{ value: "grafana", title: "Grafana", description: "Contact point Webhook" }]} />
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function ChoiceCards({ value, onValueChange, options, label, className, }) {
|
|
17
|
+
return (_jsx(RadioGroupPrimitive, { "data-slot": "choice-cards", "aria-label": label, value: value, onValueChange: (next) => onValueChange(next), className: cn("grid grid-cols-2 gap-2 sm:grid-cols-3 sm:gap-3", className), children: options.map((option) => (_jsxs(RadioPrimitive.Root, { value: option.value, "aria-label": option.description ? `${option.title}, ${option.description}` : option.title, className: cn("flex min-h-11 flex-col items-start gap-2 rounded-2xl border border-border bg-card p-3 text-left sm:p-4", "transition-[border-color,box-shadow,background-color] duration-(--duration-fast) ease-out outline-none", "hover:border-foreground/40 focus-visible:ring-3 focus-visible:ring-ring/50", "data-checked:border-primary data-checked:bg-primary/5 data-checked:ring-1 data-checked:ring-primary", "data-disabled:cursor-not-allowed data-disabled:opacity-50"), children: [option.icon ? (_jsx("span", { "aria-hidden": true, className: "grid size-8 place-items-center text-foreground", children: option.icon })) : null, _jsx("span", { className: "text-sm font-medium text-pretty", children: option.title }), option.description ? (_jsx("span", { className: "text-xs text-pretty text-muted-foreground", children: option.description })) : null] }, option.value))) }));
|
|
18
|
+
}
|
package/dist/products.d.ts
CHANGED
|
@@ -47,13 +47,9 @@ export type ProductOrigin = {
|
|
|
47
47
|
basePath: string;
|
|
48
48
|
};
|
|
49
49
|
/**
|
|
50
|
-
* Adresse de l'app de chaque produit
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* ```ts
|
|
55
|
-
* analytics: { origin: "https://app.hgdc.ch", basePath: "/analytics" },
|
|
56
|
-
* ```
|
|
50
|
+
* Adresse de l'app de chaque produit servi sous `https://app.hgdc.ch/<mot>`, par mot en minuscules,
|
|
51
|
+
* déduite d'`APP_PRODUCTS` (`@hgdc/ui/addresses`). Un autre produit reste à `https://<mot>.hgdc.ch`
|
|
52
|
+
* sans base.
|
|
57
53
|
*
|
|
58
54
|
* Ne change que l'entrée dans l'app (`entryHref`, menus et barre) : la page d'accueil publique
|
|
59
55
|
* (`href`) reste `https://<mot>.hgdc.ch`.
|
package/dist/products.js
CHANGED
|
@@ -5,6 +5,7 @@ import Briefcase01Icon from "@hugeicons/core-free-icons/Briefcase01Icon";
|
|
|
5
5
|
import Mail01Icon from "@hugeicons/core-free-icons/Mail01Icon";
|
|
6
6
|
import Rocket01Icon from "@hugeicons/core-free-icons/Rocket01Icon";
|
|
7
7
|
import UserCircleIcon from "@hugeicons/core-free-icons/UserCircleIcon";
|
|
8
|
+
import { APP_ORIGIN, APP_PRODUCTS } from "./addresses.js";
|
|
8
9
|
import { HGDC_EMAIL_ACCENT } from "./email-palette.js";
|
|
9
10
|
import { isFamilyProduct } from "./family-svg.js";
|
|
10
11
|
export const PRODUCT_STAGE_LABEL = {
|
|
@@ -19,25 +20,14 @@ export const PRODUCT_STAGE_LABEL = {
|
|
|
19
20
|
*/
|
|
20
21
|
export const PRODUCT_ENTRY_PATH = "/auth/hgdc";
|
|
21
22
|
/**
|
|
22
|
-
* Adresse de l'app de chaque produit
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* ```ts
|
|
27
|
-
* analytics: { origin: "https://app.hgdc.ch", basePath: "/analytics" },
|
|
28
|
-
* ```
|
|
23
|
+
* Adresse de l'app de chaque produit servi sous `https://app.hgdc.ch/<mot>`, par mot en minuscules,
|
|
24
|
+
* déduite d'`APP_PRODUCTS` (`@hgdc/ui/addresses`). Un autre produit reste à `https://<mot>.hgdc.ch`
|
|
25
|
+
* sans base.
|
|
29
26
|
*
|
|
30
27
|
* Ne change que l'entrée dans l'app (`entryHref`, menus et barre) : la page d'accueil publique
|
|
31
28
|
* (`href`) reste `https://<mot>.hgdc.ch`.
|
|
32
29
|
*/
|
|
33
|
-
export const PRODUCT_ORIGINS = {
|
|
34
|
-
analytics: { origin: "https://app.hgdc.ch", basePath: "/analytics" },
|
|
35
|
-
mail: { origin: "https://app.hgdc.ch", basePath: "/mail" },
|
|
36
|
-
host: { origin: "https://app.hgdc.ch", basePath: "/host" },
|
|
37
|
-
docs: { origin: "https://app.hgdc.ch", basePath: "/docs" },
|
|
38
|
-
// Console seule : status.hgdc.ch reste l'adresse des pages publiques et la console de secours.
|
|
39
|
-
status: { origin: "https://app.hgdc.ch", basePath: "/status" },
|
|
40
|
-
};
|
|
30
|
+
export const PRODUCT_ORIGINS = Object.fromEntries(APP_PRODUCTS.map((word) => [word, { origin: APP_ORIGIN, basePath: `/${word}` }]));
|
|
41
31
|
/** Adresse de l'app d'un produit : celle de `PRODUCT_ORIGINS`, sinon `https://<mot>.hgdc.ch`. */
|
|
42
32
|
export function productOrigin(word, origins = PRODUCT_ORIGINS) {
|
|
43
33
|
const key = word.toLowerCase();
|
package/dist/steps.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marche à suivre numérotée, courte (3 à 5 étapes) : brancher un outil, configurer un DNS.
|
|
3
|
+
* Une étape = une phrase d'action ; le détail facultatif passe dessous, en plus petit.
|
|
4
|
+
*
|
|
5
|
+
* ```tsx
|
|
6
|
+
* <Steps items={[
|
|
7
|
+
* { title: "Dans Grafana, ouvre Alerting puis Contact points." },
|
|
8
|
+
* { title: "Ajoute un contact point Webhook et colle l'adresse.", detail: <Snippet value={url} /> },
|
|
9
|
+
* ]} />
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare function Steps({ items, className, }: {
|
|
13
|
+
items: Array<{
|
|
14
|
+
title: React.ReactNode;
|
|
15
|
+
detail?: React.ReactNode;
|
|
16
|
+
}>;
|
|
17
|
+
className?: string;
|
|
18
|
+
}): React.JSX.Element;
|
package/dist/steps.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "./cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* Marche à suivre numérotée, courte (3 à 5 étapes) : brancher un outil, configurer un DNS.
|
|
5
|
+
* Une étape = une phrase d'action ; le détail facultatif passe dessous, en plus petit.
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <Steps items={[
|
|
9
|
+
* { title: "Dans Grafana, ouvre Alerting puis Contact points." },
|
|
10
|
+
* { title: "Ajoute un contact point Webhook et colle l'adresse.", detail: <Snippet value={url} /> },
|
|
11
|
+
* ]} />
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function Steps({ items, className, }) {
|
|
15
|
+
return (_jsx("ol", { "data-slot": "steps", className: cn("space-y-4", className), children: items.map((item, index) => (_jsxs("li", { className: "flex gap-3", children: [_jsx("span", { "aria-hidden": true, className: "grid size-6 shrink-0 place-items-center rounded-full bg-muted text-xs font-semibold tabular-nums", children: index + 1 }), _jsxs("div", { className: "min-w-0 flex-1 space-y-2 pt-0.5", children: [_jsx("p", { className: "text-sm text-pretty", children: item.title }), item.detail ? _jsx("div", { className: "text-sm text-muted-foreground", children: item.detail }) : null] })] }, index))) }));
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hgdc/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.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",
|