@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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/bin/jtk.mjs +41 -0
  4. package/docs/booking.md +164 -0
  5. package/docs/catalogue.md +459 -0
  6. package/docs/collections.md +249 -0
  7. package/docs/css.md +86 -0
  8. package/docs/gallery.md +127 -0
  9. package/docs/hero-motion.md +189 -0
  10. package/docs/kit.md +454 -0
  11. package/docs/languages.md +182 -0
  12. package/docs/lead-form.md +109 -0
  13. package/docs/pages.md +193 -0
  14. package/docs/photos.md +314 -0
  15. package/docs/scaffold.md +75 -0
  16. package/docs/shapes.md +140 -0
  17. package/docs/surface.md +187 -0
  18. package/lib/catalogue.mjs +1678 -0
  19. package/lib/codes.mjs +171 -0
  20. package/lib/create.mjs +282 -0
  21. package/package.json +16 -0
  22. package/template/astro.config.mjs +84 -0
  23. package/template/figures.mjs +122 -0
  24. package/template/gitignore +16 -0
  25. package/template/jtakeit-meta.mjs +112 -0
  26. package/template/jtk/content/index.json +38 -0
  27. package/template/jtk/design.json +24 -0
  28. package/template/markdown.mjs +36 -0
  29. package/template/package-lock.json +5320 -0
  30. package/template/package.json +26 -0
  31. package/template/specimens.mjs +46 -0
  32. package/template/src/components/Blocks.astro +151 -0
  33. package/template/src/components/BookingForm.astro +506 -0
  34. package/template/src/components/Clip.astro +155 -0
  35. package/template/src/components/Hero.astro +66 -0
  36. package/template/src/components/LeadForm.astro +347 -0
  37. package/template/src/components/OpeningHours.astro +69 -0
  38. package/template/src/components/Pile.astro +185 -0
  39. package/template/src/components/Shot.astro +472 -0
  40. package/template/src/components/gallery/Gallery.astro +381 -0
  41. package/template/src/components/gallery/galleries.ts +139 -0
  42. package/template/src/components/motion/HeroField.astro +520 -0
  43. package/template/src/components/motion/fields.ts +430 -0
  44. package/template/src/components/surface/Pattern.astro +278 -0
  45. package/template/src/components/surface/patterns.ts +187 -0
  46. package/template/src/content/blocks.ts +758 -0
  47. package/template/src/content.config.ts +19 -0
  48. package/template/src/copy/LOCALE.ts +324 -0
  49. package/template/src/data/site.ts +137 -0
  50. package/template/src/layouts/Layout.astro +282 -0
  51. package/template/src/lib/alive.ts +49 -0
  52. package/template/src/lib/entries.ts +106 -0
  53. package/template/src/lib/entryLoader.ts +315 -0
  54. package/template/src/lib/noise.ts +26 -0
  55. package/template/src/lib/page.ts +287 -0
  56. package/template/src/lib/photos.ts +168 -0
  57. package/template/src/lib/under.ts +32 -0
  58. package/template/src/lib/uploads.ts +85 -0
  59. package/template/src/pages/[...entry].astro +207 -0
  60. package/template/src/pages/[...feed].xml.ts +64 -0
  61. package/template/src/pages/index.astro +90 -0
  62. package/template/src/pages/llms.txt.ts +50 -0
  63. package/template/src/pages/privacy.astro +59 -0
  64. package/template/src/pages/robots.txt.ts +21 -0
  65. package/template/src/pages/sitemap.xml.ts +50 -0
  66. package/template/src/styles/global.css +411 -0
  67. package/template/src/styles/surface.css +375 -0
  68. package/template/tsconfig.json +5 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * The grounds a page can be printed on.
