@justai/cuts 0.151.0 → 0.152.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/ChildPersona.astro +1 -1
- package/src/Posts.astro +17 -0
- package/src/Toolbar.astro +20 -132
- package/src/behaviour/toolbar.ts +8 -19
- package/src/ground.css +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justai/cuts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.152.0",
|
|
4
4
|
"description": "A persona's named parts — the page shell that holds them, and the cuts themselves.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@justai/core": "^0.
|
|
45
|
-
"@justai/ui": "^0.
|
|
44
|
+
"@justai/core": "^0.41.0",
|
|
45
|
+
"@justai/ui": "^0.28.0",
|
|
46
46
|
"@justai/atrium": "^0.1.9"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
package/src/ChildPersona.astro
CHANGED
|
@@ -260,7 +260,7 @@ const chrome = face === "page";
|
|
|
260
260
|
exactly that constant (base.css, Posts.astro, eight persona repos) and surfaced only when the
|
|
261
261
|
children's console started warning about it: a scoped rule inside a cut is where a stale number
|
|
262
262
|
hides longest, because nobody greps a component for a layout constant. */
|
|
263
|
-
.pp #profile, .pp #kernel { scroll-margin-top: var(--shell-top,
|
|
263
|
+
.pp #profile, .pp #kernel { scroll-margin-top: var(--shell-top, 52px); }
|
|
264
264
|
|
|
265
265
|
/* THE `sheet` FACE: no column, no ground, no chrome. The sheet around it IS the frame, and a
|
|
266
266
|
second frame inside one is a box in a box. Keyed on the face name rather than on a boolean, so a
|
package/src/Posts.astro
CHANGED
|
@@ -167,6 +167,23 @@ const vars = [
|
|
|
167
167
|
/* The landing offset is `--shell-top` and only that — see base.css. A hardcoded twin here is a
|
|
168
168
|
second opinion the browser can pick when it scrolls to `#posts` by itself. */
|
|
169
169
|
.posts { border-block-start: 1px solid var(--border); scroll-margin-top: var(--shell-top); }
|
|
170
|
+
/* queries: the posts icon does not reach the posts · first tap on posts stops short · #posts lands
|
|
171
|
+
* in the middle of the kernel · the second tap works · the feed is lazy
|
|
172
|
+
*
|
|
173
|
+
* ── A CUT YOU CAN BE SENT TO MUST BE TALL ENOUGH TO BE ARRIVED AT ───────────────────────────────
|
|
174
|
+
*
|
|
175
|
+
* The feed loads when this section comes into view, so until then the section is only its footer.
|
|
176
|
+
* Landing on it means scrolling until its top sits under the bar — and the document did not reach
|
|
177
|
+
* that far: the browser stops at the bottom of the page and says nothing (cause 1 of the landing
|
|
178
|
+
* doc, met again in the toolbar's own link). Measured on location at 390x844: the page ends at
|
|
179
|
+
* 5119, the most it can scroll is 5119 - 844 = 4275, the posts landing is 5007 — so the first tap
|
|
180
|
+
* on the bubble and every `#posts` link stopped 706px short, with the icon and the address bar
|
|
181
|
+
* already saying "posts". The second tap worked because by then the feed had loaded.
|
|
182
|
+
*
|
|
183
|
+
* So the section is at least one active view tall, the same floor the kernel has in base.css: the
|
|
184
|
+
* landing always has room, and the feed arriving later grows the page BELOW the reader rather than
|
|
185
|
+
* moving anything. The literal first, for engines without dvh. */
|
|
186
|
+
.posts { min-height: calc(100vh - 52px); min-height: calc(100dvh - var(--shell-top)); box-sizing: border-box; }
|
|
170
187
|
/* A post is hoverable because it is a link to its own page, and the hover used to say so with a grey wash
|
|
171
188
|
— `--text` at 3.5% — which reads as dimming rather than as lifting. It now uses the card material, so
|
|
172
189
|
hovering a post looks like the same gesture as hovering a catalogue card.
|
package/src/Toolbar.astro
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
// ░░ TOOLBAR cut — the persona's sticky chrome: home · section-nav · language · sign-in, plus the
|
|
3
|
-
// scroll-
|
|
3
|
+
// scroll-spy that binds the whole page together. One row, one height. ░░
|
|
4
4
|
//
|
|
5
5
|
// This markup + its ~40 lines of CSS + its ~80-line scroll-spy were near-identical in every persona's
|
|
6
6
|
// main component (only the kernel glyph and a couple of optional controls differed). It lives here now,
|
|
@@ -33,18 +33,15 @@
|
|
|
33
33
|
// something plausible is how thirteen of fifteen personas wore nobody's face for months with
|
|
34
34
|
// nothing red anywhere. Pass the slot when an inline SVG is wanted instead of an <img>.
|
|
35
35
|
// Note what a mark cannot do: an <img> ignores `currentColor`, so `.active`'s accent never reaches
|
|
36
|
-
// it.
|
|
37
|
-
// it, and a mark is an identity rather than a UI state. Slot presence adds `.tb-mark`, which the
|
|
38
|
-
// sizing rule uses.
|
|
36
|
+
// it. Slot presence adds `.tb-mark`, which the sizing rule uses.
|
|
39
37
|
// • langPicker — needs the persona's own locale data (the list must NOT live in the shared package —
|
|
40
38
|
// it bit us twice; see @justai/ui/locale) → a slot the persona fills with its <LangPicker/>.
|
|
41
39
|
// • navExtra — optional extra nav item after Posts (e.g. the timers' fullscreen button) → slot.
|
|
42
40
|
// • toolbarRight — optional right-side control before the picker (e.g. time's 24H/AM-PM toggle) → slot.
|
|
43
41
|
//
|
|
44
42
|
// CONTRACT with the page (the same three cut ids the whole shell agrees on): the scroll-spy needs a
|
|
45
|
-
// `#below` wrapper around toolbar+kernel+posts
|
|
46
|
-
// `#posts
|
|
47
|
-
// internals. It is also the page's REVEAL: it sets `body.ready` (the other half of @justai/core's
|
|
43
|
+
// `#below` wrapper around toolbar+kernel+posts and a `<section id="kernel">` between `#profile` and
|
|
44
|
+
// `#posts`. It touches NO kernel internals. It is also the page's REVEAL: it sets `body.ready` (the other half of @justai/core's
|
|
48
45
|
// REVEAL_CSS) — so every persona that renders a Toolbar is revealed; move it and the page stays blank.
|
|
49
46
|
interface Props {
|
|
50
47
|
sectionsLabel: string; // aria-label for the section-nav group
|
|
@@ -72,22 +69,6 @@ interface Props {
|
|
|
72
69
|
// Posts is required only where there IS a stream (doctrine 02 — an empty cut shipped to look
|
|
73
70
|
// complete is the buffet). A child persona has none, so `parent` turns this off by default.
|
|
74
71
|
posts?: boolean;
|
|
75
|
-
// What the title strip says when the Kernel or the Posts cut is the one at the toolbar line.
|
|
76
|
-
//
|
|
77
|
-
// OMIT THEM AND NOTHING MOVES: the strip keeps naming the persona and its handle, which is right
|
|
78
|
-
// almost everywhere. On a leaf the kernel IS the persona — the strip reading "QR Code" while you
|
|
79
|
-
// use qr replaces the profile header that scrolled away, and "App" would be strictly less.
|
|
80
|
-
//
|
|
81
|
-
// app.zone is the exception the pair exists for, and the reason is structural rather than a matter
|
|
82
|
-
// of taste: it is the one persona whose kernel is NOT itself. Its kernel is a catalogue of the
|
|
83
|
-
// others, and its profile header — a few pixels above — already says app.zone. So the strip spends
|
|
84
|
-
// its only line repeating what the visitor can see. There it says "Apps" and "Posts" instead.
|
|
85
|
-
//
|
|
86
|
-
// BOTH OR NEITHER, deliberately. Half an override would need this file to reproduce the other
|
|
87
|
-
// half's default, which means copying core's `.pname` / `.handle` selectors into a second place
|
|
88
|
-
// that nothing keeps in step. The strip is one line and its vocabulary should be one kind of
|
|
89
|
-
// thing — names or sections, not one of each — so the API says so out loud.
|
|
90
|
-
kernelTitle?: string;
|
|
91
72
|
/**
|
|
92
73
|
* Which cut a visit with no hash opens on. Defaults to the kernel, which is right for every
|
|
93
74
|
* persona whose kernel is the thing it does.
|
|
@@ -99,7 +80,6 @@ interface Props {
|
|
|
99
80
|
* markup, and the behaviour reads the markup rather than being handed a closure.
|
|
100
81
|
*/
|
|
101
82
|
landOn?: string;
|
|
102
|
-
postsTitle?: string;
|
|
103
83
|
|
|
104
84
|
// queries: toolbar shows a generic person icon · the profile icon is not my persona ·
|
|
105
85
|
// how do I put my own mark in the toolbar · avatar
|
|
@@ -171,7 +151,7 @@ interface Props {
|
|
|
171
151
|
import BackToZone from "./BackToZone.astro";
|
|
172
152
|
const {
|
|
173
153
|
sectionsLabel, profileLabel, kernelLabel, postsLabel,
|
|
174
|
-
files = true, filesLabel = "Files",
|
|
154
|
+
files = true, filesLabel = "Files", landOn, avatar = "/icon.svg", parent,
|
|
175
155
|
} = Astro.props;
|
|
176
156
|
// A child's row answers UP to its parent, not out to the zone, and has no stream of its own — so
|
|
177
157
|
// both default off the moment `parent` is given, rather than each consumer remembering to say so.
|
|
@@ -179,11 +159,11 @@ const { home = !parent, posts = !parent, apex = "app.zone" } = Astro.props;
|
|
|
179
159
|
import AuthMount from "./AuthMount.astro";
|
|
180
160
|
---
|
|
181
161
|
|
|
182
|
-
<!--
|
|
162
|
+
<!-- `landOn` reaches the script as a data attribute rather than through `define:vars`, which would
|
|
183
163
|
make this script inline and it has an import. Astro drops an attribute whose value is undefined,
|
|
184
|
-
so a persona that passes
|
|
164
|
+
so a persona that passes nothing leaves no trace in the markup at all. -->
|
|
185
165
|
<div class="tb-slot">
|
|
186
|
-
<header class="toolbar" data-
|
|
166
|
+
<header class="toolbar" data-land-on={landOn}>
|
|
187
167
|
<div class="tb-row">
|
|
188
168
|
<div class="tb-left">
|
|
189
169
|
{home && <BackToZone apex={apex} />}
|
|
@@ -297,7 +277,6 @@ import AuthMount from "./AuthMount.astro";
|
|
|
297
277
|
<AuthMount />
|
|
298
278
|
</div>
|
|
299
279
|
</div>
|
|
300
|
-
<div class="tb-title" id="tbTitle"><span class="tb-title-text" id="tbTitleText"></span></div>
|
|
301
280
|
</header>
|
|
302
281
|
</div>
|
|
303
282
|
|
|
@@ -305,64 +284,22 @@ import AuthMount from "./AuthMount.astro";
|
|
|
305
284
|
/* ---- app toolbar — sticky to the top of the active region (kernel + posts); it never
|
|
306
285
|
enters the Profile (it lives inside .below). Flat / knife-cut: a left group and a
|
|
307
286
|
right group, no rounded pills. ---- */
|
|
308
|
-
/* queries: tb-slot · why is the toolbar wrapped · the
|
|
309
|
-
*
|
|
287
|
+
/* queries: tb-slot · why is the toolbar wrapped · the gap under the toolbar · the band under the
|
|
288
|
+
* bar · the toolbar reserves a box · secondary line · title strip
|
|
310
289
|
*
|
|
311
|
-
* ── THE SLOT IS
|
|
290
|
+
* ── THE SLOT IS STICKY; THE BAR IS STATIC INSIDE IT, AND THEY ARE THE SAME HEIGHT ──────────────
|
|
312
291
|
*
|
|
313
|
-
*
|
|
314
|
-
* the
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
292
|
+
* There used to be a second line under the row — a title strip that opened over 0.35s when the
|
|
293
|
+
* kernel or the posts reached the bar. `position: sticky` never leaves flow, so the strip moved the
|
|
294
|
+
* whole page by 26px each time it opened or closed; the slot was given a fixed reserved box so it
|
|
295
|
+
* would not, and that box was 26px of empty bar under the row whenever the strip was shut — the
|
|
296
|
+
* band at the profile on every persona. The founder struck the strip on 2026-10-12: *"o boşluk
|
|
297
|
+
* oluşuyor ve bundan nefret ediyorum."* The active icon already says which cut you are on, and
|
|
298
|
+
* the name the strip repeated sits one line above in the persona's own mark.
|
|
320
299
|
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
* there is nothing for an engine to compensate for — which is also why only a device ever showed
|
|
324
|
-
* it: Blink scroll-anchors the step away and WebKit has no scroll anchoring. */
|
|
300
|
+
* With one row the bar's height no longer changes, so the slot needs no box of its own: it is
|
|
301
|
+
* exactly the bar. It stays because it is the sticky element the cut's contract names. */
|
|
325
302
|
.tb-slot { position: sticky; top: 0; z-index: 40; display: flow-root; }
|
|
326
|
-
/* queries: the title strip moves the fold · the page drifts after it lands · a band of posts under
|
|
327
|
-
* the game · tb-slot min-height · the slot follows the bar · the strip pushes the page down
|
|
328
|
-
*
|
|
329
|
-
* ── THE BOX IS THE SLOT'S OWN, SO IT TRAVELS WITH THE SLOT ─────────────────────────────────────
|
|
330
|
-
*
|
|
331
|
-
* `position: sticky` never leaves flow: it reserves its full border box, so whatever the bar's LIVE
|
|
332
|
-
* height is at any instant, that is where everything under it sits. The strip opens and closes over
|
|
333
|
-
* 0.35s inside that box — so without a reserved height the shell breathes 26px and the whole
|
|
334
|
-
* document below it breathes with it. That is the drift the founder lost days to.
|
|
335
|
-
*
|
|
336
|
-
* IT LIVED IN `@justai/ui`'s base.css UNTIL 2026-08-06, and measured on pin.games that was the same
|
|
337
|
-
* as not existing: a persona that never imports base.css got the slot's structure from here and its
|
|
338
|
-
* BOX from a file it does not load, so the slot collapsed to the bar and posts moved 26px between
|
|
339
|
-
* the kernel and the profile. The first law again — a component brings its own ground — and the
|
|
340
|
-
* slot is this component's element, so its box is this component's business. The rule that keeps
|
|
341
|
-
* the whole strip safe cannot be the one rule that lives somewhere the strip does not.
|
|
342
|
-
*
|
|
343
|
-
* AND THE RESERVED BAND WEARS THE BAR'S OWN MATERIAL, not the room's. A slot taller than its bar is
|
|
344
|
-
* 26px of SOMETHING under the shelf whenever the strip is shut — the state at the profile, on
|
|
345
|
-
* screen, at rest. Painted in the persona's ground it was a hard black band between a light profile
|
|
346
|
-
* and a light kernel: the founder photographed it within a minute. It is the BAR'S box, so it takes
|
|
347
|
-
* the bar's fill, bleeding by the same `--edge` expression so the two cannot leave slivers. */
|
|
348
|
-
.tb-slot { min-height: var(--shell-top, 78px); }
|
|
349
|
-
.tb-slot::before {
|
|
350
|
-
content: "";
|
|
351
|
-
position: absolute;
|
|
352
|
-
z-index: -1;
|
|
353
|
-
inset-block: 0;
|
|
354
|
-
inset-inline:
|
|
355
|
-
calc(-1 * max(var(--edge, 16px), env(safe-area-inset-left)))
|
|
356
|
-
calc(-1 * max(var(--edge, 16px), env(safe-area-inset-right)));
|
|
357
|
-
background: var(--toolbar-bg, #1e202a);
|
|
358
|
-
}
|
|
359
|
-
/* The shelf's fill has two branches and so must its box: `--toolbar-bg` is one token but its
|
|
360
|
-
FALLBACK differs by scheme, and a band carrying only the dark default is a black strip on a light
|
|
361
|
-
page — which is exactly what the founder photographed a minute after the first attempt. */
|
|
362
|
-
@media (prefers-color-scheme: light) {
|
|
363
|
-
/* Guarded like every light fork in the fleet: data-theme="dark" wins over the media query. */
|
|
364
|
-
:global(html:not([data-theme="dark"])) .tb-slot::before { background: var(--toolbar-bg, #fbfcfe); }
|
|
365
|
-
}
|
|
366
303
|
.toolbar {
|
|
367
304
|
/* position, top and z-index live on .tb-slot above — this element is static inside it now. */
|
|
368
305
|
display: flex; flex-direction: column;
|
|
@@ -415,56 +352,7 @@ import AuthMount from "./AuthMount.astro";
|
|
|
415
352
|
has nothing to paint now that the shelf is opaque and always shadowed. Kept because the class is
|
|
416
353
|
part of this cut's contract and a consumer may hang its own behaviour on it. */
|
|
417
354
|
@media (min-width: 640px) { .toolbar { margin-inline: -28px; padding-inline: 28px; } }
|
|
418
|
-
/* icons row + the scroll-reactive title strip below it */
|
|
419
355
|
.tb-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
420
|
-
/* queries: --tb-strip · the title strip's height · the toolbar changes height · 26px ·
|
|
421
|
-
* the kernel is 26px short · the game frame does not reach the fold
|
|
422
|
-
*
|
|
423
|
-
* ── THE ONE NUMBER THAT MAKES THIS ROW'S HEIGHT A MOVING TARGET, DECLARED SO IT CAN BE READ ──
|
|
424
|
-
*
|
|
425
|
-
* The strip opens and closes over 0.35s, so `.toolbar`'s height is anywhere in a 26px range at any
|
|
426
|
-
* given moment — and anything that measures the row and feeds a LAYOUT with it is sampling an
|
|
427
|
-
* animation. `--shell-top` did exactly that and the kernel's height came out 26px short whenever
|
|
428
|
-
* the page happened to be measured with the strip open, which is to say whenever somebody opened
|
|
429
|
-
* the persona at #kernel. It reads as a strip of the next section showing above the fold.
|
|
430
|
-
*
|
|
431
|
-
* So the number is a custom property rather than a literal: this rule uses it, and @justai/core's
|
|
432
|
-
* `personaScroll` reads it to compute the row's EXPANDED height without waiting for or racing the
|
|
433
|
-
* transition — `toolbar - strip` is the row, and the row plus this is what the bar will be. One
|
|
434
|
-
* declaration, two readers, and nothing samples a moving value. */
|
|
435
|
-
.toolbar { --tb-strip: 26px; }
|
|
436
|
-
/* queries: the bar grows after load · why does the strip animate on arrival · data-motion ·
|
|
437
|
-
* first paint animation · can this transition wait for the first interaction
|
|
438
|
-
*
|
|
439
|
-
* ── THE TRANSITION IS ALSO A DAMPER, WHICH IS WHY IT CANNOT SIMPLY WAIT ─────────────────────
|
|
440
|
-
*
|
|
441
|
-
* The founder asked the obvious and right question: *"şu geçiş süresi güzel — ama neden bu özellik
|
|
442
|
-
* kullanıcının ilk interaction'ından sonra aktif edilmiyor?"* A persona lands on its kernel, so the
|
|
443
|
-
* strip's correct state on the first frame is open; animating into it grows the bar 26px just after
|
|
444
|
-
* the page appears, which is a glitch nobody asked for.
|
|
445
|
-
*
|
|
446
|
-
* IT WAS TRIED, AND IT BREAKS SOMETHING ELSE. Gated behind a `data-motion` flag set on the first
|
|
447
|
-
* pointer/key/wheel, the strip snaps open during the landing — and that 26px arrives in a SINGLE
|
|
448
|
-
* frame, inside `#below`, while the scroll spy is deciding which cut is active. That is the
|
|
449
|
-
* bistable oscillator `personaScroll` documents at length: the spy measures a page its own output
|
|
450
|
-
* moved. Measured: with the gate in place, `#navProfile` no longer navigates — the page re-asserts
|
|
451
|
-
* the kernel and stays. The 0.35s is not only easing; it is what keeps that step out of one frame.
|
|
452
|
-
*
|
|
453
|
-
* SO THE HEIGHT IS NEVER READ INSTEAD. `--shell-top` is computed as `row + --tb-strip` — the row
|
|
454
|
-
* being the bar minus whatever the strip currently is, which is the same number at every frame of
|
|
455
|
-
* the transition. Nothing samples the animation, so nothing depends on when it was sampled.
|
|
456
|
-
*
|
|
457
|
-
* The real fix for the founder's question is a toolbar whose height does not change at all: reserve
|
|
458
|
-
* the strip's space always and fade only its content. That removes the feedback at the source and
|
|
459
|
-
* makes the gate free — and it is a fleet-wide design decision about how the bar looks at the
|
|
460
|
-
* profile, so it is his to take rather than one to slip in. */
|
|
461
|
-
.tb-title { display: flex; align-items: center; height: 0; overflow: hidden; opacity: 0; transition: height 0.35s var(--ease-out), opacity 0.25s var(--ease-out); }
|
|
462
|
-
/* The fallback is not decoration: the token is declared on `.toolbar` and consumed here, which is
|
|
463
|
-
a different selector — so the framework's own token spec reads it as ungrounded and is right to.
|
|
464
|
-
A rule that silently collapses to `height: 0` would close the strip and say nothing. */
|
|
465
|
-
.tb-title.show { height: 26px; height: var(--tb-strip, 26px); opacity: 1; }
|
|
466
|
-
.tb-title-text { font-size: var(--fs-sm); font-weight: 600; letter-spacing: -0.01em; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: opacity 0.16s var(--ease-out); }
|
|
467
|
-
.tb-title-text.fade { opacity: 0; }
|
|
468
356
|
/* nav lives on the left, beside the back affordance — the middle is intentionally empty */
|
|
469
357
|
.tb-left { display: flex; align-items: center; gap: 2px; min-width: 0; }
|
|
470
358
|
.tb-nav-group { display: flex; align-items: center; gap: 2px; }
|
package/src/behaviour/toolbar.ts
CHANGED
|
@@ -8,18 +8,18 @@
|
|
|
8
8
|
// Out here a compiler can open it and a test can call it. What stays in the component is the markup
|
|
9
9
|
// and the CSS, which is what a component is.
|
|
10
10
|
// queries: where does the toolbar's scroll behaviour live · land on the kernel · scroll spy ·
|
|
11
|
-
//
|
|
11
|
+
// why is the scroll code not in this file any more
|
|
12
12
|
//
|
|
13
13
|
// The BEHAVIOUR moved to @justai/core (`personaScroll`); what stays here is the markup and the CSS.
|
|
14
14
|
//
|
|
15
15
|
// It moved because this cut can only serve pages that adopt its markup, and three surfaces cannot:
|
|
16
16
|
// `/me` and `/files` carry extra navigation of their own and the feed is a different build. All
|
|
17
17
|
// three hand-wrote the same eighty lines, and by the third copy they had drifted — `/files` opened
|
|
18
|
-
// on the profile
|
|
19
|
-
//
|
|
18
|
+
// on the profile, and its hash writer clobbered the query string where this one preserved it. One
|
|
19
|
+
// implementation, four consumers.
|
|
20
20
|
//
|
|
21
|
-
// The defaults ARE this cut's contract — the three cut ids, `nav<Cut>`, `#
|
|
22
|
-
//
|
|
21
|
+
// The defaults ARE this cut's contract — the three cut ids, `nav<Cut>`, `.toolbar`, `#below` — so a
|
|
22
|
+
// persona using the shell passes nothing at all.
|
|
23
23
|
import { personaScroll, adoptMark } from "@justai/core";
|
|
24
24
|
|
|
25
25
|
// queries: the parent icon in a child toolbar has a background · navParent tile · the child's row
|
|
@@ -52,9 +52,6 @@ if (document.getElementById("navParent")) adoptMark({ id: "navParent" });
|
|
|
52
52
|
const ownMark = document.querySelector("#navProfile img");
|
|
53
53
|
if (ownMark) adoptMark({ id: "navProfile" });
|
|
54
54
|
|
|
55
|
-
// Both or neither — see the props above. When both are set the strip names the SECTIONS; core's
|
|
56
|
-
// default, which names the persona and its handle, is left entirely alone otherwise. Nothing here
|
|
57
|
-
// reproduces that default, which is the point: `.pname` and `.handle` stay core's business.
|
|
58
55
|
// ── the stage: the row stays LIVE, and using it pauses the game ───────────────────────────
|
|
59
56
|
// queries: toolbar during a game · tapping posts while playing · auto pause · data-stage-silent
|
|
60
57
|
//
|
|
@@ -80,15 +77,7 @@ document.querySelector(".toolbar")?.addEventListener(
|
|
|
80
77
|
);
|
|
81
78
|
|
|
82
79
|
const bar = document.querySelector(".toolbar") as HTMLElement | null;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// `landOn` travels as a data attribute for the same reason the two titles do: this file runs in a
|
|
86
|
-
// page it did not render, so the markup is the interface. Undefined when the attribute is absent,
|
|
87
|
-
// which is the option's default — the kernel.
|
|
80
|
+
// `landOn` travels as a data attribute: this file runs in a page it did not render, so the markup is
|
|
81
|
+
// the interface. Undefined when the attribute is absent, which is the option's default — the kernel.
|
|
88
82
|
const landOn = bar?.dataset.landOn;
|
|
89
|
-
personaScroll({
|
|
90
|
-
...(kt && pt
|
|
91
|
-
? { titleFor: (id: string) => (id === "kernel" ? kt : id === "posts" ? pt : "") }
|
|
92
|
-
: {}),
|
|
93
|
-
...(landOn ? { landOn } : {}),
|
|
94
|
-
});
|
|
83
|
+
personaScroll(landOn ? { landOn } : {});
|
package/src/ground.css
CHANGED
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
/* What the shell takes above the kernel — see @justai/ui base.css, which measures it. Ground only:
|
|
150
150
|
`:where()` is specificity zero, so a consumer that ships the shell always wins, and a surface that
|
|
151
151
|
ships no shell still lands its cuts clear of a sticky bar instead of under one. */
|
|
152
|
-
:where(:root) { --shell-top:
|
|
152
|
+
:where(:root) { --shell-top: 52px; }
|
|
153
153
|
|
|
154
154
|
:where(html) {
|
|
155
155
|
background: var(--bg);
|