mirror of
https://github.com/elk-zone/elk.git
synced 2024-12-18 17:11:56 +03:00
feat: markdown editor, close #1845
This commit is contained in:
parent
fa3cfd6059
commit
6d0cbd2914
3 changed files with 93 additions and 5 deletions
|
@ -29,6 +29,9 @@ const { t } = useI18n()
|
||||||
const draftState = useDraft(draftKey, initial)
|
const draftState = useDraft(draftKey, initial)
|
||||||
const { draft } = $(draftState)
|
const { draft } = $(draftState)
|
||||||
|
|
||||||
|
const settings = useUserSettings()
|
||||||
|
const textareaEl = ref<HTMLTextAreaElement>()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isExceedingAttachmentLimit, isUploading, failedAttachments, isOverDropZone,
|
isExceedingAttachmentLimit, isUploading, failedAttachments, isOverDropZone,
|
||||||
uploadAttachments, pickAttachments, setDescription, removeAttachment,
|
uploadAttachments, pickAttachments, setDescription, removeAttachment,
|
||||||
|
@ -48,11 +51,17 @@ const { editor } = useTiptap({
|
||||||
set: (newVal) => {
|
set: (newVal) => {
|
||||||
draft.params.status = newVal
|
draft.params.status = newVal
|
||||||
draft.lastUpdated = Date.now()
|
draft.lastUpdated = Date.now()
|
||||||
|
if (settings.value.editorMode === 'markdown')
|
||||||
|
onTipTapChanged()
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
placeholder: computed(() => placeholder ?? draft.params.inReplyToId ? t('placeholder.replying') : t('placeholder.default_1')),
|
placeholder: computed(() => placeholder ?? draft.params.inReplyToId ? t('placeholder.replying') : t('placeholder.default_1')),
|
||||||
autofocus: shouldExpanded,
|
autofocus: shouldExpanded,
|
||||||
onSubmit: publish,
|
onSubmit: () => {
|
||||||
|
if (settings.value.editorMode === 'markdown')
|
||||||
|
onMarkdownChanged()
|
||||||
|
publish()
|
||||||
|
},
|
||||||
onFocus() {
|
onFocus() {
|
||||||
if (!isExpanded && draft.initialText) {
|
if (!isExpanded && draft.initialText) {
|
||||||
editor.value?.chain().insertContent(`${draft.initialText} `).focus('end').run()
|
editor.value?.chain().insertContent(`${draft.initialText} `).focus('end').run()
|
||||||
|
@ -113,10 +122,16 @@ async function handlePaste(evt: ClipboardEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertEmoji(name: string) {
|
function insertEmoji(name: string) {
|
||||||
editor.value?.chain().focus().insertEmoji(name).run()
|
if (settings.value.editorMode === 'markdown')
|
||||||
|
insertMarkdownAtCursor(name)
|
||||||
|
else
|
||||||
|
editor.value?.chain().focus().insertEmoji(name).run()
|
||||||
}
|
}
|
||||||
function insertCustomEmoji(image: any) {
|
function insertCustomEmoji(image: any) {
|
||||||
editor.value?.chain().focus().insertCustomEmoji(image).run()
|
if (settings.value.editorMode === 'markdown')
|
||||||
|
insertMarkdownAtCursor(`:${image['data-emoji-id']}:`)
|
||||||
|
else
|
||||||
|
editor.value?.chain().focus().insertCustomEmoji(image).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleSensitive() {
|
async function toggleSensitive() {
|
||||||
|
@ -129,6 +144,55 @@ async function publish() {
|
||||||
emit('published', status)
|
emit('published', status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let markdown = $ref(htmlToText(draft.params.status || ''))
|
||||||
|
|
||||||
|
function insertMarkdownAtCursor(text: string) {
|
||||||
|
if (!textareaEl.value)
|
||||||
|
return
|
||||||
|
textareaEl.value.focus()
|
||||||
|
const start = textareaEl.value.selectionStart || 0
|
||||||
|
const end = textareaEl.value.selectionEnd || 0
|
||||||
|
const before = markdown.substring(0, start)
|
||||||
|
const after = markdown.substring(end)
|
||||||
|
markdown = before + text + after
|
||||||
|
textareaEl.value.setSelectionRange(end + text.length, end + text.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onMarkdownChanged() {
|
||||||
|
draft.params.status = await convertMastodonHTML(markdown)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTipTapChanged() {
|
||||||
|
markdown = htmlToText(draft.params.status || '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleEditor() {
|
||||||
|
if (settings.value.editorMode === 'markdown') {
|
||||||
|
onMarkdownChanged()
|
||||||
|
settings.value.editorMode = 'tiptap'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
onTipTapChanged()
|
||||||
|
settings.value.editorMode = 'markdown'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(markdown, () => {
|
||||||
|
if (settings.value.editorMode === 'markdown')
|
||||||
|
onMarkdownChanged()
|
||||||
|
})
|
||||||
|
|
||||||
|
useTextareaAutosize({
|
||||||
|
input: markdown,
|
||||||
|
element: textareaEl,
|
||||||
|
})
|
||||||
|
|
||||||
|
const editorClass = $computed(() =>
|
||||||
|
shouldExpanded
|
||||||
|
? 'min-h-30 md:max-h-[calc(100vh-200px)] sm:max-h-[calc(100vh-400px)] max-h-35 of-y-auto overscroll-contain'
|
||||||
|
: '',
|
||||||
|
)
|
||||||
|
|
||||||
useWebShareTarget(async ({ data: { data, action } }: any) => {
|
useWebShareTarget(async ({ data: { data, action } }: any) => {
|
||||||
if (action !== 'compose-with-shared-data')
|
if (action !== 'compose-with-shared-data')
|
||||||
return
|
return
|
||||||
|
@ -218,10 +282,24 @@ defineExpose({
|
||||||
</CommonErrorMessage>
|
</CommonErrorMessage>
|
||||||
|
|
||||||
<div relative flex-1 flex flex-col>
|
<div relative flex-1 flex flex-col>
|
||||||
|
<template v-if="settings.editorMode === 'markdown'">
|
||||||
|
<textarea
|
||||||
|
|
||||||
|
ref="textareaEl"
|
||||||
|
v-model="markdown"
|
||||||
|
bg-base font-mono outline-none border-none resize-none
|
||||||
|
:class="editorClass"
|
||||||
|
/>
|
||||||
|
<div text-sm flex="~ gap-1" items-center op50 mb--3 mt-2>
|
||||||
|
<div i-ri:markdown-line />
|
||||||
|
{{ $t('state.markdown_editor') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<EditorContent
|
<EditorContent
|
||||||
|
v-else
|
||||||
:editor="editor"
|
:editor="editor"
|
||||||
flex max-w-full
|
flex max-w-full
|
||||||
:class="shouldExpanded ? 'min-h-30 md:max-h-[calc(100vh-200px)] sm:max-h-[calc(100vh-400px)] max-h-35 of-y-auto overscroll-contain' : ''"
|
:class="editorClass"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -292,7 +370,14 @@ defineExpose({
|
||||||
</button>
|
</button>
|
||||||
</CommonTooltip>
|
</CommonTooltip>
|
||||||
|
|
||||||
<PublishEditorTools v-if="editor" :editor="editor" />
|
<CommonTooltip placement="top" :content="$t('tooltip.toggle_editor')">
|
||||||
|
<button btn-action-icon :aria-label="$t('tooltip.toggle_editor')" @click="toggleEditor()">
|
||||||
|
<div v-if="settings.editorMode === 'markdown'" i-ri:markdown-line />
|
||||||
|
<div v-else i-ri:file-text-line />
|
||||||
|
</button>
|
||||||
|
</CommonTooltip>
|
||||||
|
|
||||||
|
<PublishEditorTools v-if="editor && settings.editorMode !== 'markdown'" :editor="editor" />
|
||||||
|
|
||||||
<div flex-auto />
|
<div flex-auto />
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ export interface UserSettings {
|
||||||
disabledTranslationLanguages: string[]
|
disabledTranslationLanguages: string[]
|
||||||
zenMode: boolean
|
zenMode: boolean
|
||||||
themeColors?: ThemeColors
|
themeColors?: ThemeColors
|
||||||
|
editorMode?: 'tiptap' | 'markdown'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ThemeColors {
|
export interface ThemeColors {
|
||||||
|
|
|
@ -488,6 +488,7 @@
|
||||||
"edited": "(Edited)",
|
"edited": "(Edited)",
|
||||||
"editing": "Editing",
|
"editing": "Editing",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
|
"markdown_editor": "Markdown Editor",
|
||||||
"publish_failed": "Publish failed",
|
"publish_failed": "Publish failed",
|
||||||
"publishing": "Publishing",
|
"publishing": "Publishing",
|
||||||
"upload_failed": "Upload failed",
|
"upload_failed": "Upload failed",
|
||||||
|
@ -597,6 +598,7 @@
|
||||||
"publish_failed": "Close failed messages at the top of editor to republish posts",
|
"publish_failed": "Close failed messages at the top of editor to republish posts",
|
||||||
"toggle_bold": "Toggle bold",
|
"toggle_bold": "Toggle bold",
|
||||||
"toggle_code_block": "Toggle code block",
|
"toggle_code_block": "Toggle code block",
|
||||||
|
"toggle_editor": "Toggle between WYSIWYG editor and markdown editor",
|
||||||
"toggle_italic": "Toggle italic"
|
"toggle_italic": "Toggle italic"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
|
|
Loading…
Reference in a new issue