@sandboxsonny/ace-kit 0.5.0 → 0.7.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/CHANGELOG.md +13 -0
- package/dist/astro-integration.js +1 -1
- package/dist/chunk-7M26C36M.js +35 -0
- package/dist/{chunk-WM5NOQE3.js → chunk-T7DKI2U3.js} +4 -3
- package/dist/cli.js +14 -1179
- package/dist/environment-J4VYOHDK.js +223 -0
- package/dist/main-AGLPUGNN.js +1733 -0
- package/dist/react-router-server.d.ts +1 -1
- package/dist/vite.js +1 -1
- package/docs/command-line.md +55 -1
- package/docs/getting-started.md +8 -0
- package/docs/react-router.md +32 -3
- package/docs/react.md +5 -2
- package/package.json +5 -2
- package/templates/astro/.dockerignore +7 -0
- package/templates/astro/.github/dependabot.yml +19 -0
- package/templates/astro/.github/workflows/ci.yml +23 -0
- package/templates/astro/.prettierignore +6 -0
- package/templates/astro/.prettierrc.json +20 -0
- package/templates/astro/.vscode/extensions.json +4 -0
- package/templates/astro/.vscode/launch.json +11 -0
- package/templates/astro/AGENTS.md +22 -0
- package/templates/astro/Dockerfile +17 -0
- package/templates/astro/_gitignore +26 -0
- package/templates/astro/astro.config.mjs +18 -0
- package/templates/astro/eslint.config.js +56 -0
- package/templates/astro/package.json +41 -0
- package/templates/astro/public/favicon.ico +0 -0
- package/templates/astro/public/favicon.svg +9 -0
- package/templates/astro/src/ace-kit.generated.d.ts +24 -0
- package/templates/astro/src/components/PageContent.astro +113 -0
- package/templates/astro/src/components/SiteFooter.astro +19 -0
- package/templates/astro/src/components/SiteHeader.astro +121 -0
- package/templates/astro/src/components/sections/Faq.astro +54 -0
- package/templates/astro/src/components/sections/Faq.schema.ts +17 -0
- package/templates/astro/src/components/sections/Gallery.astro +74 -0
- package/templates/astro/src/components/sections/Gallery.schema.ts +20 -0
- package/templates/astro/src/components/sections/Hero.astro +58 -0
- package/templates/astro/src/components/sections/Hero.schema.ts +14 -0
- package/templates/astro/src/layouts/BaseLayout.astro +36 -0
- package/templates/astro/src/pages/[...slug].astro +31 -0
- package/templates/astro/src/styles/global.css +56 -0
- package/templates/astro/src/types/page.d.ts +4 -0
- package/templates/astro/tsconfig.json +11 -0
- package/templates/astro/vitest.config.ts +4 -0
- package/templates/astro.section-types.json +109 -0
- package/templates/react-router/.prettierignore +5 -0
- package/templates/react-router/.prettierrc.json +11 -0
- package/templates/react-router/_gitignore +7 -0
- package/templates/react-router/app/ace-kit.generated.d.ts +24 -0
- package/templates/react-router/app/app.css +257 -0
- package/templates/react-router/app/components/page-content.tsx +55 -0
- package/templates/react-router/app/components/sections/faq.schema.ts +17 -0
- package/templates/react-router/app/components/sections/faq.tsx +26 -0
- package/templates/react-router/app/components/sections/gallery.schema.ts +20 -0
- package/templates/react-router/app/components/sections/gallery.tsx +39 -0
- package/templates/react-router/app/components/sections/hero.schema.ts +14 -0
- package/templates/react-router/app/components/sections/hero.tsx +25 -0
- package/templates/react-router/app/components/site-footer.tsx +9 -0
- package/templates/react-router/app/components/site-header.tsx +49 -0
- package/templates/react-router/app/entry.server.tsx +1 -0
- package/templates/react-router/app/root.tsx +75 -0
- package/templates/react-router/app/routes/page.test.tsx +118 -0
- package/templates/react-router/app/routes/page.tsx +22 -0
- package/templates/react-router/app/routes.ts +8 -0
- package/templates/react-router/app/types/page.d.ts +4 -0
- package/templates/react-router/eslint.config.js +76 -0
- package/templates/react-router/package.json +51 -0
- package/templates/react-router/public/favicon.svg +9 -0
- package/templates/react-router/react-router.config.ts +6 -0
- package/templates/react-router/tsconfig.json +22 -0
- package/templates/react-router/vite.config.ts +10 -0
- package/templates/react-router/vitest.config.ts +15 -0
- package/templates/react-router.section-types.json +109 -0
|
@@ -142,7 +142,7 @@ declare const getMenuLinks: (handle: string, options?: {
|
|
|
142
142
|
fallback?: AceNavigationLink[];
|
|
143
143
|
}) => Promise<AceNavigationLink[]>;
|
|
144
144
|
/**
|
|
145
|
-
* The loader for the route that draws every page. The route is a catch-all (`route("*", "routes/page.tsx")`):
|
|
145
|
+
* The loader for the route that draws every page. The route is a catch-all, plus an index line because "*" does not match "/" (`index("routes/page.tsx", { id: "home" })` and `route("*", "routes/page.tsx", { id: "page" })`):
|
|
146
146
|
*
|
|
147
147
|
* export const loader = createPageLoader<PageValues>();
|
|
148
148
|
* export { headers } from "@sandboxsonny/ace-kit/react-router/server";
|
package/dist/vite.js
CHANGED
package/docs/command-line.md
CHANGED
|
@@ -1,17 +1,71 @@
|
|
|
1
1
|
# The command line
|
|
2
2
|
|
|
3
|
-
`ace-kit` is also a command. It signs you in to CMS Ace from your terminal, and writes types for your content.
|
|
3
|
+
`ace-kit` is also a command. It makes new sites, signs you in to CMS Ace from your terminal, and writes types for your content.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
+
npx @sandboxsonny/ace-kit create my-site --site my-site.com # make a new site (see Making a site)
|
|
6
7
|
npx ace-kit login # sign in
|
|
7
8
|
npx ace-kit whoami # who am I signed in as?
|
|
8
9
|
npx ace-kit logout # sign out
|
|
10
|
+
npx ace-kit doctor # check this site is set up properly (see Checking a site)
|
|
9
11
|
npx ace-kit generate # write TypeScript types (see Typed content)
|
|
10
12
|
npx ace-kit sync # send your section types to the CMS (see Sections)
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
Commands talk to the hosted CMS Ace unless told otherwise. Only for a CMS on your own machine, give `--api-url`, or set `ACE_API_URL` in the environment or a `.env` file in the folder you run it in. Failing both, a command uses the address you last signed in to (kept in a small file beside your logins), and failing that the hosted one, so `ace-kit login` and `ace-kit whoami` need no flags at all. Commands about a site (`sync`, `generate`) take `--site example.com`, or read `ACE_SITE_DOMAIN`.
|
|
14
16
|
|
|
17
|
+
## Making a site
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npx @sandboxsonny/ace-kit create my-site my-site.com
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
One command makes everything a new site needs:
|
|
24
|
+
|
|
25
|
+
1. **Checks** the folder, the domain and the name, before anything is made.
|
|
26
|
+
2. **Signs you in** if you aren't already (your browser opens; type the code from the terminal, as in [Signing in](#signing-in)).
|
|
27
|
+
3. **Makes the site in CMS Ace** and gives it a starter: a `pages` content type, Home, About and Contact entries, a main menu and the three example section types (hero, FAQ, gallery).
|
|
28
|
+
4. **Copies a starter site** into `my-site/` with its name, domain and package name filled in.
|
|
29
|
+
|
|
30
|
+
If a site with that domain already exists in CMS Ace, it is **left alone** (nothing is added to it, in case it has real content), a warning says so, and only the folder is made. If the CMS refuses to make the site (for instance, you have made as many as your account allows) nothing is made at all.
|
|
31
|
+
|
|
32
|
+
Your account must be a **partner or super admin** (only they can make sites). The login `create` uses can set up the site it just made, for an hour, and no other site: it can't write content anywhere else.
|
|
33
|
+
|
|
34
|
+
| Option | Meaning |
|
|
35
|
+
| --------------------------------- | ------------------------------------------------------------------------------------- |
|
|
36
|
+
| `<domain>` (or `--site <domain>`) | The domain the site has in CMS Ace. Required. |
|
|
37
|
+
| `--framework astro\|react-router` | `astro` (the default) or `react-router`. Both have the same three example sections. |
|
|
38
|
+
| `--name <name>` | The name shown to visitors. Default: made from the folder, so `my-site` is "My Site". |
|
|
39
|
+
| `--api-url <address>` | Only for a CMS on your own machine (or set `ACE_API_URL`). |
|
|
40
|
+
|
|
41
|
+
Against a CMS on your own machine (`--api-url` or `ACE_API_URL` set to `http://localhost:8080`), it also writes a `.env` in the new folder with `ACE_API_URL` and `ACE_PREVIEW_ADMIN_ORIGIN=http://localhost:5173`, and sets the site's Preview address to the local dev server (`http://localhost:4321`, or 4322 for React Router), so the site and live preview work with no more setup. Against the hosted CMS Ace none of that is needed.
|
|
42
|
+
|
|
43
|
+
The folder must not exist yet (or must be empty). The starter is a small server-rendered site with a header, footer, rich text, live preview and Prettier, ESLint, tests and a CI workflow. When it finishes: `cd my-site`, `npm install`, `npm run dev`.
|
|
44
|
+
|
|
45
|
+
## Checking a site
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
npx ace-kit doctor
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Run it in your site's folder when something isn't working. It changes nothing, never prints your login, and says what to do about each problem:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
✓ Node 24.14.0
|
|
55
|
+
✓ An Astro site
|
|
56
|
+
✓ Ace Kit 0.6.0 is installed
|
|
57
|
+
✓ CMS: https://api.ace-cms.co.uk (the hosted CMS Ace)
|
|
58
|
+
✓ Site: shop.example.com
|
|
59
|
+
✓ The CMS answers
|
|
60
|
+
✓ The CMS knows the site: "Shop"
|
|
61
|
+
✓ Pages has 3 published entries, including home
|
|
62
|
+
✓ Signed in as sam@example.com
|
|
63
|
+
✓ 3 section types in your code (faq, gallery, hero)
|
|
64
|
+
✓ The CMS has all of them
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
It checks your Node version, that Ace Kit is installed, which CMS and site your settings point at, that the CMS can be reached and knows the site, that the site has its Pages content, that you are signed in, the site's preview address, and that the section types in your code match the CMS. `✗` is a problem (the command exits with 1), `!` is a warning, `-` is a note. It takes `--site`, `--api-url` and `--dir` like `sync`.
|
|
68
|
+
|
|
15
69
|
## Signing in
|
|
16
70
|
|
|
17
71
|
```sh
|
package/docs/getting-started.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Ace Kit is everything a website needs to use CMS Ace (see the [README](../README.md)): a typed client for the public API, addressing (`/{content type}/{entry}`), responsive images, menus, rich text, live preview support, and thin Astro and React adapters. It has no runtime dependencies.
|
|
4
4
|
|
|
5
|
+
## Starting from nothing
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npx @sandboxsonny/ace-kit create my-site my-site.com
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
makes an Astro (or, with `--framework react-router`, a React Router) site with everything below already wired up. See [the command line](./command-line.md#making-a-site). To add the kit to a site you already have, read on.
|
|
12
|
+
|
|
5
13
|
## Install
|
|
6
14
|
|
|
7
15
|
```sh
|
package/docs/react-router.md
CHANGED
|
@@ -4,7 +4,7 @@ Ace Kit has a React Router adapter, so a site only writes its design. It needs `
|
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
app/
|
|
7
|
-
routes.ts route("*"
|
|
7
|
+
routes.ts index + route("*") for routes/page.tsx one route draws every page
|
|
8
8
|
entry.server.tsx one line
|
|
9
9
|
root.tsx createRootLoader + your layout and header
|
|
10
10
|
routes/page.tsx createPageLoader + your page
|
|
@@ -47,9 +47,13 @@ It waits until a page is completely ready before answering (every page is fully
|
|
|
47
47
|
|
|
48
48
|
```ts
|
|
49
49
|
// app/routes.ts
|
|
50
|
-
import { type RouteConfig, route } from "@react-router/dev/routes";
|
|
50
|
+
import { type RouteConfig, index, route } from "@react-router/dev/routes";
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
// "/" is the home entry. A "*" route doesn't match "/", so the home page needs its own `index` line.
|
|
53
|
+
export default [
|
|
54
|
+
index("routes/page.tsx", { id: "home" }),
|
|
55
|
+
route("*", "routes/page.tsx", { id: "page" }),
|
|
56
|
+
] satisfies RouteConfig;
|
|
53
57
|
```
|
|
54
58
|
|
|
55
59
|
```tsx
|
|
@@ -117,3 +121,28 @@ export async function loader() {
|
|
|
117
121
|
## Without the adapter
|
|
118
122
|
|
|
119
123
|
Everything the adapter does is built from the framework-free [core](./getting-started.md): `loadPage`, `loadMenuLinks`, `previewTokenFrom`, `addFramingPolicy`, the [React components](./react.md) and `usePreviewRefresh`. The adapter is about 150 lines; read it if you need to do something it doesn't.
|
|
124
|
+
|
|
125
|
+
## Sections
|
|
126
|
+
|
|
127
|
+
A sections field is drawn with `AceSections`, which gives each section to the component for its kind. Each kind is a component with a `*.schema.ts` file beside it saying what an editor can fill in (see [Sections](./sections.md)):
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
// app/components/page-content.tsx
|
|
131
|
+
import { AceSections } from "@sandboxsonny/ace-kit/react-router";
|
|
132
|
+
|
|
133
|
+
import { Hero } from "~/components/sections/hero";
|
|
134
|
+
|
|
135
|
+
<AceSections sections={entry.values.content} components={{ hero: Hero }} />;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// app/components/sections/hero.tsx, typed from hero.schema.ts
|
|
140
|
+
import type { SectionOf } from "@sandboxsonny/ace-kit";
|
|
141
|
+
import type hero from "./hero.schema";
|
|
142
|
+
|
|
143
|
+
export function Hero({ section }: { section: SectionOf<typeof hero> }) {
|
|
144
|
+
return <h2>{section.values.heading}</h2>;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Schema files in `app/` (or `src/`) are found by `ace-kit sync`, and while `npm run dev` runs, saving one syncs it to the CMS. A new site from `npx @sandboxsonny/ace-kit create --framework react-router` comes with a hero, an FAQ and a gallery.
|
package/docs/react.md
CHANGED
|
@@ -74,8 +74,11 @@ Pass `adminOrigin` only for a page shown with a preview token (`previewTokenFrom
|
|
|
74
74
|
## A route in React Router 7
|
|
75
75
|
|
|
76
76
|
```tsx
|
|
77
|
-
// app/routes.ts: one route draws every page
|
|
78
|
-
export default [
|
|
77
|
+
// app/routes.ts: one route draws every page ("/" needs its own index line: a "*" route does not match it)
|
|
78
|
+
export default [
|
|
79
|
+
index("routes/page.tsx", { id: "home" }),
|
|
80
|
+
route("*", "routes/page.tsx", { id: "page" }),
|
|
81
|
+
] satisfies RouteConfig;
|
|
79
82
|
|
|
80
83
|
// app/routes/page.tsx
|
|
81
84
|
export async function loader({ request, params }: Route.LoaderArgs) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sandboxsonny/ace-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Everything a website needs to use CMS Ace: a typed client, addressing, images, menus, rich text, live preview, and Astro and React adapters.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cms",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"files": [
|
|
30
30
|
"dist",
|
|
31
31
|
"astro",
|
|
32
|
+
"templates",
|
|
32
33
|
"docs",
|
|
33
34
|
"CHANGELOG.md",
|
|
34
35
|
"LICENSE"
|
|
@@ -87,8 +88,10 @@
|
|
|
87
88
|
"format": "prettier --write .",
|
|
88
89
|
"format:check": "prettier --check .",
|
|
89
90
|
"typecheck": "tsc --noEmit",
|
|
90
|
-
"check": "npm run format:check && npm run lint && npm run typecheck && npm test && npm run build && npm run check:package",
|
|
91
|
+
"check": "npm run format:check && npm run lint && npm run typecheck && npm test && npm run build && npm run check:package && npm run check:templates",
|
|
91
92
|
"check:package": "node scripts/check-package.mjs",
|
|
93
|
+
"check:templates": "node scripts/sync-templates.mjs --check",
|
|
94
|
+
"sync:templates": "node scripts/sync-templates.mjs",
|
|
92
95
|
"pack:local": "npm run build && npm pack",
|
|
93
96
|
"storybook": "storybook dev -p 6006",
|
|
94
97
|
"build:storybook": "storybook build",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: npm
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
groups:
|
|
8
|
+
# Small upgrades arrive together as one pull request. A major version of anything is its own pull request, so
|
|
9
|
+
# one that needs a deliberate look (a new Astro or Ace Kit major) doesn't hold back the rest.
|
|
10
|
+
minor-and-patch:
|
|
11
|
+
update-types: [minor, patch]
|
|
12
|
+
- package-ecosystem: docker
|
|
13
|
+
directory: /
|
|
14
|
+
schedule:
|
|
15
|
+
interval: monthly
|
|
16
|
+
- package-ecosystem: github-actions
|
|
17
|
+
directory: /
|
|
18
|
+
schedule:
|
|
19
|
+
interval: monthly
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
check:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7
|
|
16
|
+
- uses: actions/setup-node@v7
|
|
17
|
+
with:
|
|
18
|
+
# Matches the Dockerfile's node:24-alpine, so CI tests what production runs.
|
|
19
|
+
node-version: 24
|
|
20
|
+
cache: npm
|
|
21
|
+
- run: npm ci
|
|
22
|
+
# Format, lint, types, tests and a build.
|
|
23
|
+
- run: npm run check
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"printWidth": 120,
|
|
3
|
+
"tabWidth": 2,
|
|
4
|
+
"useTabs": false,
|
|
5
|
+
"semi": true,
|
|
6
|
+
"singleQuote": false,
|
|
7
|
+
"trailingComma": "all",
|
|
8
|
+
"bracketSpacing": true,
|
|
9
|
+
"arrowParens": "always",
|
|
10
|
+
"endOfLine": "lf",
|
|
11
|
+
"plugins": ["prettier-plugin-astro"],
|
|
12
|
+
"overrides": [
|
|
13
|
+
{
|
|
14
|
+
"files": "*.astro",
|
|
15
|
+
"options": {
|
|
16
|
+
"parser": "astro"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## Development
|
|
2
|
+
|
|
3
|
+
When starting the dev server, use background mode:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
astro dev --background
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Manage the background server with `astro dev stop`, `astro dev status`, and `astro dev logs`.
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
Full documentation: https://docs.astro.build
|
|
14
|
+
|
|
15
|
+
Consult these guides before working on related tasks:
|
|
16
|
+
|
|
17
|
+
- [Adding pages, dynamic routes, or middleware](https://docs.astro.build/en/guides/routing/)
|
|
18
|
+
- [Working with Astro components](https://docs.astro.build/en/basics/astro-components/)
|
|
19
|
+
- [Using React, Vue, Svelte, or other framework components](https://docs.astro.build/en/guides/framework-components/)
|
|
20
|
+
- [Adding or managing content](https://docs.astro.build/en/guides/content-collections/)
|
|
21
|
+
- [Adding styles or using Tailwind](https://docs.astro.build/en/guides/styling/)
|
|
22
|
+
- [Supporting multiple languages](https://docs.astro.build/en/guides/internationalization/)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
FROM node:24-alpine AS production-dependencies-env
|
|
2
|
+
COPY ./package.json package-lock.json /app/
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
RUN npm ci --omit=dev
|
|
5
|
+
|
|
6
|
+
FROM node:24-alpine AS build-env
|
|
7
|
+
COPY . /app/
|
|
8
|
+
WORKDIR /app
|
|
9
|
+
RUN npm ci && npm run build
|
|
10
|
+
|
|
11
|
+
FROM node:24-alpine
|
|
12
|
+
ENV HOST=0.0.0.0
|
|
13
|
+
COPY ./package.json package-lock.json /app/
|
|
14
|
+
COPY --from=production-dependencies-env /app/node_modules /app/node_modules
|
|
15
|
+
COPY --from=build-env /app/dist /app/dist
|
|
16
|
+
WORKDIR /app
|
|
17
|
+
CMD ["node", "dist/server/entry.mjs"]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# build output
|
|
2
|
+
dist/
|
|
3
|
+
# generated types
|
|
4
|
+
.astro/
|
|
5
|
+
|
|
6
|
+
# dependencies
|
|
7
|
+
node_modules/
|
|
8
|
+
|
|
9
|
+
# logs
|
|
10
|
+
npm-debug.log*
|
|
11
|
+
yarn-debug.log*
|
|
12
|
+
yarn-error.log*
|
|
13
|
+
pnpm-debug.log*
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# environment variables
|
|
17
|
+
.env
|
|
18
|
+
.env.production
|
|
19
|
+
|
|
20
|
+
# macOS-specific files
|
|
21
|
+
.DS_Store
|
|
22
|
+
|
|
23
|
+
# jetbrains setting folder
|
|
24
|
+
.idea/
|
|
25
|
+
.env.*
|
|
26
|
+
!.env.example
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { defineConfig } from "astro/config";
|
|
3
|
+
|
|
4
|
+
import node from "@astrojs/node";
|
|
5
|
+
import ace from "@sandboxsonny/ace-kit/astro/integration";
|
|
6
|
+
|
|
7
|
+
// https://astro.build/config
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
// The site's domain in CMS Ace. Ace Kit reads it from here (ACE_SITE_DOMAIN, if set, wins), so the dev server can find
|
|
10
|
+
// or make your own private copy of this site to work on.
|
|
11
|
+
site: "https://example.adamsdevelopment.co.uk",
|
|
12
|
+
// Pages are rendered on each request so they always show the CMS's live content.
|
|
13
|
+
output: "server",
|
|
14
|
+
adapter: node({ mode: "standalone" }),
|
|
15
|
+
// Ace Kit connects the site to CMS Ace: it declares ACE_API_URL, ACE_SITE_DOMAIN and ACE_PREVIEW_ADMIN_ORIGIN, and
|
|
16
|
+
// lets the CMS's admin app frame the site for live preview.
|
|
17
|
+
integrations: [ace()],
|
|
18
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import eslint from "@eslint/js";
|
|
2
|
+
import astro from "eslint-plugin-astro";
|
|
3
|
+
import prettierConfig from "eslint-config-prettier";
|
|
4
|
+
import globals from "globals";
|
|
5
|
+
import typescriptEslint from "typescript-eslint";
|
|
6
|
+
|
|
7
|
+
export default typescriptEslint.config(
|
|
8
|
+
{ ignores: ["node_modules", "dist", ".astro", "public"] },
|
|
9
|
+
|
|
10
|
+
eslint.configs.recommended,
|
|
11
|
+
...typescriptEslint.configs.recommended,
|
|
12
|
+
...astro.configs.recommended,
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
files: ["**/*.{ts,astro,mjs}"],
|
|
16
|
+
languageOptions: { globals: { ...globals.browser, ...globals.node } },
|
|
17
|
+
rules: {
|
|
18
|
+
// Types are imported with `import type` from src/types.
|
|
19
|
+
"@typescript-eslint/consistent-type-imports": ["error", { fixStyle: "separate-type-imports" }],
|
|
20
|
+
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
|
|
21
|
+
|
|
22
|
+
// No abbreviated names in code. Spell it out: `request`, `response`, `message`...
|
|
23
|
+
"id-denylist": [
|
|
24
|
+
"error",
|
|
25
|
+
"req",
|
|
26
|
+
"res",
|
|
27
|
+
"resp",
|
|
28
|
+
"cfg",
|
|
29
|
+
"msg",
|
|
30
|
+
"btn",
|
|
31
|
+
"tmp",
|
|
32
|
+
"idx",
|
|
33
|
+
"evt",
|
|
34
|
+
"cb",
|
|
35
|
+
"fn",
|
|
36
|
+
"opts",
|
|
37
|
+
"args",
|
|
38
|
+
"val",
|
|
39
|
+
"num",
|
|
40
|
+
"str",
|
|
41
|
+
"obj",
|
|
42
|
+
"arr",
|
|
43
|
+
],
|
|
44
|
+
|
|
45
|
+
eqeqeq: ["error", "always"],
|
|
46
|
+
"no-console": ["warn", { allow: ["error", "warn"] }],
|
|
47
|
+
"prefer-const": "error",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Command-line scripts report what they did on the console.
|
|
52
|
+
{ files: ["scripts/**"], rules: { "no-console": "off" } },
|
|
53
|
+
|
|
54
|
+
// Must stay last: turns off any rule that would fight with Prettier.
|
|
55
|
+
prettierConfig,
|
|
56
|
+
);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "example-astro-site",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=22.12.0"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "astro dev",
|
|
10
|
+
"build": "astro build",
|
|
11
|
+
"preview": "astro preview",
|
|
12
|
+
"astro": "astro",
|
|
13
|
+
"lint": "eslint .",
|
|
14
|
+
"lint:fix": "eslint . --fix",
|
|
15
|
+
"format": "prettier --write .",
|
|
16
|
+
"format:check": "prettier --check .",
|
|
17
|
+
"typecheck": "astro check",
|
|
18
|
+
"check": "npm run format:check && npm run lint && npm run typecheck && npm test && npm run build",
|
|
19
|
+
"test": "vitest run --passWithNoTests",
|
|
20
|
+
"generate": "ace-kit generate"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@astrojs/node": "^11.1.7",
|
|
24
|
+
"@sandboxsonny/ace-kit": "^0.5.0",
|
|
25
|
+
"astro": "^7.3.8"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@astrojs/check": "^0.9.10",
|
|
29
|
+
"@eslint/js": "^10.0.1",
|
|
30
|
+
"eslint": "^10.12.0",
|
|
31
|
+
"eslint-config-prettier": "^10.1.8",
|
|
32
|
+
"eslint-plugin-astro": "^1.7.0",
|
|
33
|
+
"globals": "^17.13.0",
|
|
34
|
+
"jsdom": "^29.1.1",
|
|
35
|
+
"prettier": "^3.9.10",
|
|
36
|
+
"prettier-plugin-astro": "^1.1.1",
|
|
37
|
+
"typescript": "^6.0.3",
|
|
38
|
+
"typescript-eslint": "^8.71.1",
|
|
39
|
+
"vitest": "^5.0.4"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
|
2
|
+
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
|
3
|
+
<style>
|
|
4
|
+
path { fill: #000; }
|
|
5
|
+
@media (prefers-color-scheme: dark) {
|
|
6
|
+
path { fill: #FFF; }
|
|
7
|
+
}
|
|
8
|
+
</style>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Generated by ace-kit from localhost. Do not edit: run `ace-kit generate` to update it.
|
|
2
|
+
import type { AceImageData, AceLinkData, AceRichTextDocument, AceSection } from "@sandboxsonny/ace-kit";
|
|
3
|
+
|
|
4
|
+
declare module "@sandboxsonny/ace-kit" {
|
|
5
|
+
interface AceContentTypes {
|
|
6
|
+
/** Pages */
|
|
7
|
+
"pages": {
|
|
8
|
+
/** Headline */
|
|
9
|
+
"headline": string;
|
|
10
|
+
/** Body */
|
|
11
|
+
"body"?: AceRichTextDocument;
|
|
12
|
+
/** Hero image */
|
|
13
|
+
"hero"?: AceImageData;
|
|
14
|
+
/** Published */
|
|
15
|
+
"published"?: string;
|
|
16
|
+
/** Button */
|
|
17
|
+
"button"?: AceLinkData;
|
|
18
|
+
/** Content */
|
|
19
|
+
"content"?: AceSection[];
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
import AceImage from "@sandboxsonny/ace-kit/astro/AceImage.astro";
|
|
3
|
+
import AceLink from "@sandboxsonny/ace-kit/astro/AceLink.astro";
|
|
4
|
+
import AceRichText from "@sandboxsonny/ace-kit/astro/AceRichText.astro";
|
|
5
|
+
import AceTextArea from "@sandboxsonny/ace-kit/astro/AceTextArea.astro";
|
|
6
|
+
import { formatAceDate } from "@sandboxsonny/ace-kit";
|
|
7
|
+
import type { AceEntry } from "@sandboxsonny/ace-kit";
|
|
8
|
+
|
|
9
|
+
import AceSections from "@sandboxsonny/ace-kit/astro/AceSections.astro";
|
|
10
|
+
|
|
11
|
+
import Faq from "~/components/sections/Faq.astro";
|
|
12
|
+
import Gallery from "~/components/sections/Gallery.astro";
|
|
13
|
+
import Hero from "~/components/sections/Hero.astro";
|
|
14
|
+
|
|
15
|
+
import type { PageValues } from "~/types/page";
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
entry: AceEntry<PageValues>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const { entry } = Astro.props;
|
|
22
|
+
const { headline, body, hero, published, button, content } = entry.values;
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
<section class="section">
|
|
26
|
+
<div class="container prose">
|
|
27
|
+
<h1>{headline || entry.title}</h1>
|
|
28
|
+
{entry.description && <p class="intro">{entry.description}</p>}
|
|
29
|
+
{
|
|
30
|
+
// A date field is a day with no time of day, so it is the same day wherever the server runs.
|
|
31
|
+
published && (
|
|
32
|
+
<p class="published">
|
|
33
|
+
Published <time datetime={published}>{formatAceDate(published, { locale: "en-GB" }) ?? published}</time>
|
|
34
|
+
</p>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
{hero && (
|
|
38
|
+
<figure>
|
|
39
|
+
<AceImage image={hero} sizes="(min-width: 64rem) 64rem, 100vw" lazy={false} />
|
|
40
|
+
</figure>
|
|
41
|
+
)}
|
|
42
|
+
{
|
|
43
|
+
// A site made before its Body field was rich text still has plain text, with blank lines between paragraphs.
|
|
44
|
+
typeof body === "string" ? (
|
|
45
|
+
<AceTextArea value={body} />
|
|
46
|
+
) : body ? (
|
|
47
|
+
<div class="rich-text">
|
|
48
|
+
<AceRichText document={body} />
|
|
49
|
+
</div>
|
|
50
|
+
) : null
|
|
51
|
+
}
|
|
52
|
+
{
|
|
53
|
+
// A link field: the editor's words and where it goes, already worked out by the CMS.
|
|
54
|
+
button && (
|
|
55
|
+
<p class="actions">
|
|
56
|
+
<AceLink link={button} class="button" />
|
|
57
|
+
</p>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
62
|
+
<AceSections sections={content} components={{ hero: Hero, faq: Faq, gallery: Gallery }} />
|
|
63
|
+
<style>
|
|
64
|
+
.prose {
|
|
65
|
+
max-width: 42rem;
|
|
66
|
+
}
|
|
67
|
+
.intro {
|
|
68
|
+
color: var(--colour-muted);
|
|
69
|
+
font-size: 1.125rem;
|
|
70
|
+
}
|
|
71
|
+
.published {
|
|
72
|
+
color: var(--colour-muted);
|
|
73
|
+
font-size: 0.9rem;
|
|
74
|
+
}
|
|
75
|
+
.actions {
|
|
76
|
+
margin-top: 2rem;
|
|
77
|
+
}
|
|
78
|
+
figure {
|
|
79
|
+
margin: 2rem 0;
|
|
80
|
+
}
|
|
81
|
+
figure :global(img) {
|
|
82
|
+
border-radius: 0.5rem;
|
|
83
|
+
}
|
|
84
|
+
.rich-text :global(* + *) {
|
|
85
|
+
margin-top: 1rem;
|
|
86
|
+
}
|
|
87
|
+
.rich-text :global(h2) {
|
|
88
|
+
font-size: 1.75rem;
|
|
89
|
+
}
|
|
90
|
+
.rich-text :global(h3) {
|
|
91
|
+
font-size: 1.4rem;
|
|
92
|
+
}
|
|
93
|
+
.rich-text :global(h4) {
|
|
94
|
+
font-size: 1.15rem;
|
|
95
|
+
}
|
|
96
|
+
.rich-text :global(ul) {
|
|
97
|
+
list-style: disc;
|
|
98
|
+
padding-left: 1.5rem;
|
|
99
|
+
}
|
|
100
|
+
.rich-text :global(ol) {
|
|
101
|
+
list-style: decimal;
|
|
102
|
+
padding-left: 1.5rem;
|
|
103
|
+
}
|
|
104
|
+
.rich-text :global(blockquote) {
|
|
105
|
+
border-left: 4px solid var(--colour-muted);
|
|
106
|
+
padding-left: 1rem;
|
|
107
|
+
font-style: italic;
|
|
108
|
+
}
|
|
109
|
+
.rich-text :global(img) {
|
|
110
|
+
max-width: 100%;
|
|
111
|
+
height: auto;
|
|
112
|
+
}
|
|
113
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
const year = new Date().getFullYear();
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<footer class="site-footer">
|
|
6
|
+
<div class="container">
|
|
7
|
+
<p>© {year} Example Site. A test site for CMS Ace.</p>
|
|
8
|
+
</div>
|
|
9
|
+
</footer>
|
|
10
|
+
|
|
11
|
+
<style>
|
|
12
|
+
.site-footer {
|
|
13
|
+
margin-top: 3rem;
|
|
14
|
+
padding-block: 2rem;
|
|
15
|
+
background: var(--colour-surface);
|
|
16
|
+
color: var(--colour-muted);
|
|
17
|
+
font-size: 0.9rem;
|
|
18
|
+
}
|
|
19
|
+
</style>
|