작성 줄 삭제 단축키 복구
This commit is contained in:
@@ -1123,6 +1123,27 @@ const transformSelectedLines = (transformLine) => {
|
||||
setTextareaSelection(lineStart, lineStart + replacement.length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 소스 모드에서 현재 선택 범위가 걸친 줄을 삭제한다.
|
||||
* @returns {void}
|
||||
*/
|
||||
const deleteSelectedSourceLines = () => {
|
||||
const { start, end, value } = getSelectionState()
|
||||
const safeStart = Math.min(start, end)
|
||||
const safeEnd = Math.max(start, end)
|
||||
const lineStart = value.lastIndexOf('\n', Math.max(0, safeStart - 1)) + 1
|
||||
const nextLineBreak = value.indexOf('\n', safeEnd)
|
||||
const lineEnd = nextLineBreak === -1 ? value.length : nextLineBreak + 1
|
||||
const previousLineBreak = value.lastIndexOf('\n', Math.max(0, lineStart - 2))
|
||||
const nextValue = `${value.slice(0, lineStart)}${value.slice(lineEnd)}`
|
||||
const nextSelection = lineStart > 0
|
||||
? previousLineBreak + 1
|
||||
: 0
|
||||
|
||||
markdownValue.value = nextValue
|
||||
setTextareaSelection(Math.min(nextSelection, nextValue.length))
|
||||
}
|
||||
|
||||
/**
|
||||
* 제목 마크다운을 적용한다.
|
||||
* @param {number} level - 제목 레벨
|
||||
@@ -1685,6 +1706,37 @@ const onPreviewDeleteLine = (lineIndex) => {
|
||||
markdownValue.value = nextLines.length ? nextLines.join('\n') : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 라이브 모드 미리보기 루트 단축키를 처리한다.
|
||||
* @param {KeyboardEvent} event - 키보드 이벤트
|
||||
* @returns {void}
|
||||
*/
|
||||
const handlePreviewKeydownCapture = (event) => {
|
||||
const isDeleteShortcut = (event.metaKey || event.ctrlKey)
|
||||
&& event.shiftKey
|
||||
&& event.key.toLowerCase() === 'k'
|
||||
|
||||
if (!isDeleteShortcut) {
|
||||
return
|
||||
}
|
||||
|
||||
const target = event.target
|
||||
|
||||
if (target instanceof HTMLElement && target.closest('[contenteditable="true"]')) {
|
||||
return
|
||||
}
|
||||
|
||||
const lineIndex = getCurrentPreviewSourceLine()
|
||||
|
||||
if (typeof lineIndex !== 'number' || lineIndex < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
onPreviewDeleteLine(lineIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* 라이브 모드 이미지 설정 패널을 연다.
|
||||
* @param {number} lineIndex - 이미지 원본 줄 번호(0-based)
|
||||
@@ -2763,7 +2815,11 @@ const handleKeydown = (event) => {
|
||||
|
||||
const key = event.key.toLowerCase()
|
||||
|
||||
if (key === 'b') {
|
||||
if (event.shiftKey && key === 'k') {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
deleteSelectedSourceLines()
|
||||
} else if (key === 'b') {
|
||||
event.preventDefault()
|
||||
wrapInline('**', '**', '굵은 글씨')
|
||||
} else if (key === 'i') {
|
||||
@@ -2869,6 +2925,7 @@ const handleKeydown = (event) => {
|
||||
class="admin-markdown-editor__preview min-h-[620px] px-0 py-5 text-[#15171a] outline-none"
|
||||
style="--site-text: #15171a; --site-muted: #6b7280; --site-panel: #f6f7f8; --site-line: #e3e6e8; --site-accent: #2eb6ea;"
|
||||
tabindex="0"
|
||||
@keydown.capture="handlePreviewKeydownCapture"
|
||||
>
|
||||
<ContentMarkdownRenderer
|
||||
ref="previewRendererRef"
|
||||
|
||||
@@ -48,7 +48,7 @@ const backgroundClass = computed(() => {
|
||||
class="prose-callout prose-callout-card mb-2.5 rounded-[10px] p-5 text-[15px] leading-8 text-[var(--site-text)]"
|
||||
:class="backgroundClass"
|
||||
>
|
||||
<div v-if="emojiEnabled || title" class="prose-callout-card__header mb-4 flex items-start gap-2">
|
||||
<div v-if="emojiEnabled || title" class="prose-callout-card__header mb-2.5 flex items-start gap-2">
|
||||
<span v-if="emojiEnabled" class="prose-callout-card__emoji inline-flex shrink-0 pt-0.5 text-[20px] leading-none">{{ emoji || '💡' }}</span>
|
||||
<strong v-if="title" class="prose-callout-card__title min-w-0 text-[18px] leading-[1.35] font-bold text-[#050505]">
|
||||
{{ title }}
|
||||
|
||||
Reference in New Issue
Block a user