{note?.title ? `${note?.title.length > 30 ? `${note?.title.slice(0, 30)}...` : note?.title} โ€ข ${$WEBUI_NAME}` : `${$WEBUI_NAME}`} {#if note} { changeDebounceHandler(); }} /> {/if} { deleteNoteHandler(note.id); showDeleteConfirm = false; }} >
{$i18n.t('This will delete')} {note.title}.
{#if loading}
{:else}
{#if $mobile}
{/if} { titleInputFocused = true; }} on:blur={(e) => { // check if target is generate button if (ignoreBlur) { ignoreBlur = false; return; } titleInputFocused = false; changeDebounceHandler(); }} /> {#if titleInputFocused && !titleGenerating}
{/if}
{#if editor}
{/if} { downloadHandler(type); }} onCopyLink={async () => { const baseUrl = window.location.origin; const res = await copyToClipboard(`${baseUrl}/notes/${note.id}`); if (res) { toast.success($i18n.t('Copied link to clipboard')); } else { toast.error($i18n.t('Failed to copy link')); } }} onCopyToClipboard={async () => { const res = await copyToClipboard( note.data.content.md, note.data.content.html, true ).catch((error) => { toast.error(`${error}`); return null; }); if (res) { toast.success($i18n.t('Copied to clipboard')); } }} onDelete={() => { showDeleteConfirm = true; }} >
{ if (e.deltaY !== 0) { e.preventDefault(); e.currentTarget.scrollLeft += e.deltaY; } }} >
{#if editor}
{$i18n.t('{{COUNT}} words', { COUNT: wordCount })}
{$i18n.t('{{COUNT}} characters', { COUNT: charCount })}
{/if}
{#if editing}
{/if} { const { from, to } = editor.state.selection; const selectedText = editor.state.doc.textBetween(from, to, ' '); if (selectedText.length === 0) { selectedContent = null; } else { selectedContent = { text: selectedText, from: from, to: to }; } }} onChange={(content) => { note.data.content.html = content.html; note.data.content.md = content.md; if (editor) { wordCount = editor.storage.characterCount.words(); charCount = editor.storage.characterCount.characters(); } }} fileHandler={true} onFileDrop={(currentEditor, files, pos) => { files.forEach(async (file) => { const fileItem = await inputFileHandler(file).catch((error) => { return null; }); if (fileItem.type === 'image') { // If the file is an image, insert it directly currentEditor .chain() .insertContentAt(pos, { type: 'image', attrs: { src: `data://${fileItem.id}` } }) .focus() .run(); } }); }} onFilePaste={() => {}} on:paste={async (e) => { e = e.detail.event || e; const clipboardData = e.clipboardData || window.clipboardData; console.log('Clipboard data:', clipboardData); if (clipboardData && clipboardData.items) { console.log('Clipboard data items:', clipboardData.items); for (const item of clipboardData.items) { console.log('Clipboard item:', item); if (item.type.indexOf('image') !== -1) { const blob = item.getAsFile(); const fileItem = await inputFileHandler(blob); if (editor) { editor ?.chain() .insertContentAt(editor.state.selection.$anchor.pos, { type: 'image', attrs: { src: `data://${fileItem.id}` // Use data URI for the image } }) .focus() .run(); } } else if (item?.kind === 'file') { const file = item.getAsFile(); await inputFileHandler(file); e.preventDefault(); } } } }} />
{/if}
{#if recording}
{ recording = false; displayMediaRecord = false; }} onConfirm={(data) => { if (data?.file) { uploadFileHandler(data?.file); } recording = false; displayMediaRecord = false; }} />
{:else} { displayMediaRecord = false; try { let stream = await navigator.mediaDevices .getUserMedia({ audio: true }) .catch(function (err) { toast.error( $i18n.t(`Permission denied when accessing microphone: {{error}}`, { error: err }) ); return null; }); if (stream) { recording = true; const tracks = stream.getTracks(); tracks.forEach((track) => track.stop()); } stream = null; } catch { toast.error($i18n.t('Permission denied when accessing microphone')); } }} onCaptureAudio={async () => { displayMediaRecord = true; recording = true; }} onUpload={async () => { const input = document.createElement('input'); input.type = 'file'; input.accept = 'audio/*'; input.multiple = false; input.click(); input.onchange = async (e) => { const files = e.target.files; if (files && files.length > 0) { await uploadFileHandler(files[0]); } }; }} >
{#if editing} {:else} { enhanceNoteHandler(); }} onChat={() => { showPanel = true; selectedPanel = 'chat'; }} >
{/if}
{/if}
{#if selectedPanel === 'chat'} { insertNoteVersion(note); }} scrollToBottomHandler={scrollToBottom} /> {:else if selectedPanel === 'settings'} { changeDebounceHandler(); }} /> {/if}