diff --git a/components/content/ContentMarkdownInlineSegments.vue b/components/content/ContentMarkdownInlineSegments.vue index 8eb12af..4f9804e 100644 --- a/components/content/ContentMarkdownInlineSegments.vue +++ b/components/content/ContentMarkdownInlineSegments.vue @@ -54,14 +54,16 @@ const getInlineColorClass = (color) => `content-markdown-inline-segments__color- {{ segment.text }} {{ segment.text }} {{ segment.text }} - {{ segment.text }} + + + - + {{ segment.text }} diff --git a/docs/changelog.md b/docs/changelog.md index 5b32e38..76f49e3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,9 @@ # 업데이트 요약 +## v1.9.34 + +- Markdown 표와 라이브 미리보기에서 링크 텍스트 안의 굵게 같은 중첩 인라인 문법과 `
` 줄바꿈 처리를 보강했다. + ## v1.9.33 - 사용자 화면 Markdown 본문의 인라인 렌더링 구조를 정리해 Elements 탭에 반복 표시되던 Vue fragment 주석을 줄였다. diff --git a/docs/deploy.md b/docs/deploy.md index 3f7215b..bad4d49 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -1,6 +1,6 @@ # 배포 가이드 -> 로컬 기준 v1.9.21에서 `npm run verify` 검증을 통과했다. NAS 실제 컨테이너 기동과 도메인/프록시 접속 검증은 운영 배포 단계에서 진행한다. +> 로컬 기준 v1.9.34에서 `npm run verify` 검증을 통과했다. NAS 실제 컨테이너 기동과 도메인/프록시 접속 검증은 운영 배포 단계에서 진행한다. ## 빌드 유형 diff --git a/docs/history.md b/docs/history.md index a89bb9a..d0e256b 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,9 @@ # 의사결정 이력 +## 2026-07-01 v1.9.34 — 인라인 문법은 링크와 색상 안에서도 같은 규칙으로 렌더링한다 + +Markdown 표 셀과 라이브 미리보기는 같은 인라인 렌더러를 공유하므로, 링크 텍스트나 색상 토큰 내부에 굵게·기울임·줄바꿈 같은 문법이 들어가도 공개 화면과 관리자 화면이 같은 결과를 보여야 한다. 따라서 링크 텍스트를 단순 문자열로 출력하지 않고 다시 인라인 세그먼트로 렌더링하며, `
` 표기도 멀티라인 인라인 변환의 줄바꿈 입력으로 정규화한다. + ## 2026-07-01 v1.9.30 — Pages 추천 표시는 게시물과 같은 아이콘 배지로 맞춘다 홈 Pages 진열장의 추천 상태가 텍스트 `추천` 배지로 표시되면 게시물 카드의 추천 표시와 시각 언어가 달라진다. 추천 상태는 빠르게 인지하는 표시이므로, 게시물과 같은 SVG 아이콘 배지로 통일해 홈 안의 추천 표현을 일관되게 유지한다. diff --git a/docs/map.md b/docs/map.md index 3d610d0..fcb39b7 100644 --- a/docs/map.md +++ b/docs/map.md @@ -40,7 +40,7 @@ | lib/markdown-image.js | 이미지 마크다운 직렬화·파싱, 단독 이미지 URL 판별 | | lib/markdown-toc.js | 공개 게시글 TOC용 H1~H3 제목 추출과 앵커 ID 생성 | | lib/markdown-slash-commands.js | 관리자 Markdown-first 에디터 슬래시 명령 목록과 삽입 줄 정의 | -| lib/markdown-inline.js | 공개·관리자 공통 인라인 마크다운 파서, 링크·굵게·기울임·인라인 코드·첨자·인라인 색상 토큰(`::color[텍스트]`) 변환 | +| lib/markdown-inline.js | 공개·관리자 공통 인라인 마크다운 파서, 링크·굵게·기울임·인라인 코드·첨자·인라인 색상 토큰(`::color[텍스트]`) 변환, 링크·색상 내부 중첩 인라인 문법과 `
` 줄바꿈 처리 | | lib/post-tag-limit.js | 게시물별 태그 최대 개수 기본값·허용 범위·정규화 | | lib/analytics-shared.js | 통계 추적 경로 필터·체류/스크롤 상수(클라이언트·서버 공용) | | lib/analytics.js | 서버 전용 visitor/session hash(`node:crypto`) | @@ -149,7 +149,7 @@ | components/content/ContentRenderer.vue | 게시물/페이지 본문 | | components/content/ContentMarkdownRenderer.vue | 마크다운 문자열 기반 본문 렌더링, 문단 text-base(16px), 빈 줄 spacer 보존·hard break `
` 처리, 표준 마크다운 표 파싱·렌더링(셀 내부 인라인 링크와 `
` 줄바꿈 포함), 공개 게시물 인아티클 광고를 본문 길이에 따라 0~2회 삽입, Obsidian식 위첨자·아래첨자 인라인 렌더링, 확장 블록 파싱, `:::` fenced 블록 원본 범위 보정, 닫히지 않은 코드 펜스 하위 콘텐츠 보호, 인용 막대 색상 옵션(`> [!bg=...]`), 라이브 문단 `>` 즉시 인용 변환과 ` ``` `·`!!!` Enter 코드 블록·콜아웃 단축 생성, 라이브 콜아웃·인용 포커스 기반 오른쪽 설정 패널 연결, 라이브 인용·콜아웃 멀티라인 편집 줄 범위 포커스와 위/아래 방향키 외부 문단 이탈, 인용 Backspace 문단 복귀, 라이브 방향키 이동 시 편집 가능한 줄·카드형 블록 탐색, 라이브 코드·콜아웃·토글 내부 줄 삭제와 마지막 줄 블록 삭제, 라이브 이미지·갤러리 드래그 병합·추가·분리 UI, 갤러리 비율 기반 행 레이아웃, 라이브 이미지·갤러리 hover 삭제 액션, 리스트 마커 파란 계열 통일과 여러 줄 항목 첫 줄 기준 정렬 | | components/content/ContentMarkdownEditableInline.vue | 라이브 모드 공통 인라인 편집 영역, 일반 인라인 마크다운·Obsidian식 첨자 렌더링과 plain text 멀티라인 본문·끝 줄바꿈 보존, 한글 IME 조합 확정 Enter의 블록별 동작 연결, 위/아래 인접 블록 이동 시 편집 스크롤 추적, Shift 위/아래 인접 블록 선택 확장·단계적 `Cmd/Ctrl+A` 처리, 멀티라인 Enter 텍스트 값 치환, 첫 줄 빈 줄 포함 줄바꿈 유지 | -| components/content/ContentMarkdownInlineSegments.vue | 공개·라이브 본문 공통 인라인 세그먼트 렌더링(링크·굵게·기울임·인라인 코드·첨자·인라인 색상), 사용자 화면 fragment 주석 반복을 줄이는 단일 루트 구조 | +| components/content/ContentMarkdownInlineSegments.vue | 공개·라이브 본문 공통 인라인 세그먼트 렌더링(링크·굵게·기울임·인라인 코드·첨자·인라인 색상), 링크·색상 내부 중첩 인라인 렌더링, 사용자 화면 fragment 주석 반복을 줄이는 단일 루트 구조 | | lib/markdown-live-selection.js | 라이브 모드 Selection Bridge, 인접 contenteditable 범위 확장·블록/문서 전체 선택·교차 선택 삭제 마크다운 반영, 콜아웃·인용 전체 선택 삭제 시 빈 본문 줄 보존, Selection focus 기준 연속 확장 | | components/content/ProseHeading.vue | h1~h6 제목, 기본 mt-12 제거 | | components/content/ProseImage.vue | 본문 내 이미지, 로드 실패·빈 URL placeholder | diff --git a/docs/spec.md b/docs/spec.md index 36da811..d72f720 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -88,9 +88,9 @@ - 댓글 아바타 이미지 로드 실패 시 이니셜 아바타로 즉시 대체한다. - 공개 게시물 본문은 콘텐츠 타입별 컴포넌트로 분리해 추후 스타일 변경이 쉽도록 구성 - 공개 게시물 오른쪽 목차는 H1~H3 제목 표시 텍스트에서 링크·굵게·기울임·인라인 코드 같은 마크다운 장식만 제거하고 `~` 같은 일반 제목 문자는 보존한다. -- 공개 Markdown 인라인 렌더러는 단일 루트와 `display: contents`를 사용해 사용자 화면 DOM의 Vue fragment 주석 반복을 줄이고, 기존 인라인 흐름은 유지한다. +- 공개 Markdown 인라인 렌더러는 단일 루트와 `display: contents`를 사용해 사용자 화면 DOM의 Vue fragment 주석 반복을 줄이고, 기존 인라인 흐름은 유지한다. 링크 텍스트와 색상 토큰 내부의 굵게·기울임·인라인 코드·색상·첨자 문법은 재귀적으로 렌더링한다. - Markdown 리스트 마커는 항목이 여러 줄로 줄바꿈되어도 항목 전체 높이 중앙이 아니라 첫 줄 기준으로 정렬한다. -- 표준 마크다운 표(`| 헤더 | ... |`, `| --- | ... |`)는 본문에서 가로 스크롤 가능한 HTML table로 렌더링한다. 정렬 구분선(`:---`, `:---:`, `---:`)은 각각 좌/중앙/우 정렬로 반영한다. 표 헤더와 셀 내부의 인라인 링크·굵게·기울임·인라인 코드를 렌더링하고, 셀 내부 `
` 또는 `
`은 줄바꿈으로 표시한다. +- 표준 마크다운 표(`| 헤더 | ... |`, `| --- | ... |`)는 본문에서 가로 스크롤 가능한 HTML table로 렌더링한다. 정렬 구분선(`:---`, `:---:`, `---:`)은 각각 좌/중앙/우 정렬로 반영한다. 표 헤더와 셀 내부의 인라인 링크·굵게·기울임·인라인 코드를 렌더링하고, 셀 내부 `
` 또는 `
`은 줄바꿈으로 표시한다. 링크 텍스트 안의 `**굵게**` 같은 중첩 인라인 문법도 렌더링한다. - 인용문(`>`)은 왼쪽 세로 막대형 기본 스타일로 표시한다. 기본 인용 텍스트는 라이트·다크 모드 모두 사이트 본문 텍스트 색상(`--site-text`)을 따른다. 첫 줄 옵션 `> [!bg=blue]` 또는 `> {bg=blue}`는 인용 막대 색상으로 반영하며, 지원 값은 콜아웃과 같은 `gray`, `blue`, `green`, `yellow`, `red`, `purple`이다. - 관리자 Markdown-first 글쓰기의 오른쪽 블록 설정 패널은 인용·콜아웃·코드 블록·토글 설정과 선택 텍스트 색상 설정을 지원한다. 콜아웃은 제목·아이콘 표시 여부·아이콘·배경색, 코드 블록은 언어·줄번호 표시 여부, 토글은 기본 펼침·닫힘 상태를 선언 줄에 저장한다. 코드 블록 줄번호는 기본 숨김이며, 켠 경우에만 선언 줄에 `line-numbers`를 저장한다. 일반 텍스트 범위를 선택하면 텍스트 색상 패널이 열리고 회색·파랑·초록·노랑·빨강·보라 인라인 색상을 적용한다. 콜아웃 아이콘은 라이브·공개 화면 모두 왼쪽 상단에 배치하고, 아이콘·제목 헤더 아래에 본문을 줄바꿈해 표시한다. 아이콘 미사용 시 자리 표시자를 남기지 않는다. 라이브 문단에서는 `>` 입력으로 인용, ``` Enter로 코드 블록, `!!!` Enter로 콜아웃을 만들 수 있고, `/표` 또는 `/table` 슬래시 명령으로 기본 3열 표 마크다운을 삽입한다. `/html`은 `:::html`, `/link`는 `:::link`, `/iframe`은 `:::iframe` fenced 블록을 삽입한다. 소스·라이브 모드 모두 텍스트를 선택한 뒤 `Cmd/Ctrl+K`를 누르면 `[선택 텍스트](https://)` 인라인 링크 마크다운을 삽입하고 URL 부분을 선택한다. 에디터 되돌리기·다시 실행은 본문 값과 함께 선택 위치를 복원해 줄 앞 이동을 줄인다. 라이브 모드에서 위·아래 방향키로 인접 블록을 이동하면 커서가 화면 밖으로 벗어날 때 편집 스크롤 영역도 함께 이동한다. 라이브 코드·인용·콜아웃·토글 블록은 맨 위/맨 아래 방향키로 외부 기본 문단을 만들며 빠져나올 수 있고, 인용 첫 글자 앞 Backspace는 일반 문단으로 되돌린다. 한글 등 IME 조합 입력 중에는 줄바꿈 직후 블록 판별이 일시적으로 비어도 마지막 블록 컨텍스트를 유지해 설정 패널이 닫히지 않게 한다. - 게시물 상세의 오른쪽 사이드바는 데스크톱에서 블로그 소개·Follow 대신 본문 H1~H3 제목 기반 목차를 최상단에 표시한다. 목차는 별도 최대 높이와 내부 스크롤을 두지 않고 전체 목록이 먼저 펼쳐지며, 왼쪽 기준선과 브랜드 컬러 활성 항목 표시선을 둔다. 목차 항목은 최소 24px 높이와 세로 중앙 정렬을 사용하며, 2줄 이상 제목에서는 항목 높이에 맞춰 활성 표시선도 함께 늘어난다. 활성 표시선은 항목의 가상 요소 배경 막대로 그려 텍스트 시작점이 밀리지 않게 한다. 목차 링크는 본문 제목에 부여된 앵커 ID로 부드럽게 이동하며, 고정 상단 헤더 높이와 여백을 반영해 제목이 화면 밖에 걸리지 않게 한다. 본문 스크롤 중에는 현재 제목에 해당하는 목차 항목을 강조하고, 목차 항목이 많으면 오른쪽 사이드바 스크롤이 활성 항목을 따라간다. 본문 제목이 없으면 목차 없음 문구를 표시한다. 오른쪽 사이드바가 본문 아래로 내려가는 모바일 폭에서는 목차를 숨긴다. 게시물 상세에서는 일반 오른쪽 사이드 광고 대신 게시물 사이드 광고 코드를 목차 아래에 표시하고, 왼쪽 사이드바에는 게시물 광고를 표시하지 않는다. 게시물 상세 목차와 게시물 사이드 광고 슬롯은 하단 구분선을 표시하지 않는다. diff --git a/docs/update.md b/docs/update.md index 73a2907..120838f 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,10 @@ # 업데이트 이력 +## v1.9.34 + +- Markdown 인라인 링크 텍스트 내부의 굵게·기울임·색상 등 중첩 인라인 렌더링 추가. +- Markdown 인라인 색상·링크 내부 `
` 줄바꿈 렌더링 보강. + ## v1.9.33 - 공개 Markdown 인라인 렌더러의 fragment 주석 반복을 줄이도록 단일 루트 구조로 정리. diff --git a/lib/markdown-inline.js b/lib/markdown-inline.js index f438c4c..7ed1be8 100644 --- a/lib/markdown-inline.js +++ b/lib/markdown-inline.js @@ -241,7 +241,8 @@ export const segmentsToInlineHtml = (segments) => segments.map((segment) => { } if (segment.type === 'link') { - return `${escapeHtml(segment.text)}` + const nestedHtml = segmentsToInlineHtml(parseInlineSegments(segment.text)) + return `${nestedHtml}` } if (segment.type === 'color' && isInlineColorName(segment.color)) { @@ -266,6 +267,7 @@ export const markdownInlineToHtml = (value) => segmentsToInlineHtml(parseInlineS * @returns {string} HTML */ export const markdownMultilineInlineToHtml = (value) => String(value || '') + .replace(//gi, '\n') .split('\n') .map((line) => markdownInlineToHtml(line)) .join('
') diff --git a/package-lock.json b/package-lock.json index df095ce..be383e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sori.studio", - "version": "1.9.33", + "version": "1.9.34", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sori.studio", - "version": "1.9.33", + "version": "1.9.34", "hasInstallScript": true, "dependencies": { "@nuxtjs/tailwindcss": "^6.14.0", diff --git a/package.json b/package.json index c675a1d..53b512a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sori.studio", - "version": "1.9.33", + "version": "1.9.34", "private": true, "type": "module", "imports": {