@cloudgrid-io/ui 0.2.0 → 0.4.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 +1 -1
- package/dist/blocks/entity-card.d.ts +89 -0
- package/dist/blocks/entity-card.d.ts.map +1 -0
- package/dist/blocks/entity-card.js +35 -0
- package/dist/blocks/entity-card.js.map +1 -0
- package/dist/blocks/entity-identity.d.ts +127 -0
- package/dist/blocks/entity-identity.d.ts.map +1 -0
- package/dist/blocks/entity-identity.js +127 -0
- package/dist/blocks/entity-identity.js.map +1 -0
- package/dist/blocks/entity-status.d.ts +97 -0
- package/dist/blocks/entity-status.d.ts.map +1 -0
- package/dist/blocks/entity-status.js +146 -0
- package/dist/blocks/entity-status.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/theme.css +30 -0
- package/dist/tokens/base.json +19 -1
- package/dist/tokens/surface-ink.json +19 -1
- package/dist/tokens/surface-panel.json +19 -1
- package/dist/tokens.css +30 -3
- package/dist/tokens.json +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The CloudGrid design system: CSS custom properties, a Tailwind v4 theme, self-hosted
|
|
4
4
|
fonts, and the same values as machine-readable JSON.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
46 React components, built on [Base UI](https://base-ui.com), styled only through tokens
|
|
7
7
|
and carrying no hardcoded colour.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The card an entity gets everywhere it is listed: a preview, a name, an
|
|
3
|
+
* address, a line about it, whatever state it is in, and a stat or two.
|
|
4
|
+
*
|
|
5
|
+
* Absorbed out of the console (#117), where the same composition serves the
|
|
6
|
+
* discover list, the discover map, my stuff, home, space pages and the inspired
|
|
7
|
+
* runtimes row. This library previously had `Card`, which is a shell — header,
|
|
8
|
+
* title, description, content, footer — and every CloudGrid-specific thing about
|
|
9
|
+
* an entity card was hand-built downstream and out of the designer's reach.
|
|
10
|
+
*
|
|
11
|
+
* This is the shell, not the console's card. It takes data as props and holds no
|
|
12
|
+
* product rules: it does not build URLs, does not know the wire status
|
|
13
|
+
* vocabulary, does not resolve visibility or permissions, does not fetch, and
|
|
14
|
+
* does not route. All of that stays where it belongs. A design system that
|
|
15
|
+
* learns the product's rules stops being a design system.
|
|
16
|
+
*
|
|
17
|
+
* ## Two tiers of preview, and neither can fail dark
|
|
18
|
+
*
|
|
19
|
+
* `seed` turns the preview region on. With `seed` alone the card shows the
|
|
20
|
+
* generative identity tile (`EntityIdentity`), derived from the id and the title
|
|
21
|
+
* with no network access at all. Add `previewUrl` and a real capture paints over
|
|
22
|
+
* it.
|
|
23
|
+
*
|
|
24
|
+
* The capture is a background image rather than an `<img>`, which is the one
|
|
25
|
+
* deliberate departure from the console's implementation. A background image
|
|
26
|
+
* that 404s paints nothing and the identity underneath simply shows through — so
|
|
27
|
+
* the fallback needs no `onError`, no `useState`, and therefore no client
|
|
28
|
+
* boundary on a card that is otherwise entirely static. The console needs its
|
|
29
|
+
* state only to hide a broken `<img>`.
|
|
30
|
+
*
|
|
31
|
+
* That costs the preview an `alt`. It is the right trade here: the console's own
|
|
32
|
+
* identity card is `aria-hidden` whenever a title sits beside it, because
|
|
33
|
+
* announcing a decorative preview after the title reads the card twice.
|
|
34
|
+
*
|
|
35
|
+
* ## Status is a slot
|
|
36
|
+
*
|
|
37
|
+
* `status` takes a node, not a status name. `EntityStatus` is a separate
|
|
38
|
+
* component with the nine-status CloudGrid vocabulary in it; putting that
|
|
39
|
+
* vocabulary in the card would mean the card knows what an entity can BE, which
|
|
40
|
+
* is product knowledge. The console maps its wire status through its own table
|
|
41
|
+
* and drops the result in here.
|
|
42
|
+
*
|
|
43
|
+
* ## Surfaces
|
|
44
|
+
*
|
|
45
|
+
* The chrome flips: ground, hairlines, title, body text and the stat rule all
|
|
46
|
+
* come from tokens, so `data-cg-surface="panel"` on any ancestor moves them
|
|
47
|
+
* together. The identity tile deliberately does not flip — see its own note; it
|
|
48
|
+
* is a picture, and a picture does not flip.
|
|
49
|
+
*/
|
|
50
|
+
export interface EntityCardStat {
|
|
51
|
+
/**
|
|
52
|
+
* A small decorative glyph, 14 to 16px. `label` is what gets announced, so
|
|
53
|
+
* the glyph itself should carry no accessible name.
|
|
54
|
+
*/
|
|
55
|
+
icon?: React.ReactNode;
|
|
56
|
+
value: React.ReactNode;
|
|
57
|
+
/** Names the stat, e.g. "Views". Rendered for assistive tech. */
|
|
58
|
+
label: string;
|
|
59
|
+
}
|
|
60
|
+
declare function EntityCard({ title, slug, description, titleLines, descriptionLines, status, stats, seed, previewUrl, href, ariaLabel, meta, footer, className, children, ...props }: Omit<React.ComponentProps<"div">, "ref" | "title"> & {
|
|
61
|
+
title: string;
|
|
62
|
+
/** The entity's address, in the mono utility face. */
|
|
63
|
+
slug?: string;
|
|
64
|
+
description?: string;
|
|
65
|
+
titleLines?: 1 | 2;
|
|
66
|
+
descriptionLines?: 1 | 2;
|
|
67
|
+
/** Top right of the header row. Drop an `EntityStatus` in. */
|
|
68
|
+
status?: React.ReactNode;
|
|
69
|
+
stats?: EntityCardStat[];
|
|
70
|
+
/**
|
|
71
|
+
* The entity's stable id. Its presence is what turns the preview region on,
|
|
72
|
+
* and its value is what picks the identity look. Pass the id, not the title.
|
|
73
|
+
*/
|
|
74
|
+
seed?: string;
|
|
75
|
+
/** A real capture, painted over the identity tile. A miss falls back to it. */
|
|
76
|
+
previewUrl?: string;
|
|
77
|
+
/** When set, the whole card is the target. A plain anchor: routing is yours. */
|
|
78
|
+
href?: string;
|
|
79
|
+
/** Accessible name for the whole-card link. Defaults to `title`. */
|
|
80
|
+
ariaLabel?: string;
|
|
81
|
+
/** Between the description and the stats. The console puts its residence line here. */
|
|
82
|
+
meta?: React.ReactNode;
|
|
83
|
+
/** Below everything, under no rule of its own. */
|
|
84
|
+
footer?: React.ReactNode;
|
|
85
|
+
/** Replaces the whole body. The preview and the card chrome still render. */
|
|
86
|
+
children?: React.ReactNode;
|
|
87
|
+
}): import("react").JSX.Element;
|
|
88
|
+
export { EntityCard };
|
|
89
|
+
//# sourceMappingURL=entity-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-card.d.ts","sourceRoot":"","sources":["../../src/blocks/entity-card.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;CACd;AAED,iBAAS,UAAU,CAAC,EAClB,KAAK,EACL,IAAI,EACJ,WAAW,EACX,UAAc,EACd,gBAAoB,EACpB,MAAM,EACN,KAAK,EACL,IAAI,EACJ,UAAU,EACV,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,MAAM,EACN,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,GAAG;IACtD,KAAK,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IAClB,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IACxB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAA;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uFAAuF;IACvF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,kDAAkD;IAClD,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,+BAwIA;AAED,OAAO,EAAE,UAAU,EAAE,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Card } from "../ui/card.js";
|
|
3
|
+
import { EntityIdentity } from "./entity-identity.js";
|
|
4
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
5
|
+
function EntityCard({ title, slug, description, titleLines = 2, descriptionLines = 1, status, stats, seed, previewUrl, href, ariaLabel, meta, footer, className, children, ...props }) {
|
|
6
|
+
const body = children ??
|
|
7
|
+
(_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("span", { dir: "auto", "data-slot": "entity-card-title", title: title, className: cn("block text-body-sm font-medium break-words text-ink", titleLines === 1 ? "truncate" : "line-clamp-2"), children: title }), slug ? (_jsx("span", { dir: "auto", "data-slot": "entity-card-slug", title: slug, className: "mt-0.5 block truncate font-mono text-caption text-faint", children: slug })) : null] }), status ? _jsx("div", { className: "shrink-0", children: status }) : null] }), description ? (_jsx("p", { dir: "auto", "data-slot": "entity-card-description", title: description, className: cn("m-0 text-body-sm text-body", descriptionLines === 1 ? "truncate" : "line-clamp-2"), children: description })) : null, meta, _jsx("div", { "aria-hidden": "true", className: "grow" }), stats && stats.length > 0 ? (_jsx("div", { "data-slot": "entity-card-stats", className: "flex flex-wrap items-center gap-4 border-t border-hairline pt-3 text-caption text-body", children: stats.map((stat) => (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [stat.icon ? (_jsx("span", { "aria-hidden": "true", className: "inline-flex [&>svg]:size-4", children: stat.icon })) : null, stat.value, _jsx("span", { className: "sr-only", children: stat.label })] }, stat.label))) })) : null, footer] }));
|
|
8
|
+
const card = (_jsxs(Card, { "data-slot": "entity-card",
|
|
9
|
+
// gap-0 py-0: `Card` pads itself for a header/content/footer stack, and
|
|
10
|
+
// this card's preview is full bleed to the top edge. The padding moves
|
|
11
|
+
// inside, onto the body, so the preview can touch the corners.
|
|
12
|
+
// No hover lift, shadow, scale or colour change, even when the whole card
|
|
13
|
+
// is a link. That is the console's founder card spec (2026-08-16) carried
|
|
14
|
+
// across rather than re-decided here, and it matches this system's own
|
|
15
|
+
// canon: containment is a hairline, not elevation.
|
|
16
|
+
// `h-full` only inside the link wrapper, where the card has to fill the
|
|
17
|
+
// anchor. As a direct grid item it must NOT be h-full: a grid area has a
|
|
18
|
+
// definite height, so height:100% pins the card to the tallest card in the
|
|
19
|
+
// row even when the grid was told `items-start`.
|
|
20
|
+
className: cn("gap-0 py-0", href && "h-full", className), ...props, children: [seed ? (_jsxs("div", { "data-slot": "entity-card-preview", className: "relative shrink-0 border-b border-hairline", children: [_jsx(EntityIdentity, { seed: seed, name: title }), previewUrl ? (_jsx("div", { "data-slot": "entity-card-capture", "aria-hidden": "true", className: "absolute inset-0 bg-cover bg-center",
|
|
21
|
+
// A background image, not an <img>: a URL that 404s paints
|
|
22
|
+
// nothing and the identity tile below shows through, with no
|
|
23
|
+
// state and no client boundary. encodeURI escapes the quote that
|
|
24
|
+
// would otherwise break out of url("...").
|
|
25
|
+
style: { backgroundImage: `url("${encodeURI(previewUrl)}")` } })) : null] })) : null, _jsx("div", { className: "flex min-h-0 flex-1 flex-col gap-3 p-(--card-spacing)", children: body })] }));
|
|
26
|
+
if (!href)
|
|
27
|
+
return card;
|
|
28
|
+
return (_jsx("a", { href: href, "aria-label": ariaLabel ?? title,
|
|
29
|
+
// The focus ring is the same token every control uses, so it flips with
|
|
30
|
+
// the surface. A card-sized link with no visible focus state is unusable
|
|
31
|
+
// by keyboard, and that failure never shows up in a screenshot.
|
|
32
|
+
className: "group block rounded-xl no-underline focus-visible:ring-3 focus-visible:ring-ring focus-visible:outline-none", children: card }));
|
|
33
|
+
}
|
|
34
|
+
export { EntityCard };
|
|
35
|
+
//# sourceMappingURL=entity-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-card.js","sourceRoot":"","sources":["../../src/blocks/entity-card.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The identity tile: what a CloudGrid entity looks like before it looks like
|
|
3
|
+
* anything. A flat tinted field, the CloudGrid motif as a hairline mesh over it,
|
|
4
|
+
* and a monogram tile carrying the entity's initials.
|
|
5
|
+
*
|
|
6
|
+
* Absorbed out of the console's `GenerativePreview` (#117), where it exists for
|
|
7
|
+
* one reason: an entity's preview slot has to be filled by SOMETHING the moment
|
|
8
|
+
* the entity is created, and a screenshot does not exist yet. Everything here is
|
|
9
|
+
* derived from the two strings the caller already has, so this can never fail to
|
|
10
|
+
* a broken image, a dark rectangle or a spinner.
|
|
11
|
+
*
|
|
12
|
+
* ## The same entity always looks the same
|
|
13
|
+
*
|
|
14
|
+
* `seed` picks the look, through FNV-1a. A grid of these reads as a set of
|
|
15
|
+
* stable identities rather than a set of placeholders, which is the whole point:
|
|
16
|
+
* the tile is doing the job a favicon does. Pass the entity's id, not its title,
|
|
17
|
+
* or a rename changes what the entity looks like.
|
|
18
|
+
*
|
|
19
|
+
* ## It does not flip per surface, deliberately
|
|
20
|
+
*
|
|
21
|
+
* Every other component in this library flips inside `data-cg-surface`. This one
|
|
22
|
+
* does not, and the reason is that it is standing in for a photograph: a real
|
|
23
|
+
* screenshot layered over it would not flip either, so a flipping fallback would
|
|
24
|
+
* make the two tiers of one slot behave differently. Its field is mixed against
|
|
25
|
+
* `--cg-neutral-0` and its ink is `--cg-text-on-primary`, both of which are white
|
|
26
|
+
* in all three scopes.
|
|
27
|
+
*
|
|
28
|
+
* The card AROUND it flips normally. Only the picture holds still.
|
|
29
|
+
*
|
|
30
|
+
* ## No colour was invented
|
|
31
|
+
*
|
|
32
|
+
* The console's version carries ten hand-picked hexes. This library's rule is
|
|
33
|
+
* that a component consumes custom properties and never hardcodes a hex, so the
|
|
34
|
+
* looks below are built from the brand's own four values by mixing. Eight looks
|
|
35
|
+
* out of four hues, at two tint depths.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* THE LOOK TABLE. Edit this to change what the identity tiles look like.
|
|
39
|
+
*
|
|
40
|
+
* Each entry is a hue token and how strongly the field is tinted with it. The
|
|
41
|
+
* monogram tile is the same hue driven toward ink, so it is always a deeper
|
|
42
|
+
* shade of the field it sits on and the white monogram on it always clears AA.
|
|
43
|
+
*
|
|
44
|
+
* Four hues, because the brand has four: the purple, the lime, the cyan and the
|
|
45
|
+
* ink. Two depths, because eight identities across a listing repeat noticeably
|
|
46
|
+
* less than four and cost nothing. Adding a fifth hue is one row here; nothing
|
|
47
|
+
* else in this file knows how many there are.
|
|
48
|
+
*
|
|
49
|
+
* The `tile` percentages are measured rather than eyeballed. White on the mixed
|
|
50
|
+
* tile: purple 7.99:1, lime 5.08:1, cyan 4.93:1, ink 15.9:1 — all clear AA for
|
|
51
|
+
* normal text, which is more than the monogram needs (it is decorative and set
|
|
52
|
+
* at a large-text size), and leaves room for a designer to lighten a tile
|
|
53
|
+
* without immediately going under.
|
|
54
|
+
*/
|
|
55
|
+
export declare const ENTITY_IDENTITY_LOOKS: readonly [{
|
|
56
|
+
readonly name: "brand-soft";
|
|
57
|
+
readonly hue: "--cg-primary";
|
|
58
|
+
readonly field: "12%";
|
|
59
|
+
readonly tile: "72%";
|
|
60
|
+
}, {
|
|
61
|
+
readonly name: "lime-soft";
|
|
62
|
+
readonly hue: "--cg-secondary";
|
|
63
|
+
readonly field: "16%";
|
|
64
|
+
readonly tile: "44%";
|
|
65
|
+
}, {
|
|
66
|
+
readonly name: "cyan-soft";
|
|
67
|
+
readonly hue: "--cg-tertiary";
|
|
68
|
+
readonly field: "16%";
|
|
69
|
+
readonly tile: "44%";
|
|
70
|
+
}, {
|
|
71
|
+
readonly name: "ink-soft";
|
|
72
|
+
readonly hue: "--cg-ink";
|
|
73
|
+
readonly field: "8%";
|
|
74
|
+
readonly tile: "84%";
|
|
75
|
+
}, {
|
|
76
|
+
readonly name: "brand-deep";
|
|
77
|
+
readonly hue: "--cg-primary";
|
|
78
|
+
readonly field: "22%";
|
|
79
|
+
readonly tile: "72%";
|
|
80
|
+
}, {
|
|
81
|
+
readonly name: "lime-deep";
|
|
82
|
+
readonly hue: "--cg-secondary";
|
|
83
|
+
readonly field: "30%";
|
|
84
|
+
readonly tile: "44%";
|
|
85
|
+
}, {
|
|
86
|
+
readonly name: "cyan-deep";
|
|
87
|
+
readonly hue: "--cg-tertiary";
|
|
88
|
+
readonly field: "30%";
|
|
89
|
+
readonly tile: "44%";
|
|
90
|
+
}, {
|
|
91
|
+
readonly name: "ink-deep";
|
|
92
|
+
readonly hue: "--cg-ink";
|
|
93
|
+
readonly field: "16%";
|
|
94
|
+
readonly tile: "84%";
|
|
95
|
+
}];
|
|
96
|
+
export type EntityIdentityLook = (typeof ENTITY_IDENTITY_LOOKS)[number];
|
|
97
|
+
/**
|
|
98
|
+
* FNV-1a over the seed. Deterministic, stable across sessions and across
|
|
99
|
+
* machines, and cheap enough to run for every card in a listing.
|
|
100
|
+
*
|
|
101
|
+
* Taken from the console unchanged, deliberately: an entity that has been the
|
|
102
|
+
* teal one for six months should not become the purple one because the library
|
|
103
|
+
* picked a different hash.
|
|
104
|
+
*/
|
|
105
|
+
export declare function entityIdentitySeed(seed: string): number;
|
|
106
|
+
/** The look a seed maps to. Same seed, same look, forever. */
|
|
107
|
+
export declare function entityIdentityLook(seed: string): EntityIdentityLook;
|
|
108
|
+
/**
|
|
109
|
+
* A name to its monogram: the initials of the first two words, or the first two
|
|
110
|
+
* letters of a single word. Punctuation and symbols are dropped first, so
|
|
111
|
+
* "@cloudgrid/cli" reads CL rather than @C.
|
|
112
|
+
*
|
|
113
|
+
* An empty or symbol-only name gives "?" rather than an empty tile, because an
|
|
114
|
+
* empty tile looks like a rendering failure and a question mark looks like an
|
|
115
|
+
* unnamed thing, which is what it is.
|
|
116
|
+
*/
|
|
117
|
+
export declare function entityMonogram(name: string): string;
|
|
118
|
+
declare function EntityIdentity({ seed, name, monogram, className, style, ...props }: Omit<React.ComponentProps<"div">, "children"> & {
|
|
119
|
+
/** The entity's stable id. Picks the look; never pass the title. */
|
|
120
|
+
seed: string;
|
|
121
|
+
/** The entity's name. Only used for the monogram. */
|
|
122
|
+
name?: string;
|
|
123
|
+
/** Overrides the derived monogram, for a name the initials read badly from. */
|
|
124
|
+
monogram?: string;
|
|
125
|
+
}): import("react").JSX.Element;
|
|
126
|
+
export { EntityIdentity };
|
|
127
|
+
//# sourceMappingURL=entity-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-identity.d.ts","sourceRoot":"","sources":["../../src/blocks/entity-identity.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASxB,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAEnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IACjD,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,+BAuDA;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* The identity tile: what a CloudGrid entity looks like before it looks like
|
|
5
|
+
* anything. A flat tinted field, the CloudGrid motif as a hairline mesh over it,
|
|
6
|
+
* and a monogram tile carrying the entity's initials.
|
|
7
|
+
*
|
|
8
|
+
* Absorbed out of the console's `GenerativePreview` (#117), where it exists for
|
|
9
|
+
* one reason: an entity's preview slot has to be filled by SOMETHING the moment
|
|
10
|
+
* the entity is created, and a screenshot does not exist yet. Everything here is
|
|
11
|
+
* derived from the two strings the caller already has, so this can never fail to
|
|
12
|
+
* a broken image, a dark rectangle or a spinner.
|
|
13
|
+
*
|
|
14
|
+
* ## The same entity always looks the same
|
|
15
|
+
*
|
|
16
|
+
* `seed` picks the look, through FNV-1a. A grid of these reads as a set of
|
|
17
|
+
* stable identities rather than a set of placeholders, which is the whole point:
|
|
18
|
+
* the tile is doing the job a favicon does. Pass the entity's id, not its title,
|
|
19
|
+
* or a rename changes what the entity looks like.
|
|
20
|
+
*
|
|
21
|
+
* ## It does not flip per surface, deliberately
|
|
22
|
+
*
|
|
23
|
+
* Every other component in this library flips inside `data-cg-surface`. This one
|
|
24
|
+
* does not, and the reason is that it is standing in for a photograph: a real
|
|
25
|
+
* screenshot layered over it would not flip either, so a flipping fallback would
|
|
26
|
+
* make the two tiers of one slot behave differently. Its field is mixed against
|
|
27
|
+
* `--cg-neutral-0` and its ink is `--cg-text-on-primary`, both of which are white
|
|
28
|
+
* in all three scopes.
|
|
29
|
+
*
|
|
30
|
+
* The card AROUND it flips normally. Only the picture holds still.
|
|
31
|
+
*
|
|
32
|
+
* ## No colour was invented
|
|
33
|
+
*
|
|
34
|
+
* The console's version carries ten hand-picked hexes. This library's rule is
|
|
35
|
+
* that a component consumes custom properties and never hardcodes a hex, so the
|
|
36
|
+
* looks below are built from the brand's own four values by mixing. Eight looks
|
|
37
|
+
* out of four hues, at two tint depths.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* THE LOOK TABLE. Edit this to change what the identity tiles look like.
|
|
41
|
+
*
|
|
42
|
+
* Each entry is a hue token and how strongly the field is tinted with it. The
|
|
43
|
+
* monogram tile is the same hue driven toward ink, so it is always a deeper
|
|
44
|
+
* shade of the field it sits on and the white monogram on it always clears AA.
|
|
45
|
+
*
|
|
46
|
+
* Four hues, because the brand has four: the purple, the lime, the cyan and the
|
|
47
|
+
* ink. Two depths, because eight identities across a listing repeat noticeably
|
|
48
|
+
* less than four and cost nothing. Adding a fifth hue is one row here; nothing
|
|
49
|
+
* else in this file knows how many there are.
|
|
50
|
+
*
|
|
51
|
+
* The `tile` percentages are measured rather than eyeballed. White on the mixed
|
|
52
|
+
* tile: purple 7.99:1, lime 5.08:1, cyan 4.93:1, ink 15.9:1 — all clear AA for
|
|
53
|
+
* normal text, which is more than the monogram needs (it is decorative and set
|
|
54
|
+
* at a large-text size), and leaves room for a designer to lighten a tile
|
|
55
|
+
* without immediately going under.
|
|
56
|
+
*/
|
|
57
|
+
export const ENTITY_IDENTITY_LOOKS = [
|
|
58
|
+
{ name: "brand-soft", hue: "--cg-primary", field: "12%", tile: "72%" },
|
|
59
|
+
{ name: "lime-soft", hue: "--cg-secondary", field: "16%", tile: "44%" },
|
|
60
|
+
{ name: "cyan-soft", hue: "--cg-tertiary", field: "16%", tile: "44%" },
|
|
61
|
+
{ name: "ink-soft", hue: "--cg-ink", field: "8%", tile: "84%" },
|
|
62
|
+
{ name: "brand-deep", hue: "--cg-primary", field: "22%", tile: "72%" },
|
|
63
|
+
{ name: "lime-deep", hue: "--cg-secondary", field: "30%", tile: "44%" },
|
|
64
|
+
{ name: "cyan-deep", hue: "--cg-tertiary", field: "30%", tile: "44%" },
|
|
65
|
+
{ name: "ink-deep", hue: "--cg-ink", field: "16%", tile: "84%" },
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* FNV-1a over the seed. Deterministic, stable across sessions and across
|
|
69
|
+
* machines, and cheap enough to run for every card in a listing.
|
|
70
|
+
*
|
|
71
|
+
* Taken from the console unchanged, deliberately: an entity that has been the
|
|
72
|
+
* teal one for six months should not become the purple one because the library
|
|
73
|
+
* picked a different hash.
|
|
74
|
+
*/
|
|
75
|
+
export function entityIdentitySeed(seed) {
|
|
76
|
+
let h = 0x811c9dc5;
|
|
77
|
+
for (let i = 0; i < seed.length; i++) {
|
|
78
|
+
h ^= seed.charCodeAt(i);
|
|
79
|
+
h = Math.imul(h, 0x01000193);
|
|
80
|
+
}
|
|
81
|
+
return h >>> 0;
|
|
82
|
+
}
|
|
83
|
+
/** The look a seed maps to. Same seed, same look, forever. */
|
|
84
|
+
export function entityIdentityLook(seed) {
|
|
85
|
+
return ENTITY_IDENTITY_LOOKS[entityIdentitySeed(seed) % ENTITY_IDENTITY_LOOKS.length];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A name to its monogram: the initials of the first two words, or the first two
|
|
89
|
+
* letters of a single word. Punctuation and symbols are dropped first, so
|
|
90
|
+
* "@cloudgrid/cli" reads CL rather than @C.
|
|
91
|
+
*
|
|
92
|
+
* An empty or symbol-only name gives "?" rather than an empty tile, because an
|
|
93
|
+
* empty tile looks like a rendering failure and a question mark looks like an
|
|
94
|
+
* unnamed thing, which is what it is.
|
|
95
|
+
*/
|
|
96
|
+
export function entityMonogram(name) {
|
|
97
|
+
const words = name
|
|
98
|
+
.replace(/[^\p{L}\p{N} ]/gu, " ")
|
|
99
|
+
.split(/\s+/)
|
|
100
|
+
.filter(Boolean);
|
|
101
|
+
const first = words[0]?.[0] ?? "?";
|
|
102
|
+
const second = words[1]?.[0] ?? words[0]?.[1] ?? "";
|
|
103
|
+
return (first + second).toUpperCase();
|
|
104
|
+
}
|
|
105
|
+
function EntityIdentity({ seed, name, monogram, className, style, ...props }) {
|
|
106
|
+
const look = entityIdentityLook(seed);
|
|
107
|
+
const letters = monogram ?? entityMonogram(name ?? "");
|
|
108
|
+
return (_jsxs("div", { "data-slot": "entity-identity", "data-look": look.name, "aria-hidden": "true", className: cn("relative isolate aspect-[1200/630] w-full select-none overflow-hidden", className), style: {
|
|
109
|
+
// Mixed against --cg-neutral-0 rather than --cg-surface-card: the card
|
|
110
|
+
// ground is `transparent` inside a purple panel, and mixing a hue into
|
|
111
|
+
// transparent gives a half-transparent hue rather than a tint. White is
|
|
112
|
+
// white in all three scopes, which is what "it does not flip" means.
|
|
113
|
+
background: `color-mix(in srgb, var(${look.hue}) ${look.field}, var(--cg-neutral-0))`,
|
|
114
|
+
...style,
|
|
115
|
+
}, ...props, children: [_jsx("div", { "aria-hidden": "true", "data-slot": "entity-identity-mesh", className: "absolute inset-0", style: {
|
|
116
|
+
backgroundImage: "linear-gradient(to right, var(--cg-identity-mesh) 1px, transparent 1px)," +
|
|
117
|
+
" linear-gradient(to bottom, var(--cg-identity-mesh) 1px, transparent 1px)",
|
|
118
|
+
backgroundSize: "22px 22px",
|
|
119
|
+
backgroundPosition: "-1px -1px",
|
|
120
|
+
"--cg-identity-mesh": "color-mix(in srgb, var(--cg-ink) 8%, transparent)",
|
|
121
|
+
} }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("span", { "data-slot": "entity-identity-monogram", className: "flex size-[46px] items-center justify-center rounded-md text-heading-md font-bold", style: {
|
|
122
|
+
background: `color-mix(in srgb, var(${look.hue}) ${look.tile}, var(--cg-ink))`,
|
|
123
|
+
color: "var(--cg-text-on-primary)",
|
|
124
|
+
}, children: letters }) })] }));
|
|
125
|
+
}
|
|
126
|
+
export { EntityIdentity };
|
|
127
|
+
//# sourceMappingURL=entity-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-identity.js","sourceRoot":"","sources":["../../src/blocks/entity-identity.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a CloudGrid entity currently IS. A coloured dot and the word for it.
|
|
3
|
+
*
|
|
4
|
+
* The first component extracted out of the CloudGrid console and into this
|
|
5
|
+
* library (#114), so the console can delete its own `StatusChip` and the two
|
|
6
|
+
* stop disagreeing about what "live" looks like. The vocabulary below is the
|
|
7
|
+
* console's, unchanged.
|
|
8
|
+
*
|
|
9
|
+
* ## The mapping is a table, and the table is the thing a designer edits
|
|
10
|
+
*
|
|
11
|
+
* Nine statuses, five tones. `ENTITY_STATUS_TONE` is the whole mapping and
|
|
12
|
+
* nothing else in this file branches on a status, so retuning what colour
|
|
13
|
+
* `paused` is means editing one line. `ENTITY_STATUS_LABEL` is the same
|
|
14
|
+
* arrangement for the words.
|
|
15
|
+
*
|
|
16
|
+
* The tones are the tokens #111 added. No component invents a colour.
|
|
17
|
+
*
|
|
18
|
+
* ## The dot carries the colour; the word does not
|
|
19
|
+
*
|
|
20
|
+
* The one deliberate departure from the console, and it is the token's own note
|
|
21
|
+
* that decides it: `--cg-online` is 3.40:1 on white, which "clears the 3:1 bar
|
|
22
|
+
* for an indicator, which is all this is ever used as. Never body text on
|
|
23
|
+
* white." On its own chip fill it measures 3.06:1. Painting the WORD with it
|
|
24
|
+
* would ship text that fails AA on the default surface.
|
|
25
|
+
*
|
|
26
|
+
* The console can colour its word because its palette carries a separate
|
|
27
|
+
* `--color-volt-ink` foreground tuned for exactly that. This library has no
|
|
28
|
+
* `-ink` variant of a state colour, and adding one is a brand decision rather
|
|
29
|
+
* than a component's to take.
|
|
30
|
+
*
|
|
31
|
+
* So the dot is the colour at indicator contrast and the word is `text-ink`,
|
|
32
|
+
* which is declared in all three scopes and flips with the surface. State is
|
|
33
|
+
* never colour alone in either arrangement, because the word always renders.
|
|
34
|
+
*
|
|
35
|
+
* ## Surfaces
|
|
36
|
+
*
|
|
37
|
+
* Nothing is asked of the consumer. Every value here is a token, so
|
|
38
|
+
* `data-cg-surface="panel"` on any ancestor flips the dot, the ground and the
|
|
39
|
+
* word together. The chip declares `text-ink` itself rather than inheriting,
|
|
40
|
+
* because text is the one thing that does not flip by inheritance.
|
|
41
|
+
*
|
|
42
|
+
* ## Grounds
|
|
43
|
+
*
|
|
44
|
+
* Four tones sit on their own fill. `offline` sits on the card ground with a
|
|
45
|
+
* control border instead, which is #111's decision rather than this component's:
|
|
46
|
+
* the muted neutral on a neutral tint measures 2.90:1, under the bar, so absence
|
|
47
|
+
* of state deliberately has no fill of its own.
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* Every state an entity can be in, in the order a surface should list them:
|
|
51
|
+
* serving first, terminal last. The console's vocabulary, unchanged.
|
|
52
|
+
*
|
|
53
|
+
* The array is the source and the type is derived from it, rather than the two
|
|
54
|
+
* being written out separately. A status added here is immediately missing from
|
|
55
|
+
* both tables below and typecheck says so, which is the only arrangement where
|
|
56
|
+
* a half-added status cannot ship.
|
|
57
|
+
*/
|
|
58
|
+
export declare const ENTITY_STATUS_ORDER: readonly ["live", "building", "charged", "draft", "paused", "stopped", "archived", "expired", "error"];
|
|
59
|
+
export type EntityStatusName = (typeof ENTITY_STATUS_ORDER)[number];
|
|
60
|
+
/** The five families of the state palette. One token pair each. */
|
|
61
|
+
export type EntityStatusTone = "online" | "pending" | "offline" | "expired" | "danger";
|
|
62
|
+
/**
|
|
63
|
+
* THE MAPPING. Edit this to change what a status looks like.
|
|
64
|
+
*
|
|
65
|
+
* Founder decisions, 2026-08-24 (#114), recorded because two of them are not
|
|
66
|
+
* what a reader would guess:
|
|
67
|
+
*
|
|
68
|
+
* `building` is PENDING, not offline. Progress reads warm, not dead-grey, and
|
|
69
|
+
* a building entity may still be serving its previous version — so grey would
|
|
70
|
+
* be wrong twice over. `--cg-pending` is an alias of `--cg-expired`, so the two
|
|
71
|
+
* are one amber today and can be separated later without touching a consumer.
|
|
72
|
+
*
|
|
73
|
+
* `charged` is OFFLINE, not online. A charged entity is a reserved cell on the
|
|
74
|
+
* grid waiting to be plugged; if nothing arrives it expires and is archived. It
|
|
75
|
+
* is not serving and it is not ready, so green would claim something untrue.
|
|
76
|
+
* Worth knowing that "reserved and waiting" is a different idea from "paused,
|
|
77
|
+
* stopped, archived, draft", and a designer may want to split it out later. It
|
|
78
|
+
* shares their tone today because the library has no token for that idea.
|
|
79
|
+
*
|
|
80
|
+
* `live` is the library's green, explicitly not the console's lime: the brand
|
|
81
|
+
* has already spent lime on decoration, so a lime "live" would not read as a
|
|
82
|
+
* signal.
|
|
83
|
+
*/
|
|
84
|
+
export declare const ENTITY_STATUS_TONE: Record<EntityStatusName, EntityStatusTone>;
|
|
85
|
+
/**
|
|
86
|
+
* The word each status shows. Plain and specific: the state, not a sentence
|
|
87
|
+
* about it. Override per instance with the `label` prop when a surface knows
|
|
88
|
+
* something more exact, e.g. "Build failed" rather than "Error".
|
|
89
|
+
*/
|
|
90
|
+
export declare const ENTITY_STATUS_LABEL: Record<EntityStatusName, string>;
|
|
91
|
+
declare function EntityStatus({ status, label, className, ...props }: Omit<React.ComponentProps<"span">, "children"> & {
|
|
92
|
+
status: EntityStatusName;
|
|
93
|
+
/** Overrides the default word. The word always renders; there is no dot-only form. */
|
|
94
|
+
label?: React.ReactNode;
|
|
95
|
+
}): import("react").JSX.Element;
|
|
96
|
+
export { EntityStatus };
|
|
97
|
+
//# sourceMappingURL=entity-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-status.d.ts","sourceRoot":"","sources":["../../src/blocks/entity-status.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,wGAUtB,CAAA;AAEV,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEnE,mEAAmE;AACnE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;AAEtF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,CAUzE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAUhE,CAAA;AAkBD,iBAAS,YAAY,CAAC,EACpB,MAAM,EACN,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG;IAClD,MAAM,EAAE,gBAAgB,CAAA;IACxB,sFAAsF;IACtF,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,+BAqCA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* What a CloudGrid entity currently IS. A coloured dot and the word for it.
|
|
5
|
+
*
|
|
6
|
+
* The first component extracted out of the CloudGrid console and into this
|
|
7
|
+
* library (#114), so the console can delete its own `StatusChip` and the two
|
|
8
|
+
* stop disagreeing about what "live" looks like. The vocabulary below is the
|
|
9
|
+
* console's, unchanged.
|
|
10
|
+
*
|
|
11
|
+
* ## The mapping is a table, and the table is the thing a designer edits
|
|
12
|
+
*
|
|
13
|
+
* Nine statuses, five tones. `ENTITY_STATUS_TONE` is the whole mapping and
|
|
14
|
+
* nothing else in this file branches on a status, so retuning what colour
|
|
15
|
+
* `paused` is means editing one line. `ENTITY_STATUS_LABEL` is the same
|
|
16
|
+
* arrangement for the words.
|
|
17
|
+
*
|
|
18
|
+
* The tones are the tokens #111 added. No component invents a colour.
|
|
19
|
+
*
|
|
20
|
+
* ## The dot carries the colour; the word does not
|
|
21
|
+
*
|
|
22
|
+
* The one deliberate departure from the console, and it is the token's own note
|
|
23
|
+
* that decides it: `--cg-online` is 3.40:1 on white, which "clears the 3:1 bar
|
|
24
|
+
* for an indicator, which is all this is ever used as. Never body text on
|
|
25
|
+
* white." On its own chip fill it measures 3.06:1. Painting the WORD with it
|
|
26
|
+
* would ship text that fails AA on the default surface.
|
|
27
|
+
*
|
|
28
|
+
* The console can colour its word because its palette carries a separate
|
|
29
|
+
* `--color-volt-ink` foreground tuned for exactly that. This library has no
|
|
30
|
+
* `-ink` variant of a state colour, and adding one is a brand decision rather
|
|
31
|
+
* than a component's to take.
|
|
32
|
+
*
|
|
33
|
+
* So the dot is the colour at indicator contrast and the word is `text-ink`,
|
|
34
|
+
* which is declared in all three scopes and flips with the surface. State is
|
|
35
|
+
* never colour alone in either arrangement, because the word always renders.
|
|
36
|
+
*
|
|
37
|
+
* ## Surfaces
|
|
38
|
+
*
|
|
39
|
+
* Nothing is asked of the consumer. Every value here is a token, so
|
|
40
|
+
* `data-cg-surface="panel"` on any ancestor flips the dot, the ground and the
|
|
41
|
+
* word together. The chip declares `text-ink` itself rather than inheriting,
|
|
42
|
+
* because text is the one thing that does not flip by inheritance.
|
|
43
|
+
*
|
|
44
|
+
* ## Grounds
|
|
45
|
+
*
|
|
46
|
+
* Four tones sit on their own fill. `offline` sits on the card ground with a
|
|
47
|
+
* control border instead, which is #111's decision rather than this component's:
|
|
48
|
+
* the muted neutral on a neutral tint measures 2.90:1, under the bar, so absence
|
|
49
|
+
* of state deliberately has no fill of its own.
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* Every state an entity can be in, in the order a surface should list them:
|
|
53
|
+
* serving first, terminal last. The console's vocabulary, unchanged.
|
|
54
|
+
*
|
|
55
|
+
* The array is the source and the type is derived from it, rather than the two
|
|
56
|
+
* being written out separately. A status added here is immediately missing from
|
|
57
|
+
* both tables below and typecheck says so, which is the only arrangement where
|
|
58
|
+
* a half-added status cannot ship.
|
|
59
|
+
*/
|
|
60
|
+
export const ENTITY_STATUS_ORDER = [
|
|
61
|
+
"live",
|
|
62
|
+
"building",
|
|
63
|
+
"charged",
|
|
64
|
+
"draft",
|
|
65
|
+
"paused",
|
|
66
|
+
"stopped",
|
|
67
|
+
"archived",
|
|
68
|
+
"expired",
|
|
69
|
+
"error",
|
|
70
|
+
];
|
|
71
|
+
/**
|
|
72
|
+
* THE MAPPING. Edit this to change what a status looks like.
|
|
73
|
+
*
|
|
74
|
+
* Founder decisions, 2026-08-24 (#114), recorded because two of them are not
|
|
75
|
+
* what a reader would guess:
|
|
76
|
+
*
|
|
77
|
+
* `building` is PENDING, not offline. Progress reads warm, not dead-grey, and
|
|
78
|
+
* a building entity may still be serving its previous version — so grey would
|
|
79
|
+
* be wrong twice over. `--cg-pending` is an alias of `--cg-expired`, so the two
|
|
80
|
+
* are one amber today and can be separated later without touching a consumer.
|
|
81
|
+
*
|
|
82
|
+
* `charged` is OFFLINE, not online. A charged entity is a reserved cell on the
|
|
83
|
+
* grid waiting to be plugged; if nothing arrives it expires and is archived. It
|
|
84
|
+
* is not serving and it is not ready, so green would claim something untrue.
|
|
85
|
+
* Worth knowing that "reserved and waiting" is a different idea from "paused,
|
|
86
|
+
* stopped, archived, draft", and a designer may want to split it out later. It
|
|
87
|
+
* shares their tone today because the library has no token for that idea.
|
|
88
|
+
*
|
|
89
|
+
* `live` is the library's green, explicitly not the console's lime: the brand
|
|
90
|
+
* has already spent lime on decoration, so a lime "live" would not read as a
|
|
91
|
+
* signal.
|
|
92
|
+
*/
|
|
93
|
+
export const ENTITY_STATUS_TONE = {
|
|
94
|
+
live: "online",
|
|
95
|
+
building: "pending",
|
|
96
|
+
charged: "offline",
|
|
97
|
+
draft: "offline",
|
|
98
|
+
paused: "offline",
|
|
99
|
+
stopped: "offline",
|
|
100
|
+
archived: "offline",
|
|
101
|
+
expired: "expired",
|
|
102
|
+
error: "danger",
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* The word each status shows. Plain and specific: the state, not a sentence
|
|
106
|
+
* about it. Override per instance with the `label` prop when a surface knows
|
|
107
|
+
* something more exact, e.g. "Build failed" rather than "Error".
|
|
108
|
+
*/
|
|
109
|
+
export const ENTITY_STATUS_LABEL = {
|
|
110
|
+
live: "Live",
|
|
111
|
+
building: "Building",
|
|
112
|
+
charged: "Charged",
|
|
113
|
+
draft: "Draft",
|
|
114
|
+
paused: "Paused",
|
|
115
|
+
stopped: "Stopped",
|
|
116
|
+
archived: "Archived",
|
|
117
|
+
expired: "Expired",
|
|
118
|
+
error: "Error",
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Tone to classes. Two slots: the chip's ground and the dot's colour.
|
|
122
|
+
*
|
|
123
|
+
* Every entry is a utility over a `--cg-*` token, so all of it flips per
|
|
124
|
+
* surface. A literal here would look correct on white and be the one wrong
|
|
125
|
+
* thing on a purple panel.
|
|
126
|
+
*/
|
|
127
|
+
const TONE_STYLE = {
|
|
128
|
+
online: { chip: "border-transparent bg-online-fill", dot: "bg-online" },
|
|
129
|
+
pending: { chip: "border-transparent bg-pending-fill", dot: "bg-pending" },
|
|
130
|
+
expired: { chip: "border-transparent bg-expired-fill", dot: "bg-expired" },
|
|
131
|
+
danger: { chip: "border-transparent bg-danger-fill", dot: "bg-danger" },
|
|
132
|
+
// No fill, by design. See the note at the top and #111's own.
|
|
133
|
+
offline: { chip: "border-line bg-card", dot: "bg-offline" },
|
|
134
|
+
};
|
|
135
|
+
function EntityStatus({ status, label, className, ...props }) {
|
|
136
|
+
const tone = ENTITY_STATUS_TONE[status];
|
|
137
|
+
const style = TONE_STYLE[tone];
|
|
138
|
+
return (_jsxs("span", { "data-slot": "entity-status", "data-status": status, "data-tone": tone, className: cn("inline-flex w-fit shrink-0 items-center gap-1.5 rounded-pill border px-2.5 py-0.5 text-caption font-medium whitespace-nowrap text-ink", style.chip, className), ...props, children: [_jsx("span", { "aria-hidden": "true", "data-slot": "entity-status-dot", className: cn("size-1.5 shrink-0 rounded-pill", style.dot,
|
|
139
|
+
// Progress, drawn rather than only named. `motion-safe:` rather than a
|
|
140
|
+
// global prefers-reduced-motion rule, because the variant travels with
|
|
141
|
+
// this file into a consumer's repo and a rule in our stylesheet does
|
|
142
|
+
// not. Same reasoning as AgentPrompt's caret.
|
|
143
|
+
status === "building" && "motion-safe:animate-pulse") }), label ?? ENTITY_STATUS_LABEL[status]] }));
|
|
144
|
+
}
|
|
145
|
+
export { EntityStatus };
|
|
146
|
+
//# sourceMappingURL=entity-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-status.js","sourceRoot":"","sources":["../../src/blocks/entity-status.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,MAAM;IACN,UAAU;IACV,SAAS;IACT,OAAO;IACP,QAAQ;IACR,SAAS;IACT,UAAU;IACV,SAAS;IACT,OAAO;CACC,CAAA;AAOV;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA+C;IAC5E,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,QAAQ;CAChB,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAqC;IACnE,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;CACf,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,GAA4D;IAC1E,MAAM,EAAE,EAAE,IAAI,EAAE,mCAAmC,EAAE,GAAG,EAAE,WAAW,EAAE;IACvE,OAAO,EAAE,EAAE,IAAI,EAAE,oCAAoC,EAAE,GAAG,EAAE,YAAY,EAAE;IAC1E,OAAO,EAAE,EAAE,IAAI,EAAE,oCAAoC,EAAE,GAAG,EAAE,YAAY,EAAE;IAC1E,MAAM,EAAE,EAAE,IAAI,EAAE,mCAAmC,EAAE,GAAG,EAAE,WAAW,EAAE;IACvE,8DAA8D;IAC9D,OAAO,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,GAAG,EAAE,YAAY,EAAE;CAC5D,CAAA;AAED,SAAS,YAAY,CAAC,EACpB,MAAM,EACN,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EAKT;IACC,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAE9B,OAAO,CACL,6BACY,eAAe,iBAIZ,MAAM,eACR,IAAI,EACf,SAAS,EAAE,EAAE,CACX,uIAAuI,EACvI,KAAK,CAAC,IAAI,EACV,SAAS,CACV,KACG,KAAK,aAET,8BAGc,MAAM,eACR,mBAAmB,EAC7B,SAAS,EAAE,EAAE,CACX,gCAAgC,EAChC,KAAK,CAAC,GAAG;gBACT,uEAAuE;gBACvE,uEAAuE;gBACvE,qEAAqE;gBACrE,8CAA8C;gBAC9C,MAAM,KAAK,UAAU,IAAI,2BAA2B,CACrD,GACD,EACD,KAAK,IAAI,mBAAmB,CAAC,MAAM,CAAC,IAChC,CACR,CAAA;AACH,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,9 @@ export * from "./blocks/compare-table.js";
|
|
|
27
27
|
export * from "./blocks/creation-tile.js";
|
|
28
28
|
export * from "./blocks/cta-banner.js";
|
|
29
29
|
export * from "./blocks/drop-zone.js";
|
|
30
|
+
export * from "./blocks/entity-card.js";
|
|
31
|
+
export * from "./blocks/entity-identity.js";
|
|
32
|
+
export * from "./blocks/entity-status.js";
|
|
30
33
|
export * from "./blocks/feature-cells.js";
|
|
31
34
|
export * from "./blocks/hub-index.js";
|
|
32
35
|
export * from "./blocks/logo.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAG/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AAGtC,cAAc,uBAAuB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAG/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AAGtC,cAAc,uBAAuB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// The public surface of @cloudgrid-io/ui.
|
|
2
2
|
//
|
|
3
3
|
// GENERATED shape, hand-committed: one `export *` per component module. Flat is
|
|
4
|
-
// safe here — the
|
|
4
|
+
// safe here — the exported names across all 46 components collide zero times,
|
|
5
5
|
// asserted by a test so a future addition cannot break it silently.
|
|
6
6
|
//
|
|
7
7
|
// Per-module re-exports rather than a bundle, deliberately. 20 of these carry a
|
|
8
8
|
// "use client" directive, and the client boundary is a property of the MODULE.
|
|
9
9
|
// tsc emits file-per-file and preserves the directive, so a React Server
|
|
10
10
|
// Component consumer keeps exactly the boundaries the source declares. Bundling
|
|
11
|
-
// them into one file would collapse
|
|
11
|
+
// them into one file would collapse 46 modules into a single client island.
|
|
12
12
|
//
|
|
13
13
|
// The CSS is NOT imported here. It ships as separate entry points
|
|
14
14
|
// (@cloudgrid-io/ui/tokens.css and friends) so a consumer with no React — the
|
|
@@ -44,6 +44,9 @@ export * from "./blocks/compare-table.js";
|
|
|
44
44
|
export * from "./blocks/creation-tile.js";
|
|
45
45
|
export * from "./blocks/cta-banner.js";
|
|
46
46
|
export * from "./blocks/drop-zone.js";
|
|
47
|
+
export * from "./blocks/entity-card.js";
|
|
48
|
+
export * from "./blocks/entity-identity.js";
|
|
49
|
+
export * from "./blocks/entity-status.js";
|
|
47
50
|
export * from "./blocks/feature-cells.js";
|
|
48
51
|
export * from "./blocks/hub-index.js";
|
|
49
52
|
export * from "./blocks/logo.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,gFAAgF;AAChF,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,oEAAoE;AACpE,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,yEAAyE;AACzE,gFAAgF;AAChF,4EAA4E;AAC5E,EAAE;AACF,kEAAkE;AAClE,8EAA8E;AAC9E,uEAAuE;AAEvE,cAAc;AACd,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAE/B,mBAAmB;AACnB,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AAEtC,0EAA0E;AAC1E,cAAc,uBAAuB,CAAA"}
|
package/dist/theme.css
CHANGED
|
@@ -97,6 +97,36 @@
|
|
|
97
97
|
--destructive to the same token, so both spellings resolve to one source. */
|
|
98
98
|
--color-danger: var(--cg-danger);
|
|
99
99
|
|
|
100
|
+
/* ---- state ----
|
|
101
|
+
What an entity IS: online, offline, pending, expired, and danger above.
|
|
102
|
+
|
|
103
|
+
#111 added the tokens and stopped there, so for one release the state
|
|
104
|
+
palette was reachable only as raw var(--cg-online). That is the shape #30
|
|
105
|
+
and #91 both found people get wrong: `danger` had utilities and its five
|
|
106
|
+
siblings did not, so the first consumer of the state palette would either
|
|
107
|
+
hardcode an escape hatch or reach for `text-accent` and get a surface.
|
|
108
|
+
|
|
109
|
+
Each name serves every colour utility, so --color-online gives text-online,
|
|
110
|
+
bg-online and border-online alike.
|
|
111
|
+
|
|
112
|
+
Checked against rule 4 before claiming these: shadcn owns background,
|
|
113
|
+
foreground, card, popover, primary, secondary, muted, accent, destructive,
|
|
114
|
+
border, input, ring, chart-* and sidebar-*. None of these collide.
|
|
115
|
+
|
|
116
|
+
There is no --color-offline-fill, because there is no --cg-offline-fill.
|
|
117
|
+
#111's note explains why, and it is a design decision rather than an
|
|
118
|
+
omission: the muted neutral on a neutral tint measures 2.90:1, under the
|
|
119
|
+
3:1 bar, so an unplugged chip uses the card ground and border-control
|
|
120
|
+
instead. A utility here would have to invent the value it maps. */
|
|
121
|
+
--color-online: var(--cg-online);
|
|
122
|
+
--color-online-fill: var(--cg-online-fill);
|
|
123
|
+
--color-offline: var(--cg-offline);
|
|
124
|
+
--color-pending: var(--cg-pending);
|
|
125
|
+
--color-pending-fill: var(--cg-pending-fill);
|
|
126
|
+
--color-expired: var(--cg-expired);
|
|
127
|
+
--color-expired-fill: var(--cg-expired-fill);
|
|
128
|
+
--color-danger-fill: var(--cg-danger-fill);
|
|
129
|
+
|
|
100
130
|
/* ---- lines ---- */
|
|
101
131
|
--color-hairline: var(--cg-border-hairline);
|
|
102
132
|
--color-line: var(--cg-border-control);
|
package/dist/tokens/base.json
CHANGED
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"state": {
|
|
55
|
-
"$description": "state: what an entity IS, not what it means editorially.\n\nAdopted from the Console rather than invented, 2026-08-24 (#96). The Console\nhad already chosen and contrast-tested these — --color-live and\n--color-attention — while the brand carried no state colour at all beyond the\ndanger placeholder. Taking its values means the Console's appearance does not\nchange when it starts consuming this package, and the two stop disagreeing\nabout what 'live' looks like.\n\nEach carries per-surface values in surface-panel and surface-ink, for the same\nreason danger does: measured against all three grounds, no single value works.\nThe live green is 1.72:1 on the purple panel, and the brand's own lime is\n1.54:1 on white. A flat value would be invisible somewhere.\n\nNo --cg-offline-fill, deliberately. Measured, the pair does not work: the\nmuted neutral on a neutral tint is 2.90:1, under the 3:1 bar for a dot or a\nborder. Rather than invent a value to satisfy the ratio, an unplugged chip\nuses the existing surface-card ground with border-control, and --cg-offline\nis the dot on that ground, where it measures 3.28:1. Absence of state should\nnot need a colour of its own.",
|
|
55
|
+
"$description": "state: what an entity IS, not what it means editorially.\n\nAdopted from the Console rather than invented, 2026-08-24 (#96). The Console\nhad already chosen and contrast-tested these — --color-live and\n--color-attention — while the brand carried no state colour at all beyond the\ndanger placeholder. Taking its values means the Console's appearance does not\nchange when it starts consuming this package, and the two stop disagreeing\nabout what 'live' looks like.\n\nEach carries per-surface values in surface-panel and surface-ink, for the same\nreason danger does: measured against all three grounds, no single value works.\nThe live green is 1.72:1 on the purple panel, and the brand's own lime is\n1.54:1 on white. A flat value would be invisible somewhere.\n\nNo --cg-offline-fill, deliberately. Measured, the pair does not work: the\nmuted neutral on a neutral tint is 2.90:1, under the 3:1 bar for a dot or a\nborder. Rather than invent a value to satisfy the ratio, an unplugged chip\nuses the existing surface-card ground with border-control, and --cg-offline\nis the dot on that ground, where it measures 3.28:1. Absence of state should\nnot need a colour of its own.\n\npending joined them on 2026-08-24 (#114) as an ALIAS of expired rather than a\nnew value. Same amber today, separate name, so the two can diverge later with\na one-line edit here and no change in any consumer. Aliases compile to var(),\nso the flip survives.",
|
|
56
56
|
"online": {
|
|
57
57
|
"$value": "#00a05c",
|
|
58
58
|
"$type": "color",
|
|
@@ -82,6 +82,15 @@
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
|
+
"pending": {
|
|
86
|
+
"$value": "{state.expired}",
|
|
87
|
+
"$description": "In progress. Deliberately an ALIAS of expired rather than the same hex written twice: the two are one amber today and they are not the same idea, so a designer must be able to separate them without touching a consumer.\n\nExpired is terminal, pending is transitional, and warm is the honest reading for both. Grey would be wrong twice over for a building entity, because it is not absence and because a building entity may still be serving its previous version.\n\nFounder decision 2026-08-24, issue #114: \"building is like something in progress, something in between amber and yellow and orange.\"",
|
|
88
|
+
"$extensions": {
|
|
89
|
+
"io.cloudgrid": {
|
|
90
|
+
"css": "--cg-pending"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
85
94
|
"online-fill": {
|
|
86
95
|
"$value": "#e6f7ef",
|
|
87
96
|
"$type": "color",
|
|
@@ -102,6 +111,15 @@
|
|
|
102
111
|
}
|
|
103
112
|
}
|
|
104
113
|
},
|
|
114
|
+
"pending-fill": {
|
|
115
|
+
"$value": "{state.expired-fill}",
|
|
116
|
+
"$description": "The chip ground for pending, aliased to expired's for the same reason the foreground is. Splitting pending from expired later means editing these two entries and nothing else.",
|
|
117
|
+
"$extensions": {
|
|
118
|
+
"io.cloudgrid": {
|
|
119
|
+
"css": "--cg-pending-fill"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
105
123
|
"danger-fill": {
|
|
106
124
|
"$value": "#fceded",
|
|
107
125
|
"$type": "color",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
}
|
|
135
135
|
},
|
|
136
136
|
"state": {
|
|
137
|
-
"$description": "state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed.",
|
|
137
|
+
"$description": "state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. pending is an alias of expired (#114), declared here so it flips rather than freezing to the base scope.",
|
|
138
138
|
"online": {
|
|
139
139
|
"$value": "#5FD99A",
|
|
140
140
|
"$type": "color",
|
|
@@ -165,6 +165,15 @@
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
|
+
"pending": {
|
|
169
|
+
"$value": "{state.expired}",
|
|
170
|
+
"$description": "Aliased to expired, which is 8.63:1 on #222. Declared here as well as at :root because an alias is substituted where it is DECLARED — a :root-only pending would freeze to the white-surface amber and stop flipping, with no error.",
|
|
171
|
+
"$extensions": {
|
|
172
|
+
"io.cloudgrid": {
|
|
173
|
+
"css": "--cg-pending"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
168
177
|
"online-fill": {
|
|
169
178
|
"$value": "rgba(255, 255, 255, 0.08)",
|
|
170
179
|
"$type": "color",
|
|
@@ -185,6 +194,15 @@
|
|
|
185
194
|
}
|
|
186
195
|
}
|
|
187
196
|
},
|
|
197
|
+
"pending-fill": {
|
|
198
|
+
"$value": "{state.expired-fill}",
|
|
199
|
+
"$description": "Aliased to expired-fill. Declared per scope for the same reason the foreground is.",
|
|
200
|
+
"$extensions": {
|
|
201
|
+
"io.cloudgrid": {
|
|
202
|
+
"css": "--cg-pending-fill"
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
},
|
|
188
206
|
"danger-fill": {
|
|
189
207
|
"$value": "rgba(255, 255, 255, 0.08)",
|
|
190
208
|
"$type": "color",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
}
|
|
119
119
|
},
|
|
120
120
|
"state": {
|
|
121
|
-
"$description": "state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed.",
|
|
121
|
+
"$description": "state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. pending is an alias of expired (#114), declared here so it flips rather than freezing to the base scope.",
|
|
122
122
|
"online": {
|
|
123
123
|
"$value": "#C8F5DC",
|
|
124
124
|
"$type": "color",
|
|
@@ -149,6 +149,15 @@
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
},
|
|
152
|
+
"pending": {
|
|
153
|
+
"$value": "{state.expired}",
|
|
154
|
+
"$description": "Aliased to expired, which is 4.68:1 on the purple. Declared here as well as at :root because an alias is substituted where it is DECLARED — a :root-only pending would freeze to the white-surface amber and stop flipping, with no error.",
|
|
155
|
+
"$extensions": {
|
|
156
|
+
"io.cloudgrid": {
|
|
157
|
+
"css": "--cg-pending"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
152
161
|
"online-fill": {
|
|
153
162
|
"$value": "rgba(255, 255, 255, 0.16)",
|
|
154
163
|
"$type": "color",
|
|
@@ -169,6 +178,15 @@
|
|
|
169
178
|
}
|
|
170
179
|
}
|
|
171
180
|
},
|
|
181
|
+
"pending-fill": {
|
|
182
|
+
"$value": "{state.expired-fill}",
|
|
183
|
+
"$description": "Aliased to expired-fill. Declared per scope for the same reason the foreground is.",
|
|
184
|
+
"$extensions": {
|
|
185
|
+
"io.cloudgrid": {
|
|
186
|
+
"css": "--cg-pending-fill"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
172
190
|
"danger-fill": {
|
|
173
191
|
"$value": "rgba(255, 255, 255, 0.16)",
|
|
174
192
|
"$type": "color",
|
package/dist/tokens.css
CHANGED
|
@@ -93,7 +93,12 @@
|
|
|
93
93
|
border. Rather than invent a value to satisfy the ratio, an unplugged chip
|
|
94
94
|
uses the existing surface-card ground with border-control, and --cg-offline
|
|
95
95
|
is the dot on that ground, where it measures 3.28:1. Absence of state should
|
|
96
|
-
not need a colour of its own.
|
|
96
|
+
not need a colour of its own.
|
|
97
|
+
|
|
98
|
+
pending joined them on 2026-08-24 (#114) as an ALIAS of expired rather than a
|
|
99
|
+
new value. Same amber today, separate name, so the two can diverge later with
|
|
100
|
+
a one-line edit here and no change in any consumer. Aliases compile to var(),
|
|
101
|
+
so the flip survives. */
|
|
97
102
|
/*
|
|
98
103
|
Serving. From the Console's --color-live. 3.40:1 on white — clears the 3:1 bar for an indicator, which is all this is ever used as. Never body text on white. */
|
|
99
104
|
--cg-online: #00a05c;
|
|
@@ -103,12 +108,22 @@
|
|
|
103
108
|
/*
|
|
104
109
|
Past its 30-day life and no longer served. From the Console's --color-attention. 4.39:1 on white. Amber rather than red: expiry is the documented default for a drop, not a fault. */
|
|
105
110
|
--cg-expired: #b0662a;
|
|
111
|
+
/*
|
|
112
|
+
In progress. Deliberately an ALIAS of expired rather than the same hex written twice: the two are one amber today and they are not the same idea, so a designer must be able to separate them without touching a consumer.
|
|
113
|
+
|
|
114
|
+
Expired is terminal, pending is transitional, and warm is the honest reading for both. Grey would be wrong twice over for a building entity, because it is not absence and because a building entity may still be serving its previous version.
|
|
115
|
+
|
|
116
|
+
Founder decision 2026-08-24, issue #114: "building is like something in progress, something in between amber and yellow and orange." */
|
|
117
|
+
--cg-pending: var(--cg-expired);
|
|
106
118
|
/*
|
|
107
119
|
From the Console's --color-live-fill. --cg-online measures 3.06:1 on it. */
|
|
108
120
|
--cg-online-fill: #e6f7ef;
|
|
109
121
|
/*
|
|
110
122
|
From the Console's --color-attention-fill. --cg-expired measures 3.99:1 on it. */
|
|
111
123
|
--cg-expired-fill: #fdf3e0;
|
|
124
|
+
/*
|
|
125
|
+
The chip ground for pending, aliased to expired's for the same reason the foreground is. Splitting pending from expired later means editing these two entries and nothing else. */
|
|
126
|
+
--cg-pending-fill: var(--cg-expired-fill);
|
|
112
127
|
/*
|
|
113
128
|
From the Console's --color-error-fill. --cg-danger measures 3.72:1 on it. danger had no fill before; a chip needs one. */
|
|
114
129
|
--cg-danger-fill: #fceded;
|
|
@@ -317,7 +332,7 @@
|
|
|
317
332
|
--cg-danger: #FFDAD6;
|
|
318
333
|
|
|
319
334
|
/* ---- state ----
|
|
320
|
-
state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. */
|
|
335
|
+
state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. pending is an alias of expired (#114), declared here so it flips rather than freezing to the base scope. */
|
|
321
336
|
/*
|
|
322
337
|
4.88:1 on the purple. The source green is 1.72:1 here — invisible, same class as the danger override. */
|
|
323
338
|
--cg-online: #C8F5DC;
|
|
@@ -327,12 +342,18 @@
|
|
|
327
342
|
/*
|
|
328
343
|
4.68:1. The amber as a tint; the source value is 1.38:1 on this ground. */
|
|
329
344
|
--cg-expired: #FFE2B8;
|
|
345
|
+
/*
|
|
346
|
+
Aliased to expired, which is 4.68:1 on the purple. Declared here as well as at :root because an alias is substituted where it is DECLARED — a :root-only pending would freeze to the white-surface amber and stop flipping, with no error. */
|
|
347
|
+
--cg-pending: var(--cg-expired);
|
|
330
348
|
/*
|
|
331
349
|
Translucent white rather than a tint; the panel foreground measures 3.62:1 on it. */
|
|
332
350
|
--cg-online-fill: rgba(255, 255, 255, 0.16);
|
|
333
351
|
/*
|
|
334
352
|
Translucent white rather than a tint; the panel foreground measures 3.47:1 on it. */
|
|
335
353
|
--cg-expired-fill: rgba(255, 255, 255, 0.16);
|
|
354
|
+
/*
|
|
355
|
+
Aliased to expired-fill. Declared per scope for the same reason the foreground is. */
|
|
356
|
+
--cg-pending-fill: var(--cg-expired-fill);
|
|
336
357
|
/*
|
|
337
358
|
Translucent white rather than a tint; the panel foreground measures 3.35:1 on it. */
|
|
338
359
|
--cg-danger-fill: rgba(255, 255, 255, 0.16);
|
|
@@ -368,7 +389,7 @@
|
|
|
368
389
|
--cg-danger: #FF8A80;
|
|
369
390
|
|
|
370
391
|
/* ---- state ----
|
|
371
|
-
state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. */
|
|
392
|
+
state: the per-surface values for online/offline/expired. Same necessity as danger — measured, not assumed. pending is an alias of expired (#114), declared here so it flips rather than freezing to the base scope. */
|
|
372
393
|
/*
|
|
373
394
|
9.00:1 on #222. Ink has headroom, so this stays a recognisable green rather than washing to mint. */
|
|
374
395
|
--cg-online: #5FD99A;
|
|
@@ -376,10 +397,16 @@
|
|
|
376
397
|
--cg-offline: #9A9A9A;
|
|
377
398
|
/* 8.63:1. Keeps the amber legible without turning yellow. */
|
|
378
399
|
--cg-expired: #F0B45E;
|
|
400
|
+
/*
|
|
401
|
+
Aliased to expired, which is 8.63:1 on #222. Declared here as well as at :root because an alias is substituted where it is DECLARED — a :root-only pending would freeze to the white-surface amber and stop flipping, with no error. */
|
|
402
|
+
--cg-pending: var(--cg-expired);
|
|
379
403
|
/* Translucent white; the ink foreground measures 7.04:1 on it. */
|
|
380
404
|
--cg-online-fill: rgba(255, 255, 255, 0.08);
|
|
381
405
|
/* Translucent white; the ink foreground measures 6.76:1 on it. */
|
|
382
406
|
--cg-expired-fill: rgba(255, 255, 255, 0.08);
|
|
407
|
+
/*
|
|
408
|
+
Aliased to expired-fill. Declared per scope for the same reason the foreground is. */
|
|
409
|
+
--cg-pending-fill: var(--cg-expired-fill);
|
|
383
410
|
/* Translucent white; the ink foreground measures 5.45:1 on it. */
|
|
384
411
|
--cg-danger-fill: rgba(255, 255, 255, 0.08);
|
|
385
412
|
}
|
package/dist/tokens.json
CHANGED
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
"--cg-online": "#00a05c",
|
|
12
12
|
"--cg-offline": "var(--cg-neutral-500)",
|
|
13
13
|
"--cg-expired": "#b0662a",
|
|
14
|
+
"--cg-pending": "var(--cg-expired)",
|
|
14
15
|
"--cg-online-fill": "#e6f7ef",
|
|
15
16
|
"--cg-expired-fill": "#fdf3e0",
|
|
17
|
+
"--cg-pending-fill": "var(--cg-expired-fill)",
|
|
16
18
|
"--cg-danger-fill": "#fceded",
|
|
17
19
|
"--cg-primary-press": "#4b39db",
|
|
18
20
|
"--cg-primary-tint": "#eeecfe",
|
|
@@ -139,8 +141,10 @@
|
|
|
139
141
|
"--cg-online": "#C8F5DC",
|
|
140
142
|
"--cg-offline": "#D9D4FB",
|
|
141
143
|
"--cg-expired": "#FFE2B8",
|
|
144
|
+
"--cg-pending": "var(--cg-expired)",
|
|
142
145
|
"--cg-online-fill": "rgba(255, 255, 255, 0.16)",
|
|
143
146
|
"--cg-expired-fill": "rgba(255, 255, 255, 0.16)",
|
|
147
|
+
"--cg-pending-fill": "var(--cg-expired-fill)",
|
|
144
148
|
"--cg-danger-fill": "rgba(255, 255, 255, 0.16)"
|
|
145
149
|
},
|
|
146
150
|
"ink": {
|
|
@@ -161,8 +165,10 @@
|
|
|
161
165
|
"--cg-online": "#5FD99A",
|
|
162
166
|
"--cg-offline": "#9A9A9A",
|
|
163
167
|
"--cg-expired": "#F0B45E",
|
|
168
|
+
"--cg-pending": "var(--cg-expired)",
|
|
164
169
|
"--cg-online-fill": "rgba(255, 255, 255, 0.08)",
|
|
165
170
|
"--cg-expired-fill": "rgba(255, 255, 255, 0.08)",
|
|
171
|
+
"--cg-pending-fill": "var(--cg-expired-fill)",
|
|
166
172
|
"--cg-danger-fill": "rgba(255, 255, 255, 0.08)"
|
|
167
173
|
}
|
|
168
174
|
}
|
package/package.json
CHANGED