stack-site-builder 1.22.0 → 1.23.1
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 +26 -0
- package/README.md +4 -1
- package/markdown.mjs +13 -8
- package/package.json +1 -1
- package/src/components/Glossary.astro +33 -0
- package/src/components/ToolAvatar.astro +7 -2
- package/src/i18n/ui.ts +4 -0
- package/src/styles/global.css +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,30 @@ 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.23.1] - 2026-07-29
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **Prose blockquote styling** — `>` blockquotes in reading content (courses,
|
|
19
|
+
articles, concepts, stacks and standalone pages) rendered with the browser
|
|
20
|
+
default and were nearly indistinguishable from a normal paragraph. They now
|
|
21
|
+
get a left accent rail and a faint neutral fill so a pulled-out passage reads
|
|
22
|
+
as set apart. Light/dark-aware (theme tokens), and no italic so it renders
|
|
23
|
+
cleanly on Korean prose. Two-trailing-space hard breaks inside the quote are
|
|
24
|
+
preserved as before.
|
|
25
|
+
|
|
26
|
+
## [1.23.0] - 2026-07-27
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **Wikilink `course` / `paper` targets** — glossary entries can now point at
|
|
31
|
+
the opt-in sections' detail pages: `{ label: '…', course: '<slug>' }` links
|
|
32
|
+
`[[Term]]` to `/course/<slug>/`, `paper: '<id>'` to `/paper/<id>/` (relative,
|
|
33
|
+
so locale- and base-path-agnostic like the existing stack/concept/article
|
|
34
|
+
targets). The glossary page lists them under new Courses/Papers sections
|
|
35
|
+
(flat — no dependency on the sites' opt-in course/paper category data), with
|
|
36
|
+
graduation-cap / scroll fallback glyphs.
|
|
37
|
+
|
|
14
38
|
## [1.22.0] - 2026-07-25
|
|
15
39
|
|
|
16
40
|
### Added
|
|
@@ -409,6 +433,8 @@ catalog sites from a thin content-only repository.
|
|
|
409
433
|
- **Standalone development setup** — a devcontainer and a minimal `playground/`
|
|
410
434
|
consuming site for developing and previewing the theme on its own.
|
|
411
435
|
|
|
436
|
+
[1.23.1]: https://github.com/CodeComposeStudio/stack-site-builder/compare/v1.23.0...v1.23.1
|
|
437
|
+
[1.23.0]: https://github.com/CodeComposeStudio/stack-site-builder/compare/v1.22.0...v1.23.0
|
|
412
438
|
[1.19.3]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.19.2...v1.19.3
|
|
413
439
|
[1.19.2]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.19.1...v1.19.2
|
|
414
440
|
[1.19.1]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.19.0...v1.19.1
|
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ export const collections = defineAasCollections({ categoryMap });
|
|
|
39
39
|
| `src/data/site.ts` | Site identity: name, repo URL (`repoNav: false` hides the header's GitHub link), the `locales` it ships, optional `sections` toggles, browser icons (`icons: { favicon, appleTouch, manifest }`), the `home` template, per-locale UI string overrides |
|
|
40
40
|
| `src/data/categories.ts` | The tool-catalog category tree (validated against content) |
|
|
41
41
|
| `src/data/concept-categories.ts` · `article-categories.ts` · `course-categories.ts` · `product-categories.ts` · `paper-categories.ts` (opt-in) | Taxonomies for concepts / articles / courses / products / papers |
|
|
42
|
-
| `src/data/glossary.mjs` | `[[Term]]` wikilink targets |
|
|
42
|
+
| `src/data/glossary.mjs` | `[[Term]]` wikilink targets — each entry links a term to a `stack` / `concept` / `article` / `course` / `paper` page, an external `href`, or is a definition-only term (`def`) |
|
|
43
43
|
| `src/content/{stacks,concepts,courses,products,papers,articles,slides}/` | The content, one MDX file per locale |
|
|
44
44
|
| `src/content/pages/` | Standalone top-level pages (e.g. an About/소개), rendered at `/<slug>/` and optionally linked in the header nav |
|
|
45
45
|
| `public/` · `samples/` | Logos/favicons and runnable sample projects |
|
|
@@ -202,6 +202,9 @@ import Bookmark from 'stack-site-builder/components/Bookmark.astro';
|
|
|
202
202
|
<Bookmark url="https://…" title="…" description="…" />
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
+
Markdown/MDX authoring gotchas (nested-list indentation, blockquotes, hard
|
|
206
|
+
breaks, wikilinks): `docs/content-authoring.md`.
|
|
207
|
+
|
|
205
208
|
## RSS
|
|
206
209
|
|
|
207
210
|
The articles collection feeds `/rss.xml` (default locale) and
|
package/markdown.mjs
CHANGED
|
@@ -230,7 +230,8 @@ function remarkSlideDirectives() {
|
|
|
230
230
|
|
|
231
231
|
// Turn `[[Term]]` (and `[[Term|display text]]`) wikilinks into links, resolving
|
|
232
232
|
// each against the site's central glossary (passed as an option). Internal targets
|
|
233
|
-
// emit a
|
|
233
|
+
// (stack/concept/article/course/paper) emit a `../<kind>/<slug>/` relative form
|
|
234
|
+
// (locale- and base-agnostic), with
|
|
234
235
|
// the number of `../` set by how deep the source page sits in its locale (see `up`
|
|
235
236
|
// below); external `href` entries pass through and get
|
|
236
237
|
// target="_blank" from rehype-external-links downstream. An unknown term throws,
|
|
@@ -344,19 +345,23 @@ function remarkGlossary({ glossary, locales = ['en', 'ko'], defaultLocale = 'en'
|
|
|
344
345
|
? `${up}concept/${entry.concept}/`
|
|
345
346
|
: entry.article
|
|
346
347
|
? `${up}article/${entry.article}/`
|
|
347
|
-
: entry.
|
|
348
|
-
? entry.
|
|
349
|
-
:
|
|
350
|
-
? `${up}
|
|
351
|
-
:
|
|
348
|
+
: entry.course
|
|
349
|
+
? `${up}course/${entry.course}/`
|
|
350
|
+
: entry.paper
|
|
351
|
+
? `${up}paper/${entry.paper}/`
|
|
352
|
+
: entry.href
|
|
353
|
+
? entry.href
|
|
354
|
+
: def
|
|
355
|
+
? `${up}glossary/#${id}`
|
|
356
|
+
: null;
|
|
352
357
|
if (!url)
|
|
353
358
|
throw new Error(
|
|
354
|
-
`[glossary] term "[[${m[1]}]]" needs one of stack/concept/article/href/def`,
|
|
359
|
+
`[glossary] term "[[${m[1]}]]" needs one of stack/concept/article/course/paper/href/def`,
|
|
355
360
|
);
|
|
356
361
|
if (anchor) {
|
|
357
362
|
// A def-only target already carries its own hash — an extra
|
|
358
363
|
// anchor is a mistake, so fail the build like an unknown term.
|
|
359
|
-
if (!entry.stack && !entry.concept && !entry.article && !entry.href)
|
|
364
|
+
if (!entry.stack && !entry.concept && !entry.article && !entry.course && !entry.paper && !entry.href)
|
|
360
365
|
throw new Error(
|
|
361
366
|
`[glossary] "[[${m[1]}]]" — a definition-only term can't take a #anchor`,
|
|
362
367
|
);
|
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.23.1",
|
|
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": {
|
|
@@ -19,6 +19,8 @@ type Entry = {
|
|
|
19
19
|
stack?: string;
|
|
20
20
|
concept?: string;
|
|
21
21
|
article?: string;
|
|
22
|
+
course?: string;
|
|
23
|
+
paper?: string;
|
|
22
24
|
href?: string;
|
|
23
25
|
def?: string | { ko: string; en: string };
|
|
24
26
|
};
|
|
@@ -54,6 +56,11 @@ const articleBySlug = new Map(articles.map((a) => [articleSlugOf(a), a]));
|
|
|
54
56
|
const tools: Term[] = [];
|
|
55
57
|
const conceptTerms: Term[] = [];
|
|
56
58
|
const articleTerms: Term[] = [];
|
|
59
|
+
// Courses/papers are opt-in sections whose category data a site may not have,
|
|
60
|
+
// so their terms render as flat groups (no @aas-data/{course,paper}-categories
|
|
61
|
+
// import — that would break sites that don't supply those files).
|
|
62
|
+
const courseTerms: Term[] = [];
|
|
63
|
+
const paperTerms: Term[] = [];
|
|
57
64
|
const defTerms: Term[] = [];
|
|
58
65
|
const external: Term[] = [];
|
|
59
66
|
|
|
@@ -110,6 +117,30 @@ for (const [id, e] of Object.entries(map)) {
|
|
|
110
117
|
catLabel: top?.label[lang] ?? '',
|
|
111
118
|
search: `${label} ${leaf?.label[lang] ?? ''} ${top?.label[lang] ?? ''}`.toLowerCase(),
|
|
112
119
|
});
|
|
120
|
+
} else if (e.course) {
|
|
121
|
+
courseTerms.push({
|
|
122
|
+
id,
|
|
123
|
+
label,
|
|
124
|
+
href: getRelativeLocaleUrl(lang, `course/${e.course}/`),
|
|
125
|
+
subtitle: def,
|
|
126
|
+
external: false,
|
|
127
|
+
icon: { name: label, fallback: 'course' },
|
|
128
|
+
catId: '',
|
|
129
|
+
catLabel: '',
|
|
130
|
+
search: `${label} ${def}`.toLowerCase(),
|
|
131
|
+
});
|
|
132
|
+
} else if (e.paper) {
|
|
133
|
+
paperTerms.push({
|
|
134
|
+
id,
|
|
135
|
+
label,
|
|
136
|
+
href: getRelativeLocaleUrl(lang, `paper/${e.paper}/`),
|
|
137
|
+
subtitle: def,
|
|
138
|
+
external: false,
|
|
139
|
+
icon: { name: label, fallback: 'paper' },
|
|
140
|
+
catId: '',
|
|
141
|
+
catLabel: '',
|
|
142
|
+
search: `${label} ${def}`.toLowerCase(),
|
|
143
|
+
});
|
|
113
144
|
} else if (e.href) {
|
|
114
145
|
external.push({
|
|
115
146
|
id,
|
|
@@ -162,6 +193,8 @@ const kinds = [
|
|
|
162
193
|
{ key: 'tool', title: t('glossary.tool'), groups: groupBy(tools, rootCategories.map((c) => c.id)) },
|
|
163
194
|
{ key: 'concept', title: t('glossary.concept'), groups: groupBy(conceptTerms, conceptTree.roots.map((c) => c.id)) },
|
|
164
195
|
{ key: 'article', title: t('glossary.article'), groups: groupBy(articleTerms, articleTree.roots.map((c) => c.id)) },
|
|
196
|
+
{ key: 'course', title: t('glossary.course'), groups: flat(courseTerms) },
|
|
197
|
+
{ key: 'paper', title: t('glossary.paper'), groups: flat(paperTerms) },
|
|
165
198
|
{ key: 'term', title: t('glossary.term'), groups: flat(defTerms) },
|
|
166
199
|
{ key: 'external', title: t('glossary.external'), groups: flat(external) },
|
|
167
200
|
].filter((k) => k.groups.length > 0);
|
|
@@ -30,12 +30,17 @@ const icons: Record<string, string> = {
|
|
|
30
30
|
'<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5V19A9 3 0 0 0 21 19V5"/><path d="M3 12A9 3 0 0 0 21 12"/>',
|
|
31
31
|
observability: '<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>',
|
|
32
32
|
// A concept/idea (lightbulb), an article (file-text, matching the Writing nav
|
|
33
|
-
// icon),
|
|
34
|
-
// fallbacks for avatars without
|
|
33
|
+
// icon), a course (graduation cap), a paper (scroll), an external link
|
|
34
|
+
// (globe), and a plain term (book) — glossary fallbacks for avatars without
|
|
35
|
+
// a logo.
|
|
35
36
|
concept:
|
|
36
37
|
'<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/>',
|
|
37
38
|
article:
|
|
38
39
|
'<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"/>',
|
|
40
|
+
course:
|
|
41
|
+
'<path d="M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z"/><path d="M22 10v6"/><path d="M6 12.5V16a6 3 0 0 0 12 0v-3.5"/>',
|
|
42
|
+
paper:
|
|
43
|
+
'<path d="M15 12h-5"/><path d="M15 8h-5"/><path d="M19 17V5a2 2 0 0 0-2-2H4"/><path d="M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3"/>',
|
|
39
44
|
external:
|
|
40
45
|
'<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',
|
|
41
46
|
term: '<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/>',
|
package/src/i18n/ui.ts
CHANGED
|
@@ -110,6 +110,8 @@ export const ui = {
|
|
|
110
110
|
'glossary.tool': 'Tools',
|
|
111
111
|
'glossary.concept': 'Concepts',
|
|
112
112
|
'glossary.article': 'Writing',
|
|
113
|
+
'glossary.course': 'Courses',
|
|
114
|
+
'glossary.paper': 'Papers',
|
|
113
115
|
'glossary.term': 'Terms',
|
|
114
116
|
'glossary.external': 'External',
|
|
115
117
|
'glossary.search': 'Search terms…',
|
|
@@ -287,6 +289,8 @@ export const ui = {
|
|
|
287
289
|
'glossary.tool': '도구',
|
|
288
290
|
'glossary.concept': '개념',
|
|
289
291
|
'glossary.article': '글',
|
|
292
|
+
'glossary.course': '강의',
|
|
293
|
+
'glossary.paper': '논문',
|
|
290
294
|
'glossary.term': '용어',
|
|
291
295
|
'glossary.external': '외부',
|
|
292
296
|
'glossary.search': '용어 검색…',
|
package/src/styles/global.css
CHANGED
|
@@ -581,6 +581,24 @@ summary {
|
|
|
581
581
|
list-style: decimal;
|
|
582
582
|
padding-left: 1.25rem;
|
|
583
583
|
}
|
|
584
|
+
/* Blockquotes — a quiet left-accent rail with a faint neutral fill, so a
|
|
585
|
+
pulled-out passage reads as set apart from the running text. No italic: it
|
|
586
|
+
renders on Korean prose too, where slanted CJK looks wrong. First/last child
|
|
587
|
+
margins collapse so the quote hugs its own padding. */
|
|
588
|
+
.prose :where(blockquote) {
|
|
589
|
+
margin: 1.25rem 0;
|
|
590
|
+
padding: 0.75rem 1.15rem;
|
|
591
|
+
border-left: 3px solid var(--aas-accent);
|
|
592
|
+
border-radius: 0 0.5rem 0.5rem 0;
|
|
593
|
+
background: var(--aas-tint);
|
|
594
|
+
color: color-mix(in srgb, var(--aas-text) 88%, transparent);
|
|
595
|
+
}
|
|
596
|
+
.prose :where(blockquote > :first-child) {
|
|
597
|
+
margin-top: 0;
|
|
598
|
+
}
|
|
599
|
+
.prose :where(blockquote > :last-child) {
|
|
600
|
+
margin-bottom: 0;
|
|
601
|
+
}
|
|
584
602
|
.prose :where(a) {
|
|
585
603
|
color: var(--aas-accent);
|
|
586
604
|
text-decoration: none;
|