@justai/cuts 0.154.0 → 0.156.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.154.0",
3
+ "version": "0.156.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": {
package/src/Base.astro CHANGED
@@ -82,6 +82,12 @@ interface Props {
82
82
  * privacy/terms child personas use this: the surface that proves it collects nothing by running
83
83
  * nothing. */
84
84
  gaId?: string | null;
85
+ /** Sign-in, ON by default. Pass `false` for a persona with no accounts: the SSO token capture is
86
+ * then not rendered in the head, so nothing reads `#auth_token` or writes `justai_token`. It is
87
+ * the head half of the opt-out — pass the same `auth={false}` to Toolbar, which then renders no
88
+ * AuthMount and loads no sdk.js. Everything else in the head (language, theme, the service
89
+ * worker, analytics as `gaId` decides) is untouched. */
90
+ auth?: boolean;
85
91
  /**
86
92
  * queries: kind game · data-kind · my game persona has margins · the game does not fill the screen ·
87
93
  * which storefront lists this persona · persona kind in the layout
@@ -135,6 +141,7 @@ const {
135
141
  themeDark,
136
142
  themeLight,
137
143
  gaId = "G-13L3BP6XCW",
144
+ auth = true,
138
145
  kind = "app",
139
146
  page,
140
147
  } = Astro.props;
@@ -210,8 +217,10 @@ const ogImage = page?.image
210
217
  #auth_token before the deferred sdk.js can read it; and the language picker copies the
211
218
  current hash onto the next locale's URL (LangPicker), which would PROPAGATE the raw token
212
219
  into a new page and into history. Capturing first defeats both. Move this and sign-in breaks
213
- silently — no error, the visitor simply lands back signed out. */}
214
- <script is:inline set:html={AUTH_CAPTURE_JS} />
220
+ silently — no error, the visitor simply lands back signed out.
221
+ A persona with no accounts (`auth={false}`) has no token to capture, so the script is not
222
+ rendered at all. */}
223
+ {auth && <script is:inline set:html={AUTH_CAPTURE_JS} />}
215
224
  <script is:inline set:html={JS_CLASS_JS} />
216
225
  {/* queries: design grid · x-ray · ?xray · safe area · debug overlay · see the layout ·
217
226
  is my content inside the safe area · layout debugging
@@ -494,7 +494,13 @@ const isNew = (added: string): boolean => { const t0 = Date.parse(added || "");
494
494
  .opt.active .tick { visibility: visible; }
495
495
  .opt.active .lb { font-weight: 600; }
496
496
 
497
- .grid { display: grid; grid-template-columns: 1fr; gap: 14px; }
497
+ /* A SHELF, NOT A STRETCHED LIST (2026-10-14). The column became 1280 and a one-track grid turned every
498
+ card into a 1220px strip with its line running the width of a desk. The founder's rule for the wide
499
+ column: it is a room, and the kernel arranges itself in it without losing its mobile soul — so the
500
+ card stays the PHONE's card (a track never narrower than 340, about a phone's), and the grid simply
501
+ fits as many of them side by side as the room holds: one on a phone, two on a tablet, three in the
502
+ 1280 column. Intrinsic, so there is no width branch, and on a phone nothing moves. */
503
+ .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr)); gap: 14px; }
498
504
  /* no entrance animation — when you walk into the room, everyone is already in their place.
499
505
  the cards are simply there on load; the only motion is a whisper on hover. */
500
506
  .empty { text-align: center; color: var(--text-dim); padding: 40px 0; }
package/src/Toolbar.astro CHANGED
@@ -54,9 +54,12 @@ interface Props {
54
54
  // translated it yet gets a working, named control rather than an unlabelled icon.
55
55
  files?: boolean;
56
56
  filesLabel?: string;
57
- // The home affordance points at app.zone, so the two apexes suppress it: app.zone IS that
58
- // destination, and justai.pro is above it (sending the parent "home" to a child platform is
59
- // the wrong direction). Every other persona keeps it.
57
+ // The home affordance points at the persona's apex (`apex` below), so EVERY apex suppresses it:
58
+ // app.zone, pin.games and cityinmotion.nl ARE that destination — told their own host, the row
59
+ // draws their mark as a link to the page it sits on, beside the profile icon that is the same
60
+ // face (cityinmotion.nl shipped exactly that until 2026-10-15) — and justai.pro is above them
61
+ // all (sending the parent "home" to a child platform is the wrong direction). Every other
62
+ // persona keeps it. The template passes `home={false}` for every apex it generates.
60
63
  home?: boolean;
61
64
  /**
62
65
  * Which storefront the home affordance points at. Defaults to app.zone — see BackToZone, which owns
@@ -147,11 +150,25 @@ interface Props {
147
150
  // `feed` already reads the host persona's avatar from the registry, and an absolute URL it was
148
151
  // given beats a relative one it inferred.
149
152
  parent?: { href?: string; label?: string; icon?: string };
153
+
154
+ // queries: accountless persona · no sign-in on this persona · turn auth off · auth={false} ·
155
+ // the toolbar loads sdk.js on a persona with no accounts · privacy-sensitive persona
156
+ //
157
+ // ── SIGN-IN, ON UNLESS A PERSONA SAYS IT HAS NO ACCOUNTS ─────────────────────────────────────
158
+ //
159
+ // ON by default, because every persona today is one place in one signed-in ecosystem. Pass
160
+ // `auth={false}` and the AuthMount is not RENDERED — no mount point, no sdk.js tag,
161
+ // so no request to auth.justai.pro is ever made. Hiding it would not be the same thing: a hidden
162
+ // mount still loads a third-party script into the persona's origin, which is the surface an
163
+ // accountless, privacy-sensitive persona is opting out of.
164
+ //
165
+ // Pass the same `auth={false}` to Base, which owns the other half (the token capture in the head).
166
+ auth?: boolean;
150
167
  }
151
168
  import BackToZone from "./BackToZone.astro";
152
169
  const {
153
170
  sectionsLabel, profileLabel, kernelLabel, postsLabel,
154
- files = true, filesLabel = "Files", landOn, avatar = "/icon.svg", parent,
171
+ files = true, filesLabel = "Files", landOn, avatar = "/icon.svg", parent, auth = true,
155
172
  } = Astro.props;
156
173
  // A child's row answers UP to its parent, not out to the zone, and has no stream of its own — so
157
174
  // both default off the moment `parent` is given, rather than each consumer remembering to say so.
@@ -274,7 +291,7 @@ import AuthMount from "./AuthMount.astro";
274
291
  <div class="tb-right">
275
292
  <slot name="toolbarRight" />
276
293
  <slot name="langPicker" />
277
- <AuthMount />
294
+ {auth && <AuthMount />}
278
295
  </div>
279
296
  </div>
280
297
  </header>