your personal website on atproto - mirror blento.app
at map 87 lines 1.8 kB view raw
1<script lang="ts"> 2 import { onDestroy, onMount } from 'svelte'; 3 import { Editor, type Extensions } from '@tiptap/core'; 4 import Placeholder from '@tiptap/extension-placeholder'; 5 import Paragraph from '@tiptap/extension-paragraph'; 6 import Document from '@tiptap/extension-document'; 7 import Text from '@tiptap/extension-text'; 8 import type { Item } from '$lib/types'; 9 10 let element: HTMLElement | undefined = $state(); 11 let editor: Editor | null = $state(null); 12 13 let { 14 item = $bindable(), 15 key, 16 class: className, 17 placeholder = '', 18 defaultContent = '' 19 }: { 20 item: Item; 21 key: string; 22 class?: string; 23 placeholder?: string; 24 defaultContent?: string; 25 } = $props(); 26 27 const update = async () => { 28 if (!editor) return; 29 30 item.cardData[key] = editor.getText(); 31 }; 32 33 onMount(async () => { 34 if (!element || editor) return; 35 36 let extensions: Extensions = [Document.configure(), Paragraph.configure(), Text.configure()]; 37 38 if (placeholder) { 39 extensions.push( 40 Placeholder.configure({ 41 placeholder: placeholder 42 }) 43 ); 44 } 45 46 editor = new Editor({ 47 element: element, 48 extensions: extensions, 49 onTransaction: () => { 50 editor = editor; 51 }, 52 onUpdate: () => { 53 update(); 54 }, 55 56 content: item.cardData[key] ?? defaultContent, 57 58 editorProps: { 59 attributes: { 60 class: 'outline-none pointer-events-auto' 61 } 62 } 63 }); 64 }); 65 66 onDestroy(() => { 67 if (editor) { 68 editor.destroy(); 69 } 70 }); 71</script> 72 73<span class={className} bind:this={element}></span> 74 75<style> 76 :global(.tiptap p.is-editor-empty:first-child::before) { 77 color: var(--color-base-800); 78 content: attr(data-placeholder); 79 opacity: 50%; 80 float: left; 81 height: 0; 82 pointer-events: none; 83 } 84 :global(.dark .tiptap p.is-editor-empty:first-child::before) { 85 color: var(--color-base-200); 86 } 87</style>