글쓰기 문단 입력과 편집 영역 정리
This commit is contained in:
@@ -391,17 +391,21 @@ const replaceSelection = (replacement, cursorOffset = replacement.length, select
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter 입력을 문단 분리 규칙에 맞게 처리한다.
|
* Enter 입력을 문단/줄바꿈 규칙에 맞게 처리한다.
|
||||||
* @param {KeyboardEvent} event - 키보드 이벤트
|
* @param {KeyboardEvent} event - 키보드 이벤트
|
||||||
* @returns {boolean} 직접 처리했는지 여부
|
* @returns {boolean} 직접 처리했는지 여부
|
||||||
*/
|
*/
|
||||||
const handleParagraphEnter = (event) => {
|
const handleParagraphEnter = (event) => {
|
||||||
if (event.key !== 'Enter' || event.shiftKey || event.metaKey || event.ctrlKey || event.altKey || event.isComposing) {
|
if (event.key !== 'Enter' || event.metaKey || event.ctrlKey || event.altKey || event.isComposing) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event.shiftKey) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
replaceSelection('\n\n')
|
replaceSelection(' \n')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1069,18 +1073,17 @@ const handleKeydown = (event) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="activeMode === 'write'" class="admin-markdown-editor__write relative">
|
<div v-if="activeMode === 'write'" class="admin-markdown-editor__write relative pl-12">
|
||||||
<div class="admin-markdown-editor__editor-surface flex min-h-[620px] overflow-hidden rounded border border-[#e3e6e8] bg-white">
|
<div class="admin-markdown-editor__editor-surface min-h-[620px]">
|
||||||
<div
|
<div
|
||||||
ref="gutterRef"
|
ref="gutterRef"
|
||||||
class="admin-markdown-editor__gutter min-w-[2.75rem] shrink-0 select-none overflow-y-auto overflow-x-hidden border-r border-[#e3e6e8] bg-[#f6f7f8] py-5 font-mono text-[13px] leading-7 text-[#8e9cac]"
|
class="admin-markdown-editor__gutter absolute bottom-0 left-0 top-0 w-10 select-none overflow-y-auto overflow-x-hidden py-5 font-mono text-[13px] leading-7 text-[#a0a8b0]"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="ln in gutterLineCount"
|
v-for="ln in gutterLineCount"
|
||||||
:key="`gutter-line-${ln}`"
|
:key="`gutter-line-${ln}`"
|
||||||
class="admin-markdown-editor__gutter-line min-h-[28px] pr-2 text-right tabular-nums"
|
class="admin-markdown-editor__gutter-line min-h-[28px] pr-2 text-right tabular-nums"
|
||||||
:class="{ 'admin-markdown-editor__gutter-line--active': ln - 1 === activeLogicalLineIndex }"
|
|
||||||
>
|
>
|
||||||
{{ ln }}
|
{{ ln }}
|
||||||
</div>
|
</div>
|
||||||
@@ -1088,7 +1091,7 @@ const handleKeydown = (event) => {
|
|||||||
<textarea
|
<textarea
|
||||||
ref="textareaRef"
|
ref="textareaRef"
|
||||||
v-model="markdownValue"
|
v-model="markdownValue"
|
||||||
class="admin-markdown-editor__textarea min-h-[620px] flex-1 resize-y border-0 bg-transparent py-5 pl-2 pr-5 font-mono text-[15px] leading-7 text-[#15171a] outline-none transition-colors placeholder:text-[#8e9cac] focus:ring-0"
|
class="admin-markdown-editor__textarea min-h-[620px] w-full resize-y border-0 bg-transparent py-5 pl-0 pr-5 font-mono text-[15px] leading-7 text-[#15171a] outline-none transition-colors placeholder:text-[#8e9cac] focus:ring-0"
|
||||||
placeholder="마크다운으로 글을 작성하세요."
|
placeholder="마크다운으로 글을 작성하세요."
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
@keydown="handleKeydown"
|
@keydown="handleKeydown"
|
||||||
@@ -1272,11 +1275,3 @@ const handleKeydown = (event) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.admin-markdown-editor__gutter-line--active {
|
|
||||||
background-color: rgba(46, 182, 234, 0.16);
|
|
||||||
color: #15171a;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -124,6 +124,20 @@ const isMarkdownBlockStart = (line) => {
|
|||||||
Boolean(parseImageLine(trimmedLine))
|
Boolean(parseImageLine(trimmedLine))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 마크다운 hard break 표식이 있는 행인지 확인한다.
|
||||||
|
* @param {string} line - 마크다운 행
|
||||||
|
* @returns {boolean} hard break 여부
|
||||||
|
*/
|
||||||
|
const hasMarkdownHardBreak = (line) => / {2,}$/.test(line)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 문단 행에서 hard break 표식을 제거한다.
|
||||||
|
* @param {string} line - 마크다운 행
|
||||||
|
* @returns {string} 정리된 문단 행
|
||||||
|
*/
|
||||||
|
const cleanParagraphLine = (line) => line.replace(/ {2,}$/, '').trim()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 닫힘 표식까지의 행 목록을 반환
|
* 닫힘 표식까지의 행 목록을 반환
|
||||||
* @param {Array<string>} lines - 전체 마크다운 행
|
* @param {Array<string>} lines - 전체 마크다운 행
|
||||||
@@ -398,10 +412,11 @@ const parseMarkdownBlocks = (markdown) => {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const paragraphLines = [trimmedLine]
|
const paragraphLines = [cleanParagraphLine(line)]
|
||||||
|
let shouldJoinNextLine = hasMarkdownHardBreak(line)
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
while (index < lines.length) {
|
while (shouldJoinNextLine && index < lines.length) {
|
||||||
const nextLine = lines[index]
|
const nextLine = lines[index]
|
||||||
const nextTrimmedLine = nextLine.trim()
|
const nextTrimmedLine = nextLine.trim()
|
||||||
|
|
||||||
@@ -409,7 +424,8 @@ const parseMarkdownBlocks = (markdown) => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
paragraphLines.push(nextTrimmedLine)
|
paragraphLines.push(cleanParagraphLine(nextLine))
|
||||||
|
shouldJoinNextLine = hasMarkdownHardBreak(nextLine)
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,7 +632,7 @@ const showNextImage = () => {
|
|||||||
class="content-markdown-renderer__code my-6 overflow-x-auto rounded bg-[#15171a] px-4 py-3 text-sm leading-6 text-white"
|
class="content-markdown-renderer__code my-6 overflow-x-auto rounded bg-[#15171a] px-4 py-3 text-sm leading-6 text-white"
|
||||||
><code>{{ block.text }}</code></pre>
|
><code>{{ block.text }}</code></pre>
|
||||||
<hr v-else-if="block.type === 'divider'" class="content-markdown-renderer__divider my-10 border-line">
|
<hr v-else-if="block.type === 'divider'" class="content-markdown-renderer__divider my-10 border-line">
|
||||||
<p v-else class="content-markdown-renderer__paragraph mb-6 text-[15px] leading-8 text-[var(--site-text)] last:mb-0">
|
<p v-else class="content-markdown-renderer__paragraph mb-2.5 text-[15px] leading-8 text-[var(--site-text)] last:mb-0">
|
||||||
<template v-for="(lineSegments, lineIndex) in parseInlineSegmentLines(block.text)" :key="`${block.id}-paragraph-line-${lineIndex}`">
|
<template v-for="(lineSegments, lineIndex) in parseInlineSegmentLines(block.text)" :key="`${block.id}-paragraph-line-${lineIndex}`">
|
||||||
<br v-if="lineIndex > 0">
|
<br v-if="lineIndex > 0">
|
||||||
<template v-for="(segment, segmentIndex) in lineSegments" :key="`${block.id}-paragraph-${lineIndex}-${segmentIndex}`">
|
<template v-for="(segment, segmentIndex) in lineSegments" :key="`${block.id}-paragraph-${lineIndex}-${segmentIndex}`">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const tagName = computed(() => `h${Math.min(Math.max(props.level, 1), 6)}`)
|
|||||||
<template>
|
<template>
|
||||||
<component
|
<component
|
||||||
:is="tagName"
|
:is="tagName"
|
||||||
class="prose-heading mt-12 font-semibold leading-[1.25] tracking-normal first:mt-0"
|
class="prose-heading mb-2.5 mt-12 font-semibold leading-[1.25] tracking-normal first:mt-0"
|
||||||
:class="{
|
:class="{
|
||||||
'text-[clamp(1.35rem,1.25rem+0.35vw,1.6rem)] leading-[1.15]': level === 1,
|
'text-[clamp(1.35rem,1.25rem+0.35vw,1.6rem)] leading-[1.15]': level === 1,
|
||||||
'text-[clamp(1.2rem,1.15rem+0.3vw,1.4rem)]': level === 2,
|
'text-[clamp(1.2rem,1.15rem+0.3vw,1.4rem)]': level === 2,
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# 업데이트 요약
|
# 업데이트 요약
|
||||||
|
|
||||||
|
## v1.0.17
|
||||||
|
|
||||||
|
- 글쓰기 영역의 보더와 카드형 배경을 제거해 본문 편집 화면을 더 가볍게 정리.
|
||||||
|
- 줄 번호를 본문 바깥에 띄우고 현재 줄 액센트 배경을 제거.
|
||||||
|
- Enter는 한 줄만 내려가는 새 문단으로, Shift+Enter는 같은 문단 안 줄바꿈으로 동작하도록 조정.
|
||||||
|
- 문단과 제목 아래 기본 간격을 10px 기준으로 정리.
|
||||||
|
|
||||||
## v1.0.16
|
## v1.0.16
|
||||||
|
|
||||||
- 글쓰기에서 Enter는 새 문단, Shift+Enter는 같은 문단 안 줄바꿈으로 동작하도록 정리.
|
- 글쓰기에서 Enter는 새 문단, Shift+Enter는 같은 문단 안 줄바꿈으로 동작하도록 정리.
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
# 의사결정 이력
|
# 의사결정 이력
|
||||||
|
|
||||||
|
## 2026-05-14 v1.0.17
|
||||||
|
|
||||||
|
### textarea 기준 문단 입력 재조정
|
||||||
|
|
||||||
|
일반 Enter를 `\\n\\n`으로 저장하면 마크다운 문단 구분은 명확하지만, 작성 화면에서는 커서가 두 줄 내려가 보여 긴 글 작성 리듬이 어색해진다. textarea 기반 편집에서는 Affine처럼 일반 Enter를 단일 줄 이동의 새 문단으로 보고, Shift+Enter만 같은 문단 안 hard break로 구분하는 쪽이 더 편하다. 따라서 일반 Enter는 브라우저 기본 입력을 유지하고, Shift+Enter만 마크다운 hard break(`공백 2개 + \\n`)를 삽입한다. 렌더러는 hard break가 있는 행만 같은 문단으로 묶고, 일반 줄은 각각 10px 간격의 문단으로 렌더링한다.
|
||||||
|
|
||||||
|
### 작성 영역 카드감 축소
|
||||||
|
|
||||||
|
본문 textarea에 외곽 보더와 배경 카드가 있으면 관리자 화면의 다른 패널과 겹쳐 편집 영역이 과하게 박스처럼 보인다. 작성 영역의 보더와 배경을 제거하고, 줄 번호 거터는 본문 흐름 바깥 absolute 영역으로 분리한다. 현재 줄 강조 액센트는 제거하고 줄 번호 자체만 위치 안내로 사용한다.
|
||||||
|
|
||||||
## 2026-05-14 v1.0.16
|
## 2026-05-14 v1.0.16
|
||||||
|
|
||||||
### 문단과 줄바꿈 의미 분리
|
### 문단과 줄바꿈 의미 분리
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
|------|-----------|
|
|------|-----------|
|
||||||
| components/admin/AdminPostForm.vue | 관리자 글 작성/수정 폼, Ghost 스타일 전체 화면 에디터, 변경사항 기반 저장 버튼 활성화, 저장 클릭 시 전체 화면 발행 모달(행 접기/펼침, Ghost 동일 SVG 아이콘, 상태 요약 후 발행/초안/비공개 선택, 발행 시에만 시점 행·즉시/예약·datetime-local), 좌우 분할 설정 패널, 설정 패널 전환 애니메이션, Post URL 보기 액션, 중립 톤 삭제 액션, 대표 이미지 hover 액션과 업로드/미디어 선택 확정, 제목 IME Enter 가드, SVG 닫기 아이콘 배지형 태그 입력(한글 유지), 로컬 자동 저장(툴바 상태 옆 복원·무시), 미저장 변경사항 이탈 확인, 검색 노출 제외(noindex), 저장 시 제목·요약을 SEO 메타로 반영, 미리보기 요청 |
|
| components/admin/AdminPostForm.vue | 관리자 글 작성/수정 폼, Ghost 스타일 전체 화면 에디터, 변경사항 기반 저장 버튼 활성화, 저장 클릭 시 전체 화면 발행 모달(행 접기/펼침, Ghost 동일 SVG 아이콘, 상태 요약 후 발행/초안/비공개 선택, 발행 시에만 시점 행·즉시/예약·datetime-local), 좌우 분할 설정 패널, 설정 패널 전환 애니메이션, Post URL 보기 액션, 중립 톤 삭제 액션, 대표 이미지 hover 액션과 업로드/미디어 선택 확정, 제목 IME Enter 가드, SVG 닫기 아이콘 배지형 태그 입력(한글 유지), 로컬 자동 저장(툴바 상태 옆 복원·무시), 미저장 변경사항 이탈 확인, 검색 노출 제외(noindex), 저장 시 제목·요약을 SEO 메타로 반영, 미리보기 요청 |
|
||||||
| components/admin/AdminPageForm.vue | 관리자 페이지 작성/수정 폼, 대표 이미지 선택 |
|
| components/admin/AdminPageForm.vue | 관리자 페이지 작성/수정 폼, 대표 이미지 선택 |
|
||||||
| components/admin/AdminMarkdownEditor.vue | 관리자 글 Markdown-first 에디터, textarea 기반 범위 선택·복사/붙여넣기, HTML 클립보드 마크다운 변환, Enter 새 문단·Shift+Enter 줄바꿈 입력, 작성 모드 왼쪽 논리 줄 번호 거터·현재 줄 강조·거터 스크롤 동기화, 작성/미리보기 전환(`Cmd/Ctrl+E`)과 커서 복원, 툴바 마크다운 삽입, 이미지·갤러리 업로드 및 미디어 라이브러리 삽입, 현재 이미지·갤러리 편집 패널 |
|
| components/admin/AdminMarkdownEditor.vue | 관리자 글 Markdown-first 에디터, textarea 기반 범위 선택·복사/붙여넣기, HTML 클립보드 마크다운 변환, Enter 새 문단·Shift+Enter hard break 줄바꿈 입력, 작성 모드 왼쪽 바깥 absolute 논리 줄 번호 거터·거터 스크롤 동기화, 작성/미리보기 전환(`Cmd/Ctrl+E`)과 커서 복원, 툴바 마크다운 삽입, 이미지·갤러리 업로드 및 미디어 라이브러리 삽입, 현재 이미지·갤러리 편집 패널 |
|
||||||
| components/admin/AdminBlockEditor.vue | 관리자 글 블록형 에디터, 이미지/갤러리/콜아웃/토글/임베드 블록, 콜아웃 Emoji on/off·이모지 프리셋·배경 프리셋 선택(우측 고정 설정 패널), 갤러리 복수 미디어 선택·이미지 수별 열 배치·삽입 위치 표시 드래그 순서 변경, 한글 조합 입력 처리, Shift+Enter 줄바꿈, 코드 블록 단축 변환, AFFiNE 참고 세로 막대형 블록 핸들 선택/삭제/드래그 이동과 삽입선 표시, 하단 빈 입력 블록 유지, 본문 placeholder 표시 |
|
| components/admin/AdminBlockEditor.vue | 관리자 글 블록형 에디터, 이미지/갤러리/콜아웃/토글/임베드 블록, 콜아웃 Emoji on/off·이모지 프리셋·배경 프리셋 선택(우측 고정 설정 패널), 갤러리 복수 미디어 선택·이미지 수별 열 배치·삽입 위치 표시 드래그 순서 변경, 한글 조합 입력 처리, Shift+Enter 줄바꿈, 코드 블록 단축 변환, AFFiNE 참고 세로 막대형 블록 핸들 선택/삭제/드래그 이동과 삽입선 표시, 하단 빈 입력 블록 유지, 본문 placeholder 표시 |
|
||||||
| components/admin/AdminNavPrimaryBranch.vue | 관리자 상단 네비 트리(테이블·태그와 동일한 행 드래그 하이라이트, 하위·삭제) |
|
| components/admin/AdminNavPrimaryBranch.vue | 관리자 상단 네비 트리(테이블·태그와 동일한 행 드래그 하이라이트, 하위·삭제) |
|
||||||
| components/admin/AdminTagForm.vue | 관리자 태그 생성/수정 폼(이름/슬러그/설명/색상만 편집) |
|
| components/admin/AdminTagForm.vue | 관리자 태그 생성/수정 폼(이름/슬러그/설명/색상만 편집) |
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
| 파일 | 화면 위치 |
|
| 파일 | 화면 위치 |
|
||||||
|------|-----------|
|
|------|-----------|
|
||||||
| components/content/ContentRenderer.vue | 게시물/페이지 본문 |
|
| components/content/ContentRenderer.vue | 게시물/페이지 본문 |
|
||||||
| components/content/ContentMarkdownRenderer.vue | 마크다운 문자열 기반 본문 렌더링, 빈 줄 문단 경계·단일 줄바꿈 `<br>` 처리, 확장 블록 파싱 |
|
| components/content/ContentMarkdownRenderer.vue | 마크다운 문자열 기반 본문 렌더링, 빈 줄 문단 경계·hard break `<br>` 처리, 확장 블록 파싱 |
|
||||||
| components/content/ProseHeading.vue | h1~h6 제목 |
|
| components/content/ProseHeading.vue | h1~h6 제목 |
|
||||||
| components/content/ProseImage.vue | 본문 내 이미지 |
|
| components/content/ProseImage.vue | 본문 내 이미지 |
|
||||||
| components/content/ProseList.vue | 목록 |
|
| components/content/ProseList.vue | 목록 |
|
||||||
|
|||||||
12
docs/spec.md
12
docs/spec.md
@@ -181,11 +181,11 @@ components/content/
|
|||||||
- `:::gallery` ~ `:::` fenced block 내부에 이미지 마크다운 행을 여러 개 작성
|
- `:::gallery` ~ `:::` fenced block 내부에 이미지 마크다운 행을 여러 개 작성
|
||||||
- 렌더링: `ContentMarkdownRenderer.vue` (그리드 + 라이트박스)
|
- 렌더링: `ContentMarkdownRenderer.vue` (그리드 + 라이트박스)
|
||||||
- 문단과 줄바꿈
|
- 문단과 줄바꿈
|
||||||
- 관리자 Markdown-first 에디터에서 일반 Enter는 새 문단을 만들기 위해 빈 줄 포함 `\\n\\n`을 삽입한다.
|
- 관리자 Markdown-first 에디터에서 일반 Enter는 브라우저 기본 단일 줄 이동으로 새 문단을 만든다.
|
||||||
- Shift+Enter는 같은 문단 안 줄바꿈을 위해 단일 `\\n`을 삽입한다.
|
- Shift+Enter는 같은 문단 안 줄바꿈을 위해 마크다운 hard break(`공백 2개 + \\n`)를 삽입한다.
|
||||||
- 공개 본문 렌더러는 연속된 텍스트 줄을 하나의 문단으로 묶고 단일 줄바꿈은 `<br>`로 표시한다.
|
- 공개 본문 렌더러는 hard break가 있는 행만 같은 문단으로 묶고 `<br>`로 표시한다.
|
||||||
- 빈 줄과 레거시 빈 문단 마커(`<!--sori:blank-paragraph-->`)는 별도 간격 블록이 아니라 문단 경계로만 사용한다.
|
- 빈 줄과 레거시 빈 문단 마커(`<!--sori:blank-paragraph-->`)는 별도 간격 블록이 아니라 문단 경계로만 사용한다.
|
||||||
- 문단 하단 간격은 24px 기준으로 유지한다.
|
- 문단과 제목 하단 기본 간격은 10px 기준으로 유지한다.
|
||||||
- 카드류
|
- 카드류
|
||||||
- Callout: `:::callout` ~ `:::` (왼쪽 강조선은 `var(--site-accent)`)
|
- Callout: `:::callout` ~ `:::` (왼쪽 강조선은 `var(--site-accent)`)
|
||||||
- Toggle: `:::toggle 제목` ~ `:::`
|
- Toggle: `:::toggle 제목` ~ `:::`
|
||||||
@@ -447,11 +447,11 @@ components/content/
|
|||||||
### 관리자 글 편집
|
### 관리자 글 편집
|
||||||
|
|
||||||
- 글 작성/수정 화면은 Markdown-first 에디터(`AdminMarkdownEditor`)를 사용한다.
|
- 글 작성/수정 화면은 Markdown-first 에디터(`AdminMarkdownEditor`)를 사용한다.
|
||||||
- 작성 모드 textarea 왼쪽에 **논리 줄 번호** 거터(`\\n` 기준 줄 수, 빈 본문은 1줄)를 두고, 캐럿이 있는 줄 번호 행에 배경색으로 **활성 표시**를 한다. textarea와 거터의 세로 스크롤은 동기화한다. 한 논리 줄이 화면에서 여러 줄로 줄바꿈될 때는 옵시디언·CodeMirror처럼 시각 줄마다 번호가 늘지 않으며, 논리 줄 단위로만 맞춘다.
|
- 작성 모드 textarea 왼쪽 바깥에 **논리 줄 번호** 거터(`\\n` 기준 줄 수, 빈 본문은 1줄)를 absolute 영역으로 두고 textarea와 거터의 세로 스크롤을 동기화한다. 한 논리 줄이 화면에서 여러 줄로 줄바꿈될 때는 옵시디언·CodeMirror처럼 시각 줄마다 번호가 늘지 않으며, 논리 줄 단위로만 맞춘다.
|
||||||
- 저장 데이터는 기존 `content` 필드의 마크다운 문자열을 그대로 유지한다.
|
- 저장 데이터는 기존 `content` 필드의 마크다운 문자열을 그대로 유지한다.
|
||||||
- 관리자 게시물/페이지 저장 API는 레거시 블록 배열·객체 본문 값이 들어와도 마크다운 문자열로 정규화한 뒤 저장한다.
|
- 관리자 게시물/페이지 저장 API는 레거시 블록 배열·객체 본문 값이 들어와도 마크다운 문자열로 정규화한 뒤 저장한다.
|
||||||
- 본문 작성 모드는 textarea 기반으로 범위 선택, 다중 문단 복사/붙여넣기, 외부 마크다운 붙여넣기를 브라우저 기본 동작에 가깝게 처리한다.
|
- 본문 작성 모드는 textarea 기반으로 범위 선택, 다중 문단 복사/붙여넣기, 외부 마크다운 붙여넣기를 브라우저 기본 동작에 가깝게 처리한다.
|
||||||
- 본문 작성 모드에서 일반 Enter는 새 문단, Shift+Enter는 같은 문단 안 줄바꿈으로 처리한다.
|
- 본문 작성 모드에서 일반 Enter는 새 문단, Shift+Enter는 같은 문단 안 줄바꿈으로 처리한다. 일반 Enter는 단일 줄 이동으로 보여야 하며, Shift+Enter는 저장 마크다운에 hard break를 남긴다.
|
||||||
- 클립보드에 `text/html`이 있으면 제목, 문단, 목록, 인용, 코드, 링크, 굵게, 기울임, 이미지를 기본 마크다운 조각으로 변환해 삽입한다.
|
- 클립보드에 `text/html`이 있으면 제목, 문단, 목록, 인용, 코드, 링크, 굵게, 기울임, 이미지를 기본 마크다운 조각으로 변환해 삽입한다.
|
||||||
- 본문 미리보기 모드는 공개 본문과 같은 `ContentMarkdownRenderer`를 사용한다.
|
- 본문 미리보기 모드는 공개 본문과 같은 `ContentMarkdownRenderer`를 사용한다.
|
||||||
- 툴바는 제목 1/2/3, 굵게, 기울임, 인라인 코드, 인용, 목록, 코드 블록, 구분선 삽입을 제공한다.
|
- 툴바는 제목 1/2/3, 굵게, 기울임, 인라인 코드, 인용, 목록, 코드 블록, 구분선 삽입을 제공한다.
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# 업데이트 이력
|
# 업데이트 이력
|
||||||
|
|
||||||
|
## v1.0.17
|
||||||
|
|
||||||
|
- 관리자 `AdminMarkdownEditor` 작성 영역의 외곽 보더와 배경 카드 처리를 제거.
|
||||||
|
- 작성 영역 줄 번호 거터를 본문 textarea 바깥의 absolute 영역으로 분리하고 활성 줄 액센트 배경을 제거.
|
||||||
|
- 일반 Enter는 브라우저 기본 단일 줄 이동으로 되돌리고, Shift+Enter만 마크다운 hard break(`공백 2개 + \\n`)로 저장하도록 수정.
|
||||||
|
- 공개 본문/관리자 미리보기 공통 `ContentMarkdownRenderer`가 hard break 행만 같은 문단 안 줄바꿈으로 묶고, 일반 줄은 각각 문단으로 렌더링하도록 정리.
|
||||||
|
- 문단과 제목 하단 기본 간격을 10px 기준으로 조정.
|
||||||
|
- 패키지 버전 `1.0.17`로 갱신.
|
||||||
|
|
||||||
## v1.0.16
|
## v1.0.16
|
||||||
|
|
||||||
- 관리자 `AdminMarkdownEditor`에서 일반 Enter는 새 문단(`\\n\\n`), Shift+Enter는 같은 문단 안 줄바꿈(`\\n`)으로 입력되도록 수정.
|
- 관리자 `AdminMarkdownEditor`에서 일반 Enter는 새 문단(`\\n\\n`), Shift+Enter는 같은 문단 안 줄바꿈(`\\n`)으로 입력되도록 수정.
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "sori.studio",
|
"name": "sori.studio",
|
||||||
"version": "1.0.16",
|
"version": "1.0.17",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sori.studio",
|
"name": "sori.studio",
|
||||||
"version": "1.0.16",
|
"version": "1.0.17",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sori.studio",
|
"name": "sori.studio",
|
||||||
"version": "1.0.16",
|
"version": "1.0.17",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"imports": {
|
"imports": {
|
||||||
|
|||||||
Reference in New Issue
Block a user