You've already forked SmartisanNote.Remake
736 lines
21 KiB
Vue
736 lines
21 KiB
Vue
<template>
|
||
<div class="editor-container">
|
||
<!-- 工具栏 -->
|
||
<div class="toolbar">
|
||
<button v-for="tool in tools" :key="tool.name" :class="{ active: tool.active }" @click="tool.action" class="toolbar-btn">
|
||
<img :src="tool.icon" :alt="tool.name" class="toolbar-icon" />
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 编辑区域 -->
|
||
<div ref="editorRef" contenteditable="true" class="editor-content" @input="handleInput" @keydown="handleKeydown" @click="updateToolbarState" @keyup="updateToolbarState"></div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, nextTick } from 'vue'
|
||
|
||
const props = defineProps({
|
||
modelValue: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
})
|
||
|
||
const emit = defineEmits(['update:modelValue'])
|
||
|
||
const editorRef = ref(null)
|
||
const content = ref(props.modelValue || '')
|
||
|
||
// 工具配置
|
||
const tools = ref([
|
||
{
|
||
name: 'bold',
|
||
icon: '/assets/icons/drawable-xxhdpi/rtf_bold_normal.9.png',
|
||
action: () => formatText('bold'),
|
||
active: false,
|
||
},
|
||
{
|
||
name: 'center',
|
||
icon: '/assets/icons/drawable-xxhdpi/rtf_center_normal.9.png',
|
||
action: () => formatText('justifyCenter'),
|
||
active: false,
|
||
},
|
||
{
|
||
name: 'todo',
|
||
icon: '/assets/icons/drawable-xxhdpi/rtf_gtasks_normal.9.png',
|
||
action: () => insertTodoList(),
|
||
active: false,
|
||
},
|
||
{
|
||
name: 'list',
|
||
icon: '/assets/icons/drawable-xxhdpi/rtf_list_normal.9.png',
|
||
action: () => formatText('insertUnorderedList'),
|
||
active: false,
|
||
},
|
||
{
|
||
name: 'header',
|
||
icon: '/assets/icons/drawable-xxhdpi/rtf_header_normal.9.png',
|
||
action: () => formatText('formatBlock', 'h2'),
|
||
active: false,
|
||
},
|
||
{
|
||
name: 'quote',
|
||
icon: '/assets/icons/drawable-xxhdpi/rtf_quot_normal.9.png',
|
||
action: () => insertQuote(),
|
||
active: false,
|
||
},
|
||
])
|
||
|
||
// 检查当前选区是否已经在某种格式中
|
||
const isAlreadyInFormat = formatType => {
|
||
const selection = window.getSelection()
|
||
if (selection.rangeCount > 0) {
|
||
const range = selection.getRangeAt(0)
|
||
const container = range.commonAncestorContainer
|
||
|
||
// 向上查找父元素,检查是否已经在指定格式中
|
||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||
while (current && current !== editorRef.value) {
|
||
if (formatType === 'bold' && current.tagName === 'B') return true
|
||
if (formatType === 'center' && current.style.textAlign === 'center') return true
|
||
if (formatType === 'header' && current.tagName === 'H2') return true
|
||
if (formatType === 'quote' && (current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content'))) return true
|
||
if (formatType === 'list' && (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI')) return true
|
||
current = current.parentElement
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// 检查是否在列表、引用或待办事项中(用于嵌套限制)
|
||
const isInListOrQuote = () => {
|
||
const selection = window.getSelection()
|
||
if (selection.rangeCount > 0) {
|
||
const range = selection.getRangeAt(0)
|
||
const container = range.commonAncestorContainer
|
||
|
||
// 向上查找父元素,检查是否在列表、引用或待办事项中
|
||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||
while (current && current !== editorRef.value) {
|
||
if (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI' || current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content') || current.classList.contains('todo-container')) {
|
||
return true
|
||
}
|
||
current = current.parentElement
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// 格式化文本
|
||
const formatText = (command, value = null) => {
|
||
// 检查是否已经应用了相同的格式
|
||
if (command === 'bold' && isAlreadyInFormat('bold')) return
|
||
if (command === 'justifyCenter' && isAlreadyInFormat('center')) return
|
||
if (command === 'formatBlock' && value === 'h2' && isAlreadyInFormat('header')) return
|
||
if (command === 'formatBlock' && value === 'blockquote' && isAlreadyInFormat('quote')) return
|
||
if (command === 'insertUnorderedList' && isAlreadyInFormat('list')) return
|
||
|
||
// 检查嵌套限制
|
||
if ((command === 'insertUnorderedList' || (command === 'formatBlock' && value === 'blockquote')) && isInListOrQuote()) {
|
||
return
|
||
}
|
||
|
||
document.execCommand(command, false, value)
|
||
updateToolbarState()
|
||
handleInput()
|
||
}
|
||
|
||
// 插入水平线
|
||
const insertHorizontalRule = () => {
|
||
document.execCommand('insertHorizontalRule', false, null)
|
||
handleInput()
|
||
}
|
||
|
||
// 插入引用格式
|
||
const insertQuote = () => {
|
||
const selection = window.getSelection()
|
||
if (selection.rangeCount > 0) {
|
||
const range = selection.getRangeAt(0)
|
||
|
||
// 检查是否已经在引用中
|
||
const container = range.commonAncestorContainer
|
||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||
while (current && current !== editorRef.value) {
|
||
if (current.tagName === 'BLOCKQUOTE' || (current.classList && current.classList.contains('quote-content'))) return
|
||
current = current.parentElement
|
||
}
|
||
|
||
// 检查嵌套限制
|
||
if (isInListOrQuote()) return
|
||
|
||
// 创建引用容器
|
||
const quoteContainer = document.createElement('div')
|
||
quoteContainer.className = 'quote-container'
|
||
|
||
// 创建图标元素
|
||
const icon = document.createElement('img')
|
||
icon.className = 'quote-icon'
|
||
icon.src = '/assets/icons/drawable-xxhdpi/rag_quote.png'
|
||
icon.alt = '引用'
|
||
|
||
// 创建内容容器
|
||
const contentSpan = document.createElement('blockquote')
|
||
contentSpan.className = 'quote-content'
|
||
contentSpan.textContent = '引用内容'
|
||
|
||
// 组装元素
|
||
quoteContainer.appendChild(icon)
|
||
quoteContainer.appendChild(contentSpan)
|
||
|
||
// 插入到当前光标位置
|
||
range.insertNode(quoteContainer)
|
||
|
||
// 添加换行
|
||
const br = document.createElement('br')
|
||
quoteContainer.parentNode.insertBefore(br, quoteContainer.nextSibling)
|
||
|
||
// 聚焦到内容区域
|
||
const newRange = document.createRange()
|
||
newRange.selectNodeContents(contentSpan)
|
||
newRange.collapse(false)
|
||
selection.removeAllRanges()
|
||
selection.addRange(newRange)
|
||
|
||
// 添加事件监听器到内容区域,监听内容变化
|
||
const checkContent = () => {
|
||
// 延迟检查,确保内容已更新
|
||
setTimeout(() => {
|
||
if (contentSpan.textContent.trim() === '') {
|
||
// 如果内容为空,移除整个引用容器
|
||
quoteContainer.remove()
|
||
handleInput()
|
||
}
|
||
}, 0)
|
||
}
|
||
|
||
contentSpan.addEventListener('input', checkContent)
|
||
contentSpan.addEventListener('blur', checkContent)
|
||
|
||
handleInput()
|
||
}
|
||
}
|
||
|
||
// 插入待办事项列表
|
||
const insertTodoList = () => {
|
||
const selection = window.getSelection()
|
||
if (selection.rangeCount > 0) {
|
||
const range = selection.getRangeAt(0)
|
||
|
||
// 检查嵌套限制
|
||
if (isInListOrQuote()) return
|
||
|
||
// 创建待办事项容器
|
||
const todoContainer = document.createElement('div')
|
||
todoContainer.contentEditable = false
|
||
todoContainer.className = 'todo-container'
|
||
|
||
// 创建图标元素
|
||
const icon = document.createElement('img')
|
||
icon.className = 'todo-icon'
|
||
icon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||
icon.alt = '待办事项'
|
||
|
||
// 创建内容容器
|
||
const contentSpan = document.createElement('span')
|
||
contentSpan.contentEditable = true
|
||
contentSpan.className = 'todo-content'
|
||
contentSpan.textContent = '待办事项'
|
||
|
||
// 组装元素
|
||
todoContainer.appendChild(icon)
|
||
todoContainer.appendChild(contentSpan)
|
||
|
||
// 插入到当前光标位置
|
||
range.insertNode(todoContainer)
|
||
|
||
// 添加换行
|
||
const br = document.createElement('br')
|
||
todoContainer.parentNode.insertBefore(br, todoContainer.nextSibling)
|
||
|
||
// 聚焦到内容区域
|
||
const newRange = document.createRange()
|
||
newRange.selectNodeContents(contentSpan)
|
||
newRange.collapse(false)
|
||
selection.removeAllRanges()
|
||
selection.addRange(newRange)
|
||
|
||
// 添加事件监听器到图标
|
||
icon.addEventListener('click', function () {
|
||
// 根据当前状态切换图标
|
||
if (this.src.includes('rtf_icon_gtasks.png')) {
|
||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png'
|
||
contentSpan.style.color = 'var(--text-tertiary)'
|
||
contentSpan.style.textDecoration = 'line-through'
|
||
} else {
|
||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||
contentSpan.style.color = 'var(--note-content)'
|
||
contentSpan.style.textDecoration = 'none'
|
||
}
|
||
handleInput()
|
||
})
|
||
|
||
// 添加事件监听器到内容区域,监听内容变化和按键事件
|
||
const checkContent = () => {
|
||
// 延迟检查,确保内容已更新
|
||
setTimeout(() => {
|
||
if (contentSpan.textContent.trim() === '') {
|
||
// 如果内容为空,移除整个待办事项容器
|
||
todoContainer.remove()
|
||
handleInput()
|
||
}
|
||
}, 0)
|
||
}
|
||
|
||
contentSpan.addEventListener('input', checkContent)
|
||
contentSpan.addEventListener('blur', checkContent)
|
||
|
||
// 监听回车键,创建同级待办事项
|
||
contentSpan.addEventListener('keydown', e => {
|
||
if (e.key === 'Enter') {
|
||
e.preventDefault()
|
||
|
||
// 创建新的待办事项
|
||
const newTodoContainer = document.createElement('div')
|
||
newTodoContainer.contentEditable = false
|
||
newTodoContainer.className = 'todo-container'
|
||
|
||
// 创建图标元素
|
||
const newIcon = document.createElement('img')
|
||
newIcon.className = 'todo-icon'
|
||
newIcon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||
newIcon.alt = '待办事项'
|
||
|
||
// 创建内容容器
|
||
const newContentSpan = document.createElement('span')
|
||
newContentSpan.contentEditable = true
|
||
newContentSpan.className = 'todo-content'
|
||
newContentSpan.textContent = ''
|
||
|
||
// 组装元素
|
||
newTodoContainer.appendChild(newIcon)
|
||
newTodoContainer.appendChild(newContentSpan)
|
||
|
||
// 插入到当前待办事项后面
|
||
todoContainer.parentNode.insertBefore(newTodoContainer, todoContainer.nextSibling)
|
||
|
||
// 添加换行
|
||
const newBr = document.createElement('br')
|
||
newTodoContainer.parentNode.insertBefore(newBr, newTodoContainer.nextSibling)
|
||
|
||
// 聚焦到新内容区域
|
||
const newRange = document.createRange()
|
||
newRange.selectNodeContents(newContentSpan)
|
||
newRange.collapse(false)
|
||
selection.removeAllRanges()
|
||
selection.addRange(newRange)
|
||
|
||
// 添加事件监听器到新图标
|
||
newIcon.addEventListener('click', function () {
|
||
// 根据当前状态切换图标
|
||
if (this.src.includes('rtf_icon_gtasks.png')) {
|
||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png'
|
||
newContentSpan.style.color = 'var(--text-tertiary)'
|
||
newContentSpan.style.textDecoration = 'line-through'
|
||
} else {
|
||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||
newContentSpan.style.color = 'var(--note-content)'
|
||
newContentSpan.style.textDecoration = 'none'
|
||
}
|
||
handleInput()
|
||
})
|
||
|
||
// 添加事件监听器到新内容区域
|
||
const newCheckContent = () => {
|
||
setTimeout(() => {
|
||
if (newContentSpan.textContent.trim() === '') {
|
||
newTodoContainer.remove()
|
||
handleInput()
|
||
}
|
||
}, 0)
|
||
}
|
||
|
||
newContentSpan.addEventListener('input', newCheckContent)
|
||
newContentSpan.addEventListener('blur', newCheckContent)
|
||
|
||
// 监听新内容区域的回车键
|
||
newContentSpan.addEventListener('keydown', e => {
|
||
if (e.key === 'Enter') {
|
||
e.preventDefault()
|
||
|
||
// 创建新的待办事项
|
||
const nextTodoContainer = document.createElement('div')
|
||
nextTodoContainer.contentEditable = false
|
||
nextTodoContainer.className = 'todo-container'
|
||
|
||
// 创建图标元素
|
||
const nextIcon = document.createElement('img')
|
||
nextIcon.className = 'todo-icon'
|
||
nextIcon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||
nextIcon.alt = '待办事项'
|
||
|
||
// 创建内容容器
|
||
const nextContentSpan = document.createElement('span')
|
||
nextContentSpan.contentEditable = true
|
||
nextContentSpan.className = 'todo-content'
|
||
nextContentSpan.textContent = ''
|
||
|
||
// 组装元素
|
||
nextTodoContainer.appendChild(nextIcon)
|
||
nextTodoContainer.appendChild(nextContentSpan)
|
||
|
||
// 插入到当前待办事项后面
|
||
newTodoContainer.parentNode.insertBefore(nextTodoContainer, newTodoContainer.nextSibling)
|
||
|
||
// 添加换行
|
||
const nextBr = document.createElement('br')
|
||
nextTodoContainer.parentNode.insertBefore(nextBr, nextTodoContainer.nextSibling)
|
||
|
||
// 聚焦到新内容区域
|
||
const nextRange = document.createRange()
|
||
nextRange.selectNodeContents(nextContentSpan)
|
||
nextRange.collapse(false)
|
||
selection.removeAllRanges()
|
||
selection.addRange(nextRange)
|
||
|
||
// 添加事件监听器到新图标
|
||
nextIcon.addEventListener('click', function () {
|
||
// 根据当前状态切换图标
|
||
if (this.src.includes('rtf_icon_gtasks.png')) {
|
||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png'
|
||
nextContentSpan.style.color = 'var(--text-tertiary)'
|
||
nextContentSpan.style.textDecoration = 'line-through'
|
||
} else {
|
||
this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png'
|
||
nextContentSpan.style.color = 'var(--note-content)'
|
||
nextContentSpan.style.textDecoration = 'none'
|
||
}
|
||
handleInput()
|
||
})
|
||
|
||
// 添加事件监听器到新内容区域
|
||
const nextCheckContent = () => {
|
||
setTimeout(() => {
|
||
if (nextContentSpan.textContent.trim() === '') {
|
||
nextTodoContainer.remove()
|
||
handleInput()
|
||
}
|
||
}, 0)
|
||
}
|
||
|
||
nextContentSpan.addEventListener('input', nextCheckContent)
|
||
nextContentSpan.addEventListener('blur', nextCheckContent)
|
||
|
||
handleInput()
|
||
}
|
||
})
|
||
|
||
handleInput()
|
||
}
|
||
})
|
||
|
||
handleInput()
|
||
}
|
||
}
|
||
|
||
// 处理输入事件
|
||
const handleInput = () => {
|
||
if (editorRef.value) {
|
||
content.value = editorRef.value.innerHTML
|
||
emit('update:modelValue', content.value)
|
||
}
|
||
}
|
||
|
||
// 处理键盘事件
|
||
const handleKeydown = e => {
|
||
// 处理Shift+Enter键换行
|
||
if (e.key === 'Enter' && e.shiftKey) {
|
||
e.preventDefault()
|
||
document.execCommand('insertHTML', false, '<br><br>')
|
||
handleInput()
|
||
return
|
||
}
|
||
|
||
// 处理Tab键缩进
|
||
if (e.key === 'Tab') {
|
||
e.preventDefault()
|
||
document.execCommand('insertHTML', false, ' ')
|
||
handleInput()
|
||
return
|
||
}
|
||
|
||
// 处理回车键创建新列表项
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
// 检查是否在列表中
|
||
const selection = window.getSelection()
|
||
if (selection.rangeCount > 0) {
|
||
const range = selection.getRangeAt(0)
|
||
const container = range.startContainer
|
||
|
||
// 检查是否在ul或ol内
|
||
let listElement = null
|
||
let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container
|
||
|
||
while (current && current !== editorRef.value) {
|
||
if (current.tagName === 'LI') {
|
||
listElement = current
|
||
break
|
||
}
|
||
current = current.parentElement
|
||
}
|
||
|
||
// 如果在列表项中且为空,退出列表
|
||
if (listElement) {
|
||
const liContent = listElement.textContent.trim()
|
||
if (liContent === '') {
|
||
e.preventDefault()
|
||
// 退出列表
|
||
document.execCommand('outdent')
|
||
handleInput()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新工具栏状态
|
||
const updateToolbarState = () => {
|
||
nextTick(() => {
|
||
tools.value.forEach(tool => {
|
||
if (tool.name === 'bold') {
|
||
tool.active = document.queryCommandState('bold')
|
||
} else if (tool.name === 'center') {
|
||
tool.active = document.queryCommandState('justifyCenter')
|
||
} else if (tool.name === 'list') {
|
||
tool.active = document.queryCommandState('insertUnorderedList')
|
||
} else if (tool.name === 'quote') {
|
||
tool.active = document.queryCommandState('formatBlock')
|
||
} else if (tool.name === 'header') {
|
||
tool.active = document.queryCommandState('formatBlock')
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 初始化编辑器内容
|
||
onMounted(() => {
|
||
if (editorRef.value) {
|
||
editorRef.value.innerHTML = content.value
|
||
}
|
||
})
|
||
|
||
// 监听外部值变化
|
||
defineExpose({
|
||
getContent: () => content.value,
|
||
setContent: newContent => {
|
||
content.value = newContent
|
||
if (editorRef.value) {
|
||
editorRef.value.innerHTML = newContent
|
||
}
|
||
},
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.editor-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
background-color: var(--background-card);
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||
}
|
||
|
||
.toolbar {
|
||
display: flex;
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
background-color: var(--background-card);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.toolbar-btn {
|
||
padding: 6px;
|
||
margin-right: 6px;
|
||
border: none;
|
||
background: transparent;
|
||
cursor: pointer;
|
||
border-radius: 4px;
|
||
transition: background-color 0.2s ease;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.toolbar-btn:hover {
|
||
background-color: var(--background-secondary);
|
||
}
|
||
|
||
.toolbar-btn.active {
|
||
background-color: var(--primary-light);
|
||
border: 1px solid var(--border);
|
||
}
|
||
|
||
.toolbar-icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.toolbar-btn.active .toolbar-icon {
|
||
opacity: 1;
|
||
}
|
||
|
||
.editor-content {
|
||
flex: 1;
|
||
padding: 20px 16px;
|
||
outline: none;
|
||
overflow-y: auto;
|
||
font-size: 16px;
|
||
line-height: 1.6;
|
||
color: var(--note-content);
|
||
min-height: 200px;
|
||
background-color: var(--background-card);
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||
}
|
||
|
||
.editor-content:focus,
|
||
.editor-content * {
|
||
outline: none;
|
||
}
|
||
|
||
/* 自定义内容样式 */
|
||
:deep(.editor-content h2) {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
margin: 8px 0 8px 0;
|
||
color: var(--note-title);
|
||
line-height: 1.4;
|
||
letter-spacing: 0.5px;
|
||
text-align: center;
|
||
position: relative;
|
||
}
|
||
|
||
:deep(.editor-content blockquote) {
|
||
border-left: 3px solid var(--primary);
|
||
padding-left: 16px;
|
||
margin: 16px 0;
|
||
color: var(--text-secondary);
|
||
background-color: var(--background-secondary);
|
||
padding: 8px 16px 8px 16px;
|
||
border-radius: 0 4px 4px 0;
|
||
font-style: italic;
|
||
}
|
||
|
||
:deep(.quote-container) {
|
||
position: relative;
|
||
margin: 16px 0;
|
||
}
|
||
|
||
:deep(.quote-icon) {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 10px;
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
:deep(.quote-content) {
|
||
border-left: 3px solid var(--primary);
|
||
padding-left: 32px;
|
||
margin-left: 16px;
|
||
color: var(--text-secondary);
|
||
background-color: var(--background-secondary);
|
||
padding: 8px 16px 8px 16px;
|
||
border-radius: 0 4px 4px 0;
|
||
font-style: italic;
|
||
}
|
||
|
||
:deep(.editor-content ul),
|
||
:deep(.editor-content ol) {
|
||
margin: 16px 0;
|
||
padding-left: 32px;
|
||
position: relative;
|
||
}
|
||
|
||
:deep(.editor-content li) {
|
||
margin: 6px 0;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
:deep(.editor-content p) {
|
||
margin: 0 0 12px 0;
|
||
line-height: 1.6;
|
||
letter-spacing: 0.3px;
|
||
}
|
||
|
||
:deep(.editor-content strong) {
|
||
color: var(--text-primary);
|
||
font-weight: 600;
|
||
}
|
||
|
||
:deep(.editor-content em) {
|
||
color: var(--text-secondary);
|
||
font-style: italic;
|
||
}
|
||
|
||
:deep(.editor-content u) {
|
||
text-decoration: none;
|
||
border-bottom: 1px solid var(--text-primary);
|
||
}
|
||
|
||
:deep(.editor-content hr) {
|
||
border: none;
|
||
height: 1px;
|
||
background-color: var(--border);
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.editor-content div[style*='text-align: center'] {
|
||
text-align: center;
|
||
}
|
||
|
||
/* 待办事项样式 */
|
||
:deep(.todo-container) {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin: 0.1rem 0;
|
||
padding: 0.02rem 0;
|
||
position: relative;
|
||
padding-left: 1.2rem;
|
||
}
|
||
|
||
:deep(.todo-icon) {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 2rem;
|
||
height: 2rem;
|
||
cursor: pointer;
|
||
}
|
||
|
||
:deep(.todo-content) {
|
||
flex: 1;
|
||
outline: none;
|
||
padding: 0.125rem 0.25rem;
|
||
min-height: 1.25rem;
|
||
border-radius: 0.125rem;
|
||
color: var(--note-content);
|
||
margin-left: 0.5rem;
|
||
}
|
||
|
||
/* 引用格式样式 */
|
||
:deep(.quote-container) {
|
||
position: relative;
|
||
margin: 1rem 0;
|
||
}
|
||
|
||
:deep(.quote-icon) {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0.625rem;
|
||
width: 1rem;
|
||
height: 1rem;
|
||
}
|
||
|
||
:deep(.quote-content) {
|
||
border-left: 0.1875rem solid var(--primary);
|
||
padding-left: 2rem;
|
||
margin-left: 1.5rem;
|
||
color: var(--text-secondary);
|
||
background-color: var(--background-secondary);
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 0 0.25rem 0.25rem 0;
|
||
font-style: italic;
|
||
}
|
||
</style>
|