3
+ *
4
+ * Data only — no DOM, no colour. `Pattern.astro` owns the layer, the ink and
5
+ * every way it is allowed to fail; this file is what each ground actually looks
6
+ * like, which is the part worth reading on its own.
7
+ *
8
+ * ── one idea holds the whole catalogue together ─────────────────────────────
9
+ *
10
+ * **A ground is a stencil, and the ink is a token.** Nothing here names a
11
+ * colour. A stencil ground is an alpha mask over a layer painted in
12
+ * `--pattern-ink`; a drawn ground is line art stroked in `currentColor`, which
13
+ * is the same token. So a variant that changes its palette — or the studio
14
+ * bar's live accent picker — repaints the ground with it, and a ground can
15
+ * never arrive in somebody else's colour the way a shipped background image
16
+ * would.
17
+ *
18
+ * The two mechanisms exist because they do different work:
19
+ *
20
+ * STENCILS a repeating figure with no beginning and no end. CSS only:
21
+ * a mask image, no markup, no bytes past this file.
22
+ * DRAWINGS one composition that bleeds off its box. SVG, because a figure
23
+ * has a size and a place, and because strokes can draw themselves.
24
+ *
25
+ * Adding one is a row in either record. What it has to earn is a *different
26
+ * job*: another spacing of parallel lines is `rules` with different constants,
27
+ * not a seventh ground. Ask what a design could do with it that it could not do
28
+ * with the six.
29
+ *
30
+ * ── what the geometry is measured in ────────────────────────────────────────
31
+ *
32
+ * --pattern-size the figure's pitch: line spacing, tile, wavelength.
33
+ * --pattern-weight stroke weight.
34
+ *
35
+ * Both are read straight out of CSS rather than passed through here, so a
36
+ * variant can retune a ground per breakpoint — a 22px rule pitch that reads on
37
+ * a laptop is a grey wash on a phone — without touching this file.
38
+ */
39
+
40
+ import { GRAIN_TILE, GRAIN_SIZE } from '../../lib/noise';
41
+
42
+ export type Pattern = 'grain' | 'rules' | 'hatch' | 'contour' | 'construction' | 'motif';
43
+
44
+ /** Grounds drawn as a CSS mask: a repeating figure, no markup. */
45
+ export type Stencil = 'grain' | 'rules' | 'hatch';
46
+
47
+ /** Grounds drawn as SVG: one composition, in a place, able to draw itself. */
48
+ export type Drawn = Exclude<Pattern, Stencil>;
49
+
50
+ export const STENCILS: Record<Stencil, string> = {
51
+ /*
52
+ * Film grain, paper fibre, plaster. The only ground with no figure at all —
53
+ * it is texture, and its whole job is that a flat token stops reading as a
54
+ * fill. The tile is shared with the `film` photo treatment, which is why it
55
+ * lives in src/lib rather than here.
56
+ */
57
+ grain: GRAIN_TILE,
58
+
59
+ /*
60
+ * The ruled plane: ledger paper, a form, a chart. Horizontal only, on
61
+ * purpose — the square grid is the most-used background on the web and it
62
+ * reads as a designer's default rather than as the trade's own paper. A page
63
+ * that genuinely wants graph paper adds the second axis here as a second
64
+ * gradient, and says in a comment which trade asked for it.
65
+ */
66
+ rules:
67
+ 'repeating-linear-gradient(to bottom, #000 0 var(--pattern-weight), transparent var(--pattern-weight) var(--pattern-size))',
68
+
69
+ /*
70
+ * Engraved hatching: one direction, the way a burin goes. Crosshatch is
71
+ * deliberately not here — two sets at low opacity average out to a grey wash,
72
+ * which is a tint, not a texture.
73
+ */
74
+ hatch:
75
+ 'repeating-linear-gradient(48deg, #000 0 var(--pattern-weight), transparent var(--pattern-weight) var(--pattern-size))',
76
+ };
77
+
78
+ /**
79
+ * Contour lines, the way a landscape is drawn.
80
+ *
81
+ * Generated rather than hand-drawn, because forty hand-drawn curves is forty
82
+ * chances to draw two the same. The seed is a constant and the arithmetic is
83
+ * integer: the same build produces the same page, or every rebuild is a diff
84
+ * nobody asked for.
85
+ */
86
+ function contour(lines = 11, samples = 56, width = 1200, height = 800): string {
87
+ let seed = 20260825;
88
+ const rand = () => ((seed = (seed * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff);
89
+ const out: string[] = [];
90
+
91
+ for (let i = 0; i < lines; i++) {
92
+ const base = ((i + 0.6) / (lines + 0.2)) * height;
93
+ // Two waves per line, one slow and one fast, so no two lines run parallel
94
+ // for long — parallel is what makes generated contours look like a comb.
95
+ const slowAmp = 16 + rand() * 44;
96
+ const fastAmp = 6 + rand() * 22;
97
+ const slowFreq = 0.8 + rand() * 1.4;
98
+ const fastFreq = 2.4 + rand() * 2.6;
99
+ const phase = rand() * Math.PI * 2;
100
+
101
+ const points: string[] = [];
102
+ for (let s = 0; s <= samples; s++) {
103
+ const t = s / samples;
104
+ const y =
105
+ base +
106
+ Math.sin(t * Math.PI * slowFreq + phase) * slowAmp +
107
+ Math.cos(t * Math.PI * fastFreq - phase * 1.7) * fastAmp;
108
+ points.push(`${(t * width).toFixed(1)} ${y.toFixed(1)}`);
109
+ }
110
+ // pathLength="1" is what lets `draw` animate a stroke without anybody
111
+ // measuring the path by hand — see surface.md.
112
+ out.push(`<path pathLength="1" style="--i:${i}" d="M ${points.join(' L ')}"/>`);
113
+ }
114
+ return out.join('');
115
+ }
116
+
117
+ export const DRAWINGS: Record<Exclude<Drawn, 'motif'>, { viewBox: string; markup: string }> = {
118
+ contour: { viewBox: '0 0 1200 800', markup: contour() },
119
+
120
+ /*
121
+ * Setting-out: the axes, circles and dotted guides a drawing is built on
122
+ * before anything is drawn on it. It is the register of a studio that shows
123
+ * its process.
124
+ *
125
+ * **It is not anybody's signature.** The build this came from had its own
126
+ * construction geometry — the guides that particular tattooist leaves in red
127
+ * inside her own work — and that drawing is hers. This is the generic
128
+ * article: use it as furniture, and put the thing that could not move to
129
+ * another site somewhere else on the page. See surface.md, and the last
130
+ * section of shapes.md.
131
+ */
132
+ construction: {
133
+ viewBox: '0 0 1200 800',
134
+ markup: [
135
+ // The thirds, set out first, the way a stencil is.
136
+ '<line pathLength="1" style="--i:0" x1="400" y1="0" x2="400" y2="800"/>',
137
+ '<line pathLength="1" style="--i:0" x1="800" y1="0" x2="800" y2="800"/>',
138
+ '<line pathLength="1" style="--i:1" x1="0" y1="267" x2="1200" y2="267"/>',
139
+ '<line pathLength="1" style="--i:1" x1="0" y1="533" x2="1200" y2="533"/>',
140
+ // The circle the composition hangs from, and its inner ring.
141
+ '<circle pathLength="1" style="--i:2" cx="800" cy="267" r="236"/>',
142
+ '<circle pathLength="1" style="--i:3" cx="800" cy="267" r="118"/>',
143
+ // The diagonal, and the arc that answers it.
144
+ '<line pathLength="1" style="--i:3" x1="120" y1="740" x2="1080" y2="120"/>',
145
+ '<path pathLength="1" style="--i:4" stroke-dasharray="2 8" d="M 164 533 A 400 400 0 0 0 964 533"/>',
146
+ // The nodes: where the guides agree.
147
+ '<circle pathLength="1" style="--i:5" cx="400" cy="533" r="6"/>',
148
+ '<circle pathLength="1" style="--i:5" cx="800" cy="267" r="6"/>',
149
+ '<circle pathLength="1" style="--i:5" cx="400" cy="267" r="6"/>',
150
+ ].join(''),
151
+ },
152
+ };
153
+
154
+ /** In the order the reference table lists them. */
155
+ export const PATTERNS: Pattern[] = ['grain', 'rules', 'hatch', 'contour', 'construction', 'motif'];
156
+
157
+ export const isStencil = (pattern: Pattern): pattern is Stencil => pattern in STENCILS;
158
+
159
+ /**
160
+ * Per-ground starting values.
161
+ *
162
+ * Not a house style — a starting point that is *in range*. Grain wants a tile
163
+ * two hundred pixels wide and hatch wants fourteen; one shared default would
164
+ * put both in the wrong place, and a ground that arrives wrong is a ground
165
+ * somebody switches off instead of tuning. The design overrides any of them
166
+ * with a prop.
167
+ *
168
+ * `opacity` is the one to look at. These are quiet on purpose: a ground is read
169
+ * at a glance and never read *at*.
170
+ */
171
+ export const DEFAULTS: Record<Pattern, { size: string; weight: string; opacity: number }> = {
172
+ grain: { size: GRAIN_SIZE, weight: '1px', opacity: 0.09 },
173
+ rules: { size: '26px', weight: '1px', opacity: 0.07 },
174
+ hatch: { size: '14px', weight: '1px', opacity: 0.06 },
175
+ contour: { size: '100%', weight: '1px', opacity: 0.09 },
176
+ construction: { size: '100%', weight: '1px', opacity: 0.08 },
177
+ motif: { size: '96px', weight: '1px', opacity: 0.08 },
178
+ };
179
+
180
+ /**
181
+ * A `<pattern>` needs an id, two motifs on one page need two, and a build must
182
+ * produce the same document twice. A module counter is all three: it lives for
183
+ * the build rather than for the render, so it does not reset per component and
184
+ * does not reach for randomness.
185
+ */
186
+ let motifs = 0;
187
+ export const nextMotifId = (): string => `fl-motif-${(motifs += 1)}`;