-
-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathvite-plugin-demos.ts
More file actions
100 lines (87 loc) · 3.35 KB
/
Copy pathvite-plugin-demos.ts
File metadata and controls
100 lines (87 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import type { Plugin } from "vite";
import { loadDemos } from "./src/load-demos";
import { glob } from "tinyglobby";
import { resolve } from "node:path";
import shiki from "./shiki";
const VIRTUAL_PREFIX = "virtual:demo/";
const RESOLVED_PREFIX = resolve("src/virtual-demos") + "/";
export function demosPlugin(): Plugin {
return {
name: "vite-plugin-demos",
async resolveId(id) {
if (id.startsWith(VIRTUAL_PREFIX)) {
return RESOLVED_PREFIX + id.slice(VIRTUAL_PREFIX.length) + ".svelte";
}
},
async load(id) {
if (!id.startsWith(RESOLVED_PREFIX)) return;
if (!id.endsWith(".svelte")) return;
const demoIndex = parseInt(id.slice(RESOLVED_PREFIX.length, -".svelte".length));
const demos = await loadDemos();
const demo = demos[demoIndex];
if (!demo) return;
const components = await glob(["src/lib/**/*.svelte", "!src/lib/forms/_picker"]);
const getFile = (component: string) => {
return components.find((f) => f.endsWith(`/${component}.svelte`))!;
};
const {
friendlyName,
minimalDemo,
components: componentsStr,
fullDemoTs,
fullDemoSvelte,
warning,
} = demo;
const demoComponents = componentsStr.split("\n").filter(Boolean);
const imports = demoComponents
.filter((c) => !["Switch", "Icon", "Slider"].includes(c))
.map((c) => `import ${c} from "${getFile(c).replace("src/lib", "$lib")}";`)
.join("\n");
const relevantLinksData = demoComponents
.filter((c) =>
c.toLowerCase() == friendlyName.toLowerCase()
? true
: !["Checkbox", "Divider", "Button"].includes(c),
)
.map((c) => ({
title: c.length > 10 ? `${c}.sv` : `${c}.svelte`,
link: getFile(c).replace(
"src/lib",
"https://github.com/KTibow/m3-svelte/blob/main/src/lib",
),
}));
// Escape for template literal
const escapedMinimalDemoHtml = (await shiki(minimalDemo, "svelte"))
.replaceAll("\\", "\\\\")
.replaceAll("`", "\\`")
.replaceAll("$", "\\$")
.replaceAll("<", "\\x3C");
const relevantLinksJson = JSON.stringify(relevantLinksData);
const friendlyNameJson = JSON.stringify(friendlyName);
const warningJson = warning ? JSON.stringify(warning) : "undefined";
return `<script lang="ts">
import iconCircle from "@ktibow/iconset-material-symbols/circle-outline";
import iconSquare from "@ktibow/iconset-material-symbols/square-outline";
import iconTriangle from "@ktibow/iconset-material-symbols/change-history-outline";
import Switch from "$lib/forms/Switch.svelte";
import Icon from "$lib/misc/Icon.svelte";
import Slider from "$lib/forms/Slider.svelte";
import Arrows from "/src/routes/_arrows.svelte";
import InternalCard from "/src/routes/_card.svelte";
${imports}
${fullDemoTs}
let { showCode }: { showCode: (
name: string,
minimalDemoHtml: string,
relevantLinks: { title: string; link: string }[],
) => void } = $props();
const minimalDemoHtml = \`${escapedMinimalDemoHtml}\`;
const relevantLinks: { title: string; link: string }[] = ${relevantLinksJson};
</script>
<InternalCard title="${friendlyName}" warning={${warningJson}} showCode={() => showCode(${friendlyNameJson}, minimalDemoHtml, relevantLinks)}>
${fullDemoSvelte}
</InternalCard>
`;
},
};
}