@justai/cuts 0.120.0 → 0.121.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.
Files changed (2) hide show
  1. package/package.json +3 -3
  2. package/src/Toolbar.astro +19 -82
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justai/cuts",
3
- "version": "0.120.0",
3
+ "version": "0.121.0",
4
4
  "description": "A persona's named parts \u2014 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.27.0",
45
- "@justai/ui": "^0.18.0",
44
+ "@justai/core": "^0.28.0",
45
+ "@justai/ui": "^0.19.0",
46
46
  "@justai/atrium": "^0.1.9"
47
47
  }
48
48
  }
package/src/Toolbar.astro CHANGED
@@ -82,8 +82,6 @@ interface Props {
82
82
  // half's default, which means copying core's `.pname` / `.handle` selectors into a second place
83
83
  // that nothing keeps in step. The strip is one line and its vocabulary should be one kind of
84
84
  // thing — names or sections, not one of each — so the API says so out loud.
85
- kernelTitle?: string;
86
- postsTitle?: string;
87
85
 
88
86
  // queries: toolbar shows a generic person icon · the profile icon is not my persona ·
89
87
  // how do I put my own mark in the toolbar · avatar
@@ -155,7 +153,7 @@ interface Props {
155
153
  import BackToZone from "./BackToZone.astro";
156
154
  const {
157
155
  sectionsLabel, profileLabel, kernelLabel, postsLabel,
158
- files = true, filesLabel = "Files", kernelTitle, postsTitle, avatar = "/icon.svg", parent,
156
+ files = true, filesLabel = "Files", avatar = "/icon.svg", parent,
159
157
  } = Astro.props;
160
158
  // A child's row answers UP to its parent, not out to the zone, and has no stream of its own — so
161
159
  // both default off the moment `parent` is given, rather than each consumer remembering to say so.
@@ -166,8 +164,7 @@ import AuthMount from "./AuthMount.astro";
166
164
  <!-- The two titles reach the script as data attributes rather than through `define:vars`, which would
167
165
  make this script inline and it has an import. Astro drops an attribute whose value is undefined,
168
166
  so a persona that passes neither leaves no trace in the markup at all. -->
169
- <div class="tb-slot">
170
- <header class="toolbar" data-kernel-title={kernelTitle} data-posts-title={postsTitle}>
167
+ <header class="toolbar">
171
168
  <div class="tb-row">
172
169
  <div class="tb-left">
173
170
  {home && <BackToZone apex={apex} />}
@@ -268,34 +265,14 @@ import AuthMount from "./AuthMount.astro";
268
265
  <AuthMount />
269
266
  </div>
270
267
  </div>
271
- <div class="tb-title" id="tbTitle"><span class="tb-title-text" id="tbTitleText"></span></div>
272
268
  </header>
273
- </div>
274
269
 
275
270
  <style>
276
271
  /* ---- app toolbar — sticky to the top of the active region (kernel + posts); it never
277
272
  enters the Profile (it lives inside .below). Flat / knife-cut: a left group and a
278
273
  right group, no rounded pills. ---- */
279
- /* queries: tb-slot · why is the toolbar wrapped · the bar changes height · the kernel is 26px
280
- * short · a band of the feed at the bottom · the toolbar reserves a box · sticky flow
281
- *
282
- * ── THE SLOT IS WHAT FLOW SEES; THE BAR IS WHAT THE EYE SEES ──────────────────────────────
283
- *
284
- * `position: sticky` NEVER LEAVES FLOW. It reserves its full border box and paints inside it — so
285
- * the bar's LIVE height positioned everything under it (52 with the title strip shut, 78 open)
286
- * while `--shell-top` was deliberately frozen at the open height so that nothing would sample the
287
- * 0.35s animation. The HEIGHT stopped sampling it. THE POSITION NEVER DID. Two numbers that must
288
- * be equal, written a hundred lines apart in two packages, and their difference is a band of the
289
- * next section above the fold: measured on the live persona with the scroll untouched, the kernel
290
- * sat 52px below `#below` instead of 78 and 25.81px of the feed was on screen.
291
- *
292
- * The wrapper separates them. The SLOT is sticky and its box is `--shell-top`; the BAR is static
293
- * inside it and may be any height it likes. Nothing above the kernel changes size any more, so
294
- * there is nothing for an engine to compensate for — which is also why only a device ever showed
295
- * it: Blink scroll-anchors the step away and WebKit has no scroll anchoring. */
296
- .tb-slot { position: sticky; top: 0; z-index: 40; display: flow-root; }
297
274
  .toolbar {
298
- /* position, top and z-index live on .tb-slot above — this element is static inside it now. */
275
+ position: sticky; top: 0; z-index: 40;
299
276
  display: flex; flex-direction: column;
300
277
  /* full-bleed: the bar (frosted bg + hairline) touches the contained-view edges; the icons stay
301
278
  aligned with the body via matching inline padding. --edge is the persona's page inline padding
@@ -348,54 +325,23 @@ import AuthMount from "./AuthMount.astro";
348
325
  @media (min-width: 640px) { .toolbar { margin-inline: -28px; padding-inline: 28px; } }
349
326
  /* icons row + the scroll-reactive title strip below it */
350
327
  .tb-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
351
- /* queries: --tb-strip · the title strip's height · the toolbar changes height · 26px ·
352
- * the kernel is 26px short · the game frame does not reach the fold
353
- *
354
- * ── THE ONE NUMBER THAT MAKES THIS ROW'S HEIGHT A MOVING TARGET, DECLARED SO IT CAN BE READ ──
355
- *
356
- * The strip opens and closes over 0.35s, so `.toolbar`'s height is anywhere in a 26px range at any
357
- * given moment — and anything that measures the row and feeds a LAYOUT with it is sampling an
358
- * animation. `--shell-top` did exactly that and the kernel's height came out 26px short whenever
359
- * the page happened to be measured with the strip open, which is to say whenever somebody opened
360
- * the persona at #kernel. It reads as a strip of the next section showing above the fold.
361
- *
362
- * So the number is a custom property rather than a literal: this rule uses it, and @justai/core's
363
- * `personaScroll` reads it to compute the row's EXPANDED height without waiting for or racing the
364
- * transition — `toolbar - strip` is the row, and the row plus this is what the bar will be. One
365
- * declaration, two readers, and nothing samples a moving value. */
366
- .toolbar { --tb-strip: 26px; }
367
- /* queries: the bar grows after load · why does the strip animate on arrival · data-motion ·
368
- * first paint animation · can this transition wait for the first interaction
369
- *
370
- * ── THE TRANSITION IS ALSO A DAMPER, WHICH IS WHY IT CANNOT SIMPLY WAIT ─────────────────────
371
- *
372
- * The founder asked the obvious and right question: *"şu geçiş süresi güzel — ama neden bu özellik
373
- * kullanıcının ilk interaction'ından sonra aktif edilmiyor?"* A persona lands on its kernel, so the
374
- * strip's correct state on the first frame is open; animating into it grows the bar 26px just after
375
- * the page appears, which is a glitch nobody asked for.
328
+ /* queries: where is the title strip · tb-title · the persona's name under the icons · tbTitle
376
329
  *
377
- * IT WAS TRIED, AND IT BREAKS SOMETHING ELSE. Gated behind a `data-motion` flag set on the first
378
- * pointer/key/wheel, the strip snaps open during the landing — and that 26px arrives in a SINGLE
379
- * frame, inside `#below`, while the scroll spy is deciding which cut is active. That is the
380
- * bistable oscillator `personaScroll` documents at length: the spy measures a page its own output
381
- * moved. Measured: with the gate in place, `#navProfile` no longer navigates — the page re-asserts
382
- * the kernel and stays. The 0.35s is not only easing; it is what keeps that step out of one frame.
330
+ * ── THERE IS NO SECONDARY STRIP, AND THAT IS A DECISION ──────────────────────────────────
383
331
  *
384
- * SO THE HEIGHT IS NEVER READ INSTEAD. `--shell-top` is computed as `row + --tb-strip` — the row
385
- * being the bar minus whatever the strip currently is, which is the same number at every frame of
386
- * the transition. Nothing samples the animation, so nothing depends on when it was sampled.
332
+ * A second row under the icons carried the current cut's name and opened over 0.35s. It cost more
333
+ * than it said. `position: sticky` never leaves flow, so the row's LIVE height positioned every
334
+ * section beneath it — 52 shut, 78 open — while anything that measured the shell had to freeze one
335
+ * of those two numbers and was therefore wrong in the other state. That gap is a band of the next
336
+ * section above the fold; on a game persona, whose kernel is an EXACT height, it is on the glass.
337
+ * It also coupled the scroll spy to the layout: the spy decided which cut was current, that opened
338
+ * the strip, the strip moved the page, and the spy read the page it had just moved.
387
339
  *
388
- * The real fix for the founder's question is a toolbar whose height does not change at all: reserve
389
- * the strip's space always and fade only its content. That removes the feedback at the source and
390
- * makes the gate free — and it is a fleet-wide design decision about how the bar looks at the
391
- * profile, so it is his to take rather than one to slip in. */
392
- .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); }
393
- /* The fallback is not decoration: the token is declared on `.toolbar` and consumed here, which is
394
- a different selector — so the framework's own token spec reads it as ungrounded and is right to.
395
- A rule that silently collapses to `height: 0` would close the strip and say nothing. */
396
- .tb-title.show { height: 26px; height: var(--tb-strip, 26px); opacity: 1; }
397
- .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); }
398
- .tb-title-text.fade { opacity: 0; }
340
+ * The founder's ruling, 2026-08-06: *"secondary şeridi tamamen kaldır. net karar."* So the bar is
341
+ * one row and one height, always. Nothing above the kernel changes size, and every derivation that
342
+ * existed to survive that change is gone with it — `--tb-strip`, the slot that reserved a constant
343
+ * box, the painted band that filled the reserve, and the probe that measured the strip before it
344
+ * opened. The name is on the profile, which is where a name belongs. */
399
345
  /* nav lives on the left, beside the back affordance — the middle is intentionally empty */
400
346
  .tb-left { display: flex; align-items: center; gap: 2px; min-width: 0; }
401
347
  .tb-nav-group { display: flex; align-items: center; gap: 2px; }
@@ -562,15 +508,6 @@ import AuthMount from "./AuthMount.astro";
562
508
  const ownMark = document.querySelector("#navProfile img");
563
509
  if (ownMark) adoptMark({ id: "navProfile" });
564
510
 
565
- // Both or neither — see the props above. When both are set the strip names the SECTIONS; core's
566
- // default, which names the persona and its handle, is left entirely alone otherwise. Nothing here
567
- // reproduces that default, which is the point: `.pname` and `.handle` stay core's business.
568
- const bar = document.querySelector(".toolbar") as HTMLElement | null;
569
- const kt = bar?.dataset.kernelTitle;
570
- const pt = bar?.dataset.postsTitle;
571
- personaScroll(
572
- kt && pt
573
- ? { titleFor: (id: string) => (id === "kernel" ? kt : id === "posts" ? pt : "") }
574
- : undefined,
575
- );
511
+ // No titleFor: the bar has one row and no strip to name anything in. See the note in the styles.
512
+ personaScroll();
576
513
  </script>