Trying out CodeMirror. I think I like it? Use it in readonly mode for view. Wrapping up for the day.

This commit is contained in:
Scott Idem
2025-05-12 19:56:56 -04:00
parent 3b38c31ba0
commit b5642583c7
4 changed files with 1658 additions and 787 deletions

2173
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -96,7 +96,7 @@
"@codemirror/theme-one-dark": "^6.1.2", "@codemirror/theme-one-dark": "^6.1.2",
"@codemirror/view": "^6.36.8", "@codemirror/view": "^6.36.8",
"@floating-ui/dom": "^1.6.0", "@floating-ui/dom": "^1.6.0",
"@lucide/svelte": "^0.494.0", "@lucide/svelte": "^0.510.0",
"@popperjs/core": "^2.11.0", "@popperjs/core": "^2.11.0",
"@tiptap/extension-bullet-list": "^2.10.2", "@tiptap/extension-bullet-list": "^2.10.2",
"@tiptap/extension-document": "^2.10.2", "@tiptap/extension-document": "^2.10.2",
@@ -105,10 +105,10 @@
"axios": "^1.7.0", "axios": "^1.7.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"dexie": "^4.0.11", "dexie": "^4.0.0",
"flowbite-svelte": "^0.48.00", "flowbite-svelte": "^0.48.00",
"html5-qrcode": "^2.3.8", "html5-qrcode": "^2.3.8",
"lucide-svelte": "^0.494.0", "lucide-svelte": "^0.510.0",
"marked": "^15.0.7", "marked": "^15.0.7",
"shadcn-svelte": "^0.14.0" "shadcn-svelte": "^0.14.0"
} }

View File

