@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jtakeit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @jtakeit/astro
|
|
2
|
+
|
|
3
|
+
The scaffold and the catalogue tool for a site on [jtakeit](https://jtakeit.com) —
|
|
4
|
+
the platform's contract as a working Astro project, ready to build on.
|
|
5
|
+
|
|
6
|
+
jtakeit is an agent-driven platform for building and running websites for clients:
|
|
7
|
+
the site is written by an agent in a repository, and the platform runs the panel the
|
|
8
|
+
business owner edits it in, the enquiries and the bookings, the backups and the
|
|
9
|
+
domain. What the platform holds a repository to is small — a `jtk/catalogue.json`
|
|
10
|
+
that validates, a `data-jtk-path` on every editable field, a `dist/` from an Astro
|
|
11
|
+
build — and this package is that contract with a page already on it.
|
|
12
|
+
|
|
13
|
+
Astro is the only generator the platform builds today.
|
|
14
|
+
|
|
15
|
+
## Scaffold
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npx @jtakeit/astro create <slug> --name "The Business" --locale de-CH
|
|
19
|
+
cd <slug> && npm ci && npm run dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
You get a static Astro project: a layout, a hero, a lead form posting to `/api/lead`
|
|
23
|
+
(the platform serves it), a booking form for the platform's diary, opening hours read
|
|
24
|
+
from `jtk/bookings.json`, pages for robots, sitemap and llms.txt, and
|
|
25
|
+
`src/content/blocks.ts` — the declaration of what the owner may edit. Nothing in it
|
|
26
|
+
decides how the site looks; every component is yours to replace.
|
|
27
|
+
|
|
28
|
+
## The catalogue
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
npx @jtakeit/astro catalogue # write jtk/catalogue.json, build, check it against dist/
|
|
32
|
+
npx @jtakeit/astro catalogue --emit-only # write it and stop
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`jtk/catalogue.json` is derived from `src/content/blocks.ts` and checked against the
|
|
36
|
+
built pages in both directions: every declared field is rendered with its path, and
|
|
37
|
+
every annotated path is declared. The platform's own validator is the authority —
|
|
38
|
+
`validate_catalogue` over MCP, or `--judge` here with `JTK_API` and `JTK_TOKEN` set —
|
|
39
|
+
and this tool sits its exam.
|
|
40
|
+
|
|
41
|
+
## Then, on the platform
|
|
42
|
+
|
|
43
|
+
1. Push the repository somewhere the platform's GitHub App can reach.
|
|
44
|
+
2. `create_site`, then `attach_repo`.
|
|
45
|
+
3. `trigger_build`; `import_branch` after committing content; `publish`.
|
|
46
|
+
4. `get_preview_link` to look; the studio hands the owner's link to the client from
|
|
47
|
+
the panel.
|
|
48
|
+
|
|
49
|
+
The whole of it, with the reasons, is in [docs/](docs/): `kit.md` first, then
|
|
50
|
+
`catalogue.md`, `pages.md`, `collections.md`, `lead-form.md`, `booking.md`,
|
|
51
|
+
`photos.md`, and the rest as you need them. The platform's own reference —
|
|
52
|
+
field kinds, modules, every error code — is what the MCP server hands an agent on
|
|
53
|
+
`initialize`, and at `https://docs.jtakeit.com`.
|
|
54
|
+
|
|
55
|
+
## Not here, on purpose
|
|
56
|
+
|
|
57
|
+
No deploy: the platform builds and serves. No server code: the form and the diary
|
|
58
|
+
are the platform's endpoints beside the site. No design system: what the site looks
|
|
59
|
+
like is the point of writing it.
|
package/bin/jtk.mjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* jtk — the command line of @jtakeit/astro.
|
|
4
|
+
*
|
|
5
|
+
* jtk create <slug> … scaffold a site (lib/create.mjs)
|
|
6
|
+
* jtk catalogue … write jtk/catalogue.json and check it (lib/catalogue.mjs)
|
|
7
|
+
*/
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import { pathToFileURL } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
14
|
+
|
|
15
|
+
switch (command) {
|
|
16
|
+
case 'create': {
|
|
17
|
+
const { create } = await import(pathToFileURL(join(HERE, '..', 'lib', 'create.mjs')).href);
|
|
18
|
+
await create(rest);
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
case 'catalogue':
|
|
22
|
+
case 'catalog': {
|
|
23
|
+
process.argv = [process.argv[0], process.argv[1], ...rest];
|
|
24
|
+
await import(pathToFileURL(join(HERE, '..', 'lib', 'catalogue.mjs')).href);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
default: {
|
|
28
|
+
const { usage } = await import(pathToFileURL(join(HERE, '..', 'lib', 'create.mjs')).href);
|
|
29
|
+
console.error(`@jtakeit/astro — the scaffold and the catalogue tool for a site on jtakeit
|
|
30
|
+
|
|
31
|
+
jtk create <slug> [options] scaffold a site into ./<slug>
|
|
32
|
+
jtk catalogue [--emit-only] [--dist ./dist] [--judge]
|
|
33
|
+
write jtk/catalogue.json from src/content/blocks.ts and
|
|
34
|
+
check it against the built pages
|
|
35
|
+
|
|
36
|
+
${usage()}
|
|
37
|
+
|
|
38
|
+
The contract the platform holds this repository to is in docs/ of this package.`);
|
|
39
|
+
process.exit(command === undefined || command === '--help' || command === '-h' ? 0 : 1);
|
|
40
|
+
}
|
|
41
|
+
}
|
package/docs/booking.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# The booking form
|
|
2
|
+
|
|
3
|
+
The diary is the platform's; the page draws it. Six addresses on the site's
|
|
4
|
+
own host answer everything a visitor needs, and nothing about availability is
|
|
5
|
+
computed in the repository — which is what lets the owner change their hours
|
|
6
|
+
in the admin and have the site offer them the next minute, with no rebuild.
|
|
7
|
+
|
|
8
|
+
Template: `src/components/BookingForm.astro`. Copy it,
|
|
9
|
+
keep the script, restyle the markup. The contract in full is
|
|
10
|
+
[bookings-on-the-site](https://jtakeit.com/docs/guides/bookings-on-the-site)
|
|
11
|
+
in the platform's docs.
|
|
12
|
+
|
|
13
|
+
## Turning it on
|
|
14
|
+
|
|
15
|
+
The site's catalogue declares the module and binds two collections:
|
|
16
|
+
|
|
17
|
+
```jsonc
|
|
18
|
+
"modules": {
|
|
19
|
+
"bookings": {
|
|
20
|
+
"services": "services", // entries with `takes` (minutes) and, to be payable, `costs`
|
|
21
|
+
"resources": "masters" // entries that get occupied; one entry is a solo business
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Both are ordinary collections the owner edits in the admin — the team page and
|
|
27
|
+
the diary's masters are the **same entries**. A service entry carries `takes`
|
|
28
|
+
as a `duration` field; a master entry may carry its own weekly `hours`. The
|
|
29
|
+
business's hours, days off and confirmation mode are the module's settings
|
|
30
|
+
document, which the owner edits under the diary; the repository never holds
|
|
31
|
+
them.
|
|
32
|
+
|
|
33
|
+
## The page
|
|
34
|
+
|
|
35
|
+
```astro
|
|
36
|
+
---
|
|
37
|
+
import BookingForm from '../components/BookingForm.astro';
|
|
38
|
+
import { entries } from '../lib/entries';
|
|
39
|
+
const services = entries('services').map((e) => ({
|
|
40
|
+
slug: e.slug, title: e.title,
|
|
41
|
+
takes: e.block.takes, costs: e.block.costs, group: e.block.group, // for the checklist's total and headings
|
|
42
|
+
}));
|
|
43
|
+
const masters = entries('masters').map((e) => ({ slug: e.slug, title: e.title }));
|
|
44
|
+
const combine = bookings.blocks[0].combine === true; // jtk/bookings.json, the owner's setting
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
And `jtk/bookings.json` says **where the form is** — `"page": "/angebote"` in its
|
|
48
|
+
block — because the form is placed by a page template rather than by a block, so
|
|
49
|
+
nothing else can tell the panel which page to open when the owner presses *Try
|
|
50
|
+
booking*. Empty means the front page.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
---
|
|
54
|
+
<BookingForm services={services} resources={masters} locale="de" combine={combine} currency="CHF" />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
With `combine` on — the module's setting, the owner's to flip — the services
|
|
58
|
+
are a checklist under their `group` headings with a running total of minutes
|
|
59
|
+
and money, and the visit is booked as one: the same person, the sum of the
|
|
60
|
+
lengths, the sum of the prices. Off, the form is one choice, as it always was.
|
|
61
|
+
Only services with a `takes` belong on the form; a price-list row without one
|
|
62
|
+
is refused by the platform, so filter before passing.
|
|
63
|
+
|
|
64
|
+
Pass `resources` only when the visitor should choose; leave it out for a solo
|
|
65
|
+
business and the platform assigns. The words are the component's, per locale;
|
|
66
|
+
the page's own copy stays in `jtk/content`.
|
|
67
|
+
|
|
68
|
+
## Its look is the site's to give
|
|
69
|
+
|
|
70
|
+
The component is a reference for the flow, not a design. It ships with
|
|
71
|
+
class names — `field`, `field__input`, `booking__slot`, `booking__submit` —
|
|
72
|
+
and a minimal `<style>` that makes it legible and nothing more. **Restyle
|
|
73
|
+
it before it goes out**, the way you restyle everything else the scaffold
|
|
74
|
+
ships: the site's own field styles, the site's own buttons for the time
|
|
75
|
+
slots and the press, the site's panel around it. A booking form that looks
|
|
76
|
+
like a browser default on a page that does not is the first thing the
|
|
77
|
+
studio sees. Keep the `data-*` hooks and the input `name`s: the script is
|
|
78
|
+
wired to them.
|
|
79
|
+
|
|
80
|
+
## What the component does, in order
|
|
81
|
+
|
|
82
|
+
1. `GET /api/turnstile` — the widget's key, or `""`. With a key it renders the
|
|
83
|
+
Turnstile widget and sends the token as `turnstile`; without one it renders
|
|
84
|
+
nothing. **The site carries no key**: which widget covers a host is the
|
|
85
|
+
platform's decision, and a client's own domain is put into one the moment it
|
|
86
|
+
is attached.
|
|
87
|
+
2. `GET /api/availability?service=&from=&to=[&resource=]` — the free starts
|
|
88
|
+
for one day, as UTC instants, with the business's `zone` beside them for
|
|
89
|
+
the clock. `service` repeats for a visit of several; the platform sums the
|
|
90
|
+
lengths and offers only the resources that do all of them.
|
|
91
|
+
3. `POST /api/book` — the visitor's choice, with `services: [...]` for a visit
|
|
92
|
+
of several (`service` alone is the one-service form). `409` means the time went while
|
|
93
|
+
the page was open, and the component reloads the day. The answer carries
|
|
94
|
+
`state` (*confirmed* or *pending*), `manage_path` (the visitor's own page:
|
|
95
|
+
cancel, move, add to calendar) and `telegram_url` (reminders).
|
|
96
|
+
4. `POST /api/pay` — only when `amount_minor` is not zero. The slot is held
|
|
97
|
+
thirty minutes; the platform's Checkout page comes back to `manage_path`.
|
|
98
|
+
|
|
99
|
+
## The band it sits in
|
|
100
|
+
|
|
101
|
+
The same rule as the lead form: give it something to stand beside — the price
|
|
102
|
+
list, the opening line, the master's photograph — or let it use the width.
|
|
103
|
+
`fl-check` fails a form band that uses less than 45% of a 1920px screen.
|
|
104
|
+
|
|
105
|
+
## In the preview
|
|
106
|
+
|
|
107
|
+
The form works on the studio's preview exactly as on the live site: the
|
|
108
|
+
platform answers `/p/<slug>/api/…` behind the preview's session, against the
|
|
109
|
+
same demo. A client can book a test appointment in their own diary before they
|
|
110
|
+
have paid, which is the sale.
|
|
111
|
+
|
|
112
|
+
`manage_path` already carries the prefix on a preview — `/p/<slug>/_booking/…`
|
|
113
|
+
— and the visitor's page is served there, so the link is used as it arrives.
|
|
114
|
+
A "received" page of your own writes every address through `under()`, the
|
|
115
|
+
`/_booking/<token>` fallback included: `href="/angebote/"` on it is the one
|
|
116
|
+
link a visitor presses right after booking, and on a preview it led to "no
|
|
117
|
+
site is attached to this address".
|
|
118
|
+
|
|
119
|
+
## A record, not a post — and every fact once
|
|
120
|
+
|
|
121
|
+
What the module reads is a record the diary occupies or offers, and the panel
|
|
122
|
+
draws it as a form. Shape the two entry types for that, not for the blog:
|
|
123
|
+
|
|
124
|
+
- **A service** is short fields — `title`, `takes`, `costs`, a `group` if the
|
|
125
|
+
price list has headings, one line — with **no `body`** and **`pages: false`**
|
|
126
|
+
on the collection. It is a row of the price list the form reads, not a page.
|
|
127
|
+
- **A resource** — a master, a chair, a table, a room — is a `title` with its
|
|
128
|
+
own `hours`, what it `does`, `seats` or `spots`, a line and a photograph if
|
|
129
|
+
the page wants them. A master may have a page and a paragraph about her; a
|
|
130
|
+
billiard table with an excerpt, a cover and eight thousand characters of
|
|
131
|
+
body is the blog's shape copied without a reason.
|
|
132
|
+
|
|
133
|
+
And a fact lives once. The owner's opening hours are the module's settings,
|
|
134
|
+
which publish writes to `jtk/bookings.json`; the page reads them from there
|
|
135
|
+
(`OpeningHours.astro` below). The prices are the services' `costs`, and the
|
|
136
|
+
price list on the page is the same entries the form reads. **Never type hours
|
|
137
|
+
or prices again as text** on a page block: the copy goes stale the day the
|
|
138
|
+
owner changes the panel's.
|
|
139
|
+
|
|
140
|
+
`validate_catalogue` says both as advice — `JTK_W_MODULE_POST`,
|
|
141
|
+
`JTK_W_MODULE_TWIN` — under `advice`, refusing nothing; `jtk catalogue --judge`
|
|
142
|
+
prints them. Act on them before the first build.
|
|
143
|
+
|
|
144
|
+
### Opening hours from the module
|
|
145
|
+
|
|
146
|
+
```astro
|
|
147
|
+
---
|
|
148
|
+
import OpeningHours from '../components/OpeningHours.astro';
|
|
149
|
+
---
|
|
150
|
+
<OpeningHours locale="de" />
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`src/components/OpeningHours.astro` reads `jtk/bookings.json`
|
|
154
|
+
if it is there — a repository nobody has published yet has none, and the
|
|
155
|
+
component draws nothing rather than failing the build — and lists the week in
|
|
156
|
+
the site's language, two rows for a day with a break. Restyle it like the rest.
|
|
157
|
+
|
|
158
|
+
## What not to do
|
|
159
|
+
|
|
160
|
+
- Do not compute free times on the page from the hours in `jtk/content` — the
|
|
161
|
+
diary's bookings live in the platform and the page cannot see them.
|
|
162
|
+
- Do not put a Turnstile key in the repository.
|
|
163
|
+
- Do not draw your own "your booking" page unless the design needs it; the
|
|
164
|
+
platform's at `manage_path` is the floor and works from day one.
|