specra 0.2.13 → 0.2.14
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/config/rehype-base-path.d.ts +1 -0
- package/config/svelte-config.js +14 -4
- package/dist/components/docs/Breadcrumb.svelte +3 -2
- package/dist/components/docs/CategoryIndex.svelte +3 -2
- package/dist/components/docs/DocNavigation.svelte +3 -2
- package/dist/components/docs/Footer.svelte +10 -1
- package/dist/components/docs/Header.svelte +2 -1
- package/dist/components/docs/NotFoundContent.svelte +4 -3
- package/dist/components/docs/ProductSwitcher.svelte +3 -2
- package/dist/components/docs/SidebarMenuItems.svelte +4 -3
- package/dist/components/docs/TabGroups.svelte +3 -2
- package/dist/mdx.js +28 -2
- package/dist/rehype-base-path.d.ts +6 -0
- package/dist/rehype-base-path.js +29 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function rehypeBasePath(options?: {}): (tree: any) => void;
|
package/config/svelte-config.js
CHANGED
|
@@ -19,6 +19,7 @@ import rehypeKatex from 'rehype-katex'
|
|
|
19
19
|
import rehypeRaw from 'rehype-raw'
|
|
20
20
|
import fs from 'fs'
|
|
21
21
|
import path from 'path'
|
|
22
|
+
import { rehypeBasePath } from '../dist/rehype-base-path.js'
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Get mdsvex preprocessor config with all Specra remark/rehype plugins
|
|
@@ -72,7 +73,7 @@ function resolveBasePath(configPath = path.join(process.cwd(), 'specra.config.js
|
|
|
72
73
|
* Scan the docs/ directory and return prerender entries for all version root pages.
|
|
73
74
|
* This ensures adapter-static discovers and prerenders every version, not just the active one.
|
|
74
75
|
*/
|
|
75
|
-
function discoverVersionEntries(
|
|
76
|
+
function discoverVersionEntries(docsDir = path.join(process.cwd(), 'docs')) {
|
|
76
77
|
const entries = ['/']
|
|
77
78
|
try {
|
|
78
79
|
if (!fs.existsSync(docsDir)) return entries
|
|
@@ -80,7 +81,7 @@ function discoverVersionEntries(basePath = '', docsDir = path.join(process.cwd()
|
|
|
80
81
|
const items = fs.readdirSync(docsDir, { withFileTypes: true })
|
|
81
82
|
for (const item of items) {
|
|
82
83
|
if (item.isDirectory() && /^v\d/.test(item.name)) {
|
|
83
|
-
entries.push(
|
|
84
|
+
entries.push(`/docs/${item.name}`)
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
} catch {
|
|
@@ -99,11 +100,20 @@ export function specraConfig(options = {}) {
|
|
|
99
100
|
const userPrerender = options.kit?.prerender || {}
|
|
100
101
|
const basePath = options.kit?.paths?.base ?? resolveBasePath()
|
|
101
102
|
|
|
103
|
+
// Inject base path rehype plugin into mdsvex if basePath is set
|
|
104
|
+
const mdsvexOptions = options.mdsvex || {}
|
|
105
|
+
if (basePath) {
|
|
106
|
+
mdsvexOptions.rehypePlugins = [
|
|
107
|
+
...(mdsvexOptions.rehypePlugins || []),
|
|
108
|
+
[rehypeBasePath, { basePath }],
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
|
|
102
112
|
return {
|
|
103
113
|
extensions: ['.svelte', '.md', '.svx', '.mdx'],
|
|
104
114
|
preprocess: [
|
|
105
115
|
...(vitePreprocess ? [vitePreprocess()] : []),
|
|
106
|
-
mdsvex(specraMdsvexConfig(
|
|
116
|
+
mdsvex(specraMdsvexConfig(mdsvexOptions))
|
|
107
117
|
],
|
|
108
118
|
kit: {
|
|
109
119
|
...options.kit,
|
|
@@ -115,7 +125,7 @@ export function specraConfig(options = {}) {
|
|
|
115
125
|
handleHttpError: 'warn',
|
|
116
126
|
handleMissingId: 'warn',
|
|
117
127
|
handleUnseenRoutes: 'warn',
|
|
118
|
-
entries: discoverVersionEntries(
|
|
128
|
+
entries: discoverVersionEntries(),
|
|
119
129
|
...userPrerender,
|
|
120
130
|
}
|
|
121
131
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { ChevronRight } from 'lucide-svelte';
|
|
3
|
+
import { base } from '$app/paths';
|
|
3
4
|
import { getConfigContext } from '../../stores/config.js';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
@@ -13,8 +14,8 @@
|
|
|
13
14
|
|
|
14
15
|
let docsBase = $derived(
|
|
15
16
|
product && product !== '_default_'
|
|
16
|
-
?
|
|
17
|
-
:
|
|
17
|
+
? `${base}/docs/${product}/${version}`
|
|
18
|
+
: `${base}/docs/${version}`
|
|
18
19
|
);
|
|
19
20
|
|
|
20
21
|
const configStore = getConfigContext();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { FileText, ArrowRight } from 'lucide-svelte';
|
|
3
|
+
import { base } from '$app/paths';
|
|
3
4
|
import type { SpecraConfig } from '../../config.types.js';
|
|
4
5
|
import type { Snippet } from 'svelte';
|
|
5
6
|
|
|
@@ -54,8 +55,8 @@
|
|
|
54
55
|
|
|
55
56
|
const baseUrl = $derived(
|
|
56
57
|
product && product !== '_default_'
|
|
57
|
-
?
|
|
58
|
-
:
|
|
58
|
+
? `${base}/docs/${product}`
|
|
59
|
+
: `${base}/docs`
|
|
59
60
|
);
|
|
60
61
|
|
|
61
62
|
// Note: We always use '/docs' as the base for non-product routes.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { ChevronLeft, ChevronRight } from 'lucide-svelte';
|
|
3
|
+
import { base } from '$app/paths';
|
|
3
4
|
|
|
4
5
|
interface NavDoc {
|
|
5
6
|
title: string;
|
|
@@ -17,8 +18,8 @@
|
|
|
17
18
|
|
|
18
19
|
let docsBase = $derived(
|
|
19
20
|
product && product !== '_default_'
|
|
20
|
-
?
|
|
21
|
-
:
|
|
21
|
+
? `${base}/docs/${product}/${version}`
|
|
22
|
+
: `${base}/docs/${version}`
|
|
22
23
|
);
|
|
23
24
|
</script>
|
|
24
25
|
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { SpecraConfig } from '../../config.types.js';
|
|
3
|
+
import { base } from '$app/paths';
|
|
3
4
|
import Logo from './Logo.svelte';
|
|
4
5
|
|
|
6
|
+
/** Prefix internal links with base path */
|
|
7
|
+
function resolveHref(href: string): string {
|
|
8
|
+
if (href.startsWith('/') && !href.startsWith('//')) {
|
|
9
|
+
return `${base}${href}`;
|
|
10
|
+
}
|
|
11
|
+
return href;
|
|
12
|
+
}
|
|
13
|
+
|
|
5
14
|
interface Props {
|
|
6
15
|
config: SpecraConfig;
|
|
7
16
|
}
|
|
@@ -25,7 +34,7 @@
|
|
|
25
34
|
{#each column.items as item, itemIdx (itemIdx)}
|
|
26
35
|
<li>
|
|
27
36
|
<a
|
|
28
|
-
href={item.href}
|
|
37
|
+
href={resolveHref(item.href)}
|
|
29
38
|
class="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
|
30
39
|
>
|
|
31
40
|
{item.label}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Search, Menu, Github, Twitter, MessageCircle } from 'lucide-svelte';
|
|
3
|
+
import { base } from '$app/paths';
|
|
3
4
|
import { getConfigContext } from '../../stores/config.js';
|
|
4
5
|
import { sidebarStore } from '../../stores/sidebar.js';
|
|
5
6
|
import VersionSwitcher from './VersionSwitcher.svelte';
|
|
@@ -110,7 +111,7 @@
|
|
|
110
111
|
>
|
|
111
112
|
<Menu class="h-5 w-5" />
|
|
112
113
|
</button>
|
|
113
|
-
<a href="/" class="flex items-center gap-2">
|
|
114
|
+
<a href="{base}/" class="flex items-center gap-2">
|
|
114
115
|
{#if !config.site.hideLogo}
|
|
115
116
|
{#if config.site.logo}
|
|
116
117
|
<Logo logo={config.site.logo} alt={config.site.title} className="w-18 object-contain" />
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { FileQuestion, Home, ArrowLeft } from 'lucide-svelte';
|
|
3
|
+
import { base } from '$app/paths';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
version?: string;
|
|
@@ -11,10 +12,10 @@
|
|
|
11
12
|
/** URL prefix: /docs/{product}/{version} for named products, /docs/{version} for default */
|
|
12
13
|
const homeLink = $derived(
|
|
13
14
|
product && product !== '_default_' && version
|
|
14
|
-
?
|
|
15
|
+
? `${base}/docs/${product}/${version}`
|
|
15
16
|
: version
|
|
16
|
-
?
|
|
17
|
-
:
|
|
17
|
+
? `${base}/docs/${version}`
|
|
18
|
+
: `${base}/`
|
|
18
19
|
);
|
|
19
20
|
</script>
|
|
20
21
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { ChevronDown, Check } from 'lucide-svelte';
|
|
3
3
|
import { goto } from '$app/navigation';
|
|
4
|
+
import { base } from '$app/paths';
|
|
4
5
|
import { browser } from '$app/environment';
|
|
5
6
|
import Icon from './Icon.svelte';
|
|
6
7
|
|
|
@@ -107,9 +108,9 @@
|
|
|
107
108
|
|
|
108
109
|
const version = product.activeVersion || 'v1.0.0';
|
|
109
110
|
if (product.isDefault) {
|
|
110
|
-
goto(
|
|
111
|
+
goto(`${base}/docs/${version}`);
|
|
111
112
|
} else {
|
|
112
|
-
goto(
|
|
113
|
+
goto(`${base}/docs/${product.slug}/${version}`);
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { page } from '$app/stores';
|
|
3
|
+
import { base } from '$app/paths';
|
|
3
4
|
import { ChevronRight, ChevronDown, Lock } from 'lucide-svelte';
|
|
4
5
|
import type { SpecraConfig } from '../../config.types.js';
|
|
5
6
|
import Icon from './Icon.svelte';
|
|
@@ -50,11 +51,11 @@
|
|
|
50
51
|
|
|
51
52
|
let { docs = [], version, product, onLinkClick, config, activeTabGroup }: Props = $props();
|
|
52
53
|
|
|
53
|
-
/** URL prefix: /docs/{product}/{version} for named products, /docs/{version} for default */
|
|
54
|
+
/** URL prefix: {base}/docs/{product}/{version} for named products, {base}/docs/{version} for default */
|
|
54
55
|
let docsBase = $derived(
|
|
55
56
|
product && product !== '_default_'
|
|
56
|
-
?
|
|
57
|
-
:
|
|
57
|
+
? `${base}/docs/${product}/${version}`
|
|
58
|
+
: `${base}/docs/${version}`
|
|
58
59
|
);
|
|
59
60
|
|
|
60
61
|
const STORAGE_KEY = 'specra-sidebar-collapsed';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { ChevronDown } from 'lucide-svelte';
|
|
3
3
|
import { goto } from '$app/navigation';
|
|
4
|
+
import { base } from '$app/paths';
|
|
4
5
|
import type { TabGroup, SpecraConfig } from '../../config.types.js';
|
|
5
6
|
import Icon from './Icon.svelte';
|
|
6
7
|
|
|
@@ -32,8 +33,8 @@
|
|
|
32
33
|
|
|
33
34
|
let docsBase = $derived(
|
|
34
35
|
product && product !== '_default_' && version
|
|
35
|
-
?
|
|
36
|
-
: version ?
|
|
36
|
+
? `${base}/docs/${product}/${version}`
|
|
37
|
+
: version ? `${base}/docs/${version}` : `${base}/docs`
|
|
37
38
|
);
|
|
38
39
|
|
|
39
40
|
let dropdownOpen = $state(false);
|
package/dist/mdx.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import matter from "gray-matter";
|
|
4
4
|
import yaml from "js-yaml";
|
|
5
|
+
import { rehypeBasePath } from "./rehype-base-path.js";
|
|
5
6
|
import { unified } from "unified";
|
|
6
7
|
import remarkParse from "remark-parse";
|
|
7
8
|
import remarkGfm from "remark-gfm";
|
|
@@ -395,15 +396,36 @@ function parseJsxExpression(expr) {
|
|
|
395
396
|
/**
|
|
396
397
|
* Process markdown content to HTML using remark/rehype pipeline.
|
|
397
398
|
*/
|
|
399
|
+
function resolveDeploymentBasePath() {
|
|
400
|
+
if (process.env.BASE_PATH)
|
|
401
|
+
return process.env.BASE_PATH;
|
|
402
|
+
try {
|
|
403
|
+
const configPath = path.join(process.cwd(), 'specra.config.json');
|
|
404
|
+
if (fs.existsSync(configPath)) {
|
|
405
|
+
const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
406
|
+
if (raw.deployment?.basePath && !raw.deployment?.customDomain) {
|
|
407
|
+
const bp = raw.deployment.basePath;
|
|
408
|
+
return bp.startsWith('/') ? bp : `/${bp}`;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch { /* ignore */ }
|
|
413
|
+
return '';
|
|
414
|
+
}
|
|
398
415
|
async function processMarkdownToHtml(markdown) {
|
|
399
|
-
const
|
|
416
|
+
const basePath = resolveDeploymentBasePath();
|
|
417
|
+
const processor = unified()
|
|
400
418
|
.use(remarkParse)
|
|
401
419
|
.use(remarkGfm)
|
|
402
420
|
.use(remarkMath)
|
|
403
421
|
.use(remarkRehype, { allowDangerousHtml: true })
|
|
404
422
|
.use(rehypeRaw)
|
|
405
423
|
.use(rehypeSlug)
|
|
406
|
-
.use(rehypeKatex)
|
|
424
|
+
.use(rehypeKatex);
|
|
425
|
+
if (basePath) {
|
|
426
|
+
processor.use(rehypeBasePath, { basePath });
|
|
427
|
+
}
|
|
428
|
+
const result = await processor
|
|
407
429
|
.use(rehypeStringify)
|
|
408
430
|
.process(markdown);
|
|
409
431
|
return String(result);
|
|
@@ -1046,6 +1068,7 @@ async function processMarkdownToMdxNodes(markdown) {
|
|
|
1046
1068
|
const dedented = dedentComponentChildren(preprocessed);
|
|
1047
1069
|
// Ensure component block integrity in the markdown
|
|
1048
1070
|
const normalized = ensureComponentBlockIntegrity(dedented);
|
|
1071
|
+
const basePath = resolveDeploymentBasePath();
|
|
1049
1072
|
const processor = unified()
|
|
1050
1073
|
.use(remarkParse)
|
|
1051
1074
|
.use(remarkGfm)
|
|
@@ -1054,6 +1077,9 @@ async function processMarkdownToMdxNodes(markdown) {
|
|
|
1054
1077
|
.use(rehypeRaw)
|
|
1055
1078
|
.use(rehypeSlug)
|
|
1056
1079
|
.use(rehypeKatex);
|
|
1080
|
+
if (basePath) {
|
|
1081
|
+
processor.use(rehypeBasePath, { basePath });
|
|
1082
|
+
}
|
|
1057
1083
|
const mdast = processor.parse(normalized);
|
|
1058
1084
|
const hast = await processor.run(mdast);
|
|
1059
1085
|
// The hast root has children - process them into MdxNodes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rehype plugin that prefixes internal absolute links with a base path.
|
|
3
|
+
* Internal links start with "/" and don't start with "http" or "//".
|
|
4
|
+
*
|
|
5
|
+
* Used for GitHub Pages deployments where the site lives under a subpath.
|
|
6
|
+
*/
|
|
7
|
+
import { visit } from 'unist-util-visit';
|
|
8
|
+
export function rehypeBasePath(options = {}) {
|
|
9
|
+
const { basePath = '' } = options;
|
|
10
|
+
if (!basePath)
|
|
11
|
+
return () => { };
|
|
12
|
+
const cleanBase = basePath.replace(/\/$/, '');
|
|
13
|
+
return (tree) => {
|
|
14
|
+
visit(tree, 'element', (node) => {
|
|
15
|
+
if (node.tagName === 'a' && node.properties?.href) {
|
|
16
|
+
const href = node.properties.href;
|
|
17
|
+
if (typeof href === 'string' && href.startsWith('/') && !href.startsWith('//') && !href.startsWith(cleanBase + '/')) {
|
|
18
|
+
node.properties.href = cleanBase + href;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (node.tagName === 'img' && node.properties?.src) {
|
|
22
|
+
const src = node.properties.src;
|
|
23
|
+
if (typeof src === 'string' && src.startsWith('/') && !src.startsWith('//') && !src.startsWith(cleanBase + '/')) {
|
|
24
|
+
node.properties.src = cleanBase + src;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specra",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "A modern documentation library for SvelteKit with built-in versioning, API reference generation, full-text search, and MDX support",
|
|
5
5
|
"svelte": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|