Create new EditorContent component

This commit is contained in:
Jon Staab
2025-02-03 20:57:47 -08:00
parent 7d4ba6c806
commit fedc99b0f0
7 changed files with 59 additions and 39 deletions

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import {onMount} from "svelte"
import {onMount, onDestroy} from "svelte"
import {writable} from "svelte/store"
import {EditorContent} from "svelte-tiptap"
import {isMobile, preventDefault} from "@lib/html"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import EditorContent from "@lib/components/EditorContent.svelte"
import {makeEditor} from "@app/editor"
interface Props {
@@ -14,29 +14,35 @@
const {onSubmit, content = ""}: Props = $props()
export const focus = () => $editor.chain().focus().run()
const autofocus = !isMobile
const uploading = writable(false)
const uploadFiles = () => $editor!.chain().selectFiles().run()
export const focus = () => editor.chain().focus().run()
const uploadFiles = () => editor.chain().selectFiles().run()
const submit = () => {
if ($uploading) return
const content = $editor!.getText({blockSeparator: "\n"}).trim()
const tags = $editor!.storage.nostr.getEditorTags()
const content = editor.getText({blockSeparator: "\n"}).trim()
const tags = editor.storage.nostr.getEditorTags()
if (!content) return
onSubmit({content, tags})
$editor!.chain().clearContent().run()
editor.chain().clearContent().run()
}
const editor = makeEditor({autofocus: !isMobile, submit, uploading, aggressive: true})
const editor = makeEditor({autofocus, submit, uploading, aggressive: true})
onMount(() => {
$editor!.chain().setContent(content).run()
editor.chain().setContent(content).run()
})
onDestroy(() => {
editor.destroy()
})
</script>
@@ -53,7 +59,7 @@
{/if}
</Button>
<div class="chat-editor flex-grow overflow-hidden">
<EditorContent editor={$editor} />
<EditorContent {editor} />
</div>
<Button
data-tip="{window.navigator.platform.includes('Mac') ? 'cmd' : 'ctrl'}+enter to send"

View File

@@ -6,7 +6,9 @@
const {url, event} = $props()
const confirm = async () => {
await publishDelete({event, relays: [url]})
const snapshot = $state.snapshot(event)
await publishDelete({event: snapshot, relays: [url]})
clearModals()
}

View File

@@ -1,5 +1,4 @@
<script lang="ts">
import {EditorContent} from "svelte-tiptap"
import {writable} from "svelte/store"
import {randomId} from "@welshman/lib"
import {createEvent, EVENT_TIME} from "@welshman/util"
@@ -11,6 +10,7 @@
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import DateTimeInput from "@lib/components/DateTimeInput.svelte"
import EditorContent from "@lib/components/EditorContent.svelte"
import {PROTECTED} from "@app/state"
import {makeEditor} from "@app/editor"
import {pushToast} from "@app/toast"
@@ -39,14 +39,14 @@
}
const event = createEvent(EVENT_TIME, {
content: $editor.getText({blockSeparator: "\n"}).trim(),
content: editor.getText({blockSeparator: "\n"}).trim(),
tags: [
["d", randomId()],
["title", title],
["location", location],
["start", dateToSeconds(start).toString()],
["end", dateToSeconds(end).toString()],
...$editor.storage.nostr.getEditorTags(),
...editor.storage.nostr.getEditorTags(),
PROTECTED,
],
})
@@ -89,12 +89,12 @@
{#snippet input()}
<div class="relative z-feature flex gap-2 border-t border-solid border-base-100 bg-base-100">
<div class="input-editor flex-grow overflow-hidden">
<EditorContent editor={$editor} />
<EditorContent {editor} />
</div>
<Button
data-tip="Add an image"
class="center btn tooltip"
onclick={() => $editor.chain().selectFiles().run()}>
onclick={() => editor.chain().selectFiles().run()}>
{#if $uploading}
<span class="loading loading-spinner loading-xs"></span>
{:else}

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import {writable} from "svelte/store"
import {EditorContent} from "svelte-tiptap"
import {createEvent, THREAD} from "@welshman/util"
import {publishThunk} from "@welshman/app"
import {isMobile, preventDefault} from "@lib/html"
@@ -9,6 +8,7 @@
import Button from "@lib/components/Button.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import EditorContent from "@lib/components/EditorContent.svelte"
import {pushToast} from "@app/toast"
import {GENERAL, tagRoom, PROTECTED} from "@app/state"
import {makeEditor} from "@app/editor"
@@ -29,7 +29,7 @@
})
}
const content = $editor.getText({blockSeparator: "\n"}).trim()
const content = editor.getText({blockSeparator: "\n"}).trim()
if (!content.trim()) {
return pushToast({
@@ -39,7 +39,7 @@
}
const tags = [
...$editor.storage.nostr.getEditorTags(),
...editor.storage.nostr.getEditorTags(),
tagRoom(GENERAL, url),
["title", title],
PROTECTED,
@@ -90,14 +90,14 @@
{/snippet}
{#snippet input()}
<div class="note-editor flex-grow overflow-hidden">
<EditorContent editor={$editor} />
<EditorContent {editor} />
</div>
{/snippet}
</Field>
<Button
data-tip="Add an image"
class="tooltip tooltip-left absolute bottom-1 right-2"
onclick={$editor.commands.selectFiles}>
onclick={editor.commands.selectFiles}>
{#if $uploading}
<span class="loading loading-spinner loading-xs"></span>
{:else}

View File

@@ -1,11 +1,11 @@
<script lang="ts">
import {writable} from "svelte/store"
import {EditorContent} from "svelte-tiptap"
import {isMobile, preventDefault} from "@lib/html"
import {fly, slideAndFade} from "@lib/transition"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import EditorContent from "@lib/components/EditorContent.svelte"
import {publishComment} from "@app/commands"
import {tagRoom, GENERAL, PROTECTED} from "@app/state"
import {makeEditor} from "@app/editor"
@@ -18,8 +18,8 @@
const submit = () => {
if ($uploading) return
const content = $editor.getText({blockSeparator: "\n"}).trim()
const tags = [...$editor.storage.nostr.getEditorTags(), tagRoom(GENERAL, url), PROTECTED]
const content = editor.getText({blockSeparator: "\n"}).trim()
const tags = [...editor.storage.nostr.getEditorTags(), tagRoom(GENERAL, url), PROTECTED]
if (!content) {
return pushToast({
@@ -41,12 +41,12 @@
class="card2 sticky bottom-2 z-feature mx-2 mt-4 bg-neutral">
<div class="relative">
<div class="note-editor flex-grow overflow-hidden">
<EditorContent editor={$editor} />
<EditorContent {editor} />
</div>
<Button
data-tip="Add an image"
class="tooltip tooltip-left absolute bottom-1 right-2"
onclick={$editor.commands.selectFiles}>
onclick={editor.commands.selectFiles}>
{#if $uploading}
<span class="loading loading-spinner loading-xs"></span>
{:else}

View File

@@ -1,6 +1,6 @@
import {asClassComponent} from "svelte/legacy"
import type {Writable} from "svelte/store"
import {derived, readable} from "svelte/store"
import {derived} from "svelte/store"
import {Editor, SvelteNodeViewRenderer} from "svelte-tiptap"
import {ctx} from "@welshman/lib"
import type {StampedEvent} from "@welshman/util"
@@ -44,10 +44,8 @@ export const makeEditor = ({
submit: () => void
uploading?: Writable<boolean>
wordCount?: Writable<number>
}) => {
let setter: (editor: Editor) => void
const _editor = new Editor({
}) =>
new Editor({
content,
autofocus,
extensions: [
@@ -96,15 +94,7 @@ export const makeEditor = ({
}),
],
onUpdate({editor}) {
setter?.(editor)
wordCount?.set(editor.storage.wordCount.words)
charCount?.set(editor.storage.wordCount.chars)
},
})
return readable(_editor, set => {
setter = set
return () => _editor.destroy()
})
}

View File

@@ -0,0 +1,22 @@
<script lang="ts">
import {onDestroy, onMount} from "svelte"
const {editor} = $props()
let element: HTMLElement
onMount(() => {
if (element) {
element.append(...(Array.from(editor.options.element.childNodes) as any))
editor.setOptions({element})
editor.contentElement = element
}
})
onDestroy(() => {
editor.contentElement = null
editor.setOptions({element: null})
})
</script>
<div bind:this={element}></div>