@caltho/site-kit 0.2.11 → 0.3.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/README.md +84 -3
- package/dist/behaviors/accordion.d.ts +4 -0
- package/dist/behaviors/accordion.js +56 -0
- package/dist/behaviors/carousel.d.ts +4 -0
- package/dist/behaviors/carousel.js +127 -0
- package/dist/behaviors/filter.d.ts +1 -0
- package/dist/behaviors/filter.js +25 -0
- package/dist/behaviors/index.d.ts +14 -0
- package/dist/behaviors/index.js +78 -0
- package/dist/behaviors/motion.d.ts +13 -0
- package/dist/behaviors/motion.js +88 -0
- package/dist/behaviors/tabs.d.ts +3 -0
- package/dist/behaviors/tabs.js +55 -0
- package/dist/built/css.d.ts +2 -0
- package/dist/built/css.js +26 -0
- package/dist/built/theme.d.ts +19 -0
- package/dist/built/theme.js +86 -0
- package/dist/built/tree.d.ts +24 -0
- package/dist/built/tree.js +96 -0
- package/dist/built.test.d.ts +1 -0
- package/dist/built.test.js +257 -0
- package/dist/consent.d.ts +33 -0
- package/dist/consent.js +36 -0
- package/dist/consent.test.d.ts +1 -0
- package/dist/consent.test.js +61 -0
- package/dist/content/index.d.ts +170 -40
- package/dist/content/index.js +155 -0
- package/dist/content/lists.d.ts +69 -0
- package/dist/content/lists.js +77 -0
- package/dist/content/lists.test.d.ts +1 -0
- package/dist/content/lists.test.js +257 -0
- package/dist/content/look.d.ts +13 -13
- package/dist/content-migrate.d.ts +51 -0
- package/dist/content-migrate.js +69 -0
- package/dist/finish.d.ts +1 -1
- package/dist/finish.js +18 -5
- package/dist/frame.test.js +25 -0
- package/dist/next/built.d.ts +40 -0
- package/dist/next/built.js +318 -0
- package/dist/next/consent.d.ts +4 -0
- package/dist/next/consent.js +13 -0
- package/dist/next/data.d.ts +2 -2
- package/dist/next/data.js +6 -4
- package/dist/next/frame.d.ts +9 -1
- package/dist/next/frame.js +5 -2
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +2 -0
- package/dist/next/metadata.js +3 -2
- package/dist/next/parts/Img.d.ts +6 -1
- package/dist/next/parts/Img.js +11 -3
- package/dist/next/preview.js +242 -15
- package/dist/next/sections.js +5 -0
- package/dist/policies.js +22 -4
- package/dist/prepare.d.ts +10 -0
- package/dist/prepare.js +67 -3
- package/dist/preview-match.d.ts +21 -0
- package/dist/preview-match.js +25 -0
- package/dist/schema.js +3 -1
- package/dist/sections/icons.d.ts +2 -0
- package/dist/sections/icons.js +4 -0
- package/dist/sections/index.d.ts +38 -16
- package/dist/sections/index.js +7 -2
- package/dist/sections.css +324 -0
- package/dist/seo.js +2 -1
- package/dist/tree/behaviors.d.ts +50 -0
- package/dist/tree/behaviors.js +67 -0
- package/dist/tree/classes.d.ts +24 -0
- package/dist/tree/classes.js +94 -0
- package/dist/tree/index.d.ts +145 -0
- package/dist/tree/index.js +196 -0
- package/dist/tree/messages.d.ts +45 -0
- package/dist/tree/messages.js +7 -0
- package/package.json +15 -1
package/dist/schema.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// check content with messages a person can act on, make a blank new item (a block, a list entry),
|
|
4
4
|
// and find the kinds of block a site has. Also the checks that need no schema at all (pages, home,
|
|
5
5
|
// links), and readable places in the content.
|
|
6
|
+
import { allPages } from "./content/lists.js";
|
|
6
7
|
const unions = (s) => s.anyOf ?? s.oneOf;
|
|
7
8
|
/** Follows a `$ref` to its definition in the same document. */
|
|
8
9
|
export function resolve(s, root) {
|
|
@@ -191,7 +192,8 @@ export function checkStructure(site) {
|
|
|
191
192
|
/** Every link to a page of the site must land on one, and every link to a part of a page must have that part. */
|
|
192
193
|
function linkIssues(site) {
|
|
193
194
|
const issues = [];
|
|
194
|
-
|
|
195
|
+
// A list's item pages are pages too (a link to /products/walnut-desk/ lands).
|
|
196
|
+
const ids = new Map(allPages(site).map((p) => [p.path, new Set(p.blocks.map((b) => b.id).filter(Boolean))]));
|
|
195
197
|
const visit = (value, path, pagePath) => {
|
|
196
198
|
if (Array.isArray(value))
|
|
197
199
|
value.forEach((v, i) => visit(v, [...path, i], pagePath));
|
package/dist/sections/icons.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export declare const ICONS: {
|
|
|
32
32
|
readonly camera: readonly ["M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z", "M12 17a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"];
|
|
33
33
|
readonly play: readonly ["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z", "m10 8 6 4-6 4z"];
|
|
34
34
|
readonly "arrow-right": readonly ["M5 12h14M12 5l7 7-7 7"];
|
|
35
|
+
readonly menu: readonly ["M4 6h16M4 12h16M4 18h16"];
|
|
36
|
+
readonly "star-four": readonly ["M12 2C13.03 7.97 16.03 10.97 22 12C16.03 13.03 13.03 16.03 12 22C10.97 16.03 7.97 13.03 2 12C7.97 10.97 10.97 7.97 12 2Z"];
|
|
35
37
|
readonly plus: readonly ["M12 5v14M5 12h14"];
|
|
36
38
|
readonly minus: readonly ["M5 12h14"];
|
|
37
39
|
readonly x: readonly ["M18 6 6 18M6 6l12 12"];
|
package/dist/sections/icons.js
CHANGED
|
@@ -37,6 +37,10 @@ export const ICONS = {
|
|
|
37
37
|
camera: ["M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z", "M12 17a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"],
|
|
38
38
|
play: ["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z", "m10 8 6 4-6 4z"],
|
|
39
39
|
"arrow-right": ["M5 12h14M12 5l7 7-7 7"],
|
|
40
|
+
// A phone's menu button: three lines.
|
|
41
|
+
menu: ["M4 6h16M4 12h16M4 18h16"],
|
|
42
|
+
// A four-point star (a mark beside a link, a divider): drawn as a line like the others, solid with fill-current.
|
|
43
|
+
"star-four": ["M12 2C13.03 7.97 16.03 10.97 22 12C16.03 13.03 13.03 16.03 12 22C10.97 16.03 7.97 13.03 2 12C7.97 10.97 10.97 7.97 12 2Z"],
|
|
40
44
|
plus: ["M12 5v14M5 12h14"],
|
|
41
45
|
minus: ["M5 12h14"],
|
|
42
46
|
x: ["M18 6 6 18M6 6l12 12"],
|
package/dist/sections/index.d.ts
CHANGED
|
@@ -51,22 +51,22 @@ export declare const parts: {
|
|
|
51
51
|
readonly heading: z.ZodObject<{
|
|
52
52
|
text: z.ZodString;
|
|
53
53
|
size: z.ZodDefault<z.ZodEnum<{
|
|
54
|
-
display: "display";
|
|
55
54
|
small: "small";
|
|
55
|
+
display: "display";
|
|
56
56
|
medium: "medium";
|
|
57
57
|
large: "large";
|
|
58
58
|
page: "page";
|
|
59
59
|
}>>;
|
|
60
60
|
font: z.ZodOptional<z.ZodEnum<{
|
|
61
|
-
heading: "heading";
|
|
62
61
|
text: "text";
|
|
62
|
+
heading: "heading";
|
|
63
63
|
}>>;
|
|
64
64
|
}, z.core.$strip>;
|
|
65
65
|
readonly text: z.ZodObject<{
|
|
66
66
|
text: z.ZodString;
|
|
67
67
|
font: z.ZodOptional<z.ZodEnum<{
|
|
68
|
-
heading: "heading";
|
|
69
68
|
text: "text";
|
|
69
|
+
heading: "heading";
|
|
70
70
|
}>>;
|
|
71
71
|
}, z.core.$strip>;
|
|
72
72
|
readonly photo: z.ZodObject<{
|
|
@@ -101,8 +101,8 @@ export declare const parts: {
|
|
|
101
101
|
text: z.ZodOptional<z.ZodString>;
|
|
102
102
|
}, z.core.$strip>>;
|
|
103
103
|
font: z.ZodOptional<z.ZodEnum<{
|
|
104
|
-
heading: "heading";
|
|
105
104
|
text: "text";
|
|
105
|
+
heading: "heading";
|
|
106
106
|
}>>;
|
|
107
107
|
numbered: z.ZodDefault<z.ZodBoolean>;
|
|
108
108
|
lines: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -111,8 +111,8 @@ export declare const parts: {
|
|
|
111
111
|
text: z.ZodString;
|
|
112
112
|
who: z.ZodOptional<z.ZodString>;
|
|
113
113
|
font: z.ZodOptional<z.ZodEnum<{
|
|
114
|
-
heading: "heading";
|
|
115
114
|
text: "text";
|
|
115
|
+
heading: "heading";
|
|
116
116
|
}>>;
|
|
117
117
|
}, z.core.$strip>;
|
|
118
118
|
readonly stats: z.ZodObject<{
|
|
@@ -163,15 +163,18 @@ export declare const parts: {
|
|
|
163
163
|
}, z.core.$strip>;
|
|
164
164
|
readonly icon: z.ZodObject<{
|
|
165
165
|
name: z.ZodEnum<{
|
|
166
|
-
card: "card";
|
|
167
|
-
check: "check";
|
|
168
|
-
phone: "phone";
|
|
169
166
|
file: "file";
|
|
170
|
-
|
|
171
|
-
play: "play";
|
|
172
|
-
x: "x";
|
|
167
|
+
check: "check";
|
|
173
168
|
search: "search";
|
|
174
169
|
link: "link";
|
|
170
|
+
tag: "tag";
|
|
171
|
+
menu: "menu";
|
|
172
|
+
play: "play";
|
|
173
|
+
x: "x";
|
|
174
|
+
card: "card";
|
|
175
|
+
phone: "phone";
|
|
176
|
+
home: "home";
|
|
177
|
+
list: "list";
|
|
175
178
|
calendar: "calendar";
|
|
176
179
|
clock: "clock";
|
|
177
180
|
users: "users";
|
|
@@ -196,13 +199,12 @@ export declare const parts: {
|
|
|
196
199
|
globe: "globe";
|
|
197
200
|
camera: "camera";
|
|
198
201
|
"arrow-right": "arrow-right";
|
|
202
|
+
"star-four": "star-four";
|
|
199
203
|
plus: "plus";
|
|
200
204
|
minus: "minus";
|
|
201
205
|
info: "info";
|
|
202
206
|
warning: "warning";
|
|
203
|
-
list: "list";
|
|
204
207
|
grid: "grid";
|
|
205
|
-
tag: "tag";
|
|
206
208
|
award: "award";
|
|
207
209
|
}>;
|
|
208
210
|
size: z.ZodDefault<z.ZodEnum<{
|
|
@@ -241,10 +243,10 @@ export declare const own: z.ZodObject<{
|
|
|
241
243
|
center: "center";
|
|
242
244
|
}>>;
|
|
243
245
|
tone: z.ZodDefault<z.ZodEnum<{
|
|
246
|
+
dark: "dark";
|
|
244
247
|
soft: "soft";
|
|
245
248
|
plain: "plain";
|
|
246
249
|
brand: "brand";
|
|
247
|
-
dark: "dark";
|
|
248
250
|
}>>;
|
|
249
251
|
shape: z.ZodDefault<z.ZodEnum<{
|
|
250
252
|
card: "card";
|
|
@@ -270,7 +272,11 @@ export declare const own: z.ZodObject<{
|
|
|
270
272
|
parts: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>, ...z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>[]], "type">>;
|
|
271
273
|
}, z.core.$strip>>;
|
|
272
274
|
}, z.core.$strip>;
|
|
273
|
-
/**
|
|
275
|
+
/**
|
|
276
|
+
* Every section the kit draws, by the type a block names. `built`: a tree of elements styled with
|
|
277
|
+
* Tailwind, made in CalOS's editor or by Cal (../tree, cal-os docs/design/site-builder.md); `use`:
|
|
278
|
+
* one of the site's components (a tree kept once in the content's `components`) with its slots filled.
|
|
279
|
+
*/
|
|
274
280
|
export declare const sections: {
|
|
275
281
|
readonly gallery: z.ZodObject<{
|
|
276
282
|
heading: z.ZodOptional<z.ZodString>;
|
|
@@ -322,10 +328,10 @@ export declare const sections: {
|
|
|
322
328
|
center: "center";
|
|
323
329
|
}>>;
|
|
324
330
|
tone: z.ZodDefault<z.ZodEnum<{
|
|
331
|
+
dark: "dark";
|
|
325
332
|
soft: "soft";
|
|
326
333
|
plain: "plain";
|
|
327
334
|
brand: "brand";
|
|
328
|
-
dark: "dark";
|
|
329
335
|
}>>;
|
|
330
336
|
shape: z.ZodDefault<z.ZodEnum<{
|
|
331
337
|
card: "card";
|
|
@@ -351,6 +357,22 @@ export declare const sections: {
|
|
|
351
357
|
parts: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>, ...z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>[]], "type">>;
|
|
352
358
|
}, z.core.$strip>>;
|
|
353
359
|
}, z.core.$strip>;
|
|
360
|
+
readonly built: z.ZodObject<{
|
|
361
|
+
name: z.ZodOptional<z.ZodString>;
|
|
362
|
+
root: z.ZodType<import("../tree/index.ts").Node, unknown, z.core.$ZodTypeInternals<import("../tree/index.ts").Node, unknown>>;
|
|
363
|
+
}, z.core.$strip>;
|
|
364
|
+
readonly use: z.ZodObject<{
|
|
365
|
+
component: z.ZodString;
|
|
366
|
+
slots: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
367
|
+
text: z.ZodOptional<z.ZodString>;
|
|
368
|
+
href: z.ZodOptional<z.ZodString>;
|
|
369
|
+
image: z.ZodOptional<z.ZodObject<{
|
|
370
|
+
src: z.ZodString;
|
|
371
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
372
|
+
phoneSrc: z.ZodOptional<z.ZodString>;
|
|
373
|
+
}, z.core.$strip>>;
|
|
374
|
+
}, z.core.$strip>>>;
|
|
375
|
+
}, z.core.$strip>;
|
|
354
376
|
};
|
|
355
377
|
export type KitSectionType = keyof typeof sections;
|
|
356
378
|
export declare const isKitSection: (type: string) => type is KitSectionType;
|
package/dist/sections/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { buttonStyleName } from "../content/look.js";
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { href, image, md, text } from "../content/index.js";
|
|
8
8
|
import { ICON_NAMES } from "./icons.js";
|
|
9
|
+
import { built, use } from "../tree/index.js";
|
|
9
10
|
export { ICON_NAMES, ICONS } from "./icons.js";
|
|
10
11
|
/** Photos in a grid, each with a caption if it has one: their work, the place, the team at it. */
|
|
11
12
|
export const gallery = z
|
|
@@ -183,8 +184,12 @@ export const own = z
|
|
|
183
184
|
.meta({ title: "Columns' parts" }),
|
|
184
185
|
})
|
|
185
186
|
.meta({ title: "Your own section", description: "Put together from headings, text, photos, buttons and more, in the site's design" });
|
|
186
|
-
/**
|
|
187
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Every section the kit draws, by the type a block names. `built`: a tree of elements styled with
|
|
189
|
+
* Tailwind, made in CalOS's editor or by Cal (../tree, cal-os docs/design/site-builder.md); `use`:
|
|
190
|
+
* one of the site's components (a tree kept once in the content's `components`) with its slots filled.
|
|
191
|
+
*/
|
|
192
|
+
export const sections = { gallery, slideshow, own, built, use };
|
|
188
193
|
export const isKitSection = (type) => Object.prototype.hasOwnProperty.call(sections, type);
|
|
189
194
|
/** Ready-made sections of the business's own, to add and then edit like any other (./presets.ts). */
|
|
190
195
|
export { presets } from "./presets.js";
|
package/dist/sections.css
CHANGED
|
@@ -1575,3 +1575,327 @@
|
|
|
1575
1575
|
.kit-btn:hover {
|
|
1576
1576
|
filter: brightness(0.94);
|
|
1577
1577
|
}
|
|
1578
|
+
|
|
1579
|
+
/*
|
|
1580
|
+
* Built sections (./next/built.tsx): their looks are their own Tailwind classes, in the CSS made for
|
|
1581
|
+
* them at build (./built/css.ts). Here only what the kit draws around them: an icon's size until its
|
|
1582
|
+
* classes say otherwise, and what each behavior needs. Without scripting, a behavior's content is
|
|
1583
|
+
* simply there: a carousel's first slide (no controls), every tab's panel (no tabs), every accordion
|
|
1584
|
+
* item open, a marquee's row still and scrollable, everything revealed.
|
|
1585
|
+
*/
|
|
1586
|
+
:where(.kit-built-icon) {
|
|
1587
|
+
display: inline-block;
|
|
1588
|
+
flex-shrink: 0;
|
|
1589
|
+
width: 1em;
|
|
1590
|
+
height: 1em;
|
|
1591
|
+
vertical-align: -0.125em;
|
|
1592
|
+
}
|
|
1593
|
+
/* A component used that the site doesn't have (in CalOS's preview only): a quiet box where it goes. */
|
|
1594
|
+
.kit-built-missing {
|
|
1595
|
+
min-height: 120px;
|
|
1596
|
+
margin: 16px var(--look-gutter, 20px);
|
|
1597
|
+
border: 1px dashed var(--look-line, #ddd);
|
|
1598
|
+
border-radius: var(--look-radius, 8px);
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
/*
|
|
1602
|
+
* Inside a built section (a tree styled with Tailwind) an element starts plain, as Tailwind's own
|
|
1603
|
+
* reset has it: a link takes the words' colour with no underline, words and lists have no margins and
|
|
1604
|
+
* no bullets, so what it looks like is what its classes say, not the site's own styles for its pages.
|
|
1605
|
+
* Each rule is as strong as one class (:is with a class that's never used), so it beats the site's
|
|
1606
|
+
* rules for a tag (a, p) and any class of the tree, drawn after it, beats it.
|
|
1607
|
+
*/
|
|
1608
|
+
:where([data-kit-built]) :is(a, .kit-plain) {
|
|
1609
|
+
color: inherit;
|
|
1610
|
+
text-decoration: inherit;
|
|
1611
|
+
}
|
|
1612
|
+
:where([data-kit-built]) :is(h1, h2, h3, h4, h5, h6, p, blockquote, figure, ul, ol, dl, dd, .kit-plain) {
|
|
1613
|
+
margin: 0;
|
|
1614
|
+
}
|
|
1615
|
+
:where([data-kit-built]) :is(ul, ol, .kit-plain) {
|
|
1616
|
+
list-style: none;
|
|
1617
|
+
padding: 0;
|
|
1618
|
+
}
|
|
1619
|
+
:where([data-kit-built]) :is(button, .kit-plain) {
|
|
1620
|
+
font: inherit;
|
|
1621
|
+
color: inherit;
|
|
1622
|
+
background: none;
|
|
1623
|
+
border: 0;
|
|
1624
|
+
padding: 0;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
/* Carousel: the slides stacked in one place, the one showing faded in; or side by side, moved along. */
|
|
1628
|
+
:where([data-kit-behavior="carousel"] > [data-kit-track]) {
|
|
1629
|
+
display: grid;
|
|
1630
|
+
}
|
|
1631
|
+
:where([data-kit-track][data-kit-transition="fade"] > [data-kit-slide]) {
|
|
1632
|
+
grid-area: 1 / 1;
|
|
1633
|
+
transition:
|
|
1634
|
+
opacity 0.6s ease,
|
|
1635
|
+
visibility 0.6s;
|
|
1636
|
+
}
|
|
1637
|
+
[data-kit-track][data-kit-transition="fade"] > [data-kit-slide]:not([data-active]) {
|
|
1638
|
+
opacity: 0;
|
|
1639
|
+
visibility: hidden;
|
|
1640
|
+
}
|
|
1641
|
+
[data-kit-track][data-kit-transition="slide"] {
|
|
1642
|
+
display: flex;
|
|
1643
|
+
overflow: hidden;
|
|
1644
|
+
}
|
|
1645
|
+
:where([data-kit-track][data-kit-transition="slide"] > [data-kit-slide]) {
|
|
1646
|
+
flex: 0 0 100%;
|
|
1647
|
+
min-width: 0;
|
|
1648
|
+
transition:
|
|
1649
|
+
transform 0.5s ease,
|
|
1650
|
+
visibility 0.5s;
|
|
1651
|
+
}
|
|
1652
|
+
[data-kit-track][data-kit-transition="slide"] > [data-kit-slide]:not([data-active]) {
|
|
1653
|
+
visibility: hidden;
|
|
1654
|
+
}
|
|
1655
|
+
[data-kit-behavior="carousel"]:not([data-kit-ready]) > [data-kit-track] > [data-kit-slide]:not([data-active]) {
|
|
1656
|
+
display: none;
|
|
1657
|
+
}
|
|
1658
|
+
[data-kit-behavior="carousel"]:not([data-kit-ready]) :is([data-kit-to], [data-kit-prev], [data-kit-next], [data-kit-pause], .kit-carousel-controls) {
|
|
1659
|
+
display: none;
|
|
1660
|
+
}
|
|
1661
|
+
.kit-carousel-controls {
|
|
1662
|
+
display: flex;
|
|
1663
|
+
align-items: center;
|
|
1664
|
+
justify-content: center;
|
|
1665
|
+
gap: 4px;
|
|
1666
|
+
margin-top: 16px;
|
|
1667
|
+
}
|
|
1668
|
+
/* A dot is a 24px target, the dot drawn small inside it. */
|
|
1669
|
+
.kit-carousel-dot {
|
|
1670
|
+
display: grid;
|
|
1671
|
+
place-items: center;
|
|
1672
|
+
width: 24px;
|
|
1673
|
+
height: 24px;
|
|
1674
|
+
border: 0;
|
|
1675
|
+
padding: 0;
|
|
1676
|
+
background: none;
|
|
1677
|
+
color: inherit;
|
|
1678
|
+
cursor: pointer;
|
|
1679
|
+
}
|
|
1680
|
+
.kit-carousel-dot::before {
|
|
1681
|
+
content: "";
|
|
1682
|
+
width: 8px;
|
|
1683
|
+
height: 8px;
|
|
1684
|
+
border-radius: 999px;
|
|
1685
|
+
background: currentColor;
|
|
1686
|
+
opacity: 0.3;
|
|
1687
|
+
}
|
|
1688
|
+
.kit-carousel-dot[aria-current="true"]::before {
|
|
1689
|
+
opacity: 1;
|
|
1690
|
+
}
|
|
1691
|
+
.kit-carousel-arrow,
|
|
1692
|
+
.kit-carousel-pause {
|
|
1693
|
+
display: grid;
|
|
1694
|
+
place-items: center;
|
|
1695
|
+
width: 36px;
|
|
1696
|
+
height: 36px;
|
|
1697
|
+
border: 1px solid var(--look-line, color-mix(in srgb, currentColor 18%, transparent));
|
|
1698
|
+
border-radius: 999px;
|
|
1699
|
+
padding: 0;
|
|
1700
|
+
background: none;
|
|
1701
|
+
color: inherit;
|
|
1702
|
+
cursor: pointer;
|
|
1703
|
+
}
|
|
1704
|
+
.kit-carousel-prev svg {
|
|
1705
|
+
transform: scaleX(-1);
|
|
1706
|
+
}
|
|
1707
|
+
/* Pause: two bars; stopped, a play triangle. */
|
|
1708
|
+
.kit-carousel-pause span {
|
|
1709
|
+
width: 10px;
|
|
1710
|
+
height: 12px;
|
|
1711
|
+
border-inline: 3px solid currentColor;
|
|
1712
|
+
}
|
|
1713
|
+
.kit-carousel-pause[data-stopped] span {
|
|
1714
|
+
width: 0;
|
|
1715
|
+
height: 0;
|
|
1716
|
+
border-inline: 0;
|
|
1717
|
+
border-left: 10px solid currentColor;
|
|
1718
|
+
border-block: 6px solid transparent;
|
|
1719
|
+
margin-left: 3px;
|
|
1720
|
+
}
|
|
1721
|
+
:is(.kit-carousel-dot, .kit-carousel-arrow, .kit-carousel-pause):focus-visible {
|
|
1722
|
+
outline: 2px solid currentColor;
|
|
1723
|
+
outline-offset: 2px;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
/* A design's own stop button (a carousel's pause slot): the same bars, then a play triangle, in whatever box it draws. */
|
|
1727
|
+
[data-kit-pause-icon] {
|
|
1728
|
+
display: block;
|
|
1729
|
+
width: 10px;
|
|
1730
|
+
height: 12px;
|
|
1731
|
+
border-inline: 3px solid currentColor;
|
|
1732
|
+
}
|
|
1733
|
+
[data-kit-pause][data-stopped] [data-kit-pause-icon] {
|
|
1734
|
+
width: 0;
|
|
1735
|
+
height: 0;
|
|
1736
|
+
border-inline: 0;
|
|
1737
|
+
border-left: 10px solid currentColor;
|
|
1738
|
+
border-block: 6px solid transparent;
|
|
1739
|
+
margin-left: 3px;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
/* A built form's spam trap: off-screen for people (and screen readers), there for bots that fill every box. */
|
|
1743
|
+
.kit-trap {
|
|
1744
|
+
position: absolute !important;
|
|
1745
|
+
left: -10000px !important;
|
|
1746
|
+
width: 1px;
|
|
1747
|
+
height: 1px;
|
|
1748
|
+
overflow: hidden;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
/* A filter's items not chosen: hidden, whatever their own classes say. */
|
|
1752
|
+
[data-kit-behavior="filter"] [data-kit-filter-value][hidden] {
|
|
1753
|
+
display: none !important;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
/* Tabs and accordions: what isn't chosen is hidden, whatever its own classes say. */
|
|
1757
|
+
[data-kit-behavior="tabs"]:not([data-kit-ready]) > [data-kit-tablist] {
|
|
1758
|
+
display: none;
|
|
1759
|
+
}
|
|
1760
|
+
[data-kit-behavior="tabs"] > [data-kit-panel][hidden],
|
|
1761
|
+
[data-kit-behavior="accordion"] > [data-kit-item] > [data-kit-body][hidden] {
|
|
1762
|
+
display: none;
|
|
1763
|
+
}
|
|
1764
|
+
[data-kit-behavior="tabs"][data-kit-ready] > [data-kit-tablist] > *,
|
|
1765
|
+
[data-kit-behavior="accordion"][data-kit-ready] > [data-kit-item] > [data-kit-head] {
|
|
1766
|
+
cursor: pointer;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/* Marquee: its row twice, moved by one row's width, again and again; still, it can be scrolled. */
|
|
1770
|
+
[data-kit-behavior="marquee"] {
|
|
1771
|
+
overflow-x: auto;
|
|
1772
|
+
}
|
|
1773
|
+
[data-kit-behavior="marquee"][data-kit-ready] {
|
|
1774
|
+
overflow: hidden;
|
|
1775
|
+
}
|
|
1776
|
+
.kit-marquee-track {
|
|
1777
|
+
display: flex;
|
|
1778
|
+
width: max-content;
|
|
1779
|
+
gap: inherit;
|
|
1780
|
+
align-items: inherit;
|
|
1781
|
+
}
|
|
1782
|
+
.kit-marquee-group {
|
|
1783
|
+
display: flex;
|
|
1784
|
+
flex-shrink: 0;
|
|
1785
|
+
gap: inherit;
|
|
1786
|
+
align-items: inherit;
|
|
1787
|
+
}
|
|
1788
|
+
[data-kit-behavior="marquee"]:not([data-kit-ready]) [data-kit-copy] {
|
|
1789
|
+
display: none;
|
|
1790
|
+
}
|
|
1791
|
+
@keyframes kit-marquee {
|
|
1792
|
+
to {
|
|
1793
|
+
transform: translateX(calc(-1 * var(--kit-marquee-shift, 50%)));
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
/* Reveal: from below, a side, small or faded, as it's scrolled to; its children one after another where it staggers them. */
|
|
1798
|
+
[data-kit-effect="up"] {
|
|
1799
|
+
--kit-reveal-from: translateY(24px);
|
|
1800
|
+
}
|
|
1801
|
+
[data-kit-effect="left"] {
|
|
1802
|
+
--kit-reveal-from: translateX(-24px);
|
|
1803
|
+
}
|
|
1804
|
+
[data-kit-effect="right"] {
|
|
1805
|
+
--kit-reveal-from: translateX(24px);
|
|
1806
|
+
}
|
|
1807
|
+
[data-kit-effect="zoom"] {
|
|
1808
|
+
--kit-reveal-from: scale(0.96);
|
|
1809
|
+
}
|
|
1810
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1811
|
+
[data-kit-behavior="marquee"][data-kit-ready] > .kit-marquee-track {
|
|
1812
|
+
animation: kit-marquee var(--kit-marquee-seconds, 30s) linear infinite;
|
|
1813
|
+
}
|
|
1814
|
+
[data-kit-behavior="marquee"][data-kit-reverse] > .kit-marquee-track {
|
|
1815
|
+
animation-direction: reverse;
|
|
1816
|
+
}
|
|
1817
|
+
[data-kit-behavior="marquee"][data-kit-ready]:is(:hover, :focus-within) > .kit-marquee-track {
|
|
1818
|
+
animation-play-state: paused;
|
|
1819
|
+
}
|
|
1820
|
+
[data-kit-behavior="reveal"][data-kit-ready]:not([data-kit-stagger]),
|
|
1821
|
+
[data-kit-behavior="reveal"][data-kit-ready][data-kit-stagger] > * {
|
|
1822
|
+
transition:
|
|
1823
|
+
opacity 0.7s ease,
|
|
1824
|
+
transform 0.7s ease;
|
|
1825
|
+
}
|
|
1826
|
+
[data-kit-behavior="reveal"][data-kit-ready]:not([data-kit-shown]):not([data-kit-stagger]),
|
|
1827
|
+
[data-kit-behavior="reveal"][data-kit-ready][data-kit-stagger]:not([data-kit-shown]) > * {
|
|
1828
|
+
opacity: 0;
|
|
1829
|
+
transform: var(--kit-reveal-from, none);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
@media print {
|
|
1833
|
+
[data-kit-behavior="reveal"] > *,
|
|
1834
|
+
[data-kit-behavior="reveal"] {
|
|
1835
|
+
opacity: 1 !important;
|
|
1836
|
+
transform: none !important;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/* The cookie banner (the site's consent setting): over the page, along an edge or in a corner, until a choice is made. */
|
|
1841
|
+
.kit-consent {
|
|
1842
|
+
position: fixed;
|
|
1843
|
+
z-index: 60;
|
|
1844
|
+
inset-inline: 0;
|
|
1845
|
+
bottom: 0;
|
|
1846
|
+
padding: 12px var(--look-gutter, 20px);
|
|
1847
|
+
}
|
|
1848
|
+
.kit-consent[hidden] {
|
|
1849
|
+
display: none;
|
|
1850
|
+
}
|
|
1851
|
+
.kit-consent-top {
|
|
1852
|
+
top: 0;
|
|
1853
|
+
bottom: auto;
|
|
1854
|
+
}
|
|
1855
|
+
.kit-consent-bottom-left,
|
|
1856
|
+
.kit-consent-bottom-right {
|
|
1857
|
+
inset-inline: auto;
|
|
1858
|
+
max-width: min(420px, 100% - 24px);
|
|
1859
|
+
padding: 12px;
|
|
1860
|
+
}
|
|
1861
|
+
.kit-consent-bottom-left {
|
|
1862
|
+
left: 0;
|
|
1863
|
+
}
|
|
1864
|
+
.kit-consent-bottom-right {
|
|
1865
|
+
right: 0;
|
|
1866
|
+
}
|
|
1867
|
+
.kit-consent-box {
|
|
1868
|
+
display: flex;
|
|
1869
|
+
flex-wrap: wrap;
|
|
1870
|
+
align-items: center;
|
|
1871
|
+
justify-content: space-between;
|
|
1872
|
+
gap: 12px 24px;
|
|
1873
|
+
max-width: var(--look-width, 1200px);
|
|
1874
|
+
margin-inline: auto;
|
|
1875
|
+
padding: 16px 20px;
|
|
1876
|
+
border: 1px solid var(--look-line, #ddd);
|
|
1877
|
+
border-radius: var(--look-radius, 8px);
|
|
1878
|
+
background: var(--look-page, #fff);
|
|
1879
|
+
color: var(--look-ink, #111);
|
|
1880
|
+
box-shadow: 0 8px 30px rgb(0 0 0 / 0.12);
|
|
1881
|
+
}
|
|
1882
|
+
.kit-consent-text {
|
|
1883
|
+
flex: 1 1 280px;
|
|
1884
|
+
font-size: var(--look-type-small-size, 14px);
|
|
1885
|
+
}
|
|
1886
|
+
.kit-consent-text > :first-child {
|
|
1887
|
+
margin-top: 0;
|
|
1888
|
+
}
|
|
1889
|
+
.kit-consent-text > :last-child {
|
|
1890
|
+
margin-bottom: 0;
|
|
1891
|
+
}
|
|
1892
|
+
.kit-consent-actions {
|
|
1893
|
+
display: flex;
|
|
1894
|
+
flex-wrap: wrap;
|
|
1895
|
+
align-items: center;
|
|
1896
|
+
gap: 8px 12px;
|
|
1897
|
+
}
|
|
1898
|
+
.kit-consent-policy {
|
|
1899
|
+
font-size: var(--look-type-small-size, 14px);
|
|
1900
|
+
color: inherit;
|
|
1901
|
+
}
|
package/dist/seo.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// What search engines and browsers read about a site besides its words: the structured data
|
|
2
2
|
// (schema.org) describing the business, robots.txt, and the files Cloudflare Pages reads for
|
|
3
3
|
// response headers and redirects. Everything here is worked out from the site's content.
|
|
4
|
+
import { allPages } from "./content/lists.js";
|
|
4
5
|
import { clock } from "./content/index.js";
|
|
5
6
|
/** The page's address as search engines should know it. */
|
|
6
7
|
export function canonical(site, path) {
|
|
@@ -96,7 +97,7 @@ export function robotsTxt(site) {
|
|
|
96
97
|
}
|
|
97
98
|
/** Every page search engines should list, at its canonical address. */
|
|
98
99
|
export function sitemapXml(site) {
|
|
99
|
-
const urls = site.
|
|
100
|
+
const urls = allPages(site).filter((p) => !p.noindex).map((p) => ` <url><loc>${canonical(site, p.path)}</loc></url>`);
|
|
100
101
|
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls.join("\n")}\n</urlset>\n`;
|
|
101
102
|
}
|
|
102
103
|
/** Where CalOS's preview draws a draft (./next/preview.tsx): framed by CalOS, never indexed. */
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const BEHAVIORS: readonly ["carousel", "tabs", "accordion", "marquee", "reveal", "count-up", "sticky", "filter"];
|
|
3
|
+
export type BehaviorName = (typeof BEHAVIORS)[number];
|
|
4
|
+
/**
|
|
5
|
+
* The settings of each. `slides` and the like name which children are the moving parts: by default a
|
|
6
|
+
* carousel's slides are its node's children; `controls` lets a carousel's dots and arrows be drawn
|
|
7
|
+
* from its own design (nodes marked with a `slot`: "prev", "next", "dots").
|
|
8
|
+
*/
|
|
9
|
+
export declare const behavior: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
10
|
+
name: z.ZodLiteral<"carousel">;
|
|
11
|
+
seconds: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
transition: z.ZodDefault<z.ZodEnum<{
|
|
13
|
+
fade: "fade";
|
|
14
|
+
slide: "slide";
|
|
15
|
+
}>>;
|
|
16
|
+
pauseOnHover: z.ZodDefault<z.ZodBoolean>;
|
|
17
|
+
dots: z.ZodDefault<z.ZodBoolean>;
|
|
18
|
+
arrows: z.ZodDefault<z.ZodBoolean>;
|
|
19
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
20
|
+
name: z.ZodLiteral<"tabs">;
|
|
21
|
+
first: z.ZodDefault<z.ZodNumber>;
|
|
22
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
23
|
+
name: z.ZodLiteral<"accordion">;
|
|
24
|
+
single: z.ZodDefault<z.ZodBoolean>;
|
|
25
|
+
open: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
27
|
+
name: z.ZodLiteral<"marquee">;
|
|
28
|
+
seconds: z.ZodDefault<z.ZodNumber>;
|
|
29
|
+
reverse: z.ZodDefault<z.ZodBoolean>;
|
|
30
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
31
|
+
name: z.ZodLiteral<"reveal">;
|
|
32
|
+
effect: z.ZodDefault<z.ZodEnum<{
|
|
33
|
+
fade: "fade";
|
|
34
|
+
up: "up";
|
|
35
|
+
left: "left";
|
|
36
|
+
right: "right";
|
|
37
|
+
zoom: "zoom";
|
|
38
|
+
}>>;
|
|
39
|
+
stagger: z.ZodDefault<z.ZodNumber>;
|
|
40
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
41
|
+
name: z.ZodLiteral<"count-up">;
|
|
42
|
+
seconds: z.ZodDefault<z.ZodNumber>;
|
|
43
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
44
|
+
name: z.ZodLiteral<"filter">;
|
|
45
|
+
field: z.ZodString;
|
|
46
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
47
|
+
name: z.ZodLiteral<"sticky">;
|
|
48
|
+
top: z.ZodDefault<z.ZodNumber>;
|
|
49
|
+
}, z.core.$strip>], "name">;
|
|
50
|
+
export type Behavior = z.infer<typeof behavior>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// What a built section's elements can do beyond being drawn: the kit's own small scripts, chosen by
|
|
2
|
+
// name with settings, never written by a business. Visitors get static HTML; a behavior adds its
|
|
3
|
+
// script only on a page that uses it, and does nothing harmful where scripting is off (the first
|
|
4
|
+
// slide shown, every accordion item readable).
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
export const BEHAVIORS = ["carousel", "tabs", "accordion", "marquee", "reveal", "count-up", "sticky", "filter"];
|
|
7
|
+
/**
|
|
8
|
+
* The settings of each. `slides` and the like name which children are the moving parts: by default a
|
|
9
|
+
* carousel's slides are its node's children; `controls` lets a carousel's dots and arrows be drawn
|
|
10
|
+
* from its own design (nodes marked with a `slot`: "prev", "next", "dots").
|
|
11
|
+
*/
|
|
12
|
+
export const behavior = z.discriminatedUnion("name", [
|
|
13
|
+
z.object({
|
|
14
|
+
name: z.literal("carousel"),
|
|
15
|
+
/** Seconds on each slide; none: only on a click. Never moves for visitors who asked for less motion. */
|
|
16
|
+
seconds: z.number().int().min(2).max(30).optional(),
|
|
17
|
+
/** Fade between slides, or slide sideways. */
|
|
18
|
+
transition: z.enum(["fade", "slide"]).default("fade"),
|
|
19
|
+
/** Pauses while the pointer is over it. */
|
|
20
|
+
pauseOnHover: z.boolean().default(true),
|
|
21
|
+
/** Draws its own dots and arrows (the kit's), where the design has none marked as slots. */
|
|
22
|
+
dots: z.boolean().default(true),
|
|
23
|
+
arrows: z.boolean().default(false),
|
|
24
|
+
}),
|
|
25
|
+
z.object({
|
|
26
|
+
name: z.literal("tabs"),
|
|
27
|
+
/** The tab shown first, by its place. */
|
|
28
|
+
first: z.number().int().min(0).max(20).default(0),
|
|
29
|
+
}),
|
|
30
|
+
z.object({
|
|
31
|
+
name: z.literal("accordion"),
|
|
32
|
+
/** Only one item open at a time. */
|
|
33
|
+
single: z.boolean().default(false),
|
|
34
|
+
/** The item open at first, by its place; none: all closed. */
|
|
35
|
+
open: z.number().int().min(0).max(50).optional(),
|
|
36
|
+
}),
|
|
37
|
+
z.object({
|
|
38
|
+
name: z.literal("marquee"),
|
|
39
|
+
seconds: z.number().int().min(5).max(120).default(30),
|
|
40
|
+
reverse: z.boolean().default(false),
|
|
41
|
+
}),
|
|
42
|
+
z.object({
|
|
43
|
+
name: z.literal("reveal"),
|
|
44
|
+
/** How it comes in as it's scrolled to; nothing for visitors who asked for less motion. */
|
|
45
|
+
effect: z.enum(["fade", "up", "left", "right", "zoom"]).default("up"),
|
|
46
|
+
/** Its children one after another, this many milliseconds apart. */
|
|
47
|
+
stagger: z.number().int().min(0).max(1000).default(0),
|
|
48
|
+
}),
|
|
49
|
+
z.object({
|
|
50
|
+
name: z.literal("count-up"),
|
|
51
|
+
/** Counts up to its words' number when scrolled to. */
|
|
52
|
+
seconds: z.number().min(0.3).max(5).default(1.2),
|
|
53
|
+
}),
|
|
54
|
+
z.object({
|
|
55
|
+
name: z.literal("filter"),
|
|
56
|
+
/**
|
|
57
|
+
* The field of the list repeated inside it that its buttons choose by: each button inside it (not in
|
|
58
|
+
* an item) shows the items whose field matches its words ("Real estate" is real-estate), "All" every one.
|
|
59
|
+
*/
|
|
60
|
+
field: z.string().regex(/^[\w-]{1,60}$/),
|
|
61
|
+
}),
|
|
62
|
+
z.object({
|
|
63
|
+
name: z.literal("sticky"),
|
|
64
|
+
/** Stays this far from the top while its section scrolls past. */
|
|
65
|
+
top: z.number().int().min(0).max(400).default(0),
|
|
66
|
+
}),
|
|
67
|
+
]);
|