작성 줄 삭제 단축키 복구

This commit is contained in:
2026-06-04 15:54:37 +09:00
parent 94226423c7
commit 264f551cb4
9 changed files with 83 additions and 8 deletions

View File

@@ -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"

View File

@@ -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 }}