stack-site-builder 1.23.0 → 1.23.2
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 +46 -0
- package/README.md +3 -0
- package/markdown.mjs +27 -0
- package/package.json +1 -1
- package/src/lib/md-tables.ts +21 -0
- package/src/lib/project.ts +14 -11
- package/src/lib/samples.ts +2 -1
- package/src/styles/global.css +115 -4
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,50 @@ 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.2] - 2026-08-06
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **Wide tables scroll instead of cramming their cells** — a table wider than its
|
|
19
|
+
column had no way out: it needs `display: table` for real column sizing, which
|
|
20
|
+
makes `overflow-x` on the table itself a no-op, so every cell was squeezed into
|
|
21
|
+
a stack of wrapped lines (a 3-column table with 1561px of natural content
|
|
22
|
+
rendered 920px wide and 3.6x its natural height, breaking code samples
|
|
23
|
+
mid-token). Every rendered table now sits in a `.aas-table-scroll` box that
|
|
24
|
+
takes the scrolling while the table keeps its natural widths — on both render
|
|
25
|
+
paths: `rehypeTableScroll` for content collections, `withTableScroll`
|
|
26
|
+
(`lib/md-tables.ts`) for the MarkdownIt paths behind READMEs and sample
|
|
27
|
+
descriptions. In a reading column the wrapper shrinks to the table and centers,
|
|
28
|
+
so a narrow table keeps its own width instead of being stretched; on slides a
|
|
29
|
+
wide table slides sideways. A table that arrives without a wrapper (raw HTML in
|
|
30
|
+
MDX, say) still behaves exactly as before.
|
|
31
|
+
- **Slide diagrams render full-size** — the generic caps (`pre` 62vh, svg 52vh)
|
|
32
|
+
don't know how much room the slide fill rules actually handed the diagram — on
|
|
33
|
+
a full-height slide that box is ~78vh — so a tall flowchart was scaled to fit
|
|
34
|
+
52vh and the unused width was letterboxed as empty margins either side.
|
|
35
|
+
Diagrams now size against the box they were given (measured on a 1958x2000
|
|
36
|
+
flowchart: 0.34 -> 0.75 scale). `compact`, `.aas-split.scroll` and `scroll-x`
|
|
37
|
+
manage their own overflow and are excluded, so they render exactly as before.
|
|
38
|
+
- **Mermaid subgraph titles stop overlapping** — mermaid draws labels as real
|
|
39
|
+
HTML in a `<foreignObject>` and sizes nodes and cluster frames from the
|
|
40
|
+
measured box; mermaid 11 wraps label text in a `<p>`, which inherited the
|
|
41
|
+
page's paragraph typography (26px/41px on a slide) while mermaid reserves only
|
|
42
|
+
~25px for a cluster title, so every subgraph title overlapped the first node
|
|
43
|
+
inside it by ~16px. Label typography is pinned back to mermaid's own so its
|
|
44
|
+
measurements hold.
|
|
45
|
+
|
|
46
|
+
## [1.23.1] - 2026-07-29
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- **Prose blockquote styling** — `>` blockquotes in reading content (courses,
|
|
51
|
+
articles, concepts, stacks and standalone pages) rendered with the browser
|
|
52
|
+
default and were nearly indistinguishable from a normal paragraph. They now
|
|
53
|
+
get a left accent rail and a faint neutral fill so a pulled-out passage reads
|
|
54
|
+
as set apart. Light/dark-aware (theme tokens), and no italic so it renders
|
|
55
|
+
cleanly on Korean prose. Two-trailing-space hard breaks inside the quote are
|
|
56
|
+
preserved as before.
|
|
57
|
+
|
|
14
58
|
## [1.23.0] - 2026-07-27
|
|
15
59
|
|
|
16
60
|
### Added
|
|
@@ -421,6 +465,8 @@ catalog sites from a thin content-only repository.
|
|
|
421
465
|
- **Standalone development setup** — a devcontainer and a minimal `playground/`
|
|
422
466
|
consuming site for developing and previewing the theme on its own.
|
|
423
467
|
|
|
468
|
+
[1.23.2]: https://github.com/CodeComposeStudio/stack-site-builder/compare/v1.23.1...v1.23.2
|
|
469
|
+
[1.23.1]: https://github.com/CodeComposeStudio/stack-site-builder/compare/v1.23.0...v1.23.1
|
|
424
470
|
[1.23.0]: https://github.com/CodeComposeStudio/stack-site-builder/compare/v1.22.0...v1.23.0
|
|
425
471
|
[1.19.3]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.19.2...v1.19.3
|
|
426
472
|
[1.19.2]: https://github.com/CodeCompose7/stack-site-builder/compare/v1.19.1...v1.19.2
|
package/README.md
CHANGED
|
@@ -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
|
@@ -94,6 +94,32 @@ function remarkMermaid() {
|
|
|
94
94
|
return (/** @type {any} */ tree) => walk(tree);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// Wrap every table in a horizontal scroll box. A table can't scroll itself: the
|
|
98
|
+
// moment it needs `display: table` for real column sizing (and a rounded frame),
|
|
99
|
+
// `overflow-x` on the table is dead, so a table wider than its column has no way
|
|
100
|
+
// out but to squeeze every cell into a stack of wrapped lines — a 120px-tall
|
|
101
|
+
// table becomes 430px of cramped text. The wrapper takes the scrolling, the
|
|
102
|
+
// table keeps its natural widths (see `.aas-table-scroll` in global.css).
|
|
103
|
+
function rehypeTableScroll() {
|
|
104
|
+
/** @param {any} node */
|
|
105
|
+
const walk = (node) => {
|
|
106
|
+
if (!node.children) return;
|
|
107
|
+
node.children.forEach((/** @type {any} */ child, /** @type {number} */ i) => {
|
|
108
|
+
if (child.type === 'element' && child.tagName === 'table') {
|
|
109
|
+
node.children[i] = {
|
|
110
|
+
type: 'element',
|
|
111
|
+
tagName: 'div',
|
|
112
|
+
properties: { className: ['aas-table-scroll'] },
|
|
113
|
+
children: [child],
|
|
114
|
+
};
|
|
115
|
+
} else {
|
|
116
|
+
walk(child);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
return (/** @type {any} */ tree) => walk(tree);
|
|
121
|
+
}
|
|
122
|
+
|
|
97
123
|
// Slide directives (needs remarkDirective, which runs first). Two are handled:
|
|
98
124
|
//
|
|
99
125
|
// :::cols columns, separated by `---`:
|
|
@@ -405,6 +431,7 @@ export function aasMarkdown({ glossary, locales = ['en', 'ko'], defaultLocale =
|
|
|
405
431
|
rehypePlugins: [
|
|
406
432
|
rehypeSlug,
|
|
407
433
|
rehypeHeadingAnchors,
|
|
434
|
+
rehypeTableScroll,
|
|
408
435
|
[rehypeExternalLinks, { target: '_blank', rel: ['noopener', 'noreferrer'] }],
|
|
409
436
|
],
|
|
410
437
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stack-site-builder",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.23.
|
|
4
|
+
"version": "1.23.2",
|
|
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": {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type MarkdownIt from 'markdown-it';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wrap every rendered table in a `.aas-table-scroll` box, matching what
|
|
5
|
+
* `rehypeTableScroll` (markdown.mjs) does for content collections. A table
|
|
6
|
+
* cannot scroll itself — it needs `display: table` for real column sizing,
|
|
7
|
+
* which makes `overflow-x` on the table a no-op — so without the wrapper a
|
|
8
|
+
* README table wider than its column has no escape but to wrap every cell.
|
|
9
|
+
*
|
|
10
|
+
* Only needed on MarkdownIt instances that RENDER (READMEs, sample
|
|
11
|
+
* descriptions); the ones that merely `parse()` for metadata can skip it.
|
|
12
|
+
*/
|
|
13
|
+
export function withTableScroll(md: MarkdownIt): MarkdownIt {
|
|
14
|
+
const base = md.renderer.rules.table_open ?? ((t, i, o, _e, s) => s.renderToken(t, i, o));
|
|
15
|
+
md.renderer.rules.table_open = (tokens, idx, opts, env, self) =>
|
|
16
|
+
`<div class="aas-table-scroll">${base(tokens, idx, opts, env, self)}`;
|
|
17
|
+
const baseClose = md.renderer.rules.table_close ?? ((t, i, o, _e, s) => s.renderToken(t, i, o));
|
|
18
|
+
md.renderer.rules.table_close = (tokens, idx, opts, env, self) =>
|
|
19
|
+
`${baseClose(tokens, idx, opts, env, self)}</div>`;
|
|
20
|
+
return md;
|
|
21
|
+
}
|
package/src/lib/project.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
|
3
3
|
import { join, relative } from 'node:path';
|
|
4
4
|
import { createHighlighter, type Highlighter } from 'shiki';
|
|
5
5
|
import MarkdownIt from 'markdown-it';
|
|
6
|
+
import { withTableScroll } from './md-tables';
|
|
6
7
|
import { site } from '@aas-data/site';
|
|
7
8
|
|
|
8
9
|
const SAMPLES_DIR = 'samples';
|
|
@@ -240,17 +241,19 @@ export async function renderProjects(folders: string[], lang: string): Promise<R
|
|
|
240
241
|
const hl = await getHighlighter();
|
|
241
242
|
const escapeHtml = (s: string) =>
|
|
242
243
|
s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
243
|
-
const md =
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
244
|
+
const md = withTableScroll(
|
|
245
|
+
new MarkdownIt({
|
|
246
|
+
html: false,
|
|
247
|
+
linkify: true,
|
|
248
|
+
highlight: (code, info) => {
|
|
249
|
+
const lang = (info || '').trim() || 'text';
|
|
250
|
+
// Hand mermaid blocks to the client-side MermaidLoader instead of Shiki,
|
|
251
|
+
// so README diagrams render as graphics rather than highlighted text.
|
|
252
|
+
if (lang === 'mermaid') return `<pre class="mermaid">${escapeHtml(code)}</pre>`;
|
|
253
|
+
return highlight(hl, code, lang);
|
|
254
|
+
},
|
|
255
|
+
}),
|
|
256
|
+
);
|
|
254
257
|
// README links open in a new tab.
|
|
255
258
|
const baseLink = md.renderer.rules.link_open ?? ((t, i, o, _e, s) => s.renderToken(t, i, o));
|
|
256
259
|
md.renderer.rules.link_open = (tokens, idx, opts, env, self) => {
|
package/src/lib/samples.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { codeToHtml } from 'shiki';
|
|
2
2
|
import MarkdownIt from 'markdown-it';
|
|
3
|
+
import { withTableScroll } from './md-tables';
|
|
3
4
|
|
|
4
|
-
const md = new MarkdownIt({ html: false, linkify: true });
|
|
5
|
+
const md = withTableScroll(new MarkdownIt({ html: false, linkify: true }));
|
|
5
6
|
|
|
6
7
|
export interface SampleHeading {
|
|
7
8
|
slug: string;
|
package/src/styles/global.css
CHANGED
|
@@ -379,8 +379,9 @@ html[lang='ko'] h1 {
|
|
|
379
379
|
}
|
|
380
380
|
/* Doc tables: a touch larger, centered (shrink-to-content), roomier cells, and
|
|
381
381
|
a full-row hover highlight. `fit-content` + `margin-inline: auto` centers the
|
|
382
|
-
table block
|
|
383
|
-
|
|
382
|
+
table block. When the table sits in a `.aas-table-scroll` wrapper (the normal
|
|
383
|
+
case — see below) the centering moves to the wrapper and the table keeps its
|
|
384
|
+
natural column widths instead. */
|
|
384
385
|
.aas-reading.aas-reading :where(table) {
|
|
385
386
|
display: table;
|
|
386
387
|
width: fit-content;
|
|
@@ -581,6 +582,24 @@ summary {
|
|
|
581
582
|
list-style: decimal;
|
|
582
583
|
padding-left: 1.25rem;
|
|
583
584
|
}
|
|
585
|
+
/* Blockquotes — a quiet left-accent rail with a faint neutral fill, so a
|
|
586
|
+
pulled-out passage reads as set apart from the running text. No italic: it
|
|
587
|
+
renders on Korean prose too, where slanted CJK looks wrong. First/last child
|
|
588
|
+
margins collapse so the quote hugs its own padding. */
|
|
589
|
+
.prose :where(blockquote) {
|
|
590
|
+
margin: 1.25rem 0;
|
|
591
|
+
padding: 0.75rem 1.15rem;
|
|
592
|
+
border-left: 3px solid var(--aas-accent);
|
|
593
|
+
border-radius: 0 0.5rem 0.5rem 0;
|
|
594
|
+
background: var(--aas-tint);
|
|
595
|
+
color: color-mix(in srgb, var(--aas-text) 88%, transparent);
|
|
596
|
+
}
|
|
597
|
+
.prose :where(blockquote > :first-child) {
|
|
598
|
+
margin-top: 0;
|
|
599
|
+
}
|
|
600
|
+
.prose :where(blockquote > :last-child) {
|
|
601
|
+
margin-bottom: 0;
|
|
602
|
+
}
|
|
584
603
|
.prose :where(a) {
|
|
585
604
|
color: var(--aas-accent);
|
|
586
605
|
text-decoration: none;
|
|
@@ -709,6 +728,18 @@ summary {
|
|
|
709
728
|
margin-inline: auto;
|
|
710
729
|
}
|
|
711
730
|
|
|
731
|
+
/* Mermaid draws its labels as real HTML inside <foreignObject> and sizes nodes
|
|
732
|
+
and subgraph frames from the measured box. Mermaid 11 wraps label text in a
|
|
733
|
+
<p>, which then inherits the PAGE's paragraph typography — on a slide that is
|
|
734
|
+
26px/41px, while mermaid only reserves ~25px for a subgraph title, so every
|
|
735
|
+
subgraph title overlapped the first node inside it by ~16px. Pin label
|
|
736
|
+
typography back to mermaid's own so its measurements hold. */
|
|
737
|
+
.mermaid foreignObject p {
|
|
738
|
+
margin: 0;
|
|
739
|
+
font-size: inherit;
|
|
740
|
+
line-height: inherit;
|
|
741
|
+
}
|
|
742
|
+
|
|
712
743
|
/* Mermaid theme: rounded corners + soft pastel fills, derived from the site
|
|
713
744
|
accent so it adapts to light/dark. `!important` overrides Mermaid's own
|
|
714
745
|
id-scoped <style> block. Applies wherever a diagram renders (prose + samples). */
|
|
@@ -776,7 +807,10 @@ summary {
|
|
|
776
807
|
}
|
|
777
808
|
|
|
778
809
|
|
|
779
|
-
/* Markdown tables — without these, columns collapse together.
|
|
810
|
+
/* Markdown tables — without these, columns collapse together. This is also the
|
|
811
|
+
fallback for a table that reaches the page WITHOUT the scroll wrapper below
|
|
812
|
+
(raw HTML in MDX, say): `display: block` + `overflow-x` at least keeps it
|
|
813
|
+
from pushing the page sideways. */
|
|
780
814
|
.prose :where(table) {
|
|
781
815
|
width: 100%;
|
|
782
816
|
border-collapse: collapse;
|
|
@@ -785,6 +819,39 @@ summary {
|
|
|
785
819
|
display: block;
|
|
786
820
|
overflow-x: auto;
|
|
787
821
|
}
|
|
822
|
+
|
|
823
|
+
/* Horizontal scroll box wrapped around every rendered table — by
|
|
824
|
+
`rehypeTableScroll` (markdown.mjs) for content collections, and by
|
|
825
|
+
`withTableScroll` (lib/md-tables.ts) for READMEs and sample descriptions.
|
|
826
|
+
A table cannot scroll itself: it needs `display: table` for real column
|
|
827
|
+
sizing, which makes `overflow-x` on the table a no-op, so a table wider than
|
|
828
|
+
its column had no escape but to wrap every cell — a 120px-tall table became
|
|
829
|
+
430px of cramped text. The wrapper takes the scrolling; the table gets its
|
|
830
|
+
natural column widths back (`max-content`, floored at the column width so a
|
|
831
|
+
narrow table still fills it). */
|
|
832
|
+
.aas-table-scroll {
|
|
833
|
+
max-width: 100%;
|
|
834
|
+
overflow-x: auto;
|
|
835
|
+
overscroll-behavior-x: contain;
|
|
836
|
+
margin: 1.25rem 0;
|
|
837
|
+
}
|
|
838
|
+
.aas-table-scroll > table {
|
|
839
|
+
display: table;
|
|
840
|
+
width: max-content;
|
|
841
|
+
min-width: 100%;
|
|
842
|
+
margin: 0;
|
|
843
|
+
}
|
|
844
|
+
/* In a reading column the wrapper shrinks to the table and centers, so a table
|
|
845
|
+
narrower than the column keeps its own width rather than being stretched. */
|
|
846
|
+
.aas-reading.aas-reading .aas-table-scroll {
|
|
847
|
+
width: fit-content;
|
|
848
|
+
margin-inline: auto;
|
|
849
|
+
}
|
|
850
|
+
.aas-reading.aas-reading .aas-table-scroll > table {
|
|
851
|
+
min-width: 0;
|
|
852
|
+
max-width: none;
|
|
853
|
+
margin-inline: 0;
|
|
854
|
+
}
|
|
788
855
|
.prose :where(th, td) {
|
|
789
856
|
border: 1px solid var(--aas-border);
|
|
790
857
|
padding: 0.55rem 0.85rem;
|
|
@@ -1253,13 +1320,25 @@ summary {
|
|
|
1253
1320
|
color: var(--aas-muted);
|
|
1254
1321
|
}
|
|
1255
1322
|
|
|
1256
|
-
/* Tables
|
|
1323
|
+
/* Tables. Same deal as prose tables: the `.aas-table-scroll` wrapper does the
|
|
1324
|
+
scrolling, so a wide table slides sideways instead of cramming its cells. */
|
|
1325
|
+
.aas-slide-inner .aas-table-scroll {
|
|
1326
|
+
width: 100%;
|
|
1327
|
+
margin: 0.5em 0;
|
|
1328
|
+
}
|
|
1257
1329
|
.aas-slide-inner table {
|
|
1258
1330
|
width: 100%;
|
|
1259
1331
|
border-collapse: collapse;
|
|
1260
1332
|
font-size: clamp(0.9rem, 1.5vw, 1.25rem);
|
|
1261
1333
|
margin: 0.5em 0;
|
|
1262
1334
|
}
|
|
1335
|
+
/* Declared after `.aas-slide-inner table` so the wrapped form wins: full column
|
|
1336
|
+
width normally, natural width (scrolling) once the table outgrows the slide. */
|
|
1337
|
+
.aas-slide-inner .aas-table-scroll > table {
|
|
1338
|
+
width: max-content;
|
|
1339
|
+
min-width: 100%;
|
|
1340
|
+
margin: 0;
|
|
1341
|
+
}
|
|
1263
1342
|
.aas-slide-inner th,
|
|
1264
1343
|
.aas-slide-inner td {
|
|
1265
1344
|
text-align: left;
|
|
@@ -1510,6 +1589,38 @@ summary {
|
|
|
1510
1589
|
/* 3b) Code stays pinned to the top of its filled box — that's the default block
|
|
1511
1590
|
flow of a tall <pre>, so nothing extra is needed. */
|
|
1512
1591
|
|
|
1592
|
+
/* 3c) Size the diagram against the box it was just given, not a fixed viewport
|
|
1593
|
+
fraction. The generic caps (`pre` 62vh, svg 52vh) don't know how much room
|
|
1594
|
+
the fill rules actually handed over — on a full-height slide that box is
|
|
1595
|
+
~78vh, so a tall flowchart rendered at a THIRD of its size with the unused
|
|
1596
|
+
height letterboxed as empty margins either side. The box already has a
|
|
1597
|
+
definite height here, so `100%` resolves against it; the svg's viewBox
|
|
1598
|
+
does the rest (it scales to fit and centers itself). Excludes the layouts
|
|
1599
|
+
that deliberately manage their own overflow: `compact` (natural size),
|
|
1600
|
+
`.aas-split.scroll` (vertical scroll box) and `scroll-x` (horizontal). */
|
|
1601
|
+
.aas-slide:not(.compact):not(.scroll-x) .aas-slide-inner > .aas-diagram > pre.mermaid,
|
|
1602
|
+
.aas-slide:not(.compact):not(.scroll-x)
|
|
1603
|
+
.aas-slide-inner
|
|
1604
|
+
> .aas-split:not(.scroll)
|
|
1605
|
+
> .aas-diagram
|
|
1606
|
+
> pre.mermaid {
|
|
1607
|
+
flex: 1 1 0;
|
|
1608
|
+
min-height: 0;
|
|
1609
|
+
max-height: 100%;
|
|
1610
|
+
width: 100%;
|
|
1611
|
+
}
|
|
1612
|
+
.aas-slide:not(.compact):not(.scroll-x) .aas-slide-inner > .aas-diagram > pre.mermaid > svg,
|
|
1613
|
+
.aas-slide:not(.compact):not(.scroll-x)
|
|
1614
|
+
.aas-slide-inner
|
|
1615
|
+
> .aas-split:not(.scroll)
|
|
1616
|
+
> .aas-diagram
|
|
1617
|
+
> pre.mermaid
|
|
1618
|
+
> svg {
|
|
1619
|
+
width: 100%;
|
|
1620
|
+
height: 100%;
|
|
1621
|
+
max-height: 100%;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1513
1624
|
/* Scrollable diagram (`<div class="aas-split scroll">`): the diagram column is a
|
|
1514
1625
|
fixed-height scroll box (opted out of the fill rules above) and the diagram
|
|
1515
1626
|
fits the column width, so a tall/complex flowchart scrolls vertically next to
|