Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9d8f043

Browse files
committedDec 21, 2024·
Remove page/pageMeta global state
1 parent cc43e37 commit 9d8f043

File tree

6 files changed

+116
-115
lines changed

6 files changed

+116
-115
lines changed
 

Diff for: ‎src/components/MonacoEditor.vue

+36-40
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
<script setup lang="ts">
22
import type { editor } from 'monaco-editor';
3-
import { onBeforeUnmount, onMounted, shallowRef, useTemplateRef } from 'vue';
3+
import { computed, onBeforeUnmount, onMounted, shallowRef, useTemplateRef, watch } from 'vue';
44
import type * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';
5-
import * as monaco from 'monaco-editor';
5+
const monaco = await import('monaco-editor');
66
// import { activateMarkers, activateAutoInsertion, registerProviders } from '@volar/monaco';
77
8-
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
9-
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
10-
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
11-
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
12-
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
13-
// import mdxWorker from '@/lib/monaco/mdx-lang-server.worker?worker';
14-
// import type { WorkerLanguageService } from '@volar/monaco/worker';
8+
const { default: editorWorker } = await import('monaco-editor/esm/vs/editor/editor.worker?worker');
9+
const { default: jsonWorker } = await import('monaco-editor/esm/vs/language/json/json.worker?worker');
10+
const { default: cssWorker } = await import('monaco-editor/esm/vs/language/css/css.worker?worker');
11+
const { default: htmlWorker } = await import('monaco-editor/esm/vs/language/html/html.worker?worker');
12+
const { default: tsWorker } = await import('monaco-editor/esm/vs/language/typescript/ts.worker?worker');
1513
1614
export type MonacoEditor = typeof monacoEditor;
1715
@@ -29,9 +27,6 @@ self.MonacoEnvironment = {
2927
if (label === 'typescript' || label === 'javascript') {
3028
return new tsWorker();
3129
}
32-
// if (label === 'mdx') {
33-
// return new mdxWorker();
34-
// }
3530
return new editorWorker();
3631
}
3732
};
@@ -42,50 +37,51 @@ const props = defineProps<{
4237
onBeforeMount?: () => void,
4338
onMount?: (editor: editor.IStandaloneCodeEditor) => void,
4439
editorOptions?: editor.IStandaloneEditorConstructionOptions,
40+
language: string,
4541
}>();
4642
43+
const text = defineModel<string>('text', { default: '' });
44+
4745
const editorElement = useTemplateRef('editorElement');
4846
const editorRef = shallowRef<editor.IStandaloneCodeEditor>();
47+
const isEditorReady = computed(() => !!editorRef.value);
48+
const model = computed(() => isEditorReady.value ? editorRef.value!.getModel() : undefined);
4949
50-
onMounted(() => {
51-
if (!editorElement.value) throw new Error('wtf');
50+
watch(() => props.language, language => {
51+
if (isEditorReady.value) {
52+
monaco.editor.setModelLanguage(editorRef.value!.getModel()!, language);
53+
}
54+
});
5255
53-
// monaco.languages.register({ id: 'mdx', extensions: ['.mdx'], mimetypes: ['text/mdx'] });
56+
watch(text, text => {
57+
if (model.value?.getValue() != text) {
58+
model.value?.setValue(text);
59+
}
60+
});
5461
55-
// monaco.languages.onLanguage('mdx', () => {
56-
// const worker = monaco.editor.createWebWorker<WorkerLanguageService>({
57-
// moduleId: 'vs/language/my-lang/myLangWorker',
58-
// label: 'mdx',
59-
// });
60-
// activateMarkers(
61-
// worker,
62-
// ['mdx'],
63-
// 'mdx-markers-owner',
64-
// // sync files
65-
// () => [],
66-
// monaco.editor
67-
// );
68-
// // auto close tags
69-
// activateAutoInsertion(
70-
// worker,
71-
// ['mdx'],
72-
// // sync files
73-
// () => [],
74-
// monaco.editor
75-
// );
76-
// registerProviders(worker, ['mdx'], () => [], monaco.languages);
77-
// });
62+
onMounted(() => {
63+
if (!editorElement.value) throw new Error('wtf');
7864
7965
props.onBeforeMount?.();
66+
8067
editorRef.value = monaco.editor.create(editorElement.value!, props.editorOptions);
68+
monaco.editor.setModelLanguage(model.value!, props.language);
69+
model.value!.setValue(text.value);
70+
71+
editorRef.value.onDidChangeModelContent(() => {
72+
const value = editorRef.value!.getValue();
73+
if (value !== text.value) {
74+
text.value = value;
75+
}
76+
});
77+
8178
props.onMount?.(editorRef.value);
8279
});
8380
8481
onBeforeUnmount(() => {
82+
editorRef.value?.getModel()?.dispose();
8583
editorRef.value?.dispose();
8684
});
87-
88-
// height: calc(100vh - 69.6px - 68px)
8985
</script>
9086

9187
<template>

Diff for: ‎src/lib/injection-keys.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { InjectionKey, ShallowRef } from "vue";
2+
import type { Page, PageMeta } from "./atproto/atweb-unauthed";
3+
4+
export const pageKey = Symbol('page') as InjectionKey<ShallowRef<Page | undefined>>;
5+
export const pageMetaKey = Symbol('pageMeta') as InjectionKey<ShallowRef<PageMeta | undefined>>;

Diff for: ‎src/lib/shared-globals.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ref, shallowRef } from "vue";
22
import type { Page, PageMeta } from "./atproto/atweb-unauthed";
33

4-
export const pageMeta = shallowRef<PageMeta>();
5-
export const page = shallowRef<Page>();
4+
// export const pageMeta = shallowRef<PageMeta>();
5+
// export const page = shallowRef<Page>();
66
export const useVanillaCss = ref(true);

Diff for: ‎src/lib/vue-utils.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import {
1212
type MultiWatchSources,
1313
type WatchHandle,
1414
type Reactive,
15+
inject,
1516
} from 'vue';
1617
import type { ReactiveMarker } from '@vue/reactivity/dist/reactivity.d.ts';
1718
import { useRouter, type RouteLocationAsPath, type RouteLocationAsRelative, type RouteLocationAsString } from 'vue-router';
18-
import { pageMeta } from './shared-globals';
1919
import { getRelativeOrAbsoluteBlobUrl } from './component-helpers';
20+
import { pageMetaKey } from './injection-keys';
2021

2122
export function getSlotChildrenText(
2223
children: Slot | VNode[] | VNodeArrayChildren | undefined,
@@ -125,8 +126,10 @@ export function resolveRoute(route: RouteLocationAsString | RouteLocationAsRelat
125126
}
126127

127128
export function computedAtUrlProperty(src: string | undefined, elementName: string, useCdn = false) {
129+
const pageMeta = inject(pageMetaKey);
130+
128131
return computedAsync(async () => {
129-
if (!pageMeta.value) {
132+
if (!pageMeta?.value) {
130133
console.warn(`no pageMeta for ${elementName} ${src}`);
131134
return;
132135
}

Diff for: ‎src/pages/edit/[[rkey]].vue

+33-32
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<script setup lang="ts">
2-
import { computed, reactive, ref, shallowRef, watch } from 'vue';
2+
import { computed, provide, reactive, ref, shallowRef, watch } from 'vue';
33
import type { editor } from 'monaco-editor';
44
import { themeNames, themes } from '@/lib/monaco/themes';
55
import { user, waitForInitialSession } from '@/lib/atproto/signed-in-user';
66
import SignInGate from '@/components/SignInGate.vue';
77
import { language as mdxLang, conf as mdxLangConf } from '@/lib/monaco/mdx-lang';
88
import type { IoGithubAtwebFile } from '@atcute/client/lexicons';
9-
import { downloadFile } from '@/lib/atproto/atweb-unauthed';
9+
import { downloadFile, Page, type PageMeta } from '@/lib/atproto/atweb-unauthed';
1010
import { filepathToRkey, rkeyToFilepath } from '@/lib/atproto/rkey';
1111
import * as monaco from 'monaco-editor';
1212
import type { AtUri } from '@atproto/syntax';
@@ -16,9 +16,10 @@ import MonacoEditor from '@/components/MonacoEditor.vue';
1616
import MarkdownRenderer from '@/components/MarkdownRenderer.vue';
1717
import { useRoute, useRouter } from 'vue-router';
1818
import UsePico from '@/components/UsePico.vue';
19-
import { pageMeta, useVanillaCss } from '@/lib/shared-globals';
19+
import { useVanillaCss } from '@/lib/shared-globals';
2020
import { frameworkStyles } from '@/lib/framework-styles';
2121
import { ShadowRoot } from 'vue-shadow-dom';
22+
import { pageKey, pageMetaKey } from '@/lib/injection-keys';
2223
2324
for (const [themeName, theme] of Object.entries(themes)) {
2425
// console.log(themeName, theme);
@@ -36,19 +37,18 @@ const MONACO_EDITOR_OPTIONS: editor.IStandaloneEditorConstructionOptions = {
3637
contextmenu: true,
3738
};
3839
40+
const pageRef = shallowRef<Page>();
41+
const pageMetaRef = shallowRef<PageMeta>();
42+
provide(pageKey, pageRef);
43+
provide(pageMetaKey, pageMetaRef);
44+
3945
const editorRef = shallowRef<editor.IStandaloneCodeEditor>();
4046
const editorValue = ref('');
47+
const editorLanguage = ref('plaintext');
4148
const submitted = ref(false);
4249
4350
function onMonacoMount(editor: editor.IStandaloneCodeEditor) {
4451
editorRef.value = editor;
45-
46-
editorRef.value.onDidChangeModelContent(() => {
47-
const value = editorRef.value!.getValue();
48-
if (value !== editorValue.value) {
49-
editorValue.value = value;
50-
}
51-
});
5252
}
5353
5454
// your action
@@ -111,36 +111,31 @@ async function setActiveFile(file: IoGithubAtwebFile.Record & { uri: AtUri }) {
111111
112112
if (!user.value) return;
113113
114-
const page = await downloadFile(user.value.did, file.uri.rkey);
115-
pageMeta.value = page;
116-
editorRef.value!.setValue(page.blobString);
114+
const page = pageRef.value = pageMetaRef.value = await downloadFile(user.value.did, file.uri.rkey);
115+
editorValue.value = page.blobString;
117116
router.push({ params: { rkey: file.uri.rkey }});
118117
}
119118
120-
watchImmediate(useRoute('/edit/[[rkey]]'), async route => {
121-
if (route.params.rkey) {
122-
const filePath = rkeyToFilepath(route.params.rkey);
123-
if (activeFile.value != route.params.rkey) {
124-
activeFile.value = filePath;
119+
const route = useRoute('/edit/[[rkey]]');
120+
if (route.params.rkey) {
121+
const filePath = rkeyToFilepath(route.params.rkey);
122+
if (activeFile.value != route.params.rkey) {
123+
activeFile.value = filePath;
125124
126-
await waitForInitialSession();
125+
await waitForInitialSession();
127126
128-
if (user.value) {
129-
const page = await downloadFile(user.value.did, route.params.rkey);
130-
pageMeta.value = page;
131-
editorRef.value!.setValue(page.blobString);
132-
}
127+
if (user.value) {
128+
const page = pageRef.value = pageMetaRef.value = await downloadFile(user.value.did, route.params.rkey);
129+
editorValue.value = page.blobString;
133130
}
134131
}
135-
});
132+
}
136133
137-
watch(activeFile, activeFile => {
138-
monaco.editor.setModelLanguage(
139-
editorRef.value!.getModel()!,
140-
activeFile ? lookupMime(activeFile) ?? 'mdx' : 'plaintext'
141-
);
134+
watchImmediate(activeFile, activeFile => {
135+
editorLanguage.value = activeFile ? lookupMime(activeFile) ?? 'mdx' : 'plaintext';
142136
if (user) {
143-
pageMeta.value = {
137+
pageRef.value = undefined;
138+
pageMetaRef.value = {
144139
did: user.value!.did,
145140
filePath: activeFile,
146141
};
@@ -190,7 +185,13 @@ await adoptedStyleSheet.replace(frameworkStyles);
190185
</div>
191186
</UsePico>
192187

193-
<MonacoEditor editor-style="height: calc(100vh - 115.5px - 86.6px)" v-on:mount="onMonacoMount" :editor-options="MONACO_EDITOR_OPTIONS" />
188+
<MonacoEditor
189+
editor-style="height: calc(100vh - 115.5px - 86.6px)"
190+
v-on:mount="onMonacoMount"
191+
:editor-options="MONACO_EDITOR_OPTIONS"
192+
:language="editorLanguage"
193+
v-model:text="editorValue"
194+
/>
194195
</div>
195196
<div class="right" style="min-width: 25vw;" v-if="isMarkdownFile">
196197
<div style="padding: 1rem; max-height: calc(100vh - 115.5px); overflow: auto;">

Diff for: ‎src/pages/page/[handle]/[rkey]/index.vue

+35-39
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,53 @@
11
<script setup lang="ts">
2-
import { onBeforeUnmount, provide, ref, shallowRef, watch } from 'vue';
2+
import { inject, provide, ref, shallowRef } from 'vue';
33
import MarkdownRenderer from '@/components/MarkdownRenderer.vue';
4-
import { downloadFile, getGetBlobUrl, type Page } from '@/lib/atproto/atweb-unauthed';
5-
import { onBeforeRouteLeave, useRoute } from 'vue-router';
4+
import { downloadFile, getGetBlobUrl, type Page, type PageMeta } from '@/lib/atproto/atweb-unauthed';
5+
import { useRoute } from 'vue-router';
66
import { resolveHandleAnonymously } from '@/lib/atproto/handles/resolve';
7-
import { page, pageMeta, useVanillaCss } from '@/lib/shared-globals';
8-
import { watchImmediate } from '@vueuse/core';
97
import { watchImmediateAsync } from '@/lib/vue-utils';
108
import UsePico from '@/components/UsePico.vue';
119
import { frameworkStyles } from '@/lib/framework-styles';
10+
import { pageKey, pageMetaKey } from '@/lib/injection-keys';
11+
12+
const pageRef = shallowRef<Page>();
13+
const pageMetaRef = shallowRef<PageMeta>();
14+
provide(pageKey, pageRef);
15+
provide(pageMetaKey, pageMetaRef);
16+
17+
const type = ref<'markdown' | 'pre' | 'image' | 'generic' | 'none'>('none');
18+
const contents = ref<string>('');
1219
1320
const route = useRoute('/page/[handle]/[rkey]/');
1421
await watchImmediateAsync(
1522
route,
1623
async () => {
1724
const did = await resolveHandleAnonymously(route.params.handle as string);
18-
page.value = await downloadFile(did, route.params.rkey as string);
19-
pageMeta.value = page.value;
20-
},
21-
);
2225
23-
onBeforeRouteLeave(() => {
24-
page.value = undefined;
25-
pageMeta.value = page.value;
26-
});
26+
let page: Page;
27+
pageRef.value = pageMetaRef.value = page = await downloadFile(did, route.params.rkey as string);
2728
28-
const type = ref<'markdown' | 'pre' | 'image' | 'generic' | 'none'>('none');
29-
const contents = ref<string>('');
30-
31-
await watchImmediateAsync(page, async page => {
32-
console.log('watched', page);
29+
console.log('watched', page);
3330
34-
if (page === undefined) return;
31+
type.value = 'none';
32+
contents.value = '';
3533
36-
type.value = 'none';
37-
contents.value = '';
38-
39-
if (page.bodyOriginal.mimeType === 'text/mdx') {
40-
console.log('setting md');
41-
type.value = 'markdown';
42-
contents.value = page.blobString;
43-
console.log('set md');
44-
} else if (page.bodyOriginal.mimeType.startsWith('image/')) {
45-
type.value = 'image';
46-
contents.value = await getGetBlobUrl(page.uri, true);
47-
} else if (page.bodyOriginal.mimeType.startsWith('text/')) {
48-
type.value = 'pre';
49-
contents.value = page.blobString;
50-
} else {
51-
type.value = 'generic';
52-
contents.value = await getGetBlobUrl(page.uri);
53-
}
54-
});
34+
if (page.bodyOriginal.mimeType === 'text/mdx') {
35+
console.log('setting md');
36+
type.value = 'markdown';
37+
contents.value = page.blobString;
38+
console.log('set md');
39+
} else if (page.bodyOriginal.mimeType.startsWith('image/')) {
40+
type.value = 'image';
41+
contents.value = await getGetBlobUrl(page.uri, true);
42+
} else if (page.bodyOriginal.mimeType.startsWith('text/')) {
43+
type.value = 'pre';
44+
contents.value = page.blobString;
45+
} else {
46+
type.value = 'generic';
47+
contents.value = await getGetBlobUrl(page.uri);
48+
}
49+
},
50+
);
5551
5652
const adoptedStyleSheet = new CSSStyleSheet();
5753
adoptedStyleSheet.replace(frameworkStyles);
@@ -72,7 +68,7 @@ adoptedStyleSheet.replace(frameworkStyles);
7268
<img v-else-if="type == 'image'" :src="contents" />
7369
<pre v-else-if="type == 'pre'">{{ contents }}</pre>
7470
<a v-else-if="type == 'generic'" :href="contents">
75-
Unknown file type <code>{{ page?.bodyOriginal.mimeType }}</code>.
71+
Unknown file type <code>{{ inject(pageKey)?.bodyOriginal.mimeType }}</code>.
7672
Click to download blob.
7773
</a>
7874
</div>

0 commit comments

Comments
 (0)
Please sign in to comment.