@storkspear/post-editor-react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +12 -0
- package/dist/ColorPicker.d.ts +11 -0
- package/dist/ColorPicker.d.ts.map +1 -0
- package/dist/ColorPicker.js +30 -0
- package/dist/ColorPicker.js.map +1 -0
- package/dist/DrawioModal.d.ts +9 -0
- package/dist/DrawioModal.d.ts.map +1 -0
- package/dist/DrawioModal.js +97 -0
- package/dist/DrawioModal.js.map +1 -0
- package/dist/FontMenu.d.ts +14 -0
- package/dist/FontMenu.d.ts.map +1 -0
- package/dist/FontMenu.js +14 -0
- package/dist/FontMenu.js.map +1 -0
- package/dist/Icon.d.ts +69 -0
- package/dist/Icon.d.ts.map +1 -0
- package/dist/Icon.js +47 -0
- package/dist/Icon.js.map +1 -0
- package/dist/InsertHandle.d.ts +14 -0
- package/dist/InsertHandle.d.ts.map +1 -0
- package/dist/InsertHandle.js +60 -0
- package/dist/InsertHandle.js.map +1 -0
- package/dist/PickMenu.d.ts +61 -0
- package/dist/PickMenu.d.ts.map +1 -0
- package/dist/PickMenu.js +57 -0
- package/dist/PickMenu.js.map +1 -0
- package/dist/Popover.d.ts +20 -0
- package/dist/Popover.d.ts.map +1 -0
- package/dist/Popover.js +22 -0
- package/dist/Popover.js.map +1 -0
- package/dist/PostTitle.d.ts +33 -0
- package/dist/PostTitle.d.ts.map +1 -0
- package/dist/PostTitle.js +171 -0
- package/dist/PostTitle.js.map +1 -0
- package/dist/SelectionBubble.d.ts +6 -0
- package/dist/SelectionBubble.d.ts.map +1 -0
- package/dist/SelectionBubble.js +71 -0
- package/dist/SelectionBubble.js.map +1 -0
- package/dist/TableTools.d.ts +10 -0
- package/dist/TableTools.d.ts.map +1 -0
- package/dist/TableTools.js +200 -0
- package/dist/TableTools.js.map +1 -0
- package/dist/Toolbar.d.ts +17 -0
- package/dist/Toolbar.d.ts.map +1 -0
- package/dist/Toolbar.js +333 -0
- package/dist/Toolbar.js.map +1 -0
- package/dist/UrlPrompt.d.ts +24 -0
- package/dist/UrlPrompt.d.ts.map +1 -0
- package/dist/UrlPrompt.js +53 -0
- package/dist/UrlPrompt.js.map +1 -0
- package/dist/VariantMenu.d.ts +47 -0
- package/dist/VariantMenu.d.ts.map +1 -0
- package/dist/VariantMenu.js +21 -0
- package/dist/VariantMenu.js.map +1 -0
- package/dist/WidthToggle.d.ts +19 -0
- package/dist/WidthToggle.d.ts.map +1 -0
- package/dist/WidthToggle.js +17 -0
- package/dist/WidthToggle.js.map +1 -0
- package/dist/bubbleShows.d.ts +10 -0
- package/dist/bubbleShows.d.ts.map +1 -0
- package/dist/bubbleShows.js +29 -0
- package/dist/bubbleShows.js.map +1 -0
- package/dist/content-baked.d.ts +22 -0
- package/dist/content-baked.d.ts.map +1 -0
- package/dist/content-baked.js +21 -0
- package/dist/content-baked.js.map +1 -0
- package/dist/content.d.ts +29 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +35 -0
- package/dist/content.js.map +1 -0
- package/dist/extensions/DiagramView.d.ts +26 -0
- package/dist/extensions/DiagramView.d.ts.map +1 -0
- package/dist/extensions/DiagramView.js +146 -0
- package/dist/extensions/DiagramView.js.map +1 -0
- package/dist/extensions/FigureView.d.ts +3 -0
- package/dist/extensions/FigureView.d.ts.map +1 -0
- package/dist/extensions/FigureView.js +108 -0
- package/dist/extensions/FigureView.js.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -0
- package/dist/objects/ObjectFloat.d.ts +11 -0
- package/dist/objects/ObjectFloat.d.ts.map +1 -0
- package/dist/objects/ObjectFloat.js +42 -0
- package/dist/objects/ObjectFloat.js.map +1 -0
- package/dist/objects/ObjectLayer.d.ts +10 -0
- package/dist/objects/ObjectLayer.d.ts.map +1 -0
- package/dist/objects/ObjectLayer.js +20 -0
- package/dist/objects/ObjectLayer.js.map +1 -0
- package/dist/objects/blockSize.d.ts +30 -0
- package/dist/objects/blockSize.d.ts.map +1 -0
- package/dist/objects/blockSize.js +56 -0
- package/dist/objects/blockSize.js.map +1 -0
- package/dist/objects/code.d.ts +3 -0
- package/dist/objects/code.d.ts.map +1 -0
- package/dist/objects/code.js +55 -0
- package/dist/objects/code.js.map +1 -0
- package/dist/objects/diagram.d.ts +21 -0
- package/dist/objects/diagram.d.ts.map +1 -0
- package/dist/objects/diagram.js +109 -0
- package/dist/objects/diagram.js.map +1 -0
- package/dist/objects/diagramGlyphs.d.ts +12 -0
- package/dist/objects/diagramGlyphs.d.ts.map +1 -0
- package/dist/objects/diagramGlyphs.js +49 -0
- package/dist/objects/diagramGlyphs.js.map +1 -0
- package/dist/objects/divider.d.ts +22 -0
- package/dist/objects/divider.d.ts.map +1 -0
- package/dist/objects/divider.js +60 -0
- package/dist/objects/divider.js.map +1 -0
- package/dist/objects/figure.d.ts +3 -0
- package/dist/objects/figure.d.ts.map +1 -0
- package/dist/objects/figure.js +62 -0
- package/dist/objects/figure.js.map +1 -0
- package/dist/objects/imageRow.d.ts +3 -0
- package/dist/objects/imageRow.d.ts.map +1 -0
- package/dist/objects/imageRow.js +29 -0
- package/dist/objects/imageRow.js.map +1 -0
- package/dist/objects/quote.d.ts +6 -0
- package/dist/objects/quote.d.ts.map +1 -0
- package/dist/objects/quote.js +13 -0
- package/dist/objects/quote.js.map +1 -0
- package/dist/objects/quoteGlyphs.d.ts +6 -0
- package/dist/objects/quoteGlyphs.d.ts.map +1 -0
- package/dist/objects/quoteGlyphs.js +28 -0
- package/dist/objects/quoteGlyphs.js.map +1 -0
- package/dist/objects/quoteRow.d.ts +3 -0
- package/dist/objects/quoteRow.d.ts.map +1 -0
- package/dist/objects/quoteRow.js +61 -0
- package/dist/objects/quoteRow.js.map +1 -0
- package/dist/objects/registry.d.ts +60 -0
- package/dist/objects/registry.d.ts.map +1 -0
- package/dist/objects/registry.js +45 -0
- package/dist/objects/registry.js.map +1 -0
- package/dist/objects/table.d.ts +11 -0
- package/dist/objects/table.d.ts.map +1 -0
- package/dist/objects/table.js +136 -0
- package/dist/objects/table.js.map +1 -0
- package/dist/objects/useDomRect.d.ts +14 -0
- package/dist/objects/useDomRect.d.ts.map +1 -0
- package/dist/objects/useDomRect.js +32 -0
- package/dist/objects/useDomRect.js.map +1 -0
- package/dist/objects/useEngaged.d.ts +14 -0
- package/dist/objects/useEngaged.d.ts.map +1 -0
- package/dist/objects/useEngaged.js +41 -0
- package/dist/objects/useEngaged.js.map +1 -0
- package/dist/pickItems.d.ts +36 -0
- package/dist/pickItems.d.ts.map +1 -0
- package/dist/pickItems.js +40 -0
- package/dist/pickItems.js.map +1 -0
- package/dist/recentColors.d.ts +7 -0
- package/dist/recentColors.d.ts.map +1 -0
- package/dist/recentColors.js +30 -0
- package/dist/recentColors.js.map +1 -0
- package/dist/seeds/drawio/aws.d.ts +15 -0
- package/dist/seeds/drawio/aws.d.ts.map +1 -0
- package/dist/seeds/drawio/aws.js +15 -0
- package/dist/seeds/drawio/aws.js.map +1 -0
- package/dist/seeds/drawio/azure.d.ts +14 -0
- package/dist/seeds/drawio/azure.d.ts.map +1 -0
- package/dist/seeds/drawio/azure.js +14 -0
- package/dist/seeds/drawio/azure.js.map +1 -0
- package/dist/seeds/drawio/ec2docker.d.ts +15 -0
- package/dist/seeds/drawio/ec2docker.d.ts.map +1 -0
- package/dist/seeds/drawio/ec2docker.js +15 -0
- package/dist/seeds/drawio/ec2docker.js.map +1 -0
- package/dist/seeds/drawio/userflow.d.ts +21 -0
- package/dist/seeds/drawio/userflow.d.ts.map +1 -0
- package/dist/seeds/drawio/userflow.js +21 -0
- package/dist/seeds/drawio/userflow.js.map +1 -0
- package/dist/seeds/mermaid.d.ts +19 -0
- package/dist/seeds/mermaid.d.ts.map +1 -0
- package/dist/seeds/mermaid.js +82 -0
- package/dist/seeds/mermaid.js.map +1 -0
- package/dist/useAnchoredPos.d.ts +22 -0
- package/dist/useAnchoredPos.d.ts.map +1 -0
- package/dist/useAnchoredPos.js +57 -0
- package/dist/useAnchoredPos.js.map +1 -0
- package/dist/useDismiss.d.ts +17 -0
- package/dist/useDismiss.d.ts.map +1 -0
- package/dist/useDismiss.js +36 -0
- package/dist/useDismiss.js.map +1 -0
- package/dist/useLastVariant.d.ts +9 -0
- package/dist/useLastVariant.d.ts.map +1 -0
- package/dist/useLastVariant.js +33 -0
- package/dist/useLastVariant.js.map +1 -0
- package/dist/useUploadCount.d.ts +3 -0
- package/dist/useUploadCount.d.ts.map +1 -0
- package/dist/useUploadCount.js +9 -0
- package/dist/useUploadCount.js.map +1 -0
- package/package.json +57 -0
- package/src/editor-ui.css +737 -0
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 편집 UI 의 겉모습 — 툴바·버블·팝오버·오버레이.
|
|
3
|
+
*
|
|
4
|
+
* 본문(`prose.css`)과 갈라 둔다: 본문 CSS 는 **발행 페이지도** 쓰고,
|
|
5
|
+
* 이 파일은 **편집기에만** 필요하다. 공개 빌드에 편집 UI 가 한 줄도 안 들어가야 한다.
|
|
6
|
+
*/
|
|
7
|
+
* { box-sizing: border-box; }
|
|
8
|
+
html, body, #root { height: 100%; }
|
|
9
|
+
body { margin: 0; background: #fff; color: #1a1a1a;
|
|
10
|
+
font-family: Pretendard, -apple-system, 'Apple SD Gothic Neo', 'Noto Sans KR', system-ui, sans-serif; }
|
|
11
|
+
|
|
12
|
+
.tb-group { display: flex; gap: 2px; padding-right: 0.4rem; flex: none;
|
|
13
|
+
border-right: 1px solid #eeece6; align-items: center; }
|
|
14
|
+
.tb-group:last-child { border-right: 0; }
|
|
15
|
+
.tb-btn { min-width: 36px; height: 36px; padding: 0 8px; flex: none;
|
|
16
|
+
border: 1px solid transparent; background: transparent; border-radius: 7px;
|
|
17
|
+
font-size: 0.85rem; color: #3a3a3a; cursor: pointer; line-height: 1; }
|
|
18
|
+
.tb-btn:hover:not(:disabled) { background: #f2f1ec; }
|
|
19
|
+
.tb-btn.is-on { background: #1a1a1a; color: #fff; }
|
|
20
|
+
.tb-btn:disabled { opacity: 0.3; cursor: default; }
|
|
21
|
+
.tb-swatch { width: 22px; height: 22px; border-radius: 50%; border: 1px solid #d8d6d0;
|
|
22
|
+
cursor: pointer; flex: none; margin: 0 1px; padding: 0; }
|
|
23
|
+
/* 고르는 칸(글꼴·문단·크기) — **상자를 두르지 않는다.**
|
|
24
|
+
테두리를 치면 버튼이 아닌데 버튼처럼 보이고, 옆의 진짜 버튼들과 무게가 같아져 줄이 시끄럽다.
|
|
25
|
+
네이버도 글자 + 작은 꺾쇠만 둔다. */
|
|
26
|
+
.tb-select {
|
|
27
|
+
display: inline-flex; align-items: center; flex: none;
|
|
28
|
+
height: 32px; border: 0; border-radius: 6px; background: transparent;
|
|
29
|
+
font-size: 0.86rem; color: #3a3a3a; cursor: pointer; text-align: left;
|
|
30
|
+
padding: 0 1.15rem 0 0.45rem; white-space: nowrap;
|
|
31
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='6' viewBox='0 0 9 6'%3E%3Cpath d='M1 1l3.5 3.5L8 1' fill='none' stroke='%238a8a8a' stroke-width='1.3' stroke-linecap='round'/%3E%3C/svg%3E");
|
|
32
|
+
background-repeat: no-repeat; background-position: right 0.35rem center;
|
|
33
|
+
}
|
|
34
|
+
.tb-select:hover { background-color: #f4f3ef; }
|
|
35
|
+
.tb-select.is-open { background-color: #eceae4; }
|
|
36
|
+
.tb-select:focus-visible { outline: 2px solid #2563eb; outline-offset: -2px; }
|
|
37
|
+
/* 아이콘만 든 고르기 칸(줄 간격) — 꺾쇠를 빼고 아이콘 버튼과 같은 크기로 선다 */
|
|
38
|
+
.tb-iconselect { background-image: none; padding: 0; width: 36px; justify-content: center; }
|
|
39
|
+
|
|
40
|
+
.editor-surface { outline: none; }
|
|
41
|
+
/**
|
|
42
|
+
* 글 끝의 여유 — 마지막 줄이 창 바닥에 붙지 않게 한다.
|
|
43
|
+
*
|
|
44
|
+
* 패딩이 없으면 문서 끝까지 내렸을 때 마지막 문단의 바닥이 곧 편집면의 바닥이라,
|
|
45
|
+
* 커서가 창 맨 아래 모서리에 붙는다. 거기서는 글자 버블도 드롭다운도 펼 자리가 없고,
|
|
46
|
+
* 무엇보다 **더 쓸 자리가 눈에 안 보여** 글이 끝난 것처럼 읽힌다.
|
|
47
|
+
* 네이버 블로그는 문서 끝까지 내려도 마지막 줄 밑에 약 245px(창 높이 1025px 기준)를
|
|
48
|
+
* 남겨 둔다 — 네이버 블로그도 창 높이의 약 24% 를 남긴다.
|
|
49
|
+
*
|
|
50
|
+
* **패딩은 contenteditable 안쪽에 준다.** 바깥 껍데기에 주면 그 빈 곳을 눌러도
|
|
51
|
+
* 아무 일이 없지만, 안쪽이면 ProseMirror 가 가장 가까운 자리 = 문서 끝으로 커서를 보낸다.
|
|
52
|
+
* 창이 낮을 때 화면을 반이나 먹지 않도록 vh 와 상한을 같이 건다.
|
|
53
|
+
*/
|
|
54
|
+
.editor-surface .ProseMirror { outline: none; min-height: 50vh; padding-bottom: min(30vh, 260px); }
|
|
55
|
+
.editor-surface .ProseMirror-selectednode { outline: 2px solid #2563eb; border-radius: 4px; }
|
|
56
|
+
.editor-surface .selectedCell { background: #e8effb; }
|
|
57
|
+
/* 열 너비 손잡이 — 편집 전용. 위치 선언이 없으면 삽입돼도 크기가 0 이라 안 보인다.
|
|
58
|
+
네이버처럼 끄는 동안 세로 안내선으로 읽히도록 셀 높이를 꽉 채운다. */
|
|
59
|
+
.editor-surface .column-resize-handle {
|
|
60
|
+
position: absolute; right: -2px; top: 0; bottom: 0; width: 3px;
|
|
61
|
+
background: #2563eb; pointer-events: none; z-index: 3;
|
|
62
|
+
}
|
|
63
|
+
/* 경계 위에 있을 때 커서를 바꿔 끌 수 있다는 걸 알린다 */
|
|
64
|
+
.editor-surface .ProseMirror.resize-cursor { cursor: col-resize; }
|
|
65
|
+
|
|
66
|
+
/* ── 툴바 v2 ── */
|
|
67
|
+
.tb-btn { display: inline-flex; align-items: center; justify-content: center; }
|
|
68
|
+
.tb-btn svg { display: block; }
|
|
69
|
+
.tb-txt { font-size: 0.76rem; letter-spacing: -0.02em; }
|
|
70
|
+
.tb-hint { font-size: 0.72rem; color: #9aa0aa; white-space: nowrap; padding: 0 2px; }
|
|
71
|
+
|
|
72
|
+
.tb-size { justify-content: center; }
|
|
73
|
+
.tb-unit { font-size: 0.72rem; color: #9a9a9a; margin: 0 6px 0 -2px; flex: none; }
|
|
74
|
+
|
|
75
|
+
.tb-swatch.is-on { box-shadow: 0 0 0 2px #fff, 0 0 0 3.5px #1a1a1a; }
|
|
76
|
+
|
|
77
|
+
/* 문맥 그룹 — 목록/표 안에 있을 때만 나타난다 */
|
|
78
|
+
.tb-context { background: #f5f4f0; border-radius: 8px; padding: 3px 6px 3px 8px;
|
|
79
|
+
border-right: 0; margin-left: 2px; animation: ctxIn .14s ease-out; }
|
|
80
|
+
@keyframes ctxIn { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }
|
|
81
|
+
|
|
82
|
+
@media (max-width: 640px) {
|
|
83
|
+
.tb-btn { min-width: 40px; height: 40px; } /* 폰 터치 타깃 */
|
|
84
|
+
.tb-size { min-width: 50px; }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/* ══ 툴바 v3 — 네이버 구조 참고: 윗줄 넣기(아이콘+글자) / 아랫줄 서식(아이콘) ══ */
|
|
89
|
+
/* 편집 도구는 **한 덩이의 띠**여야 한다.
|
|
90
|
+
소비자 레이아웃의 좌우 패딩 안에 갇히면 왼쪽에 빈 칸이 생겨 「어디까지가 도구인지」가 흐려진다.
|
|
91
|
+
음수 마진으로 그 패딩을 뚫고 나가고, 뚫은 만큼 안쪽에서 되돌려 준다. */
|
|
92
|
+
/* 붙는 자리는 **소비자가 알려 준다.** 여기에 숫자를 박아 두면 소비자의 머리줄 높이가 바뀌는 날
|
|
93
|
+
툴바가 그 밑으로 파고들어 겹친다. */
|
|
94
|
+
.toolbar2 {
|
|
95
|
+
position: sticky; top: var(--editor-sticky-top, 0px); z-index: 20; background: #fff;
|
|
96
|
+
margin-inline: calc(-1 * var(--editor-gutter, 0px));
|
|
97
|
+
border-bottom: 1px solid #dedbd4;
|
|
98
|
+
box-shadow: 0 1px 0 #fff, 0 2px 6px rgba(0, 0, 0, 0.035);
|
|
99
|
+
}
|
|
100
|
+
/* 도구 띠의 안쪽 여백은 **소비자 패딩과 무관하게** 작게 — 본문 글줄에 맞추면 도구가
|
|
101
|
+
가운데로 밀려 띠의 왼쪽이 비어 보인다. 네이버도 화면 가장자리에 가깝게 붙여 둔다. */
|
|
102
|
+
.toolbar2 .tb-row { padding-inline: 0.85rem; }
|
|
103
|
+
/* ⚠ 한 축이 `auto` 면 다른 축의 `visible` 은 **`auto` 로 계산된다**(CSS Overflow 3).
|
|
104
|
+
즉 이 줄은 세로로도 잘리는 상자다 — 그래서 메뉴·팝오버가 전부 포털로 빠져 있다.
|
|
105
|
+
`visible` 이라고 적어 두면 읽는 사람이 안 잘린다고 믿는다. 계산되는 값을 그대로 적는다. */
|
|
106
|
+
.tb-row { display: flex; align-items: center; gap: 2px; overflow: auto hidden;
|
|
107
|
+
-webkit-overflow-scrolling: touch; scrollbar-width: thin; }
|
|
108
|
+
.tb-row-insert { padding-block: 0.5rem 0.4rem; border-bottom: 1px solid #f0eee9; gap: 4px; }
|
|
109
|
+
.tb-row-format { padding-block: 0.32rem; }
|
|
110
|
+
/* 편집기 밖에 손이 가 있는 동안 — 누를 수 있게 두면 글이 엉뚱한 데 걸리고 화면이 튄다.
|
|
111
|
+
줄 **전체**가 클릭을 안 받아야 한다. 자식만 막으면 줄의 빈 자리를 누른 것이
|
|
112
|
+
「편집 UI 를 눌렀다」로 세어져 잠금이 풀린다(그래서 두 번째 클릭에서 다시 튄다). */
|
|
113
|
+
.tb-row-format.is-idle { opacity: 0.42; pointer-events: none; }
|
|
114
|
+
.tb-row-format.is-idle .tb-sheet-btn { pointer-events: auto; }
|
|
115
|
+
|
|
116
|
+
/* 넣기 타일 */
|
|
117
|
+
/* 위아래가 빡빡하면 아이콘과 글자가 서로 붙어 버튼이 눌린 것처럼 보인다.
|
|
118
|
+
숨 쉴 자리를 준다 — 넣기 줄은 이 편집기에서 제일 먼저 눈이 가는 줄이다. */
|
|
119
|
+
.tb-tile { display: flex; flex-direction: column; align-items: center; gap: 4px; flex: none;
|
|
120
|
+
min-width: 58px; padding: 9px 10px 8px; border: 1px solid transparent; border-radius: 10px;
|
|
121
|
+
background: transparent; color: #3a3a3a; cursor: pointer; }
|
|
122
|
+
.tb-tile:hover { background: #f4f3ef; }
|
|
123
|
+
.tb-tile.is-on { background: #1a1a1a; color: #fff; }
|
|
124
|
+
.tb-tile-ico { display: flex; }
|
|
125
|
+
.tb-tile-label { font-size: 0.7rem; letter-spacing: -0.03em; display: inline-flex; align-items: center; gap: 2px; white-space: nowrap; }
|
|
126
|
+
.tb-caret { width: 0; height: 0; border-left: 3.5px solid transparent; border-right: 3.5px solid transparent;
|
|
127
|
+
border-top: 4px solid currentColor; display: inline-block; opacity: .55; }
|
|
128
|
+
|
|
129
|
+
/* 구분자 */
|
|
130
|
+
.tb-div { width: 1px; height: 20px; background: #e6e4de; flex: none; margin: 0 6px; }
|
|
131
|
+
|
|
132
|
+
/* ▾ 메뉴 */
|
|
133
|
+
.tb-anchor { position: relative; flex: none; display: flex; }
|
|
134
|
+
.tb-caret-btn { display: inline-flex; align-items: center; gap: 2px; padding: 0 6px; }
|
|
135
|
+
.tb-menu { position: absolute; top: calc(100% + 5px); left: 0; z-index: 60; min-width: 190px;
|
|
136
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 10px; padding: 5px;
|
|
137
|
+
box-shadow: 0 8px 26px rgba(0,0,0,.13); }
|
|
138
|
+
.tb-menu button { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
|
|
139
|
+
border: 0; background: transparent; border-radius: 7px; padding: 7px 9px; cursor: pointer; color: #2a2a2a;
|
|
140
|
+
min-height: 40px; } /* 폰 터치 타깃 — 34px 이면 손가락으로 못 누른다 */
|
|
141
|
+
.tb-menu button:hover { background: #f4f3ef; }
|
|
142
|
+
.tb-menu button.on { background: #1a1a1a; color: #fff; }
|
|
143
|
+
.tb-menu button span { display: flex; flex-direction: column; line-height: 1.3; }
|
|
144
|
+
.tb-menu button b { font-size: 0.83rem; font-weight: 600; }
|
|
145
|
+
.tb-menu button i { font-size: 0.72rem; opacity: .62; font-style: normal; }
|
|
146
|
+
|
|
147
|
+
.tb-block { min-width: 66px; }
|
|
148
|
+
.tb-size { min-width: 46px; padding-left: 0.3rem; justify-content: center; }
|
|
149
|
+
.tb-lang { min-width: 82px; }
|
|
150
|
+
|
|
151
|
+
@media (max-width: 640px) {
|
|
152
|
+
.tb-tile { min-width: 52px; padding: 7px 7px 6px; }
|
|
153
|
+
.tb-btn { min-width: 40px; height: 40px; }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* ── 글 제목 — 편집 전용 ──
|
|
157
|
+
모양은 전부 core 의 prose.css 가 갖는다(발행 페이지와 같은 파일).
|
|
158
|
+
여기 있는 것은 **편집 중에만 있는 것**뿐이다. */
|
|
159
|
+
.post-head.is-editing { margin-top: 6.2rem; margin-bottom: 6rem; }
|
|
160
|
+
/* 배너 모드에서는 위 여백을 안 준다 — prose.css 의 규칙과 같은 뜻이다 */
|
|
161
|
+
.post-head.is-editing[data-banner='1'] { margin-top: 0; }
|
|
162
|
+
/* 밑줄은 header 가 갖는다(prose.css) — 포커스 표시도 그 선을 진하게 한다.
|
|
163
|
+
제목이 사진 위에 없으므로 배너 유무를 가르지 않는다. */
|
|
164
|
+
.post-head.is-editing:focus-within { border-bottom-color: #1a1a1a; }
|
|
165
|
+
/* 안내 글씨는 **안내처럼** — 제목과 같은 굵기·검정이면 이미 쓴 제목으로 읽힌다.
|
|
166
|
+
contenteditable 이라 ::placeholder 가 없다. 빈 상태에서만 ::before 로 그린다. */
|
|
167
|
+
.post-head.is-editing .post-title:empty::before {
|
|
168
|
+
content: attr(data-placeholder); color: #c7c4bd; letter-spacing: -0.02em;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* 제목 도구 — 전부 absolute 라 제목의 기하를 건드리지 않는다 */
|
|
172
|
+
.ph-tools, .ph-actions, .ph-badge, .ph-hint { position: absolute; z-index: 2; }
|
|
173
|
+
/* 배너 넣기 버튼은 제목 **위쪽 빈 자리**에 둔다 — 제목 첫 줄과 나란히 두면
|
|
174
|
+
글자에 붙어 보이고, 제목을 길게 쓰면 겹친다.
|
|
175
|
+
위 여백이 6.2rem 이라 -40px 은 그 안에 넉넉히 들어간다. */
|
|
176
|
+
.ph-tools { top: -40px; right: 0; display: flex; gap: 4px; }
|
|
177
|
+
.ph-tools button, .ph-actions button, .ph-badge {
|
|
178
|
+
display: inline-flex; align-items: center; gap: 4px; cursor: pointer;
|
|
179
|
+
border: 1px solid #e0ded8; background: #fff; border-radius: 7px;
|
|
180
|
+
min-height: 30px; padding: 0 9px; font-size: 0.76rem; color: #3a3a3a;
|
|
181
|
+
}
|
|
182
|
+
.ph-tools button:hover { background: #f4f3ef; }
|
|
183
|
+
.ph-tools button:disabled { opacity: .45; cursor: default; }
|
|
184
|
+
/* 배너 위 버튼은 사진 위에 뜬다 — 흰 배경으로는 사진이 밝을 때 묻힌다 */
|
|
185
|
+
.post-head[data-banner='1'] .ph-actions button,
|
|
186
|
+
.post-head[data-banner='1'] .ph-badge {
|
|
187
|
+
border-color: rgba(255,255,255,.34); background: rgba(0,0,0,.44); color: #fff;
|
|
188
|
+
-webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
|
|
189
|
+
}
|
|
190
|
+
.post-head[data-banner='1'] .ph-actions button:hover { background: rgba(0,0,0,.62); }
|
|
191
|
+
.ph-badge { top: 10px; left: 10px; }
|
|
192
|
+
.ph-badge[aria-pressed='false'] { opacity: .62; }
|
|
193
|
+
.ph-actions { top: 10px; right: 10px; display: flex; gap: 6px; }
|
|
194
|
+
.ph-actions .is-go { background: #1f9d55 !important; border-color: #1f9d55 !important; color: #fff !important; }
|
|
195
|
+
/* 안내문은 **사진 가운데**에 뜬다 — header 기준이면 제목까지 포함한 가운데라
|
|
196
|
+
사진 아래쪽 여백에 걸린다. `.post-cover` 가 position:relative 다. */
|
|
197
|
+
.ph-hint {
|
|
198
|
+
left: 0; right: 0; top: 50%; transform: translateY(-50%);
|
|
199
|
+
margin: 0; text-align: center; color: #fff; font-size: 0.95rem;
|
|
200
|
+
text-shadow: 0 1px 3px rgba(0,0,0,.5); pointer-events: none;
|
|
201
|
+
}
|
|
202
|
+
.post-head.is-moving .post-cover { touch-action: none; cursor: grab; }
|
|
203
|
+
.post-head.is-moving .post-cover:active { cursor: grabbing; }
|
|
204
|
+
|
|
205
|
+
/* ── 색 팔레트 ── */
|
|
206
|
+
.cp { position: absolute; top: calc(100% + 6px); left: 0; z-index: 70;
|
|
207
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 12px; padding: 10px;
|
|
208
|
+
box-shadow: 0 10px 30px rgba(0,0,0,.14); }
|
|
209
|
+
.cp-head { font-size: 0.72rem; color: #8a8a8a; margin: 0 2px 7px; letter-spacing: -0.02em; }
|
|
210
|
+
.cp-grid { display: flex; gap: 4px; align-items: flex-start; }
|
|
211
|
+
.cp-col { display: flex; flex-direction: column; gap: 4px; }
|
|
212
|
+
.cp-cell { width: 19px; height: 19px; border-radius: 4px; border: 1px solid rgba(0,0,0,.10);
|
|
213
|
+
cursor: pointer; padding: 0; flex: none; }
|
|
214
|
+
.cp-cell:hover { transform: scale(1.18); border-color: rgba(0,0,0,.28); }
|
|
215
|
+
.cp-cell.is-on { box-shadow: 0 0 0 2px #fff, 0 0 0 3.5px #1a1a1a; }
|
|
216
|
+
.cp-none { background: #fff; display: flex; align-items: center; justify-content: center;
|
|
217
|
+
align-self: flex-start; }
|
|
218
|
+
.cp-none svg { width: 15px; height: 15px; stroke: #e03131; stroke-width: 1.8; }
|
|
219
|
+
|
|
220
|
+
/* ── 선택 시 뜨는 버블 툴바 ── */
|
|
221
|
+
/* 인용 안에서는 인용 모양 일곱 개가 앞에 붙어 줄이 길어진다 — 좁은 화면에서는 옆으로 굴린다.
|
|
222
|
+
(여기에 overflow 를 걸 수 있게 된 건 팝오버들이 전부 포털로 빠져나간 뒤다.
|
|
223
|
+
안 그랬으면 한 축만 auto 여도 나머지 축이 같이 잘려 드롭다운이 통째로 사라진다.) */
|
|
224
|
+
.bub { display: flex; align-items: center; gap: 2px; background: #fff;
|
|
225
|
+
border: 1px solid #e0ded8; border-radius: 10px; padding: 4px 5px;
|
|
226
|
+
box-shadow: 0 6px 22px rgba(0,0,0,.15);
|
|
227
|
+
max-width: min(92vw, 780px); overflow-x: auto; scrollbar-width: thin; }
|
|
228
|
+
.bub > * { flex: none; }
|
|
229
|
+
.bub button { display: inline-flex; align-items: center; justify-content: center; gap: 3px;
|
|
230
|
+
min-width: 30px; height: 30px; padding: 0 6px; border: 0; background: transparent;
|
|
231
|
+
border-radius: 7px; color: #3a3a3a; cursor: pointer; }
|
|
232
|
+
.bub button:hover { background: #f4f3ef; }
|
|
233
|
+
.bub button.on { background: #1a1a1a; color: #fff; }
|
|
234
|
+
.bub-div { width: 1px; height: 18px; background: #e6e4de; margin: 0 3px; flex: none; }
|
|
235
|
+
.bub-size { min-width: 44px; }
|
|
236
|
+
.bub-anchor { position: relative; display: flex; }
|
|
237
|
+
.bub-letter { font-size: 0.82rem; font-weight: 700; line-height: 1; }
|
|
238
|
+
.bub-swatch { width: 12px; height: 12px; border-radius: 3px; border: 1px solid rgba(0,0,0,.14); }
|
|
239
|
+
.cp-sub { font-size: 0.7rem; color: #9a9a9a; margin: 2px 2px 5px; }
|
|
240
|
+
.cp-recent { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 9px;
|
|
241
|
+
padding-bottom: 9px; border-bottom: 1px solid #efedE8; max-width: 240px; }
|
|
242
|
+
|
|
243
|
+
/* ══ 표 조작 오버레이 — 네이버 구조 참고, 색은 초록 대신 차분한 남색 계열 ══ */
|
|
244
|
+
.tt-layer { position: fixed; inset: 0; pointer-events: none; z-index: 40; }
|
|
245
|
+
.tt-layer > *, .tt-layer button { pointer-events: auto; }
|
|
246
|
+
|
|
247
|
+
.tt-corner { position: fixed; width: 12px; height: 12px; padding: 0; cursor: pointer;
|
|
248
|
+
background: #e8e6e0; border: 1px solid #d8d6d0; border-radius: 3px 0 0 0; }
|
|
249
|
+
.tt-corner:hover { background: var(--tt-accent, #4c6ef5); border-color: var(--tt-accent, #4c6ef5); }
|
|
250
|
+
|
|
251
|
+
.tt-band { position: fixed; padding: 0; cursor: pointer; border: 1px solid #e2e0da;
|
|
252
|
+
background: #eeece6; border-radius: 2px; }
|
|
253
|
+
.tt-band:hover { background: #4c6ef5; border-color: #4c6ef5; }
|
|
254
|
+
|
|
255
|
+
.tt-plus { position: fixed; width: 18px; height: 18px; padding: 0; cursor: pointer;
|
|
256
|
+
display: flex; align-items: center; justify-content: center;
|
|
257
|
+
background: #fff; color: #8a8a8a; border: 1px solid #d8d6d0; border-radius: 50%;
|
|
258
|
+
opacity: 0; transition: opacity .12s, background .12s, color .12s; }
|
|
259
|
+
.tt-layer:hover .tt-plus { opacity: 1; }
|
|
260
|
+
.tt-plus:hover { background: #4c6ef5; color: #fff; border-color: #4c6ef5; opacity: 1; }
|
|
261
|
+
|
|
262
|
+
.tt-trash { position: fixed; width: 38px; height: 34px; padding: 0; cursor: pointer;
|
|
263
|
+
display: flex; align-items: center; justify-content: center;
|
|
264
|
+
background: #fff; color: #c92a2a; border: 1px solid #e0ded8; border-radius: 9px;
|
|
265
|
+
box-shadow: 0 4px 16px rgba(0,0,0,.14); }
|
|
266
|
+
.tt-trash:hover { background: #fff5f5; border-color: #ffc9c9; }
|
|
267
|
+
|
|
268
|
+
.tt-anchor { position: fixed; }
|
|
269
|
+
.tt-more { width: 26px; height: 26px; padding: 0; cursor: pointer; margin-left: 5px;
|
|
270
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 7px; color: #5b5b5b;
|
|
271
|
+
box-shadow: 0 3px 12px rgba(0,0,0,.12); line-height: 1; }
|
|
272
|
+
.tt-more:hover { background: #f4f3ef; }
|
|
273
|
+
.tt-menu { position: absolute; top: 30px; left: 0; min-width: 152px; z-index: 80;
|
|
274
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 10px; padding: 5px;
|
|
275
|
+
box-shadow: 0 10px 28px rgba(0,0,0,.15); display: flex; flex-direction: column; }
|
|
276
|
+
.tt-menu button { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
|
|
277
|
+
border: 0; background: transparent; border-radius: 7px; padding: 7px 9px; cursor: pointer;
|
|
278
|
+
color: #2a2a2a; font-size: 0.83rem; }
|
|
279
|
+
.tt-menu button:hover { background: #f4f3ef; }
|
|
280
|
+
.tt-menu button.danger { color: #c92a2a; }
|
|
281
|
+
.tt-menu button.danger:hover { background: #fff5f5; }
|
|
282
|
+
.tt-menu-div { height: 1px; background: #efedE8; margin: 4px 2px; }
|
|
283
|
+
|
|
284
|
+
/* 선택된 셀 — 네이버 초록 대신 차분한 남색 틴트 */
|
|
285
|
+
.editor-surface .selectedCell { position: relative; background: rgba(76,110,245,.10); }
|
|
286
|
+
.editor-surface .selectedCell::after { content: ''; position: absolute; inset: 0;
|
|
287
|
+
border: 1px solid rgba(76,110,245,.35); pointer-events: none; }
|
|
288
|
+
|
|
289
|
+
/* 표 너비 슬라이더 */
|
|
290
|
+
.tt-width { position: fixed; display: flex; align-items: center; gap: 8px;
|
|
291
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 9px; padding: 5px 11px;
|
|
292
|
+
box-shadow: 0 4px 16px rgba(0,0,0,.11); font-size: 0.76rem; color: #5b5b5b; }
|
|
293
|
+
.tt-width input[type='range'] { width: 104px; accent-color: #4c6ef5; }
|
|
294
|
+
.tt-width b { color: #1a1a1a; font-variant-numeric: tabular-nums; min-width: 2.2em; text-align: right; }
|
|
295
|
+
.tt-width i { font-style: normal; color: #9a9a9a; }
|
|
296
|
+
.prose table { table-layout: fixed; }
|
|
297
|
+
|
|
298
|
+
.tt-width-div { width: 1px; height: 18px; background: #e6e4de; margin: 0 2px; }
|
|
299
|
+
.tt-bg-anchor { position: relative; display: flex; }
|
|
300
|
+
.tt-bg { width: 28px; height: 26px; padding: 0; display: flex; align-items: center; justify-content: center;
|
|
301
|
+
border: 0; background: transparent; border-radius: 7px; cursor: pointer; color: #3a3a3a; }
|
|
302
|
+
.tt-bg:hover { background: #f2f1ec; }
|
|
303
|
+
|
|
304
|
+
/* 표 폭은 감싸개가 갖는다 — 라이브러리가 table 인라인 width 를 지우므로 !important 로 고정 */
|
|
305
|
+
.editor-surface .tableWrapper > table,
|
|
306
|
+
.prose .tableWrapper > table { min-width: 0 !important; width: 100% !important; }
|
|
307
|
+
|
|
308
|
+
/* 아랫줄 안의 인라인 폭 슬라이더 (표) */
|
|
309
|
+
.tb-width-inline { display: inline-flex; align-items: center; gap: 6px; flex: none;
|
|
310
|
+
font-size: 0.76rem; color: #5b5b5b; white-space: nowrap; }
|
|
311
|
+
.tb-width-inline input[type='range'] { width: 92px; accent-color: #4c6ef5; }
|
|
312
|
+
.tb-width-inline b { color: #1a1a1a; font-variant-numeric: tabular-nums; min-width: 2.1em; text-align: right; }
|
|
313
|
+
.tb-width-inline i { font-style: normal; color: #9a9a9a; }
|
|
314
|
+
.tb-phone-only { display: none; }
|
|
315
|
+
@media (max-width: 640px) { .tb-phone-only { display: inline-flex; } }
|
|
316
|
+
|
|
317
|
+
/* ── 변형 고르기 메뉴 (구분선·인용구·표 프리셋·목록 모양 공용) ── */
|
|
318
|
+
.vm { position: absolute; top: calc(100% + 6px); left: 0; z-index: 70;
|
|
319
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 11px; padding: 6px;
|
|
320
|
+
box-shadow: 0 10px 30px rgba(0,0,0,.15); display: grid; gap: 4px; }
|
|
321
|
+
.vm-col-1 { grid-template-columns: 1fr; min-width: 214px; }
|
|
322
|
+
/* 폭을 안 주면 격자 칸이 미리보기의 max-content 로 벌어져 팝오버가 화면을 가로지른다. 열 수마다 폭을 못 박는다. */
|
|
323
|
+
.vm-col-3 { grid-template-columns: repeat(3, 1fr); width: 264px; }
|
|
324
|
+
.vm-col-4 { grid-template-columns: repeat(4, 1fr); width: 340px; }
|
|
325
|
+
|
|
326
|
+
.vm-item { display: flex; align-items: center; gap: 10px; text-align: left;
|
|
327
|
+
border: 1px solid transparent; background: transparent; border-radius: 8px;
|
|
328
|
+
padding: 6px 8px; cursor: pointer; color: #2a2a2a; min-height: 40px; }
|
|
329
|
+
.vm-col-4 .vm-item, .vm-col-3 .vm-item { flex-direction: column; gap: 3px; padding: 7px 4px; text-align: center; }
|
|
330
|
+
.vm-item:hover { background: #f4f3ef; }
|
|
331
|
+
.vm-item.is-on { border-color: #1a1a1a; background: #f7f6f2; }
|
|
332
|
+
|
|
333
|
+
/* 미리보기 — 본문과 같은 CSS 가 걸리도록 .prose 를 쓰되, 지면 여백만 지운다 */
|
|
334
|
+
.vm-preview { display: block; flex: none; pointer-events: none;
|
|
335
|
+
background: transparent; overflow: hidden; }
|
|
336
|
+
.vm-preview > * { margin: 0 !important; max-width: none !important; }
|
|
337
|
+
/* 프레임 두 종은 갈고리 자리(2.4em 안팎)를 padding 으로 비워 둔다 —
|
|
338
|
+
66px 짜리 미리보기에서는 그 여백이 글자를 세로로 쪼갠다. 타일에서만 좁힌다. */
|
|
339
|
+
.vm-preview blockquote[data-variant='frame'],
|
|
340
|
+
.vm-preview blockquote[data-variant='framebold'] { padding: 0.9em !important; }
|
|
341
|
+
.vm-col-1 .vm-preview { width: 66px; }
|
|
342
|
+
/* 높이를 34px 로 **고정**하면 3줄짜리 표 미리보기가 위아래로 잘려 무슨 스타일인지 안 보인다. 구분선처럼 한 줄짜리는 그대로 34px 이고, 표는 필요한 만큼 늘어난다. */
|
|
343
|
+
.vm-col-4 .vm-preview, .vm-col-3 .vm-preview { width: 100%; min-height: 34px;
|
|
344
|
+
display: flex; align-items: center; justify-content: center; }
|
|
345
|
+
/* 격자형 미리보기의 자식은 칸 폭을 채워야 한다 —
|
|
346
|
+
그러지 않으면 width:100% 짜리 모양(긴 선·굵은 선)이 기준을 못 잡아 0px 이 된다 */
|
|
347
|
+
.vm-col-4 .vm-preview > *, .vm-col-3 .vm-preview > * { width: 100%; }
|
|
348
|
+
/* 미리보기 칸 안에서는 본문용 비율 크기를 칸 폭에 맞춰 줄인다.
|
|
349
|
+
(본문에서 clamp(...) 로 커지게 해 둔 값이 작은 칸을 뚫고 나간다) */
|
|
350
|
+
.vm-preview hr::after { max-width: 100% !important; }
|
|
351
|
+
.vm-preview hr[data-kind='wave']::after,
|
|
352
|
+
.vm-preview hr[data-kind='diamond']::after,
|
|
353
|
+
.vm-preview hr[data-kind='slash']::after,
|
|
354
|
+
.vm-preview hr[data-kind='dots']::after,
|
|
355
|
+
.vm-preview hr[data-kind='short']::after { width: 88% !important; }
|
|
356
|
+
/* 점 세 개는 폭이 60px 로 **고정**이라 줄이면 안 된다 — 줄이면 점이 두 개로 보인다 */
|
|
357
|
+
.vm-preview hr[data-kind='dots3']::after { width: 60px !important; }
|
|
358
|
+
|
|
359
|
+
/* ── 메뉴 바닥의 축 줄 (구분선 두께·색) ── */
|
|
360
|
+
.vm-axis { grid-column: 1 / -1; display: flex; align-items: center; gap: 4px;
|
|
361
|
+
padding: 5px 6px; border-top: 1px solid #eceae4; }
|
|
362
|
+
/* 이름은 **줄바꿈되면 안 된다** — 「모서리」가 26px 폭에서 두 줄로 쪼개졌다 */
|
|
363
|
+
.vm-axis-name { font-size: 0.72rem; color: #8a8a8a; min-width: 34px; flex: none; white-space: nowrap; }
|
|
364
|
+
.vm-chip { border: 1px solid #e0ded8; background: #fff; border-radius: 6px;
|
|
365
|
+
padding: 3px 8px; font-size: 0.74rem; color: #3a3a3a; cursor: pointer; }
|
|
366
|
+
.vm-chip:hover:not(:disabled) { background: #f4f3ef; }
|
|
367
|
+
.vm-chip.is-on { background: #1a1a1a; border-color: #1a1a1a; color: #fff; }
|
|
368
|
+
.vm-chip:disabled { opacity: .38; cursor: default; }
|
|
369
|
+
/* 색 견본 — 값이 곧 그림이라 글씨를 안 쓴다 */
|
|
370
|
+
.vm-dot { border: 1px solid transparent; background: none; border-radius: 50%;
|
|
371
|
+
padding: 2px; cursor: pointer; line-height: 0; }
|
|
372
|
+
.vm-dot > i { display: block; width: 15px; height: 15px; border-radius: 50%;
|
|
373
|
+
box-shadow: inset 0 0 0 1px rgba(0,0,0,.10); }
|
|
374
|
+
.vm-dot.is-on { border-color: #1a1a1a; }
|
|
375
|
+
|
|
376
|
+
/* 구역 제목 — 격자 한 줄을 통째로 쓴다. 첫 줄이면 위 여백을 뺀다(판이 뜨는 자리가 밀린다) */
|
|
377
|
+
.vm-head { grid-column: 1 / -1; margin: 8px 4px 2px; display: flex; align-items: baseline; gap: 6px; }
|
|
378
|
+
.vm-head:first-child { margin-top: 2px; }
|
|
379
|
+
.vm-head b { font-size: 0.74rem; font-weight: 600; color: #1a1a1a; }
|
|
380
|
+
.vm-head i { font-size: 0.7rem; font-style: normal; color: #9a958c; }
|
|
381
|
+
.vm-head + .vm-item { margin-top: 0; }
|
|
382
|
+
|
|
383
|
+
.vm-text { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
|
|
384
|
+
.vm-text b { font-size: 0.83rem; font-weight: 600; }
|
|
385
|
+
.vm-text i { font-size: 0.72rem; opacity: .62; font-style: normal; }
|
|
386
|
+
.vm-col-4 .vm-text b, .vm-col-3 .vm-text b { font-size: 0.72rem; font-weight: 500; }
|
|
387
|
+
|
|
388
|
+
@media (max-width: 640px) {
|
|
389
|
+
/* 폰에서는 바텀시트로 */
|
|
390
|
+
.vm { position: fixed; inset: auto 0 0 0; top: auto; border-radius: 14px 14px 0 0;
|
|
391
|
+
max-height: 62vh; overflow-y: auto; padding: 10px 10px calc(10px + env(safe-area-inset-bottom)); }
|
|
392
|
+
.vm-col-4 { width: auto; }
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* ── 본체 + ▾ 로 갈린 타일 (네이버 구조) ── */
|
|
396
|
+
.tb-split { display: inline-flex; align-items: stretch; flex: none; border-radius: 10px;
|
|
397
|
+
border: 1px solid #e6e4de; background: #fff; overflow: hidden; }
|
|
398
|
+
.tb-split:hover { border-color: #d8d6d0; }
|
|
399
|
+
.tb-split .tb-split-main { border-radius: 0; padding-right: 4px; min-width: 50px; border: 0; }
|
|
400
|
+
.tb-split-caret { display: flex; align-items: center; justify-content: center; width: 24px;
|
|
401
|
+
border: 0; border-left: 1px solid #eeece6; border-radius: 0;
|
|
402
|
+
background: #fbfaf8; color: #5b5b5b; cursor: pointer; padding: 0; }
|
|
403
|
+
.tb-split-caret:hover { background: #efedE8; color: #1a1a1a; }
|
|
404
|
+
.tb-split-caret .tb-caret { border-top-width: 5px; border-left-width: 4px; border-right-width: 4px; opacity: .8; }
|
|
405
|
+
.tb-split.is-open { border-color: #1a1a1a; }
|
|
406
|
+
.tb-split.is-open .tb-split-caret { background: #1a1a1a; color: #fff; border-left-color: #1a1a1a; }
|
|
407
|
+
.tb-split.is-on .tb-split-main { background: #1a1a1a; color: #fff; }
|
|
408
|
+
.tb-split.is-on .tb-split-caret { border-left-color: rgba(255,255,255,.25); }
|
|
409
|
+
@media (max-width: 640px) { .tb-split-caret { width: 22px; } }
|
|
410
|
+
|
|
411
|
+
/* 아랫줄 안의 입력칸 (코드 블록 제목·강조 줄) */
|
|
412
|
+
.tb-input { height: 30px; border: 1px solid #e0ded8; border-radius: 7px; background: #fff;
|
|
413
|
+
font-size: 0.76rem; padding: 0 8px; color: #2a2a2a; font-family: inherit; flex: none; }
|
|
414
|
+
.tb-input:focus { outline: none; border-color: #1a1a1a; }
|
|
415
|
+
.tb-input.is-bad { border-color: #e8a0a0; background: #fff8f8; }
|
|
416
|
+
.tb-code-title { width: 150px; }
|
|
417
|
+
.tb-lang { width: 108px; }
|
|
418
|
+
.tb-code-note { width: 260px; }
|
|
419
|
+
.tb-code-note:disabled { background: #f7f6f3; color: #b0aca2; }
|
|
420
|
+
@media (max-width: 640px) {
|
|
421
|
+
.tb-input { height: 40px; }
|
|
422
|
+
.tb-code-title { width: 120px; }
|
|
423
|
+
.tb-code-note { width: 150px; }
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/* 선택된 객체 위에 뜨는 바 */
|
|
427
|
+
.obj-float { position: fixed; z-index: 45; display: flex; align-items: center; gap: 2px;
|
|
428
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 10px; padding: 4px 5px;
|
|
429
|
+
box-shadow: 0 6px 22px rgba(0,0,0,.15); white-space: nowrap; }
|
|
430
|
+
.obj-float .tb-btn { min-width: 30px; height: 30px; }
|
|
431
|
+
.obj-float .tb-div { height: 18px; margin: 0 3px; }
|
|
432
|
+
@media (pointer: coarse) { .obj-float .tb-btn { min-width: 40px; height: 40px; } }
|
|
433
|
+
|
|
434
|
+
/* 좌측 여백의 삽입 핸들 */
|
|
435
|
+
.ins-anchor { position: fixed; z-index: 35; }
|
|
436
|
+
.ins-btn { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;
|
|
437
|
+
border: 1px solid #e0ded8; background: #fff; border-radius: 8px; color: #8a8a8a; cursor: pointer;
|
|
438
|
+
opacity: .45; transition: opacity .12s, color .12s, border-color .12s; }
|
|
439
|
+
.ins-anchor:hover .ins-btn, .ins-btn:focus-visible { opacity: 1; color: #1a1a1a; border-color: #c9c6bd; }
|
|
440
|
+
.ins-menu { position: absolute; top: 32px; left: 0; min-width: 190px; }
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
/* ══ 폰: 윗줄을 접는다 ══
|
|
444
|
+
실측 근거 — 헤더 45 + 윗줄 46 + 아랫줄 50 = 141px 고정.
|
|
445
|
+
667px 화면에서 키보드(약 260px)가 뜨면 본문이 260px 밖에 안 남아 글을 못 쓴다.
|
|
446
|
+
윗줄을 시트로 접으면 툴바가 50px 대로 내려간다. */
|
|
447
|
+
@media (max-width: 640px) {
|
|
448
|
+
.toolbar2 .tb-row-insert {
|
|
449
|
+
position: fixed; inset: auto 0 0 0; z-index: 80;
|
|
450
|
+
display: none; flex-wrap: wrap; gap: 6px; justify-content: flex-start;
|
|
451
|
+
background: #fff; border-top: 1px solid #e6e4de; border-bottom: 0;
|
|
452
|
+
border-radius: 14px 14px 0 0; box-shadow: 0 -8px 28px rgba(0,0,0,.14);
|
|
453
|
+
padding: 12px 10px calc(12px + env(safe-area-inset-bottom));
|
|
454
|
+
max-height: 55vh; overflow-y: auto;
|
|
455
|
+
}
|
|
456
|
+
.toolbar2.sheet-open .tb-row-insert { display: flex; }
|
|
457
|
+
.toolbar2 .tb-row-insert > * { flex: 0 0 calc(25% - 5px); }
|
|
458
|
+
.toolbar2 .tb-tile { width: 100%; min-height: 62px; }
|
|
459
|
+
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/* 시트를 여는 버튼 — 기본은 숨김, 폰에서만 보인다.
|
|
463
|
+
(기본 규칙을 미디어쿼리 뒤에 두면 특이도가 같아 나중 것이 이겨 폰에서도 숨는다) */
|
|
464
|
+
.tb-sheet-btn { display: none; align-items: center; justify-content: center;
|
|
465
|
+
min-width: 40px; height: 40px; flex: none; margin-right: 4px;
|
|
466
|
+
border: 1px solid #e0ded8; background: #fff; border-radius: 8px; color: #1a1a1a; cursor: pointer; }
|
|
467
|
+
.tb-sheet-backdrop { display: none; }
|
|
468
|
+
@media (max-width: 640px) {
|
|
469
|
+
.tb-sheet-btn { display: inline-flex; }
|
|
470
|
+
.tb-sheet-backdrop { display: block; position: fixed; inset: 0; z-index: 79; background: rgba(0,0,0,.18); }
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* 타일 라벨 밑에 현재 고른 모양 이름을 작게 — 22px 아이콘으로는 모양이 안 읽힌다.
|
|
474
|
+
(메뉴 안에서는 크게 보이므로 거기서는 진짜 렌더 미리보기를 그대로 쓴다) */
|
|
475
|
+
.tb-tile-sub { display: block; font-size: 0.6rem; color: #9a9a9a; letter-spacing: -0.04em;
|
|
476
|
+
max-width: 56px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
477
|
+
.tb-tile.is-on .tb-tile-sub, .tb-split.is-on .tb-tile-sub { color: rgba(255,255,255,.7); }
|
|
478
|
+
|
|
479
|
+
/* 드롭다운을 fixed 로 띄울 때는 CSS 의 absolute 좌표를 쓰지 않는다.
|
|
480
|
+
(툴바 줄의 overflow 가 세로까지 잘라내 absolute 로는 화면에 안 나왔다) */
|
|
481
|
+
.vm.is-fixed { position: fixed; top: auto; left: auto; }
|
|
482
|
+
|
|
483
|
+
/* 사진 업로드 진행 — 화면 오른쪽 아래에 잠깐 뜬다 */
|
|
484
|
+
.up-chip {
|
|
485
|
+
position: fixed; right: 18px; bottom: 60px; z-index: 60;
|
|
486
|
+
background: #1c1d21; color: #f2f2f2; border-radius: 999px;
|
|
487
|
+
padding: 8px 16px; font-size: 0.8rem; letter-spacing: -0.01em;
|
|
488
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, .22);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/* 글자색 버튼 — 글자 버블의 것과 같은 모양 */
|
|
492
|
+
.tb-color { gap: 3px; }
|
|
493
|
+
.tb-color-swatch { width: 11px; height: 11px; border-radius: 3px; border: 1px solid rgba(0,0,0,.18); }
|
|
494
|
+
.tb-color-letter { font-size: 0.82rem; font-weight: 700; line-height: 1; }
|
|
495
|
+
|
|
496
|
+
/* 행 높이 손잡이 — 행 경계 위에 얇게 깔린다. 평소엔 안 보이고 올려놓으면 파란 선이 뜬다 */
|
|
497
|
+
.tt-rowsize {
|
|
498
|
+
position: fixed; height: 7px; cursor: row-resize; z-index: 41;
|
|
499
|
+
touch-action: none;
|
|
500
|
+
}
|
|
501
|
+
.tt-rowsize::after {
|
|
502
|
+
content: ''; position: absolute; left: 0; right: 0; top: 2px; height: 3px;
|
|
503
|
+
background: #4c6ef5; opacity: 0; transition: opacity .12s;
|
|
504
|
+
}
|
|
505
|
+
.tt-rowsize:hover::after { opacity: 1; }
|
|
506
|
+
|
|
507
|
+
/* 변형 메뉴 아래 덧줄 (표 테두리의 「선 색」 등) */
|
|
508
|
+
.vm-footer { grid-column: 1 / -1; border-top: 1px solid #eceae4; margin-top: 4px; padding-top: 4px; position: relative; }
|
|
509
|
+
.vm-footer > button {
|
|
510
|
+
display: flex; align-items: center; gap: 6px; width: 100%;
|
|
511
|
+
border: 0; background: none; cursor: pointer; padding: 7px 9px; border-radius: 7px;
|
|
512
|
+
font-size: 0.78rem; color: #3a3a3a;
|
|
513
|
+
}
|
|
514
|
+
.vm-footer > button:hover { background: #f2f1ec; }
|
|
515
|
+
/* 목록 모양 덧줄 — 세 모양을 나란히. 네이버엔 없는 우리 기능이라 본 목록 아래에 붙인다. */
|
|
516
|
+
.vm-markers { display: flex; gap: 4px; }
|
|
517
|
+
.vm-markers > button { flex: 1; justify-content: center; padding: 4px; border: 1px solid #eceae4; }
|
|
518
|
+
.vm-markers > button.is-on { border-color: #1a1a1a; background: #f7f6f2; }
|
|
519
|
+
.vm-markers .vm-preview { width: auto; }
|
|
520
|
+
|
|
521
|
+
/* 목록 메뉴 — 아이콘 셋을 세로로 (네이버 블로그와 같은 모양) */
|
|
522
|
+
.tb-listmenu { position: absolute; left: 0; top: calc(100% + 6px); z-index: 60;
|
|
523
|
+
background: #fff; border: 1px solid #e6e4de; border-radius: 10px; padding: 5px;
|
|
524
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.1); display: flex; flex-direction: column; gap: 2px; width: 46px; }
|
|
525
|
+
.tb-listmenu.is-fixed { top: auto; }
|
|
526
|
+
.tb-listmenu > button { display: flex; align-items: center; justify-content: center;
|
|
527
|
+
width: 36px; height: 34px; border: 0; background: none; cursor: pointer; border-radius: 7px; color: #3a3a3a; }
|
|
528
|
+
.tb-listmenu > button:hover { background: #f4f3ef; }
|
|
529
|
+
.tb-listmenu > button.is-on { background: #1a1a1a; color: #fff; }
|
|
530
|
+
/* 모양 덧줄 — 우리 기능. 아이콘 셋을 밀어내지 않게 아래에 얇게 */
|
|
531
|
+
.tb-listmarkers { border-top: 1px solid #eceae4; margin-top: 3px; padding-top: 3px;
|
|
532
|
+
display: flex; flex-direction: column; gap: 2px; }
|
|
533
|
+
.tb-listmarkers > button { display: flex; align-items: center; justify-content: center;
|
|
534
|
+
width: 36px; height: 28px; border: 1px solid transparent; background: none; cursor: pointer;
|
|
535
|
+
border-radius: 6px; font-size: 0.72rem; color: #5b5b5b; line-height: 1; }
|
|
536
|
+
.tb-listmarkers > button:hover { background: #f4f3ef; }
|
|
537
|
+
.tb-listmarkers > button.is-on { border-color: #1a1a1a; background: #f7f6f2; color: #1a1a1a; }
|
|
538
|
+
|
|
539
|
+
/* 글꼴 — 고른 이름을 그 글꼴로 보여 준다 */
|
|
540
|
+
.bub-font { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
|
|
541
|
+
max-width: 110px; overflow: hidden; font-size: 0.82rem; }
|
|
542
|
+
.tb-font { min-width: 96px; }
|
|
543
|
+
/* 그리는 방식 칸 — 「글로 쓰기」와 「캔버스로 그리기」는 길이가 달라
|
|
544
|
+
고를 때마다 오른쪽 도구가 통째로 밀린다. 글꼴 칸과 같은 처방을 쓴다. */
|
|
545
|
+
.tb-dgmode { min-width: 122px; }
|
|
546
|
+
|
|
547
|
+
/* ── 고르는 메뉴 (글꼴·문단·크기·줄간격·언어 공용) ──
|
|
548
|
+
`<select>` 를 안 쓰므로 OS 메뉴가 아니라 우리 CSS 가 그린다.
|
|
549
|
+
목록이 길어도(크기 16줄·언어 27줄) 화면을 넘지 않게 스스로 스크롤한다. */
|
|
550
|
+
.pm { position: absolute; top: calc(100% + 6px); left: 0; z-index: 70;
|
|
551
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 10px; padding: 5px;
|
|
552
|
+
box-shadow: 0 10px 30px rgba(0,0,0,.14);
|
|
553
|
+
max-height: min(58vh, 430px); overflow-y: auto; overscroll-behavior: contain; }
|
|
554
|
+
.pm-item { display: block; width: 100%; text-align: left; border: 0; background: none;
|
|
555
|
+
cursor: pointer; padding: 9px 10px; border-radius: 7px; font-size: 0.92rem; color: #1a1a1a;
|
|
556
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
557
|
+
.pm-center .pm-item { text-align: center; }
|
|
558
|
+
/* 글꼴 고르기 — 이름이 곧 견본이라 본문보다 크게 보여 준다 */
|
|
559
|
+
.pm-fonts { width: 200px !important; }
|
|
560
|
+
.pm-fonts .pm-item { font-size: 1.18rem; line-height: 1.5; padding: 10px 12px; }
|
|
561
|
+
.pm-item:hover { background: #f4f3ef; }
|
|
562
|
+
.pm-item.is-on { background: #f7f6f2; font-weight: 600; }
|
|
563
|
+
.pm-item.is-on::after { content: '✓'; float: right; color: #1a1a1a; margin-left: 8px; }
|
|
564
|
+
.pm-center .pm-item.is-on::after { float: none; margin-left: 5px; }
|
|
565
|
+
|
|
566
|
+
/* 글자 버블 안의 고르기 칸은 버블 높이(30px)에 맞춘다 */
|
|
567
|
+
/* `.bub button` 이 padding 을 덮어써 꺾쇠가 글자 위에 겹친다 — 여기서 되돌린다 */
|
|
568
|
+
.bub .tb-select { height: 28px; font-size: 0.8rem; padding: 0 1.05rem 0 0.4rem; border-radius: 7px; }
|
|
569
|
+
|
|
570
|
+
/* ── 주소 입력 팝오버 (링크·비디오) ── */
|
|
571
|
+
.up { position: absolute; top: calc(100% + 6px); left: 0; z-index: 70;
|
|
572
|
+
background: #fff; border: 1px solid #e0ded8; border-radius: 12px; padding: 12px;
|
|
573
|
+
box-shadow: 0 10px 30px rgba(0,0,0,.14); }
|
|
574
|
+
.up-head { font-size: 0.74rem; color: #8a8a8a; margin: 0 2px 7px; letter-spacing: -0.02em; }
|
|
575
|
+
.up-input { width: 100%; height: 36px; padding: 0 10px; border-radius: 8px;
|
|
576
|
+
border: 1px solid #d9d6cf; font-size: 0.88rem; color: #1a1a1a; background: #fff; }
|
|
577
|
+
.up-input:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,.14); }
|
|
578
|
+
.up-input.is-bad { border-color: #d64545; box-shadow: 0 0 0 3px rgba(214,69,69,.13); }
|
|
579
|
+
.up-hint { margin: 7px 2px 0; font-size: 0.73rem; color: #9a9a9a; line-height: 1.45; }
|
|
580
|
+
.up-hint.is-bad { color: #c53030; }
|
|
581
|
+
.up-foot { display: flex; justify-content: flex-end; gap: 6px; margin-top: 10px; }
|
|
582
|
+
.up-foot button { height: 32px; padding: 0 14px; border-radius: 8px; cursor: pointer;
|
|
583
|
+
font-size: 0.84rem; border: 1px solid transparent; }
|
|
584
|
+
.up-cancel { background: #f4f3ef; color: #4a4a4a; }
|
|
585
|
+
.up-cancel:hover { background: #eceae4; }
|
|
586
|
+
.up-ok { background: #1a1a1a; color: #fff; }
|
|
587
|
+
.up-ok:hover { background: #333; }
|
|
588
|
+
|
|
589
|
+
/* 글자 배경색 버튼 — 「가」 뒤에 색이 깔린다 */
|
|
590
|
+
.tb-hl-letter, .bub-hl-letter {
|
|
591
|
+
padding: 1px 4px; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.10);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/* 문맥줄 버튼에 아이콘과 한글 라벨을 같이 — 아이콘만으로는 무슨 기능인지 안 읽힌다 */
|
|
595
|
+
.tb-row-format .tb-btn { gap: 4px; }
|
|
596
|
+
|
|
597
|
+
/* 인용 떠 있는 바 — 모양 일곱 개를 바로 누른다 */
|
|
598
|
+
.tb-qv { min-width: 32px; height: 32px; padding: 0 4px; color: #5b5b5b; }
|
|
599
|
+
.tb-qv.is-on { background: #1a1a1a; color: #fff; }
|
|
600
|
+
|
|
601
|
+
/* 잡힌 블록 — PickedBlock 데코레이션이 붙인다.
|
|
602
|
+
편집기 밖을 누르면 사라진다(:focus-within). 떠 있는 바도 같은 조건으로 숨는다. */
|
|
603
|
+
.ProseMirror:focus-within [data-picked] {
|
|
604
|
+
outline: 2px solid #2563eb; outline-offset: 8px; border-radius: 3px;
|
|
605
|
+
}
|
|
606
|
+
.ProseMirror:focus-within details[data-code][data-picked] { outline-offset: 4px; }
|
|
607
|
+
|
|
608
|
+
/* 넣기 줄 오른쪽 끝으로 미는 칸 */
|
|
609
|
+
.tb-right { margin-left: auto; display: flex; align-items: center; padding-right: 2px; }
|
|
610
|
+
|
|
611
|
+
/* ── 본문 폭 고르개 ── */
|
|
612
|
+
/* 직각 — 관리자의 어휘가 직각 검정 사각형이라 눌린 쪽(is-on)이 그 도형과 같아야 한다 */
|
|
613
|
+
.wt { display: inline-flex; gap: 2px; padding: 2px; border-radius: 0; background: #f2f1ec; }
|
|
614
|
+
.wt button {
|
|
615
|
+
border: 0; background: none; border-radius: 0; cursor: pointer;
|
|
616
|
+
padding: 5px 11px; font-size: 0.78rem; color: #5b5b5b; letter-spacing: -0.02em;
|
|
617
|
+
}
|
|
618
|
+
.wt button:hover { color: #1a1a1a; }
|
|
619
|
+
.wt button.is-on { background: #1a1a1a; color: #fff; }
|
|
620
|
+
|
|
621
|
+
/* ── 다이어그램 ─────────────────────────────────────────────────────────
|
|
622
|
+
그림 자체는 prose.css 가 그린다(편집·발행이 같은 것을 봐야 한다).
|
|
623
|
+
여기는 **편집할 때만 있는 것** — 껍데기, 원본 칸, 오류줄, 그리기 모달. */
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* 껍데기 — **잡았을 때만** 생긴다.
|
|
627
|
+
*
|
|
628
|
+
* 안 잡았을 때는 발행본과 글자 하나까지 같아야 하므로 아무것도 안 씌운다.
|
|
629
|
+
* 잡으면 미리보기와 원본 칸이 테두리 하나로 묶인 한 덩어리가 된다 — 소스코드 블록의
|
|
630
|
+
* `details[data-code] > .cb-bar + pre` 와 같은 어휘다.
|
|
631
|
+
*
|
|
632
|
+
* 이게 없던 동안의 화면: 빈 상자는 `width: fit-content` 라 글자만큼 쪼그라들어 가운데
|
|
633
|
+
* 떠 있고, 그 밑의 `textarea` 만 폭을 다 썼다. 한 블록 안에 폭 모델이 둘이었다.
|
|
634
|
+
*/
|
|
635
|
+
.editor-surface .dg-shell {
|
|
636
|
+
border: 1px solid #e6e4de; border-radius: 10px; overflow: hidden; background: #fff;
|
|
637
|
+
}
|
|
638
|
+
/* 껍데기가 테두리를 맡으므로 안쪽 상자는 테두리를 내려놓고 폭을 다 쓴다 */
|
|
639
|
+
.editor-surface .dg-shell > .dg-body {
|
|
640
|
+
width: auto; max-width: none; margin: 0; border: 0; border-radius: 0;
|
|
641
|
+
min-height: 132px; display: grid; place-items: center;
|
|
642
|
+
}
|
|
643
|
+
.editor-surface .dg-shell > .dg-body > .dg-svg { max-width: 100%; }
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* 잡은 표시 — **껍데기에** 건다.
|
|
647
|
+
*
|
|
648
|
+
* ⚠ 기준은 `ProseMirror-selectednode` 다. 내 `selected` prop 만 보고 `data-selected` 를
|
|
649
|
+
* 달았더니 아무것도 안 나왔다 — 캡션을 품은 노드는 클릭이 캡션의 글자 선택으로 떨어져
|
|
650
|
+
* 그 prop 이 안 켜진다. 그리고 그 클래스는 **저절로 안 붙는다**: 붙게 만드는 쪽은
|
|
651
|
+
* `DiagramView` 의 mousedown 이다. 두 곳이 맞물려야 이 규칙이 산다.
|
|
652
|
+
*/
|
|
653
|
+
.editor-surface .react-renderer.ProseMirror-selectednode .dg-shell {
|
|
654
|
+
outline: 2px solid #2563eb; outline-offset: 2px;
|
|
655
|
+
}
|
|
656
|
+
/* 껍데기가 없을 때(안 잡힘)는 옛 자리로 — 그림 상자에 건다 */
|
|
657
|
+
.editor-surface .react-renderer.ProseMirror-selectednode > .dg > .dg-body {
|
|
658
|
+
outline: 2px solid #2563eb; outline-offset: 3px;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* 빈 상태 — **기하에 영향을 주지 않는다.**
|
|
663
|
+
* 이 레포의 다른 빈 블록 안내는 전부 `position: absolute` 인 `::before` 다(prose.css).
|
|
664
|
+
* 여기만 실제 요소로 `padding: 2rem 0` 를 밀어 넣었더니 `fit-content` 상자를 부풀렸다.
|
|
665
|
+
*/
|
|
666
|
+
.dg-empty {
|
|
667
|
+
position: absolute; inset: 0; display: grid; place-items: center;
|
|
668
|
+
padding: 0 1rem; text-align: center;
|
|
669
|
+
color: #8a9099; font-size: .88rem; pointer-events: none;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/* 굽는 중 — 오른쪽 위 작은 점. 300ms 쉬고 굽기 때문에 자주 안 보인다 */
|
|
673
|
+
.dg-busy {
|
|
674
|
+
position: absolute; right: 10px; top: 10px; width: 6px; height: 6px;
|
|
675
|
+
border-radius: 50%; background: #1a1a1a; opacity: .5;
|
|
676
|
+
}
|
|
677
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
678
|
+
.dg-busy { animation: dgPulse 1s ease-in-out infinite; }
|
|
679
|
+
}
|
|
680
|
+
@keyframes dgPulse { 0%, 100% { opacity: .5 } 50% { opacity: .12 } }
|
|
681
|
+
|
|
682
|
+
/* 원본 칸 — 껍데기 아래쪽 절반. 위 경계선 하나로 미리보기와 갈린다 */
|
|
683
|
+
.dg-panel { border-top: 1px solid #ece9e2; background: #fbfbfa; }
|
|
684
|
+
.dg-bar {
|
|
685
|
+
display: flex; align-items: center; gap: 8px;
|
|
686
|
+
padding: .42rem .7rem; color: #8a867e; font-size: .74rem;
|
|
687
|
+
}
|
|
688
|
+
.dg-bar b { font-weight: 600; color: #4a463f; }
|
|
689
|
+
/* 종류 칩 — mermaidKind() 가 첫 줄로 짚어 준다 */
|
|
690
|
+
.dg-kind {
|
|
691
|
+
padding: 1px 7px; border: 1px solid #e0ddd6; border-radius: 999px;
|
|
692
|
+
background: #fff; font-size: .7rem; color: #6f6b63;
|
|
693
|
+
}
|
|
694
|
+
.dg-bar .dg-spacer { margin-left: auto; }
|
|
695
|
+
.dg-bar .tb-btn { height: 28px; min-width: 28px; }
|
|
696
|
+
|
|
697
|
+
.dg-input {
|
|
698
|
+
display: block; box-sizing: border-box; width: 100%; resize: none; overflow: hidden;
|
|
699
|
+
min-height: 4.4em; padding: 0 .8rem .7rem;
|
|
700
|
+
border: 0; outline: 0; background: transparent; color: #1a1a1a;
|
|
701
|
+
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
702
|
+
font-size: .82rem; line-height: 1.6; tab-size: 2;
|
|
703
|
+
}
|
|
704
|
+
.dg-input::placeholder { color: #b4afa5; }
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* 오류 — **한글 한 문장이 먼저**, 원문은 근거로 작게.
|
|
708
|
+
* 원문만 보여 줬더니 첫 글자를 치는 순간 빨간 영어가 떴다
|
|
709
|
+
* (`No diagram type detected matching given configuration for text: $`).
|
|
710
|
+
* 그렇다고 버리지는 않는다 — 파스 오류의 줄·열이 제일 쓸모 있다.
|
|
711
|
+
*/
|
|
712
|
+
.dg-err {
|
|
713
|
+
margin: 0; padding: .5rem .8rem .6rem;
|
|
714
|
+
border-top: 1px solid #f0e2e0; background: #fdf7f6;
|
|
715
|
+
color: #a3231b; font-size: .78rem; line-height: 1.5;
|
|
716
|
+
}
|
|
717
|
+
.dg-err code {
|
|
718
|
+
display: block; margin-top: .25rem;
|
|
719
|
+
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
720
|
+
font-size: .72rem; color: #9a7a76; word-break: break-all;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/* draw.io — 화면을 통째로 덮는다. 그리는 동안은 글이 아니라 도면이 일이다 */
|
|
724
|
+
.dio { position: fixed; inset: 0; z-index: 200; display: flex; flex-direction: column; background: #fff; }
|
|
725
|
+
.dio-bar {
|
|
726
|
+
display: flex; align-items: center; gap: .75rem; flex: none;
|
|
727
|
+
height: 44px; padding: 0 .6rem 0 1rem; background: #000; color: #fff;
|
|
728
|
+
}
|
|
729
|
+
.dio-t { font-weight: 700; font-size: .9rem; letter-spacing: -.02em; }
|
|
730
|
+
.dio-hint { margin-right: auto; font-size: .8rem; color: rgba(255,255,255,.6); }
|
|
731
|
+
.dio-x {
|
|
732
|
+
flex: none; width: 32px; height: 32px; border: 0; border-radius: 0;
|
|
733
|
+
background: transparent; color: rgba(255,255,255,.72); cursor: pointer; font-size: 1rem;
|
|
734
|
+
}
|
|
735
|
+
.dio-x:hover { background: rgba(255,255,255,.14); color: #fff; }
|
|
736
|
+
.dio-wait { position: absolute; inset: 44px 0 0; display: grid; place-items: center; margin: 0; color: #6b7280; }
|
|
737
|
+
.dio-frame { flex: 1 1 auto; width: 100%; border: 0; }
|