@master/internal-site 0.1.2 → 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/README.md +43 -0
- package/dist/astro.mjs +233 -47
- package/dist/config.d.mts +6 -0
- package/dist/localization-LfIbIysE.mjs +356 -0
- package/dist/localization.d.mts +69 -0
- package/dist/localization.mjs +1 -0
- package/package.json +12 -9
- package/src/astro/content-pages.ts +30 -11
- package/src/astro/index.ts +11 -5
- package/src/astro/localized-mdx.ts +45 -0
- package/src/astro/routes.template.ts +4 -0
- package/src/astro/site-context.ts +10 -2
- package/src/astro/style-assets.ts +107 -0
- package/src/benchmarks/BenchmarkBarRows.astro +3 -2
- package/src/benchmarks/BenchmarkBars.astro +1 -1
- package/src/benchmarks/BenchmarkChart.astro +5 -1
- package/src/benchmarks/BenchmarkChartGroup.astro +1 -1
- package/src/benchmarks/BenchmarkDataTable.astro +1 -1
- package/src/benchmarks/BenchmarkFigure.astro +2 -1
- package/src/benchmarks/BenchmarkMetricTable.astro +2 -2
- package/src/benchmarks/BenchmarkMetrics.astro +1 -1
- package/src/benchmarks/BenchmarkSampleSummary.astro +1 -1
- package/src/benchmarks/BenchmarkScrollRegion.svelte +2 -1
- package/src/benchmarks/BenchmarkSource.astro +1 -1
- package/src/benchmarks/BenchmarkStackedBars.astro +4 -3
- package/src/benchmarks/BenchmarkStatus.astro +3 -1
- package/src/benchmarks/localization.ts +22 -0
- package/src/benchmarks/types.ts +2 -0
- package/src/blog/article/BlogArticleContents.svelte +1 -1
- package/src/blog/article/BlogArticleEnd.astro +6 -9
- package/src/blog/article/BlogArticleMasthead.astro +17 -9
- package/src/config.ts +3 -0
- package/src/css/NamespaceUtilityTable.astro +1 -1
- package/src/css/ThemeNumberVariableTable.astro +1 -1
- package/src/css/foundation-data/specimen-content.ts +2 -2
- package/src/css/markdown.ts +64 -14
- package/src/demo/Demo.svelte +10 -4
- package/src/demo/DemoAsset.astro +6 -3
- package/src/demo/DemoAxes.svelte +4 -2
- package/src/demo/DemoCatalog.astro +9 -6
- package/src/demo/DemoComparison.svelte +3 -0
- package/src/demo/DemoContainer.svelte +8 -3
- package/src/demo/DemoControls.svelte +5 -1
- package/src/demo/DemoCopyButton.svelte +9 -4
- package/src/demo/DemoCopyGroup.svelte +6 -2
- package/src/demo/DemoExample.astro +3 -1
- package/src/demo/DemoFeatureSupport.svelte +5 -1
- package/src/demo/DemoGeneratedCSS.svelte +5 -1
- package/src/demo/DemoIndex.astro +6 -3
- package/src/demo/DemoLegend.svelte +3 -1
- package/src/demo/DemoMeasure.svelte +4 -2
- package/src/demo/DemoMedia.svelte +3 -1
- package/src/demo/DemoMotion.svelte +6 -3
- package/src/demo/DemoPaletteGroups.svelte +4 -2
- package/src/demo/DemoScrollArea.svelte +2 -0
- package/src/demo/DemoStyleComparison.astro +6 -3
- package/src/demo/DemoSurface.svelte +2 -0
- package/src/demo/DemoThemeComparison.astro +5 -2
- package/src/demo/DemoTokenTable.astro +5 -3
- package/src/demo/DemoViewTransition.astro +3 -1
- package/src/demo/DemoViewport.svelte +18 -11
- package/src/demo/DemoWaterfall.astro +4 -2
- package/src/demo/ProjectStyleExample.astro +4 -1
- package/src/demo/foundations/FoundationDialog.astro +6 -2
- package/src/demo/foundations/FoundationMedia.astro +1 -0
- package/src/demo/foundations/FoundationShrink.astro +1 -0
- package/src/demo/foundations/FoundationTokensView.astro +16 -5
- package/src/demo/foundations/Palette.svelte +11 -7
- package/src/demo/foundations/dialog-copy.d.ts +1 -0
- package/src/demo/foundations/dialog-copy.js +5 -0
- package/src/demo/illustration-materials.ts +1 -1
- package/src/demo/illustration.css +218 -0
- package/src/docs-shell/common/i18n.config.d.ts +1 -1
- package/src/docs-shell/common/i18n.config.js +4 -12
- package/src/docs-shell/common/locales.d.ts +8 -0
- package/src/docs-shell/common/locales.js +18 -0
- package/src/docs-shell/common/terminology.json +32 -0
- package/src/docs-shell/common/translations.d.ts +3 -0
- package/src/docs-shell/common/translations.js +294 -0
- package/src/docs-shell/components/ArticleHeader.astro +5 -3
- package/src/docs-shell/components/Callout.astro +1 -0
- package/src/docs-shell/components/CodeCopyButton.astro +5 -1
- package/src/docs-shell/components/CodeTabBar.astro +7 -3
- package/src/docs-shell/components/CodeTabs.astro +2 -1
- package/src/docs-shell/components/CodeView.astro +1 -1
- package/src/docs-shell/components/DocHeader.svelte +13 -17
- package/src/docs-shell/components/DocHeading.astro +3 -1
- package/src/docs-shell/components/DocMenuButton.svelte +126 -61
- package/src/docs-shell/components/DocSidebar.svelte +3 -2
- package/src/docs-shell/components/DocVersionSelect.svelte +2 -0
- package/src/docs-shell/components/DocumentAPIIndex.astro +1 -1
- package/src/docs-shell/components/DocumentChoices.astro +1 -1
- package/src/docs-shell/components/DocumentCodeExampleView.astro +3 -1
- package/src/docs-shell/components/DocumentCodeTable.astro +4 -2
- package/src/docs-shell/components/DocumentCopyButton.svelte +3 -0
- package/src/docs-shell/components/DocumentDisclosure.astro +2 -0
- package/src/docs-shell/components/DocumentFileTree.astro +3 -0
- package/src/docs-shell/components/DocumentFlow.astro +4 -1
- package/src/docs-shell/components/DocumentIllustration.astro +8 -12
- package/src/docs-shell/components/DocumentKeyList.astro +6 -4
- package/src/docs-shell/components/DocumentNamespaceTable.astro +5 -3
- package/src/docs-shell/components/DocumentOptionEntry.astro +0 -1
- package/src/docs-shell/components/DocumentOptionList.astro +1 -1
- package/src/docs-shell/components/DocumentOptions.astro +3 -2
- package/src/docs-shell/components/DocumentParameters.astro +1 -1
- package/src/docs-shell/components/DocumentPrompt.astro +2 -0
- package/src/docs-shell/components/DocumentValueList.astro +1 -1
- package/src/docs-shell/components/DocumentationIndex.svelte +8 -7
- package/src/docs-shell/components/ExpandContent.svelte +3 -0
- package/src/docs-shell/components/ExplorerView.astro +1 -0
- package/src/docs-shell/components/GeneratedCSS.astro +4 -1
- package/src/docs-shell/components/Header.svelte +1 -1
- package/src/docs-shell/components/InlineCode.astro +1 -0
- package/src/docs-shell/components/InteractingIndicator.astro +1 -0
- package/src/docs-shell/components/LanguageButton.svelte +1 -0
- package/src/docs-shell/components/LanguageSelect.svelte +2 -0
- package/src/docs-shell/components/Link.svelte +3 -2
- package/src/docs-shell/components/NotFound.astro +6 -4
- package/src/docs-shell/components/PMAction.astro +1 -0
- package/src/docs-shell/components/PageContent.svelte +1 -1
- package/src/docs-shell/components/PageContentDisclosure.astro +2 -1
- package/src/docs-shell/components/PageContentList.svelte +2 -0
- package/src/docs-shell/components/PageNavs.astro +3 -3
- package/src/docs-shell/components/SearchButton.svelte +3 -0
- package/src/docs-shell/components/SearchDialog.svelte +18 -16
- package/src/docs-shell/components/Segments.svelte +2 -0
- package/src/docs-shell/components/StepSection.astro +1 -2
- package/src/docs-shell/components/Tabs.astro +1 -0
- package/src/docs-shell/components/ThemeSelect.svelte +2 -0
- package/src/docs-shell/components/TimeAgo.svelte +6 -6
- package/src/docs-shell/components/markdown/Table.astro +1 -0
- package/src/docs-shell/components/markdown-components.ts +0 -1
- package/src/docs-shell/contexts/search.ts +1 -1
- package/src/docs-shell/factories/Page.astro +10 -5
- package/src/docs-shell/factories/create-page.ts +33 -6
- package/src/docs-shell/layouts/BlogArticle.astro +3 -11
- package/src/docs-shell/remark/markdown-components.js +28 -7
- package/src/docs-shell/remark/slug-and-toc.js +5 -7
- package/src/docs-shell/scripts/code.ts +5 -2
- package/src/docs-shell/scripts/document.ts +1 -1
- package/src/docs-shell/site.ts +9 -1
- package/src/docs-shell/types/Metadata.ts +11 -0
- package/src/docs-shell/utils/document-copy.d.ts +2 -0
- package/src/docs-shell/utils/document-copy.js +18 -0
- package/src/docs-shell/utils/generate-metadata.ts +5 -1
- package/src/docs-shell/utils/head.ts +5 -2
- package/src/docs-shell/utils/i18n-pathname.ts +13 -2
- package/src/docs-shell/utils/i18n.ts +4 -1
- package/src/docs-shell/utils/localized-metadata.ts +22 -0
- package/src/docs-shell/utils/markdown-links.ts +61 -0
- package/src/docs-shell/utils/markdown-tree.ts +19 -6
- package/src/docs-shell/utils/resolve-heading.d.ts +1 -0
- package/src/docs-shell/utils/resolve-heading.js +21 -0
- package/src/docs-shell/utils/search-pages.ts +75 -22
- package/src/examples/components/ArticleTransitionScene.svelte +4 -0
- package/src/examples/layout-system/page.astro +0 -1
- package/src/home/HomeBentoFrame.astro +1 -0
- package/src/home/HomeBentoGrid.astro +1 -0
- package/src/home/bento.css +167 -0
- package/src/home/design.css +1 -1
- package/src/home/hero.css +5 -0
- package/src/home/home.css +4 -576
- package/src/home/segmented-control.css +94 -0
- package/src/layouts/Document.astro +4 -2
- package/src/public/icons/json.svg +1 -0
- package/src/scripts/atomic-class-authoring.ts +98 -0
- package/src/scripts/localization.ts +239 -0
- package/src/scripts/mdx-sample.ts +12 -0
- package/src/scripts/static-social.ts +17 -3
- package/src/scripts/style-delivery.mjs +120 -0
- package/src/sections/blog.astro +1 -1
- package/src/sections/guide.astro +4 -3
- package/src/styles/blog-article.css +10 -7
- package/src/styles/blog-materials.css +13 -0
- package/src/styles/demo.css +0 -1
- package/src/styles/docs-shell/code.css +5 -61
- package/src/styles/docs-shell/documentation-search.css +1 -0
- package/src/styles/docs-shell/header.css +2 -73
- package/src/styles/docs-shell/menu.css +37 -17
- package/src/styles/docs-shell/page-content.css +2 -37
- package/src/styles/docs-shell/prose.css +18 -9
- package/src/styles/docs-shell/steps.css +2 -39
- package/src/styles/document-comparison.css +5 -2
- package/src/styles/documentation-illustration.css +1 -9
- package/src/styles/documentation-index.css +2 -1
- package/src/styles/documents.css +2 -4
- package/src/styles/interface.css +5 -3
- package/src/styles/system/DESIGN.md +34 -14
- package/src/styles/system/browser.css +21 -0
- package/src/styles/system/button-feedback.css +13 -0
- package/src/styles/system/callout.css +14 -0
- package/src/styles/system/chart.css +18 -0
- package/src/styles/system/checks.css +18 -0
- package/src/styles/system/code-panel.css +82 -0
- package/src/styles/system/code-tabs.css +40 -0
- package/src/styles/system/code.css +8 -85
- package/src/styles/system/compare.css +7 -0
- package/src/styles/system/controls.css +10 -109
- package/src/styles/system/copy.css +32 -0
- package/src/styles/system/data.css +10 -134
- package/src/styles/system/dialog.css +16 -0
- package/src/styles/system/disclosure.css +19 -0
- package/src/styles/system/expand.css +11 -0
- package/src/styles/system/fields.css +25 -0
- package/src/styles/system/header-core.css +101 -0
- package/src/styles/system/hint.css +5 -0
- package/src/styles/system/index.css +13 -0
- package/src/styles/system/inline-code.css +4 -0
- package/src/styles/system/kbd.css +4 -0
- package/src/styles/system/logos.css +10 -0
- package/src/styles/system/menu.css +14 -0
- package/src/styles/system/metrics.css +22 -0
- package/src/styles/system/pagehead.css +13 -0
- package/src/styles/system/pager.css +13 -0
- package/src/styles/system/parameters.css +17 -0
- package/src/styles/system/prompt.css +7 -0
- package/src/styles/system/prose.css +4 -75
- package/src/styles/system/range.css +12 -0
- package/src/styles/system/reading.css +44 -0
- package/src/styles/system/scroll.css +6 -0
- package/src/styles/system/search-trigger.css +10 -0
- package/src/styles/system/segmented.css +22 -0
- package/src/styles/system/sheet.css +8 -0
- package/src/styles/system/shell.css +8 -102
- package/src/styles/system/sidebar.css +14 -0
- package/src/styles/system/source.css +5 -0
- package/src/styles/system/specimens.css +3 -0
- package/src/styles/system/stage.css +18 -0
- package/src/styles/system/steps.css +51 -0
- package/src/styles/system/surfaces.css +8 -104
- package/src/styles/system/table.css +23 -0
- package/src/styles/system/toc.css +59 -0
- package/src/styles/system/tooltip.css +6 -0
- package/src/styles/system/tray-code.css +6 -0
- package/src/styles/system/tray.css +20 -0
- package/src/styles/system/tree.css +15 -0
- package/src/styles/system/waterfall.css +14 -0
- package/src/virtual.d.ts +5 -1
- package/src/blog/article/language.ts +0 -29
package/README.md
CHANGED
|
@@ -27,6 +27,12 @@ Optional `header.communityNavs` selects the links shown beside search without re
|
|
|
27
27
|
|
|
28
28
|
The app module exports its logo component, navigation, version links and source/feedback URLs using the `SiteApp` contract. Consumers retain their own content and homepage composition. Ordinary documents use `content/<section>/<slug>/content.mdx` and `metadata.ts`; a local `page.astro` can override the generated entry. Dynamic routes enumerate params from lightweight `params.ts` files. The integration owns generated routes, page asset collection and the Astro/Svelte renderer setup.
|
|
29
29
|
|
|
30
|
+
Blog articles with a cover declare `cover: { src, alt, width, height }` in their
|
|
31
|
+
metadata. The shared article layout renders it below the byline and uses it for
|
|
32
|
+
Open Graph and Twitter images. An optional `socialImage` points to a PNG/JPEG
|
|
33
|
+
version of the same artwork; a cover takes precedence over separate social-card
|
|
34
|
+
images. Articles without a cover retain their existing layout and social cards.
|
|
35
|
+
|
|
30
36
|
```css
|
|
31
37
|
/* styles/globals.css */
|
|
32
38
|
@import '@master/css';
|
|
@@ -62,6 +68,43 @@ Import individual component subpaths, including `.astro` and `.svelte` extension
|
|
|
62
68
|
|
|
63
69
|
The CSS-specific subpaths require the matching optional compiler, tooling, schema, preset and language-service peers. Keep them out of browser-only imports. Shared public assets are served in development and copied into build output; consumer public files take precedence. No install hook writes consumer source files.
|
|
64
70
|
|
|
71
|
+
## Local MDX translations
|
|
72
|
+
|
|
73
|
+
English uses the root URL. The shared locale definitions map `ja`, `tw`, `ko`
|
|
74
|
+
and `cn` to matching URL prefixes and the HTML language tags `ja`, `zh-TW`,
|
|
75
|
+
`ko` and `zh-CN`. Keep complete sibling editions in `content.<locale>.mdx`;
|
|
76
|
+
`metadata.ts` retains English identity, dates, authors and ordering. Translated
|
|
77
|
+
frontmatter supplies titles, summaries, image descriptions and article-specific
|
|
78
|
+
demonstration copy. Keep explicit heading IDs identical across editions.
|
|
79
|
+
|
|
80
|
+
`build/localization.ts` supplies filesystem discovery, localized document reads,
|
|
81
|
+
dependency fingerprints, explicit review operations and completeness checks.
|
|
82
|
+
Configure `i18n.validation` with the consumer's resource-loader and review-index
|
|
83
|
+
URLs. The integration validates them on every production build, including direct
|
|
84
|
+
`astro build` calls. Source fingerprints include metadata and imported local or
|
|
85
|
+
shared source files. A missing edition or changed source/translation fails the
|
|
86
|
+
gate until independently reviewed. Builds never refresh review records.
|
|
87
|
+
|
|
88
|
+
The resource loader also exposes local and shared UI dictionaries to the same
|
|
89
|
+
gate. Common controls use `common/translations.js`; product copy belongs to each
|
|
90
|
+
consumer. Both sites follow `common/terminology.json`. Use `sharedInterfaceKeys()`
|
|
91
|
+
to include newly introduced literal interface requests in the UI inventory.
|
|
92
|
+
|
|
93
|
+
The route registry imports each selected MDX edition through Astro's propagated
|
|
94
|
+
asset boundary. Nested MDX imports inherit their parent's language through Vite;
|
|
95
|
+
missing prose editions and draft includes throw. Prose-free fenced companion
|
|
96
|
+
examples stay shared. Do not import every edition eagerly or reimplement the
|
|
97
|
+
resolver in a consumer. Per-request `documentCopyOf(Astro)` and `demoCopy` let
|
|
98
|
+
shared demonstrations read localized prose while retaining one executable model.
|
|
99
|
+
|
|
100
|
+
Consumers derive navigation, search, Markdown, feeds and llms exports from their
|
|
101
|
+
public inventory and the selected local edition. Use `extractSearchNodesFromMdx`
|
|
102
|
+
for authored MDX and `extractSearchNodesFromMarkdown` for portable output; the
|
|
103
|
+
latter retains explicit anchor targets and GFM tables. `transformMarkdownLinks`
|
|
104
|
+
edits reader links without changing inline or fenced examples. Withdraw stale
|
|
105
|
+
owned exports when a source becomes a draft or is removed. Required Reference
|
|
106
|
+
inputs reject draft status instead of publishing a partial catalog.
|
|
107
|
+
|
|
65
108
|
## Development and releases
|
|
66
109
|
|
|
67
110
|
From the Master repository, run `bun run build:packages`, `bun run --cwd packages/internal-site type-check` and `bun run --cwd packages/internal-site test`. Astro checks `.astro` implementations and Svelte checks interactive components separately. The root `build` builds the Node entrypoints before the site.
|
package/dist/astro.mjs
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import { d as validateSiteTranslations, f as isSharedMdxSample, h as createHeadingResolver, m as locales } from "./localization-LfIbIysE.mjs";
|
|
1
2
|
import { svgoOptimizer } from "astro/config";
|
|
2
3
|
import svelte from "@astrojs/svelte";
|
|
3
4
|
import mdx from "@astrojs/mdx";
|
|
4
|
-
import { unified } from "@astrojs/markdown-remark";
|
|
5
|
+
import { parseFrontmatter, unified } from "@astrojs/markdown-remark";
|
|
5
6
|
import masterCSS from "@master/css-astro";
|
|
6
7
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
-
import { dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
8
|
+
import { dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
8
9
|
import { cp, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
|
|
9
10
|
import { createReadStream, existsSync } from "node:fs";
|
|
10
11
|
import { isCSSRequest, searchForWorkspaceRoot, transformWithOxc } from "vite";
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import { parse, parseExpressionAt } from "acorn";
|
|
11
14
|
import { optimize } from "svgo";
|
|
12
|
-
import Slugger from "github-slugger";
|
|
13
15
|
import { SKIP, visit } from "unist-util-visit";
|
|
14
|
-
import { parse, parseExpressionAt } from "acorn";
|
|
15
16
|
// src/astro/module-id.ts
|
|
16
17
|
/** A Vite module id without its query or hash. */
|
|
17
18
|
function cleanId(id) {
|
|
@@ -56,6 +57,33 @@ async function prepareContentPages(site, root, contentPrefix) {
|
|
|
56
57
|
const destination = join(root, ".astro/master-site/pages");
|
|
57
58
|
const pages = {};
|
|
58
59
|
const wanted = /* @__PURE__ */ new Set();
|
|
60
|
+
const localizedDocuments = {};
|
|
61
|
+
const localizedMetadata = {};
|
|
62
|
+
const availableLocales = {};
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
if (!file.endsWith("/content.mdx")) continue;
|
|
65
|
+
const directory = dirname(file);
|
|
66
|
+
const route = relative(content, directory).replaceAll("\\", "/");
|
|
67
|
+
const pathname = "/" + route.split("/").filter((part) => !/^\(.+\)$/.test(part)).join("/");
|
|
68
|
+
const key = `${contentPrefix}/${route ? route + "/" : ""}page.astro`;
|
|
69
|
+
const section = route.split("/").find((part) => !/^\(.+\)$/.test(part)) ?? "home";
|
|
70
|
+
const locales = site.i18n.sectionLocales?.[section] ?? site.i18n.locales;
|
|
71
|
+
const metadataSource = await readFile(join(directory, "metadata.ts"), "utf8").catch(() => "");
|
|
72
|
+
const draft = parseFrontmatter(await readFile(file, "utf8")).frontmatter.draft === true || /\bdraft\s*:\s*true\b/.test(metadataSource);
|
|
73
|
+
const documents = {};
|
|
74
|
+
const metadata = {};
|
|
75
|
+
for (const locale of draft ? [] : locales) {
|
|
76
|
+
const variant = locale === site.i18n.defaultLocale ? file : join(directory, `content.${locale}.mdx`);
|
|
77
|
+
if (!files.has(variant)) continue;
|
|
78
|
+
const { frontmatter } = parseFrontmatter(await readFile(variant, "utf8"));
|
|
79
|
+
if (frontmatter.draft === true) continue;
|
|
80
|
+
documents[locale] = pathToFileURL(variant);
|
|
81
|
+
metadata[locale] = frontmatter;
|
|
82
|
+
}
|
|
83
|
+
localizedDocuments[pathname] = documents;
|
|
84
|
+
localizedMetadata[pathname] = metadata;
|
|
85
|
+
availableLocales[key] = Object.keys(documents);
|
|
86
|
+
}
|
|
59
87
|
for (const file of files) {
|
|
60
88
|
if (!file.endsWith("/content.mdx")) continue;
|
|
61
89
|
const directory = dirname(file);
|
|
@@ -86,15 +114,6 @@ export const generateMetadata = createPageMetadata(metadata, dictionaries)
|
|
|
86
114
|
pages[`${contentPrefix}/${route ? route + "/" : ""}page.astro`] = pathToFileURL(output);
|
|
87
115
|
}
|
|
88
116
|
for (const stale of await contentFiles(destination).catch(() => [])) if (stale.endsWith("/page.astro") && !wanted.has(stale)) await unlink(stale);
|
|
89
|
-
const availableLocales = {};
|
|
90
|
-
for (const file of files) {
|
|
91
|
-
if (!file.endsWith("/content.mdx")) continue;
|
|
92
|
-
const directory = dirname(file);
|
|
93
|
-
const route = relative(content, directory).replaceAll("\\", "/");
|
|
94
|
-
const section = route.split("/").find((segment) => !/^\(.+\)$/.test(segment)) ?? "home";
|
|
95
|
-
if (!site.i18n.translatedOnly?.includes(section)) continue;
|
|
96
|
-
availableLocales[`${contentPrefix}/${route ? route + "/" : ""}page.astro`] = site.i18n.locales.filter((locale) => locale === site.i18n.defaultLocale || files.has(join(directory, `content.${locale}.mdx`)));
|
|
97
|
-
}
|
|
98
117
|
for (const section of site.i18n.translatedOnly ?? []) {
|
|
99
118
|
const key = `${contentPrefix}/${section}/page.astro`;
|
|
100
119
|
if (!files.has(join(content, section, "page.astro"))) continue;
|
|
@@ -103,7 +122,9 @@ export const generateMetadata = createPageMetadata(metadata, dictionaries)
|
|
|
103
122
|
}
|
|
104
123
|
return {
|
|
105
124
|
pages,
|
|
106
|
-
availableLocales
|
|
125
|
+
availableLocales,
|
|
126
|
+
localizedDocuments,
|
|
127
|
+
localizedMetadata
|
|
107
128
|
};
|
|
108
129
|
}
|
|
109
130
|
// src/astro/server-styles.ts
|
|
@@ -156,41 +177,171 @@ function svgMarkup() {
|
|
|
156
177
|
}
|
|
157
178
|
};
|
|
158
179
|
}
|
|
159
|
-
// src/
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (explicit) {
|
|
163
|
-
title = title.slice(0, explicit.index);
|
|
164
|
-
id = explicit[1];
|
|
165
|
-
}
|
|
166
|
-
const words = title?.split?.(" ");
|
|
167
|
-
if (words?.pop() === "[sr-only]") return {
|
|
168
|
-
title: words.join(" "),
|
|
169
|
-
id: id?.replace("-sr-only", "")?.replace("-[sr-only]", ""),
|
|
170
|
-
className: "sr-only"
|
|
171
|
-
};
|
|
180
|
+
// src/astro/localized-mdx.ts
|
|
181
|
+
/** Nested article MDX follows its importer; executable examples keep one source. */
|
|
182
|
+
function localizedMdx({ locales: locales$1 = locales, defaultLocale = "en" } = {}) {
|
|
172
183
|
return {
|
|
173
|
-
|
|
174
|
-
|
|
184
|
+
name: "@master/internal-site:localized-mdx",
|
|
185
|
+
enforce: "pre",
|
|
186
|
+
async resolveId(source, importer, options) {
|
|
187
|
+
if (!importer || !cleanId(importer).endsWith(".mdx")) return;
|
|
188
|
+
const language = cleanId(importer).match(/\.([a-z]{2})\.mdx$/)?.[1];
|
|
189
|
+
const locale = language && locales$1.includes(language) ? language : defaultLocale;
|
|
190
|
+
const resolved = await this.resolve(source, importer, {
|
|
191
|
+
...options,
|
|
192
|
+
skipSelf: true
|
|
193
|
+
});
|
|
194
|
+
if (!resolved || resolved.external) return;
|
|
195
|
+
const id = cleanId(resolved.id);
|
|
196
|
+
if (!id.endsWith(".mdx") || id.startsWith("\0")) return;
|
|
197
|
+
const suffix = resolved.id.slice(id.length) || source.slice(cleanId(source).length);
|
|
198
|
+
const file = id.startsWith("file:") ? fileURLToPath(id) : id.startsWith("/@fs/") ? id.slice(5) : id;
|
|
199
|
+
if (!isAbsolute(file)) return;
|
|
200
|
+
const original = file.replace(/\.([a-z]{2})\.mdx$/, (match, language) => locales$1.includes(language) ? ".mdx" : match);
|
|
201
|
+
this.addWatchFile(original);
|
|
202
|
+
const originalSource = await readFile(original, "utf8");
|
|
203
|
+
const originalMetadata = parseFrontmatter(originalSource).frontmatter;
|
|
204
|
+
if (originalMetadata.draft === true || originalMetadata.disabled === true) throw new Error(`Unpublished source MDX include: ${original}`);
|
|
205
|
+
if (locale === defaultLocale || !originalSource.trim() || isSharedMdxSample(original, originalSource)) return {
|
|
206
|
+
...resolved,
|
|
207
|
+
id: original + suffix
|
|
208
|
+
};
|
|
209
|
+
const translated = original.replace(/\.mdx$/, `.${locale}.mdx`);
|
|
210
|
+
this.addWatchFile(translated);
|
|
211
|
+
let translatedSource;
|
|
212
|
+
try {
|
|
213
|
+
translatedSource = await readFile(translated, "utf8");
|
|
214
|
+
} catch (cause) {
|
|
215
|
+
throw new Error(`Missing translated MDX include: ${translated}`, { cause });
|
|
216
|
+
}
|
|
217
|
+
const metadata = parseFrontmatter(translatedSource).frontmatter;
|
|
218
|
+
if (metadata.draft === true || metadata.disabled === true) throw new Error(`Unpublished translated MDX include: ${translated}`);
|
|
219
|
+
return {
|
|
220
|
+
...resolved,
|
|
221
|
+
id: translated + suffix
|
|
222
|
+
};
|
|
223
|
+
}
|
|
175
224
|
};
|
|
176
225
|
}
|
|
226
|
+
// src/astro/style-assets.ts
|
|
227
|
+
/** Collapse only the compiler's unconditional, same-directory asset links.
|
|
228
|
+
* This is concatenation of already compiled CSS, not a second CSS compiler.
|
|
229
|
+
* Keep conditions, layers, URLs, repeated occurrences and unrelated imports intact.
|
|
230
|
+
*/
|
|
231
|
+
async function inlineGeneratedStyles(file, ancestors = []) {
|
|
232
|
+
if (ancestors.includes(file)) throw new Error(`Cyclic generated stylesheet: ${file}`);
|
|
233
|
+
const source = await readFile(file, "utf8");
|
|
234
|
+
let code = "", cursor = 0;
|
|
235
|
+
while (cursor < source.length) {
|
|
236
|
+
const rest = source.slice(cursor);
|
|
237
|
+
const trivia = /^(?:\s+|\/\*[\s\S]*?\*\/|@layer\s+[\w,\s-]+;)/.exec(rest);
|
|
238
|
+
if (trivia) {
|
|
239
|
+
code += trivia[0];
|
|
240
|
+
cursor += trivia[0].length;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
const match = /^@import\s+["'](\.\/master-css-[\w-]+\.css)["']\s*;/.exec(rest);
|
|
244
|
+
if (!match) break;
|
|
245
|
+
code += await inlineGeneratedStyles(resolve(dirname(file), match[1]), [...ancestors, file]) + "\n";
|
|
246
|
+
cursor += match[0].length;
|
|
247
|
+
}
|
|
248
|
+
const expanded = code + source.slice(cursor);
|
|
249
|
+
return /@(?:import|charset|namespace)\b/.test(expanded) ? source : expanded;
|
|
250
|
+
}
|
|
251
|
+
/** Preserve HTML link order and each reusable entry's cache identity. Originals
|
|
252
|
+
* remain available to any JS/CSS references; no client loading logic is added. */
|
|
253
|
+
async function compactStyleAssets(output) {
|
|
254
|
+
const root = resolve(output), replacements = /* @__PURE__ */ new Map();
|
|
255
|
+
const documents = /* @__PURE__ */ new Map(), users = /* @__PURE__ */ new Map();
|
|
256
|
+
const boundaries = /* @__PURE__ */ new Set();
|
|
257
|
+
async function emit(code) {
|
|
258
|
+
const href = `/_astro/site-style-${createHash("sha256").update(code).digest("hex").slice(0, 20)}.css`;
|
|
259
|
+
await writeFile(resolve(root, "." + href), code);
|
|
260
|
+
return href;
|
|
261
|
+
}
|
|
262
|
+
async function walk(directory) {
|
|
263
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
264
|
+
const file = resolve(directory, entry.name);
|
|
265
|
+
if (entry.isDirectory()) {
|
|
266
|
+
await walk(file);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (!entry.name.endsWith(".html")) continue;
|
|
270
|
+
let html = await readFile(file, "utf8");
|
|
271
|
+
const links = [...html.matchAll(/<link\b(?=[^>]*\brel="stylesheet")(?=[^>]*\bhref="(\/_astro\/[^"/]+\.css)")[^>]*>/g)];
|
|
272
|
+
for (const match of links) {
|
|
273
|
+
const href = match[1];
|
|
274
|
+
if (!replacements.has(href)) {
|
|
275
|
+
const input = resolve(root, "." + href);
|
|
276
|
+
const source = await readFile(input, "utf8");
|
|
277
|
+
const code = await inlineGeneratedStyles(input);
|
|
278
|
+
const next = source === code ? href : await emit(code);
|
|
279
|
+
replacements.set(href, next);
|
|
280
|
+
}
|
|
281
|
+
const next = replacements.get(href);
|
|
282
|
+
if (/\/(site|interface|documents)\./.test(href)) boundaries.add(next);
|
|
283
|
+
const pages = users.get(next) ?? [];
|
|
284
|
+
if (!pages.includes(file)) pages.push(file);
|
|
285
|
+
users.set(next, pages);
|
|
286
|
+
html = html.replace(match[0], match[0].replace(`href="${href}"`, `href="${next}"`));
|
|
287
|
+
}
|
|
288
|
+
documents.set(file, html);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
await walk(root);
|
|
292
|
+
const signatures = new Map([...users].map(([href, pages]) => [href, pages.sort().join("\n")]));
|
|
293
|
+
const adjacent = /* @__PURE__ */ new Map();
|
|
294
|
+
for (const [file, html] of documents) for (const match of html.matchAll(/(?=<link rel="stylesheet" href="([^"\s]+)">\s*<link rel="stylesheet" href="([^"\s]+)">)/g)) {
|
|
295
|
+
const key = `${match[1]}\n${match[2]}`;
|
|
296
|
+
const pages = adjacent.get(key) ?? /* @__PURE__ */ new Set();
|
|
297
|
+
pages.add(file);
|
|
298
|
+
adjacent.set(key, pages);
|
|
299
|
+
}
|
|
300
|
+
for (const [file, source] of documents) {
|
|
301
|
+
let html = source;
|
|
302
|
+
const runs = [...source.matchAll(/(?:<link rel="stylesheet" href="\/_astro\/[^"/]+\.css">\s*){2,}/g)];
|
|
303
|
+
for (const run of runs) {
|
|
304
|
+
const links = [...run[0].matchAll(/<link rel="stylesheet" href="([^"\s]+)">\s*/g)];
|
|
305
|
+
let replacement = "", group = [];
|
|
306
|
+
async function flush() {
|
|
307
|
+
if (group.length > 1) {
|
|
308
|
+
const code = (await Promise.all(group.map((link) => readFile(resolve(root, "." + link[1]), "utf8")))).join("\n");
|
|
309
|
+
replacement += code.includes("@import") ? group.map((link) => link[0]).join("") : `<link rel="stylesheet" href="${await emit(code)}">`;
|
|
310
|
+
} else replacement += group.map((link) => link[0]).join("");
|
|
311
|
+
group = [];
|
|
312
|
+
}
|
|
313
|
+
for (const link of links) {
|
|
314
|
+
if (boundaries.has(link[1])) {
|
|
315
|
+
await flush();
|
|
316
|
+
replacement += link[0];
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (group.length && (signatures.get(group[0][1]) !== signatures.get(link[1]) || adjacent.get(`${group.at(-1)[1]}\n${link[1]}`)?.size !== users.get(link[1])?.length)) await flush();
|
|
320
|
+
group.push(link);
|
|
321
|
+
}
|
|
322
|
+
await flush();
|
|
323
|
+
html = html.replace(run[0], replacement);
|
|
324
|
+
}
|
|
325
|
+
await writeFile(file, html);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
177
328
|
// src/docs-shell/remark/slug-and-toc.js
|
|
178
329
|
function remarkSlugAndTOC() {
|
|
179
330
|
return (tree) => {
|
|
180
|
-
const
|
|
331
|
+
const resolveHeading = createHeadingResolver();
|
|
181
332
|
const toc = [];
|
|
182
333
|
visit(tree, "heading", (node) => {
|
|
183
334
|
const depth = node.depth;
|
|
184
|
-
if (depth
|
|
335
|
+
if (depth < 2 || depth > 6) return;
|
|
185
336
|
const title = node.children.filter((n) => n.type === "text" || n.type === "inlineCode").map((n) => n.value).join(" ").trim();
|
|
186
|
-
const resolved = resolveHeading(title,
|
|
337
|
+
const resolved = resolveHeading(title, depth);
|
|
187
338
|
const lastText = node.children.findLast((child) => child.type === "text");
|
|
188
339
|
if (lastText) lastText.value = lastText.value.replace(/\s+\{#[\w-]+\}$/, "");
|
|
189
340
|
node.data ??= {};
|
|
190
341
|
node.data.hProperties ??= {};
|
|
191
342
|
node.data.id = resolved.id;
|
|
192
343
|
node.data.hProperties.id = resolved.id;
|
|
193
|
-
toc.push({
|
|
344
|
+
if (depth === 2 || depth === 3) toc.push({
|
|
194
345
|
id: resolved.id,
|
|
195
346
|
title: resolved.title,
|
|
196
347
|
level: depth
|
|
@@ -301,8 +452,38 @@ function fenceProps(node) {
|
|
|
301
452
|
if (!props.lang) props.lang = node.lang ?? "";
|
|
302
453
|
return props;
|
|
303
454
|
}
|
|
304
|
-
const
|
|
305
|
-
|
|
455
|
+
const componentPaths = {
|
|
456
|
+
a: "markdown/Anchor.astro",
|
|
457
|
+
h2: "markdown/Heading2.astro",
|
|
458
|
+
h3: "markdown/Heading3.astro",
|
|
459
|
+
img: "Image.svelte",
|
|
460
|
+
Image: "Image.svelte",
|
|
461
|
+
table: "markdown/Table.astro",
|
|
462
|
+
Code: "Code.astro",
|
|
463
|
+
InlineCode: "InlineCode.astro",
|
|
464
|
+
PMAction: "PMAction.astro",
|
|
465
|
+
Do: "Do.astro",
|
|
466
|
+
DoNot: "DoNot.astro",
|
|
467
|
+
Info: "Info.astro",
|
|
468
|
+
Warn: "Warn.astro",
|
|
469
|
+
InteractingIndicator: "InteractingIndicator.astro"
|
|
470
|
+
};
|
|
471
|
+
function documentComponents(tree) {
|
|
472
|
+
const used = /* @__PURE__ */ new Set();
|
|
473
|
+
visit(tree, (node) => {
|
|
474
|
+
if (node.type === "link" || node.type === "linkReference") used.add("a");
|
|
475
|
+
if (node.type === "image" || node.type === "imageReference") used.add("img");
|
|
476
|
+
if (node.type === "table") used.add("table");
|
|
477
|
+
if (node.type === "heading" && [2, 3].includes(node.depth)) used.add(`h${node.depth}`);
|
|
478
|
+
if (["mdxJsxFlowElement", "mdxJsxTextElement"].includes(node.type) && node.name in componentPaths) used.add(node.name);
|
|
479
|
+
});
|
|
480
|
+
const entries = [...used].sort().map((name, index) => ({
|
|
481
|
+
name,
|
|
482
|
+
local: `__masterComponent${index}`,
|
|
483
|
+
path: componentPaths[name]
|
|
484
|
+
}));
|
|
485
|
+
return entries.map(({ local, path }) => `import ${local} from '@master/internal-site/components/${path}'`).join("\n") + `\nexport const components = {${entries.map(({ name, local }) => `${name}: ${local}`).join(", ")}}`;
|
|
486
|
+
}
|
|
306
487
|
/**
|
|
307
488
|
* Markdown constructs that render through site components: fences become `Code` (or a
|
|
308
489
|
* package-manager `PMAction`), inline code becomes `InlineCode`, and marked paragraphs become
|
|
@@ -310,14 +491,6 @@ export const components = __markdownComponents`;
|
|
|
310
491
|
*/
|
|
311
492
|
function remarkMarkdownComponents() {
|
|
312
493
|
return (tree) => {
|
|
313
|
-
tree.children.unshift({
|
|
314
|
-
type: "mdxjsEsm",
|
|
315
|
-
value: componentsExport,
|
|
316
|
-
data: { estree: parse(componentsExport, {
|
|
317
|
-
ecmaVersion: "latest",
|
|
318
|
-
sourceType: "module"
|
|
319
|
-
}) }
|
|
320
|
-
});
|
|
321
494
|
visit(tree, (node, index, parent) => {
|
|
322
495
|
if (!parent || index === void 0) return;
|
|
323
496
|
if (node.type === "code") {
|
|
@@ -352,6 +525,15 @@ function remarkMarkdownComponents() {
|
|
|
352
525
|
return index;
|
|
353
526
|
}
|
|
354
527
|
});
|
|
528
|
+
const source = documentComponents(tree);
|
|
529
|
+
tree.children.unshift({
|
|
530
|
+
type: "mdxjsEsm",
|
|
531
|
+
value: source,
|
|
532
|
+
data: { estree: parse(source, {
|
|
533
|
+
ecmaVersion: "latest",
|
|
534
|
+
sourceType: "module"
|
|
535
|
+
}) }
|
|
536
|
+
});
|
|
355
537
|
};
|
|
356
538
|
}
|
|
357
539
|
// src/astro/index.ts
|
|
@@ -364,7 +546,8 @@ function masterSite(site) {
|
|
|
364
546
|
return {
|
|
365
547
|
name: "@master/internal-site",
|
|
366
548
|
hooks: {
|
|
367
|
-
"astro:config:setup": async ({ config, updateConfig, addRenderer, injectRoute }) => {
|
|
549
|
+
"astro:config:setup": async ({ config, command, updateConfig, addRenderer, injectRoute }) => {
|
|
550
|
+
if (command === "build") await validateSiteTranslations(site.i18n);
|
|
368
551
|
const root = fileURLToPath(config.root);
|
|
369
552
|
const contentRelative = relative(root, fileURLToPath(site.content)).split(sep).join("/");
|
|
370
553
|
if (contentRelative.startsWith("..")) throw new Error("Site content must be inside the Astro project root");
|
|
@@ -382,7 +565,8 @@ function masterSite(site) {
|
|
|
382
565
|
"virtual:master-site/config": `export default ${JSON.stringify(site)}`,
|
|
383
566
|
"virtual:master-site/app": moduleImport(site.app),
|
|
384
567
|
"virtual:master-site/highlight": moduleImport(site.highlighter ?? new URL("../docs-shell/utils/highlight-code-core.ts", new URL("../src/astro/index.ts", import.meta.url).href)),
|
|
385
|
-
"virtual:master-site/translations": `export default
|
|
568
|
+
"virtual:master-site/translations": `export default {${Object.entries(prepared.localizedDocuments).map(([pathname, documents]) => `${JSON.stringify(pathname)}: {${Object.entries(documents).map(([locale, url]) => `${JSON.stringify(locale)}: ${propagated(url)}`).join(",")}}`).join(",")}}`,
|
|
569
|
+
"virtual:master-site/localized-metadata": `export default ${JSON.stringify(prepared.localizedMetadata)}`
|
|
386
570
|
};
|
|
387
571
|
const plugin = {
|
|
388
572
|
name: "@master/internal-site:modules",
|
|
@@ -420,10 +604,10 @@ function masterSite(site) {
|
|
|
420
604
|
server.restart();
|
|
421
605
|
}, 100);
|
|
422
606
|
};
|
|
423
|
-
server.watcher.on("add", refresh).on("unlink", refresh);
|
|
607
|
+
server.watcher.on("add", refresh).on("unlink", refresh).on("change", refresh);
|
|
424
608
|
server.httpServer?.once("close", () => {
|
|
425
609
|
clearTimeout(restart);
|
|
426
|
-
server.watcher.off("add", refresh).off("unlink", refresh);
|
|
610
|
+
server.watcher.off("add", refresh).off("unlink", refresh).off("change", refresh);
|
|
427
611
|
});
|
|
428
612
|
server.middlewares.use((request, response, next) => {
|
|
429
613
|
let pathname;
|
|
@@ -479,6 +663,7 @@ function masterSite(site) {
|
|
|
479
663
|
vite: {
|
|
480
664
|
plugins: [
|
|
481
665
|
plugin,
|
|
666
|
+
localizedMdx(site.i18n),
|
|
482
667
|
sourceURL(),
|
|
483
668
|
serverStyles([root, packageSource]),
|
|
484
669
|
svgMarkup()
|
|
@@ -503,6 +688,7 @@ function masterSite(site) {
|
|
|
503
688
|
recursive: true,
|
|
504
689
|
force: false
|
|
505
690
|
});
|
|
691
|
+
await compactStyleAssets(fileURLToPath(destination));
|
|
506
692
|
}
|
|
507
693
|
}
|
|
508
694
|
};
|
package/dist/config.d.mts
CHANGED
|
@@ -31,10 +31,16 @@ export interface SiteI18nConfig {
|
|
|
31
31
|
hreflangOfLocale: Record<string, string>;
|
|
32
32
|
nameOfLocale: Record<string, string>;
|
|
33
33
|
localizablePathnameRoots: string[];
|
|
34
|
+
localizableOrigins?: Record<string, readonly string[]>;
|
|
34
35
|
translations: Record<string, Record<string, string>>;
|
|
35
36
|
sectionLocales?: Record<string, readonly string[]>;
|
|
36
37
|
/** These sections emit translated URLs only when translated MDX exists. */
|
|
37
38
|
translatedOnly?: readonly string[];
|
|
39
|
+
/** Build-only resource loader and version-controlled explicit translation reviews. */
|
|
40
|
+
validation?: {
|
|
41
|
+
reviews: URL;
|
|
42
|
+
resources: URL;
|
|
43
|
+
};
|
|
38
44
|
}
|
|
39
45
|
export interface DocumentConfig {
|
|
40
46
|
layout: URL;
|