@@ -1,73 +1,118 @@
<script lang="ts"> <script lang="ts">
import { onMount, onDestroy, createEventDispatcher } from 'svelte'; // *** Import Svelte version 5 specific
import { EditorView, keymap, placeholder as placeholderExt } from '@codemirror/view'; import { browser } from '$app/environment';
import { EditorState, StateEffect, type Extension } from '@codemirror/state';
import { indentWithTab } from '@codemirror/commands';
import { basicSetup } from 'codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from "@codemirror/theme-one-dark";
// Props import { onMount, onDestroy, createEventDispatcher } from 'svelte';
export let content: string = 'test test test test'; import { EditorView, keymap, placeholder as placeholderExt } from '@codemirror/view';
export let new_content: string = ''; import { EditorState, StateEffect, type Extension } from '@codemirror/state';
export let language: Extension = javascript(); import { indentWithTab } from '@codemirror/commands';
export let theme: Extension = oneDark; import { basicSetup } from 'codemirror';
export let extensions: Extension[] = []; import { javascript } from '@codemirror/lang-javascript';
export let editable: boolean = true; import { oneDark } from "@codemirror/theme-one-dark";
export let placeholder: string = 'Start typing...';
const dispatch = createEventDispatcher<{ change: string }>(); // Props
export let content: string = 'test test test test';
export let new_content: string = '';
export let language: Extension = javascript();
export let theme: Extension = oneDark;
export let extensions: Extension[] = [];
export let editable: boolean = true;
export let placeholder: string = 'Start typing...';
let classes = "";
export { classes as class };
let editor_element: HTMLDivElement; let baseTheme = EditorView.baseTheme({
let editorView: EditorView; ".cm-o-replacement": {
display: "inline-block",
width: ".5em",
height: ".5em",
borderRadius: ".25em"
},
"&light .cm-o-replacement": {
backgroundColor: "#04c"
},
"&dark .cm-o-replacement": {
backgroundColor: "#5bf"
}
})
// theme == baseTheme;
// Reactive declaration for extensions const dispatch = createEventDispatcher<{ change: string }>();
$: editor_extensions = [
basicSetup,
EditorView.editable.of(editable),
keymap.of([indentWithTab]),
placeholderExt(placeholder),
language,
theme,
...extensions
];
// Initialize CodeMirror on mount let editor_element: HTMLDivElement;
onMount(() => { let editorView: EditorView;
editorView = new EditorView({
state: EditorState.create({ // Reactive declaration for extensions
doc: content, $: editor_extensions = [
extensions: editor_extensions, basicSetup,
}), EditorView.editable.of(editable),
parent: editor_element, keymap.of([indentWithTab]),
dispatch: (transaction) => { placeholderExt(placeholder),
editorView.update([transaction]); language,
if (transaction.docChanged) { theme,
new_content = editorView.state.doc.toString(); // baseTheme = {
const newContent = editorView.state.doc.toString(); // ".cm-o-replacement": {
dispatch('change', newContent); // display: "inline-block",
} // width: ".5em",
// height: ".5em",
// borderRadius: ".25em"
// },
// "&light .cm-o-replacement": {
// backgroundColor: "#04c"
// },
// "&dark .cm-o-replacement": {
// backgroundColor: "#5bf"
// }
// },
...extensions
];
// Initialize CodeMirror on mount
onMount(() => {
editorView = new EditorView({
state: EditorState.create({
doc: content,
extensions: editor_extensions,
}),
parent: editor_element,
dispatch: (transaction) => {
editorView.update([transaction]);
if (transaction.docChanged) {
new_content = editorView.state.doc.toString();
const newContent = editorView.state.doc.toString();
dispatch('change', newContent);
} }
}); }
}); });
});
// Clean up on destroy // Clean up on destroy
onDestroy(() => { onDestroy(() => {
editorView?.destroy(); editorView?.destroy();
}); });
// Update editor content when `content` prop changes // Update editor content when `content` prop changes
$: if (editorView && editorView.state.doc.toString() !== content) { $: if (editorView && editorView.state.doc.toString() !== content) {
editorView.setState( editorView.setState(
EditorState.create({ EditorState.create({
doc: content, doc: content,
extensions: editor_extensions extensions: editor_extensions
}) })
); );
}; };
</script> </script>
<div bind:this={editor_element} class="codemirror-wrapper"></div> {#if browser}
<div bind:this={editor_element} class="codemirror-wrapper {classes}"></div>
{:else}
<div class="scm-waiting {classes}">
<div class="scm-waiting__loading scm-loading">
<p class="scm-loading__text">Loading editor...</p>
</div>
<pre class="scm-pre cm-editor">{value}</pre>
</div>
{/if}
<style> <style>
.codemirror-wrapper :global(.cm-focused) { .codemirror-wrapper :global(.cm-focused) {

View File

@@ -1894,40 +1894,67 @@ tabindex={$ae_loc.edit_mode ? 0 : -1} -->
</div> </div>
{:else} {:else}
<!-- <div <!-- <div
class="
flex-grow
h-full max-h-full
w-full min-w-full max-w-6xl"
> -->
<!-- disabled={tmp_entry_obj?.private && !$journals_loc?.entry?.decrypt_kv[$lq__journal_entry_obj?.journal_entry_id]} -->
<textarea
bind:value={tmp_entry_obj.content}
ondblclick={() => {
// if ($ae_loc.trusted_access && $ae_loc.edit_mode) {
// // Toggle edit mode
// $journals_loc.entry.edit = !$journals_loc.entry.edit;
// $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] = $journals_loc.entry.edit;
// }
}}
class=" class="
flex-grow flex-grow
flex-shrink-0 h-full max-h-full
basis-full w-full min-w-full max-w-6xl"
h-max min-h-max max-h-full > -->
w-full min-w-full max-w-6xl <!-- disabled={tmp_entry_obj?.private && !$journals_loc?.entry?.decrypt_kv[$lq__journal_entry_obj?.journal_entry_id]} -->
p-2
space-y-1 {#if !$ae_loc.edit_mode || !$ae_loc.trusted_access}
font-mono <textarea
bg-slate-100 text-gray-900 bind:value={tmp_entry_obj.content}
dark:bg-slate-900 dark:text-gray-100 ondblclick={() => {
shadow-lg rounded-lg // if ($ae_loc.trusted_access && $ae_loc.edit_mode) {
border border-orange-200 dark:border-orange-700 // // Toggle edit mode
hover:border-orange-500 dark:hover:border-orange-500 // $journals_loc.entry.edit = !$journals_loc.entry.edit;
" // $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] = $journals_loc.entry.edit;
placeholder="Edit journal entry content here..." // }
></textarea> }}
class="
flex-grow
flex-shrink-0
basis-full
h-max min-h-max max-h-full
w-full min-w-full max-w-6xl
p-2
space-y-1
font-mono
bg-slate-100 text-gray-900
dark:bg-slate-900 dark:text-gray-100
shadow-lg rounded-lg
border border-orange-200 dark:border-orange-700
hover:border-orange-500 dark:hover:border-orange-500
"
placeholder="Edit journal entry content here..."
></textarea>
{:else}
<E_app_codemirror_v5
content={tmp_entry_obj?.content ?? ''}
bind:new_content={tmp_entry_obj.content}
language={markdown()}
placeholder="Write your JavaScript code here..."
classes="
flex-grow
flex-shrink-0
basis-full
h-max min-h-max max-h-full
w-full min-w-full max-w-6xl
p-2
space-y-1
font-mono
bg-slate-100 text-gray-900
dark:bg-slate-900 dark:text-gray-100
shadow-lg rounded-lg
border border-orange-200 dark:border-orange-700
hover:border-orange-500 dark:hover:border-orange-500
"
/>
{/if}
<!-- Only enable editing if the user has trusted access --> <!-- Only enable editing if the user has trusted access -->
<button <button
@@ -2054,16 +2081,16 @@ zzzz
classes="editor" classes="editor"
/> --> /> -->
<!-- bind:content={tmp_entry_obj.content} --> <!-- bind:content={tmp_entry_obj.content} -->
<E_app_codemirror_v5 <!-- <E_app_codemirror_v5
bind:content={tmp_entry_obj.content} content={tmp_entry_obj?.content ?? ''}
bind:new_content={tmp_entry_obj.new_content} bind:new_content={tmp_entry_obj.content}
language={markdown()} language={markdown()}
placeholder="Write your JavaScript code here..." placeholder="Write your JavaScript code here..."
/> /> -->
<pre> <!-- <pre>
{tmp_entry_obj.new_content} {tmp_entry_obj.new_content}
</pre> </pre> -->
</div> </div>
{/if} {/if}