stack-site-builder 1.12.0 → 1.13.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 +14 -0
- package/README.md +29 -1
- package/index.d.ts +10 -0
- package/index.mjs +20 -1
- package/package.json +1 -1
- package/src/layouts/BaseLayout.astro +11 -1
- package/src/lib/sections.ts +34 -0
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,19 @@ content schema, while a consuming site supplies only content, taxonomy data and
|
|
|
11
11
|
config. Sites track the theme with `pnpm up stack-site-builder`, so each release
|
|
12
12
|
here is a plain version bump they pull in.
|
|
13
13
|
|
|
14
|
+
## [1.13.0] - 2026-07-20
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Optional sections** — a site can turn off any of the secondary sections
|
|
19
|
+
(concepts, articles, samples, slides, glossary, and the standalone `pages`
|
|
20
|
+
collection); the core catalog stays on. Disabling one removes both its routes
|
|
21
|
+
and its header-nav item. Declare `sections` in `src/data/site.ts` (hides the
|
|
22
|
+
nav item) and forward it to `aasTheme({ sections })` in astro.config (skips the
|
|
23
|
+
routes); the key type (`SectionKey`) is exported from the theme, so
|
|
24
|
+
`satisfies Partial<Record<SectionKey, boolean>>` gives autocomplete of the
|
|
25
|
+
valid keys. The playground drops `slides` to demonstrate.
|
|
26
|
+
|
|
14
27
|
## [1.12.0] - 2026-07-20
|
|
15
28
|
|
|
16
29
|
Locales are now **site-configurable**. The theme was wired to exactly two
|
|
@@ -107,6 +120,7 @@ catalog sites from a thin content-only repository.
|
|
|
107
120
|
- **Standalone development setup** — a devcontainer and a minimal `playground/`
|
|
108
121
|
consuming site for developing and previewing the theme on its own.
|
|
109
122
|
|
|
123
|
+
[1.13.0]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.12.0...v1.13.0
|
|
110
124
|
[1.12.0]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.11.0...v1.12.0
|
|
111
125
|
[1.11.0]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.10.0...v1.11.0
|
|
112
126
|
[1.10.0]: https://github.com/CodeCompose7/stack-site-builder/releases/tag/v1.10.0
|
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ export const collections = defineAasCollections({ categoryMap });
|
|
|
34
34
|
|
|
35
35
|
| Where | What |
|
|
36
36
|
| --- | --- |
|
|
37
|
-
| `src/data/site.ts` | Site identity: name, repo URL, the `locales` it ships, per-locale UI string overrides |
|
|
37
|
+
| `src/data/site.ts` | Site identity: name, repo URL, the `locales` it ships, optional `sections` toggles, per-locale UI string overrides |
|
|
38
38
|
| `src/data/categories.ts` | The tool-catalog category tree (validated against content) |
|
|
39
39
|
| `src/data/concept-categories.ts` · `article-categories.ts` | Taxonomies for concepts / articles |
|
|
40
40
|
| `src/data/glossary.mjs` | `[[Term]]` wikilink targets |
|
|
@@ -62,3 +62,31 @@ locale from one source. To add a language (say Japanese):
|
|
|
62
62
|
labels the same way you did for the built-in locales.
|
|
63
63
|
|
|
64
64
|
No theme files change — adding a locale is entirely site config and content.
|
|
65
|
+
|
|
66
|
+
## Sections
|
|
67
|
+
|
|
68
|
+
The core catalog (home, tool detail, categories, tags, vendors) is always on.
|
|
69
|
+
The rest are opt-out — **concepts, articles, samples, slides, glossary** and the
|
|
70
|
+
standalone **pages** collection (About/소개, …) — so a site can ship only what it
|
|
71
|
+
needs. Turning one off removes both its routes and its header-nav item. (`pages`
|
|
72
|
+
also has finer control: each page's `nav` / `draft` frontmatter, or simply not
|
|
73
|
+
authoring it.)
|
|
74
|
+
|
|
75
|
+
Declare the toggles once in `src/data/site.ts` and forward them to the theme in
|
|
76
|
+
astro.config (which needs them to skip route injection). Import `SectionKey` from
|
|
77
|
+
the theme so `satisfies` lists the valid keys as you type:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// src/data/site.ts
|
|
81
|
+
import type { SectionKey } from 'stack-site-builder';
|
|
82
|
+
export const site = {
|
|
83
|
+
/* … */
|
|
84
|
+
sections: { slides: false } satisfies Partial<Record<SectionKey, boolean>>,
|
|
85
|
+
};
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
// astro.config.mjs
|
|
90
|
+
import { site } from './src/data/site';
|
|
91
|
+
integrations: [aasTheme({ glossary, sections: site.sections })];
|
|
92
|
+
```
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import type { AstroIntegration } from 'astro';
|
|
2
2
|
|
|
3
|
+
/** Optional content sections that a site can turn off. `pages` is the
|
|
4
|
+
* standalone-pages collection (About/소개, …). */
|
|
5
|
+
export type SectionKey = 'concepts' | 'articles' | 'samples' | 'slides' | 'glossary' | 'pages';
|
|
6
|
+
|
|
3
7
|
export interface AasThemeOptions {
|
|
4
8
|
/** The site's glossary (`src/data/glossary.mjs`) — `[[wikilink]]` targets. */
|
|
5
9
|
glossary: Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Turn optional sections off (all on by default), e.g. `{ slides: false }`.
|
|
12
|
+
* A disabled section's routes aren't injected; pass the same object to
|
|
13
|
+
* `src/data/site.ts` `sections` so its header-nav item is hidden too.
|
|
14
|
+
*/
|
|
15
|
+
sections?: Partial<Record<SectionKey, boolean>>;
|
|
6
16
|
}
|
|
7
17
|
|
|
8
18
|
/**
|
package/index.mjs
CHANGED
|
@@ -54,13 +54,29 @@ function patternOf(file) {
|
|
|
54
54
|
return `/${p}`.replace(/\/$/, '') || '/';
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// Which optional section each page belongs to (null = always-on core route).
|
|
58
|
+
// Mirrors SectionKey in src/lib/sections.ts.
|
|
59
|
+
/** @param {string} file @returns {string | null} */
|
|
60
|
+
function sectionOf(file) {
|
|
61
|
+
if (file.startsWith('concept/')) return 'concepts';
|
|
62
|
+
if (file.startsWith('article/')) return 'articles';
|
|
63
|
+
if (file.startsWith('sample/')) return 'samples';
|
|
64
|
+
if (file.startsWith('slides/')) return 'slides';
|
|
65
|
+
if (file === 'glossary.astro') return 'glossary';
|
|
66
|
+
if (file === '[page].astro') return 'pages';
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
/**
|
|
58
71
|
* @param {object} opts
|
|
59
72
|
* @param {Record<string, any>} opts.glossary — the site's glossary
|
|
60
73
|
* (`src/data/glossary.mjs`), used by `[[wikilink]]` resolution.
|
|
74
|
+
* @param {Partial<Record<string, boolean>>} [opts.sections] — optional-section
|
|
75
|
+
* toggles (`{ slides: false }`); a disabled section's routes are not injected.
|
|
76
|
+
* Keep it in sync with `src/data/site.ts` `sections` (which hides the nav item).
|
|
61
77
|
* @returns {import('astro').AstroIntegration[]}
|
|
62
78
|
*/
|
|
63
|
-
export default function aasTheme({ glossary }) {
|
|
79
|
+
export default function aasTheme({ glossary, sections = {} }) {
|
|
64
80
|
/** @type {import('astro').AstroIntegration} */
|
|
65
81
|
const core = {
|
|
66
82
|
name: 'stack-site-builder',
|
|
@@ -77,7 +93,10 @@ export default function aasTheme({ glossary }) {
|
|
|
77
93
|
// A single physical page tree under `[...lang]/` serves every locale: the
|
|
78
94
|
// default at the root, each other under `/<code>/`. Each page's
|
|
79
95
|
// getStaticPaths enumerates the locales, so adding one needs no new files.
|
|
96
|
+
// Skip a page whose optional section the site turned off (`{ slides: false }`).
|
|
80
97
|
for (const file of PAGES) {
|
|
98
|
+
const section = sectionOf(file);
|
|
99
|
+
if (section && sections[section] === false) continue;
|
|
81
100
|
injectRoute({
|
|
82
101
|
pattern: patternOf(`[...lang]/${file}`),
|
|
83
102
|
entrypoint: `stack-site-builder/pages/[...lang]/${file}`,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stack-site-builder",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.13.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "The engine behind the awesome-*-stack catalog sites: an Astro theme with the catalog/concepts/articles/slides/samples routes, components, styles and markdown pipeline. Sites provide content, taxonomy data and config.",
|
|
7
7
|
"repository": {
|
|
@@ -7,6 +7,7 @@ import LanguageSwitcher from '../components/LanguageSwitcher.astro';
|
|
|
7
7
|
import ThemeToggle from '../components/ThemeToggle.astro';
|
|
8
8
|
import BackToTop from '../components/BackToTop.astro';
|
|
9
9
|
import { getNavPages, pageSlugOf } from '../lib/pages';
|
|
10
|
+
import { sectionEnabled, type SectionKey } from '../lib/sections';
|
|
10
11
|
|
|
11
12
|
interface Props {
|
|
12
13
|
title: string;
|
|
@@ -43,12 +44,13 @@ const navPages = await getNavPages(lang);
|
|
|
43
44
|
// layouts never drift: an icon-only row (≥sm) and a labelled dropdown menu
|
|
44
45
|
// (<sm, so a phone header stays to a few controls instead of a long icon run).
|
|
45
46
|
// `svg` is the icon's inner markup (drawn into a shared <svg> shell below).
|
|
46
|
-
const
|
|
47
|
+
const allNavItems: {
|
|
47
48
|
href: string;
|
|
48
49
|
label: string;
|
|
49
50
|
svg: string;
|
|
50
51
|
external?: boolean;
|
|
51
52
|
keepFilters?: boolean;
|
|
53
|
+
section?: SectionKey;
|
|
52
54
|
}[] = [
|
|
53
55
|
{
|
|
54
56
|
href: `${home}#categories`,
|
|
@@ -59,31 +61,37 @@ const navItems: {
|
|
|
59
61
|
{
|
|
60
62
|
href: getRelativeLocaleUrl(lang, 'concept/'),
|
|
61
63
|
label: t('nav.concepts'),
|
|
64
|
+
section: 'concepts',
|
|
62
65
|
svg: '<path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/>',
|
|
63
66
|
},
|
|
64
67
|
{
|
|
65
68
|
href: getRelativeLocaleUrl(lang, 'article/'),
|
|
66
69
|
label: t('nav.blog'),
|
|
70
|
+
section: 'articles',
|
|
67
71
|
svg: '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M16 13H8"/><path d="M16 17H8"/><path d="M10 9H8"/>',
|
|
68
72
|
},
|
|
69
73
|
{
|
|
70
74
|
href: getRelativeLocaleUrl(lang, 'sample/'),
|
|
71
75
|
label: t('nav.samples'),
|
|
76
|
+
section: 'samples',
|
|
72
77
|
svg: '<polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/>',
|
|
73
78
|
},
|
|
74
79
|
{
|
|
75
80
|
href: getRelativeLocaleUrl(lang, 'slides/'),
|
|
76
81
|
label: t('nav.slides'),
|
|
82
|
+
section: 'slides',
|
|
77
83
|
svg: '<path d="M2 3h20"/><path d="M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3"/><path d="m7 21 5-5 5 5"/><path d="M12 12v9"/>',
|
|
78
84
|
},
|
|
79
85
|
{
|
|
80
86
|
href: getRelativeLocaleUrl(lang, 'glossary/'),
|
|
81
87
|
label: t('nav.glossary'),
|
|
88
|
+
section: 'glossary',
|
|
82
89
|
svg: '<path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/>',
|
|
83
90
|
},
|
|
84
91
|
...navPages.map((p) => ({
|
|
85
92
|
href: getRelativeLocaleUrl(lang, `${pageSlugOf(p)}/`),
|
|
86
93
|
label: p.data.navLabel ?? p.data.title,
|
|
94
|
+
section: 'pages' as SectionKey,
|
|
87
95
|
svg: '<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>',
|
|
88
96
|
})),
|
|
89
97
|
{
|
|
@@ -93,6 +101,8 @@ const navItems: {
|
|
|
93
101
|
svg: '<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C4 2 3 2 3 2c-.3 1.15-.3 2.35 0 3.5A5.4 5.4 0 0 0 2 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/>',
|
|
94
102
|
},
|
|
95
103
|
];
|
|
104
|
+
// Drop the nav links for sections the site turned off (their routes aren't built).
|
|
105
|
+
const navItems = allNavItems.filter((item) => !item.section || sectionEnabled(item.section));
|
|
96
106
|
---
|
|
97
107
|
|
|
98
108
|
<!doctype html>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { site } from '@aas-data/site';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Optional content sections a site can turn off. The core catalog (home, stack
|
|
5
|
+
* detail, categories, tags, vendors) is always on; these are opt-out. Disabling
|
|
6
|
+
* one removes both its routes and its header-nav item (routes are skipped in the
|
|
7
|
+
* integration, the nav link in BaseLayout).
|
|
8
|
+
*
|
|
9
|
+
* `pages` is the standalone-pages collection (About/소개, contact, …); turning it
|
|
10
|
+
* off drops every page and its nav item at once — finer control is per-page via
|
|
11
|
+
* the `nav` / `draft` frontmatter, or by not authoring the page.
|
|
12
|
+
*
|
|
13
|
+
* A site sets overrides in `src/data/site.ts` (`sections`), which astro.config
|
|
14
|
+
* also forwards to the theme integration for route filtering. Omitted = enabled.
|
|
15
|
+
*/
|
|
16
|
+
export type SectionKey = 'concepts' | 'articles' | 'samples' | 'slides' | 'glossary' | 'pages';
|
|
17
|
+
|
|
18
|
+
const DEFAULTS: Record<SectionKey, boolean> = {
|
|
19
|
+
concepts: true,
|
|
20
|
+
articles: true,
|
|
21
|
+
samples: true,
|
|
22
|
+
slides: true,
|
|
23
|
+
glossary: true,
|
|
24
|
+
pages: true,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Whether each optional section is enabled, after applying the site's overrides. */
|
|
28
|
+
export const sections: Record<SectionKey, boolean> = {
|
|
29
|
+
...DEFAULTS,
|
|
30
|
+
...((site as { sections?: Partial<Record<SectionKey, boolean>> }).sections ?? {}),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** True unless the site explicitly turned `key` off. */
|
|
34
|
+
export const sectionEnabled = (key: SectionKey): boolean => sections[key];
|