@justai/cuts 0.138.0 → 0.140.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/package.json +3 -3
- package/src/ActionList.astro +27 -31
- package/src/ActionRow.astro +64 -68
- package/src/BackToZone.astro +35 -39
- package/src/Catalogue.astro +88 -88
- package/src/CatalogueCard.astro +68 -72
- package/src/ChildPersona.astro +51 -55
- package/src/ConfirmSheet.astro +65 -69
- package/src/FilePicker.astro +13 -17
- package/src/LangPicker.astro +41 -45
- package/src/Posts.astro +169 -173
- package/src/Preroll.astro +193 -197
- package/src/Profile.astro +35 -39
- package/src/Segmented.astro +54 -58
- package/src/Sheet.astro +212 -237
- package/src/Toolbar.astro +280 -284
- package/src/behaviour/catalogue.ts +16 -8
- package/src/ground.css +120 -124
|
@@ -27,13 +27,18 @@
|
|
|
27
27
|
const locale = document.documentElement.lang || "en";
|
|
28
28
|
const NEW_MS = 7 * 864e5; // a persona wears NEW only for its first week (honest — from its createdAt)
|
|
29
29
|
const newLabel = grid.dataset.newLabel || "New";
|
|
30
|
-
// queries: which personas appear on this apex · runtime append kind · why is my game not listed
|
|
30
|
+
// queries: which personas appear on this apex · runtime append kind · why is my game not listed ·
|
|
31
|
+
// a CiM persona is missing from its storefront · apex query parameter · mixed-kind apex
|
|
31
32
|
//
|
|
32
33
|
// WHICH CITIZENS THIS APEX LISTS — where the hostname test used to be. A bundled script cannot
|
|
33
|
-
// reach this component's props, so the
|
|
34
|
-
// newLabel and catMap.
|
|
35
|
-
//
|
|
36
|
-
|
|
34
|
+
// reach this component's props, so the fact it needs rides the same data-attribute channel as
|
|
35
|
+
// newLabel and catMap.
|
|
36
|
+
//
|
|
37
|
+
// IT ASKS THE REGISTRY BY HOUSEHOLD, NOT BY SPECIES, and the difference only became visible with a
|
|
38
|
+
// third apex. `kind` selects a SORT of persona; on app.zone and pin.games that happens to select
|
|
39
|
+
// the residents too, because every citizen of those two is the same sort. cityinmotion.nl is the
|
|
40
|
+
// household where they part — its citizens are sometimes games and sometimes apps — and asking it
|
|
41
|
+
// for one kind returns half a family and calls that the storefront.
|
|
37
42
|
const apexHost = grid.dataset.apex || "app.zone";
|
|
38
43
|
// The category label must be localized like the SSR path (catLabel), but the API returns the
|
|
39
44
|
// category in English regardless of ?locale=. So carry this page's cat dictionary through a data
|
|
@@ -93,13 +98,16 @@
|
|
|
93
98
|
return `<a class="card" href="${esc(url)}" data-name="${esc(name.toLowerCase())}" data-category="${esc(cat)}" data-id="${esc((a.handle || "").toLowerCase())}" data-added="${esc(a.createdAt || "")}">${icon}<div class="meta"><div class="top"><h2>${esc(name)}</h2>${badge}</div><p>${esc(tagMap[a.home] ?? a.bio ?? "")}</p></div><svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg></a>`;
|
|
94
99
|
};
|
|
95
100
|
|
|
96
|
-
fetch(`https://api.justai.pro/api/catalog?locale=${encodeURIComponent(locale)}&
|
|
101
|
+
fetch(`https://api.justai.pro/api/catalog?locale=${encodeURIComponent(locale)}&apex=${encodeURIComponent(apexHost)}`)
|
|
97
102
|
.then((r) => (r.ok ? r.json() : null))
|
|
98
103
|
.then((data) => {
|
|
99
104
|
if (!data || !data.personas) return;
|
|
100
105
|
const newcomers = (data.personas as Entry[]).filter(
|
|
101
|
-
//
|
|
102
|
-
//
|
|
106
|
+
// THE RESIDENCY TEST STAYS, AND IS NOW A REDUNDANCY ON PURPOSE. Asking by apex means the
|
|
107
|
+
// registry has already excluded the other households AND the platform furniture that stands
|
|
108
|
+
// on no shelf, so this filter should never remove anything. It is kept because a browser can
|
|
109
|
+
// be holding a cached response from before the question changed, and because a storefront
|
|
110
|
+
// listing somebody else's citizen is the one failure here that looks fine.
|
|
103
111
|
//
|
|
104
112
|
// queries: auth appeared on app.zone · a persona from another apex is listed · why both
|
|
105
113
|
// kind and home · residency
|
package/src/ground.css
CHANGED
|
@@ -27,139 +27,135 @@
|
|
|
27
27
|
* checks the tokens statically, but only a bare-page render proves it.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
:where(:root) {
|
|
31
|
+
/* skeleton — mirrors @justai/ui tokens.css, pinned equal by the harness */
|
|
32
|
+
--fs-2xs: 0.76rem;
|
|
33
|
+
--fs-xs: 0.84rem;
|
|
34
|
+
--fs-sm: 0.92rem;
|
|
35
|
+
--fs-base: 1rem;
|
|
36
|
+
--fs-md: 1.13rem;
|
|
37
|
+
--fs-lg: 1.32rem;
|
|
38
|
+
--fs-xl: 1.6rem;
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
--fs-xs: 0.84rem;
|
|
37
|
-
--fs-sm: 0.92rem;
|
|
38
|
-
--fs-base: 1rem;
|
|
39
|
-
--fs-md: 1.13rem;
|
|
40
|
-
--fs-lg: 1.32rem;
|
|
41
|
-
--fs-xl: 1.6rem;
|
|
40
|
+
--radius-sm: 10px;
|
|
41
|
+
--radius-md: 14px;
|
|
42
|
+
--radius-lg: 20px;
|
|
43
|
+
--radius-pill: 999px;
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
--radius-lg: 20px;
|
|
46
|
-
--radius-pill: 999px;
|
|
45
|
+
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
46
|
+
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
/* ground — the fleet-neutral defaults for the colour contract (dark first: the fleet's default scheme) */
|
|
49
|
+
--font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Inter", system-ui, sans-serif;
|
|
50
|
+
--bg: #0a0c10;
|
|
51
|
+
--text: #f2f4f8;
|
|
52
|
+
--text-dim: #9aa3b2;
|
|
53
|
+
--border: rgba(255, 255, 255, 0.1);
|
|
54
|
+
--surface: rgba(255, 255, 255, 0.04);
|
|
55
|
+
--surface-2: rgba(255, 255, 255, 0.07);
|
|
56
|
+
--accent: #0a84ff;
|
|
57
|
+
/* THE INK ON A FILLED ACCENT. Every persona already declares this — the template writes it from
|
|
58
|
+
the accent's own `color.on` — but no cut had rendered a filled accent button until <Preroll>'s
|
|
59
|
+
play surface, so it had never needed a ground and did not have one. It arrives with the same
|
|
60
|
+
lesson the card tokens above carry: a token is not grounded because the fleet defines it, it is
|
|
61
|
+
grounded because THIS package does. The value pairs with the `--accent` on the line above and
|
|
62
|
+
is not scheme-aware, because that accent is not either.
|
|
63
|
+
A persona whose accent is pale — a yellow, an orange — must override it, and every one of them
|
|
64
|
+
already does; white ink on a #f5a623 button is the failure this token exists to prevent. */
|
|
65
|
+
--accent-on: #ffffff;
|
|
66
|
+
/* THE ecosystem's destructive red — Apple's system red, and one of it. Written here rather than
|
|
67
|
+
in each component because a confirmation sheet and a Sign Out row saying "this ends something"
|
|
68
|
+
in two different reds is exactly the drift the ConfirmSheet's own header warns about. It is
|
|
69
|
+
scheme-aware: Apple lightens red on dark backgrounds (#FF453A) and deepens it on light
|
|
70
|
+
(#FF3B30), and a single value would read wrong on one of them. */
|
|
71
|
+
--danger: #ff453a;
|
|
50
72
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
the accent's own `color.on` — but no cut had rendered a filled accent button until <Preroll>'s
|
|
62
|
-
play surface, so it had never needed a ground and did not have one. It arrives with the same
|
|
63
|
-
lesson the card tokens above carry: a token is not grounded because the fleet defines it, it is
|
|
64
|
-
grounded because THIS package does. The value pairs with the `--accent` on the line above and
|
|
65
|
-
is not scheme-aware, because that accent is not either.
|
|
66
|
-
A persona whose accent is pale — a yellow, an orange — must override it, and every one of them
|
|
67
|
-
already does; white ink on a #f5a623 button is the failure this token exists to prevent. */
|
|
68
|
-
--accent-on: #ffffff;
|
|
69
|
-
/* THE ecosystem's destructive red — Apple's system red, and one of it. Written here rather than
|
|
70
|
-
in each component because a confirmation sheet and a Sign Out row saying "this ends something"
|
|
71
|
-
in two different reds is exactly the drift the ConfirmSheet's own header warns about. It is
|
|
72
|
-
scheme-aware: Apple lightens red on dark backgrounds (#FF453A) and deepens it on light
|
|
73
|
-
(#FF3B30), and a single value would read wrong on one of them. */
|
|
74
|
-
--danger: #ff453a;
|
|
73
|
+
/* THE CARD — a storefront tile's own surface, and the reason it is here rather than in the apex
|
|
74
|
+
that used to own it. The Catalogue moved into this package the day pin.games became real, and
|
|
75
|
+
it arrived consuming four tokens that had stayed behind in app.zone's stylesheet. Nothing broke
|
|
76
|
+
on app.zone, which still grounds them; the harness caught it anyway, and the founder put the
|
|
77
|
+
stake in the ground in one line: *why would pin.games have shadowless cards — whatever I see on
|
|
78
|
+
app.zone, that is it.* These are app.zone's own values, read rather than redesigned, so the
|
|
79
|
+
second storefront is the first one. */
|
|
80
|
+
--card-bg: rgba(28, 28, 34, 0.55);
|
|
81
|
+
--card-blur: blur(30px) saturate(1.6);
|
|
82
|
+
--card-shadow-hover: 0 2px 6px rgba(0, 0, 0, 0.4), 0 12px 28px -14px rgba(0, 0, 0, 0.55);
|
|
75
83
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
* So the scale is named by ELEVATION — how far off the page a thing is — and the catalogue's own
|
|
101
|
-
* token now reads from it rather than restating it. `--card-shadow` stays because live personas
|
|
102
|
-
* consume it; it is an alias now, not a second definition.
|
|
103
|
-
*
|
|
104
|
-
* The law: **nothing that is not a sheet may exceed `--shadow-card`, and no shadow is coloured.**
|
|
105
|
-
* A tinted shadow is a glow, a glow is a light source, and this ground has one sun and no lamps. */
|
|
106
|
-
--shadow-card: 0 1px 2px 0 rgba(0, 0, 0, 0.32);
|
|
107
|
-
--shadow-bar: 0 2px 12px -2px rgba(0, 0, 0, 0.55);
|
|
108
|
-
--shadow-sheet: 0 18px 40px -20px rgba(0, 0, 0, 0.45);
|
|
109
|
-
--card-shadow: var(--shadow-card);
|
|
110
|
-
}
|
|
84
|
+
/* ── ELEVATION — mirrors @justai/ui tokens.css, and the tokens spec holds the two identical ──
|
|
85
|
+
*
|
|
86
|
+
* queries: box shadow token · which shadow · the panel looks detached · drop shadow standard ·
|
|
87
|
+
* golge standardi · card shadow vs sheet shadow
|
|
88
|
+
*
|
|
89
|
+
* THE VALUES WERE ALREADY HERE, under one name and one meaning: `--card-shadow`, described as
|
|
90
|
+
* "a storefront tile's own surface". Measured across the live fleet on 2026-08-20 they turned out
|
|
91
|
+
* to be the shadow of EVERY resting surface — app.zone's catalogue cards, qr's type buttons,
|
|
92
|
+
* calculator's panel, all byte-identical — so the name was narrower than the fact, and a persona
|
|
93
|
+
* building its own kernel panel had nothing to reach for and invented one. The one that produced
|
|
94
|
+
* the ruling had invented a MODAL's: twice the opacity, 3.7× the blur, and in dark deeper than
|
|
95
|
+
* the fleet's actual modal.
|
|
96
|
+
*
|
|
97
|
+
* So the scale is named by ELEVATION — how far off the page a thing is — and the catalogue's own
|
|
98
|
+
* token now reads from it rather than restating it. `--card-shadow` stays because live personas
|
|
99
|
+
* consume it; it is an alias now, not a second definition.
|
|
100
|
+
*
|
|
101
|
+
* The law: **nothing that is not a sheet may exceed `--shadow-card`, and no shadow is coloured.**
|
|
102
|
+
* A tinted shadow is a glow, a glow is a light source, and this ground has one sun and no lamps. */
|
|
103
|
+
--shadow-card: 0 1px 2px 0 rgba(0, 0, 0, 0.32);
|
|
104
|
+
--shadow-bar: 0 2px 12px -2px rgba(0, 0, 0, 0.55);
|
|
105
|
+
--shadow-sheet: 0 18px 40px -20px rgba(0, 0, 0, 0.45);
|
|
106
|
+
--card-shadow: var(--shadow-card);
|
|
107
|
+
}
|
|
111
108
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
109
|
+
/* queries: force dark while playing · theme switch · data-theme dark · stage theme
|
|
110
|
+
* THE GUARD IS THE FLEET'S OWN IDIOM — time's wall wrote it first: *"data-theme wins over the media
|
|
111
|
+
* query in both directions."* A light-system visitor whose page carries data-theme="dark" gets the
|
|
112
|
+
* dark theme this file already ships; removing the attribute returns them to auto. The stage
|
|
113
|
+
* protocol is the first caster (a game playing = dark), and any future manual theme switch gets
|
|
114
|
+
* this seam for free. */
|
|
115
|
+
@media (prefers-color-scheme: light) {
|
|
116
|
+
:where(:root:not([data-theme="dark"])) {
|
|
117
|
+
--bg: #f6f7f9;
|
|
118
|
+
--text: #0a0c10;
|
|
119
|
+
--text-dim: #5b6472;
|
|
120
|
+
--border: rgba(0, 0, 0, 0.08);
|
|
121
|
+
--surface: rgba(255, 255, 255, 0.7);
|
|
122
|
+
--surface-2: rgba(0, 0, 0, 0.05);
|
|
123
|
+
--danger: #ff3b30;
|
|
127
124
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
125
|
+
/* Light is not the dark card with a different fill: the blur goes away entirely. A frosted
|
|
126
|
+
panel over a pale page reads as a smudge, so app.zone drops it and pays the shadow instead. */
|
|
127
|
+
--card-bg: #fff;
|
|
128
|
+
--card-blur: none;
|
|
129
|
+
--card-shadow-hover: 0 2px 4px rgba(16, 24, 40, 0.06), 0 12px 26px -8px rgba(16, 24, 40, 0.15);
|
|
133
130
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
131
|
+
/* Light needs TWO layers where dark needs one: on a near-white ground a single ambient blur
|
|
132
|
+
reads as dirt, so the pair is a 1px contact line that seats the object plus a wide, faint
|
|
133
|
+
ambient. `--card-shadow` inherits its alias from the block above and needs no line here. */
|
|
134
|
+
--shadow-card: 0 1px 2px 0 rgba(16, 24, 40, 0.05), 0 4px 12px -4px rgba(16, 24, 40, 0.1);
|
|
135
|
+
--shadow-bar: 0 1px 2px rgba(16, 24, 40, 0.06), 0 8px 20px -8px rgba(16, 24, 40, 0.16);
|
|
136
|
+
--shadow-sheet: 0 18px 40px -20px rgba(0, 0, 0, 0.45);
|
|
141
137
|
}
|
|
138
|
+
}
|
|
142
139
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
140
|
+
/* The page's ground — margin reset, the fleet's type baseline, and the page colour ON :where(html),
|
|
141
|
+
* NEVER on body. Learned live, fleet-wide, within a day: personas paint their dot-grid on html and
|
|
142
|
+
* leave body's background UNDECLARED — relying on the web's default transparency structurally, not
|
|
143
|
+
* by declaration. Zero specificity beats a declaration that exists; it still fills one that never
|
|
144
|
+
* did. A body background from the ground, with the fleet's `body{height:100%}`, painted an opaque
|
|
145
|
+
* viewport-tall box over the top of every grid — dots gone at the top, reappearing where body ends.
|
|
146
|
+
* The founder saw it before any instrument did. The rule that survives: THE GROUND MAY ONLY SUPPLY
|
|
147
|
+
* WHAT A BARE PAGE LACKS ON ELEMENTS CONSUMERS DECLARE — html's background is declared by every
|
|
148
|
+
* persona (they win); body's transparency is load-bearing and stays untouched. */
|
|
149
|
+
/* What the shell takes above the kernel — see @justai/ui base.css, which measures it. Ground only:
|
|
150
|
+
`:where()` is specificity zero, so a consumer that ships the shell always wins, and a surface that
|
|
151
|
+
ships no shell still lands its cuts clear of a sticky bar instead of under one. */
|
|
152
|
+
:where(:root) { --shell-top: 78px; }
|
|
156
153
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
154
|
+
:where(html) {
|
|
155
|
+
background: var(--bg);
|
|
156
|
+
}
|
|
157
|
+
:where(body) {
|
|
158
|
+
margin: 0;
|
|
159
|
+
color: var(--text);
|
|
160
|
+
font: 1rem/1.5 var(--font);
|
|
165
161
|
}
|