@justai/cuts 0.66.0 → 0.68.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justai/cuts",
3
- "version": "0.66.0",
3
+ "version": "0.68.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": {
@@ -114,8 +114,18 @@ const { id, label, tone = "plain", detail, hidden, i18n, ...rest } = Astro.props
114
114
  .jal-label { flex: 1; min-width: 0; }
115
115
  .jal-detail { color: var(--text-dim); font-size: var(--fs-xs); flex: none; }
116
116
 
117
- .jal-row.is-accent { color: var(--accent); font-weight: 600; }
118
- .jal-row.is-accent .jal-ico { color: var(--accent); }
117
+ /* queries: the accent row is unreadable in light mode · is-accent contrast · accent as text ·
118
+ my persona's accent is too bright to read in a sheet
119
+ THE ACCENT AS INK IS NOT THE ACCENT AS PAINT. A fill only has to be SEEN; a word has to be READ,
120
+ and a persona whose accent is light fails contrast here while looking perfect as a button — tts's
121
+ amber measures 1.67:1 on the light surface against the 4.5 a word needs.
122
+ This is the same problem ConfirmSheet already solved with `--confirm-accent`, one component over,
123
+ for the same stated reason ("the action reads as TEXT"). The hook is additive: a consumer that
124
+ sets nothing gets exactly what it got before, and one that sets `--accent-text` gets a readable
125
+ row. Prefer fixing it here over a persona globalising this class — that is what tts had to do
126
+ while this shipped, and a persona reaching into a cut's internals is a fix that rots. */
127
+ .jal-row.is-accent { color: var(--accent-text, var(--accent)); font-weight: 600; }
128
+ .jal-row.is-accent .jal-ico { color: var(--accent-text, var(--accent)); }
119
129
  .jal-row.is-danger { color: var(--danger); }
120
130
  .jal-row.is-danger .jal-ico { color: var(--danger); }
121
131
  .jal-row.is-danger:active { background: color-mix(in srgb, var(--danger) 12%, transparent); }
@@ -119,7 +119,8 @@ const ordered = orderLocales(locales);
119
119
  .item:active { background: color-mix(in srgb, var(--text) 12%, transparent); }
120
120
  @media (hover: hover) { .item:hover { background: color-mix(in srgb, var(--text) 8%, transparent); } }
121
121
  .item:focus-visible { outline: none; background: color-mix(in srgb, var(--accent) 16%, transparent); }
122
- .item.active { color: var(--accent); font-weight: 600; }
122
+ /* The chosen locale reads as TEXT — see ActionRow for why this takes the ink hook. */
123
+ .item.active { color: var(--accent-text, var(--accent)); font-weight: 600; }
123
124
  .item svg { width: 17px; height: 17px; flex: none; }
124
125
  </style>
125
126
 
package/src/Posts.astro CHANGED
@@ -248,14 +248,14 @@ const vars = [
248
248
  .phandle, .dot, .pt { color: var(--text-dim); font-weight: 400; }
249
249
  /* a persona's name in the feed links to its profile (X-style); humans have no link */
250
250
  .pn { color: inherit; text-decoration: none; }
251
- .pn:hover b { color: var(--accent); }
251
+ .pn:hover b { color: var(--accent-text, var(--accent)); }
252
252
  a.pt { text-decoration: none; }
253
253
  a.pt:hover { text-decoration: underline; }
254
254
  .pbd { font-size: var(--fs-sm); line-height: 1.5; margin-block-start: 4px; }
255
255
  .pact { display: flex; gap: 22px; margin-block-start: 12px; color: var(--text-dim); }
256
256
  .pact svg { width: 17px; height: 17px; }
257
257
  .pact span { cursor: pointer; transition: color 0.2s; }
258
- .pact span:hover { color: var(--accent); }
258
+ .pact span:hover { color: var(--accent-text, var(--accent)); }
259
259
  .ch { display: flex; align-items: center; gap: 4px; font-size: var(--fs-xs); }
260
260
  .ch b { font-weight: 600; }
261
261
  .ch .muted { color: var(--text-dim); font-weight: 400; }
package/src/Toolbar.astro CHANGED
@@ -50,13 +50,33 @@ interface Props {
50
50
  // destination, and justai.pro is above it (sending the parent "home" to a child platform is
51
51
  // the wrong direction). Every other persona keeps it.
52
52
  home?: boolean;
53
+ // What the title strip says when the Kernel or the Posts cut is the one at the toolbar line.
54
+ //
55
+ // OMIT THEM AND NOTHING MOVES: the strip keeps naming the persona and its handle, which is right
56
+ // almost everywhere. On a leaf the kernel IS the persona — the strip reading "QR Code" while you
57
+ // use qr replaces the profile header that scrolled away, and "App" would be strictly less.
58
+ //
59
+ // app.zone is the exception the pair exists for, and the reason is structural rather than a matter
60
+ // of taste: it is the one persona whose kernel is NOT itself. Its kernel is a catalogue of the
61
+ // others, and its profile header — a few pixels above — already says app.zone. So the strip spends
62
+ // its only line repeating what the visitor can see. There it says "Apps" and "Posts" instead.
63
+ //
64
+ // BOTH OR NEITHER, deliberately. Half an override would need this file to reproduce the other
65
+ // half's default, which means copying core's `.pname` / `.handle` selectors into a second place
66
+ // that nothing keeps in step. The strip is one line and its vocabulary should be one kind of
67
+ // thing — names or sections, not one of each — so the API says so out loud.
68
+ kernelTitle?: string;
69
+ postsTitle?: string;
53
70
  }
54
71
  import BackToZone from "./BackToZone.astro";
55
- const { sectionsLabel, profileLabel, kernelLabel, postsLabel, home = true, files = true, filesLabel = "Files" } = Astro.props;
72
+ const { sectionsLabel, profileLabel, kernelLabel, postsLabel, home = true, files = true, filesLabel = "Files", kernelTitle, postsTitle } = Astro.props;
56
73
  import AuthMount from "./AuthMount.astro";
57
74
  ---
58
75
 
59
- <header class="toolbar">
76
+ <!-- The two titles reach the script as data attributes rather than through `define:vars`, which would
77
+ make this script inline and it has an import. Astro drops an attribute whose value is undefined,
78
+ so a persona that passes neither leaves no trace in the markup at all. -->
79
+ <header class="toolbar" data-kernel-title={kernelTitle} data-posts-title={postsTitle}>
60
80
  <div class="tb-row">
61
81
  <div class="tb-left">
62
82
  {home && <BackToZone />}
@@ -170,7 +190,9 @@ import AuthMount from "./AuthMount.astro";
170
190
  }
171
191
  .tb-nav:hover { color: var(--text); }
172
192
  .tb-nav:active { transform: scale(0.9); }
173
- .tb-nav.active { color: var(--accent); }
193
+ /* The active glyph is a graphic, so it wants 3:1 rather than 4.5 — which a light accent still
194
+ misses. Same ink hook as everywhere the accent stops being paint. */
195
+ .tb-nav.active { color: var(--accent-text, var(--accent)); }
174
196
 
175
197
  /* A MARK IS NOT DIMMED, AND THE PROFILE CUT DOES NOT NEED IT TO BE.
176
198
  It shipped dimmed at rest for one version, on the reasoning that a mark cannot take `currentColor`
@@ -214,5 +236,15 @@ import AuthMount from "./AuthMount.astro";
214
236
  // The defaults ARE this cut's contract — the three cut ids, `nav<Cut>`, `#tbTitle`/`#tbTitleText`,
215
237
  // `.toolbar`, `#below` — so a persona using the shell passes nothing at all.
216
238
  import { personaScroll } from "@justai/core";
217
- personaScroll();
239
+ // Both or neither — see the props above. When both are set the strip names the SECTIONS; core's
240
+ // default, which names the persona and its handle, is left entirely alone otherwise. Nothing here
241
+ // reproduces that default, which is the point: `.pname` and `.handle` stay core's business.
242
+ const bar = document.querySelector(".toolbar") as HTMLElement | null;
243
+ const kt = bar?.dataset.kernelTitle;
244
+ const pt = bar?.dataset.postsTitle;
245
+ personaScroll(
246
+ kt && pt
247
+ ? { titleFor: (id: string) => (id === "kernel" ? kt : id === "posts" ? pt : "") }
248
+ : undefined,
249
+ );
218
250
  </script>