@calliopelabs/ui 0.1.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 CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  The shared operator UI of Calliope AI: the app shell, navigation, page frame, data table and list patterns, status colours, design tokens and appearance settings that Astrolift AI and Zentinelle AI both run on. Extracted from the Astrolift AI frontend and generalized with a per-product config, so each console keeps its own name, accent, sidebar colour and navigation while sharing everything else.
4
4
 
5
- It is built Storybook first: every component and every screen pattern is built and reviewed in the catalog before an app uses it. The catalog is published at **https://calliopeai.github.io/calliope-ui/**.
5
+ The shared base of the Calliope AI ui series. Product packages (`@calliopelabs/ui-astrolift`, `ui-zentinelle`, `ui-workbench`, later `ui-chat`) depend on it and carry only what is specific to their product. `0.2.0` was published as `@calliopelabs/ui-astrolift` with the same exports; it is deprecated in favour of this package.
6
+
7
+ It is built Storybook first: every component and every screen pattern is built and reviewed in the catalog before an app uses it. The catalog is published at **https://calliope-ux.astro.conflict.cloud**.
6
8
 
7
9
  - React 19 and TypeScript, shipped as per-file ESM with types. No Next-only APIs: the app hands the package its link component.
8
10
  - Tailwind CSS 4: the theme tokens as CSS, plus a preset.
