@caqophony/ui 0.5.0 → 0.6.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/dist/{chunk-I5DQCG6D.js → chunk-WGWKCFG2.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/marketing.d.mts +4 -2
- package/dist/marketing.js +2 -2
- package/dist/material-art.d.mts +35 -2
- package/dist/material-art.js +36 -5
- package/dist/material.d.mts +12 -14
- package/dist/material.js +118 -94
- package/package.json +1 -1
- package/styles.css +6 -0
|
@@ -346,7 +346,7 @@ function NavbarMenu({
|
|
|
346
346
|
defaultOpen = false,
|
|
347
347
|
triggerClassName,
|
|
348
348
|
folded = false,
|
|
349
|
-
|
|
349
|
+
night = false
|
|
350
350
|
}) {
|
|
351
351
|
return /* @__PURE__ */ jsx5("div", { className: folded ? "ml-auto" : "ml-auto md:hidden", children: /* @__PURE__ */ jsxs4(
|
|
352
352
|
NavDrawer,
|
|
@@ -356,7 +356,7 @@ function NavbarMenu({
|
|
|
356
356
|
closedFrom: folded ? null : "md",
|
|
357
357
|
defaultOpen,
|
|
358
358
|
triggerClassName,
|
|
359
|
-
surface,
|
|
359
|
+
surface: night ? "night" : void 0,
|
|
360
360
|
children: [
|
|
361
361
|
search && /* @__PURE__ */ jsx5("div", { className: "px-4 pb-3", children: search }),
|
|
362
362
|
links && /* @__PURE__ */ jsx5("nav", { className: "flex flex-col px-4 pb-3 [&>a]:whitespace-normal [&>a]:py-2.5 [&>a]:text-base", children: links }),
|
package/dist/index.js
CHANGED
package/dist/marketing.d.mts
CHANGED
|
@@ -41,8 +41,10 @@ interface MarketingHeaderProps {
|
|
|
41
41
|
* through the bar; its drawer stands on the same scope.
|
|
42
42
|
*
|
|
43
43
|
* #5948: below `md` the links and actions fold into the library's one phone
|
|
44
|
-
* drawer (`NavbarMenu`), in both variants.
|
|
45
|
-
* surface
|
|
44
|
+
* drawer (`NavbarMenu`), in both variants. A `light` bar's drawer stands on
|
|
45
|
+
* the card surface. #5997: a `dark` bar's stands on the night scope, as a
|
|
46
|
+
* `night` bar's does (#5980): its actions are `MarketingCta ground="dark"`,
|
|
47
|
+
* which read near-white on a day card.
|
|
46
48
|
*
|
|
47
49
|
* #5952: the row has a limit, and past it the bar folds into the same drawer at
|
|
48
50
|
* any width (`useFold`), so a brand is never squeezed to make room for links.
|
package/dist/marketing.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
Button,
|
|
4
4
|
Container,
|
|
5
5
|
NavbarMenu
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WGWKCFG2.js";
|
|
7
7
|
import {
|
|
8
8
|
ScrollHintXMark
|
|
9
9
|
} from "./chunk-ID7VBGJA.js";
|
|
@@ -196,7 +196,7 @@ function MarketingHeader({
|
|
|
196
196
|
{
|
|
197
197
|
folded,
|
|
198
198
|
triggerClassName: isDark ? DARK_MENU_BUTTON : isNight ? NIGHT_MENU_BUTTON : void 0,
|
|
199
|
-
|
|
199
|
+
night: isNight || isDark,
|
|
200
200
|
links: hasLinks ? navItems.map((item) => /* @__PURE__ */ jsx(
|
|
201
201
|
"a",
|
|
202
202
|
{
|
package/dist/material-art.d.mts
CHANGED
|
@@ -92,6 +92,20 @@ interface ArtPoly extends ArtFilled {
|
|
|
92
92
|
el: 'polygon' | 'polyline';
|
|
93
93
|
points: ReadonlyArray<readonly [number, number]>;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* #5998 — a ground: the author states where it sits in its frame (`y`) and its
|
|
97
|
+
* tone, and the code runs it the scene's full width and down past its foot
|
|
98
|
+
* (`GROUND_BLEED`), as the approved ports drew theirs by hand (x -4000 to
|
|
99
|
+
* 8000). It stands in a frame's own `nodes` only (the format's check names one
|
|
100
|
+
* in a group or a motif), so no transform moves its bleed. A `HeroScene` clips
|
|
101
|
+
* the sides, and the next band paints over the foot.
|
|
102
|
+
*/
|
|
103
|
+
interface ArtGround {
|
|
104
|
+
el: 'ground';
|
|
105
|
+
y: number;
|
|
106
|
+
fill?: ArtPaint;
|
|
107
|
+
opacity?: number;
|
|
108
|
+
}
|
|
95
109
|
interface ArtText extends ArtFilled {
|
|
96
110
|
el: 'text';
|
|
97
111
|
x: number;
|
|
@@ -102,7 +116,7 @@ interface ArtText extends ArtFilled {
|
|
|
102
116
|
/** Words on the page, apart from the drawing: step 5 holds them to the Brief. */
|
|
103
117
|
copy: string;
|
|
104
118
|
}
|
|
105
|
-
type ArtNode = ArtGroup | ArtPath | ArtRect | ArtCircle | ArtEllipse | ArtLine | ArtPoly | ArtText;
|
|
119
|
+
type ArtNode = ArtGroup | ArtPath | ArtRect | ArtCircle | ArtEllipse | ArtLine | ArtPoly | ArtText | ArtGround;
|
|
106
120
|
/** Where a frame stays when its box has another shape. */
|
|
107
121
|
type ArtAnchor = 'top' | 'center' | 'bottom' | 'right';
|
|
108
122
|
/** `cover` fills the box and may cut the frame; `contain` keeps all of it. */
|
|
@@ -127,11 +141,30 @@ interface ArtTree {
|
|
|
127
141
|
}
|
|
128
142
|
/** The one writer of how a frame sits in its box, for `Art` and `SkyField`. */
|
|
129
143
|
declare const preserveOf: (anchor: ArtAnchor, fit?: ArtFit) => string;
|
|
144
|
+
/**
|
|
145
|
+
* #6002 — how an `Art` frame sits in its box. A frame whose own `nodes` hold a
|
|
146
|
+
* `ground` stands on its box's foot (`YMax`) whatever its `anchor`, whose
|
|
147
|
+
* horizontal part it keeps: a hero's side frame is `contain`ed in a column
|
|
148
|
+
* taller than it, and a centred one put its ground at the copy's height
|
|
149
|
+
* (blind check 9, jobpilot-a: `y` 840 of 1000 under the CTAs from 1024 up).
|
|
150
|
+
* The objects standing on the ground are in the same frame units, so the whole
|
|
151
|
+
* frame moves, never the ground alone. Every other frame, and `SkyField`, keep
|
|
152
|
+
* `preserveOf`.
|
|
153
|
+
*/
|
|
154
|
+
declare const framePreserveOf: (frame: Pick<ArtFrame, "anchor" | "fit" | "nodes">) => string;
|
|
130
155
|
/** The one writer of where frames are cut, for `Art` and `SkyField`. */
|
|
131
156
|
declare const frameClass: (only: ArtOnly | undefined) => string;
|
|
157
|
+
/**
|
|
158
|
+
* #5998 — how far a ground runs past its frame, each way and down, in the
|
|
159
|
+
* frame's larger side. Measured on the gencheck-8 answers and the three ports
|
|
160
|
+
* at every gate width: the scene runs past a frame's drawn content by at most
|
|
161
|
+
* 1.09 of that side (1600px wide), and from `lg` up the side draws at 750px
|
|
162
|
+
* or more, so 8 covers a scene about 6,600px wide.
|
|
163
|
+
*/
|
|
164
|
+
declare const GROUND_BLEED = 8;
|
|
132
165
|
/** Draws a piece of art, for a `Figure`'s slot or a mark. */
|
|
133
166
|
declare function Art({ tree }: {
|
|
134
167
|
tree: ArtTree;
|
|
135
168
|
}): ReactElement;
|
|
136
169
|
|
|
137
|
-
export { Art, type ArtAnchor, type ArtCircle, type ArtDrawing, type ArtEllipse, type ArtFilled, type ArtFit, type ArtFrame, type ArtGroup, type ArtLine, type ArtNode, type ArtOnly, type ArtPaint, type ArtPath, type ArtPoly, type ArtRect, type ArtText, type ArtTransform, type ArtTree, frameClass, preserveOf };
|
|
170
|
+
export { Art, type ArtAnchor, type ArtCircle, type ArtDrawing, type ArtEllipse, type ArtFilled, type ArtFit, type ArtFrame, type ArtGround, type ArtGroup, type ArtLine, type ArtNode, type ArtOnly, type ArtPaint, type ArtPath, type ArtPoly, type ArtRect, type ArtText, type ArtTransform, type ArtTree, GROUND_BLEED, frameClass, framePreserveOf, preserveOf };
|
package/dist/material-art.js
CHANGED
|
@@ -48,7 +48,15 @@ var ANCHOR = {
|
|
|
48
48
|
bottom: "xMidYMax",
|
|
49
49
|
right: "xMaxYMid"
|
|
50
50
|
};
|
|
51
|
-
var
|
|
51
|
+
var FIT = { contain: "meet", cover: "slice" };
|
|
52
|
+
var preserveOf = (anchor, fit = "cover") => `${ANCHOR[anchor]} ${FIT[fit]}`;
|
|
53
|
+
var ANCHOR_X = {
|
|
54
|
+
top: "xMid",
|
|
55
|
+
center: "xMid",
|
|
56
|
+
bottom: "xMid",
|
|
57
|
+
right: "xMax"
|
|
58
|
+
};
|
|
59
|
+
var framePreserveOf = (frame) => frame.nodes.some((node) => node.el === "ground") ? `${ANCHOR_X[frame.anchor]}YMax ${FIT[frame.fit ?? "cover"]}` : preserveOf(frame.anchor, frame.fit);
|
|
52
60
|
var SHOWN = {
|
|
53
61
|
phone: "size-full md:hidden",
|
|
54
62
|
desktop: "hidden size-full md:block",
|
|
@@ -96,10 +104,14 @@ function drawn(node) {
|
|
|
96
104
|
transform: node.transform?.map(transformOf).join(" ")
|
|
97
105
|
};
|
|
98
106
|
}
|
|
99
|
-
|
|
107
|
+
var GROUND_BLEED = 8;
|
|
108
|
+
function render(frame) {
|
|
109
|
+
return (node, key) => drawNode(node, key, frame);
|
|
110
|
+
}
|
|
111
|
+
function drawNode(node, key, frame) {
|
|
100
112
|
switch (node.el) {
|
|
101
113
|
case "g":
|
|
102
|
-
return /* @__PURE__ */ jsx("g", { ...drawn(node), children: node.children.map(render) }, key);
|
|
114
|
+
return /* @__PURE__ */ jsx("g", { ...drawn(node), children: node.children.map(render(frame)) }, key);
|
|
103
115
|
case "path":
|
|
104
116
|
return /* @__PURE__ */ jsx("path", { d: node.d, ...drawn(node) }, key);
|
|
105
117
|
case "rect":
|
|
@@ -169,6 +181,22 @@ function render(node, key) {
|
|
|
169
181
|
},
|
|
170
182
|
key
|
|
171
183
|
);
|
|
184
|
+
case "ground": {
|
|
185
|
+
const bleed = GROUND_BLEED * Math.max(frame.width, frame.height);
|
|
186
|
+
return /* @__PURE__ */ jsx(
|
|
187
|
+
"rect",
|
|
188
|
+
{
|
|
189
|
+
"data-art-ground": "",
|
|
190
|
+
x: -bleed,
|
|
191
|
+
y: node.y,
|
|
192
|
+
width: frame.width + 2 * bleed,
|
|
193
|
+
height: Math.max(frame.height - node.y, 0) + bleed,
|
|
194
|
+
opacity: node.opacity,
|
|
195
|
+
...painted(node)
|
|
196
|
+
},
|
|
197
|
+
key
|
|
198
|
+
);
|
|
199
|
+
}
|
|
172
200
|
case "text":
|
|
173
201
|
return /* @__PURE__ */ jsx(
|
|
174
202
|
"text",
|
|
@@ -195,16 +223,19 @@ function Art({ tree }) {
|
|
|
195
223
|
"svg",
|
|
196
224
|
{
|
|
197
225
|
viewBox: `0 0 ${frame.width} ${frame.height}`,
|
|
198
|
-
preserveAspectRatio:
|
|
226
|
+
preserveAspectRatio: framePreserveOf(frame),
|
|
227
|
+
"data-art-only": frame.only,
|
|
199
228
|
"aria-hidden": "true",
|
|
200
229
|
className: frameClass(frame.only),
|
|
201
|
-
children: frame.nodes.map(render)
|
|
230
|
+
children: frame.nodes.map(render(frame))
|
|
202
231
|
},
|
|
203
232
|
i
|
|
204
233
|
)) });
|
|
205
234
|
}
|
|
206
235
|
export {
|
|
207
236
|
Art,
|
|
237
|
+
GROUND_BLEED,
|
|
208
238
|
frameClass,
|
|
239
|
+
framePreserveOf,
|
|
209
240
|
preserveOf
|
|
210
241
|
};
|
package/dist/material.d.mts
CHANGED
|
@@ -198,14 +198,13 @@ interface FieldSize {
|
|
|
198
198
|
height: number;
|
|
199
199
|
}
|
|
200
200
|
/**
|
|
201
|
-
* #5985 round 2 —
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
201
|
+
* #5985 round 2 — how far a field's horizon pieces run on past it: every piece
|
|
202
|
+
* bleeds both ways (`BLEED_WIDTHS`), and `down` runs every fill on below the
|
|
203
|
+
* field's bottom. #5997 retired the copy-side end (`close`): the approved port
|
|
204
|
+
* runs its ground the hero's full width, under the copy, and an end inside the
|
|
205
|
+
* scene showed as a tongue on every generated hero (generation check 7, 4 of 4).
|
|
205
206
|
*/
|
|
206
207
|
interface FieldReach {
|
|
207
|
-
left: 'bleed' | 'close';
|
|
208
|
-
right: 'bleed' | 'close';
|
|
209
208
|
down: boolean;
|
|
210
209
|
}
|
|
211
210
|
/** A field outside a `HeroScene`, `Band`'s edge and the stored art: the bleed both ways, filled to the field's bottom. */
|
|
@@ -253,10 +252,7 @@ interface CloudBankProps {
|
|
|
253
252
|
* `contain`, and no start edge lands in a zone.
|
|
254
253
|
*
|
|
255
254
|
* #5985 round 2 — `reach` (a `HeroScene`'s field): `down` fills every path on
|
|
256
|
-
* `DOWN_SHARE` of a field-height below the field's bottom
|
|
257
|
-
* has no bleed: the run ends with a last bump, a quarter ellipse from the run's
|
|
258
|
-
* top down to the frame's edge at the foot of that fill, at least a `max` wide,
|
|
259
|
-
* so it never stands as a straight edge.
|
|
255
|
+
* `DOWN_SHARE` of a field-height below the field's bottom.
|
|
260
256
|
*/
|
|
261
257
|
declare function cloudBankPaths(field: FieldSize, bank: Omit<CloudBankProps, 'tone'>, reach: FieldReach): readonly string[];
|
|
262
258
|
/**
|
|
@@ -283,9 +279,7 @@ interface RidgeProps {
|
|
|
283
279
|
* pixels from before to keep.
|
|
284
280
|
*
|
|
285
281
|
* #5985 round 2 — `down` fills on `DOWN_SHARE` of a field-height below the
|
|
286
|
-
* field's bottom
|
|
287
|
-
* there is no bleed: the swell at the edge slopes down to the frame's edge at
|
|
288
|
-
* the foot of that fill.
|
|
282
|
+
* field's bottom.
|
|
289
283
|
*/
|
|
290
284
|
declare function ridgePath(field: FieldSize, ridge: Omit<RidgeProps, 'tone'>, reach: FieldReach): string;
|
|
291
285
|
/** A smooth ridge line across its field, filled to the field's bottom. */
|
|
@@ -309,7 +303,11 @@ interface RoutePoint {
|
|
|
309
303
|
x: number;
|
|
310
304
|
y: number;
|
|
311
305
|
label?: string;
|
|
312
|
-
/**
|
|
306
|
+
/**
|
|
307
|
+
* Which side of the point its label sits, first: the route keeps it unless
|
|
308
|
+
* the label would cross another or a mark, or leave the field, and then
|
|
309
|
+
* places it on the first side clear of them (#5997).
|
|
310
|
+
*/
|
|
313
311
|
side?: 'above' | 'below' | 'left' | 'right';
|
|
314
312
|
/** `passed`: filled; `here`: ringed; `ahead`: hollow. */
|
|
315
313
|
state: 'passed' | 'here' | 'ahead';
|
package/dist/material.js
CHANGED
|
@@ -89,7 +89,8 @@ var ANCHOR = {
|
|
|
89
89
|
bottom: "xMidYMax",
|
|
90
90
|
right: "xMaxYMid"
|
|
91
91
|
};
|
|
92
|
-
var
|
|
92
|
+
var FIT = { contain: "meet", cover: "slice" };
|
|
93
|
+
var preserveOf = (anchor, fit = "cover") => `${ANCHOR[anchor]} ${FIT[fit]}`;
|
|
93
94
|
var SHOWN = {
|
|
94
95
|
phone: "size-full md:hidden",
|
|
95
96
|
desktop: "hidden size-full md:block",
|
|
@@ -263,11 +264,8 @@ function sized(piece, field) {
|
|
|
263
264
|
);
|
|
264
265
|
}
|
|
265
266
|
var MAX_BUMPS = 2e3;
|
|
266
|
-
var BLEED_BOTH_SIDES = {
|
|
267
|
-
|
|
268
|
-
right: "bleed",
|
|
269
|
-
down: false
|
|
270
|
-
};
|
|
267
|
+
var BLEED_BOTH_SIDES = { down: false };
|
|
268
|
+
var IN_SCENE = { down: true };
|
|
271
269
|
var SceneCopyContext = createContext(null);
|
|
272
270
|
var GroundContext = createContext(null);
|
|
273
271
|
var FieldContext = createContext(null);
|
|
@@ -280,11 +278,8 @@ function useField(piece) {
|
|
|
280
278
|
);
|
|
281
279
|
return field;
|
|
282
280
|
}
|
|
283
|
-
function reachOf(copy
|
|
284
|
-
|
|
285
|
-
if (only === "stack" || only === "phone")
|
|
286
|
-
return { left: "bleed", right: "bleed", down: true };
|
|
287
|
-
return copy === "start" ? { left: "close", right: "bleed", down: true } : { left: "bleed", right: "close", down: true };
|
|
281
|
+
function reachOf(copy) {
|
|
282
|
+
return copy === null ? BLEED_BOTH_SIDES : IN_SCENE;
|
|
288
283
|
}
|
|
289
284
|
function SkyField({
|
|
290
285
|
width,
|
|
@@ -304,7 +299,7 @@ function SkyField({
|
|
|
304
299
|
const field = {
|
|
305
300
|
width,
|
|
306
301
|
height,
|
|
307
|
-
reach: reachOf(copy
|
|
302
|
+
reach: reachOf(copy),
|
|
308
303
|
ground: ground === "none" ? under : ground,
|
|
309
304
|
routes: new Set(
|
|
310
305
|
routes.map(
|
|
@@ -380,7 +375,7 @@ function cloudBankPaths(field, bank, reach) {
|
|
|
380
375
|
const rounded = (n) => Number(n.toFixed(1));
|
|
381
376
|
const step = (r, draw) => (draw() - 0.5) * r * 0.5 - climb * r * 2 / width;
|
|
382
377
|
const next = rng(seed);
|
|
383
|
-
|
|
378
|
+
let frame = `M${-max} ${bottom}L${-max} ${y}`;
|
|
384
379
|
let x = -max;
|
|
385
380
|
let endX = x;
|
|
386
381
|
let endY = y;
|
|
@@ -393,63 +388,35 @@ function cloudBankPaths(field, bank, reach) {
|
|
|
393
388
|
x += r * 2;
|
|
394
389
|
endX += rounded(r * 2);
|
|
395
390
|
endY += rounded(lift);
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
const end = (from, edge, up) => {
|
|
399
|
-
const rx = Math.abs(edge - from.x).toFixed(1);
|
|
400
|
-
const ry = bottom - from.y;
|
|
401
|
-
if (ry <= 0)
|
|
402
|
-
throw new Error(
|
|
403
|
-
`CloudBank: its end at the frame's edge has no depth to fall (top ${from.y.toFixed(1)}, fill to ${bottom}); a closed side fills on below the field`
|
|
404
|
-
);
|
|
405
|
-
return up ? `A${rx} ${ry.toFixed(1)} 0 0 1 ${from.x.toFixed(1)} ${from.y.toFixed(1)}` : `A${rx} ${ry.toFixed(1)} 0 0 1 ${edge} ${bottom}`;
|
|
406
|
-
};
|
|
407
|
-
const first = reach.left === "close" ? run.findIndex((b) => b.endX >= max) : -1;
|
|
408
|
-
let last = run.length - 1;
|
|
409
|
-
if (reach.right === "close") {
|
|
410
|
-
last = -1;
|
|
411
|
-
run.forEach((b, i) => {
|
|
412
|
-
if (b.endX <= width - max && i > first) last = i;
|
|
413
|
-
});
|
|
391
|
+
frame += arc(r, lift);
|
|
414
392
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
let offset = 0;
|
|
428
|
-
while (lx > -BLEED_WIDTHS * width - max) {
|
|
429
|
-
const r = min + back() * (max - min);
|
|
430
|
-
const s = step(r, back);
|
|
431
|
-
const lift = level ? offset - s : s;
|
|
432
|
-
offset -= rounded(lift);
|
|
433
|
-
arcs.unshift(arc(r, lift));
|
|
434
|
-
lx -= rounded(r * 2);
|
|
435
|
-
}
|
|
436
|
-
paths.push(
|
|
437
|
-
`M${lx.toFixed(1)} ${bottom}L${lx.toFixed(1)} ${(y + offset).toFixed(1)}${arcs.join("")}L${-max} ${y}L${-max + under} ${y + under}L${-max + under} ${bottom}Z`
|
|
438
|
-
);
|
|
393
|
+
frame += `L${x} ${bottom}Z`;
|
|
394
|
+
const back = rng(seed + BLEED_STREAM);
|
|
395
|
+
const arcs = [];
|
|
396
|
+
let lx = -max;
|
|
397
|
+
let offset = 0;
|
|
398
|
+
while (lx > -BLEED_WIDTHS * width - max) {
|
|
399
|
+
const r = min + back() * (max - min);
|
|
400
|
+
const s = step(r, back);
|
|
401
|
+
const lift = level ? offset - s : s;
|
|
402
|
+
offset -= rounded(lift);
|
|
403
|
+
arcs.unshift(arc(r, lift));
|
|
404
|
+
lx -= rounded(r * 2);
|
|
439
405
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
406
|
+
const paths = [
|
|
407
|
+
`M${lx.toFixed(1)} ${bottom}L${lx.toFixed(1)} ${(y + offset).toFixed(1)}${arcs.join("")}L${-max} ${y}L${-max + under} ${y + under}L${-max + under} ${bottom}Z`
|
|
408
|
+
];
|
|
409
|
+
let right = `M${(endX - under).toFixed(1)} ${bottom}L${(endX - under).toFixed(1)} ${(endY + under).toFixed(1)}L${endX.toFixed(1)} ${endY.toFixed(1)}`;
|
|
410
|
+
let rx = x;
|
|
411
|
+
while (rx < (1 + BLEED_WIDTHS) * width + max) {
|
|
412
|
+
const r = min + next() * (max - min);
|
|
413
|
+
const s = step(r, next);
|
|
414
|
+
const lift = level ? s - drift : s;
|
|
415
|
+
drift += lift;
|
|
416
|
+
right += arc(r, lift);
|
|
417
|
+
rx += r * 2;
|
|
452
418
|
}
|
|
419
|
+
paths.push(`${right}L${rx} ${bottom}Z`);
|
|
453
420
|
paths.push(frame);
|
|
454
421
|
return paths;
|
|
455
422
|
}
|
|
@@ -465,27 +432,20 @@ function ridgePath(field, ridge, reach) {
|
|
|
465
432
|
measuredAll("Ridge", field, { y, rise, swells, seed });
|
|
466
433
|
const bottom = reach.down ? height * (1 + DOWN_SHARE) : height;
|
|
467
434
|
const step = width / swells;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
const cy = y - back() * rise;
|
|
476
|
-
const end = i === -1 ? y : y - back() * rise * 0.3;
|
|
477
|
-
d += `Q${(i + 0.5) * step} ${cy.toFixed(1)} ${(i + 1) * step} ${end.toFixed(1)}`;
|
|
478
|
-
}
|
|
435
|
+
const back = rng(seed + BLEED_STREAM);
|
|
436
|
+
const from = -BLEED_WIDTHS * width;
|
|
437
|
+
let d = `M${from} ${bottom}L${from} ${(y - back() * rise * 0.3).toFixed(1)}`;
|
|
438
|
+
for (let i = -BLEED_WIDTHS * swells; i < 0; i++) {
|
|
439
|
+
const cy = y - back() * rise;
|
|
440
|
+
const end = i === -1 ? y : y - back() * rise * 0.3;
|
|
441
|
+
d += `Q${(i + 0.5) * step} ${cy.toFixed(1)} ${(i + 1) * step} ${end.toFixed(1)}`;
|
|
479
442
|
}
|
|
480
443
|
const next = rng(seed);
|
|
481
|
-
|
|
482
|
-
for (let i = 0; i < count; i++) {
|
|
444
|
+
for (let i = 0; i < (1 + BLEED_WIDTHS) * swells; i++) {
|
|
483
445
|
const cy = y - next() * rise;
|
|
484
446
|
const tail = (y - next() * rise * 0.3).toFixed(1);
|
|
485
|
-
|
|
486
|
-
d += `Q${(i + 0.5) * step} ${cy.toFixed(1)} ${(i + 1) * step} ${end}`;
|
|
447
|
+
d += `Q${(i + 0.5) * step} ${cy.toFixed(1)} ${(i + 1) * step} ${tail}`;
|
|
487
448
|
}
|
|
488
|
-
if (reach.right === "close") return `${d}Z`;
|
|
489
449
|
return `${d}L${(1 + BLEED_WIDTHS) * width} ${bottom}Z`;
|
|
490
450
|
}
|
|
491
451
|
function Ridge({ tone, ...ridge }) {
|
|
@@ -509,7 +469,71 @@ function Stars({ tone, ...stars }) {
|
|
|
509
469
|
const dots = starDots(field, stars);
|
|
510
470
|
return /* @__PURE__ */ jsx2("g", { className: FILL[tone], children: dots.map((dot, i) => /* @__PURE__ */ jsx2("circle", { cx: dot.cx, cy: dot.cy, r: dot.r }, i)) });
|
|
511
471
|
}
|
|
512
|
-
var LABEL_HALO = 0.
|
|
472
|
+
var LABEL_HALO = 0.12;
|
|
473
|
+
var LABEL_ADVANCE_EM = 0.62;
|
|
474
|
+
function routeLabelPlaces(points, labelSize, field) {
|
|
475
|
+
const gap = labelSize * 1.1;
|
|
476
|
+
const pad = labelSize * LABEL_HALO / 2;
|
|
477
|
+
const marks = points.map((p) => {
|
|
478
|
+
const r = labelSize * (p.state === "here" ? 0.85 : 0.34);
|
|
479
|
+
return {
|
|
480
|
+
what: `the mark at ${p.x},${p.y}`,
|
|
481
|
+
box: { left: p.x - r, top: p.y - r, right: p.x + r, bottom: p.y + r }
|
|
482
|
+
};
|
|
483
|
+
});
|
|
484
|
+
const placed = [];
|
|
485
|
+
return points.map((p, i) => {
|
|
486
|
+
if (!p.label) return null;
|
|
487
|
+
const words = p.label;
|
|
488
|
+
const width = words.length * LABEL_ADVANCE_EM * labelSize;
|
|
489
|
+
const before = points[Math.max(0, i - 1)];
|
|
490
|
+
const after = points[Math.min(points.length - 1, i + 1)];
|
|
491
|
+
const across = Math.abs(after.x - before.x) >= Math.abs(after.y - before.y);
|
|
492
|
+
const order = across ? ["above", "below", "right", "left"] : ["right", "left", "above", "below"];
|
|
493
|
+
const sides = p.side === void 0 ? order : [p.side, ...order.filter((side) => side !== p.side)];
|
|
494
|
+
const candidates = sides.map((side) => {
|
|
495
|
+
const x = side === "left" ? p.x - gap : side === "right" ? p.x + gap : p.x;
|
|
496
|
+
const y = side === "above" ? p.y - gap : side === "below" ? p.y + gap * 1.5 : p.y + labelSize * 0.35;
|
|
497
|
+
const anchor = side === "left" ? "end" : side === "right" ? "start" : "middle";
|
|
498
|
+
const left = anchor === "start" ? x : anchor === "end" ? x - width : x - width / 2;
|
|
499
|
+
return {
|
|
500
|
+
x,
|
|
501
|
+
y,
|
|
502
|
+
anchor,
|
|
503
|
+
side,
|
|
504
|
+
box: {
|
|
505
|
+
left: left - pad,
|
|
506
|
+
right: left + width + pad,
|
|
507
|
+
top: y - labelSize * 0.8 - pad,
|
|
508
|
+
bottom: y + labelSize * 0.25 + pad
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
});
|
|
512
|
+
const others = [...placed, ...marks.filter((_, k) => k !== i)];
|
|
513
|
+
const blocks = (c) => [
|
|
514
|
+
...others.map((o) => ({
|
|
515
|
+
what: o.what,
|
|
516
|
+
across: Math.min(c.box.right, o.box.right) - Math.max(c.box.left, o.box.left),
|
|
517
|
+
down: Math.min(c.box.bottom, o.box.bottom) - Math.max(c.box.top, o.box.top)
|
|
518
|
+
})).filter((h) => h.across > 0 && h.down > 0).map(
|
|
519
|
+
(h) => `crosses ${h.what} by ${h.across.toFixed(1)} by ${h.down.toFixed(1)}`
|
|
520
|
+
),
|
|
521
|
+
...[
|
|
522
|
+
{ edge: "left", by: -c.box.left },
|
|
523
|
+
{ edge: "top", by: -c.box.top },
|
|
524
|
+
{ edge: "right", by: c.box.right - field.width },
|
|
525
|
+
{ edge: "bottom", by: c.box.bottom - field.height }
|
|
526
|
+
].filter((e) => e.by > 0).map((e) => `runs ${e.by.toFixed(1)} past the field's ${e.edge}`)
|
|
527
|
+
];
|
|
528
|
+
const clear = candidates.find((c) => blocks(c).length === 0);
|
|
529
|
+
if (clear === void 0)
|
|
530
|
+
throw new Error(
|
|
531
|
+
`RouteLine: the label "${words}" has no clear side, in field units: ${candidates.map((c) => `${c.side} ${blocks(c).join(" and ")}`).join("; ")}. Move its point, or what it meets, apart`
|
|
532
|
+
);
|
|
533
|
+
placed.push({ what: `the label "${words}"`, box: clear.box });
|
|
534
|
+
return clear;
|
|
535
|
+
});
|
|
536
|
+
}
|
|
513
537
|
function RouteLine({
|
|
514
538
|
points,
|
|
515
539
|
tone,
|
|
@@ -535,19 +559,16 @@ function RouteLine({
|
|
|
535
559
|
if (layer === "labels") {
|
|
536
560
|
if (!labelled || field.ground === null) return null;
|
|
537
561
|
const halo = STROKE[field.ground];
|
|
538
|
-
const
|
|
562
|
+
const places = routeLabelPlaces(points, labelSize, field);
|
|
539
563
|
return /* @__PURE__ */ jsx2(Fragment2, { children: points.map((p, i) => {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const lx = side === "left" ? p.x - gap : side === "right" ? p.x + gap : p.x;
|
|
543
|
-
const ly = side === "above" ? p.y - gap : side === "below" ? p.y + gap * 1.5 : p.y + labelSize * 0.35;
|
|
544
|
-
const anchor = side === "left" ? "end" : side === "right" ? "start" : "middle";
|
|
564
|
+
const place = places[i];
|
|
565
|
+
if (!p.label || !place) return null;
|
|
545
566
|
return /* @__PURE__ */ jsx2(
|
|
546
567
|
"text",
|
|
547
568
|
{
|
|
548
|
-
x:
|
|
549
|
-
y:
|
|
550
|
-
textAnchor: anchor,
|
|
569
|
+
x: place.x,
|
|
570
|
+
y: place.y,
|
|
571
|
+
textAnchor: place.anchor,
|
|
551
572
|
fontSize: labelSize,
|
|
552
573
|
fontWeight: 600,
|
|
553
574
|
strokeWidth: labelSize * LABEL_HALO,
|
|
@@ -759,13 +780,15 @@ var HEIGHT2 = {
|
|
|
759
780
|
fold: "lg:min-h-[min(calc(100svh-4rem),56rem)]",
|
|
760
781
|
tall: "lg:min-h-[46rem]"
|
|
761
782
|
};
|
|
783
|
+
var CLIP_ABOVE = "[clip-path:inset(0_0_-100vh_0)]";
|
|
784
|
+
var COPY_CONTAINER = "lg:[container-type:inline-size] lg:[container-name:hero-copy]";
|
|
762
785
|
function HeroScene({
|
|
763
786
|
height,
|
|
764
787
|
subject,
|
|
765
788
|
copySide = "start",
|
|
766
789
|
children
|
|
767
790
|
}) {
|
|
768
|
-
return /* @__PURE__ */ jsx5("div", { "data-hero-scene": "", className: "overflow-x-clip", children: /* @__PURE__ */ jsxs3(
|
|
791
|
+
return /* @__PURE__ */ jsx5("div", { "data-hero-scene": "", className: cn("overflow-x-clip", CLIP_ABOVE), children: /* @__PURE__ */ jsxs3(
|
|
769
792
|
"div",
|
|
770
793
|
{
|
|
771
794
|
className: cn(
|
|
@@ -779,6 +802,7 @@ function HeroScene({
|
|
|
779
802
|
"data-hero-copy": "",
|
|
780
803
|
className: cn(
|
|
781
804
|
"relative z-10 flex min-w-0 flex-col items-start justify-center gap-6 py-10 md:py-14",
|
|
805
|
+
COPY_CONTAINER,
|
|
782
806
|
CONTENT_GUTTER,
|
|
783
807
|
copySide === "end" && "lg:order-2"
|
|
784
808
|
),
|
package/package.json
CHANGED
package/styles.css
CHANGED
|
@@ -289,6 +289,12 @@
|
|
|
289
289
|
line-height: 1.5;
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
@container hero-copy (width > 0px) {
|
|
293
|
+
.text-display-poster {
|
|
294
|
+
font-size: min(clamp(3rem, 1.05rem + 8vw, 7rem), calc(100cqi * 7 / 33.5));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
292
298
|
[data-page-surface='marketing'] {
|
|
293
299
|
--page-bg: var(--background);
|
|
294
300
|
--section-band: color-mix(in srgb, hsl(var(--foreground)) 8%, hsl(var(--background)));
|