@jtakeit/astro 0.1.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/LICENSE +21 -0
- package/README.md +59 -0
- package/bin/jtk.mjs +41 -0
- package/docs/booking.md +164 -0
- package/docs/catalogue.md +459 -0
- package/docs/collections.md +249 -0
- package/docs/css.md +86 -0
- package/docs/gallery.md +127 -0
- package/docs/hero-motion.md +189 -0
- package/docs/kit.md +454 -0
- package/docs/languages.md +182 -0
- package/docs/lead-form.md +109 -0
- package/docs/pages.md +193 -0
- package/docs/photos.md +314 -0
- package/docs/scaffold.md +75 -0
- package/docs/shapes.md +140 -0
- package/docs/surface.md +187 -0
- package/lib/catalogue.mjs +1678 -0
- package/lib/codes.mjs +171 -0
- package/lib/create.mjs +282 -0
- package/package.json +16 -0
- package/template/astro.config.mjs +84 -0
- package/template/figures.mjs +122 -0
- package/template/gitignore +16 -0
- package/template/jtakeit-meta.mjs +112 -0
- package/template/jtk/content/index.json +38 -0
- package/template/jtk/design.json +24 -0
- package/template/markdown.mjs +36 -0
- package/template/package-lock.json +5320 -0
- package/template/package.json +26 -0
- package/template/specimens.mjs +46 -0
- package/template/src/components/Blocks.astro +151 -0
- package/template/src/components/BookingForm.astro +506 -0
- package/template/src/components/Clip.astro +155 -0
- package/template/src/components/Hero.astro +66 -0
- package/template/src/components/LeadForm.astro +347 -0
- package/template/src/components/OpeningHours.astro +69 -0
- package/template/src/components/Pile.astro +185 -0
- package/template/src/components/Shot.astro +472 -0
- package/template/src/components/gallery/Gallery.astro +381 -0
- package/template/src/components/gallery/galleries.ts +139 -0
- package/template/src/components/motion/HeroField.astro +520 -0
- package/template/src/components/motion/fields.ts +430 -0
- package/template/src/components/surface/Pattern.astro +278 -0
- package/template/src/components/surface/patterns.ts +187 -0
- package/template/src/content/blocks.ts +758 -0
- package/template/src/content.config.ts +19 -0
- package/template/src/copy/LOCALE.ts +324 -0
- package/template/src/data/site.ts +137 -0
- package/template/src/layouts/Layout.astro +282 -0
- package/template/src/lib/alive.ts +49 -0
- package/template/src/lib/entries.ts +106 -0
- package/template/src/lib/entryLoader.ts +315 -0
- package/template/src/lib/noise.ts +26 -0
- package/template/src/lib/page.ts +287 -0
- package/template/src/lib/photos.ts +168 -0
- package/template/src/lib/under.ts +32 -0
- package/template/src/lib/uploads.ts +85 -0
- package/template/src/pages/[...entry].astro +207 -0
- package/template/src/pages/[...feed].xml.ts +64 -0
- package/template/src/pages/index.astro +90 -0
- package/template/src/pages/llms.txt.ts +50 -0
- package/template/src/pages/privacy.astro +59 -0
- package/template/src/pages/robots.txt.ts +21 -0
- package/template/src/pages/sitemap.xml.ts +50 -0
- package/template/src/styles/global.css +411 -0
- package/template/src/styles/surface.css +375 -0
- package/template/tsconfig.json +5 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Edges and entrances.
|
|
3
|
+
*
|
|
4
|
+
* Two of the three catalogues in `docs/surface.md` of @jtakeit/astro.
|
|
5
|
+
* The third — the ground a page is printed on — is a component, because it is
|
|
6
|
+
* a figure with a size and a place; these two are properties of blocks that
|
|
7
|
+
* already exist, so they are attributes rather than wrappers:
|
|
8
|
+
*
|
|
9
|
+
* <section class="band" data-edge="corners" data-reveal="wipe">
|
|
10
|
+
*
|
|
11
|
+
* Which is also why they degrade well. Delete the attribute and the block is a
|
|
12
|
+
* block; delete this file and the page still reads. Nothing here changes what a
|
|
13
|
+
* section *is*.
|
|
14
|
+
*
|
|
15
|
+
* ── the rules that stop this becoming a demo ────────────────────────────────
|
|
16
|
+
*
|
|
17
|
+
* · One reveal per page. Four different entrances is a component gallery, not
|
|
18
|
+
* a design, and it is the loudest tell that nobody chose.
|
|
19
|
+
* · Nothing in the first screen is revealed. It delays the largest paint and
|
|
20
|
+
* it shows a visitor on a slow line an empty page. `fl-check` fails on it.
|
|
21
|
+
* · An animated edge belongs to something that can be clicked. Furniture that
|
|
22
|
+
* performs is furniture being looked at instead of the words.
|
|
23
|
+
* · One continuously moving thing per page, and the hero usually already
|
|
24
|
+
* spent it.
|
|
25
|
+
*
|
|
26
|
+
* Every hidden start state hangs on `html.js`, which the layout sets before
|
|
27
|
+
* first paint — otherwise a visitor with JavaScript off is left staring at
|
|
28
|
+
* `opacity: 0` forever. `.is-in` is added by the observer in Layout.astro.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/* ── the ground's host ───────────────────────────────────────────────────────
|
|
32
|
+
*
|
|
33
|
+
* A block-scope <Pattern> sits at z-index -1: above this section's background,
|
|
34
|
+
* below its content. That only holds where the section is a stacking context,
|
|
35
|
+
* and these are the two properties that make it one. Without them the ground
|
|
36
|
+
* disappears behind the band's own colour, which looks exactly like a ground
|
|
37
|
+
* that was never added.
|
|
38
|
+
*/
|
|
39
|
+
.has-pattern {
|
|
40
|
+
position: relative;
|
|
41
|
+
isolation: isolate;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ── the hand ────────────────────────────────────────────────────────────────
|
|
45
|
+
*
|
|
46
|
+
* One element, laid down slightly off square. `--tilt` is the magnitude and it
|
|
47
|
+
* is the same everywhere on the page; this only chooses the direction.
|
|
48
|
+
*
|
|
49
|
+
* <figure class="shot" data-tilt="left">
|
|
50
|
+
*
|
|
51
|
+
* ── two things worth knowing ────────────────────────────────────────────────
|
|
52
|
+
*
|
|
53
|
+
* It is the `rotate` property, not `transform: rotate()`. They are separate
|
|
54
|
+
* properties now, which means a tilted element can still be moved by an
|
|
55
|
+
* entrance — `data-tilt="left" data-reveal="rise"` works, where a transform
|
|
56
|
+
* would have overwritten the other one and the block would arrive straight.
|
|
57
|
+
*
|
|
58
|
+
* And the rule that makes it worth anything: **the tilt is the exception.** A
|
|
59
|
+
* page tilts its pile, or its one signature card, and sets everything else
|
|
60
|
+
* square — the hand reads because the rest is a straight edge to read it
|
|
61
|
+
* against. See references/shapes.md.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
[data-tilt='left'] {
|
|
65
|
+
rotate: calc(var(--tilt) * -1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
[data-tilt='right'] {
|
|
69
|
+
rotate: var(--tilt);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* ── edges ───────────────────────────────────────────────────────────────────
|
|
73
|
+
*
|
|
74
|
+
* Drawn on a pseudo-element rather than as a border, so that adding an edge
|
|
75
|
+
* never changes a block's size and never fights the padding a design already
|
|
76
|
+
* settled. `notch` is the exception — a cut corner is the box, not a line on
|
|
77
|
+
* it.
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
[data-edge] {
|
|
81
|
+
position: relative;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
[data-edge]::after {
|
|
85
|
+
content: '';
|
|
86
|
+
position: absolute;
|
|
87
|
+
inset: 0;
|
|
88
|
+
border-radius: inherit;
|
|
89
|
+
pointer-events: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* The hairline. Everything else on this list is a departure from it. */
|
|
93
|
+
[data-edge='hairline']::after {
|
|
94
|
+
border: var(--edge-weight) solid var(--edge-ink);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Sewn, ruled, provisional. */
|
|
98
|
+
[data-edge='stitch']::after {
|
|
99
|
+
border: var(--edge-weight) dashed var(--edge-ink);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* Crop marks: the corners are drawn and the sides are not, so the block reads
|
|
104
|
+
* as registered rather than as boxed. The mask is four squares, one per corner,
|
|
105
|
+
* each revealing the two border runs that meet there.
|
|
106
|
+
*/
|
|
107
|
+
[data-edge='corners']::after {
|
|
108
|
+
border: var(--edge-weight) solid var(--edge-ink);
|
|
109
|
+
-webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), linear-gradient(#000 0 0),
|
|
110
|
+
linear-gradient(#000 0 0);
|
|
111
|
+
mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), linear-gradient(#000 0 0),
|
|
112
|
+
linear-gradient(#000 0 0);
|
|
113
|
+
-webkit-mask-size: var(--edge-corner) var(--edge-corner);
|
|
114
|
+
mask-size: var(--edge-corner) var(--edge-corner);
|
|
115
|
+
-webkit-mask-position: top left, top right, bottom left, bottom right;
|
|
116
|
+
mask-position: top left, top right, bottom left, bottom right;
|
|
117
|
+
-webkit-mask-repeat: no-repeat;
|
|
118
|
+
mask-repeat: no-repeat;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* A ticket, a label, a price tag. The cut is on the box itself, so a block with
|
|
123
|
+
* a background of its own is the one to put it on — on a transparent block
|
|
124
|
+
* there is nothing to cut.
|
|
125
|
+
*/
|
|
126
|
+
[data-edge='notch'] {
|
|
127
|
+
clip-path: polygon(
|
|
128
|
+
0 0,
|
|
129
|
+
calc(100% - var(--edge-corner)) 0,
|
|
130
|
+
100% var(--edge-corner),
|
|
131
|
+
100% 100%,
|
|
132
|
+
0 100%
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
[data-edge='notch']::after {
|
|
137
|
+
display: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Two frames, one offset from the other: a poster's register. The outer one is
|
|
142
|
+
* an outline, which sits outside the box without taking space — and which is
|
|
143
|
+
* why this belongs on blocks rather than on anything focusable, whose own focus
|
|
144
|
+
* ring is drawn the same way.
|
|
145
|
+
*/
|
|
146
|
+
[data-edge='offset'] {
|
|
147
|
+
outline: var(--edge-weight) solid var(--accent);
|
|
148
|
+
outline-offset: var(--edge-offset);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
[data-edge='offset']::after {
|
|
152
|
+
border: var(--edge-weight) solid var(--edge-ink);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
* The perimeter draws itself once, clockwise from the top. A conic gradient as
|
|
157
|
+
* a mask is the whole trick: one angle animated from nothing to a full turn
|
|
158
|
+
* reveals the border in the order a pen would draw it.
|
|
159
|
+
*
|
|
160
|
+
* Without JavaScript the border is simply there — the hidden state is under
|
|
161
|
+
* `html.js`, and the finished state is the default.
|
|
162
|
+
*/
|
|
163
|
+
@property --edge-p {
|
|
164
|
+
syntax: '<number>';
|
|
165
|
+
inherits: false;
|
|
166
|
+
initial-value: 1;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
[data-edge='trace']::after {
|
|
170
|
+
border: var(--edge-weight) solid var(--edge-ink);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
html.js [data-edge='trace']::after {
|
|
174
|
+
--edge-p: 0;
|
|
175
|
+
-webkit-mask-image: conic-gradient(#000 calc(var(--edge-p) * 1turn), transparent 0);
|
|
176
|
+
mask-image: conic-gradient(#000 calc(var(--edge-p) * 1turn), transparent 0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
html.js [data-edge='trace'].is-in::after {
|
|
180
|
+
animation: edge-trace 0.9s var(--ease) forwards;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@keyframes edge-trace {
|
|
184
|
+
to {
|
|
185
|
+
--edge-p: 1;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/*
|
|
190
|
+
* A light travelling around the edge. This is the loud one: it never stops, so
|
|
191
|
+
* it is the page's single continuous animation and it belongs on the one thing
|
|
192
|
+
* a visitor is supposed to press. `fl-check` counts them and checks what they
|
|
193
|
+
* are attached to.
|
|
194
|
+
*
|
|
195
|
+
* The ring is a conic gradient with the middle masked out — `exclude` leaves
|
|
196
|
+
* only the padding, which is the border. Under the light there is a plain ring
|
|
197
|
+
* in the edge colour: without it the block has no edge for three quarters of
|
|
198
|
+
* every turn, which reads as a border that keeps breaking.
|
|
199
|
+
*/
|
|
200
|
+
@property --edge-a {
|
|
201
|
+
syntax: '<angle>';
|
|
202
|
+
inherits: false;
|
|
203
|
+
initial-value: 0deg;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
[data-edge='sweep']::after {
|
|
207
|
+
padding: var(--edge-weight);
|
|
208
|
+
background-color: var(--edge-ink);
|
|
209
|
+
background-image: conic-gradient(
|
|
210
|
+
from var(--edge-a),
|
|
211
|
+
transparent 0 52%,
|
|
212
|
+
var(--accent) 76%,
|
|
213
|
+
transparent 90% 100%
|
|
214
|
+
);
|
|
215
|
+
-webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
|
|
216
|
+
mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
|
|
217
|
+
-webkit-mask-clip: content-box, border-box;
|
|
218
|
+
mask-clip: content-box, border-box;
|
|
219
|
+
-webkit-mask-composite: xor;
|
|
220
|
+
mask-composite: exclude;
|
|
221
|
+
animation: edge-sweep 4.5s linear infinite;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@keyframes edge-sweep {
|
|
225
|
+
to {
|
|
226
|
+
--edge-a: 360deg;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/*
|
|
231
|
+
* The card answers the hand. `focus-within` as well as hover, or the same card
|
|
232
|
+
* is dead to a keyboard.
|
|
233
|
+
*/
|
|
234
|
+
[data-edge='lift'] {
|
|
235
|
+
transition:
|
|
236
|
+
box-shadow var(--dur) var(--ease),
|
|
237
|
+
transform var(--dur) var(--ease);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
[data-edge='lift']:hover,
|
|
241
|
+
[data-edge='lift']:focus-within {
|
|
242
|
+
box-shadow: var(--shadow-2, 0 12px 34px rgb(0 0 0 / 12%));
|
|
243
|
+
transform: translateY(-2px);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
[data-edge='none']::after {
|
|
247
|
+
display: none;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ── entrances ───────────────────────────────────────────────────────────────
|
|
251
|
+
*
|
|
252
|
+
* One per page. They are not seven flavours of fade: a page of photographs
|
|
253
|
+
* wants `develop`, a list wants `stagger`, a dense page wants `settle` because
|
|
254
|
+
* travel makes a long column feel like it is bouncing.
|
|
255
|
+
*
|
|
256
|
+
* `data-reveal` with no value is `rise`, so the plain attribute keeps working
|
|
257
|
+
* wherever it was already written.
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
html.js [data-reveal=''],
|
|
261
|
+
html.js [data-reveal='rise'] {
|
|
262
|
+
opacity: 0;
|
|
263
|
+
transform: translateY(var(--reveal-dist));
|
|
264
|
+
transition:
|
|
265
|
+
opacity var(--reveal-dur) var(--ease),
|
|
266
|
+
transform var(--reveal-dur) var(--ease);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* No travel: it arrives where it already was. For pages with a lot of blocks. */
|
|
270
|
+
html.js [data-reveal='settle'] {
|
|
271
|
+
opacity: 0;
|
|
272
|
+
transform: scale(1.015);
|
|
273
|
+
transition:
|
|
274
|
+
opacity var(--reveal-dur) var(--ease),
|
|
275
|
+
transform var(--reveal-dur) var(--ease);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* A print register: the block is uncovered rather than moved. */
|
|
279
|
+
html.js [data-reveal='wipe'] {
|
|
280
|
+
clip-path: inset(0 100% 0 0);
|
|
281
|
+
transition: clip-path calc(var(--reveal-dur) * 1.2) var(--ease);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Photographic: out of focus, then not. Expensive on a large box — put it on
|
|
285
|
+
the picture, not on the section around it. */
|
|
286
|
+
html.js [data-reveal='develop'] {
|
|
287
|
+
opacity: 0;
|
|
288
|
+
filter: blur(12px) saturate(0.6);
|
|
289
|
+
transition:
|
|
290
|
+
opacity var(--reveal-dur) var(--ease),
|
|
291
|
+
filter var(--reveal-dur) var(--ease);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/*
|
|
295
|
+
* The children, in order. `--i` is set by the observer as the row enters, so a
|
|
296
|
+
* list rendered from a document does not have to carry an index into its
|
|
297
|
+
* markup — which is the version of this that gets forgotten on the second list.
|
|
298
|
+
*/
|
|
299
|
+
html.js [data-reveal='stagger'] > * {
|
|
300
|
+
opacity: 0;
|
|
301
|
+
transform: translateY(var(--reveal-dist));
|
|
302
|
+
transition:
|
|
303
|
+
opacity var(--reveal-dur) var(--ease),
|
|
304
|
+
transform var(--reveal-dur) var(--ease);
|
|
305
|
+
transition-delay: calc(var(--i, 0) * var(--reveal-step));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
html.js [data-reveal='stagger'].is-in > * {
|
|
309
|
+
opacity: 1;
|
|
310
|
+
transform: none;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/*
|
|
314
|
+
* Line art draws itself. Every figure needs `pathLength="1"`, and then one rule
|
|
315
|
+
* covers a circle, a line and a 56-point contour alike — nobody measures a path
|
|
316
|
+
* by hand, and a figure edited next month still draws.
|
|
317
|
+
*/
|
|
318
|
+
html.js [data-reveal='draw'] :is(path, line, circle, rect, polyline, ellipse) {
|
|
319
|
+
stroke-dasharray: 1;
|
|
320
|
+
stroke-dashoffset: 1;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
html.js [data-reveal='draw'].is-in :is(path, line, circle, rect, polyline, ellipse) {
|
|
324
|
+
animation: reveal-draw 1.4s var(--ease) forwards;
|
|
325
|
+
animation-delay: calc(var(--i, 0) * 180ms);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
@keyframes reveal-draw {
|
|
329
|
+
to {
|
|
330
|
+
stroke-dashoffset: 0;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
html.js [data-reveal=''].is-in,
|
|
335
|
+
html.js [data-reveal='rise'].is-in,
|
|
336
|
+
html.js [data-reveal='settle'].is-in,
|
|
337
|
+
html.js [data-reveal='develop'].is-in {
|
|
338
|
+
opacity: 1;
|
|
339
|
+
transform: none;
|
|
340
|
+
filter: none;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
html.js [data-reveal='wipe'].is-in {
|
|
344
|
+
clip-path: inset(0 0 0 0);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/*
|
|
348
|
+
* Reduced motion means the finished state, never a broken one — and never a
|
|
349
|
+
* missing one either: the drawing is complete, the block is in place, the
|
|
350
|
+
* border is closed.
|
|
351
|
+
*/
|
|
352
|
+
@media (prefers-reduced-motion: reduce) {
|
|
353
|
+
html.js [data-reveal],
|
|
354
|
+
html.js [data-reveal] > * {
|
|
355
|
+
opacity: 1;
|
|
356
|
+
transform: none;
|
|
357
|
+
filter: none;
|
|
358
|
+
clip-path: none;
|
|
359
|
+
transition: none;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
html.js [data-reveal='draw'] :is(path, line, circle, rect, polyline, ellipse) {
|
|
363
|
+
stroke-dashoffset: 0;
|
|
364
|
+
animation: none;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
html.js [data-edge='trace']::after {
|
|
368
|
+
--edge-p: 1;
|
|
369
|
+
animation: none;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
[data-edge='sweep']::after {
|
|
373
|
+
animation: none;
|
|
374
|
+
}
|
|
375
|
+
}
|