@dfosco/storyboard-react 4.2.0-beta.2 → 4.2.0-beta.20
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/package.json +9 -4
- package/src/AuthModal/AuthModal.jsx +6 -2
- package/src/BranchBar/BranchBar.jsx +20 -6
- package/src/BranchBar/BranchBar.module.css +13 -4
- package/src/BranchBar/useBranches.js +20 -6
- package/src/BranchBar/useBranches.test.js +68 -0
- package/src/CommandPalette/CommandPalette.jsx +478 -186
- package/src/CommandPalette/command-palette.css +142 -78
- package/src/Icon.jsx +157 -58
- package/src/Viewfinder.jsx +561 -191
- package/src/Viewfinder.module.css +434 -93
- package/src/Workspace.jsx +7 -0
- package/src/canvas/CanvasPage.bridge.test.jsx +14 -6
- package/src/canvas/CanvasPage.dragdrop.test.jsx +10 -6
- package/src/canvas/CanvasPage.jsx +738 -216
- package/src/canvas/CanvasPage.module.css +13 -15
- package/src/canvas/CanvasPage.multiselect.test.jsx +17 -6
- package/src/canvas/ConnectorLayer.jsx +121 -153
- package/src/canvas/ConnectorLayer.module.css +69 -0
- package/src/canvas/PageSelector.test.jsx +15 -6
- package/src/canvas/canvasApi.js +68 -2
- package/src/canvas/connectorGeometry.js +132 -0
- package/src/canvas/hotPoolDevLogs.js +25 -0
- package/src/canvas/useCanvas.js +1 -1
- package/src/canvas/useMarqueeSelect.js +30 -4
- package/src/canvas/widgets/CodePenEmbed.jsx +1 -0
- package/src/canvas/widgets/ComponentSetWidget.jsx +199 -0
- package/src/canvas/widgets/ComponentSetWidget.module.css +89 -0
- package/src/canvas/widgets/ComponentWidget.jsx +1 -0
- package/src/canvas/widgets/CropOverlay.jsx +219 -0
- package/src/canvas/widgets/CropOverlay.module.css +118 -0
- package/src/canvas/widgets/ExpandedPane.jsx +472 -0
- package/src/canvas/widgets/ExpandedPane.module.css +179 -0
- package/src/canvas/widgets/ExpandedPane.test.jsx +240 -0
- package/src/canvas/widgets/ExpandedPaneTopBar.jsx +111 -0
- package/src/canvas/widgets/ExpandedPaneTopBar.module.css +59 -0
- package/src/canvas/widgets/ExpandedPaneTopBar.test.jsx +45 -0
- package/src/canvas/widgets/FigmaEmbed.jsx +62 -47
- package/src/canvas/widgets/FigmaEmbed.module.css +61 -0
- package/src/canvas/widgets/ImageWidget.jsx +130 -9
- package/src/canvas/widgets/ImageWidget.module.css +30 -0
- package/src/canvas/widgets/LinkPreview.jsx +112 -4
- package/src/canvas/widgets/LinkPreview.module.css +127 -0
- package/src/canvas/widgets/MarkdownBlock.jsx +164 -17
- package/src/canvas/widgets/MarkdownBlock.module.css +148 -0
- package/src/canvas/widgets/PromptWidget.jsx +414 -0
- package/src/canvas/widgets/PromptWidget.module.css +273 -0
- package/src/canvas/widgets/PrototypeEmbed.jsx +77 -38
- package/src/canvas/widgets/PrototypeEmbed.module.css +117 -0
- package/src/canvas/widgets/PrototypeEmbed.test.jsx +2 -2
- package/src/canvas/widgets/ResizeHandle.jsx +17 -6
- package/src/canvas/widgets/StoryWidget.jsx +72 -15
- package/src/canvas/widgets/TerminalReadWidget.jsx +146 -0
- package/src/canvas/widgets/TerminalReadWidget.module.css +94 -0
- package/src/canvas/widgets/TerminalWidget.jsx +496 -69
- package/src/canvas/widgets/TerminalWidget.module.css +271 -8
- package/src/canvas/widgets/TilesWidget.jsx +302 -0
- package/src/canvas/widgets/TilesWidget.module.css +133 -0
- package/src/canvas/widgets/WidgetChrome.jsx +73 -153
- package/src/canvas/widgets/WidgetChrome.module.css +30 -1
- package/src/canvas/widgets/embedInteraction.test.jsx +24 -26
- package/src/canvas/widgets/expandUtils.js +557 -0
- package/src/canvas/widgets/expandUtils.test.js +155 -0
- package/src/canvas/widgets/index.js +9 -0
- package/src/canvas/widgets/snapshotDisplay.test.jsx +23 -71
- package/src/canvas/widgets/tilePool.js +23 -0
- package/src/canvas/widgets/tiles/diagonal-bl.png +0 -0
- package/src/canvas/widgets/tiles/diagonal-br.png +0 -0
- package/src/canvas/widgets/tiles/diagonal-tl.png +0 -0
- package/src/canvas/widgets/tiles/leaf.png +0 -0
- package/src/canvas/widgets/tiles/quarter-tl.png +0 -0
- package/src/canvas/widgets/tiles/quarter-tr.png +0 -0
- package/src/canvas/widgets/tiles/solid-a.png +0 -0
- package/src/canvas/widgets/tiles/solid-b.png +0 -0
- package/src/canvas/widgets/widgetConfig.js +55 -4
- package/src/canvas/widgets/widgetIcons.jsx +190 -0
- package/src/canvas/widgets/widgetProps.js +1 -0
- package/src/context.jsx +47 -19
- package/src/hooks/useConfig.js +14 -0
- package/src/hooks/usePrototypeReloadGuard.js +64 -0
- package/src/index.js +8 -2
- package/src/story/ComponentSetPage.jsx +186 -0
- package/src/story/ComponentSetPage.module.css +121 -0
- package/src/story/StoryPage.jsx +32 -2
- package/src/vite/data-plugin.js +324 -30
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { useState, useRef, useEffect, useCallback, useMemo } from 'react'
|
|
1
|
+
import { useState, useRef, useEffect, useCallback, useMemo, forwardRef, useImperativeHandle } from 'react'
|
|
2
2
|
import { remark } from 'remark'
|
|
3
3
|
import remarkGfm from 'remark-gfm'
|
|
4
4
|
import remarkHtml from 'remark-html'
|
|
5
5
|
import WidgetWrapper from './WidgetWrapper.jsx'
|
|
6
6
|
import ResizeHandle from './ResizeHandle.jsx'
|
|
7
7
|
import { readProp } from './widgetProps.js'
|
|
8
|
-
import { schemas } from './widgetConfig.js'
|
|
8
|
+
import { schemas, getFeaturesForSurface } from './widgetConfig.js'
|
|
9
|
+
import ExpandedPane from './ExpandedPane.jsx'
|
|
10
|
+
import { findAllConnectedSplitTargets, getSplitPaneLabel, buildPaneForWidget, buildSplitLayout } from './expandUtils.js'
|
|
9
11
|
import styles from './MarkdownBlock.module.css'
|
|
10
12
|
|
|
11
13
|
const markdownSchema = schemas['markdown']
|
|
@@ -64,18 +66,28 @@ async function highlightCodeBlocks(html) {
|
|
|
64
66
|
)
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
export default function MarkdownBlock({ props, onUpdate, resizable }) {
|
|
69
|
+
export default forwardRef(function MarkdownBlock({ id, props, onUpdate, resizable }, ref) {
|
|
68
70
|
const content = readProp(props, 'content', markdownSchema)
|
|
69
71
|
const width = readProp(props, 'width', markdownSchema)
|
|
70
72
|
const height = props?.height
|
|
71
73
|
const collapsed = !!props?.collapsed
|
|
72
74
|
const canEdit = typeof onUpdate === 'function'
|
|
73
75
|
const [editing, setEditing] = useState(false)
|
|
76
|
+
const [expandMode, setExpandMode] = useState(null)
|
|
77
|
+
const expanded = expandMode !== null
|
|
74
78
|
const editingActive = canEdit && editing
|
|
75
79
|
const textareaRef = useRef(null)
|
|
76
80
|
const blockRef = useRef(null)
|
|
77
81
|
const [editHeight, setEditHeight] = useState(null)
|
|
78
82
|
|
|
83
|
+
useImperativeHandle(ref, () => ({
|
|
84
|
+
handleAction(actionId) {
|
|
85
|
+
if (actionId === 'expand' || actionId === 'expand-single') { setExpandMode('single'); return true }
|
|
86
|
+
if (actionId === 'split-screen') { setExpandMode('split'); return true }
|
|
87
|
+
return false
|
|
88
|
+
},
|
|
89
|
+
}), [])
|
|
90
|
+
|
|
79
91
|
const handleResize = useCallback((w, h) => {
|
|
80
92
|
onUpdate?.({ width: w, height: h })
|
|
81
93
|
}, [onUpdate])
|
|
@@ -115,12 +127,17 @@ export default function MarkdownBlock({ props, onUpdate, resizable }) {
|
|
|
115
127
|
}
|
|
116
128
|
}, [canEdit, content])
|
|
117
129
|
|
|
130
|
+
const startEditing = useCallback(() => {
|
|
131
|
+
// Capture the preview height BEFORE React swaps to the textarea
|
|
132
|
+
if (blockRef.current) {
|
|
133
|
+
setEditHeight(blockRef.current.offsetHeight)
|
|
134
|
+
blockRef.current.dataset.scrollTop = blockRef.current.scrollTop
|
|
135
|
+
}
|
|
136
|
+
setEditing(true)
|
|
137
|
+
}, [])
|
|
138
|
+
|
|
118
139
|
useEffect(() => {
|
|
119
140
|
if (editingActive) {
|
|
120
|
-
// Capture the preview height before switching to editor
|
|
121
|
-
if (blockRef.current && !editHeight) {
|
|
122
|
-
setEditHeight(blockRef.current.offsetHeight)
|
|
123
|
-
}
|
|
124
141
|
if (textareaRef.current) {
|
|
125
142
|
// Place cursor at end and prevent scroll jump to top
|
|
126
143
|
const len = textareaRef.current.value.length
|
|
@@ -134,9 +151,10 @@ export default function MarkdownBlock({ props, onUpdate, resizable }) {
|
|
|
134
151
|
} else {
|
|
135
152
|
setEditHeight(null)
|
|
136
153
|
}
|
|
137
|
-
}, [editingActive
|
|
154
|
+
}, [editingActive])
|
|
138
155
|
|
|
139
156
|
return (
|
|
157
|
+
<>
|
|
140
158
|
<WidgetWrapper>
|
|
141
159
|
<div
|
|
142
160
|
ref={blockRef}
|
|
@@ -170,18 +188,11 @@ export default function MarkdownBlock({ props, onUpdate, resizable }) {
|
|
|
170
188
|
data-canvas-allow-text-selection={!canEdit ? '' : undefined}
|
|
171
189
|
onClick={!canEdit ? (e) => e.stopPropagation() : undefined}
|
|
172
190
|
onCopy={!canEdit ? handleReadOnlyCopy : undefined}
|
|
173
|
-
onDoubleClick={canEdit ?
|
|
174
|
-
// Save scroll position before switching to editor
|
|
175
|
-
if (blockRef.current) blockRef.current.dataset.scrollTop = blockRef.current.scrollTop
|
|
176
|
-
setEditing(true)
|
|
177
|
-
} : undefined}
|
|
191
|
+
onDoubleClick={canEdit ? startEditing : undefined}
|
|
178
192
|
role={canEdit ? 'button' : undefined}
|
|
179
193
|
tabIndex={canEdit ? 0 : undefined}
|
|
180
194
|
onKeyDown={canEdit ? (e) => {
|
|
181
|
-
if (e.key === 'Enter')
|
|
182
|
-
if (blockRef.current) blockRef.current.dataset.scrollTop = blockRef.current.scrollTop
|
|
183
|
-
setEditing(true)
|
|
184
|
-
}
|
|
195
|
+
if (e.key === 'Enter') startEditing()
|
|
185
196
|
} : undefined}
|
|
186
197
|
dangerouslySetInnerHTML={{
|
|
187
198
|
__html: renderedHtml || (canEdit
|
|
@@ -200,5 +211,141 @@ export default function MarkdownBlock({ props, onUpdate, resizable }) {
|
|
|
200
211
|
)}
|
|
201
212
|
</div>
|
|
202
213
|
</WidgetWrapper>
|
|
214
|
+
{expanded && (
|
|
215
|
+
<MarkdownExpandPane
|
|
216
|
+
widgetId={id}
|
|
217
|
+
content={content}
|
|
218
|
+
splitMode={expandMode === 'split'}
|
|
219
|
+
onClose={() => setExpandMode(null)}
|
|
220
|
+
onUpdate={onUpdate}
|
|
221
|
+
/>
|
|
222
|
+
)}
|
|
223
|
+
</>
|
|
224
|
+
)
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Builds pane configs and renders ExpandedPane for an expanded markdown widget.
|
|
229
|
+
*/
|
|
230
|
+
function MarkdownExpandPane({ widgetId, content, splitMode, onClose, onUpdate }) {
|
|
231
|
+
const [editing, setEditing] = useState(false)
|
|
232
|
+
const canEdit = typeof onUpdate === 'function'
|
|
233
|
+
|
|
234
|
+
const connectedWidgets = useMemo(
|
|
235
|
+
() => splitMode ? findAllConnectedSplitTargets(widgetId) : [],
|
|
236
|
+
[widgetId, splitMode],
|
|
237
|
+
)
|
|
238
|
+
const primaryWidget = useMemo(() => {
|
|
239
|
+
const bridge = window.__storyboardCanvasBridgeState
|
|
240
|
+
return bridge?.widgets?.find((w) => w.id === widgetId) || { id: widgetId, type: 'markdown', position: { x: 0, y: 0 }, props: {} }
|
|
241
|
+
}, [widgetId])
|
|
242
|
+
|
|
243
|
+
// Surface: fullbar for single expand, splitbar for split
|
|
244
|
+
const surface = splitMode ? 'splitbar' : 'fullbar'
|
|
245
|
+
const surfaceFeatures = useMemo(
|
|
246
|
+
() => canEdit ? getFeaturesForSurface('markdown', surface) : [],
|
|
247
|
+
[canEdit, surface],
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
const getState = useCallback((key) => {
|
|
251
|
+
if (key === 'editing') return editing
|
|
252
|
+
return undefined
|
|
253
|
+
}, [editing])
|
|
254
|
+
|
|
255
|
+
const handleAction = useCallback((actionId) => {
|
|
256
|
+
if (actionId === 'toggle-edit') {
|
|
257
|
+
setEditing((v) => !v)
|
|
258
|
+
}
|
|
259
|
+
}, [])
|
|
260
|
+
|
|
261
|
+
const buildPaneFn = useCallback((widget) => {
|
|
262
|
+
if (widget.id === widgetId) {
|
|
263
|
+
return {
|
|
264
|
+
id: widgetId,
|
|
265
|
+
label: getSplitPaneLabel(primaryWidget) || 'Markdown',
|
|
266
|
+
widgetType: 'markdown',
|
|
267
|
+
kind: 'react',
|
|
268
|
+
features: surfaceFeatures,
|
|
269
|
+
getState,
|
|
270
|
+
onAction: handleAction,
|
|
271
|
+
render: () => (
|
|
272
|
+
<ExpandedMarkdownEditor
|
|
273
|
+
content={content}
|
|
274
|
+
onUpdate={onUpdate}
|
|
275
|
+
editing={editing}
|
|
276
|
+
onToggleEdit={() => setEditing((v) => !v)}
|
|
277
|
+
/>
|
|
278
|
+
),
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return buildPaneForWidget(widget, surface)
|
|
282
|
+
}, [widgetId, primaryWidget, content, onUpdate, editing, surfaceFeatures, getState, handleAction, surface])
|
|
283
|
+
|
|
284
|
+
const layout = useMemo(
|
|
285
|
+
() => buildSplitLayout(primaryWidget, connectedWidgets, buildPaneFn),
|
|
286
|
+
[primaryWidget, connectedWidgets, buildPaneFn],
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<ExpandedPane
|
|
291
|
+
initialLayout={layout}
|
|
292
|
+
variant={layout.flat().length <= 1 ? 'modal' : 'full'}
|
|
293
|
+
onClose={onClose}
|
|
294
|
+
/>
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Editable markdown view for expanded/split-screen panes.
|
|
300
|
+
* Self-contained: renders markdown from raw content with syntax highlighting.
|
|
301
|
+
* Editing state is controlled externally via props (toggle button lives in the title bar).
|
|
302
|
+
*/
|
|
303
|
+
export function ExpandedMarkdownEditor({ content, onUpdate, editing, onToggleEdit }) {
|
|
304
|
+
const textareaRef = useRef(null)
|
|
305
|
+
const canEdit = typeof onUpdate === 'function'
|
|
306
|
+
|
|
307
|
+
const rawHtml = useMemo(() => renderMarkdown(content), [content])
|
|
308
|
+
const [renderedHtml, setRenderedHtml] = useState(rawHtml)
|
|
309
|
+
|
|
310
|
+
useEffect(() => {
|
|
311
|
+
setRenderedHtml(rawHtml)
|
|
312
|
+
if (!rawHtml.includes('<code class="language-')) return
|
|
313
|
+
let cancelled = false
|
|
314
|
+
highlightCodeBlocks(rawHtml).then((highlighted) => {
|
|
315
|
+
if (!cancelled) setRenderedHtml(highlighted)
|
|
316
|
+
})
|
|
317
|
+
return () => { cancelled = true }
|
|
318
|
+
}, [rawHtml])
|
|
319
|
+
|
|
320
|
+
useEffect(() => {
|
|
321
|
+
if (editing && textareaRef.current) {
|
|
322
|
+
const len = textareaRef.current.value.length
|
|
323
|
+
textareaRef.current.setSelectionRange(len, len)
|
|
324
|
+
textareaRef.current.focus({ preventScroll: true })
|
|
325
|
+
}
|
|
326
|
+
}, [editing])
|
|
327
|
+
|
|
328
|
+
if (editing && canEdit) {
|
|
329
|
+
return (
|
|
330
|
+
<textarea
|
|
331
|
+
ref={textareaRef}
|
|
332
|
+
className={styles.expandedEditor}
|
|
333
|
+
value={content}
|
|
334
|
+
onChange={(e) => onUpdate({ content: e.target.value })}
|
|
335
|
+
onKeyDown={(e) => { if (e.key === 'Escape') onToggleEdit?.() }}
|
|
336
|
+
placeholder="Write markdown…"
|
|
337
|
+
/>
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return (
|
|
342
|
+
<div
|
|
343
|
+
className={styles.expandedPreview}
|
|
344
|
+
style={{ flex: 1, overflow: 'auto' }}
|
|
345
|
+
onDoubleClick={canEdit ? onToggleEdit : undefined}
|
|
346
|
+
dangerouslySetInnerHTML={{
|
|
347
|
+
__html: renderedHtml || '<p>No content</p>',
|
|
348
|
+
}}
|
|
349
|
+
/>
|
|
203
350
|
)
|
|
204
351
|
}
|
|
@@ -227,3 +227,151 @@
|
|
|
227
227
|
color: var(--sb--markdown-fg);
|
|
228
228
|
resize: none;
|
|
229
229
|
}
|
|
230
|
+
|
|
231
|
+
/* ── Expanded preview in modal ──────────────────────────────────── */
|
|
232
|
+
|
|
233
|
+
.expandedPreview {
|
|
234
|
+
--sb--markdown-bg: var(--bgColor-default, #ffffff);
|
|
235
|
+
--sb--markdown-fg: var(--fgColor-default, #1f2328);
|
|
236
|
+
--sb--markdown-muted: var(--fgColor-muted, #656d76);
|
|
237
|
+
--sb--markdown-accent: var(--bgColor-accent-emphasis, #2f81f7);
|
|
238
|
+
padding: 32px 40px;
|
|
239
|
+
font-size: 15px;
|
|
240
|
+
line-height: 1.7;
|
|
241
|
+
color: var(--sb--markdown-fg);
|
|
242
|
+
background: var(--sb--markdown-bg);
|
|
243
|
+
font-family: var(--tc-font-stack, system-ui, -apple-system, sans-serif);
|
|
244
|
+
max-width: 800px;
|
|
245
|
+
margin: 0 auto;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.expandedPreview * {
|
|
249
|
+
pointer-events: auto;
|
|
250
|
+
color: inherit;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.expandedPreview a {
|
|
254
|
+
color: var(--sb--markdown-accent);
|
|
255
|
+
text-decoration: none;
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.expandedPreview a:hover {
|
|
260
|
+
text-decoration: underline;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.expandedPreview img {
|
|
264
|
+
max-width: 100%;
|
|
265
|
+
height: auto;
|
|
266
|
+
border-radius: 6px;
|
|
267
|
+
border: 1px solid var(--borderColor-default, #d0d7de);
|
|
268
|
+
margin: 8px 0;
|
|
269
|
+
display: block;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.expandedPreview video {
|
|
273
|
+
max-width: 100%;
|
|
274
|
+
height: auto;
|
|
275
|
+
border-radius: 6px;
|
|
276
|
+
border: 1px solid var(--borderColor-default, #d0d7de);
|
|
277
|
+
margin: 8px 0;
|
|
278
|
+
display: block;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.expandedPreview h1 { font-size: 24px; font-weight: 700; margin: 0 0 12px; line-height: 1.3; }
|
|
282
|
+
.expandedPreview h2 { font-size: 20px; font-weight: 600; margin: 0 0 10px; line-height: 1.3; }
|
|
283
|
+
.expandedPreview h3 { font-size: 17px; font-weight: 600; margin: 0 0 6px; line-height: 1.3; }
|
|
284
|
+
.expandedPreview p { margin: 0 0 12px; }
|
|
285
|
+
|
|
286
|
+
.expandedPreview code {
|
|
287
|
+
background: var(--bgColor-neutral-muted, #afb8c133);
|
|
288
|
+
padding: 2px 5px;
|
|
289
|
+
border-radius: 4px;
|
|
290
|
+
font-size: 13px;
|
|
291
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.expandedPreview pre {
|
|
295
|
+
padding: 12px 16px;
|
|
296
|
+
border-radius: 6px;
|
|
297
|
+
border: 1px solid var(--borderColor-muted, #d8dee4);
|
|
298
|
+
overflow-x: auto;
|
|
299
|
+
margin: 8px 0;
|
|
300
|
+
background: var(--bgColor-neutral-muted, #afb8c133);
|
|
301
|
+
line-height: 1.4;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.expandedPreview pre code {
|
|
305
|
+
background: none;
|
|
306
|
+
padding: 0;
|
|
307
|
+
font-size: 13px;
|
|
308
|
+
white-space: pre;
|
|
309
|
+
display: block;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.expandedPreview ul { margin: 0 0 12px; padding-left: 24px; list-style: disc; }
|
|
313
|
+
.expandedPreview ol { margin: 0 0 12px; padding-left: 24px; list-style: decimal; }
|
|
314
|
+
.expandedPreview li { margin: 0 0 4px; display: list-item; }
|
|
315
|
+
|
|
316
|
+
.expandedPreview blockquote {
|
|
317
|
+
border-left: 4px solid var(--borderColor-default, #d0d7de);
|
|
318
|
+
margin: 12px 0;
|
|
319
|
+
padding: 4px 16px;
|
|
320
|
+
color: var(--sb--markdown-muted);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.expandedPreview table {
|
|
324
|
+
border-collapse: collapse;
|
|
325
|
+
margin: 12px 0;
|
|
326
|
+
width: 100%;
|
|
327
|
+
font-size: 14px;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.expandedPreview th,
|
|
331
|
+
.expandedPreview td {
|
|
332
|
+
border: 1px solid var(--borderColor-default, #d0d7de);
|
|
333
|
+
padding: 6px 12px;
|
|
334
|
+
text-align: left;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.expandedPreview th {
|
|
338
|
+
background: var(--bgColor-muted, #f6f8fa);
|
|
339
|
+
font-weight: 600;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.expandedPreview hr {
|
|
343
|
+
border: none;
|
|
344
|
+
border-top: 1px solid var(--borderColor-default, #d0d7de);
|
|
345
|
+
margin: 16px 0;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.expandedPreview input[type="checkbox"] {
|
|
349
|
+
margin-right: 6px;
|
|
350
|
+
pointer-events: none;
|
|
351
|
+
accent-color: var(--sb--markdown-accent);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.expandedPreview li:has(input[type="checkbox"]) {
|
|
355
|
+
list-style: none;
|
|
356
|
+
margin-left: -24px;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/* ── Expanded editor ─────────────────────────────────────────────── */
|
|
360
|
+
|
|
361
|
+
.expandedEditor {
|
|
362
|
+
display: block;
|
|
363
|
+
width: 100%;
|
|
364
|
+
height: 100%;
|
|
365
|
+
box-sizing: border-box;
|
|
366
|
+
padding: 32px 40px;
|
|
367
|
+
border: none;
|
|
368
|
+
outline: none;
|
|
369
|
+
resize: none;
|
|
370
|
+
background: var(--bgColor-default, #ffffff);
|
|
371
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
372
|
+
font-size: 14px;
|
|
373
|
+
line-height: 1.6;
|
|
374
|
+
color: var(--fgColor-default, #1f2328);
|
|
375
|
+
max-width: 800px;
|
|
376
|
+
margin: 0 auto;
|
|
377
|
+
}
|