@justai/cuts 0.140.0 → 0.142.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 +2 -2
- package/src/BackToZone.astro +33 -2
- package/src/Catalogue.astro +20 -3
- package/src/Toolbar.astro +7 -2
- package/src/behaviour/posts.ts +34 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justai/cuts",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A persona's named parts
|
|
3
|
+
"version": "0.142.0",
|
|
4
|
+
"description": "A persona's named parts — the page shell that holds them, and the cuts themselves.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
package/src/BackToZone.astro
CHANGED
|
@@ -43,12 +43,41 @@
|
|
|
43
43
|
// geometry here is a second copy of the one in that file, which is authored by hand and generated by
|
|
44
44
|
// nothing — a redraw has to be carried across to this component as well.
|
|
45
45
|
interface Props {
|
|
46
|
-
/**
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Which storefront "home" means here. Defaults to app.zone — the fleet as it stood.
|
|
48
|
+
*
|
|
49
|
+
* A STRING, NOT A UNION OF THE TWO APEXES WE HAPPENED TO HAVE. The union was a fourth copy of the
|
|
50
|
+
* apex table (the others: edge-router's `apexes`, core's `STREAMS`, the generator's `APEXES`), and
|
|
51
|
+
* it is the copy that fails LOUDEST — a third household could not type-check, which is how it was
|
|
52
|
+
* found. Loud is the good outcome; the quiet one is below.
|
|
53
|
+
*/
|
|
54
|
+
apex?: string;
|
|
48
55
|
}
|
|
49
56
|
const { apex = "app.zone" } = Astro.props;
|
|
50
57
|
const href = `https://${apex}`;
|
|
51
58
|
|
|
59
|
+
/**
|
|
60
|
+
* queries: the home mark is app.zone's on another apex · no home button on a new apex · a household
|
|
61
|
+
* with no mark · why does my persona have no home affordance · BackToZone renders nothing
|
|
62
|
+
*
|
|
63
|
+
* AN APEX WE CANNOT DRAW GETS NO CONTROL AT ALL — and that is the honest outcome, not a gap.
|
|
64
|
+
*
|
|
65
|
+
* This was `apex === "pin.games" ? pinMark : appzoneMark`, a ternary whose ELSE branch quietly meant
|
|
66
|
+
* "app.zone". Point a third household at it and the control renders app.zone's four-arm mark, labelled
|
|
67
|
+
* with the other domain, linking to a front door that may not even be served yet: a wrong brand, on
|
|
68
|
+
* somebody else's name, as a dead link. Nothing errors. Nothing looks broken.
|
|
69
|
+
*
|
|
70
|
+
* So the marks are a TABLE and the fallback is nothing. Law 1 says a component brings its own ground;
|
|
71
|
+
* a component that cannot represent a household must decline rather than borrow another's face. The
|
|
72
|
+
* toolbar already survives this — `BackToZone` sizes and pulls itself, and the row is written for its
|
|
73
|
+
* absence — so the whole degradation is one missing control.
|
|
74
|
+
*
|
|
75
|
+
* It self-corrects: the day a household has a mark here, every persona under it grows the affordance
|
|
76
|
+
* on its next build, with no persona-level change anywhere.
|
|
77
|
+
*/
|
|
78
|
+
const MARKS = ["app.zone", "pin.games"];
|
|
79
|
+
const drawable = MARKS.includes(apex);
|
|
80
|
+
|
|
52
81
|
// queries: the home mark is missing arms · the mark is the wrong size · 36px · scoped styles do
|
|
53
82
|
// not apply · set:html · data-astro-cid
|
|
54
83
|
//
|
|
@@ -67,6 +96,7 @@ const href = `https://${apex}`;
|
|
|
67
96
|
// Elements again. The ternary was never the problem.
|
|
68
97
|
---
|
|
69
98
|
|
|
99
|
+
{drawable && (
|
|
70
100
|
<a class="home" href={href} data-home aria-label={apex} title={apex}>
|
|
71
101
|
{apex === "pin.games" ? (
|
|
72
102
|
<svg class="pgmark" viewBox="287 266 482 491" aria-hidden="true">
|
|
@@ -90,6 +120,7 @@ const href = `https://${apex}`;
|
|
|
90
120
|
</svg>
|
|
91
121
|
)}
|
|
92
122
|
</a>
|
|
123
|
+
)}
|
|
93
124
|
|
|
94
125
|
<style>
|
|
95
126
|
/* icon-only, flat — flush to the left edge of the (full-bleed) toolbar */
|
package/src/Catalogue.astro
CHANGED
|
@@ -43,7 +43,24 @@ interface Props {
|
|
|
43
43
|
/** BCP-47 code of the page — the language the registry is asked for. */
|
|
44
44
|
lang: string;
|
|
45
45
|
/** Which citizens this apex lists. The whole difference between two storefronts. */
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
|
+
* queries: Catalogue kind prop · data-kind on the grid · what kind does a mixed household pass ·
|
|
48
|
+
* vestigial prop · why is kind optional now
|
|
49
|
+
*
|
|
50
|
+
* VESTIGIAL, AND KEPT ONLY SO THE TWO EXISTING APEXES STILL COMPILE.
|
|
51
|
+
*
|
|
52
|
+
* It fed one thing: `data-kind` on the grid, which the runtime append read to ask the registry
|
|
53
|
+
* `?kind=`. That question moved to `?apex=` when a household arrived whose citizens are not all one
|
|
54
|
+
* species, and the attribute lost its last reader in the same change. (`data-kind` on `<html>` is a
|
|
55
|
+
* DIFFERENT attribute, written by Base and read by @justai/ui for a game kernel's geometry — that
|
|
56
|
+
* one is alive.)
|
|
57
|
+
*
|
|
58
|
+
* Optional rather than deleted because `app.zone` and `pin.games` still pass it, and a required prop
|
|
59
|
+
* removed is a build error in two repos for no gain. It goes when they next build. A mixed household
|
|
60
|
+
* has no answer to it at all, which is the clearest possible statement that it was the wrong
|
|
61
|
+
* question here.
|
|
62
|
+
*/
|
|
63
|
+
kind?: string;
|
|
47
64
|
/** The apex's own host, used for the referral parameter on every card. */
|
|
48
65
|
apexHost: string;
|
|
49
66
|
/** Layer one. Empty is valid and correct for an apex with nothing seeded yet. */
|
|
@@ -85,7 +102,7 @@ interface Props {
|
|
|
85
102
|
};
|
|
86
103
|
}
|
|
87
104
|
const {
|
|
88
|
-
lang,
|
|
105
|
+
lang, apexHost,
|
|
89
106
|
seed = [], order = [], taglines = {}, catLabels = {}, entries = {},
|
|
90
107
|
locales, strings,
|
|
91
108
|
} = Astro.props;
|
|
@@ -211,7 +228,7 @@ const isNew = (added: string): boolean => { const t0 = Date.parse(added || "");
|
|
|
211
228
|
{/* taglines ride the same channel as newLabel and catMap: a data attribute on the grid. The
|
|
212
229
|
runtime append builds its cards in plain strings and cannot reach this component's scope, so
|
|
213
230
|
anything it needs has to arrive this way. Keyed by host, which is what the API calls `home`. */}
|
|
214
|
-
<section class="grid" id="grid" data-
|
|
231
|
+
<section class="grid" id="grid" data-apex={apexHost} data-new-label={strings.new} data-cat-map={JSON.stringify(catLabels)} data-order={JSON.stringify(order)} data-taglines={JSON.stringify(taglines)}>
|
|
215
232
|
{seed.map((app) => <CatalogueCard app={app} name={appName(app)} desc={appDesc(app)} isNew={isNew(app.added)} newLabel={strings.new} />)}
|
|
216
233
|
</section>
|
|
217
234
|
{/* queries: runtime cards are unstyled · the card has no CSS · an apex with no seed · scope cid ·
|
package/src/Toolbar.astro
CHANGED
|
@@ -61,8 +61,13 @@ interface Props {
|
|
|
61
61
|
// destination, and justai.pro is above it (sending the parent "home" to a child platform is
|
|
62
62
|
// the wrong direction). Every other persona keeps it.
|
|
63
63
|
home?: boolean;
|
|
64
|
-
/**
|
|
65
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Which storefront the home affordance points at. Defaults to app.zone — see BackToZone, which owns
|
|
66
|
+
* the marks and DECLINES to draw a household it has no mark for rather than borrowing app.zone's.
|
|
67
|
+
* A string, not a union: the ecosystem grows households, and a type that lists two of them is a
|
|
68
|
+
* fourth copy of the apex table.
|
|
69
|
+
*/
|
|
70
|
+
apex?: string;
|
|
66
71
|
|
|
67
72
|
// Posts is required only where there IS a stream (doctrine 02 — an empty cut shipped to look
|
|
68
73
|
// complete is the buffet). A child persona has none, so `parent` turns this off by default.
|
package/src/behaviour/posts.ts
CHANGED
|
@@ -144,6 +144,33 @@
|
|
|
144
144
|
// So there is no fallback now. If we were not told where a persona lives, its name is rendered
|
|
145
145
|
// WITHOUT a link: a name that goes nowhere is a small disappointment, and a name that goes
|
|
146
146
|
// somewhere wrong is a broken ecosystem seen by a stranger.
|
|
147
|
+
// queries: apex logo has a tile in the feed · app.zone tiled on justai's page · which personas sign
|
|
148
|
+
// bare · is this persona an apex · favicon.svg vs icon.svg for a commenter
|
|
149
|
+
//
|
|
150
|
+
// AN APEX SIGNS BARE; EVERYONE ELSE WEARS THEIR TILE. A persona signing its OWN posts already gets
|
|
151
|
+
// this through `avatarSrc`/`avatarBare`, which is how each apex hands itself the bare pair. Another
|
|
152
|
+
// persona replying did not: it was drawn from the registry's `avatar` — /icon.svg, the tile — so on
|
|
153
|
+
// an apex's own page the two sibling apexes appeared in tiles among that page's children, which is
|
|
154
|
+
// exactly the sibling claim the bare mark exists to deny (app-zone/.justai/expert/how-an-app-zone-
|
|
155
|
+
// icon-is-lit.md: the platform mark is inset where app marks are raised).
|
|
156
|
+
//
|
|
157
|
+
// APEX-NESS IS READ, NEVER DECLARED. A persona is an apex when its home is a BARE registrable domain
|
|
158
|
+
// — app.zone, pin.games, justai.pro — and a child's home always carries a label in front of it:
|
|
159
|
+
// qr.app.zone, sudoku.pin.games. One dot versus two. The same test the icon builder applies
|
|
160
|
+
// (builder/icon/build.py, apex_handles) and the feed service applies (feed Feed.astro, isApex), on
|
|
161
|
+
// purpose: three places may not disagree about who is an apex. Read from `home` and not from
|
|
162
|
+
// `personaKind`, because `platform` answers a different question — auth is a platform persona and is
|
|
163
|
+
// not an apex.
|
|
164
|
+
//
|
|
165
|
+
// /favicon.svg and /mark.svg are the platform standard, generated from the same /icon.svg by
|
|
166
|
+
// @justai/astro-config/mark, so an apex has this pair by construction and no name is hardcoded here.
|
|
167
|
+
// The registered avatar stays /icon.svg for everyone: the tile IS right in the catalogue, and only a
|
|
168
|
+
// feed asks an apex for its bare mark.
|
|
169
|
+
const apexHome = (url: string | null | undefined): string | null => {
|
|
170
|
+
if (!url) return null;
|
|
171
|
+
const h = String(url).replace(/^https?:\/\//, "").replace(/\/.*$/, "");
|
|
172
|
+
return (h.match(/\./g) || []).length === 1 ? h : null;
|
|
173
|
+
};
|
|
147
174
|
const comment = (c: C, last: boolean): string => {
|
|
148
175
|
const ln = last ? "" : `<span class="ln"></span>`;
|
|
149
176
|
if (c.isPersona) {
|
|
@@ -151,11 +178,15 @@
|
|
|
151
178
|
// face and name; ANOTHER persona wears ITS canonical icon (glyph fallback), its own name, its
|
|
152
179
|
// @handle, and its name links to its own profile. The verified check stays for both.
|
|
153
180
|
const own = c.authorHandle === PERSONA;
|
|
181
|
+
// A replying apex signs bare from ITS OWN home, in the scheme pair, exactly as it does on its page.
|
|
182
|
+
const apex = own ? null : apexHome(c.personaUrl);
|
|
154
183
|
const av = own
|
|
155
184
|
? AV
|
|
156
|
-
:
|
|
157
|
-
? `<img class="mk" src="
|
|
158
|
-
:
|
|
185
|
+
: apex
|
|
186
|
+
? `<img class="mk bare av-light" src="https://${esc(apex)}/favicon.svg" alt=""><img class="mk bare av-dark" src="https://${esc(apex)}/mark.svg" alt="">`
|
|
187
|
+
: c.authorAvatar
|
|
188
|
+
? `<img class="mk" src="${esc(c.authorAvatar)}" alt="">`
|
|
189
|
+
: `<span style="font-size:16px">${esc(c.authorGlyph || "✦")}</span>`;
|
|
159
190
|
const nm = own ? NAME : esc(c.authorName); // own name is authored markup; an API name is escaped
|
|
160
191
|
const purl = own ? "#profile" : c.personaUrl ? `${c.personaUrl}/#profile` : null;
|
|
161
192
|
const at = own ? PERSONA : c.authorHandle;
|