-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
107 lines (94 loc) · 2.69 KB
/
main.js
File metadata and controls
107 lines (94 loc) · 2.69 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
101
102
103
104
105
106
107
// @ts-check
/** @import { PropType } from "vue" */
import { defineComponent, onWatcherCleanup, ref, watchEffect } from "vue";
import { createApp } from "vue/dist/vue.esm-bundler.js";
import { fetchReadmeHTML, fetchSourceHTML } from "./utils.js";
const html = String.raw;
/** @satisfies{{ [url: string]: { lang: string } }} */
const sources = /** @type { const } */ ({
"./index.html": { lang: "html" },
"./main.js": { lang: "javascript" },
"./utils.js": { lang: "javascript" },
});
const SourceView = defineComponent({
props: {
url: {
type: /** @type { PropType<keyof typeof sources> } */ (String),
required: true,
},
},
emits: {
// deno-lint-ignore no-unused-vars
loadingChange: /** @param { boolean } loading */ (loading) => true,
},
template: html`
<div v-html="sourceHTML"></div>
`,
setup(props, context) {
const sourceHTML = ref(/** @type { string | undefined } */ (undefined));
watchEffect(() => {
const ctrl = new AbortController();
context.emit("loadingChange", true);
fetchSourceHTML(props.url, sources[props.url].lang, ctrl.signal).then(
(html) => {
sourceHTML.value = html;
context.emit("loadingChange", false);
},
);
onWatcherCleanup(() => ctrl.abort());
});
return { sourceHTML };
},
});
const SourcesView = defineComponent({
components: { SourceView },
template: html`
<label>
Source:
<select v-model="selectedUrl">
<option v-for="(lang, url) in sources" :key="url" :value="url">
{{ url }}
</option>
</select>
</label>
<progress v-if="sourceLoading"></progress>
<source-view :url="selectedUrl" @loading-change="sourceLoading = $event" />
`,
setup() {
const selectedUrl = ref(
/** @type {keyof typeof sources} */ ("./index.html"),
);
const sourceLoading = ref(false);
return { selectedUrl, sources, sourceLoading };
},
});
const ReadmeView = defineComponent({
template: html`
<section v-html="readmeHTML"></section>
`,
setup() {
const readmeHTML = ref(/** @type { string | undefined } */ (undefined));
watchEffect(() => {
const ctrl = new AbortController();
fetchReadmeHTML(ctrl.signal).then((html) => {
readmeHTML.value = html;
});
onWatcherCleanup(() => ctrl.abort());
});
return { readmeHTML };
},
});
const App = defineComponent({
components: { ReadmeView, SourcesView },
template: html`
<readme-view />
<sources-view />
`,
setup() {},
});
Object.assign(globalThis, {
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
});
createApp(App).mount(document.body);