@refrakt-md/content 0.12.0 → 0.14.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/dist/frontmatter.d.ts +17 -0
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +29 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +31 -1
- package/dist/loader.js.map +1 -1
- package/dist/refract-loader.d.ts +53 -1
- package/dist/refract-loader.d.ts.map +1 -1
- package/dist/refract-loader.js +131 -42
- package/dist/refract-loader.js.map +1 -1
- package/dist/site.d.ts +52 -0
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +132 -34
- package/dist/site.js.map +1 -1
- package/dist/tint-cascade.d.ts +45 -0
- package/dist/tint-cascade.d.ts.map +1 -0
- package/dist/tint-cascade.js +71 -0
- package/dist/tint-cascade.js.map +1 -0
- package/dist/tint-ssr.d.ts +46 -0
- package/dist/tint-ssr.d.ts.map +1 -0
- package/dist/tint-ssr.js +67 -0
- package/dist/tint-ssr.js.map +1 -0
- package/package.json +5 -5
package/dist/frontmatter.d.ts
CHANGED
|
@@ -9,6 +9,23 @@ export interface Frontmatter {
|
|
|
9
9
|
author?: string;
|
|
10
10
|
tags?: string[];
|
|
11
11
|
image?: string;
|
|
12
|
+
/** Icon name resolvable by the `{% icon %}` rune. Used by `nav layout="cards"`
|
|
13
|
+
* to render an icon on each child page card. */
|
|
14
|
+
icon?: string;
|
|
15
|
+
/** Named tint preset to apply for this page (or subtree, when set in a
|
|
16
|
+
* `_layout.md`). Cascades down the layout chain; explicit `null` resets
|
|
17
|
+
* to inherit from the layer above. See SPEC-052. */
|
|
18
|
+
tint?: string | null;
|
|
19
|
+
/** Initial colour-scheme behaviour for this page (or subtree, when set in
|
|
20
|
+
* a `_layout.md`). `'auto'` follows user preference and system pref;
|
|
21
|
+
* `'light'` / `'dark'` lock the SSR-emitted mode. Cascades down the
|
|
22
|
+
* layout chain. */
|
|
23
|
+
'tint-mode'?: 'auto' | 'light' | 'dark';
|
|
24
|
+
/** When `true`, the page (or subtree) ignores user theme preference and
|
|
25
|
+
* hides the theme-toggle UI — used for marketing surfaces where the
|
|
26
|
+
* brand should look the same to every visitor. Cascades down the layout
|
|
27
|
+
* chain. See SPEC-052. */
|
|
28
|
+
'tint-lock'?: boolean;
|
|
12
29
|
[key: string]: unknown;
|
|
13
30
|
}
|
|
14
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAW3F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKtF"}
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;qDACiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;yDAEqD;IACrD,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;wBAGoB;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACxC;;;+BAG2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAW3F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKtF"}
|
package/dist/frontmatter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAiCxB;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAExE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAgB,IAAI,EAAE,CAAC;IACpE,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEzB,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAwB,EAAE,OAAe;IAC5E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IACxE,OAAO,QAAQ,OAAO,UAAU,OAAO,EAAE,CAAC;AAC5C,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,13 +2,15 @@ export { ContentTree, type ContentNode, type ContentPage, type ContentDirectory,
|
|
|
2
2
|
export { parseFrontmatter, serializeFrontmatter, type Frontmatter } from './frontmatter.js';
|
|
3
3
|
export { Router, type Route } from './router.js';
|
|
4
4
|
export { resolveLayouts, type ResolvedLayout, type Region } from './layout.js';
|
|
5
|
+
export { resolveTintCascade, type ResolvedTintCascade, type CascadeRootDefaults, } from './tint-cascade.js';
|
|
6
|
+
export { htmlTintAttributes, colorSchemeMetaContent, prePaintScript } from './tint-ssr.js';
|
|
5
7
|
export { buildNavigation, type NavTree, type NavGroup, type NavItem } from './navigation.js';
|
|
6
|
-
export { loadContent, type Site, type SitePage } from './site.js';
|
|
7
|
-
export { createSiteLoader, type SiteLoader, type SiteLoaderOptions } from './loader.js';
|
|
8
|
+
export { loadContent, loadContentFromTree, type Site, type SitePage, type LoadContentFromTreeOptions, type VirtualReader } from './site.js';
|
|
9
|
+
export { createSiteLoader, createVirtualSiteLoader, type SiteLoader, type SiteLoaderOptions, type VirtualSiteLoaderOptions } from './loader.js';
|
|
8
10
|
export { generateSitemap, type SitemapEntry } from './sitemap.js';
|
|
9
11
|
export { collectRuneTypes, analyzeRuneUsage, type RuneUsageReport } from './analyze.js';
|
|
10
12
|
export { getGitTimestamps, getStatTimestamps, resolveTimestamps, type FileTimestamps } from './timestamps.js';
|
|
11
13
|
export { EntityRegistryImpl } from './registry.js';
|
|
12
|
-
export { createRefraktLoader, type RefraktLoader, type RefraktLoaderOptions } from './refract-loader.js';
|
|
14
|
+
export { createRefraktLoader, createVirtualRefraktLoader, buildHighlightOptions, type RefraktLoader, type RefraktLoaderOptions, type VirtualRefraktLoaderOptions } from './refract-loader.js';
|
|
13
15
|
export { runPipeline, type HookSet, type PipelineResult, type PipelineStats } from './pipeline.js';
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7H,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7H,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,KAAK,0BAA0B,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5I,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAChJ,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC9G,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAC9L,OAAO,EAAE,WAAW,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,13 +2,15 @@ export { ContentTree } from './content-tree.js';
|
|
|
2
2
|
export { parseFrontmatter, serializeFrontmatter } from './frontmatter.js';
|
|
3
3
|
export { Router } from './router.js';
|
|
4
4
|
export { resolveLayouts } from './layout.js';
|
|
5
|
+
export { resolveTintCascade, } from './tint-cascade.js';
|
|
6
|
+
export { htmlTintAttributes, colorSchemeMetaContent, prePaintScript } from './tint-ssr.js';
|
|
5
7
|
export { buildNavigation } from './navigation.js';
|
|
6
|
-
export { loadContent } from './site.js';
|
|
7
|
-
export { createSiteLoader } from './loader.js';
|
|
8
|
+
export { loadContent, loadContentFromTree } from './site.js';
|
|
9
|
+
export { createSiteLoader, createVirtualSiteLoader } from './loader.js';
|
|
8
10
|
export { generateSitemap } from './sitemap.js';
|
|
9
11
|
export { collectRuneTypes, analyzeRuneUsage } from './analyze.js';
|
|
10
12
|
export { getGitTimestamps, getStatTimestamps, resolveTimestamps } from './timestamps.js';
|
|
11
13
|
export { EntityRegistryImpl } from './registry.js';
|
|
12
|
-
export { createRefraktLoader } from './refract-loader.js';
|
|
14
|
+
export { createRefraktLoader, createVirtualRefraktLoader, buildHighlightOptions } from './refract-loader.js';
|
|
13
15
|
export { runPipeline } from './pipeline.js';
|
|
14
16
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA+E,MAAM,mBAAmB,CAAC;AAC7H,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAoB,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,MAAM,EAAc,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,eAAe,EAA6C,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA+E,MAAM,mBAAmB,CAAC;AAC7H,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAoB,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,MAAM,EAAc,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAC;AAC/E,OAAO,EACL,kBAAkB,GAGnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,eAAe,EAA6C,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAiF,MAAM,WAAW,CAAC;AAC5I,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAA0E,MAAM,aAAa,CAAC;AAChJ,OAAO,EAAE,eAAe,EAAqB,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAwB,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAuB,MAAM,iBAAiB,CAAC;AAC9G,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,qBAAqB,EAAmF,MAAM,qBAAqB,CAAC;AAC9L,OAAO,EAAE,WAAW,EAAyD,MAAM,eAAe,CAAC"}
|
package/dist/loader.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Schema } from '@markdoc/markdoc';
|
|
2
|
-
import type { Plugin } from '@refrakt-md/types';
|
|
3
|
-
import { type Site } from './site.js';
|
|
2
|
+
import type { Plugin, SecurityPolicy } from '@refrakt-md/types';
|
|
3
|
+
import { type Site, type VirtualReader } from './site.js';
|
|
4
|
+
import type { ContentTree } from './content-tree.js';
|
|
4
5
|
export interface SiteLoaderOptions {
|
|
5
6
|
dirPath: string;
|
|
6
7
|
basePath?: string;
|
|
@@ -20,4 +21,30 @@ export interface SiteLoader {
|
|
|
20
21
|
invalidate(): void;
|
|
21
22
|
}
|
|
22
23
|
export declare function createSiteLoader(options: SiteLoaderOptions): SiteLoader;
|
|
24
|
+
export interface VirtualSiteLoaderOptions {
|
|
25
|
+
/** Pre-built content tree. The page corpus, layouts, and partials are read
|
|
26
|
+
* from here — there is no filesystem fallback. */
|
|
27
|
+
tree: ContentTree;
|
|
28
|
+
basePath?: string;
|
|
29
|
+
icons?: Record<string, Record<string, string>>;
|
|
30
|
+
additionalTags?: Record<string, Schema>;
|
|
31
|
+
plugins?: Plugin[];
|
|
32
|
+
/** Site-wide Markdoc variables available in content via {% $name %} syntax. */
|
|
33
|
+
variables?: Record<string, unknown>;
|
|
34
|
+
/** Security policy for sandbox runes. Default: `'trusted'`. */
|
|
35
|
+
securityPolicy?: SecurityPolicy;
|
|
36
|
+
/** Optional async reader for ad-hoc lookups. Forward-compatibility hook —
|
|
37
|
+
* see `LoadContentFromTreeOptions.reader` for details. */
|
|
38
|
+
reader?: VirtualReader;
|
|
39
|
+
/** When true, every load() call re-runs the pipeline against the current
|
|
40
|
+
* tree (no caching). Use when the host swaps the tree's contents in place. */
|
|
41
|
+
dev?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Site loader for hosted (non-filesystem) environments. Wraps
|
|
45
|
+
* {@link loadContentFromTree} with the same caching semantics as
|
|
46
|
+
* {@link createSiteLoader}: the result is memoized until `invalidate()` is
|
|
47
|
+
* called, unless `dev: true`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createVirtualSiteLoader(options: VirtualSiteLoaderOptions): SiteLoader;
|
|
23
50
|
//# sourceMappingURL=loader.d.ts.map
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAoC,KAAK,IAAI,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,oFAAoF;IACpF,GAAG,CAAC,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IAC1B,0DAA0D;IAC1D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,sEAAsE;IACtE,UAAU,IAAI,IAAI,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAsBvE;AAED,MAAM,WAAW,wBAAwB;IACxC;uDACmD;IACnD,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC;+DAC2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB;mFAC+E;IAC/E,GAAG,CAAC,EAAE,OAAO,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,UAAU,CAsBrF"}
|
package/dist/loader.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loadContent } from './site.js';
|
|
1
|
+
import { loadContent, loadContentFromTree } from './site.js';
|
|
2
2
|
export function createSiteLoader(options) {
|
|
3
3
|
let cached = null;
|
|
4
4
|
return {
|
|
@@ -15,4 +15,34 @@ export function createSiteLoader(options) {
|
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Site loader for hosted (non-filesystem) environments. Wraps
|
|
20
|
+
* {@link loadContentFromTree} with the same caching semantics as
|
|
21
|
+
* {@link createSiteLoader}: the result is memoized until `invalidate()` is
|
|
22
|
+
* called, unless `dev: true`.
|
|
23
|
+
*/
|
|
24
|
+
export function createVirtualSiteLoader(options) {
|
|
25
|
+
let cached = null;
|
|
26
|
+
return {
|
|
27
|
+
load() {
|
|
28
|
+
if (!options.dev && cached)
|
|
29
|
+
return cached;
|
|
30
|
+
const promise = loadContentFromTree(options.tree, {
|
|
31
|
+
basePath: options.basePath,
|
|
32
|
+
icons: options.icons,
|
|
33
|
+
additionalTags: options.additionalTags,
|
|
34
|
+
plugins: options.plugins,
|
|
35
|
+
variables: options.variables,
|
|
36
|
+
securityPolicy: options.securityPolicy,
|
|
37
|
+
reader: options.reader,
|
|
38
|
+
});
|
|
39
|
+
if (!options.dev)
|
|
40
|
+
cached = promise;
|
|
41
|
+
return promise;
|
|
42
|
+
},
|
|
43
|
+
invalidate() {
|
|
44
|
+
cached = null;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
18
48
|
//# sourceMappingURL=loader.js.map
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAiC,MAAM,WAAW,CAAC;AAuB5F,MAAM,UAAU,gBAAgB,CAAC,OAA0B;IAC1D,IAAI,MAAM,GAAyB,IAAI,CAAC;IAExC,OAAO;QACN,IAAI;YACH,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAC1C,MAAM,OAAO,GAAG,WAAW,CAC1B,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,cAAc,EACtB,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,kBAAkB,EAC1B,OAAO,CAAC,SAAS,CACjB,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,GAAG;gBAAE,MAAM,GAAG,OAAO,CAAC;YACnC,OAAO,OAAO,CAAC;QAChB,CAAC;QACD,UAAU;YACT,MAAM,GAAG,IAAI,CAAC;QACf,CAAC;KACD,CAAC;AACH,CAAC;AAsBD;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAiC;IACxE,IAAI,MAAM,GAAyB,IAAI,CAAC;IAExC,OAAO;QACN,IAAI;YACH,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAC1C,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,IAAI,EAAE;gBACjD,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,MAAM,EAAE,OAAO,CAAC,MAAM;aACtB,CAAC,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,GAAG;gBAAE,MAAM,GAAG,OAAO,CAAC;YACnC,OAAO,OAAO,CAAC;QAChB,CAAC;QACD,UAAU;YACT,MAAM,GAAG,IAAI,CAAC;QACf,CAAC;KACD,CAAC;AACH,CAAC"}
|
package/dist/refract-loader.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SiteConfig } from '@refrakt-md/types';
|
|
2
|
+
import type { ContentTree } from './content-tree.js';
|
|
3
|
+
import type { Site, VirtualReader } from './site.js';
|
|
2
4
|
export interface RefraktLoaderOptions {
|
|
3
5
|
/** Path to refrakt.config.json. Default: './refrakt.config.json' */
|
|
4
6
|
configPath?: string;
|
|
@@ -23,5 +25,55 @@ export interface RefraktLoader {
|
|
|
23
25
|
/** Clears the cached site so the next getSite() re-reads from disk. */
|
|
24
26
|
invalidateSite(): void;
|
|
25
27
|
}
|
|
28
|
+
/** Compose the options bag handed to `createHighlightTransform`. Merges the
|
|
29
|
+
* site's `highlight.*` block with theme-level code settings (`theme.code.*`)
|
|
30
|
+
* so a single object reaches the transform — keeps adapter call sites tidy
|
|
31
|
+
* and lets the highlight package stay unaware of where each option comes
|
|
32
|
+
* from. Exported so non-SvelteKit adapters (HTML build script, Astro setup,
|
|
33
|
+
* custom hosts) can compose options the same way. */
|
|
34
|
+
export declare function buildHighlightOptions(site: SiteConfig): {
|
|
35
|
+
codeColorScheme?: "auto" | "light" | "dark" | undefined;
|
|
36
|
+
theme?: string | {
|
|
37
|
+
light: string;
|
|
38
|
+
dark: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
26
41
|
export declare function createRefraktLoader(options?: RefraktLoaderOptions): RefraktLoader;
|
|
42
|
+
export interface VirtualRefraktLoaderOptions {
|
|
43
|
+
/** Pre-resolved per-site configuration. The caller is responsible for
|
|
44
|
+
* selecting the site (e.g., via `resolveSite()`) and normalizing any
|
|
45
|
+
* config-relative paths. Filesystem paths inside this config (`theme`,
|
|
46
|
+
* `contentDir`, plugin specifiers) are still resolved through the Node
|
|
47
|
+
* module loader where applicable; only authoring content is virtualized. */
|
|
48
|
+
site: SiteConfig;
|
|
49
|
+
/** Pre-built content tree. Required — the page corpus, layouts, and
|
|
50
|
+
* partials all come from here. */
|
|
51
|
+
tree: ContentTree;
|
|
52
|
+
/** Optional async reader for ad-hoc lookups. Reserved; see
|
|
53
|
+
* {@link VirtualReader}. */
|
|
54
|
+
reader?: VirtualReader;
|
|
55
|
+
/** Markdoc variables available in content via {% $name %} syntax. */
|
|
56
|
+
variables?: Record<string, unknown>;
|
|
57
|
+
/** URL base path for the Router. Default: `'/'`. */
|
|
58
|
+
basePath?: string;
|
|
59
|
+
/** Skip caching — re-run the pipeline on every load(). Default: false. */
|
|
60
|
+
dev?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Refrakt loader for hosted (non-filesystem) environments. Sibling to
|
|
64
|
+
* {@link createRefraktLoader}.
|
|
65
|
+
*
|
|
66
|
+
* Differences:
|
|
67
|
+
* - Accepts a pre-resolved {@link SiteConfig} instead of reading
|
|
68
|
+
* `refrakt.config.json` from disk. The caller is expected to source and
|
|
69
|
+
* normalize the config however suits their host (env, DB, GitHub, etc.).
|
|
70
|
+
* - Drives content from a pre-built {@link ContentTree} rather than walking
|
|
71
|
+
* the filesystem. Combine with a `reader` for forward-compatibility with
|
|
72
|
+
* future async lookup paths.
|
|
73
|
+
*
|
|
74
|
+
* Theme module and plugin specifiers are still resolved through Node's module
|
|
75
|
+
* loader, so the theme package and any plugins must be reachable as installed
|
|
76
|
+
* dependencies in the host environment.
|
|
77
|
+
*/
|
|
78
|
+
export declare function createVirtualRefraktLoader(options: VirtualRefraktLoaderOptions): RefraktLoader;
|
|
27
79
|
//# sourceMappingURL=refract-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refract-loader.d.ts","sourceRoot":"","sources":["../src/refract-loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"refract-loader.d.ts","sourceRoot":"","sources":["../src/refract-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAU,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAQ5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACpC,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;2DACuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,8DAA8D;IAC9D,GAAG,CAAC,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC7B,wDAAwD;IACxD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,yDAAyD;IACzD,YAAY,IAAI,OAAO,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IAC5C,8CAA8C;IAC9C,qBAAqB,IAAI,OAAO,CAAC;QAAE,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,uEAAuE;IACvE,cAAc,IAAI,IAAI,CAAC;CACvB;AASD;;;;;sDAKsD;AACtD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU;;;;;;EAQrD;AA0DD,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAuDjF;AAED,MAAM,WAAW,2BAA2B;IAC3C;;;;iFAI6E;IAC7E,IAAI,EAAE,UAAU,CAAC;IACjB;uCACmC;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB;iCAC6B;IAC7B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,OAAO,CAAC;CACd;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,aAAa,CAkD9F"}
|
package/dist/refract-loader.js
CHANGED
|
@@ -1,7 +1,69 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { getThemePackage } from '@refrakt-md/types';
|
|
3
4
|
import { normalizeRefraktConfig, resolveSite } from '@refrakt-md/transform/node';
|
|
4
|
-
import { createSiteLoader } from './loader.js';
|
|
5
|
+
import { createSiteLoader, createVirtualSiteLoader, } from './loader.js';
|
|
6
|
+
/** Compose the options bag handed to `createHighlightTransform`. Merges the
|
|
7
|
+
* site's `highlight.*` block with theme-level code settings (`theme.code.*`)
|
|
8
|
+
* so a single object reaches the transform — keeps adapter call sites tidy
|
|
9
|
+
* and lets the highlight package stay unaware of where each option comes
|
|
10
|
+
* from. Exported so non-SvelteKit adapters (HTML build script, Astro setup,
|
|
11
|
+
* custom hosts) can compose options the same way. */
|
|
12
|
+
export function buildHighlightOptions(site) {
|
|
13
|
+
const themeCode = typeof site.theme === 'object' && site.theme !== null
|
|
14
|
+
? site.theme.code
|
|
15
|
+
: undefined;
|
|
16
|
+
return {
|
|
17
|
+
...(site.highlight ?? {}),
|
|
18
|
+
...(themeCode?.colorScheme ? { codeColorScheme: themeCode.colorScheme } : {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Resolve a site's theme module + plugin merges into a single context object.
|
|
22
|
+
* Shared between the FS loader and the virtual loader so both produce
|
|
23
|
+
* byte-identical transforms from the same SiteConfig. */
|
|
24
|
+
async function assembleSiteContext(site) {
|
|
25
|
+
const themePackage = getThemePackage(site.theme);
|
|
26
|
+
const themeModule = await import(/* @vite-ignore */ themePackage + '/transform');
|
|
27
|
+
const themeConfig = themeModule.themeConfig ?? themeModule.luminaConfig ?? themeModule.default;
|
|
28
|
+
const icons = {
|
|
29
|
+
...themeConfig.icons,
|
|
30
|
+
global: { ...(themeConfig.icons?.global ?? {}), ...(site.icons ?? {}) },
|
|
31
|
+
};
|
|
32
|
+
const { assembleThemeConfig, createTransform } = await import('@refrakt-md/transform');
|
|
33
|
+
const pluginNames = site.plugins ?? [];
|
|
34
|
+
if (pluginNames.length === 0) {
|
|
35
|
+
return {
|
|
36
|
+
transform: createTransform(themeConfig),
|
|
37
|
+
communityTags: undefined,
|
|
38
|
+
communityPackages: undefined,
|
|
39
|
+
icons,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const { loadPlugin, mergePlugins, runes: coreRunes } = await import('@refrakt-md/runes');
|
|
43
|
+
const loaded = await Promise.all(pluginNames.map((name) => loadPlugin(name)));
|
|
44
|
+
const coreRuneNames = new Set(Object.keys(coreRunes));
|
|
45
|
+
const merged = mergePlugins(loaded, coreRuneNames, site.runes?.prefer);
|
|
46
|
+
const { config: assembledConfig } = assembleThemeConfig({
|
|
47
|
+
coreConfig: themeConfig,
|
|
48
|
+
pluginRunes: merged.themeRunes,
|
|
49
|
+
pluginIcons: merged.themeIcons,
|
|
50
|
+
pluginBackgrounds: merged.themeBackgrounds,
|
|
51
|
+
extensions: merged.extensions,
|
|
52
|
+
provenance: merged.provenance,
|
|
53
|
+
});
|
|
54
|
+
if (site.tints) {
|
|
55
|
+
assembledConfig.tints = { ...assembledConfig.tints, ...site.tints };
|
|
56
|
+
}
|
|
57
|
+
if (site.backgrounds) {
|
|
58
|
+
assembledConfig.backgrounds = { ...assembledConfig.backgrounds, ...site.backgrounds };
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
transform: createTransform(assembledConfig),
|
|
62
|
+
communityTags: Object.keys(merged.tags).length > 0 ? merged.tags : undefined,
|
|
63
|
+
communityPackages: merged.plugins,
|
|
64
|
+
icons,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
5
67
|
export function createRefraktLoader(options) {
|
|
6
68
|
const configPath = resolve(options?.configPath ?? './refrakt.config.json');
|
|
7
69
|
const rawConfig = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
@@ -12,55 +74,20 @@ export function createRefraktLoader(options) {
|
|
|
12
74
|
const contentDir = resolve(site.contentDir);
|
|
13
75
|
let _initPromise = null;
|
|
14
76
|
let _transform = null;
|
|
15
|
-
let _communityTags;
|
|
16
|
-
let _communityPackages;
|
|
17
77
|
let _loader = null;
|
|
18
78
|
let _hl = null;
|
|
19
79
|
async function init() {
|
|
20
80
|
if (_initPromise)
|
|
21
81
|
return _initPromise;
|
|
22
82
|
_initPromise = (async () => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const themeConfig = themeModule.themeConfig ?? themeModule.luminaConfig ?? themeModule.default;
|
|
26
|
-
const icons = {
|
|
27
|
-
...themeConfig.icons,
|
|
28
|
-
global: { ...(themeConfig.icons?.global ?? {}), ...(site.icons ?? {}) },
|
|
29
|
-
};
|
|
30
|
-
const { assembleThemeConfig, createTransform } = await import('@refrakt-md/transform');
|
|
31
|
-
const pluginNames = site.plugins ?? [];
|
|
32
|
-
if (pluginNames.length === 0) {
|
|
33
|
-
_transform = createTransform(themeConfig);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
const { loadPlugin, mergePlugins, runes: coreRunes } = await import('@refrakt-md/runes');
|
|
37
|
-
const loaded = await Promise.all(pluginNames.map((name) => loadPlugin(name)));
|
|
38
|
-
const coreRuneNames = new Set(Object.keys(coreRunes));
|
|
39
|
-
const merged = mergePlugins(loaded, coreRuneNames, site.runes?.prefer);
|
|
40
|
-
_communityTags = Object.keys(merged.tags).length > 0 ? merged.tags : undefined;
|
|
41
|
-
_communityPackages = merged.plugins;
|
|
42
|
-
const { config: assembledConfig } = assembleThemeConfig({
|
|
43
|
-
coreConfig: themeConfig,
|
|
44
|
-
pluginRunes: merged.themeRunes,
|
|
45
|
-
pluginIcons: merged.themeIcons,
|
|
46
|
-
pluginBackgrounds: merged.themeBackgrounds,
|
|
47
|
-
extensions: merged.extensions,
|
|
48
|
-
provenance: merged.provenance,
|
|
49
|
-
});
|
|
50
|
-
if (site.tints) {
|
|
51
|
-
assembledConfig.tints = { ...assembledConfig.tints, ...site.tints };
|
|
52
|
-
}
|
|
53
|
-
if (site.backgrounds) {
|
|
54
|
-
assembledConfig.backgrounds = { ...assembledConfig.backgrounds, ...site.backgrounds };
|
|
55
|
-
}
|
|
56
|
-
_transform = createTransform(assembledConfig);
|
|
57
|
-
}
|
|
83
|
+
const ctx = await assembleSiteContext(site);
|
|
84
|
+
_transform = ctx.transform;
|
|
58
85
|
_loader = createSiteLoader({
|
|
59
86
|
dirPath: contentDir,
|
|
60
87
|
basePath: '/',
|
|
61
|
-
icons,
|
|
62
|
-
additionalTags:
|
|
63
|
-
plugins:
|
|
88
|
+
icons: ctx.icons,
|
|
89
|
+
additionalTags: ctx.communityTags,
|
|
90
|
+
plugins: ctx.communityPackages,
|
|
64
91
|
variables: options?.variables,
|
|
65
92
|
dev: options?.dev ?? false,
|
|
66
93
|
});
|
|
@@ -80,7 +107,69 @@ export function createRefraktLoader(options) {
|
|
|
80
107
|
if (_hl)
|
|
81
108
|
return _hl;
|
|
82
109
|
const { createHighlightTransform } = await import('@refrakt-md/highlight');
|
|
83
|
-
_hl = await createHighlightTransform(site
|
|
110
|
+
_hl = await createHighlightTransform(buildHighlightOptions(site));
|
|
111
|
+
return _hl;
|
|
112
|
+
},
|
|
113
|
+
invalidateSite() {
|
|
114
|
+
_loader?.invalidate();
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Refrakt loader for hosted (non-filesystem) environments. Sibling to
|
|
120
|
+
* {@link createRefraktLoader}.
|
|
121
|
+
*
|
|
122
|
+
* Differences:
|
|
123
|
+
* - Accepts a pre-resolved {@link SiteConfig} instead of reading
|
|
124
|
+
* `refrakt.config.json` from disk. The caller is expected to source and
|
|
125
|
+
* normalize the config however suits their host (env, DB, GitHub, etc.).
|
|
126
|
+
* - Drives content from a pre-built {@link ContentTree} rather than walking
|
|
127
|
+
* the filesystem. Combine with a `reader` for forward-compatibility with
|
|
128
|
+
* future async lookup paths.
|
|
129
|
+
*
|
|
130
|
+
* Theme module and plugin specifiers are still resolved through Node's module
|
|
131
|
+
* loader, so the theme package and any plugins must be reachable as installed
|
|
132
|
+
* dependencies in the host environment.
|
|
133
|
+
*/
|
|
134
|
+
export function createVirtualRefraktLoader(options) {
|
|
135
|
+
const { site, tree, reader, variables, basePath, dev } = options;
|
|
136
|
+
let _initPromise = null;
|
|
137
|
+
let _transform = null;
|
|
138
|
+
let _loader = null;
|
|
139
|
+
let _hl = null;
|
|
140
|
+
async function init() {
|
|
141
|
+
if (_initPromise)
|
|
142
|
+
return _initPromise;
|
|
143
|
+
_initPromise = (async () => {
|
|
144
|
+
const ctx = await assembleSiteContext(site);
|
|
145
|
+
_transform = ctx.transform;
|
|
146
|
+
_loader = createVirtualSiteLoader({
|
|
147
|
+
tree,
|
|
148
|
+
basePath: basePath ?? '/',
|
|
149
|
+
icons: ctx.icons,
|
|
150
|
+
additionalTags: ctx.communityTags,
|
|
151
|
+
plugins: ctx.communityPackages,
|
|
152
|
+
variables,
|
|
153
|
+
reader,
|
|
154
|
+
dev: dev ?? false,
|
|
155
|
+
});
|
|
156
|
+
})();
|
|
157
|
+
return _initPromise;
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
async getSite() {
|
|
161
|
+
await init();
|
|
162
|
+
return _loader.load();
|
|
163
|
+
},
|
|
164
|
+
async getTransform() {
|
|
165
|
+
await init();
|
|
166
|
+
return _transform;
|
|
167
|
+
},
|
|
168
|
+
async getHighlightTransform() {
|
|
169
|
+
if (_hl)
|
|
170
|
+
return _hl;
|
|
171
|
+
const { createHighlightTransform } = await import('@refrakt-md/highlight');
|
|
172
|
+
_hl = await createHighlightTransform(buildHighlightOptions(site));
|
|
84
173
|
return _hl;
|
|
85
174
|
},
|
|
86
175
|
invalidateSite() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refract-loader.js","sourceRoot":"","sources":["../src/refract-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,
|
|
1
|
+
{"version":3,"file":"refract-loader.js","sourceRoot":"","sources":["../src/refract-loader.ts"],"names":[],"mappings":"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"}
|
package/dist/site.d.ts
CHANGED
|
@@ -6,7 +6,11 @@ import { ContentTree, type PartialFile } from './content-tree.js';
|
|
|
6
6
|
import { Frontmatter } from './frontmatter.js';
|
|
7
7
|
import { Route } from './router.js';
|
|
8
8
|
import { ResolvedLayout } from './layout.js';
|
|
9
|
+
import { type ResolvedTintCascade } from './tint-cascade.js';
|
|
9
10
|
import { NavTree } from './navigation.js';
|
|
11
|
+
/** Async reader for ad-hoc lookups in virtual (non-FS) hosting environments.
|
|
12
|
+
* Returns the file content or `null` when the path is unknown. */
|
|
13
|
+
export type VirtualReader = (path: string) => Promise<string | null>;
|
|
10
14
|
export interface Site {
|
|
11
15
|
/** The content tree */
|
|
12
16
|
tree: ContentTree;
|
|
@@ -31,6 +35,10 @@ export interface SitePage {
|
|
|
31
35
|
headings: HeadingInfo[];
|
|
32
36
|
layout: ResolvedLayout;
|
|
33
37
|
seo: PageSeo;
|
|
38
|
+
/** Per-page tint cascade resolved from the layout chain + page frontmatter
|
|
39
|
+
* (SPEC-052). Adapters emit this as `data-theme` / `data-tint` /
|
|
40
|
+
* `data-tint-lock` attributes on `<html>` at SSR time. */
|
|
41
|
+
tintCascade: ResolvedTintCascade;
|
|
34
42
|
}
|
|
35
43
|
/**
|
|
36
44
|
* Load a content directory and resolve all pages, routes, layouts, and navigation.
|
|
@@ -47,4 +55,48 @@ export interface SitePage {
|
|
|
47
55
|
* to strip scripts and harden the sandbox iframe.
|
|
48
56
|
*/
|
|
49
57
|
export declare function loadContent(dirPath: string, basePath?: string, icons?: Record<string, Record<string, string>>, additionalTags?: Record<string, Schema>, packages?: Plugin[], sandboxExamplesDir?: string, variables?: Record<string, unknown>, securityPolicy?: SecurityPolicy): Promise<Site>;
|
|
58
|
+
/** Options accepted by {@link loadContentFromTree}. */
|
|
59
|
+
export interface LoadContentFromTreeOptions {
|
|
60
|
+
/** URL base path for the Router. Default: `'/'`. */
|
|
61
|
+
basePath?: string;
|
|
62
|
+
/** Icon registry to inject into the Markdoc transform context. */
|
|
63
|
+
icons?: Record<string, Record<string, string>>;
|
|
64
|
+
/** Markdoc tag schemas to merge on top of the core runes. */
|
|
65
|
+
additionalTags?: Record<string, Schema>;
|
|
66
|
+
/** Plugins whose pipeline hooks should run in addition to core hooks. */
|
|
67
|
+
plugins?: Plugin[];
|
|
68
|
+
/** Site-wide Markdoc variables available in content via `{% $name %}`. */
|
|
69
|
+
variables?: Record<string, unknown>;
|
|
70
|
+
/** Security policy for sandbox runes. Default: `'trusted'`. */
|
|
71
|
+
securityPolicy?: SecurityPolicy;
|
|
72
|
+
/** Site-wide `theme.colorScheme` default — seeds the per-page tint cascade.
|
|
73
|
+
* Defaults to `'auto'`. Adapters typically read this from
|
|
74
|
+
* `refrakt.config.json` site.theme.colorScheme. See SPEC-052. */
|
|
75
|
+
colorScheme?: 'auto' | 'light' | 'dark';
|
|
76
|
+
/** Optional reader for ad-hoc lookups in virtual environments.
|
|
77
|
+
*
|
|
78
|
+
* Reserved for future asynchronous resolution paths (e.g., on-demand sandbox
|
|
79
|
+
* source resolution). Not currently consumed by any built-in code path — the
|
|
80
|
+
* page corpus, partials, and layouts all come from `tree`. Accepted here so
|
|
81
|
+
* hosts can wire it once and not need to thread it again when new internal
|
|
82
|
+
* consumers land. */
|
|
83
|
+
reader?: VirtualReader;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Like {@link loadContent}, but driven by a pre-built {@link ContentTree}
|
|
87
|
+
* instead of a filesystem directory. The full transform + cross-page pipeline
|
|
88
|
+
* still runs.
|
|
89
|
+
*
|
|
90
|
+
* Use this from hosted environments where content originates somewhere other
|
|
91
|
+
* than the local filesystem (e.g., a GitHub fetch, a database, an in-memory
|
|
92
|
+
* authoring sandbox). The caller is responsible for assembling the tree.
|
|
93
|
+
*
|
|
94
|
+
* Differences from `loadContent`:
|
|
95
|
+
* - No directory read — accepts the tree directly.
|
|
96
|
+
* - No git history — timestamps come from frontmatter only.
|
|
97
|
+
* - No sandbox filesystem access — sandbox runes resolve to null/empty.
|
|
98
|
+
* (Provide `__sandboxReadFile` etc. via `variables` if your host has its own
|
|
99
|
+
* synchronous access strategy.)
|
|
100
|
+
*/
|
|
101
|
+
export declare function loadContentFromTree(tree: ContentTree, options?: LoadContentFromTreeOptions): Promise<Site>;
|
|
50
102
|
//# sourceMappingURL=site.d.ts.map
|
package/dist/site.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAQ,mBAAmB,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1E,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEjG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAoB,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAU,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAkB,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI1C,MAAM,WAAW,IAAI;IACnB,uBAAuB;IACvB,IAAI,EAAE,WAAW,CAAC;IAClB,iDAAiD;IACjD,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,wCAAwC;IACxC,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,kFAAkF;IAClF,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,mDAAmD;IACnD,aAAa,EAAE,aAAa,CAAC;IAC7B,6EAA6E;IAC7E,UAAU,EAAE,cAAc,CAAC;IAC3B,sEAAsE;IACtE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,mBAAmB,CAAC;IAChC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,cAAc,CAAC;IACvB,GAAG,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"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"}
|
package/dist/site.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import Markdoc from '@markdoc/markdoc';
|
|
4
|
-
import { tags, nodes, extractHeadings, extractSeo, corePipelineHooks, escapeFenceTags } from '@refrakt-md/runes';
|
|
4
|
+
import { tags, nodes, extractHeadings, extractSeo, corePipelineHooks, escapeFenceTags, resolveCoreSentinels } from '@refrakt-md/runes';
|
|
5
5
|
import { resolveSecurityPolicy } from '@refrakt-md/types';
|
|
6
6
|
import { ContentTree } from './content-tree.js';
|
|
7
7
|
import { parseFrontmatter } from './frontmatter.js';
|
|
8
8
|
import { Router } from './router.js';
|
|
9
9
|
import { resolveLayouts } from './layout.js';
|
|
10
|
+
import { resolveTintCascade } from './tint-cascade.js';
|
|
10
11
|
import { runPipeline } from './pipeline.js';
|
|
11
12
|
import { getGitTimestamps, resolveTimestamps } from './timestamps.js';
|
|
12
13
|
/** Synchronous file reader that returns null on failure. */
|
|
@@ -50,29 +51,17 @@ function transformContent(content, path, icons, additionalTags, contentVariables
|
|
|
50
51
|
}
|
|
51
52
|
return { renderable: Markdoc.transform(ast, config), headings };
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* can load code from external files in that directory.
|
|
62
|
-
*
|
|
63
|
-
* `securityPolicy` controls how runes treat untrusted author content. Defaults
|
|
64
|
-
* to `'trusted'` (current behaviour). Set `'strict'` for hosted-product use
|
|
65
|
-
* to strip scripts and harden the sandbox iframe.
|
|
66
|
-
*/
|
|
67
|
-
export async function loadContent(dirPath, basePath = '/', icons, additionalTags, packages, sandboxExamplesDir, variables, securityPolicy) {
|
|
68
|
-
const resolvedSecurity = resolveSecurityPolicy(securityPolicy);
|
|
69
|
-
const tree = await ContentTree.fromDirectory(dirPath);
|
|
70
|
-
const router = new Router(basePath);
|
|
54
|
+
const nullSandboxHooks = {
|
|
55
|
+
read: () => null,
|
|
56
|
+
list: () => [],
|
|
57
|
+
exists: () => false,
|
|
58
|
+
};
|
|
59
|
+
async function processContentTree(tree, opts) {
|
|
60
|
+
const resolvedSecurity = resolveSecurityPolicy(opts.securityPolicy);
|
|
61
|
+
const router = new Router(opts.basePath ?? '/');
|
|
71
62
|
const pages = [];
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
? resolve(sandboxExamplesDir)
|
|
75
|
-
: resolve(dirPath, '..', 'examples');
|
|
63
|
+
const sandbox = opts.sandbox ?? nullSandboxHooks;
|
|
64
|
+
const gitTimestamps = opts.gitTimestamps ?? new Map();
|
|
76
65
|
// Pre-parse partials into Markdoc ASTs for the transform config
|
|
77
66
|
const partialFiles = tree.partials();
|
|
78
67
|
let parsedPartials;
|
|
@@ -82,39 +71,76 @@ export async function loadContent(dirPath, basePath = '/', icons, additionalTags
|
|
|
82
71
|
parsedPartials[name] = Markdoc.parse(escapeFenceTags(partial.raw));
|
|
83
72
|
}
|
|
84
73
|
}
|
|
85
|
-
// Batch-collect git timestamps once before the page loop
|
|
86
|
-
const gitTimestamps = getGitTimestamps(dirPath);
|
|
87
74
|
for (const page of tree.pages()) {
|
|
88
75
|
const { frontmatter, content } = parseFrontmatter(page.raw);
|
|
89
76
|
const route = router.resolve(page.relativePath, frontmatter);
|
|
90
|
-
const layout = resolveLayouts(page, tree.root, icons);
|
|
77
|
+
const layout = resolveLayouts(page, tree.root, opts.icons);
|
|
91
78
|
const fileTimestamps = resolveTimestamps(page.relativePath, page.filePath, gitTimestamps, frontmatter);
|
|
92
79
|
const contentVariables = {
|
|
93
|
-
...variables,
|
|
80
|
+
...opts.variables,
|
|
94
81
|
frontmatter,
|
|
95
82
|
page: { url: route.url, filePath: route.filePath, draft: route.draft },
|
|
96
83
|
file: {
|
|
97
84
|
created: fileTimestamps.created,
|
|
98
85
|
modified: fileTimestamps.modified,
|
|
99
86
|
},
|
|
100
|
-
__sandboxReadFile:
|
|
101
|
-
__sandboxListDir:
|
|
102
|
-
__sandboxDirExists:
|
|
103
|
-
__sandboxExamplesDir:
|
|
87
|
+
__sandboxReadFile: sandbox.read,
|
|
88
|
+
__sandboxListDir: sandbox.list,
|
|
89
|
+
__sandboxDirExists: sandbox.exists,
|
|
90
|
+
__sandboxExamplesDir: opts.sandboxExamplesDir,
|
|
104
91
|
__securityPolicy: resolvedSecurity,
|
|
105
92
|
};
|
|
106
|
-
const { renderable, headings } = transformContent(content, route.url, icons, additionalTags, contentVariables, parsedPartials);
|
|
93
|
+
const { renderable, headings } = transformContent(content, route.url, opts.icons, opts.additionalTags, contentVariables, parsedPartials);
|
|
107
94
|
const seo = extractSeo(renderable, frontmatter, route.url);
|
|
108
|
-
|
|
95
|
+
const tintCascade = resolveTintCascade(page, tree.root, {
|
|
96
|
+
colorScheme: opts.colorScheme,
|
|
97
|
+
});
|
|
98
|
+
pages.push({ route, frontmatter, content, renderable, headings, layout, seo, tintCascade });
|
|
109
99
|
}
|
|
110
100
|
// Build hook sets: core always runs first, then plugins in config order
|
|
111
101
|
const hookSets = [{ pluginName: '__core__', hooks: corePipelineHooks }];
|
|
112
|
-
for (const pkg of
|
|
102
|
+
for (const pkg of opts.plugins ?? []) {
|
|
113
103
|
if (pkg.pipeline) {
|
|
114
104
|
hookSets.push({ pluginName: pkg.name, hooks: pkg.pipeline });
|
|
115
105
|
}
|
|
116
106
|
}
|
|
117
107
|
const { pages: enrichedPages, warnings, stats, aggregated } = await runPipeline(pages, hookSets);
|
|
108
|
+
// Apply auto-resolutions to layout regions per page. Layouts are parsed once
|
|
109
|
+
// and shared across pages, but the auto-open / auto-pagination sentinels need
|
|
110
|
+
// per-page context (current URL, sibling order). The pipeline already wired
|
|
111
|
+
// core hooks against each page's renderable; here we apply the same resolvers
|
|
112
|
+
// to every region's content with the same aggregated data.
|
|
113
|
+
const coreData = aggregated['__core__'];
|
|
114
|
+
if (coreData) {
|
|
115
|
+
for (const page of enrichedPages) {
|
|
116
|
+
if (page.layout.regions.size === 0)
|
|
117
|
+
continue;
|
|
118
|
+
const ctx = makeContextForRegions(warnings, page.route.url);
|
|
119
|
+
// Build the global search scope: page.renderable + every region's content.
|
|
120
|
+
// This gives auto-pagination visibility into navs that live in other
|
|
121
|
+
// regions (e.g. the sidebar nav in the `nav` region) so prev/next can
|
|
122
|
+
// follow the declared reading order.
|
|
123
|
+
const navSearchScope = [page.renderable];
|
|
124
|
+
for (const region of page.layout.regions.values()) {
|
|
125
|
+
navSearchScope.push(region.content);
|
|
126
|
+
}
|
|
127
|
+
const resolvedRegions = new Map();
|
|
128
|
+
let mutated = false;
|
|
129
|
+
for (const [name, region] of page.layout.regions) {
|
|
130
|
+
const resolved = resolveCoreSentinels(region.content, page.route.url, coreData, ctx, navSearchScope);
|
|
131
|
+
if (resolved !== region.content) {
|
|
132
|
+
mutated = true;
|
|
133
|
+
resolvedRegions.set(name, { ...region, content: resolved });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
resolvedRegions.set(name, region);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (mutated) {
|
|
140
|
+
page.layout.regions = resolvedRegions;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
118
144
|
return {
|
|
119
145
|
tree,
|
|
120
146
|
pages: enrichedPages,
|
|
@@ -125,4 +151,76 @@ export async function loadContent(dirPath, basePath = '/', icons, additionalTags
|
|
|
125
151
|
partials: partialFiles,
|
|
126
152
|
};
|
|
127
153
|
}
|
|
154
|
+
function makeContextForRegions(warnings, url) {
|
|
155
|
+
return {
|
|
156
|
+
info(message, infoUrl) { warnings.push({ severity: 'info', phase: 'postProcess', pluginName: '__core__/regions', url: infoUrl ?? url, message }); },
|
|
157
|
+
warn(message, warnUrl) { warnings.push({ severity: 'warning', phase: 'postProcess', pluginName: '__core__/regions', url: warnUrl ?? url, message }); },
|
|
158
|
+
error(message, errUrl) { warnings.push({ severity: 'error', phase: 'postProcess', pluginName: '__core__/regions', url: errUrl ?? url, message }); },
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Load a content directory and resolve all pages, routes, layouts, and navigation.
|
|
163
|
+
*
|
|
164
|
+
* When `packages` are provided, the cross-page pipeline runs after loading:
|
|
165
|
+
* core hooks + package hooks register entities, aggregate cross-page data,
|
|
166
|
+
* and post-process pages before returning.
|
|
167
|
+
*
|
|
168
|
+
* When `sandboxExamplesDir` is provided, sandbox runes with `src` attributes
|
|
169
|
+
* can load code from external files in that directory.
|
|
170
|
+
*
|
|
171
|
+
* `securityPolicy` controls how runes treat untrusted author content. Defaults
|
|
172
|
+
* to `'trusted'` (current behaviour). Set `'strict'` for hosted-product use
|
|
173
|
+
* to strip scripts and harden the sandbox iframe.
|
|
174
|
+
*/
|
|
175
|
+
export async function loadContent(dirPath, basePath = '/', icons, additionalTags, packages, sandboxExamplesDir, variables, securityPolicy) {
|
|
176
|
+
const tree = await ContentTree.fromDirectory(dirPath);
|
|
177
|
+
const resolvedExamplesDir = sandboxExamplesDir
|
|
178
|
+
? resolve(sandboxExamplesDir)
|
|
179
|
+
: resolve(dirPath, '..', 'examples');
|
|
180
|
+
return processContentTree(tree, {
|
|
181
|
+
basePath,
|
|
182
|
+
icons,
|
|
183
|
+
additionalTags,
|
|
184
|
+
plugins: packages,
|
|
185
|
+
variables,
|
|
186
|
+
securityPolicy,
|
|
187
|
+
gitTimestamps: getGitTimestamps(dirPath),
|
|
188
|
+
sandbox: {
|
|
189
|
+
read: sandboxReadFile,
|
|
190
|
+
list: sandboxListDir,
|
|
191
|
+
exists: sandboxDirExists,
|
|
192
|
+
},
|
|
193
|
+
sandboxExamplesDir: resolvedExamplesDir,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Like {@link loadContent}, but driven by a pre-built {@link ContentTree}
|
|
198
|
+
* instead of a filesystem directory. The full transform + cross-page pipeline
|
|
199
|
+
* still runs.
|
|
200
|
+
*
|
|
201
|
+
* Use this from hosted environments where content originates somewhere other
|
|
202
|
+
* than the local filesystem (e.g., a GitHub fetch, a database, an in-memory
|
|
203
|
+
* authoring sandbox). The caller is responsible for assembling the tree.
|
|
204
|
+
*
|
|
205
|
+
* Differences from `loadContent`:
|
|
206
|
+
* - No directory read — accepts the tree directly.
|
|
207
|
+
* - No git history — timestamps come from frontmatter only.
|
|
208
|
+
* - No sandbox filesystem access — sandbox runes resolve to null/empty.
|
|
209
|
+
* (Provide `__sandboxReadFile` etc. via `variables` if your host has its own
|
|
210
|
+
* synchronous access strategy.)
|
|
211
|
+
*/
|
|
212
|
+
export async function loadContentFromTree(tree, options = {}) {
|
|
213
|
+
// `reader` is accepted on the options bag for forward compatibility but not
|
|
214
|
+
// currently plumbed — sandbox runes call file ops synchronously, so an async
|
|
215
|
+
// reader can't back them today.
|
|
216
|
+
return processContentTree(tree, {
|
|
217
|
+
basePath: options.basePath,
|
|
218
|
+
icons: options.icons,
|
|
219
|
+
additionalTags: options.additionalTags,
|
|
220
|
+
plugins: options.plugins,
|
|
221
|
+
variables: options.variables,
|
|
222
|
+
securityPolicy: options.securityPolicy,
|
|
223
|
+
colorScheme: options.colorScheme,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
128
226
|
//# sourceMappingURL=site.js.map
|
package/dist/site.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGvI,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAoB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAe,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAS,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAkB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAA4B,MAAM,mBAAmB,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAgB,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAuB,MAAM,iBAAiB,CAAC;AAqC3F,4DAA4D;AAC5D,SAAS,eAAe,CAAC,CAAS;IAChC,IAAI,CAAC;QAAC,OAAO,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAAC,CAAC;IACxC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AACxB,CAAC;AAED,yEAAyE;AACzE,SAAS,cAAc,CAAC,CAAS;IAC/B,IAAI,CAAC;QAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IAC9B,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AACtB,CAAC;AAED,gDAAgD;AAChD,SAAS,gBAAgB,CAAC,CAAS;IACjC,IAAI,CAAC;QAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAAC,CAAC;IACzC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AACzB,CAAC;AAED,SAAS,gBAAgB,CACvB,OAAe,EACf,IAAY,EACZ,KAA8C,EAC9C,cAAuC,EACvC,gBAA0C,EAC1C,QAA+B;IAE/B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,cAAc,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,MAAM,MAAM,GAA4B,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE;YAC5E,YAAY,EAAE,IAAI,GAAG,EAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YAClE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpC,GAAG,gBAAgB;SACpB,EAAE,CAAC;IACJ,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,MAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;AACzE,CAAC;AAQD,MAAM,gBAAgB,GAAiB;IACrC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI;IAChB,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;IACd,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK;CACpB,CAAC;AAgBF,KAAK,UAAU,kBAAkB,CAC/B,IAAiB,EACjB,IAA+B;IAE/B,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC;IAChD,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACjD,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,GAAG,EAA0B,CAAC;IAE9E,gEAAgE;IAChE,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IACrC,IAAI,cAAgD,CAAC;IACrD,IAAI,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QAC1B,cAAc,GAAG,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,YAAY,EAAE,CAAC;YAC3C,cAAc,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QAChC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,MAAM,cAAc,GAAG,iBAAiB,CACtC,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,QAAQ,EACb,aAAa,EACb,WAAW,CACZ,CAAC;QACF,MAAM,gBAAgB,GAA4B;YAChD,GAAG,IAAI,CAAC,SAAS;YACjB,WAAW;YACX,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE;YACtE,IAAI,EAAE;gBACJ,OAAO,EAAE,cAAc,CAAC,OAAO;gBAC/B,QAAQ,EAAE,cAAc,CAAC,QAAQ;aAClC;YACD,iBAAiB,EAAE,OAAO,CAAC,IAAI;YAC/B,gBAAgB,EAAE,OAAO,CAAC,IAAI;YAC9B,kBAAkB,EAAE,OAAO,CAAC,MAAM;YAClC,oBAAoB,EAAE,IAAI,CAAC,kBAAkB;YAC7C,gBAAgB,EAAE,gBAAgB;SACnC,CAAC;QACF,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAC/C,OAAO,EACP,KAAK,CAAC,GAAG,EACT,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,cAAc,EACnB,gBAAgB,EAChB,cAAc,CACf,CAAC;QACF,MAAM,GAAG,GAAG,UAAU,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAE3D,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;YACtD,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC;QAEH,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,wEAAwE;IACxE,MAAM,QAAQ,GAAc,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACnF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YACjB,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAEjG,6EAA6E;IAC7E,8EAA8E;IAC9E,4EAA4E;IAC5E,8EAA8E;IAC9E,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAA2D,CAAC;IAClG,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC;gBAAE,SAAS;YAC7C,MAAM,GAAG,GAAG,qBAAqB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC5D,2EAA2E;YAC3E,qEAAqE;YACrE,sEAAsE;YACtE,qCAAqC;YACrC,MAAM,cAAc,GAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACpD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;gBAClD,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACtC,CAAC;YACD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAgD,CAAC;YAChF,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,cAAc,CAA0B,CAAC;gBAC9H,IAAI,QAAQ,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;oBAChC,OAAO,GAAG,IAAI,CAAC;oBACf,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAC9D,CAAC;qBAAM,CAAC;oBACN,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACX,IAAI,CAAC,MAAkD,CAAC,OAAO,GAAG,eAA6C,CAAC;YACnH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI;QACJ,KAAK,EAAE,aAAa;QACpB,UAAU,EAAE,EAAE,EAAE,sCAAsC;QACtD,gBAAgB,EAAE,QAAQ;QAC1B,aAAa,EAAE,KAAK;QACpB,UAAU;QACV,QAAQ,EAAE,YAAY;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,QAA2B,EAAE,GAAW;IACrE,OAAO;QACL,IAAI,CAAC,OAAe,EAAE,OAAgB,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACpK,IAAI,CAAC,OAAe,EAAE,OAAgB,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACvK,KAAK,CAAC,OAAe,EAAE,MAAe,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;KACrK,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAe,EACf,WAAmB,GAAG,EACtB,KAA8C,EAC9C,cAAuC,EACvC,QAAmB,EACnB,kBAA2B,EAC3B,SAAmC,EACnC,cAA+B;IAE/B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,mBAAmB,GAAG,kBAAkB;QAC5C,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;QAC7B,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAEvC,OAAO,kBAAkB,CAAC,IAAI,EAAE;QAC9B,QAAQ;QACR,KAAK;QACL,cAAc;QACd,OAAO,EAAE,QAAQ;QACjB,SAAS;QACT,cAAc;QACd,aAAa,EAAE,gBAAgB,CAAC,OAAO,CAAC;QACxC,OAAO,EAAE;YACP,IAAI,EAAE,eAAe;YACrB,IAAI,EAAE,cAAc;YACpB,MAAM,EAAE,gBAAgB;SACzB;QACD,kBAAkB,EAAE,mBAAmB;KACxC,CAAC,CAAC;AACL,CAAC;AA8BD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAiB,EACjB,UAAsC,EAAE;IAExC,4EAA4E;IAC5E,6EAA6E;IAC7E,gCAAgC;IAChC,OAAO,kBAAkB,CAAC,IAAI,EAAE;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ContentDirectory, ContentPage } from './content-tree.js';
|
|
2
|
+
/**
|
|
3
|
+
* The resolved tint cascade for a page — a deterministic three-field tuple
|
|
4
|
+
* the renderer emits onto `<html>` as `data-*` attributes per SPEC-052.
|
|
5
|
+
*
|
|
6
|
+
* - `tint` — named tint preset, or `null` (no named tint active)
|
|
7
|
+
* - `tintMode` — `'auto'` / `'light'` / `'dark'`. `'auto'` is the default;
|
|
8
|
+
* `'light'` and `'dark'` indicate an explicit mode preference.
|
|
9
|
+
* - `locked` — when `true`, the SSR-emitted mode is final: user
|
|
10
|
+
* preference is preserved in localStorage but not applied, and the
|
|
11
|
+
* theme-toggle UI hides.
|
|
12
|
+
*/
|
|
13
|
+
export interface ResolvedTintCascade {
|
|
14
|
+
tint: string | null;
|
|
15
|
+
tintMode: 'auto' | 'light' | 'dark';
|
|
16
|
+
locked: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Root defaults applied before any layout / page frontmatter contributes.
|
|
20
|
+
* Adapters can pass `theme.colorScheme` from `refrakt.config.json` to seed
|
|
21
|
+
* `tintMode`; everything else starts unset.
|
|
22
|
+
*/
|
|
23
|
+
export interface CascadeRootDefaults {
|
|
24
|
+
/** Maps to {@link ResolvedTintCascade.tintMode}. */
|
|
25
|
+
colorScheme?: 'auto' | 'light' | 'dark';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the tint cascade for a page by walking its layout chain
|
|
29
|
+
* outermost-to-innermost and overlaying its own frontmatter last.
|
|
30
|
+
*
|
|
31
|
+
* Cascade order (last writer wins per field):
|
|
32
|
+
*
|
|
33
|
+
* 1. Root defaults (typically from `theme.colorScheme` in site config)
|
|
34
|
+
* 2. Each `_layout.md` from the root toward the page, in order
|
|
35
|
+
* 3. The page's own frontmatter
|
|
36
|
+
*
|
|
37
|
+
* `undefined` at any level means "inherit from the next outer layer".
|
|
38
|
+
* Explicit `null` for `tint` is the canonical "reset to no named tint"
|
|
39
|
+
* idiom — preserved through the cascade so authors can break out of a
|
|
40
|
+
* parent layout's tint without applying a new one.
|
|
41
|
+
*
|
|
42
|
+
* Pure function: given the same inputs, returns the same tuple. No I/O.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveTintCascade(page: ContentPage, rootDir: ContentDirectory, defaults?: CascadeRootDefaults): ResolvedTintCascade;
|
|
45
|
+
//# sourceMappingURL=tint-cascade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tint-cascade.d.ts","sourceRoot":"","sources":["../src/tint-cascade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGvE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACpC,MAAM,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,gBAAgB,EACzB,QAAQ,GAAE,mBAAwB,GAChC,mBAAmB,CAiBrB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { parseFrontmatter } from './frontmatter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the tint cascade for a page by walking its layout chain
|
|
4
|
+
* outermost-to-innermost and overlaying its own frontmatter last.
|
|
5
|
+
*
|
|
6
|
+
* Cascade order (last writer wins per field):
|
|
7
|
+
*
|
|
8
|
+
* 1. Root defaults (typically from `theme.colorScheme` in site config)
|
|
9
|
+
* 2. Each `_layout.md` from the root toward the page, in order
|
|
10
|
+
* 3. The page's own frontmatter
|
|
11
|
+
*
|
|
12
|
+
* `undefined` at any level means "inherit from the next outer layer".
|
|
13
|
+
* Explicit `null` for `tint` is the canonical "reset to no named tint"
|
|
14
|
+
* idiom — preserved through the cascade so authors can break out of a
|
|
15
|
+
* parent layout's tint without applying a new one.
|
|
16
|
+
*
|
|
17
|
+
* Pure function: given the same inputs, returns the same tuple. No I/O.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveTintCascade(page, rootDir, defaults = {}) {
|
|
20
|
+
const resolved = {
|
|
21
|
+
tint: null,
|
|
22
|
+
tintMode: defaults.colorScheme ?? 'auto',
|
|
23
|
+
locked: false,
|
|
24
|
+
};
|
|
25
|
+
const layoutChain = findLayoutChain(page, rootDir);
|
|
26
|
+
for (const layoutPage of layoutChain) {
|
|
27
|
+
const layoutFrontmatter = parseFrontmatter(layoutPage.raw).frontmatter;
|
|
28
|
+
applyLayer(resolved, layoutFrontmatter);
|
|
29
|
+
}
|
|
30
|
+
const pageFrontmatter = parseFrontmatter(page.raw).frontmatter;
|
|
31
|
+
applyLayer(resolved, pageFrontmatter);
|
|
32
|
+
return resolved;
|
|
33
|
+
}
|
|
34
|
+
function applyLayer(resolved, layer) {
|
|
35
|
+
if ('tint' in layer && layer.tint !== undefined) {
|
|
36
|
+
// `null` is a real value here — author's "reset to no named tint" idiom.
|
|
37
|
+
resolved.tint = layer.tint;
|
|
38
|
+
}
|
|
39
|
+
if ('tint-mode' in layer && layer['tint-mode'] !== undefined) {
|
|
40
|
+
const mode = layer['tint-mode'];
|
|
41
|
+
if (mode === 'auto' || mode === 'light' || mode === 'dark') {
|
|
42
|
+
resolved.tintMode = mode;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if ('tint-lock' in layer && layer['tint-lock'] !== undefined) {
|
|
46
|
+
resolved.locked = Boolean(layer['tint-lock']);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Walk from the root down to the page's directory, collecting every
|
|
51
|
+
* `_layout.md` along the way. Returns the chain in outermost-to-innermost
|
|
52
|
+
* order so the cascade can apply each in turn.
|
|
53
|
+
*
|
|
54
|
+
* Mirrors `layout.ts`'s `findLayoutChain` so the two stay in lockstep.
|
|
55
|
+
*/
|
|
56
|
+
function findLayoutChain(page, rootDir) {
|
|
57
|
+
const parts = page.relativePath.split('/').slice(0, -1);
|
|
58
|
+
const chain = [];
|
|
59
|
+
let current = rootDir;
|
|
60
|
+
if (current.layout)
|
|
61
|
+
chain.push(current.layout);
|
|
62
|
+
for (const part of parts) {
|
|
63
|
+
current = current.children.find(c => c.name === part);
|
|
64
|
+
if (!current)
|
|
65
|
+
break;
|
|
66
|
+
if (current.layout)
|
|
67
|
+
chain.push(current.layout);
|
|
68
|
+
}
|
|
69
|
+
return chain;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=tint-cascade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tint-cascade.js","sourceRoot":"","sources":["../src/tint-cascade.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAoB,MAAM,kBAAkB,CAAC;AA6BtE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,kBAAkB,CACjC,IAAiB,EACjB,OAAyB,EACzB,WAAgC,EAAE;IAElC,MAAM,QAAQ,GAAwB;QACrC,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,QAAQ,CAAC,WAAW,IAAI,MAAM;QACxC,MAAM,EAAE,KAAK;KACb,CAAC;IAEF,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACnD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACtC,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC;QACvE,UAAU,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC;IAC/D,UAAU,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IAEtC,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,SAAS,UAAU,CAAC,QAA6B,EAAE,KAAkB;IACpE,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACjD,yEAAyE;QACzE,QAAQ,CAAC,IAAI,GAAG,KAAK,CAAC,IAAqB,CAAC;IAC7C,CAAC;IACD,IAAI,WAAW,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5D,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC1B,CAAC;IACF,CAAC;IACD,IAAI,WAAW,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE,CAAC;QAC9D,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC/C,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,IAAiB,EAAE,OAAyB;IACpE,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,IAAI,OAAO,GAAiC,OAAO,CAAC;IACpD,IAAI,OAAO,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO;YAAE,MAAM;QACpB,IAAI,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ResolvedTintCascade } from './tint-cascade.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build the attribute string adapters should put on the `<html>` element at
|
|
4
|
+
* SSR time, per SPEC-052. Reads the resolved cascade tuple from a SitePage
|
|
5
|
+
* and emits `data-theme`, `data-tint`, `data-tint-lock`, plus the matching
|
|
6
|
+
* `color-scheme` declaration when locked.
|
|
7
|
+
*
|
|
8
|
+
* The returned string is just the attributes (no leading/trailing space) —
|
|
9
|
+
* adapters interpolate it into their HTML shell however suits them best.
|
|
10
|
+
* For example, in a SvelteKit `hooks.server.ts` `transformPageChunk`:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* html.replace('<html', `<html ${htmlTintAttributes(cascade)}`)
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* If the cascade has no opinions (default `'auto'`, no locked mode, no
|
|
17
|
+
* named tint), returns the empty string — `<html>` stays clean and the
|
|
18
|
+
* pre-paint script handles user / system preference at runtime.
|
|
19
|
+
*/
|
|
20
|
+
export declare function htmlTintAttributes(cascade: ResolvedTintCascade): string;
|
|
21
|
+
/**
|
|
22
|
+
* Build the `<meta name="color-scheme">` content value adapters should
|
|
23
|
+
* emit. `'light dark'` when unlocked (browser may pick); explicit when
|
|
24
|
+
* locked.
|
|
25
|
+
*/
|
|
26
|
+
export declare function colorSchemeMetaContent(cascade: ResolvedTintCascade): string;
|
|
27
|
+
/**
|
|
28
|
+
* The canonical anti-FOIT pre-paint script. Drop this inline into `<head>`
|
|
29
|
+
* before any stylesheets so it runs before first paint and there's no flash
|
|
30
|
+
* of incorrect theme.
|
|
31
|
+
*
|
|
32
|
+
* Behaviour per SPEC-052:
|
|
33
|
+
* - On a locked page (`data-tint-lock="true"`), do nothing — the SSR
|
|
34
|
+
* output is final.
|
|
35
|
+
* - On an unlocked page, apply the user's saved preference from
|
|
36
|
+
* localStorage (key `rf-theme`); fall back to system
|
|
37
|
+
* `prefers-color-scheme` if no preference is saved.
|
|
38
|
+
* - The toggle component (separate concern) writes the same localStorage
|
|
39
|
+
* key on click. Saved preference is preserved across visits to locked
|
|
40
|
+
* pages.
|
|
41
|
+
*
|
|
42
|
+
* Returns the raw JavaScript string (no `<script>` wrapper) so adapters
|
|
43
|
+
* can inline it however their templating system prefers.
|
|
44
|
+
*/
|
|
45
|
+
export declare function prePaintScript(): string;
|
|
46
|
+
//# sourceMappingURL=tint-ssr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tint-ssr.d.ts","sourceRoot":"","sources":["../src/tint-ssr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAYvE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAK3E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
|
package/dist/tint-ssr.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the attribute string adapters should put on the `<html>` element at
|
|
3
|
+
* SSR time, per SPEC-052. Reads the resolved cascade tuple from a SitePage
|
|
4
|
+
* and emits `data-theme`, `data-tint`, `data-tint-lock`, plus the matching
|
|
5
|
+
* `color-scheme` declaration when locked.
|
|
6
|
+
*
|
|
7
|
+
* The returned string is just the attributes (no leading/trailing space) —
|
|
8
|
+
* adapters interpolate it into their HTML shell however suits them best.
|
|
9
|
+
* For example, in a SvelteKit `hooks.server.ts` `transformPageChunk`:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* html.replace('<html', `<html ${htmlTintAttributes(cascade)}`)
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* If the cascade has no opinions (default `'auto'`, no locked mode, no
|
|
16
|
+
* named tint), returns the empty string — `<html>` stays clean and the
|
|
17
|
+
* pre-paint script handles user / system preference at runtime.
|
|
18
|
+
*/
|
|
19
|
+
export function htmlTintAttributes(cascade) {
|
|
20
|
+
const parts = [];
|
|
21
|
+
if (cascade.tintMode === 'light' || cascade.tintMode === 'dark') {
|
|
22
|
+
parts.push(`data-theme="${cascade.tintMode}"`);
|
|
23
|
+
}
|
|
24
|
+
if (cascade.tint !== null) {
|
|
25
|
+
parts.push(`data-tint="${escapeAttr(cascade.tint)}"`);
|
|
26
|
+
}
|
|
27
|
+
if (cascade.locked) {
|
|
28
|
+
parts.push('data-tint-lock="true"');
|
|
29
|
+
}
|
|
30
|
+
return parts.join(' ');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build the `<meta name="color-scheme">` content value adapters should
|
|
34
|
+
* emit. `'light dark'` when unlocked (browser may pick); explicit when
|
|
35
|
+
* locked.
|
|
36
|
+
*/
|
|
37
|
+
export function colorSchemeMetaContent(cascade) {
|
|
38
|
+
if (cascade.locked && (cascade.tintMode === 'light' || cascade.tintMode === 'dark')) {
|
|
39
|
+
return cascade.tintMode;
|
|
40
|
+
}
|
|
41
|
+
return 'light dark';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The canonical anti-FOIT pre-paint script. Drop this inline into `<head>`
|
|
45
|
+
* before any stylesheets so it runs before first paint and there's no flash
|
|
46
|
+
* of incorrect theme.
|
|
47
|
+
*
|
|
48
|
+
* Behaviour per SPEC-052:
|
|
49
|
+
* - On a locked page (`data-tint-lock="true"`), do nothing — the SSR
|
|
50
|
+
* output is final.
|
|
51
|
+
* - On an unlocked page, apply the user's saved preference from
|
|
52
|
+
* localStorage (key `rf-theme`); fall back to system
|
|
53
|
+
* `prefers-color-scheme` if no preference is saved.
|
|
54
|
+
* - The toggle component (separate concern) writes the same localStorage
|
|
55
|
+
* key on click. Saved preference is preserved across visits to locked
|
|
56
|
+
* pages.
|
|
57
|
+
*
|
|
58
|
+
* Returns the raw JavaScript string (no `<script>` wrapper) so adapters
|
|
59
|
+
* can inline it however their templating system prefers.
|
|
60
|
+
*/
|
|
61
|
+
export function prePaintScript() {
|
|
62
|
+
return `(function(){var d=document.documentElement;if(d.dataset.tintLock==='true')return;var s=null;try{s=localStorage.getItem('rf-theme')}catch(e){}var m=s&&s!=='auto'?s:(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light');d.setAttribute('data-theme',m)})();`;
|
|
63
|
+
}
|
|
64
|
+
function escapeAttr(value) {
|
|
65
|
+
return value.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=tint-ssr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tint-ssr.js","sourceRoot":"","sources":["../src/tint-ssr.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC9D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACjE,KAAK,CAAC,IAAI,CAAC,eAAe,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA4B;IAClE,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC;QACrF,OAAO,OAAO,CAAC,QAAQ,CAAC;IACzB,CAAC;IACD,OAAO,YAAY,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc;IAC7B,OAAO,4QAA4Q,CAAC;AACrR,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACnF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@refrakt-md/content",
|
|
3
3
|
"description": "Content loading and transformation pipeline",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"build": "tsc"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@refrakt-md/highlight": "0.
|
|
33
|
-
"@refrakt-md/runes": "0.
|
|
34
|
-
"@refrakt-md/transform": "0.
|
|
35
|
-
"@refrakt-md/types": "0.
|
|
32
|
+
"@refrakt-md/highlight": "0.14.0",
|
|
33
|
+
"@refrakt-md/runes": "0.14.0",
|
|
34
|
+
"@refrakt-md/transform": "0.14.0",
|
|
35
|
+
"@refrakt-md/types": "0.14.0",
|
|
36
36
|
"@markdoc/markdoc": "0.4.0",
|
|
37
37
|
"yaml": "^2.4.0"
|
|
38
38
|
}
|