블록 설정 패널 확장 v1.5.37
This commit is contained in:
@@ -19,7 +19,7 @@ import {
|
||||
stripQuoteMarker
|
||||
} from '../../lib/markdown-live-edit.js'
|
||||
import { buildCodeBlockLines, parseCodeFenceLine } from '../../lib/markdown-code-block.js'
|
||||
import { buildToggleBlockLines } from '../../lib/markdown-toggle.js'
|
||||
import { buildToggleBlockLines, parseToggleOpenerLine } from '../../lib/markdown-toggle.js'
|
||||
import { CALLOUT_BACKGROUND_OPTIONS, parseCalloutOptions } from '../../lib/markdown-callout.js'
|
||||
import { createHeadingIdFactory } from '../../lib/markdown-toc.js'
|
||||
import ContentMarkdownCodeBlockEditor from './ContentMarkdownCodeBlockEditor.vue'
|
||||
@@ -566,9 +566,9 @@ const parseMarkdownBlocks = (markdown) => {
|
||||
if (trimmedLine.startsWith(':::toggle')) {
|
||||
const startLine = index
|
||||
const { contentLines, nextIndex } = collectFencedLines(lines, index + 1)
|
||||
const title = trimmedLine.replace(/^:::toggle\s*/, '').trim()
|
||||
const toggleOptions = parseToggleOpenerLine(trimmedLine)
|
||||
blocks.push(attachSourceRange(
|
||||
createBlock('toggle', contentLines.join('\n'), null, `block-${blocks.length}`, { title }),
|
||||
createBlock('toggle', contentLines.join('\n'), null, `block-${blocks.length}`, toggleOptions),
|
||||
startLine,
|
||||
nextIndex
|
||||
))
|
||||
@@ -1245,6 +1245,7 @@ const onToggleBlockInsertBelow = (block, payload) => {
|
||||
|
||||
onToggleBlockCommit(block, buildToggleBlockLines({
|
||||
title: block.title,
|
||||
defaultOpen: block.defaultOpen,
|
||||
body: value
|
||||
}))
|
||||
pendingFocusPosition.value = 'start'
|
||||
@@ -2517,13 +2518,14 @@ onBeforeUnmount(() => {
|
||||
<ContentMarkdownToggleEditor
|
||||
v-else-if="block.type === 'toggle' && interactive"
|
||||
:title="block.title"
|
||||
:default-open="block.defaultOpen"
|
||||
:title-source-line="block.meta.startLine"
|
||||
:body-source-line="block.meta.startLine + 1"
|
||||
:model-value="block.text"
|
||||
@commit="onToggleBlockCommit(block, $event)"
|
||||
@insert-below="onToggleBlockInsertBelow(block, $event)"
|
||||
/>
|
||||
<ProseToggle v-else-if="block.type === 'toggle'" :title="block.title || '더 보기'" animated>
|
||||
<ProseToggle v-else-if="block.type === 'toggle'" :title="block.title || '더 보기'" :default-open="block.defaultOpen" animated>
|
||||
<template v-for="(segment, segmentIndex) in parseInlineSegments(block.text)" :key="`${block.id}-toggle-${segmentIndex}`">
|
||||
<strong v-if="segment.type === 'strong'">{{ segment.text }}</strong>
|
||||
<em v-else-if="segment.type === 'em'">{{ segment.text }}</em>
|
||||
|
||||
@@ -14,6 +14,11 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 기본 펼침 여부 */
|
||||
defaultOpen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 선언 줄 source-line(0-based) */
|
||||
titleSourceLine: {
|
||||
type: Number,
|
||||
@@ -44,7 +49,8 @@ watch(() => props.title, (value) => {
|
||||
const commitToggle = (options = {}) => {
|
||||
emit('commit', buildToggleBlockLines({
|
||||
title: options.title ?? titleDraft.value,
|
||||
body: options.body ?? props.modelValue
|
||||
body: options.body ?? props.modelValue,
|
||||
defaultOpen: options.defaultOpen ?? props.defaultOpen
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -104,7 +110,7 @@ const onExitBelow = (payload) => {
|
||||
class="content-markdown-toggle-editor"
|
||||
data-editable-scope
|
||||
:title="titleDraft"
|
||||
default-open
|
||||
:default-open="true"
|
||||
animated
|
||||
>
|
||||
<template #title>
|
||||
|
||||
@@ -28,11 +28,24 @@ const props = defineProps({
|
||||
*/
|
||||
const isSafeFileUrl = computed(() => Boolean(props.href && (props.href.startsWith('/') || /^https?:\/\//i.test(props.href))))
|
||||
|
||||
/**
|
||||
* 파일 확장자를 제거한 표시명을 반환한다.
|
||||
* @param {string} filename - 파일명
|
||||
* @returns {string} 확장자를 제외한 이름
|
||||
*/
|
||||
const stripFileExtension = (filename) => String(filename || '').replace(/\.[^.]+$/, '')
|
||||
|
||||
/**
|
||||
* 카드 제목을 반환한다.
|
||||
* @returns {string} 제목
|
||||
*/
|
||||
const displayTitle = computed(() => props.title || props.fileName || 'File')
|
||||
const displayTitle = computed(() => {
|
||||
if (props.fileName && (!props.title || props.title === stripFileExtension(props.fileName))) {
|
||||
return props.fileName
|
||||
}
|
||||
|
||||
return props.title || props.fileName || 'File'
|
||||
})
|
||||
|
||||
/**
|
||||
* 표시 파일명을 반환한다.
|
||||
@@ -51,6 +64,25 @@ const displayFileName = computed(() => {
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 파일 카드 보조 정보를 반환한다.
|
||||
* @returns {string} 보조 정보
|
||||
*/
|
||||
const displayMeta = computed(() => {
|
||||
const title = String(displayTitle.value || '').trim()
|
||||
const fileName = String(displayFileName.value || '').trim()
|
||||
|
||||
if (title && fileName && title === fileName) {
|
||||
return props.size || ''
|
||||
}
|
||||
|
||||
if (fileName) {
|
||||
return props.size ? `${fileName} · ${props.size}` : fileName
|
||||
}
|
||||
|
||||
return props.size || props.href
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -67,8 +99,8 @@ const displayFileName = computed(() => {
|
||||
<span v-if="description" class="prose-file__description mt-1 block text-sm leading-relaxed text-[var(--site-muted)]">
|
||||
{{ description }}
|
||||
</span>
|
||||
<span class="prose-file__meta mt-3 block truncate text-sm font-semibold text-[var(--site-text)]">
|
||||
{{ displayFileName || href }}<template v-if="size"> · {{ size }}</template>
|
||||
<span v-if="displayMeta" class="prose-file__meta mt-3 block truncate text-sm font-semibold text-[var(--site-text)]">
|
||||
{{ displayMeta }}
|
||||
</span>
|
||||
</span>
|
||||
<span class="prose-file__download flex h-20 w-20 shrink-0 items-center justify-center rounded-[6px] bg-[color-mix(in_srgb,var(--site-line)_36%,var(--site-panel))] text-[var(--site-accent)] transition-transform group-hover:scale-[1.02] sm:h-[86px] sm:w-[86px]">
|
||||
|
||||
Reference in New Issue
Block a user