@escape-game-over/atlas 0.1.24 → 0.1.26
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 +27 -44
- package/bin/use-project.mjs +18 -13
- package/docs/NOT-BUILT.md +1 -1
- package/docs/client-scripts.md +96 -193
- package/docs/rich-text.md +18 -20
- package/package.json +9 -15
- package/src/analytics/google.ts +6 -6
- package/src/analytics/index.ts +4 -3
- package/src/analytics/tags.ts +13 -58
- package/src/analytics/umami.ts +8 -8
- package/src/astro/AtlasElement.astro +26 -0
- package/src/astro/ConsentBanner.astro +25 -0
- package/src/astro/ConsentElement.astro +67 -0
- package/src/astro/Document.astro +44 -0
- package/src/astro/Image.astro +101 -0
- package/src/astro/MetaTags.astro +30 -40
- package/src/astro/RichText.astro +88 -0
- package/src/astro/Zoom.astro +61 -0
- package/src/astro/client.ts +18 -9
- package/src/astro/consent.ts +20 -0
- package/src/astro/dev-log.ts +8 -14
- package/src/astro/element.ts +76 -112
- package/src/astro/filters-view.ts +48 -64
- package/src/astro/filters.ts +42 -35
- package/src/astro/index.ts +2 -9
- package/src/astro/ref.ts +46 -0
- package/src/astro/site-routes.ts +9 -15
- package/src/config.ts +23 -36
- package/src/content/index.ts +1 -1
- package/src/content/marks.ts +13 -13
- package/src/content/rich.ts +26 -42
- package/src/hours.ts +48 -11
- package/src/i18n/define.ts +14 -74
- package/src/index.ts +40 -57
- package/src/meta/index.ts +7 -13
- package/src/meta/share-image.ts +2 -26
- package/src/meta/tag.ts +1 -45
- package/src/money.ts +161 -6
- package/src/project.ts +84 -73
- package/src/routes/define.ts +8 -44
- package/src/routes/resolve.ts +1 -1
- package/src/site/api.ts +7 -33
- package/src/site/create.ts +6 -10
- package/src/site/define.ts +120 -0
- package/src/site/index.ts +2 -5
- package/src/site/page.ts +4 -2
- package/src/sitemap.ts +2 -35
- package/src/warn.ts +16 -17
- package/src/astro/dom.ts +0 -35
- package/src/astro/markup.ts +0 -656
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ Linking to a page the active deployment switched off is a compile error, not a
|
|
|
61
61
|
One file per deployment, saying only what differs:
|
|
62
62
|
|
|
63
63
|
```ts
|
|
64
|
-
export default
|
|
64
|
+
export default atlas.project(defaultMessages, defaultRoutes, {
|
|
65
65
|
url: "https://acme.example",
|
|
66
66
|
siteName: "Acme Rome",
|
|
67
67
|
icon,
|
|
@@ -92,22 +92,22 @@ never writes a type argument:
|
|
|
92
92
|
|
|
93
93
|
```ts
|
|
94
94
|
// 1. which languages exist, how URLs are shaped
|
|
95
|
-
export
|
|
95
|
+
export const atlas = defineSite({ locales: {...}, defaultRouting: {...} })
|
|
96
96
|
|
|
97
97
|
// 2. the base copy and routes
|
|
98
|
-
export const baseMessages =
|
|
99
|
-
export const baseRoutes =
|
|
98
|
+
export const baseMessages = atlas.messages({...})
|
|
99
|
+
export const baseRoutes = atlas.routes({...})
|
|
100
100
|
|
|
101
101
|
// 3. one deployment
|
|
102
|
-
export default
|
|
102
|
+
export default atlas.project(baseMessages, baseRoutes, {...})
|
|
103
103
|
|
|
104
104
|
// 4. the API the pages use
|
|
105
|
-
export const site =
|
|
105
|
+
export const site = atlas.site(baseMessages, baseRoutes, project)
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
Step 4 returns `t()`, `rich()`, `plain()`, `pathFor()`, `urlFor()`, `fileUrl()`,
|
|
109
|
-
`
|
|
110
|
-
`
|
|
109
|
+
`localeLinksFor()`, `metaFor()`, `breadcrumbFor()`,
|
|
110
|
+
`getStaticPaths()`, `routes`, `sitemap()`, `robots()`, `llms()` and
|
|
111
111
|
`redirects()` already wired.
|
|
112
112
|
|
|
113
113
|
`t()` is bound to a locale and knows each message's `{placeholders}` from its
|
|
@@ -233,7 +233,7 @@ worded.
|
|
|
233
233
|
The same question answers it every time: *would this differ between two pages of
|
|
234
234
|
the same site?*
|
|
235
235
|
|
|
236
|
-
| Per page — passed to `metaFor()` | Site-level — declared in `
|
|
236
|
+
| Per page — passed to `metaFor()` | Site-level — declared in `atlas.project()` |
|
|
237
237
|
| -------------------------------- | ------------------------------------------ |
|
|
238
238
|
| `title`, `description` | `siteName`, `twitterSite` |
|
|
239
239
|
| `image` (asset **and** its alt) | `icon`, `themeColor`, `colorScheme` |
|
|
@@ -251,16 +251,9 @@ actually renders, and why `twitter:card` is pinned.
|
|
|
251
251
|
|
|
252
252
|
A project switches routes off. Anything defined *alongside* a route then has two
|
|
253
253
|
ways to rot: the page is built and its config is missing, or the page is gone and
|
|
254
|
-
its config lingers.
|
|
254
|
+
its config lingers. `PerRoute<typeof site, T>` rejects both.
|
|
255
255
|
|
|
256
|
-
|
|
257
|
-
| --------------------- | ------------------------------------ | ------------------------------------------------ |
|
|
258
|
-
| Shape | a table keyed by route id | a single value |
|
|
259
|
-
| Says | "every built route has one of these" | "this value belongs to *that* page" |
|
|
260
|
-
| When the route is off | that key is rejected | the type is `never` — the field cannot be filled |
|
|
261
|
-
| Use with | `satisfies` | a normal annotation |
|
|
262
|
-
|
|
263
|
-
`PerRoute` must be used with `satisfies`, not as an annotation: excess-property
|
|
256
|
+
It must be used with `satisfies`, not as an annotation: excess-property
|
|
264
257
|
checking is what catches the stale half, and only an object literal checked
|
|
265
258
|
against a known target gets it.
|
|
266
259
|
|
|
@@ -269,8 +262,6 @@ const heroes = {
|
|
|
269
262
|
home: { variant: "wide" },
|
|
270
263
|
about: { variant: "tall" },
|
|
271
264
|
} satisfies PerRoute<typeof site, Hero>; // ✗ if `about` is off, ✗ if `contact` is on
|
|
272
|
-
|
|
273
|
-
const careers: WhenEnabled<typeof site, "careers", Careers> = { ats: "…" }; // ✗ if off
|
|
274
265
|
```
|
|
275
266
|
|
|
276
267
|
## The rules this package keeps
|
|
@@ -299,16 +290,8 @@ const careers: WhenEnabled<typeof site, "careers", Careers> = { ats: "…" }; /
|
|
|
299
290
|
".": "./src/index.ts",
|
|
300
291
|
"./astro": "./src/astro/index.ts",
|
|
301
292
|
"./astro/images": "./src/astro/images.ts",
|
|
302
|
-
"./astro/
|
|
303
|
-
"./
|
|
304
|
-
"./astro/consent": "./src/astro/consent.ts",
|
|
305
|
-
"./astro/dev-log": "./src/astro/dev-log.ts",
|
|
306
|
-
"./astro/dom": "./src/astro/dom.ts",
|
|
307
|
-
"./astro/element": "./src/astro/element.ts",
|
|
308
|
-
"./astro/filters": "./src/astro/filters.ts",
|
|
309
|
-
"./astro/filters-view": "./src/astro/filters-view.ts",
|
|
310
|
-
"./astro/meta-tags": "./src/astro/MetaTags.astro",
|
|
311
|
-
"./astro/youtube": "./src/astro/youtube.ts"
|
|
293
|
+
"./astro/document": "./src/astro/Document.astro",
|
|
294
|
+
"./client": "./src/astro/client.ts"
|
|
312
295
|
}
|
|
313
296
|
```
|
|
314
297
|
|
|
@@ -324,27 +307,27 @@ may use `node:` built-ins but not `astro:assets`. `./astro/images` is the
|
|
|
324
307
|
opposite: it runs inside the build, from a page, and is unusable from a config.
|
|
325
308
|
Merging them breaks whichever caller loads first.
|
|
326
309
|
|
|
327
|
-
|
|
328
|
-
`youtube`, `background-video`, `consent`, `element
|
|
329
|
-
|
|
330
|
-
than in the build, and is separate again for the same reason: none of it can be
|
|
331
|
-
reached from a config, and none of it draws. See
|
|
310
|
+
`./client` is the browser half — `carousel`, `filters`, `filters-view`,
|
|
311
|
+
`youtube`, `background-video`, `consent`, `element` — one path
|
|
312
|
+
for all of it. See
|
|
332
313
|
[`docs/client-scripts.md`](docs/client-scripts.md).
|
|
333
314
|
|
|
334
315
|
**The package ships TypeScript source, and there is no build step.**
|
|
335
|
-
`
|
|
316
|
+
`Document.astro` could not go through `tsc` anyway, and Astro's own
|
|
336
317
|
`tsconfigs/base.json` already sets `allowImportingTsExtensions`, so every
|
|
337
318
|
consumer gets it for free.
|
|
338
319
|
|
|
339
320
|
## The `atlas` command
|
|
340
321
|
|
|
341
322
|
```bash
|
|
342
|
-
atlas use <project> #
|
|
323
|
+
atlas use <project> # links config/project -> config/projects/<name>
|
|
343
324
|
atlas use --fallback rome # only when nothing else named one
|
|
344
325
|
```
|
|
345
326
|
|
|
346
|
-
|
|
347
|
-
|
|
327
|
+
A link, not a copy: an edit made through `config/project` lands in the real
|
|
328
|
+
file. A directory junction on Windows, which needs no admin rights. Ignore it with
|
|
329
|
+
`**/config/project` — no trailing slash, since git sees a link as a file. The
|
|
330
|
+
contract is just that the project contains `project.ts`.
|
|
348
331
|
It resolves paths from the working directory, so a workspace's own
|
|
349
332
|
`package.json` passes nothing. A deployment pipeline can skip it and write its
|
|
350
333
|
own `config/project`.
|
|
@@ -358,7 +341,7 @@ command whose output gets deployed has to say what it is building.
|
|
|
358
341
|
```txt
|
|
359
342
|
src/ the package — see the export map above for what is reachable
|
|
360
343
|
index.ts the public API
|
|
361
|
-
site/ createSite() and the Site it returns
|
|
344
|
+
site/ defineSite(), createSite() and the Site it returns
|
|
362
345
|
meta/ head tags: canonical, hreflang, Open Graph, Twitter, robots
|
|
363
346
|
jsonld/ the @graph — one file per node, each linked to Google's docs
|
|
364
347
|
i18n/ defineMessages(), t(), placeholder extraction
|
|
@@ -400,9 +383,9 @@ proves the package is genuinely independent of anything consuming it.
|
|
|
400
383
|
|
|
401
384
|
The `astro check` pass covers `src/astro/`, the one directory that cannot meet
|
|
402
385
|
that bar. It needs `astro/client` for `astro:assets` and `ImageMetadata`, and
|
|
403
|
-
|
|
404
|
-
zero `.astro` files no matter how they are globbed. Without this pass the
|
|
405
|
-
|
|
386
|
+
the `.astro` components need a checker that can parse `.astro` at all — `tsc` reads
|
|
387
|
+
zero `.astro` files no matter how they are globbed. Without this pass the
|
|
388
|
+
components the package ships are checked by nothing: `astro check` in
|
|
406
389
|
`test:examples` only ever walks an example's own `src/`, so it never reaches it,
|
|
407
390
|
and a type error there passes the entire gate.
|
|
408
391
|
|
|
@@ -412,7 +395,7 @@ practical reason: `astro check` writes a `.astro/` types directory and a
|
|
|
412
395
|
publish both. The `tsconfig.json` there adds nothing — it extends
|
|
413
396
|
`src/astro/tsconfig.json` and only widens the glob, so the rules stay in one
|
|
414
397
|
place. `src/astro/tsconfig.json` is what an editor finds; without it, opening
|
|
415
|
-
`
|
|
398
|
+
`Document.astro` resolves against the root config, which supplies no ambient
|
|
416
399
|
types, and every prop degrades to `any`.
|
|
417
400
|
|
|
418
401
|
`test:examples` **builds every deployment**, not just type-checks one, and both
|
package/bin/use-project.mjs
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Links `config/project` to one project overlay, the folder the whole build
|
|
4
4
|
* reads from. Run automatically before `dev`, `build` and `check`.
|
|
5
5
|
*
|
|
6
|
+
* A link rather than a copy, so an edit made through `config/project` — where
|
|
7
|
+
* an editor's go-to-definition lands — is an edit to the real file. A
|
|
8
|
+
* junction on Windows, which needs no admin rights; a symlink elsewhere.
|
|
9
|
+
*
|
|
6
10
|
* atlas use acme
|
|
7
11
|
* PROJECT=acme npm run build
|
|
8
12
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* own `config/project` — the contract is just that it contains `project.ts`.
|
|
13
|
+
* A deployment pipeline can skip this command and write its own
|
|
14
|
+
* `config/project` — the contract is just that it contains `project.ts`.
|
|
12
15
|
*/
|
|
13
|
-
import {
|
|
16
|
+
import { lstat, readdir, rm, stat, symlink, unlink } from "node:fs/promises";
|
|
14
17
|
import { join } from "node:path";
|
|
15
18
|
|
|
16
19
|
/**
|
|
@@ -26,10 +29,7 @@ import { join } from "node:path";
|
|
|
26
29
|
const ROOT = process.cwd();
|
|
27
30
|
const PROJECTS_DIR = join(ROOT, "config", "projects");
|
|
28
31
|
const TARGET_DIR = join(ROOT, "config", "project");
|
|
29
|
-
/**
|
|
30
|
-
* Only an entry-point check — the whole directory is copied recursively, so a
|
|
31
|
-
* project can add files and folders freely without touching this script.
|
|
32
|
-
*/
|
|
32
|
+
/** Only an entry-point check: a project can add files and folders freely. */
|
|
33
33
|
const ENTRY_FILE = "project.ts";
|
|
34
34
|
|
|
35
35
|
/**
|
|
@@ -122,10 +122,15 @@ if (!(await exists(join(sourceDir, ENTRY_FILE)))) {
|
|
|
122
122
|
process.exit(1);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
await
|
|
125
|
+
// Only the link goes, never what it points at. A real directory is a copy left
|
|
126
|
+
// by an older version of this command.
|
|
127
|
+
const existing = await lstat(TARGET_DIR).catch(() => undefined);
|
|
128
|
+
if (existing?.isSymbolicLink()) await unlink(TARGET_DIR);
|
|
129
|
+
else if (existing !== undefined) await rm(TARGET_DIR, { recursive: true });
|
|
130
|
+
|
|
131
|
+
// "junction" is Windows' no-admin directory link, and ignored everywhere else.
|
|
132
|
+
await symlink(sourceDir, TARGET_DIR, "junction");
|
|
128
133
|
|
|
129
134
|
console.log(
|
|
130
|
-
`Using project "${name}" (config/projects/${name}
|
|
135
|
+
`Using project "${name}" (config/project -> config/projects/${name})`
|
|
131
136
|
);
|
package/docs/NOT-BUILT.md
CHANGED
|
@@ -230,7 +230,7 @@ type could — a property that is not valid for the type it sits on.
|
|
|
230
230
|
### Should a paragraph be authored as an array of translation keys?
|
|
231
231
|
|
|
232
232
|
**No. One sentence is one message, and the styling lives in the copy as
|
|
233
|
-
`[marks]`. `content/` carries the parser, the runs and `plain()`; nothing
|
|
233
|
+
`[marks]`. `content/` carries the parser, the runs and `site.plain()`; nothing
|
|
234
234
|
carries a `ContentItem[]`.**
|
|
235
235
|
|
|
236
236
|
This is the shape the sibling B2C template uses, and it is the one thing from
|