From d46ed3bfa06f63bd107daa037fd236d8fa4527d8 Mon Sep 17 00:00:00 2001 From: Seungjun Jeong Date: Tue, 27 Oct 2026 21:20:45 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20editor=20view=20modes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/WriteEditor.tsx | 122 +++++++++++++++------------- src/components/write-editor.css | 137 +++++++++----------------------- 2 files changed, 104 insertions(+), 155 deletions(-) diff --git a/src/components/WriteEditor.tsx b/src/components/WriteEditor.tsx index d8e565f..10dcab0 100644 --- a/src/components/WriteEditor.tsx +++ b/src/components/WriteEditor.tsx @@ -111,7 +111,7 @@ export default function WriteEditor() { const [busy, setBusy] = useState(false); const [uploads, setUploads] = useState(0); const [dragging, setDragging] = useState(false); - const [preview, setPreview] = useState(false); + const [view, setView] = useState<'editor' | 'preview' | 'both'>('both'); const editor = useRef(null); const imageInput = useRef(null); const openedDeepLink = useRef(false); @@ -589,7 +589,25 @@ export default function WriteEditor() { return (
-
+
+ {( + [ + ['editor', '에디터 보기'], + ['preview', '미리보기'], + ['both', '둘 다 보기'], + ] as const + ).map(([value, label]) => ( + + ))} +
+
-
- -
- - - {id && posts.some((post) => post.id === id) && ( - - )} - -
-
-
+
- {title ? ( -

{title}

- ) : ( -

미리보기

- )} - {tags.length > 0 && ( -
- {tags.map((tag) => ( - {tag} - ))} -
- )} +
+ {title ? ( +

{title}

+ ) : ( +

미리보기

+ )} + {tags.length > 0 && ( +
+ {tags.map((tag) => ( + {tag} + ))} +
+ )} +
{previewTooLong ? (

본문이 100,000자를 넘어 미리보기를 생략했습니다. 임시저장과 @@ -846,13 +826,43 @@ export default function WriteEditor() {

) : (
)}
+
+ +
+ + {id && posts.some((post) => post.id === id) && ( + + )} + +
+
{status && (
{status} diff --git a/src/components/write-editor.css b/src/components/write-editor.css index 94c311f..e0977f3 100644 --- a/src/components/write-editor.css +++ b/src/components/write-editor.css @@ -1,16 +1,46 @@ .write-shell { - min-height: 100vh; + height: 100dvh; + display: flex; + flex-direction: column; +} +.write-view-switch { + display: flex; + justify-content: center; + gap: 4px; + padding: 8px; + border-bottom: 1px solid var(--border); +} +.write-view-switch button { + border: 0; + border-radius: 6px; + padding: 7px 12px; + color: var(--muted-foreground); + font-size: 13px; + font-weight: 600; +} +.write-view-switch button[aria-pressed='true'] { + background: var(--secondary); + color: var(--foreground); } .write-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - min-height: 100vh; + min-height: 0; + flex: 1; +} +.write-layout.view-editor, +.write-layout.view-preview { + grid-template-columns: minmax(0, 1fr); +} +.view-editor .write-preview, +.view-preview .write-pane { + display: none; } .write-pane { display: flex; flex-direction: column; min-width: 0; - height: 100vh; + height: 100%; background: var(--background); } .write-head { @@ -205,14 +235,11 @@ .write-publish-button:hover { background: color-mix(in oklch, var(--primary) 90%, transparent) !important; } -.write-mobile-preview { - display: none; -} .write-preview { min-width: 0; - height: 100vh; + height: 100%; overflow: auto; - background: var(--muted); + background: var(--background); border-left: 1px solid var(--border); } .write-preview-content { @@ -220,12 +247,6 @@ margin: 0 auto; padding: 68px 56px 100px; } -.write-preview h1 { - margin: 0 0 24px; - font-size: clamp(32px, 3vw, 44px); - letter-spacing: -0.04em; - line-height: 1.35; -} .write-preview-placeholder { color: var(--muted-foreground); font-size: 23px; @@ -238,68 +259,6 @@ margin: 0 0 38px; color: var(--primary); } -.write-markdown { - font-size: 17px; - line-height: 1.85; - overflow-wrap: anywhere; -} -.write-markdown h1, -.write-markdown h2, -.write-markdown h3 { - margin: 1.6em 0 0.7em; - line-height: 1.4; -} -.write-markdown h1 { - font-size: 2em; -} -.write-markdown h2 { - font-size: 1.55em; -} -.write-markdown h3 { - font-size: 1.25em; -} -.write-markdown p { - margin: 0 0 1.3em; -} -.write-markdown img { - max-width: 100%; - height: auto; -} -.write-markdown pre { - overflow: auto; - padding: 18px; - background: var(--muted); - border-radius: 6px; - font-size: 14px; -} -.write-markdown code { - background: var(--muted); - border-radius: 3px; - padding: 2px 4px; - font-size: 0.9em; -} -.write-markdown pre code { - padding: 0; -} -.write-markdown blockquote { - margin: 1.5em 0; - padding: 2px 0 2px 18px; - border-left: 4px solid var(--primary); - color: var(--muted-foreground); -} -.write-markdown a { - color: var(--primary); -} -.write-markdown table { - border-collapse: collapse; - display: block; - overflow-x: auto; -} -.write-markdown th, -.write-markdown td { - border: 1px solid var(--border); - padding: 8px 12px; -} .write-status { position: fixed; top: 24px; @@ -504,33 +463,13 @@ } @media (max-width: 900px) { - .write-layout { - display: block; - } - .write-pane, - .write-preview { - width: 100%; - } - .write-preview { - display: none; - position: fixed; - inset: 0 0 68px; - height: auto; - z-index: 2; - } - .write-preview.is-visible { - display: block; + .write-layout.view-both { + grid-template-columns: minmax(0, 1fr); + grid-template-rows: minmax(0, 1fr) minmax(0, 1fr); } .write-preview-content { padding: 35px 24px; } - .write-footer { - position: relative; - z-index: 3; - } - .write-mobile-preview { - display: inline-block; - } } @media (max-width: 600px) {