@@ -73,9 +75,9 @@ const NAV: NavModel = [
73
75
  export const astrolift = defineProduct({ ...astroliftBrand, nav: NAV });
74
76
  ```
75
77
 
76
- Astrolift AI: leaf green on the deep planet green sidebar (`#04231a`), all six grounds, graphite by default (mist when the system runs light), and its eight named themes.
78
+ Astrolift AI: leaf green on the deep planet green sidebar (`#04231a`), six grounds (every one but navy), graphite by default (mist when the system runs light), and its eight named themes.
77
79
 
78
- Zentinelle AI: teal (`#37efed`, `#0d7470` on light grounds) on the navy sidebar (`#0b0b19`), a true black ground by default, the family accents beside teal, and no emerald ground. Its seven areas gate rows by role:
80
+ Zentinelle AI: teal (`#37efed`, `#0d7470` on light grounds) on the navy sidebar (`#0b0b19`), a true black ground by default, the family accents beside teal, and no emerald or navy ground. Its seven areas gate rows by role:
79
81
 
80
82
  ```ts
81
83
  import { defineProduct, zentinelleBrand, type NavModel } from "@calliopelabs/ui";
@@ -114,6 +116,8 @@ const NAV: NavModel = [
114
116
  export const zentinelle = defineProduct({ ...zentinelleBrand, nav: NAV });
115
117
  ```
116
118
 
119
+ Calliope AI Workbench (`workbenchBrand`): Workbench blue (`#8fb8e8`, `#2f5d94` on light grounds) on a navy sidebar (`#0e1730`), its own navy ground by default (mist when the system runs light), the family accents beside its blue, and no emerald ground.
120
+
117
121
  `defineProduct` validates the config and throws on anything that would paint wrong: a colour that is not lowercase `#rrggbb`, a default ground the product does not offer, a brand accent key the family already uses.
118
122
 
119
123
  ## Wire the shell
@@ -263,7 +267,7 @@ The package fetches nothing. `DataTable` reads a `TableController`: rows, state,
263
267
 
264
268
  ## Appearance
265
269
 
266
- The person sets four axes, per product: the **ground** (black, charcoal, graphite, emerald, paper, mist; it decides light or dark), the **accent** (the product's own, a family accent, or any colour that stands 3:1 off the ground), the **density** (`compact` hairline rows or boxed `cards`) and the **corners** (0, 2, 4 or 10 px). `AppearancePicker` is the settings UI for all four.
270
+ The person sets four axes, per product: the **ground** (black, charcoal, graphite, emerald, navy, paper, mist; it decides light or dark), the **accent** (the product's own, a family accent, or any colour that stands 3:1 off the ground), the **density** (`compact` hairline rows or boxed `cards`) and the **corners** (0, 2, 4 or 10 px). `AppearancePicker` is the settings UI for all four.
267
271
 
268
272
  - Precedence: a locked org theme, then the person's choice, then the org default, then the product default. Until someone picks a ground, light or dark follows the system.
269
273
  - An org policy that arrives after sign-in goes in through `useAppearance().setPolicy`. An app that keeps the preference on its server passes `onChange` and hands the server's copy back through `applyServerAppearance`.
@@ -296,11 +300,11 @@ Conventions for contributors and agents are in [`bootstrap.md`](bootstrap.md).
296
300
 
297
301
  ## Releasing
298
302
 
299
- `publish.yml` publishes to npm as `@calliopelabs/ui` through npm trusted publishing: there is no npm token, the job's GitHub OIDC identity stands in for one, and the package carries provenance. It runs when a GitHub release is published, or by hand on an existing version tag; it refuses a branch. Before anything is published, `release-checks.yml` checks that the tag names the `package.json` version and points at the commit being built, then runs every CI gate on that commit. A prerelease version (`0.2.0-alpha.1`) goes out under the `alpha` dist-tag, and a version already on npm is left alone. Nothing in the workflows bumps a version or creates a tag.
303
+ `publish.yml` publishes to npm as `@calliopelabs/ui` through npm trusted publishing: there is no npm token, the job's GitHub OIDC identity stands in for one. The package carries no provenance while the repository is private: npm accepts provenance only from public repositories. It runs when a GitHub release is published, or by hand on an existing version tag; it refuses a branch. Before anything is published, `release-checks.yml` checks that the tag names the `package.json` version and points at the commit being built, then runs every CI gate on that commit. A prerelease version (`0.2.0-alpha.1`) goes out under the `alpha` dist-tag, and a version already on npm is left alone. Nothing in the workflows bumps a version or creates a tag.
300
304
 
301
305
  ### The first publish
302
306
 
303
- A brand new package cannot use trusted publishing: npm attaches a trusted publisher to a package that already exists. So `0.1.0` is published once by hand, by an npm account in the `calliopelabs` organization with two-factor authentication on. In a fresh clone of `main`, tag it (a tag push starts no workflow) and publish that clean checkout of the tag:
307
+ A brand new package cannot use trusted publishing: npm attaches a trusted publisher to a package that already exists. So the first version, `0.1.0`, was published once by hand, by an npm account in the `calliopelabs` organization with two-factor authentication on. In a fresh clone of `main`, tag it (a tag push starts no workflow) and publish that clean checkout of the tag:
304
308
 
305
309
  ```sh
306
310
  git clone https://github.com/calliopeai/calliope-ui.git calliope-ui-v0.1.0 && cd calliope-ui-v0.1.0
@@ -92,3 +92,97 @@ export declare const zentinelleBrand: {
92
92
  readonly light: "mist";
93
93
  };
94
94
  };
95
+ /**
96
+ * Calliope AI Workbench (JunoHub, the installer's default theme, the desktop
97
+ * splash): a sober light blue on navy. The navy comes from junohub `custom.css`
98
+ * (--calliope-dark); the hub's teal and violet are retired. Dark only today, so
99
+ * it defaults to its own navy ground, which no other product offers.
100
+ */
101
+ export declare const workbenchBrand: {
102
+ readonly id: "workbench";
103
+ readonly name: "Calliope AI Workbench";
104
+ readonly accent: {
105
+ readonly key: "workbench-blue";
106
+ readonly label: "Workbench blue";
107
+ readonly dark: "#8fb8e8";
108
+ readonly onDark: "#0b1120";
109
+ readonly light: "#2f5d94";
110
+ readonly onLight: "#f3fbf7";
111
+ };
112
+ readonly sidebar: "#0e1730";
113
+ readonly grounds: readonly ["navy", "black", "charcoal", "graphite", "paper", "mist"];
114
+ readonly defaultGround: {
115
+ readonly dark: "navy";
116
+ readonly light: "mist";
117
+ };
118
+ };
119
+ /**
120
+ * Calliope AI Chat Studio: blue, from `sql-agent-ui/src/index.css` (--brand
121
+ * in :root and .dark, --sidebar-background in .dark).
122
+ */
123
+ export declare const chatStudioBrand: {
124
+ readonly id: "chat-studio";
125
+ readonly name: "Calliope AI Chat Studio";
126
+ readonly accent: {
127
+ readonly key: "studio-blue";
128
+ readonly label: "Studio blue";
129
+ readonly dark: "#8ab4f8";
130
+ readonly onDark: "#0c0c0c";
131
+ readonly light: "#1d4ed8";
132
+ readonly onLight: "#ffffff";
133
+ };
134
+ readonly sidebar: "#080808";
135
+ readonly grounds: readonly ["black", "charcoal", "graphite", "paper", "mist"];
136
+ readonly defaultGround: {
137
+ readonly dark: "black";
138
+ readonly light: "paper";
139
+ };
140
+ };
141
+ /**
142
+ * Calliope AI Loadr: Catppuccin blue, from `frontend/src/index.css`
143
+ * (--ctp-blue for Latte and Mocha, --accent-strong-fg). Sidebar is Mocha's
144
+ * mantle. Dark by default.
145
+ */
146
+ export declare const loadrBrand: {
147
+ readonly id: "loadr";
148
+ readonly name: "Calliope AI Loadr";
149
+ readonly accent: {
150
+ readonly key: "loadr-blue";
151
+ readonly label: "Loadr blue";
152
+ readonly dark: "#89b4fa";
153
+ readonly onDark: "#11111b";
154
+ readonly light: "#1e66f5";
155
+ readonly onLight: "#ffffff";
156
+ };
157
+ readonly sidebar: "#181825";
158
+ readonly grounds: readonly ["black", "charcoal", "graphite", "paper", "mist"];
159
+ readonly defaultGround: {
160
+ readonly dark: "charcoal";
161
+ readonly light: "paper";
162
+ };
163
+ };
164
+ /**
165
+ * Cykick: cyan on near-black with square corners, from
166
+ * `ui/theme/native-themes.json` (primary, background, radius 0). Cykick's
167
+ * own plugins read tokens, not these components; the brand keeps the family
168
+ * values in one place.
169
+ */
170
+ export declare const cykickBrand: {
171
+ readonly id: "cykick";
172
+ readonly name: "Cykick";
173
+ readonly accent: {
174
+ readonly key: "cykick-cyan";
175
+ readonly label: "Cykick cyan";
176
+ readonly dark: "#22d3ee";
177
+ readonly onDark: "#07090e";
178
+ readonly light: "#0e7490";
179
+ readonly onLight: "#ffffff";
180
+ };
181
+ readonly sidebar: "#07090e";
182
+ readonly grounds: readonly ["black", "charcoal", "graphite", "paper", "mist"];
183
+ readonly defaultGround: {
184
+ readonly dark: "black";
185
+ readonly light: "mist";
186
+ };
187
+ readonly defaultCorners: 0;
188
+ };
@@ -59,3 +59,93 @@ export const zentinelleBrand = {
59
59
  grounds: ["black", "charcoal", "graphite", "paper", "mist"],
60
60
  defaultGround: { dark: "black", light: "mist" },
61
61
  };
62
+ /*
63
+ * The brands below are copied from what each product ships today, so nothing
64
+ * changes when an app moves onto the library. Where a product has no value
65
+ * the model needs (usually a light-ground accent), the nearest one that
66
+ * passes the contrast tests is used and marked "derived" for the designer.
67
+ */
68
+ /**
69
+ * Calliope AI Workbench (JunoHub, the installer's default theme, the desktop
70
+ * splash): a sober light blue on navy. The navy comes from junohub `custom.css`
71
+ * (--calliope-dark); the hub's teal and violet are retired. Dark only today, so
72
+ * it defaults to its own navy ground, which no other product offers.
73
+ */
74
+ export const workbenchBrand = {
75
+ id: "workbench",
76
+ name: "Calliope AI Workbench",
77
+ accent: {
78
+ key: "workbench-blue",
79
+ label: "Workbench blue",
80
+ dark: "#8fb8e8",
81
+ onDark: "#0b1120",
82
+ // derived: the hub has no light ground
83
+ light: "#2f5d94",
84
+ onLight: "#f3fbf7",
85
+ },
86
+ sidebar: "#0e1730",
87
+ grounds: ["navy", "black", "charcoal", "graphite", "paper", "mist"],
88
+ defaultGround: { dark: "navy", light: "mist" },
89
+ };
90
+ /**
91
+ * Calliope AI Chat Studio: blue, from `sql-agent-ui/src/index.css` (--brand
92
+ * in :root and .dark, --sidebar-background in .dark).
93
+ */
94
+ export const chatStudioBrand = {
95
+ id: "chat-studio",
96
+ name: "Calliope AI Chat Studio",
97
+ accent: {
98
+ key: "studio-blue",
99
+ label: "Studio blue",
100
+ dark: "#8ab4f8",
101
+ onDark: "#0c0c0c",
102
+ light: "#1d4ed8",
103
+ onLight: "#ffffff",
104
+ },
105
+ sidebar: "#080808",
106
+ grounds: ["black", "charcoal", "graphite", "paper", "mist"],
107
+ defaultGround: { dark: "black", light: "paper" },
108
+ };
109
+ /**
110
+ * Calliope AI Loadr: Catppuccin blue, from `frontend/src/index.css`
111
+ * (--ctp-blue for Latte and Mocha, --accent-strong-fg). Sidebar is Mocha's
112
+ * mantle. Dark by default.
113
+ */
114
+ export const loadrBrand = {
115
+ id: "loadr",
116
+ name: "Calliope AI Loadr",
117
+ accent: {
118
+ key: "loadr-blue",
119
+ label: "Loadr blue",
120
+ dark: "#89b4fa",
121
+ onDark: "#11111b",
122
+ light: "#1e66f5",
123
+ onLight: "#ffffff",
124
+ },
125
+ sidebar: "#181825",
126
+ grounds: ["black", "charcoal", "graphite", "paper", "mist"],
127
+ defaultGround: { dark: "charcoal", light: "paper" },
128
+ };
129
+ /**
130
+ * Cykick: cyan on near-black with square corners, from
131
+ * `ui/theme/native-themes.json` (primary, background, radius 0). Cykick's
132
+ * own plugins read tokens, not these components; the brand keeps the family
133
+ * values in one place.
134
+ */
135
+ export const cykickBrand = {
136
+ id: "cykick",
137
+ name: "Cykick",
138
+ accent: {
139
+ key: "cykick-cyan",
140
+ label: "Cykick cyan",
141
+ dark: "#22d3ee",
142
+ onDark: "#07090e",
143
+ // derived: no light accent in native-themes.json
144
+ light: "#0e7490",
145
+ onLight: "#ffffff",
146
+ },
147
+ sidebar: "#07090e",
148
+ grounds: ["black", "charcoal", "graphite", "paper", "mist"],
149
+ defaultGround: { dark: "black", light: "mist" },
150
+ defaultCorners: 0,
151
+ };
@@ -36,7 +36,7 @@ export interface ProductConfig {
36
36
  accent: FamilyAccent | BrandAccent;
37
37
  /** The brand surface: the sidebar on dark grounds (graphite and light grounds stay neutral). */
38
38
  sidebar: string;
39
- /** The grounds offered, in picker order. All six when absent. */
39
+ /** The grounds offered, in picker order. All seven when absent. */
40
40
  grounds?: readonly Ground[];
41
41
  /** The ground until someone chooses: one per mode, following the operating system. */
42
42
  defaultGround?: {
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { cn } from "./lib/cn.js";
8
8
  export { ACCENTS, ACCENT_KEYS, DENSITIES, DENSITY_KEYS, GROUNDS, GROUND_KEYS, MODE_TOKENS, SURFACES, type AccentSpec, type Density, type FamilyAccent, type Ground, type Mode, type StatusName, } from "./theme/tokens.js";
9
9
  export { MIN_NON_TEXT_CONTRAST, MIN_TEXT_CONTRAST, contrastRatio, luminance, } from "./theme/contrast.js";
10
10
  export { CORNERS, defineProduct, type BrandAccent, type Corners, type Product, type ProductAccent, type ProductConfig, type ProductTheme, } from "./appearance/product.js";
11
- export { astroliftBrand, zentinelleBrand } from "./appearance/brands.js";
11
+ export { astroliftBrand, chatStudioBrand, cykickBrand, loadrBrand, workbenchBrand, zentinelleBrand, } from "./appearance/brands.js";
12
12
  export { accentContrast, appearanceFromServer, applyAppearance, clearAppearance, inkFor, isCustomAccent, modeFor, normalize, normalizePartial, parseCustomAccent, readAppearance, resolveAppearance, writeAppearance, type Appearance, type CustomAccent, type OrgAppearancePolicy, type ResolvedAppearance, } from "./appearance/appearance.js";
13
13
  export { appearanceScript, productStyles } from "./appearance/boot.js";
14
14
  export { AppearanceScript, type AppearanceScriptProps } from "./appearance/AppearanceScript.js";
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ export { ACCENTS, ACCENT_KEYS, DENSITIES, DENSITY_KEYS, GROUNDS, GROUND_KEYS, MO
11
11
  export { MIN_NON_TEXT_CONTRAST, MIN_TEXT_CONTRAST, contrastRatio, luminance, } from "./theme/contrast.js";
12
12
  // Product and appearance
13
13
  export { CORNERS, defineProduct, } from "./appearance/product.js";
14
- export { astroliftBrand, zentinelleBrand } from "./appearance/brands.js";
14
+ export { astroliftBrand, chatStudioBrand, cykickBrand, loadrBrand, workbenchBrand, zentinelleBrand, } from "./appearance/brands.js";
15
15
  export { accentContrast, appearanceFromServer, applyAppearance, clearAppearance, inkFor, isCustomAccent, modeFor, normalize, normalizePartial, parseCustomAccent, readAppearance, resolveAppearance, writeAppearance, } from "./appearance/appearance.js";
16
16
  export { appearanceScript, productStyles } from "./appearance/boot.js";
17
17
  export { AppearanceScript } from "./appearance/AppearanceScript.js";
@@ -200,6 +200,22 @@
200
200
  --sidebar-border: rgba(255, 255, 255, 0.08);
201
201
  }
202
202
 
203
+ /* Ground: Navy (dark) */
204
+ [data-mode="dark"][data-ground="navy"] {
205
+ --background: #0b1120;
206
+ --card: #152141;
207
+ --popover: #1a284a;
208
+ --secondary: #1d2b50;
209
+ --muted: #182545;
210
+ --accent: #213157;
211
+ --muted-foreground: #97a6c2;
212
+ --border: rgba(255, 255, 255, 0.1);
213
+ --input: rgba(255, 255, 255, 0.1);
214
+ --sidebar: var(--brand-sidebar, #152141);
215
+ --sidebar-accent: color-mix(in oklab, var(--primary) 16%, transparent);
216
+ --sidebar-border: rgba(255, 255, 255, 0.08);
217
+ }
218
+
203
219
  /* Ground: Paper (light) */
204
220
  [data-mode="light"][data-ground="paper"] {
205
221
  --background: #faf6ee;
@@ -32,6 +32,10 @@ export declare const GROUNDS: {
32
32
  readonly label: "Emerald";
33
33
  readonly mode: "dark";
34
34
  };
35
+ readonly navy: {
36
+ readonly label: "Navy";
37
+ readonly mode: "dark";
38
+ };
35
39
  readonly paper: {
36
40
  readonly label: "Paper";
37
41
  readonly mode: "light";
@@ -19,6 +19,7 @@ export const GROUNDS = {
19
19
  charcoal: { label: "Charcoal", mode: "dark" },
20
20
  graphite: { label: "Graphite", mode: "dark" },
21
21
  emerald: { label: "Emerald", mode: "dark" },
22
+ navy: { label: "Navy", mode: "dark" },
22
23
  paper: { label: "Paper", mode: "light" },
23
24
  mist: { label: "Mist", mode: "light" },
24
25
  };
@@ -82,6 +83,27 @@ export const SURFACES = {
82
83
  sidebarAccent: PRIMARY_TINT_16,
83
84
  sidebarBorder: "rgba(255, 255, 255, 0.08)",
84
85
  },
86
+ /*
87
+ * Workbench's navy, from JunoHub's palette: page #0b1120 and card
88
+ * rgba(22, 35, 69, 0.9) composited on the page, with the neutral hairlines
89
+ * every other dark ground uses. Its text colours are not carried over: foreground is per mode,
90
+ * and the hub's muted text (#e6e9ee) is not muted, so muted text is a
91
+ * navy-tinted grey that reads on every panel.
92
+ */
93
+ navy: {
94
+ background: "#0b1120",
95
+ card: "#152141",
96
+ popover: "#1a284a",
97
+ secondary: "#1d2b50",
98
+ muted: "#182545",
99
+ accent: "#213157",
100
+ mutedForeground: "#97a6c2",
101
+ border: "rgba(255, 255, 255, 0.1)",
102
+ input: "rgba(255, 255, 255, 0.1)",
103
+ sidebar: "brand",
104
+ sidebarAccent: PRIMARY_TINT_16,
105
+ sidebarBorder: "rgba(255, 255, 255, 0.08)",
106
+ },
85
107
  paper: {
86
108
  background: "#faf6ee",
87
109
  card: "#fffdf9",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calliopelabs/ui",
3
- "version": "0.1.0",
3
+ "version": "0.4.0",
4
4
  "description": "Calliope AI shared operator UI: app shell, navigation, page frame, data table and list patterns, status colours, design tokens and appearance for Astrolift AI and Zentinelle AI.",
5
5
  "keywords": [
6
6
  "calliope-ai",