@beatzball/create-litro 0.1.3 → 0.2.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 +133 -0
- package/dist/recipes/fullstack/template/app.ts +11 -8
- package/dist/recipes/fullstack/template/pages/blog/[slug].ts +4 -5
- package/dist/recipes/fullstack/template/pages/index.ts +4 -5
- package/dist/recipes/starlight/recipe.config.d.ts +4 -0
- package/dist/recipes/starlight/recipe.config.d.ts.map +1 -0
- package/dist/recipes/starlight/recipe.config.js +9 -0
- package/dist/recipes/starlight/recipe.config.js.map +1 -0
- package/dist/recipes/starlight/recipe.config.ts +11 -0
- package/dist/recipes/starlight/template/_data/metadata.js +10 -0
- package/dist/recipes/starlight/template/app.ts +18 -0
- package/dist/recipes/starlight/template/content/blog/.11tydata.json +1 -0
- package/dist/recipes/starlight/template/content/blog/release-notes.md +44 -0
- package/dist/recipes/starlight/template/content/blog/welcome.md +44 -0
- package/dist/recipes/starlight/template/content/docs/.11tydata.json +1 -0
- package/dist/recipes/starlight/template/content/docs/configuration.md +77 -0
- package/dist/recipes/starlight/template/content/docs/getting-started.md +53 -0
- package/dist/recipes/starlight/template/content/docs/guides-deploying.md +79 -0
- package/dist/recipes/starlight/template/content/docs/guides-first-page.md +64 -0
- package/dist/recipes/starlight/template/content/docs/installation.md +54 -0
- package/dist/recipes/starlight/template/litro.recipe.json +7 -0
- package/dist/recipes/starlight/template/nitro.config.ts +57 -0
- package/dist/recipes/starlight/template/package.json +26 -0
- package/dist/recipes/starlight/template/pages/blog/[slug].ts +125 -0
- package/dist/recipes/starlight/template/pages/blog/index.ts +114 -0
- package/dist/recipes/starlight/template/pages/blog/tags/[tag].ts +110 -0
- package/dist/recipes/starlight/template/pages/docs/[slug].ts +147 -0
- package/dist/recipes/starlight/template/pages/index.ts +135 -0
- package/dist/recipes/starlight/template/public/styles/starlight.css +215 -0
- package/dist/recipes/starlight/template/server/middleware/vite-dev.ts +29 -0
- package/dist/recipes/starlight/template/server/routes/[...].ts +57 -0
- package/dist/recipes/starlight/template/server/starlight.config.js +29 -0
- package/dist/recipes/starlight/template/src/components/sl-aside.ts +91 -0
- package/dist/recipes/starlight/template/src/components/sl-badge.ts +76 -0
- package/dist/recipes/starlight/template/src/components/sl-card-grid.ts +34 -0
- package/dist/recipes/starlight/template/src/components/sl-card.ts +91 -0
- package/dist/recipes/starlight/template/src/components/sl-tab-item.ts +35 -0
- package/dist/recipes/starlight/template/src/components/sl-tabs.ts +108 -0
- package/dist/recipes/starlight/template/src/components/starlight-header.ts +152 -0
- package/dist/recipes/starlight/template/src/components/starlight-page.ts +168 -0
- package/dist/recipes/starlight/template/src/components/starlight-sidebar.ts +125 -0
- package/dist/recipes/starlight/template/src/components/starlight-toc.ts +133 -0
- package/dist/recipes/starlight/template/src/date-utils.ts +20 -0
- package/dist/recipes/starlight/template/src/extract-headings.ts +68 -0
- package/dist/recipes/starlight/template/src/route-meta.ts +16 -0
- package/dist/recipes/starlight/template/tsconfig.json +14 -0
- package/dist/recipes/starlight/template/vite.config.ts +19 -0
- package/dist/src/scaffold.test.js +134 -0
- package/dist/src/scaffold.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/recipes/fullstack/template/app.ts +11 -8
- package/recipes/fullstack/template/pages/blog/[slug].ts +4 -5
- package/recipes/fullstack/template/pages/index.ts +4 -5
- package/recipes/starlight/recipe.config.ts +11 -0
- package/recipes/starlight/template/_data/metadata.js +10 -0
- package/recipes/starlight/template/app.ts +18 -0
- package/recipes/starlight/template/content/blog/.11tydata.json +1 -0
- package/recipes/starlight/template/content/blog/release-notes.md +44 -0
- package/recipes/starlight/template/content/blog/welcome.md +44 -0
- package/recipes/starlight/template/content/docs/.11tydata.json +1 -0
- package/recipes/starlight/template/content/docs/configuration.md +77 -0
- package/recipes/starlight/template/content/docs/getting-started.md +53 -0
- package/recipes/starlight/template/content/docs/guides-deploying.md +79 -0
- package/recipes/starlight/template/content/docs/guides-first-page.md +64 -0
- package/recipes/starlight/template/content/docs/installation.md +54 -0
- package/recipes/starlight/template/litro.recipe.json +7 -0
- package/recipes/starlight/template/nitro.config.ts +57 -0
- package/recipes/starlight/template/package.json +26 -0
- package/recipes/starlight/template/pages/blog/[slug].ts +125 -0
- package/recipes/starlight/template/pages/blog/index.ts +114 -0
- package/recipes/starlight/template/pages/blog/tags/[tag].ts +110 -0
- package/recipes/starlight/template/pages/docs/[slug].ts +147 -0
- package/recipes/starlight/template/pages/index.ts +135 -0
- package/recipes/starlight/template/public/styles/starlight.css +215 -0
- package/recipes/starlight/template/server/middleware/vite-dev.ts +29 -0
- package/recipes/starlight/template/server/routes/[...].ts +57 -0
- package/recipes/starlight/template/server/starlight.config.js +29 -0
- package/recipes/starlight/template/src/components/sl-aside.ts +91 -0
- package/recipes/starlight/template/src/components/sl-badge.ts +76 -0
- package/recipes/starlight/template/src/components/sl-card-grid.ts +34 -0
- package/recipes/starlight/template/src/components/sl-card.ts +91 -0
- package/recipes/starlight/template/src/components/sl-tab-item.ts +35 -0
- package/recipes/starlight/template/src/components/sl-tabs.ts +108 -0
- package/recipes/starlight/template/src/components/starlight-header.ts +152 -0
- package/recipes/starlight/template/src/components/starlight-page.ts +168 -0
- package/recipes/starlight/template/src/components/starlight-sidebar.ts +125 -0
- package/recipes/starlight/template/src/components/starlight-toc.ts +133 -0
- package/recipes/starlight/template/src/date-utils.ts +20 -0
- package/recipes/starlight/template/src/extract-headings.ts +68 -0
- package/recipes/starlight/template/src/route-meta.ts +16 -0
- package/recipes/starlight/template/tsconfig.json +14 -0
- package/recipes/starlight/template/vite.config.ts +19 -0
- package/src/scaffold.test.ts +148 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,138 @@
|
|
|
1
1
|
# create-litro
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 78fdaf6: Add `starlight` recipe — Astro Starlight-inspired docs + blog site scaffolded as Lit web components with full SSG support.
|
|
8
|
+
|
|
9
|
+
`npm create @beatzball/litro my-docs -- --recipe starlight` scaffolds a static docs + blog site with:
|
|
10
|
+
|
|
11
|
+
- **Layout components**: `<starlight-page>`, `<starlight-header>`, `<starlight-sidebar>`, `<starlight-toc>`
|
|
12
|
+
- **UI components**: `<sl-card>`, `<sl-card-grid>`, `<sl-badge>`, `<sl-aside>`, `<sl-tabs>`, `<sl-tab-item>`
|
|
13
|
+
- **Pages**: `/` (splash), `/docs/:slug`, `/blog`, `/blog/:slug`, `/blog/tags/:tag` — all SSG-prerendered
|
|
14
|
+
- **`--sl-*` CSS token layer** with dark/light mode toggle and no flash of unstyled content
|
|
15
|
+
- **`server/starlight.config.js`** — site title, nav links, sidebar groups
|
|
16
|
+
- SSG-only (no `--mode` flag needed)
|
|
17
|
+
|
|
18
|
+
## 0.1.4
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- 76d3bc7: fix: client-side navigation links do not work on first load
|
|
23
|
+
|
|
24
|
+
`<litro-link>` clicks were silently no-ops in scaffolded apps because of
|
|
25
|
+
three compounding bugs.
|
|
26
|
+
|
|
27
|
+
***
|
|
28
|
+
|
|
29
|
+
**Bug 1 — Empty route table on init** (`LitroOutlet`, `app.ts`)
|
|
30
|
+
|
|
31
|
+
`app.ts` set `outlet.routes` inside a `DOMContentLoaded` callback (a
|
|
32
|
+
macrotask). By that point Lit's first-update microtask had already fired,
|
|
33
|
+
so `firstUpdated()` ran with `routes = []` and the router was initialised
|
|
34
|
+
with no routes.
|
|
35
|
+
|
|
36
|
+
_Fix — `LitroOutlet`_: Replace `@property({ type: Array }) routes` with a
|
|
37
|
+
plain getter/setter. The setter calls `router.setRoutes()` directly when
|
|
38
|
+
the router is already initialised, without going through Lit's render cycle
|
|
39
|
+
(which would crash with "ChildPart has no parentNode" because
|
|
40
|
+
`firstUpdated()` removes Lit's internal marker nodes to give the router
|
|
41
|
+
ownership of the outlet's subtree).
|
|
42
|
+
|
|
43
|
+
_Fix — `app.ts`_ (fullstack recipe template + playground): Set
|
|
44
|
+
`outlet.routes` synchronously after imports rather than inside a
|
|
45
|
+
`DOMContentLoaded` callback. Module scripts are deferred by the browser;
|
|
46
|
+
by the time they execute the DOM is fully parsed and `<litro-outlet>` is
|
|
47
|
+
present.
|
|
48
|
+
|
|
49
|
+
***
|
|
50
|
+
|
|
51
|
+
**Bug 2 — Click handler never attached on SSR'd pages** (`LitroLink`)
|
|
52
|
+
|
|
53
|
+
`@lit-labs/ssr` adds `defer-hydration` to custom elements inside shadow
|
|
54
|
+
DOM. `@lit-labs/ssr-client` patches `LitElement.prototype.connectedCallback`
|
|
55
|
+
to block Lit's update cycle when this attribute is present. A `@click`
|
|
56
|
+
binding on the shadow `<a>` is a Lit binding — it is never attached until
|
|
57
|
+
`defer-hydration` is removed, which only happens when the parent component
|
|
58
|
+
hydrates. For page components that are never hydrated client-side (because
|
|
59
|
+
the router replaces the SSR content before they load), `<litro-link>`
|
|
60
|
+
elements inside them never receive a click handler.
|
|
61
|
+
|
|
62
|
+
This is why the playground appeared to work: its home page has no
|
|
63
|
+
`<litro-link>` elements. The fullstack generator template does, so clicks
|
|
64
|
+
on the SSR'd page were silently ignored.
|
|
65
|
+
|
|
66
|
+
_Fix_: Move the click handler from a `@click` binding on the shadow `<a>`
|
|
67
|
+
to the HOST element via `addEventListener('click', ...)` registered in
|
|
68
|
+
`connectedCallback()` (before `super.connectedCallback()`). The host
|
|
69
|
+
listener runs in `LitroLink`'s own `connectedCallback` override, which
|
|
70
|
+
executes before the `@lit-labs/ssr-client` patch checks for
|
|
71
|
+
`defer-hydration`. This ensures the handler is active immediately after the
|
|
72
|
+
element connects to the DOM, even for SSR'd elements on first load.
|
|
73
|
+
|
|
74
|
+
The shadow `<a>` is kept without a `@click` binding — it exists for
|
|
75
|
+
progressive enhancement (no-JS navigation) and accessibility (cursor,
|
|
76
|
+
focus, keyboard navigation).
|
|
77
|
+
|
|
78
|
+
***
|
|
79
|
+
|
|
80
|
+
**Bug 3 — `_resolve()` race condition** (`LitroRouter`)
|
|
81
|
+
|
|
82
|
+
`setRoutes()` calls `_resolve()` immediately for the current URL. If the
|
|
83
|
+
user clicks a link before that initial `_resolve()` completes (e.g. while
|
|
84
|
+
the page action's dynamic import is in flight), a second `_resolve()` call
|
|
85
|
+
starts concurrently. If the first call (for `/`) completes after the second
|
|
86
|
+
(for `/blog`), it overwrites the blog page with the home page.
|
|
87
|
+
|
|
88
|
+
_Fix_: Add a `_resolveToken` monotonic counter. Each `_resolve()` call
|
|
89
|
+
captures its own token at the start and checks it after every `await`. If
|
|
90
|
+
the token has advanced, a newer navigation superseded this one and the call
|
|
91
|
+
returns without touching the DOM.
|
|
92
|
+
|
|
93
|
+
***
|
|
94
|
+
|
|
95
|
+
**Bug 4 — `@property()` decorators silently dropped by esbuild TC39 transform** (`LitroLink`)
|
|
96
|
+
|
|
97
|
+
esbuild 0.21+ uses the TC39 Stage 3 decorator transform. In that mode,
|
|
98
|
+
Lit's `@property()` decorator only handles `accessor` fields; applied to a
|
|
99
|
+
plain field (`href = ''`) it is silently not applied. As a result `href`,
|
|
100
|
+
`target`, and `rel` were absent from `observedAttributes`, so
|
|
101
|
+
`attributeChangedCallback` was never called during element upgrade, leaving
|
|
102
|
+
`this.href = ''` forever regardless of what the HTML attribute said.
|
|
103
|
+
|
|
104
|
+
_Fix_: Replace the three `@property()` field decorators with a
|
|
105
|
+
`static override properties = { href, target, rel }` declaration. Lit reads
|
|
106
|
+
this static field at class-finalization time via `finalize()`, which runs
|
|
107
|
+
before the element is defined in `customElements`, ensuring the properties
|
|
108
|
+
are correctly registered in `observedAttributes`.
|
|
109
|
+
|
|
110
|
+
***
|
|
111
|
+
|
|
112
|
+
Adds a new `LitroOutlet.test.ts` test file (6 tests) covering the
|
|
113
|
+
synchronous and late-assignment code paths, the setter guard, SSR child
|
|
114
|
+
clearing, and the `LitroRouter` constructor call.
|
|
115
|
+
|
|
116
|
+
Updates `LitroLink.test.ts` (12 tests) to dispatch real `MouseEvent`s on
|
|
117
|
+
the host element (exercising the `addEventListener` path) rather than
|
|
118
|
+
calling the private handler directly by name.
|
|
119
|
+
|
|
120
|
+
***
|
|
121
|
+
|
|
122
|
+
**Template fix — `@state() declare serverData` incompatible with jiti/SSG**
|
|
123
|
+
|
|
124
|
+
The fullstack recipe template used `@state() declare serverData: T | null` to
|
|
125
|
+
narrow the `serverData: unknown` type inherited from `LitroPage`. The `declare`
|
|
126
|
+
modifier emits no runtime code, but jiti's oxc-transform (used in SSG mode to
|
|
127
|
+
load page files) throws "Fields with the 'declare' modifier cannot be
|
|
128
|
+
initialized here" under TC39 Stage 3 decorator mode.
|
|
129
|
+
|
|
130
|
+
_Fix_: Remove `@state() declare serverData` from both page templates. Use a
|
|
131
|
+
local type cast in `render()` instead: `const data = this.serverData as T | null`.
|
|
132
|
+
The property is already reactive (declared as `@state() serverData = null` in
|
|
133
|
+
`LitroPage`). Updated `LitroPage.ts` JSDoc and `DECISIONS.md` to document this
|
|
134
|
+
pattern and warn against `declare` fields in subclasses.
|
|
135
|
+
|
|
3
136
|
## 0.1.3
|
|
4
137
|
|
|
5
138
|
### Patch Changes
|
|
@@ -10,11 +10,14 @@ import '@beatzball/litro/runtime/LitroLink.js';
|
|
|
10
10
|
// emptyOutDir does not delete it between builds.
|
|
11
11
|
import { routes } from './routes.generated.js';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
// Set routes synchronously. By the time this module-script executes (all
|
|
14
|
+
// module scripts are deferred), the HTML is fully parsed and <litro-outlet>
|
|
15
|
+
// is already in the DOM. Setting outlet.routes here — before Lit's first
|
|
16
|
+
// update microtask fires — ensures firstUpdated() sees the real route table
|
|
17
|
+
// rather than the empty default, so the router starts correctly.
|
|
18
|
+
const outlet = document.querySelector('litro-outlet') as (Element & { routes: unknown }) | null;
|
|
19
|
+
if (outlet) {
|
|
20
|
+
outlet.routes = routes;
|
|
21
|
+
} else {
|
|
22
|
+
console.warn('[litro] <litro-outlet> not found — router will not start.');
|
|
23
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
|
-
import { customElement
|
|
2
|
+
import { customElement } from 'lit/decorators.js';
|
|
3
3
|
import { LitroPage } from '@beatzball/litro/runtime';
|
|
4
4
|
import { definePageData } from '@beatzball/litro';
|
|
5
5
|
import type { LitroLocation } from '@beatzball/litro-router';
|
|
@@ -27,8 +27,6 @@ export async function generateRoutes(): Promise<string[]> {
|
|
|
27
27
|
|
|
28
28
|
@customElement('page-blog-slug')
|
|
29
29
|
export class BlogPostPage extends LitroPage {
|
|
30
|
-
@state() declare serverData: PostData | null;
|
|
31
|
-
|
|
32
30
|
// Called by LitroRouter on client-side navigation to fetch data for the new slug.
|
|
33
31
|
override async fetchData(location: LitroLocation): Promise<PostData> {
|
|
34
32
|
const slug = location.params['slug'] ?? '';
|
|
@@ -40,10 +38,11 @@ export class BlogPostPage extends LitroPage {
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
render() {
|
|
41
|
+
const data = this.serverData as PostData | null;
|
|
43
42
|
return html`
|
|
44
43
|
<article>
|
|
45
|
-
<h1>${
|
|
46
|
-
<p>${
|
|
44
|
+
<h1>${data?.title ?? 'Loading…'}</h1>
|
|
45
|
+
<p>${data?.content ?? ''}</p>
|
|
47
46
|
<litro-link href="/blog">← Back to Blog</litro-link>
|
|
48
47
|
|
|
|
49
48
|
<litro-link href="/">← Home</litro-link>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
|
-
import { customElement
|
|
2
|
+
import { customElement } from 'lit/decorators.js';
|
|
3
3
|
import { LitroPage } from '@beatzball/litro/runtime';
|
|
4
4
|
import { definePageData } from '@beatzball/litro';
|
|
5
5
|
|
|
@@ -18,8 +18,6 @@ export const pageData = definePageData(async (_event) => {
|
|
|
18
18
|
|
|
19
19
|
@customElement('page-home')
|
|
20
20
|
export class HomePage extends LitroPage {
|
|
21
|
-
@state() declare serverData: HomeData | null;
|
|
22
|
-
|
|
23
21
|
// Called on client-side navigation (not on the initial SSR load).
|
|
24
22
|
override async fetchData() {
|
|
25
23
|
const res = await fetch('/api/hello');
|
|
@@ -27,11 +25,12 @@ export class HomePage extends LitroPage {
|
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
render() {
|
|
28
|
+
const data = this.serverData as HomeData | null;
|
|
30
29
|
if (this.loading) return html`<p>Loading…</p>`;
|
|
31
30
|
return html`
|
|
32
31
|
<main>
|
|
33
|
-
<h1>${
|
|
34
|
-
<p><small>Rendered at: ${
|
|
32
|
+
<h1>${data?.message ?? 'Welcome to {{projectName}}'}</h1>
|
|
33
|
+
<p><small>Rendered at: ${data?.timestamp ?? '—'}</small></p>
|
|
35
34
|
<nav>
|
|
36
35
|
<litro-link href="/blog">Go to Blog →</litro-link>
|
|
37
36
|
</nav>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe.config.d.ts","sourceRoot":"","sources":["../../../recipes/starlight/recipe.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,QAAA,MAAM,MAAM,EAAE,WAMb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const recipe = {
|
|
2
|
+
name: 'starlight',
|
|
3
|
+
displayName: 'Starlight (docs + blog)',
|
|
4
|
+
description: 'Astro Starlight-inspired docs and blog site with Lit web components',
|
|
5
|
+
mode: 'ssg',
|
|
6
|
+
contentLayer: 'content',
|
|
7
|
+
};
|
|
8
|
+
export default recipe;
|
|
9
|
+
//# sourceMappingURL=recipe.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe.config.js","sourceRoot":"","sources":["../../../recipes/starlight/recipe.config.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAgB;IAC1B,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,yBAAyB;IACtC,WAAW,EAAE,qEAAqE;IAClF,IAAI,EAAE,KAAK;IACX,YAAY,EAAE,SAAS;CACxB,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LitroRecipe } from '../../src/types.js';
|
|
2
|
+
|
|
3
|
+
const recipe: LitroRecipe = {
|
|
4
|
+
name: 'starlight',
|
|
5
|
+
displayName: 'Starlight (docs + blog)',
|
|
6
|
+
description: 'Astro Starlight-inspired docs and blog site with Lit web components',
|
|
7
|
+
mode: 'ssg',
|
|
8
|
+
contentLayer: 'content',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default recipe;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// CRITICAL: must be first — patches LitElement before any component is loaded.
|
|
2
|
+
import '@lit-labs/ssr-client/lit-element-hydrate-support.js';
|
|
3
|
+
|
|
4
|
+
// Client runtime: router outlet and link custom elements.
|
|
5
|
+
import '@beatzball/litro/runtime/LitroOutlet.js';
|
|
6
|
+
import '@beatzball/litro/runtime/LitroLink.js';
|
|
7
|
+
|
|
8
|
+
// Routes generated by the page scanner before each vite build.
|
|
9
|
+
import { routes } from './routes.generated.js';
|
|
10
|
+
|
|
11
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
12
|
+
const outlet = document.querySelector('litro-outlet') as (Element & { routes: unknown }) | null;
|
|
13
|
+
if (outlet) {
|
|
14
|
+
outlet.routes = routes;
|
|
15
|
+
} else {
|
|
16
|
+
console.warn('[litro] <litro-outlet> not found — router will not start.');
|
|
17
|
+
}
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "tags": ["posts"] }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Release Notes
|
|
3
|
+
date: 2026-01-10
|
|
4
|
+
description: What's new in this version of the Starlight recipe for Litro.
|
|
5
|
+
tags:
|
|
6
|
+
- posts
|
|
7
|
+
- release
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Starlight Recipe 0.1.0
|
|
11
|
+
|
|
12
|
+
The first release of the Starlight recipe for Litro. This scaffolds a fully static docs and blog site with Starlight's design system, implemented entirely as Lit web components.
|
|
13
|
+
|
|
14
|
+
### What's New
|
|
15
|
+
|
|
16
|
+
**Layout components**
|
|
17
|
+
|
|
18
|
+
- `<starlight-page>` — three-column grid layout (sidebar | content | TOC)
|
|
19
|
+
- `<starlight-header>` — top navigation with dark/light mode toggle
|
|
20
|
+
- `<starlight-sidebar>` — grouped navigation with active-item highlighting
|
|
21
|
+
- `<starlight-toc>` — table of contents extracted from headings
|
|
22
|
+
|
|
23
|
+
**UI components**
|
|
24
|
+
|
|
25
|
+
- `<sl-card>` and `<sl-card-grid>` — feature cards for the splash page
|
|
26
|
+
- `<sl-badge>` — inline color-coded chips (note, tip, caution, danger)
|
|
27
|
+
- `<sl-aside>` — callout boxes with icons and colored borders
|
|
28
|
+
- `<sl-tabs>` and `<sl-tab-item>` — tabbed content sections
|
|
29
|
+
|
|
30
|
+
**CSS design system**
|
|
31
|
+
|
|
32
|
+
All colors, fonts, and spacing are defined as `--sl-*` custom properties in `public/styles/starlight.css`. Override any token to customize the theme.
|
|
33
|
+
|
|
34
|
+
**Dark mode**
|
|
35
|
+
|
|
36
|
+
A FOUC-free theme toggle that reads/writes `localStorage` and sets `data-theme` on `<html>`. Implemented as a synchronous inline script in `<head>`.
|
|
37
|
+
|
|
38
|
+
**Content layer**
|
|
39
|
+
|
|
40
|
+
Docs and blog content live under `content/`. The Litro content layer scans Markdown files, parses frontmatter, renders HTML, and exposes everything via the `litro:content` virtual module.
|
|
41
|
+
|
|
42
|
+
### Breaking Changes
|
|
43
|
+
|
|
44
|
+
None — this is the initial release.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Welcome to {{projectName}}
|
|
3
|
+
date: 2026-01-15
|
|
4
|
+
description: Introducing the {{projectName}} docs and blog site, built with Litro and Starlight-inspired components.
|
|
5
|
+
tags:
|
|
6
|
+
- posts
|
|
7
|
+
- welcome
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Hello, World!
|
|
11
|
+
|
|
12
|
+
Welcome to **{{projectName}}** — a docs and blog site scaffolded with Litro's Starlight recipe.
|
|
13
|
+
|
|
14
|
+
This blog is powered by Litro's content layer. Each `.md` file in `content/blog/` becomes a post, available at `/blog/<slug>`. Write in plain Markdown; the framework handles rendering, tag indexing, and static generation.
|
|
15
|
+
|
|
16
|
+
## What's Included
|
|
17
|
+
|
|
18
|
+
- **Docs site** at `/docs/` — structured documentation with a sidebar, table of contents, and prev/next navigation
|
|
19
|
+
- **Blog** at `/blog/` — a chronological listing of posts with tag filtering
|
|
20
|
+
- **Dark mode** — a theme toggle in the header that persists to `localStorage`
|
|
21
|
+
- **CSS design tokens** — all colors, fonts, and spacing via `--sl-*` custom properties
|
|
22
|
+
|
|
23
|
+
## Writing Posts
|
|
24
|
+
|
|
25
|
+
Create a new `.md` file in `content/blog/`:
|
|
26
|
+
|
|
27
|
+
```markdown
|
|
28
|
+
---
|
|
29
|
+
title: My Post Title
|
|
30
|
+
date: 2026-02-01
|
|
31
|
+
description: A short summary.
|
|
32
|
+
tags:
|
|
33
|
+
- posts
|
|
34
|
+
- my-tag
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
Post body here.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Every post in `content/blog/` inherits the `posts` tag via `blog.11tydata.json`. List any additional tags in the post frontmatter — tag pages are generated automatically at `/blog/tags/<tag>`.
|
|
41
|
+
|
|
42
|
+
## Building
|
|
43
|
+
|
|
44
|
+
Run `pnpm build` to generate the static HTML for every route, then `pnpm preview` to serve it locally.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "section": "docs" }
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration
|
|
3
|
+
description: Configure your Starlight site — title, navigation, sidebar, and theme.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 3
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Site Config
|
|
9
|
+
|
|
10
|
+
All site-wide settings live in `server/starlight.config.js`:
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
export const siteConfig = {
|
|
14
|
+
title: 'My Docs',
|
|
15
|
+
description: 'Documentation and blog powered by Litro',
|
|
16
|
+
logo: null,
|
|
17
|
+
editUrlBase: null,
|
|
18
|
+
nav: [...],
|
|
19
|
+
sidebar: [...],
|
|
20
|
+
};
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### `title`
|
|
24
|
+
|
|
25
|
+
The site title shown in the header and used in `<title>` tags.
|
|
26
|
+
|
|
27
|
+
### `description`
|
|
28
|
+
|
|
29
|
+
A short description used in meta tags.
|
|
30
|
+
|
|
31
|
+
### `editUrlBase`
|
|
32
|
+
|
|
33
|
+
If set (e.g. `'https://github.com/you/repo/edit/main'`), each doc page shows an "Edit this page" link pointing to the source file on GitHub.
|
|
34
|
+
|
|
35
|
+
### `nav`
|
|
36
|
+
|
|
37
|
+
Top-level navigation links shown in the header:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
nav: [
|
|
41
|
+
{ label: 'Docs', href: '/docs/getting-started' },
|
|
42
|
+
{ label: 'Blog', href: '/blog' },
|
|
43
|
+
],
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### `sidebar`
|
|
47
|
+
|
|
48
|
+
Sidebar groups, each with a label and array of items. Each item has a `label` and a `slug` (the filename without `.md` under `content/docs/`):
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
sidebar: [
|
|
52
|
+
{
|
|
53
|
+
label: 'Start Here',
|
|
54
|
+
items: [
|
|
55
|
+
{ label: 'Getting Started', slug: 'getting-started' },
|
|
56
|
+
{ label: 'Installation', slug: 'installation' },
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## CSS Design Tokens
|
|
63
|
+
|
|
64
|
+
The visual theme is controlled by CSS custom properties in `public/styles/starlight.css`. Override any `--sl-*` variable to customize colors, fonts, and spacing:
|
|
65
|
+
|
|
66
|
+
```css
|
|
67
|
+
:root {
|
|
68
|
+
--sl-color-accent: #7c3aed; /* primary accent color */
|
|
69
|
+
--sl-font-sans: ui-sans-serif, system-ui, sans-serif;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Dark mode tokens are under `[data-theme='dark'] { ... }`.
|
|
74
|
+
|
|
75
|
+
## Dark / Light Mode
|
|
76
|
+
|
|
77
|
+
The theme toggle button in the header reads and writes `localStorage.getItem('sl-theme')`. A FOUC-prevention inline script (injected via `routeMeta.head`) sets `data-theme` on `<html>` before first paint.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
description: Learn how to set up and run your Litro Starlight docs site.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Welcome
|
|
9
|
+
|
|
10
|
+
You've just scaffolded a docs and blog site powered by **Litro** — a fullstack web framework that combines Lit web components with Nitro's server engine.
|
|
11
|
+
|
|
12
|
+
This site is a **static site** (SSG mode). Run `pnpm build` to pre-render every page to HTML, then `pnpm preview` to serve the output locally.
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
You'll need **Node.js 20+** and a package manager (`pnpm`, `npm`, or `yarn`).
|
|
17
|
+
|
|
18
|
+
## Install Dependencies
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Start the Dev Server
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The dev server starts on `http://localhost:3030`. Changes to Lit components and Markdown content are reflected immediately.
|
|
31
|
+
|
|
32
|
+
## Project Structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
my-docs/
|
|
36
|
+
pages/ Lit page components (filename = route)
|
|
37
|
+
src/
|
|
38
|
+
components/ Starlight layout and UI components
|
|
39
|
+
content/
|
|
40
|
+
docs/ Documentation Markdown files
|
|
41
|
+
blog/ Blog post Markdown files
|
|
42
|
+
server/
|
|
43
|
+
starlight.config.js Site title, nav, and sidebar config
|
|
44
|
+
public/
|
|
45
|
+
styles/ CSS design tokens (--sl-* variables)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Next Steps
|
|
49
|
+
|
|
50
|
+
- Edit `server/starlight.config.js` to update the site title, nav links, and sidebar groups.
|
|
51
|
+
- Add new docs pages to `content/docs/` — each `.md` file becomes a route under `/docs/`.
|
|
52
|
+
- Write blog posts in `content/blog/`.
|
|
53
|
+
- Run `pnpm build` to generate the static site.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Deploying
|
|
3
|
+
description: Deploy your Litro Starlight docs site to any CDN or static hosting platform.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 5
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Build
|
|
9
|
+
|
|
10
|
+
Generate the static HTML output:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pnpm build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This runs `litro build` under the hood, which:
|
|
17
|
+
|
|
18
|
+
1. Scans `pages/` to discover all routes
|
|
19
|
+
2. Calls `generateRoutes()` on each dynamic page to enumerate all paths
|
|
20
|
+
3. Pre-renders every path to a `.html` file in `.output/public/`
|
|
21
|
+
|
|
22
|
+
## Output
|
|
23
|
+
|
|
24
|
+
After a successful build, the static site is in `.output/public/`. You can serve this directory from any web server or CDN.
|
|
25
|
+
|
|
26
|
+
## Platforms
|
|
27
|
+
|
|
28
|
+
### Vercel
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# vercel.json
|
|
32
|
+
{
|
|
33
|
+
"outputDirectory": ".output/public"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or connect the repository in the Vercel dashboard — Vercel detects the static output automatically.
|
|
38
|
+
|
|
39
|
+
### Netlify
|
|
40
|
+
|
|
41
|
+
```toml
|
|
42
|
+
# netlify.toml
|
|
43
|
+
[build]
|
|
44
|
+
command = "pnpm build"
|
|
45
|
+
publish = ".output/public"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Cloudflare Pages
|
|
49
|
+
|
|
50
|
+
Set the build output directory to `.output/public` in the Cloudflare Pages dashboard.
|
|
51
|
+
|
|
52
|
+
### GitHub Pages
|
|
53
|
+
|
|
54
|
+
Add a GitHub Actions workflow:
|
|
55
|
+
|
|
56
|
+
```yaml
|
|
57
|
+
- name: Build
|
|
58
|
+
run: pnpm build
|
|
59
|
+
|
|
60
|
+
- name: Deploy
|
|
61
|
+
uses: peaceiris/actions-gh-pages@v3
|
|
62
|
+
with:
|
|
63
|
+
github_token: GITHUB_TOKEN # set via repository secrets
|
|
64
|
+
publish_dir: .output/public
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Custom Domain
|
|
68
|
+
|
|
69
|
+
Configure the custom domain in your hosting provider's dashboard. No Litro-specific changes are needed — the static output is plain HTML, CSS, and JS.
|
|
70
|
+
|
|
71
|
+
## Preview Locally
|
|
72
|
+
|
|
73
|
+
Before deploying, preview the production build locally:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pnpm preview
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This serves the `.output/` directory using Nitro's static preset server on `http://localhost:3030`.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Your First Page
|
|
3
|
+
description: Create a new docs page and add it to the sidebar navigation.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Create a Markdown File
|
|
9
|
+
|
|
10
|
+
Add a new `.md` file to `content/docs/`. The filename (without extension) becomes the URL slug.
|
|
11
|
+
|
|
12
|
+
For example, create `content/docs/my-topic.md`:
|
|
13
|
+
|
|
14
|
+
```markdown
|
|
15
|
+
---
|
|
16
|
+
title: My Topic
|
|
17
|
+
description: A brief description for SEO and the sidebar.
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Introduction
|
|
21
|
+
|
|
22
|
+
Write your documentation here using standard Markdown.
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Add It to the Sidebar
|
|
26
|
+
|
|
27
|
+
Open `server/starlight.config.js` and add an entry to the appropriate sidebar group:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
sidebar: [
|
|
31
|
+
{
|
|
32
|
+
label: 'My Section',
|
|
33
|
+
items: [
|
|
34
|
+
{ label: 'My Topic', slug: 'my-topic' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The `slug` must match the filename (without `.md`). The page will be available at `/docs/my-topic`.
|
|
41
|
+
|
|
42
|
+
## Frontmatter Fields
|
|
43
|
+
|
|
44
|
+
| Field | Type | Required | Description |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| `title` | `string` | Yes | Page title (shown in sidebar and `<title>`) |
|
|
47
|
+
| `description` | `string` | No | Short summary for SEO |
|
|
48
|
+
| `sidebar.order` | `number` | No | Controls sort order within the sidebar group |
|
|
49
|
+
| `sidebar.label` | `string` | No | Override the label shown in the sidebar |
|
|
50
|
+
|
|
51
|
+
## Markdown Features
|
|
52
|
+
|
|
53
|
+
This site supports **GitHub Flavored Markdown (GFM)**, including:
|
|
54
|
+
|
|
55
|
+
- Tables (like the one above)
|
|
56
|
+
- Fenced code blocks with syntax highlighting
|
|
57
|
+
- Task lists: `- [ ] Todo`
|
|
58
|
+
- Strikethrough: `~~text~~`
|
|
59
|
+
|
|
60
|
+
Headings (`##`, `###`, `####`) are automatically extracted to build the table of contents shown on the right side of each docs page.
|
|
61
|
+
|
|
62
|
+
## After Adding a Page
|
|
63
|
+
|
|
64
|
+
Run `pnpm build` to regenerate the static HTML for all routes, then `pnpm preview` to verify the new page appears in the sidebar and TOC.
|