@justai/cuts 0.133.0 → 0.138.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 +6 -3
- package/src/ActionList.astro +31 -27
- package/src/ActionRow.astro +68 -64
- package/src/BackToZone.astro +39 -35
- package/src/Base.astro +21 -3
- package/src/Catalogue.astro +95 -319
- package/src/CatalogueCard.astro +72 -68
- package/src/ChildPersona.astro +55 -51
- package/src/ConfirmSheet.astro +69 -65
- package/src/FilePicker.astro +21 -378
- package/src/LangPicker.astro +49 -104
- package/src/Posts.astro +177 -396
- package/src/Preroll.astro +204 -487
- package/src/Profile.astro +39 -35
- package/src/Segmented.astro +62 -111
- package/src/Sheet.astro +247 -507
- package/src/Toolbar.astro +288 -362
- package/src/behaviour/catalogue.ts +239 -0
- package/src/behaviour/filePicker.ts +372 -0
- package/src/behaviour/langPicker.ts +70 -0
- package/src/behaviour/posts.ts +234 -0
- package/src/behaviour/preroll.ts +298 -0
- package/src/behaviour/segmented.ts +64 -0
- package/src/behaviour/sheet.ts +300 -0
- package/src/behaviour/toolbar.ts +89 -0
- package/src/ground.css +124 -120
package/src/ChildPersona.astro
CHANGED
|
@@ -217,64 +217,68 @@ const chrome = face === "page";
|
|
|
217
217
|
</div>
|
|
218
218
|
|
|
219
219
|
<style>
|
|
220
|
-
/*
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
220
|
+
/* Scoped by Astro's hash AND placed in the cascade: a persona overriding this never has to
|
|
221
|
+
out-specify it. See @justai/ui/tokens.css for the order, and for what deliberately stays out. */
|
|
222
|
+
@layer justai.components {
|
|
223
|
+
/* THE SHELL, scoped under `.pp` — the 26 rules files, me and feed each carried verbatim.
|
|
224
|
+
*
|
|
225
|
+
* They are written here at the SAME depth the children wrote them, and that is deliberate: a
|
|
226
|
+
* child's own `.pp .x` rule ties with this one and wins on order, so a child that needs to differ
|
|
227
|
+
* still can, without !important and without knowing anything about this file. */
|
|
225
228
|
|
|
226
|
-
|
|
227
|
-
|
|
229
|
+
.pp { min-height: 100vh; min-height: 100dvh; } /* the pair survives — see @justai/astro-config */
|
|
230
|
+
.pp a { color: inherit; text-decoration: none; }
|
|
228
231
|
|
|
229
|
-
|
|
230
|
-
.pp .app {
|
|
231
|
-
/* Set here AND read with a fallback, which is not belt-and-braces: a consumer that overrides
|
|
232
|
-
`.pp .app` — same selector, later stylesheet — drops the declaration and keeps the reads, and
|
|
233
|
-
an unresolved var() invalidates the whole `padding-inline`. The cut brings its own ground
|
|
234
|
-
(law 1) means the ground has to survive being partly overwritten. */
|
|
235
|
-
--gutter: 16px;
|
|
236
|
-
display: flex; flex-direction: column;
|
|
237
|
-
padding-inline: max(var(--gutter, 16px), env(safe-area-inset-left)) max(var(--gutter, 16px), env(safe-area-inset-right));
|
|
238
|
-
}
|
|
239
|
-
/* 640 is the fleet's one threshold and the fleet's one column width — @justai/ui declares
|
|
240
|
-
`--column`, and a media query cannot read a custom property, so the NUMBER has to be written
|
|
241
|
-
again here. Written again is not decided again: if this ever disagrees with base.css, this is
|
|
242
|
-
the copy that is wrong. */
|
|
243
|
-
@media (min-width: 640px) {
|
|
232
|
+
/* the column — the fleet's one presentation at every width */
|
|
244
233
|
.pp .app {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
234
|
+
/* Set here AND read with a fallback, which is not belt-and-braces: a consumer that overrides
|
|
235
|
+
`.pp .app` — same selector, later stylesheet — drops the declaration and keeps the reads, and
|
|
236
|
+
an unresolved var() invalidates the whole `padding-inline`. The cut brings its own ground
|
|
237
|
+
(law 1) means the ground has to survive being partly overwritten. */
|
|
238
|
+
--gutter: 16px;
|
|
239
|
+
display: flex; flex-direction: column;
|
|
240
|
+
padding-inline: max(var(--gutter, 16px), env(safe-area-inset-left)) max(var(--gutter, 16px), env(safe-area-inset-right));
|
|
241
|
+
}
|
|
242
|
+
/* 640 is the fleet's one threshold and the fleet's one column width — @justai/ui declares
|
|
243
|
+
`--column`, and a media query cannot read a custom property, so the NUMBER has to be written
|
|
244
|
+
again here. Written again is not decided again: if this ever disagrees with base.css, this is
|
|
245
|
+
the copy that is wrong. */
|
|
246
|
+
@media (min-width: 640px) {
|
|
247
|
+
.pp .app {
|
|
248
|
+
--gutter: 28px;
|
|
249
|
+
max-width: 640px;
|
|
250
|
+
max-width: var(--column, 640px);
|
|
251
|
+
margin-left: auto; margin-right: auto; margin-inline: auto;
|
|
252
|
+
padding-left: 28px; padding-right: 28px; padding-inline: var(--gutter, 28px);
|
|
253
|
+
border-left: 1px solid var(--border); border-right: 1px solid var(--border);
|
|
254
|
+
border-inline: 1px solid var(--border); background: var(--surface);
|
|
255
|
+
backdrop-filter: blur(40px) saturate(1.4); -webkit-backdrop-filter: blur(40px) saturate(1.4);
|
|
256
|
+
}
|
|
253
257
|
}
|
|
254
|
-
}
|
|
255
258
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
259
|
+
.pp .below { position: relative; }
|
|
260
|
+
/* the sticky row means a section reached by its id arrives UNDER it unless it says otherwise */
|
|
261
|
+
/* The landing offset is `--shell-top` and only that — measured by the shell, published on :root,
|
|
262
|
+
enforced by personaScroll. This line carried a literal 82px through THREE fleet-wide sweeps of
|
|
263
|
+
exactly that constant (base.css, Posts.astro, eight persona repos) and surfaced only when the
|
|
264
|
+
children's console started warning about it: a scoped rule inside a cut is where a stale number
|
|
265
|
+
hides longest, because nobody greps a component for a layout constant. */
|
|
266
|
+
.pp #profile, .pp #kernel { scroll-margin-top: var(--shell-top, 78px); }
|
|
264
267
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
268
|
+
/* THE `sheet` FACE: no column, no ground, no chrome. The sheet around it IS the frame, and a
|
|
269
|
+
second frame inside one is a box in a box. Keyed on the face name rather than on a boolean, so a
|
|
270
|
+
third face styles itself by adding a selector instead of by renaming this one. */
|
|
271
|
+
.pp[data-face="sheet"] { min-height: 0; }
|
|
272
|
+
.pp[data-face="sheet"] .app { max-width: none; margin-inline: 0; border: 0; background: none;
|
|
273
|
+
backdrop-filter: none; -webkit-backdrop-filter: none; }
|
|
271
274
|
|
|
272
|
-
|
|
273
|
-
|
|
275
|
+
/* a mark fills its box; the picture inside it covers */
|
|
276
|
+
.pp .mk { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
274
277
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
278
|
+
/* Motion is never forced on somebody who asked it not to be — and the biggest effects, the ones a
|
|
279
|
+
surface is proudest of, are exactly what that setting exists to suppress. */
|
|
280
|
+
@media (prefers-reduced-motion: reduce) {
|
|
281
|
+
.pp *, .pp *::before, .pp *::after { animation: none !important; transition: none !important; }
|
|
282
|
+
}
|
|
279
283
|
}
|
|
280
284
|
</style>
|
package/src/ConfirmSheet.astro
CHANGED
|
@@ -87,72 +87,76 @@ const { id, title, body, actionLabel, cancelLabel, destructive = false, ask = fa
|
|
|
87
87
|
</dialog>
|
|
88
88
|
|
|
89
89
|
<style>
|
|
90
|
-
/*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
/* Scoped by Astro's hash AND placed in the cascade: a persona overriding this never has to
|
|
91
|
+
out-specify it. See @justai/ui/tokens.css for the order, and for what deliberately stays out. */
|
|
92
|
+
@layer justai.components {
|
|
93
|
+
/* The dialog sits in the browser's top layer — above every z-index in every persona, by law. */
|
|
94
|
+
.confirm {
|
|
95
|
+
/* dock to the bottom like an iOS sheet (native <dialog> centers by default) */
|
|
96
|
+
margin: auto auto max(12px, env(safe-area-inset-bottom));
|
|
97
|
+
width: min(400px, calc(100vw - 24px));
|
|
98
|
+
padding: 0;
|
|
99
|
+
border: 0;
|
|
100
|
+
background: none;
|
|
101
|
+
overflow: visible;
|
|
102
|
+
}
|
|
103
|
+
.confirm::backdrop {
|
|
104
|
+
background: rgba(0, 0, 0, 0.4);
|
|
105
|
+
backdrop-filter: blur(4px);
|
|
106
|
+
-webkit-backdrop-filter: blur(4px);
|
|
107
|
+
}
|
|
108
|
+
.confirm[open] .confirm-form { animation: confirm-up 0.4s var(--ease-spring) both; }
|
|
109
|
+
.confirm[open]::backdrop { animation: confirm-fade 0.2s var(--ease-out) both; }
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
111
|
+
.confirm-form { display: flex; flex-direction: column; gap: 8px; }
|
|
112
|
+
.confirm-group {
|
|
113
|
+
border-radius: 18px; overflow: hidden; border: 1px solid var(--border);
|
|
114
|
+
/* Apple's THICK material, deliberately: at 80% the kernel behind ghosted through the card
|
|
115
|
+
(founder-caught on the QR grid). The frosted feel comes from the blur, not from letting
|
|
116
|
+
content bleed into the words — a sheet asking for a decision must be legible first. */
|
|
117
|
+
background: color-mix(in srgb, var(--bg) 93%, transparent);
|
|
118
|
+
backdrop-filter: blur(30px) saturate(1.5); -webkit-backdrop-filter: blur(30px) saturate(1.5);
|
|
119
|
+
}
|
|
120
|
+
.confirm-msg { padding: 18px 18px 16px; text-align: center; display: flex; flex-direction: column; gap: 5px; }
|
|
121
|
+
.confirm-msg strong { font-size: var(--fs-md); font-weight: 700; letter-spacing: -0.01em; color: var(--text); }
|
|
122
|
+
.confirm-msg span { font-size: var(--fs-xs); color: var(--text-dim); line-height: 1.45; }
|
|
123
|
+
/* a title-less sheet's body is not supporting text under a headline — it IS the voice AND the
|
|
124
|
+
title, so it speaks in the primary colour at the native body size (founder: the question
|
|
125
|
+
deserves reading size, not caption size) */
|
|
126
|
+
.confirm-msg span:only-child { color: var(--text); font-size: var(--fs-base); line-height: 1.5; }
|
|
127
|
+
.confirm-act {
|
|
128
|
+
width: 100%; padding: 15px; border: 0; border-block-start: 1px solid var(--border);
|
|
129
|
+
/* --confirm-accent: the declared hook for personas whose accent is too BRIGHT to read as text
|
|
130
|
+
on the frosted card in light mode (cleanmylink's mint, howlong's amber, whatismyip's mint —
|
|
131
|
+
the same three that once hooked the old filled consent button). They set a theme-aware
|
|
132
|
+
darker tone of their own hue; everyone else says nothing. */
|
|
133
|
+
background: none; font: 600 var(--fs-md) var(--font, inherit); color: var(--confirm-accent, var(--accent)); cursor: pointer;
|
|
134
|
+
transition: background 0.15s;
|
|
135
|
+
}
|
|
136
|
+
.confirm-act:active { background: color-mix(in srgb, var(--text) 9%, transparent); }
|
|
137
|
+
/* focus is a wash, not a ring: the fleet's 4px focus ring gets CLIPPED by the card's
|
|
138
|
+
overflow:hidden into two stray bars — inside a sheet, the focused button fills with a
|
|
139
|
+
whisper of its own colour instead (currentColor: accent, red, or text alike) */
|
|
140
|
+
.confirm-act:focus-visible { box-shadow: none; outline: none; background: color-mix(in srgb, currentColor 12%, transparent); }
|
|
141
|
+
/* iOS system red — the one colour that means "this ends something" on every persona alike */
|
|
142
|
+
.confirm-act.destructive { color: var(--danger); }
|
|
143
|
+
/* the ASK genre: the invitation is the preferred path (Apple's bold preferredAction)… */
|
|
144
|
+
.confirm-act.preferred { font-weight: 700; }
|
|
145
|
+
/* …and the safe choice answers in a calm, full-contrast regular voice — equal size, equal tap,
|
|
146
|
+
never dimmed (a decline you have to hunt for is not a free choice), just not the emphasis */
|
|
147
|
+
.confirm-act.quiet { color: var(--text); font-weight: 400; }
|
|
148
|
+
/* the safe choice wears the boldest face, in its own detached card */
|
|
149
|
+
.confirm-cancel {
|
|
150
|
+
border: 1px solid var(--border); border-radius: 18px;
|
|
151
|
+
background: color-mix(in srgb, var(--bg) 93%, transparent);
|
|
152
|
+
backdrop-filter: blur(30px) saturate(1.5); -webkit-backdrop-filter: blur(30px) saturate(1.5);
|
|
153
|
+
font-weight: 700; color: var(--text);
|
|
154
|
+
}
|
|
155
|
+
@keyframes confirm-up { from { transform: translateY(20px); opacity: 0; } }
|
|
156
|
+
@keyframes confirm-fade { from { opacity: 0; } }
|
|
157
|
+
@media (prefers-reduced-motion: reduce) {
|
|
158
|
+
.confirm[open] .confirm-form, .confirm[open]::backdrop { animation: none; }
|
|
159
|
+
}
|
|
156
160
|
}
|
|
157
161
|
</style>
|
|
158
162
|
|