svelora 2.2.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/CodeBlock/CodeBlock.svelte +83 -0
- package/dist/CodeBlock/CodeBlock.svelte.d.ts +5 -0
- package/dist/CodeBlock/code-block.types.d.ts +15 -0
- package/dist/CodeBlock/code-block.types.js +1 -0
- package/dist/CodeBlock/code-block.variants.d.ts +288 -0
- package/dist/CodeBlock/code-block.variants.js +69 -0
- package/dist/CodeBlock/index.d.ts +2 -0
- package/dist/CodeBlock/index.js +1 -0
- package/dist/Drawer/Drawer.svelte +13 -3
- package/dist/Editor/Editor.svelte +3 -0
- package/dist/Fonts/Fonts.svelte +54 -0
- package/dist/Fonts/Fonts.svelte.d.ts +5 -0
- package/dist/Fonts/fonts.d.ts +12 -0
- package/dist/Fonts/fonts.js +128 -0
- package/dist/Fonts/fonts.types.d.ts +40 -0
- package/dist/Fonts/fonts.types.js +1 -0
- package/dist/Fonts/index.d.ts +3 -0
- package/dist/Fonts/index.js +2 -0
- package/dist/config.d.ts +12 -1
- package/dist/config.js +9 -0
- package/dist/docs/code-block.d.ts +13 -0
- package/dist/docs/code-block.js +214 -0
- package/dist/docs/navigation.d.ts +27 -0
- package/dist/docs/navigation.js +491 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mcp/cursor.mcp.json +12 -0
- package/dist/mcp/install-template.mjs +55 -0
- package/dist/mcp/server.mjs +338 -0
- package/dist/mcp/svelora-docs.data.json +138 -0
- package/dist/theme.css +20 -1
- package/package.json +30 -9
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const defaultSansFallback = "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
|
2
|
+
const defaultMonoFallback = "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace";
|
|
3
|
+
export const defaultFontFamilies = [
|
|
4
|
+
{
|
|
5
|
+
name: 'Inter',
|
|
6
|
+
variable: '--font-sans-family',
|
|
7
|
+
weights: [400, 500, 600, 700]
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: 'Inter',
|
|
11
|
+
variable: '--font-heading-family',
|
|
12
|
+
weights: [400, 500, 600, 700]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'JetBrains Mono',
|
|
16
|
+
variable: '--font-mono-family',
|
|
17
|
+
weights: [400, 500, 700]
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
export const fontsDefaults = {
|
|
21
|
+
families: defaultFontFamilies,
|
|
22
|
+
display: 'swap',
|
|
23
|
+
preconnect: true
|
|
24
|
+
};
|
|
25
|
+
function isLocalFont(font) {
|
|
26
|
+
return font.provider === 'local';
|
|
27
|
+
}
|
|
28
|
+
function normalizeFontName(name) {
|
|
29
|
+
return name.trim().replace(/\s+/g, ' ');
|
|
30
|
+
}
|
|
31
|
+
function getFontWeights(weights) {
|
|
32
|
+
const normalized = (weights ?? [400]).filter((weight, index, source) => Number.isInteger(weight) &&
|
|
33
|
+
weight >= 100 &&
|
|
34
|
+
weight <= 900 &&
|
|
35
|
+
source.indexOf(weight) === index);
|
|
36
|
+
return normalized.length > 0 ? [...normalized].sort((a, b) => a - b) : [400];
|
|
37
|
+
}
|
|
38
|
+
function getFontStyles(styles) {
|
|
39
|
+
const normalized = (styles ?? ['normal']).filter((style, index, source) => (style === 'normal' || style === 'italic') && source.indexOf(style) === index);
|
|
40
|
+
if (normalized.length === 0)
|
|
41
|
+
return ['normal'];
|
|
42
|
+
if (normalized.includes('normal') && normalized.includes('italic')) {
|
|
43
|
+
return ['normal', 'italic'];
|
|
44
|
+
}
|
|
45
|
+
return normalized[0] === 'italic' ? ['italic'] : ['normal'];
|
|
46
|
+
}
|
|
47
|
+
function encodeFamilyName(name) {
|
|
48
|
+
return normalizeFontName(name).replaceAll(' ', '+');
|
|
49
|
+
}
|
|
50
|
+
function escapeFontName(name) {
|
|
51
|
+
return name.replaceAll('\\', '\\\\').replaceAll("'", "\\'");
|
|
52
|
+
}
|
|
53
|
+
function getDefaultFallback(variable) {
|
|
54
|
+
return variable?.includes('mono') ? defaultMonoFallback : defaultSansFallback;
|
|
55
|
+
}
|
|
56
|
+
function buildFamilyQuery(font) {
|
|
57
|
+
const name = encodeFamilyName(font.name);
|
|
58
|
+
const weights = getFontWeights(font.weights);
|
|
59
|
+
const styles = getFontStyles(font.styles);
|
|
60
|
+
if (styles.length === 1 && styles[0] === 'normal') {
|
|
61
|
+
return `${name}:wght@${weights.join(';')}`;
|
|
62
|
+
}
|
|
63
|
+
const pairs = styles.flatMap((style) => weights.map((weight) => `${style === 'italic' ? 1 : 0},${weight}`));
|
|
64
|
+
return `${name}:ital,wght@${pairs.join(';')}`;
|
|
65
|
+
}
|
|
66
|
+
export function buildGoogleFontsUrl(fonts, display = 'swap') {
|
|
67
|
+
const families = fonts
|
|
68
|
+
.filter((font) => !isLocalFont(font))
|
|
69
|
+
.map((font) => buildFamilyQuery(font))
|
|
70
|
+
.filter((family, index, source) => family.length > 0 && source.indexOf(family) === index);
|
|
71
|
+
if (families.length === 0)
|
|
72
|
+
return '';
|
|
73
|
+
const params = new URLSearchParams();
|
|
74
|
+
families.forEach((family) => {
|
|
75
|
+
params.append('family', family);
|
|
76
|
+
});
|
|
77
|
+
params.set('display', display);
|
|
78
|
+
return `https://fonts.googleapis.com/css2?${params.toString()}`;
|
|
79
|
+
}
|
|
80
|
+
export function buildFontFamily(font) {
|
|
81
|
+
const family = `'${escapeFontName(normalizeFontName(font.name))}'`;
|
|
82
|
+
return `${family}, ${font.fallback ?? getDefaultFallback(font.variable)}`;
|
|
83
|
+
}
|
|
84
|
+
function buildLocalFontSourceReference(source) {
|
|
85
|
+
const url = `url('${source.src.replaceAll("'", "\\'")}')`;
|
|
86
|
+
return source.format ? `${url} format('${source.format}')` : url;
|
|
87
|
+
}
|
|
88
|
+
export function buildLocalFontFaceCss(fonts, defaultDisplay = 'swap') {
|
|
89
|
+
const declarations = fonts.filter(isLocalFont).flatMap((font) => font.sources.map((source) => {
|
|
90
|
+
const lines = [
|
|
91
|
+
'@font-face {',
|
|
92
|
+
` font-family: '${escapeFontName(normalizeFontName(font.name))}';`,
|
|
93
|
+
` src: ${buildLocalFontSourceReference(source)};`,
|
|
94
|
+
` font-display: ${font.display ?? defaultDisplay};`,
|
|
95
|
+
` font-style: ${source.style ?? 'normal'};`,
|
|
96
|
+
` font-weight: ${source.weight ?? 400};`
|
|
97
|
+
];
|
|
98
|
+
if (source.unicodeRange) {
|
|
99
|
+
lines.push(` unicode-range: ${source.unicodeRange};`);
|
|
100
|
+
}
|
|
101
|
+
lines.push('}');
|
|
102
|
+
return lines.join('\n');
|
|
103
|
+
}));
|
|
104
|
+
return declarations.join('\n\n');
|
|
105
|
+
}
|
|
106
|
+
export function buildFontVariablesCss(fonts) {
|
|
107
|
+
const declarations = fonts
|
|
108
|
+
.filter((font) => typeof font.variable === 'string' && font.variable.length > 2)
|
|
109
|
+
.map((font) => ` ${font.variable}: ${buildFontFamily(font)};`);
|
|
110
|
+
if (declarations.length === 0)
|
|
111
|
+
return '';
|
|
112
|
+
return `:root {\n${declarations.join('\n')}\n}`;
|
|
113
|
+
}
|
|
114
|
+
export function resolveFontsOptions(config) {
|
|
115
|
+
if (config === false)
|
|
116
|
+
return false;
|
|
117
|
+
if (config === true) {
|
|
118
|
+
return fontsDefaults;
|
|
119
|
+
}
|
|
120
|
+
if (config && typeof config === 'object') {
|
|
121
|
+
return {
|
|
122
|
+
families: config.families ?? fontsDefaults.families,
|
|
123
|
+
display: config.display ?? fontsDefaults.display,
|
|
124
|
+
preconnect: config.preconnect ?? fontsDefaults.preconnect
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return fontsDefaults;
|
|
128
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type GoogleFontStyle = 'normal' | 'italic';
|
|
2
|
+
export type GoogleFontDisplay = 'auto' | 'block' | 'swap' | 'fallback' | 'optional';
|
|
3
|
+
export type FontProvider = 'google' | 'local';
|
|
4
|
+
export type GoogleFontDefinition = {
|
|
5
|
+
provider?: 'google';
|
|
6
|
+
name: string;
|
|
7
|
+
weights?: number[];
|
|
8
|
+
styles?: GoogleFontStyle[];
|
|
9
|
+
variable?: `--${string}`;
|
|
10
|
+
fallback?: string;
|
|
11
|
+
};
|
|
12
|
+
export type LocalFontSourceFormat = 'woff2' | 'woff' | 'truetype' | 'opentype' | 'embedded-opentype' | 'svg';
|
|
13
|
+
export type LocalFontSource = {
|
|
14
|
+
src: string;
|
|
15
|
+
format?: LocalFontSourceFormat;
|
|
16
|
+
weight?: number | `${number} ${number}`;
|
|
17
|
+
style?: GoogleFontStyle;
|
|
18
|
+
unicodeRange?: string;
|
|
19
|
+
};
|
|
20
|
+
export type LocalFontDefinition = {
|
|
21
|
+
provider: 'local';
|
|
22
|
+
name: string;
|
|
23
|
+
sources: LocalFontSource[];
|
|
24
|
+
variable?: `--${string}`;
|
|
25
|
+
fallback?: string;
|
|
26
|
+
display?: GoogleFontDisplay;
|
|
27
|
+
};
|
|
28
|
+
export type FontDefinition = GoogleFontDefinition | LocalFontDefinition;
|
|
29
|
+
export type FontsOptions = {
|
|
30
|
+
families?: FontDefinition[];
|
|
31
|
+
display?: GoogleFontDisplay;
|
|
32
|
+
preconnect?: boolean;
|
|
33
|
+
};
|
|
34
|
+
export type FontsConfig = boolean | FontsOptions;
|
|
35
|
+
export type FontsProps = {
|
|
36
|
+
fonts?: FontDefinition[];
|
|
37
|
+
families?: FontDefinition[];
|
|
38
|
+
display?: GoogleFontDisplay;
|
|
39
|
+
preconnect?: boolean;
|
|
40
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { default as Fonts } from './Fonts.svelte';
|
|
2
|
+
export { buildFontFamily, buildFontVariablesCss, buildGoogleFontsUrl, buildLocalFontFaceCss, defaultFontFamilies, fontsDefaults, resolveFontsOptions } from './fonts.js';
|
|
3
|
+
export type { FontDefinition, FontsConfig, FontsOptions, GoogleFontDefinition, GoogleFontDisplay, GoogleFontStyle, LocalFontDefinition, LocalFontSource, LocalFontSourceFormat, FontsProps, FontProvider } from './fonts.types.js';
|
package/dist/config.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FontsConfig } from './Fonts/fonts.types.js';
|
|
1
2
|
/**
|
|
2
3
|
* Svelora Global Configuration
|
|
3
4
|
*
|
|
@@ -6,6 +7,15 @@
|
|
|
6
7
|
* import { defineConfig } from 'svelora'
|
|
7
8
|
*
|
|
8
9
|
* defineConfig({
|
|
10
|
+
* fonts: {
|
|
11
|
+
* families: [
|
|
12
|
+
* {
|
|
13
|
+
* name: 'Inter',
|
|
14
|
+
* variable: '--font-sans-family',
|
|
15
|
+
* weights: [400, 500, 600, 700]
|
|
16
|
+
* }
|
|
17
|
+
* ]
|
|
18
|
+
* },
|
|
9
19
|
* button: {
|
|
10
20
|
* defaultVariants: { variant: 'outline', color: 'secondary' },
|
|
11
21
|
* slots: { base: 'shadow-md', label: 'font-bold' }
|
|
@@ -48,8 +58,9 @@ type DeepPartial<T> = {
|
|
|
48
58
|
};
|
|
49
59
|
/** Generic component config shape */
|
|
50
60
|
export type UIConfig = {
|
|
51
|
-
[key: string]: DeepPartial<Record<string, unknown>> | undefined;
|
|
61
|
+
[key: string]: DeepPartial<Record<string, unknown>> | FontsConfig | undefined;
|
|
52
62
|
icons?: DeepPartial<typeof iconsDefaults>;
|
|
63
|
+
fonts?: FontsConfig;
|
|
53
64
|
};
|
|
54
65
|
/**
|
|
55
66
|
* Define global configuration for Svelora components
|
package/dist/config.js
CHANGED
|
@@ -6,6 +6,15 @@
|
|
|
6
6
|
* import { defineConfig } from 'svelora'
|
|
7
7
|
*
|
|
8
8
|
* defineConfig({
|
|
9
|
+
* fonts: {
|
|
10
|
+
* families: [
|
|
11
|
+
* {
|
|
12
|
+
* name: 'Inter',
|
|
13
|
+
* variable: '--font-sans-family',
|
|
14
|
+
* weights: [400, 500, 600, 700]
|
|
15
|
+
* }
|
|
16
|
+
* ]
|
|
17
|
+
* },
|
|
9
18
|
* button: {
|
|
10
19
|
* defaultVariants: { variant: 'outline', color: 'secondary' },
|
|
11
20
|
* slots: { base: 'shadow-md', label: 'font-bold' }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type DocSectionSnippet = {
|
|
2
|
+
heading: string;
|
|
3
|
+
snippet: string;
|
|
4
|
+
};
|
|
5
|
+
export type DocSectionSnippetOverrides = Record<string, string>;
|
|
6
|
+
export declare function normalizeCode(code: string): string;
|
|
7
|
+
export declare function extractSectionSnippet(sectionSource: string): string;
|
|
8
|
+
export declare function getSectionSnippets(source: string, routeOverrides?: DocSectionSnippetOverrides): DocSectionSnippet[];
|
|
9
|
+
export declare function renderHighlightedCode(code: string, isDarkMode?: boolean): Promise<string>;
|
|
10
|
+
export declare function slugToComponentName(slug: string): string;
|
|
11
|
+
export declare function slugToHookName(slug: string): string;
|
|
12
|
+
export declare function buildDefaultComponentExample(slug: string): string;
|
|
13
|
+
export declare function buildDefaultHookExample(slug: string): string;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { codeToHtml } from 'shiki';
|
|
2
|
+
export function normalizeCode(code) {
|
|
3
|
+
const lines = code.replaceAll('\r\n', '\n').split('\n');
|
|
4
|
+
const firstNonEmpty = lines.findIndex((line) => line.trim().length > 0);
|
|
5
|
+
const lastNonEmptyFromEnd = [...lines].reverse().findIndex((line) => line.trim().length > 0);
|
|
6
|
+
if (firstNonEmpty < 0 || lastNonEmptyFromEnd < 0) {
|
|
7
|
+
return '';
|
|
8
|
+
}
|
|
9
|
+
const trimmed = lines.slice(firstNonEmpty, lines.length - lastNonEmptyFromEnd);
|
|
10
|
+
const indents = trimmed
|
|
11
|
+
.filter((line) => line.trim().length > 0)
|
|
12
|
+
.map((line) => line.match(/^(\s*)/)?.[1].length ?? 0);
|
|
13
|
+
const minIndent = indents.length > 0 ? Math.min(...indents) : 0;
|
|
14
|
+
return trimmed
|
|
15
|
+
.map((line) => line.slice(minIndent))
|
|
16
|
+
.join('\n')
|
|
17
|
+
.trim();
|
|
18
|
+
}
|
|
19
|
+
function unwrapPreviewWrappers(source) {
|
|
20
|
+
let current = source.trim();
|
|
21
|
+
const stripPrefix = (token) => token.split(':').at(-1) ?? token;
|
|
22
|
+
const isPresentationToken = (token) => {
|
|
23
|
+
const t = stripPrefix(token);
|
|
24
|
+
if (t.length === 0)
|
|
25
|
+
return false;
|
|
26
|
+
if (t.startsWith('max-w-') || t.startsWith('min-w-') || t.startsWith('w-'))
|
|
27
|
+
return true;
|
|
28
|
+
if (t.startsWith('max-h-') || t.startsWith('min-h-') || t.startsWith('h-'))
|
|
29
|
+
return true;
|
|
30
|
+
if (/^(m|p)[trblxyse]?-\d+$/.test(t))
|
|
31
|
+
return true;
|
|
32
|
+
if (t.startsWith('gap-') || t.startsWith('space-'))
|
|
33
|
+
return true;
|
|
34
|
+
if (t.startsWith('overflow-'))
|
|
35
|
+
return true;
|
|
36
|
+
if (t === 'grid' || t.startsWith('grid-'))
|
|
37
|
+
return true;
|
|
38
|
+
if (t === 'flex' || t === 'inline-flex' || t.startsWith('flex-'))
|
|
39
|
+
return true;
|
|
40
|
+
if (t.startsWith('items-') || t.startsWith('justify-') || t.startsWith('content-'))
|
|
41
|
+
return true;
|
|
42
|
+
if (t.startsWith('self-') || t.startsWith('place-'))
|
|
43
|
+
return true;
|
|
44
|
+
if (t.startsWith('rounded'))
|
|
45
|
+
return true;
|
|
46
|
+
if (t.startsWith('border') || t.startsWith('ring') || t.startsWith('shadow'))
|
|
47
|
+
return true;
|
|
48
|
+
if (t === 'bg-transparent')
|
|
49
|
+
return true;
|
|
50
|
+
if (t.startsWith('bg-surface'))
|
|
51
|
+
return true;
|
|
52
|
+
if (t.startsWith('bg-['))
|
|
53
|
+
return true;
|
|
54
|
+
if (t.startsWith('text-') || t.startsWith('font-') || t.startsWith('leading-'))
|
|
55
|
+
return true;
|
|
56
|
+
if (t.startsWith('tracking-'))
|
|
57
|
+
return true;
|
|
58
|
+
if (t === 'uppercase' || t === 'lowercase' || t === 'capitalize')
|
|
59
|
+
return true;
|
|
60
|
+
if (t.startsWith('opacity-'))
|
|
61
|
+
return true;
|
|
62
|
+
if (t.startsWith('backdrop-blur') || t.startsWith('blur'))
|
|
63
|
+
return true;
|
|
64
|
+
if (t.startsWith('aspect-') || t.startsWith('object-'))
|
|
65
|
+
return true;
|
|
66
|
+
if (t.startsWith('size-'))
|
|
67
|
+
return true;
|
|
68
|
+
if (t.startsWith('[') && t.includes(']:'))
|
|
69
|
+
return true;
|
|
70
|
+
return false;
|
|
71
|
+
};
|
|
72
|
+
for (let pass = 0; pass < 3; pass += 1) {
|
|
73
|
+
const match = current.match(/^<div\b([^>]*)>([\s\S]*)<\/div>$/);
|
|
74
|
+
if (!match)
|
|
75
|
+
break;
|
|
76
|
+
const attrs = match[1];
|
|
77
|
+
const attrsWithoutClass = attrs
|
|
78
|
+
.replace(/\s*\bclass=(?:"[^"]*"|'[^']*')/, '')
|
|
79
|
+
.replace(/\s+/g, ' ')
|
|
80
|
+
.trim();
|
|
81
|
+
if (attrsWithoutClass.length > 0)
|
|
82
|
+
break;
|
|
83
|
+
const classMatch = attrs.match(/\bclass=(?:"([^"]*)"|'([^']*)')/);
|
|
84
|
+
const classValue = (classMatch?.[1] ?? classMatch?.[2] ?? '').trim();
|
|
85
|
+
const tokens = classValue.length > 0 ? classValue.split(/\s+/) : [];
|
|
86
|
+
const isPreviewBg = tokens.some((token) => token.startsWith('bg-surface-container'));
|
|
87
|
+
const isBordered = tokens.some((token) => token.startsWith('border-outline-variant'));
|
|
88
|
+
const isRounded = tokens.some((token) => token.startsWith('rounded'));
|
|
89
|
+
const hasPadding = tokens.some((token) => /^p[trblxy]?-\d+$/.test(token));
|
|
90
|
+
const isMaxWidth = tokens.some((token) => token.startsWith('max-w-'));
|
|
91
|
+
const isOverflow = tokens.some((token) => token.startsWith('overflow-'));
|
|
92
|
+
const isPresentationOnly = tokens.length > 0 && tokens.every(isPresentationToken);
|
|
93
|
+
const shouldUnwrap = ((isPreviewBg || isBordered || isRounded) && hasPadding) || isOverflow;
|
|
94
|
+
const shouldUnwrapMaxWidth = isMaxWidth && isPresentationOnly;
|
|
95
|
+
if (!shouldUnwrap && !shouldUnwrapMaxWidth)
|
|
96
|
+
break;
|
|
97
|
+
current = match[2].trim();
|
|
98
|
+
}
|
|
99
|
+
return current;
|
|
100
|
+
}
|
|
101
|
+
export function extractSectionSnippet(sectionSource) {
|
|
102
|
+
const openTagEnd = sectionSource.indexOf('>');
|
|
103
|
+
const closeTagStart = sectionSource.lastIndexOf('</section>');
|
|
104
|
+
if (openTagEnd < 0 || closeTagStart < 0) {
|
|
105
|
+
return normalizeCode(sectionSource);
|
|
106
|
+
}
|
|
107
|
+
let inner = sectionSource.slice(openTagEnd + 1, closeTagStart);
|
|
108
|
+
inner = inner.replace(/^\s*<h2\b[\s\S]*?<\/h2>\s*/, '');
|
|
109
|
+
inner = inner.replace(/^\s*<!--[\s\S]*?-->\s*/g, '');
|
|
110
|
+
while (/^\s*<p\b[\s\S]*?<\/p>\s*/.test(inner)) {
|
|
111
|
+
inner = inner.replace(/^\s*<p\b[\s\S]*?<\/p>\s*/, '');
|
|
112
|
+
}
|
|
113
|
+
inner = inner.replace(/\s*<!--[\s\S]*?-->\s*$/g, '');
|
|
114
|
+
inner = unwrapPreviewWrappers(inner);
|
|
115
|
+
return normalizeCode(inner);
|
|
116
|
+
}
|
|
117
|
+
function decodeHeading(value) {
|
|
118
|
+
return value
|
|
119
|
+
.replaceAll('&', '&')
|
|
120
|
+
.replaceAll('×', '×')
|
|
121
|
+
.replaceAll(''', "'")
|
|
122
|
+
.replaceAll('"', '"')
|
|
123
|
+
.trim();
|
|
124
|
+
}
|
|
125
|
+
function extractSectionHeading(sectionSource) {
|
|
126
|
+
const match = sectionSource.match(/<h2\b[^>]*>([\s\S]*?)<\/h2>/);
|
|
127
|
+
if (!match)
|
|
128
|
+
return '';
|
|
129
|
+
return decodeHeading(match[1].replace(/<[^>]+>/g, ' '));
|
|
130
|
+
}
|
|
131
|
+
export function getSectionSnippets(source, routeOverrides = {}) {
|
|
132
|
+
const overrides = routeOverrides;
|
|
133
|
+
return [...source.matchAll(/<section\b[\s\S]*?<\/section>/g)].map((match) => {
|
|
134
|
+
const sectionSource = match[0];
|
|
135
|
+
const heading = extractSectionHeading(sectionSource);
|
|
136
|
+
const overrideSnippet = heading ? overrides[heading] : undefined;
|
|
137
|
+
return {
|
|
138
|
+
heading,
|
|
139
|
+
snippet: overrideSnippet ?? extractSectionSnippet(sectionSource)
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function detectLanguage(code) {
|
|
144
|
+
const source = code.trim();
|
|
145
|
+
if (source.includes('<script lang="ts">') ||
|
|
146
|
+
source.includes('$state(') ||
|
|
147
|
+
source.includes('{#each') ||
|
|
148
|
+
source.includes('<Button') ||
|
|
149
|
+
source.includes('<FormField')) {
|
|
150
|
+
return 'svelte';
|
|
151
|
+
}
|
|
152
|
+
if (source.startsWith('{') || source.startsWith('[')) {
|
|
153
|
+
return 'json';
|
|
154
|
+
}
|
|
155
|
+
if (source.startsWith('@import') ||
|
|
156
|
+
(source.includes('{') && source.includes(':') && source.includes(';'))) {
|
|
157
|
+
return 'css';
|
|
158
|
+
}
|
|
159
|
+
if (source.includes('import ') || source.includes('export ') || source.includes('interface ')) {
|
|
160
|
+
return 'ts';
|
|
161
|
+
}
|
|
162
|
+
if (source.startsWith('<') && source.endsWith('>')) {
|
|
163
|
+
return 'html';
|
|
164
|
+
}
|
|
165
|
+
if (source.startsWith('npm ') || source.startsWith('bun ') || source.startsWith('pnpm ')) {
|
|
166
|
+
return 'bash';
|
|
167
|
+
}
|
|
168
|
+
return 'js';
|
|
169
|
+
}
|
|
170
|
+
function decorateHighlightedHtml(html) {
|
|
171
|
+
return html.replace(/<pre class="shiki[\s\S]*?"[^>]*>/, '<pre class="shiki">');
|
|
172
|
+
}
|
|
173
|
+
export async function renderHighlightedCode(code, isDarkMode = true) {
|
|
174
|
+
const html = await codeToHtml(code, {
|
|
175
|
+
lang: detectLanguage(code),
|
|
176
|
+
theme: isDarkMode ? 'github-dark' : 'github-light'
|
|
177
|
+
});
|
|
178
|
+
return decorateHighlightedHtml(html);
|
|
179
|
+
}
|
|
180
|
+
export function slugToComponentName(slug) {
|
|
181
|
+
return slug
|
|
182
|
+
.split('-')
|
|
183
|
+
.filter((token) => token.length > 0)
|
|
184
|
+
.map((token) => (token[0] ? token[0].toUpperCase() + token.slice(1) : token))
|
|
185
|
+
.join('');
|
|
186
|
+
}
|
|
187
|
+
export function slugToHookName(slug) {
|
|
188
|
+
const tokens = slug.split('-').filter((token) => token.length > 0);
|
|
189
|
+
if (tokens.length === 0)
|
|
190
|
+
return '';
|
|
191
|
+
const [first, ...rest] = tokens;
|
|
192
|
+
return [
|
|
193
|
+
first,
|
|
194
|
+
...rest.map((token) => (token[0] ? token[0].toUpperCase() + token.slice(1) : token))
|
|
195
|
+
].join('');
|
|
196
|
+
}
|
|
197
|
+
export function buildDefaultComponentExample(slug) {
|
|
198
|
+
const componentName = slugToComponentName(slug);
|
|
199
|
+
return (`<script lang="ts">
|
|
200
|
+
import { ${componentName} } from 'svelora';
|
|
201
|
+
<` +
|
|
202
|
+
`/script>
|
|
203
|
+
|
|
204
|
+
<${componentName} />`);
|
|
205
|
+
}
|
|
206
|
+
export function buildDefaultHookExample(slug) {
|
|
207
|
+
const hookName = slugToHookName(slug);
|
|
208
|
+
return (`<script lang="ts">
|
|
209
|
+
import { ${hookName} } from 'svelora';
|
|
210
|
+
<` +
|
|
211
|
+
`/script>
|
|
212
|
+
|
|
213
|
+
const value = ${hookName}();`);
|
|
214
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type DocsItem = {
|
|
2
|
+
title: string;
|
|
3
|
+
href: string;
|
|
4
|
+
icon: string;
|
|
5
|
+
legacyHref?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
};
|
|
8
|
+
export type DocsGroup = {
|
|
9
|
+
title: string;
|
|
10
|
+
items: DocsItem[];
|
|
11
|
+
};
|
|
12
|
+
export declare const docsMeta: {
|
|
13
|
+
readonly name: "Svelora";
|
|
14
|
+
readonly version: `v${string}`;
|
|
15
|
+
readonly npmCommand: "npm install svelora";
|
|
16
|
+
readonly githubHref: "https://github.com/asphum/svelora";
|
|
17
|
+
};
|
|
18
|
+
export declare const docsIntroItems: DocsItem[];
|
|
19
|
+
export declare const docsThemeItems: DocsItem[];
|
|
20
|
+
export declare const docsComponentGroups: DocsGroup[];
|
|
21
|
+
export declare const docsHookItems: DocsItem[];
|
|
22
|
+
export declare const docsTopNav: DocsItem[];
|
|
23
|
+
export declare const allComponentItems: DocsItem[];
|
|
24
|
+
export declare const allDocsItems: DocsItem[];
|
|
25
|
+
export declare const totalComponents: number;
|
|
26
|
+
export declare const totalHooks: number;
|
|
27
|
+
export declare const docsPathAliases: Map<string, string>;
|