@h-ai/ui 0.1.0-alpha.10 → 0.1.0-alpha.12
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/dist/components/compounds/Form.svelte +2 -0
- package/dist/components/compounds/Modal.svelte +251 -59
- package/dist/components/primitives/Button.svelte +2 -0
- package/dist/components/scenes/ai/AiDocumentEditor.svelte +1775 -331
- package/dist/components/scenes/ai/MarkdownRenderer.svelte +2 -2
- package/dist/components/scenes/ai/document-download.js +249 -75
- package/dist/components/scenes/ai/document-parse.d.ts +8 -0
- package/dist/components/scenes/ai/document-parse.js +25 -8
- package/dist/components/scenes/ai/document-types.d.ts +42 -4
- package/dist/components/scenes/ai/editor-markdown-extensions.d.ts +11 -0
- package/dist/components/scenes/ai/editor-markdown-extensions.js +184 -0
- package/dist/components/scenes/ai/index.d.ts +3 -1
- package/dist/components/scenes/ai/index.js +1 -0
- package/dist/components/scenes/ai/markdown-parse.js +2 -0
- package/dist/components/scenes/ai/table/AiTableEditor.svelte +1640 -0
- package/dist/components/scenes/ai/table/AiTableEditor.svelte.d.ts +6 -0
- package/dist/components/scenes/ai/table/table-types.d.ts +101 -0
- package/dist/components/scenes/ai/table/table-types.js +1 -0
- package/dist/messages/en-US.json +27 -0
- package/dist/messages/zh-CN.json +27 -0
- package/dist/types.d.ts +10 -0
- package/package.json +4 -2
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
import type {
|
|
15
15
|
AiDocumentEditorProps,
|
|
16
16
|
MarkdownBlockFormatKind,
|
|
17
|
+
MarkdownBlockStyleKind,
|
|
17
18
|
MarkdownCodeBlockItem,
|
|
18
19
|
MarkdownCodeRunRequest,
|
|
19
20
|
MarkdownCodeRunResult,
|
|
21
|
+
MarkdownColorFormatRequest,
|
|
20
22
|
MarkdownInlineFormatKind,
|
|
21
23
|
MarkdownRewriteAction,
|
|
24
|
+
MarkdownTextAlignKind,
|
|
22
25
|
} from './document-types.js'
|
|
23
26
|
import { uiM } from '../../../messages.js'
|
|
24
27
|
import { cn } from '../../../utils.js'
|
|
@@ -47,10 +50,132 @@
|
|
|
47
50
|
error?: string
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
interface SelectionFormatState {
|
|
54
|
+
/** 当前选区所在段落样式,用于标题/正文下拉默认值。 */
|
|
55
|
+
blockFormat: MarkdownBlockStyleKind
|
|
56
|
+
/** 当前选区所在段落的对齐方式。 */
|
|
57
|
+
alignment: MarkdownTextAlignKind
|
|
58
|
+
/** 当前选区是否命中加粗样式。 */
|
|
59
|
+
bold: boolean
|
|
60
|
+
/** 当前选区是否命中删除线样式。 */
|
|
61
|
+
strike: boolean
|
|
62
|
+
/** 当前选区是否命中斜体样式。 */
|
|
63
|
+
italic: boolean
|
|
64
|
+
/** 当前选区是否命中下划线样式。 */
|
|
65
|
+
underline: boolean
|
|
66
|
+
/** 当前选区是否命中 `<mark>` 或自定义底色高亮。 */
|
|
67
|
+
highlight: boolean
|
|
68
|
+
/** 当前选区是否落在行内代码内。 */
|
|
69
|
+
code: boolean
|
|
70
|
+
/** 当前选区命中的链接地址;为空表示无链接。 */
|
|
71
|
+
linkHref: string
|
|
72
|
+
/** 当前选区前景色;为空表示使用默认文字颜色。 */
|
|
73
|
+
textColor: string | null
|
|
74
|
+
/** 当前选区背景色;为空表示使用默认背景。 */
|
|
75
|
+
backgroundColor: string | null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface PreviewSelectionState {
|
|
79
|
+
/** 浏览器当前仍然有效的正文选区。 */
|
|
80
|
+
selection: Selection
|
|
81
|
+
/** 当前选区对应的 DOM Range,用于计算浮层定位。 */
|
|
82
|
+
range: Range
|
|
83
|
+
/** 归一化后的选中文本。 */
|
|
84
|
+
text: string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type SelectionMenuKind = 'rewrite' | 'block' | 'align' | 'link' | 'color'
|
|
88
|
+
|
|
89
|
+
const BLOCK_FORMAT_OPTIONS: Array<{
|
|
90
|
+
value: MarkdownBlockStyleKind
|
|
91
|
+
labelKey:
|
|
92
|
+
| 'markdown_format_paragraph'
|
|
93
|
+
| 'markdown_format_heading_1'
|
|
94
|
+
| 'markdown_format_heading_2'
|
|
95
|
+
| 'markdown_format_heading_3'
|
|
96
|
+
| 'markdown_format_heading_4'
|
|
97
|
+
shortLabel: string
|
|
98
|
+
}> = [
|
|
99
|
+
{
|
|
100
|
+
value: 'paragraph',
|
|
101
|
+
labelKey: 'markdown_format_paragraph',
|
|
102
|
+
shortLabel: 'T',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
value: 'heading1',
|
|
106
|
+
labelKey: 'markdown_format_heading_1',
|
|
107
|
+
shortLabel: 'H1',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
value: 'heading2',
|
|
111
|
+
labelKey: 'markdown_format_heading_2',
|
|
112
|
+
shortLabel: 'H2',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
value: 'heading3',
|
|
116
|
+
labelKey: 'markdown_format_heading_3',
|
|
117
|
+
shortLabel: 'H3',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
value: 'heading4',
|
|
121
|
+
labelKey: 'markdown_format_heading_4',
|
|
122
|
+
shortLabel: 'H4',
|
|
123
|
+
},
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
const ALIGN_OPTIONS: Array<{
|
|
127
|
+
value: MarkdownTextAlignKind
|
|
128
|
+
labelKey:
|
|
129
|
+
| 'markdown_align_left'
|
|
130
|
+
| 'markdown_align_center'
|
|
131
|
+
| 'markdown_align_right'
|
|
132
|
+
| 'markdown_align_justify'
|
|
133
|
+
}> = [
|
|
134
|
+
{ value: 'left', labelKey: 'markdown_align_left' },
|
|
135
|
+
{ value: 'center', labelKey: 'markdown_align_center' },
|
|
136
|
+
{ value: 'right', labelKey: 'markdown_align_right' },
|
|
137
|
+
{ value: 'justify', labelKey: 'markdown_align_justify' },
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
const TEXT_COLOR_PRESETS = [
|
|
141
|
+
'#0f172a',
|
|
142
|
+
'#475569',
|
|
143
|
+
'#b91c1c',
|
|
144
|
+
'#ea580c',
|
|
145
|
+
'#ca8a04',
|
|
146
|
+
'#15803d',
|
|
147
|
+
'#2563eb',
|
|
148
|
+
'#7c3aed',
|
|
149
|
+
] as const
|
|
150
|
+
|
|
151
|
+
const BACKGROUND_COLOR_PRESETS = [
|
|
152
|
+
'#fee2e2',
|
|
153
|
+
'#ffedd5',
|
|
154
|
+
'#fef3c7',
|
|
155
|
+
'#dcfce7',
|
|
156
|
+
'#dbeafe',
|
|
157
|
+
'#ede9fe',
|
|
158
|
+
'#f3f4f6',
|
|
159
|
+
'#e2e8f0',
|
|
160
|
+
] as const
|
|
161
|
+
|
|
162
|
+
const DEFAULT_SELECTION_FORMAT_STATE: SelectionFormatState = {
|
|
163
|
+
blockFormat: 'paragraph',
|
|
164
|
+
alignment: 'left',
|
|
165
|
+
bold: false,
|
|
166
|
+
strike: false,
|
|
167
|
+
italic: false,
|
|
168
|
+
underline: false,
|
|
169
|
+
highlight: false,
|
|
170
|
+
code: false,
|
|
171
|
+
linkHref: '',
|
|
172
|
+
textColor: null,
|
|
173
|
+
backgroundColor: null,
|
|
174
|
+
}
|
|
175
|
+
|
|
50
176
|
// 复制前后的图标以内联 SVG 缓存,避免每次点击都重新拼接按钮内容。
|
|
51
177
|
const COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>`
|
|
52
178
|
const CHECK_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`
|
|
53
|
-
const HTML_SNIPPET_REGEX = /<!doctype html>|<html[\s>]|<body[\s>]|<div[\s>]|<main[\s>]/i
|
|
54
179
|
|
|
55
180
|
let {
|
|
56
181
|
// 暴露给外层的滚动容器引用,用于同步滚动或定位选区工具条。
|
|
@@ -71,6 +196,10 @@
|
|
|
71
196
|
showCopyButton = true,
|
|
72
197
|
// 是否显示代码块运行按钮与预览占位。
|
|
73
198
|
showRunButton = false,
|
|
199
|
+
// 是否在代码块头部显示“代码/预览”切换。
|
|
200
|
+
showCodePreviewToggle = false,
|
|
201
|
+
// 代码预览切换模式下展示在语言标签旁的提示文案。
|
|
202
|
+
codePreviewHint = '',
|
|
74
203
|
// 是否启用语法高亮。
|
|
75
204
|
enableHighlight = true,
|
|
76
205
|
// 是否把换行渲染为 <br>。
|
|
@@ -123,8 +252,16 @@
|
|
|
123
252
|
oncopydocument,
|
|
124
253
|
// 块级格式动作回调。
|
|
125
254
|
onapplyblockformat,
|
|
255
|
+
// 细粒度块样式动作回调。
|
|
256
|
+
onapplyblockstyle,
|
|
126
257
|
// 行内格式动作回调。
|
|
127
258
|
onapplyinlineformat,
|
|
259
|
+
// 对齐动作回调。
|
|
260
|
+
onapplyalignment,
|
|
261
|
+
// 链接设置动作回调。
|
|
262
|
+
onapplylink,
|
|
263
|
+
// 颜色设置动作回调。
|
|
264
|
+
onapplycolor,
|
|
128
265
|
// 选区复制回调。
|
|
129
266
|
oncopyselection,
|
|
130
267
|
// 选区注释回调。
|
|
@@ -141,10 +278,10 @@
|
|
|
141
278
|
let selectedText = $state('')
|
|
142
279
|
// 选区工具条显示开关。
|
|
143
280
|
let selectionToolbarVisible = $state(false)
|
|
144
|
-
//
|
|
145
|
-
let
|
|
281
|
+
// 选区工具条当前展开的子菜单,统一管理避免多个面板互相覆盖。
|
|
282
|
+
let activeSelectionMenu = $state<SelectionMenuKind | null>(null)
|
|
146
283
|
// 文档头部标题只有在正文首个标题滚出可视区后才显示,避免双标题并排出现。
|
|
147
|
-
let showPinnedTitle = $state(
|
|
284
|
+
let showPinnedTitle = $state(false)
|
|
148
285
|
// 选区工具条在滚动容器中的定位坐标。
|
|
149
286
|
let toolbarPosition = $state<SelectionToolbarPosition>({
|
|
150
287
|
top: 0,
|
|
@@ -152,23 +289,52 @@
|
|
|
152
289
|
placement: 'top',
|
|
153
290
|
alignment: 'center',
|
|
154
291
|
})
|
|
292
|
+
// 选区工具条自身 DOM,用于根据真实尺寸修正贴边位置。
|
|
293
|
+
let selectionToolbarEl = $state<HTMLDivElement | null>(null)
|
|
294
|
+
// 当前展开菜单对应的触发按钮,用来把面板锚定到具体按钮下方/上方。
|
|
295
|
+
let activeSelectionMenuTrigger = $state<HTMLElement | null>(null)
|
|
296
|
+
// 菜单面板相对工具条的水平锚点。
|
|
297
|
+
let selectionMenuLeft = $state(0)
|
|
298
|
+
// 菜单面板在锚点处的对齐方式,避免宽面板越过正文边界。
|
|
299
|
+
let selectionMenuAlignment = $state<'left' | 'center' | 'right'>('center')
|
|
155
300
|
// documentCopied 只负责顶部复制按钮的瞬时反馈,不和正文内容状态混用。
|
|
156
301
|
let documentCopied = $state(false)
|
|
157
302
|
// copyFeedbackTimer 用来保证连续点击复制时,成功态能按最后一次操作重新计时。
|
|
158
|
-
let copyFeedbackTimer:
|
|
303
|
+
let copyFeedbackTimer: number | undefined = $state()
|
|
159
304
|
// 每个代码块的运行状态和预览结果,key 为 codeBlockId。
|
|
160
305
|
let codePreviews = $state<Record<string, CodePreviewState>>({})
|
|
306
|
+
// selectionFormatState 跟随真实 DOM 选区,负责驱动按钮按下态与下拉默认值。
|
|
307
|
+
let selectionFormatState = $state<SelectionFormatState>({
|
|
308
|
+
...DEFAULT_SELECTION_FORMAT_STATE,
|
|
309
|
+
})
|
|
310
|
+
// linkDraft 只在链接弹层里暂存输入值,避免每次打开都丢掉正在编辑的链接。
|
|
311
|
+
let linkDraft = $state('')
|
|
312
|
+
// 真实尺寸修正只需要排队一帧,避免反复触发 handleSelectionChange 形成抖动。
|
|
313
|
+
let selectionToolbarMeasurePending = false
|
|
314
|
+
// 选区刷新统一合并到同一帧,避免 selectionchange / mouseup / blur 连续触发时抖动。
|
|
315
|
+
let selectionRefreshFrame: number | undefined
|
|
316
|
+
let selectionRefreshNeedsRemeasure = false
|
|
317
|
+
// 浏览器在滚动到底部或切换焦点时会短暂给出空选区,这里延迟一拍再关闭工具条。
|
|
318
|
+
let selectionToolbarCloseTimer: number | undefined
|
|
161
319
|
|
|
162
320
|
// code 类型产物通常只有裸代码文本,这里统一包成 fenced block 进入同一条渲染链路。
|
|
163
321
|
const documentContent = $derived(
|
|
164
322
|
resolveDocumentMarkdownContent(content, sourceKind, codeLanguage),
|
|
165
323
|
)
|
|
166
324
|
// 渲染结果同时提供 HTML、目录和代码块元数据,供顶部目录与代码预览共用。
|
|
325
|
+
const codePreviewToggleEnabled = $derived(
|
|
326
|
+
showCodePreviewToggle && sourceKind === 'code',
|
|
327
|
+
)
|
|
328
|
+
const normalizedCodePreviewHint = $derived(codePreviewHint.trim())
|
|
167
329
|
const renderResult = $derived(
|
|
168
330
|
renderMarkdownDocument(documentContent, {
|
|
169
331
|
enableHighlight,
|
|
170
332
|
showCopyButton,
|
|
171
333
|
showRunButton,
|
|
334
|
+
showCodePreviewToggle: codePreviewToggleEnabled,
|
|
335
|
+
codeViewCodeLabel: uiM('markdown_format_code'),
|
|
336
|
+
codeViewPreviewLabel: uiM('file_list_preview'),
|
|
337
|
+
codePreviewHint: normalizedCodePreviewHint,
|
|
172
338
|
breaks,
|
|
173
339
|
}),
|
|
174
340
|
)
|
|
@@ -182,21 +348,44 @@
|
|
|
182
348
|
const resolvedRewriteActions = $derived(
|
|
183
349
|
resolveRewriteActions(rewriteActions, onrewrite),
|
|
184
350
|
)
|
|
351
|
+
const directRewriteAction = $derived(
|
|
352
|
+
resolvedRewriteActions.length === 1 ? resolvedRewriteActions[0] : null,
|
|
353
|
+
)
|
|
354
|
+
// 新版工具条支持 paragraph / heading1-4,优先走细粒度回调,避免把旧接口误当成新接口调用。
|
|
355
|
+
const richBlockFormattingEnabled = $derived(Boolean(onapplyblockstyle))
|
|
356
|
+
// 旧版 heading / bullet 回调仍然保留,用于兼容外部还没迁移的调用方。
|
|
357
|
+
const legacyBlockFormattingEnabled = $derived(
|
|
358
|
+
Boolean(onapplyblockformat) && !onapplyblockstyle,
|
|
359
|
+
)
|
|
360
|
+
// 这里统一判断是否存在任意块级格式能力,方便控制分隔线和浮层显隐。
|
|
361
|
+
const anyBlockFormattingEnabled = $derived(
|
|
362
|
+
richBlockFormattingEnabled || legacyBlockFormattingEnabled,
|
|
363
|
+
)
|
|
185
364
|
// selectionToolsEnabled 统一判断选区工具条是否值得出现,避免正文只读展示时还露出空浮层。
|
|
186
365
|
const selectionToolsEnabled = $derived(
|
|
187
366
|
[
|
|
188
367
|
onrewrite,
|
|
189
|
-
|
|
368
|
+
anyBlockFormattingEnabled,
|
|
190
369
|
onapplyinlineformat,
|
|
370
|
+
onapplyalignment,
|
|
371
|
+
onapplylink,
|
|
372
|
+
onapplycolor,
|
|
191
373
|
oncopyselection,
|
|
192
374
|
onannotation,
|
|
193
375
|
].some(Boolean),
|
|
194
376
|
)
|
|
377
|
+
// 当前段落样式的展示文案,直接来自 `selectionFormatState`,避免按钮标题和下拉选中值不同步。
|
|
378
|
+
const activeBlockFormatOption = $derived(
|
|
379
|
+
BLOCK_FORMAT_OPTIONS.find(
|
|
380
|
+
option => option.value === selectionFormatState.blockFormat,
|
|
381
|
+
) ?? BLOCK_FORMAT_OPTIONS[0],
|
|
382
|
+
)
|
|
195
383
|
// readerDocumentClass 只负责正文文章区域,不和外层容器类名混用。
|
|
196
384
|
const readerDocumentClass = $derived(
|
|
197
385
|
cn(
|
|
198
386
|
'hai-markdown',
|
|
199
387
|
'hai-markdown-document',
|
|
388
|
+
sourceKind === 'code' ? 'hai-markdown-code-only' : '',
|
|
200
389
|
editable ? 'hai-markdown-editable' : '',
|
|
201
390
|
),
|
|
202
391
|
)
|
|
@@ -242,6 +431,7 @@
|
|
|
242
431
|
|
|
243
432
|
$effect(() => {
|
|
244
433
|
void documentContent
|
|
434
|
+
codePreviews = {}
|
|
245
435
|
closeSelectionToolbar()
|
|
246
436
|
})
|
|
247
437
|
|
|
@@ -259,6 +449,33 @@
|
|
|
259
449
|
if (copyFeedbackTimer) {
|
|
260
450
|
window.clearTimeout(copyFeedbackTimer)
|
|
261
451
|
}
|
|
452
|
+
|
|
453
|
+
if (selectionRefreshFrame) {
|
|
454
|
+
window.cancelAnimationFrame(selectionRefreshFrame)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (selectionToolbarCloseTimer) {
|
|
458
|
+
window.clearTimeout(selectionToolbarCloseTimer)
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
$effect(() => {
|
|
464
|
+
if (typeof document === 'undefined' || !previewHost || !selectionToolsEnabled) {
|
|
465
|
+
return
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const handleDocumentSelectionChange = (): void => {
|
|
469
|
+
queueSelectionRefresh()
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
document.addEventListener('selectionchange', handleDocumentSelectionChange)
|
|
473
|
+
|
|
474
|
+
return () => {
|
|
475
|
+
document.removeEventListener(
|
|
476
|
+
'selectionchange',
|
|
477
|
+
handleDocumentSelectionChange,
|
|
478
|
+
)
|
|
262
479
|
}
|
|
263
480
|
})
|
|
264
481
|
|
|
@@ -282,6 +499,8 @@
|
|
|
282
499
|
]
|
|
283
500
|
}
|
|
284
501
|
|
|
502
|
+
const HTML_DOCUMENT_PATTERN = /<!doctype html>|<html[\s>]|<body[\s>]|<div[\s>]|<main[\s>]/i
|
|
503
|
+
|
|
285
504
|
async function copyRawContent(): Promise<boolean> {
|
|
286
505
|
try {
|
|
287
506
|
await navigator.clipboard.writeText(content)
|
|
@@ -348,9 +567,7 @@
|
|
|
348
567
|
}
|
|
349
568
|
|
|
350
569
|
function looksLikeHtml(code: string): boolean {
|
|
351
|
-
return
|
|
352
|
-
code,
|
|
353
|
-
)
|
|
570
|
+
return HTML_DOCUMENT_PATTERN.test(code)
|
|
354
571
|
}
|
|
355
572
|
|
|
356
573
|
function buildJavaScriptPreview(code: string): string {
|
|
@@ -467,6 +684,38 @@ ${safeCode}
|
|
|
467
684
|
return undefined
|
|
468
685
|
}
|
|
469
686
|
|
|
687
|
+
function formatPreviewLanguageLabel(language: string | undefined): string | null {
|
|
688
|
+
const normalized = language?.trim().toLocaleLowerCase()
|
|
689
|
+
if (!normalized) {
|
|
690
|
+
return null
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (
|
|
694
|
+
normalized === 'javascript'
|
|
695
|
+
|| normalized === 'js'
|
|
696
|
+
|| normalized === 'mjs'
|
|
697
|
+
) {
|
|
698
|
+
return 'JavaScript'
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (normalized === 'markdown' || normalized === 'md') {
|
|
702
|
+
return 'Markdown'
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return normalized.toUpperCase()
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function resolvePreviewUnavailableMessage(language: string | undefined): string {
|
|
709
|
+
const languageLabel = formatPreviewLanguageLabel(language)
|
|
710
|
+
if (!languageLabel) {
|
|
711
|
+
return uiM('markdown_run_unavailable')
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return uiM('markdown_run_unavailable_language', {
|
|
715
|
+
language: languageLabel,
|
|
716
|
+
})
|
|
717
|
+
}
|
|
718
|
+
|
|
470
719
|
async function runCodeBlock(blockId: string): Promise<void> {
|
|
471
720
|
const codeBlock = lookupCodeBlock(blockId)
|
|
472
721
|
if (!codeBlock) {
|
|
@@ -497,7 +746,7 @@ ${safeCode}
|
|
|
497
746
|
...codePreviews,
|
|
498
747
|
[blockId]: {
|
|
499
748
|
status: 'error',
|
|
500
|
-
error:
|
|
749
|
+
error: resolvePreviewUnavailableMessage(request.language),
|
|
501
750
|
},
|
|
502
751
|
}
|
|
503
752
|
return
|
|
@@ -523,6 +772,20 @@ ${safeCode}
|
|
|
523
772
|
}
|
|
524
773
|
}
|
|
525
774
|
|
|
775
|
+
function setCodeBlockView(
|
|
776
|
+
codeBlock: HTMLElement,
|
|
777
|
+
view: 'code' | 'preview',
|
|
778
|
+
): void {
|
|
779
|
+
codeBlock.dataset.codeView = view
|
|
780
|
+
const toggleButtons = codeBlock.querySelectorAll<HTMLButtonElement>(
|
|
781
|
+
'[data-code-view-toggle]',
|
|
782
|
+
)
|
|
783
|
+
for (const button of toggleButtons) {
|
|
784
|
+
const isActive = button.dataset.codeView === view
|
|
785
|
+
button.setAttribute('aria-pressed', isActive ? 'true' : 'false')
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
526
789
|
async function handleClick(event: MouseEvent): Promise<void> {
|
|
527
790
|
const target = event.target as HTMLElement
|
|
528
791
|
const copyButton = target.closest(
|
|
@@ -533,6 +796,26 @@ ${safeCode}
|
|
|
533
796
|
return
|
|
534
797
|
}
|
|
535
798
|
|
|
799
|
+
const viewButton = target.closest(
|
|
800
|
+
'[data-code-view-toggle]',
|
|
801
|
+
) as HTMLButtonElement | null
|
|
802
|
+
const viewCodeBlock = viewButton?.closest<HTMLElement>('.hai-md-code-block')
|
|
803
|
+
const viewCodeBlockId = viewButton?.dataset.codeBlockId
|
|
804
|
+
const nextView = viewButton?.dataset.codeView === 'preview'
|
|
805
|
+
? 'preview'
|
|
806
|
+
: 'code'
|
|
807
|
+
if (viewButton && viewCodeBlock) {
|
|
808
|
+
setCodeBlockView(viewCodeBlock, nextView)
|
|
809
|
+
if (
|
|
810
|
+
nextView === 'preview'
|
|
811
|
+
&& viewCodeBlockId
|
|
812
|
+
&& codePreviews[viewCodeBlockId]?.status !== 'ready'
|
|
813
|
+
) {
|
|
814
|
+
await runCodeBlock(viewCodeBlockId)
|
|
815
|
+
}
|
|
816
|
+
return
|
|
817
|
+
}
|
|
818
|
+
|
|
536
819
|
const runButton = target.closest(
|
|
537
820
|
'[data-run-code]',
|
|
538
821
|
) as HTMLButtonElement | null
|
|
@@ -574,12 +857,12 @@ ${safeCode}
|
|
|
574
857
|
}
|
|
575
858
|
|
|
576
859
|
if (preview.status === 'running') {
|
|
577
|
-
host.innerHTML = `<div class="hai-md-preview-card"><div class="hai-md-preview-
|
|
860
|
+
host.innerHTML = `<div class="hai-md-preview-card"><div class="hai-md-preview-empty"><div class="hai-md-preview-empty-title">${escapePreviewText(uiM('markdown_running'))}</div><div class="hai-md-preview-loading"></div></div></div>`
|
|
578
861
|
return
|
|
579
862
|
}
|
|
580
863
|
|
|
581
864
|
if (preview.status === 'error') {
|
|
582
|
-
host.innerHTML = `<div class="hai-md-preview-card hai-md-preview-error"><div class="hai-md-preview-
|
|
865
|
+
host.innerHTML = `<div class="hai-md-preview-card hai-md-preview-error"><div class="hai-md-preview-empty"><div class="hai-md-preview-empty-title">${escapePreviewText(uiM('markdown_run_failed'))}</div><p class="hai-md-preview-empty-text">${escapePreviewText(preview.error ?? uiM('markdown_run_failed'))}</p></div></div>`
|
|
583
866
|
return
|
|
584
867
|
}
|
|
585
868
|
|
|
@@ -605,7 +888,6 @@ ${safeCode}
|
|
|
605
888
|
const markdownHtml = parseMarkdown(result.content, {
|
|
606
889
|
enableHighlight,
|
|
607
890
|
showCopyButton: false,
|
|
608
|
-
showRunButton: false,
|
|
609
891
|
breaks,
|
|
610
892
|
})
|
|
611
893
|
|
|
@@ -629,10 +911,323 @@ ${safeCode}
|
|
|
629
911
|
return escapePreviewText(value).replace(/\n/g, ' ')
|
|
630
912
|
}
|
|
631
913
|
|
|
914
|
+
function getSelectionAnchorElement(selection: Selection): HTMLElement | null {
|
|
915
|
+
const anchorNode = selection.anchorNode
|
|
916
|
+
if (!anchorNode) {
|
|
917
|
+
return null
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
return anchorNode instanceof HTMLElement
|
|
921
|
+
? anchorNode
|
|
922
|
+
: anchorNode.parentElement
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function getClosestBlockElement(element: HTMLElement | null): HTMLElement | null {
|
|
926
|
+
if (!element || !previewHost) {
|
|
927
|
+
return null
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const block = element.closest('p, h1, h2, h3, h4, h5, h6, li')
|
|
931
|
+
return block instanceof HTMLElement && previewHost.contains(block)
|
|
932
|
+
? block
|
|
933
|
+
: null
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
function readComputedInlineState(element: HTMLElement | null): Pick<
|
|
937
|
+
SelectionFormatState,
|
|
938
|
+
'bold' | 'italic' | 'strike' | 'underline'
|
|
939
|
+
> {
|
|
940
|
+
if (!element || typeof window === 'undefined') {
|
|
941
|
+
return {
|
|
942
|
+
bold: false,
|
|
943
|
+
italic: false,
|
|
944
|
+
strike: false,
|
|
945
|
+
underline: false,
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
const style = window.getComputedStyle(element)
|
|
950
|
+
const fontWeight = Number.parseInt(style.fontWeight, 10)
|
|
951
|
+
const decoration = `${style.textDecorationLine} ${style.textDecoration}`
|
|
952
|
+
.toLowerCase()
|
|
953
|
+
|
|
954
|
+
return {
|
|
955
|
+
bold: Number.isNaN(fontWeight)
|
|
956
|
+
? ['bold', 'bolder'].includes(style.fontWeight.toLowerCase())
|
|
957
|
+
: fontWeight >= 600,
|
|
958
|
+
italic:
|
|
959
|
+
style.fontStyle === 'italic' || style.fontStyle.startsWith('oblique'),
|
|
960
|
+
strike: decoration.includes('line-through'),
|
|
961
|
+
underline: decoration.includes('underline'),
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function readBlockFormat(element: HTMLElement | null): MarkdownBlockStyleKind {
|
|
966
|
+
const tagName = getClosestBlockElement(element)?.tagName.toLowerCase()
|
|
967
|
+
|
|
968
|
+
if (tagName === 'h1') {
|
|
969
|
+
return 'heading1'
|
|
970
|
+
}
|
|
971
|
+
if (tagName === 'h2') {
|
|
972
|
+
return 'heading2'
|
|
973
|
+
}
|
|
974
|
+
if (tagName === 'h3') {
|
|
975
|
+
return 'heading3'
|
|
976
|
+
}
|
|
977
|
+
if (tagName === 'h4') {
|
|
978
|
+
return 'heading4'
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
return 'paragraph'
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
function normalizeTextAlign(value: string | null | undefined): MarkdownTextAlignKind | null {
|
|
985
|
+
const normalized = value?.trim().toLowerCase()
|
|
986
|
+
if (!normalized) {
|
|
987
|
+
return null
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if (normalized === 'start') {
|
|
991
|
+
return 'left'
|
|
992
|
+
}
|
|
993
|
+
if (normalized === 'end') {
|
|
994
|
+
return 'right'
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
return normalized === 'center'
|
|
998
|
+
|| normalized === 'right'
|
|
999
|
+
|| normalized === 'justify'
|
|
1000
|
+
|| normalized === 'left'
|
|
1001
|
+
? normalized
|
|
1002
|
+
: null
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
function readAlignment(element: HTMLElement | null): MarkdownTextAlignKind {
|
|
1006
|
+
const block = getClosestBlockElement(element)
|
|
1007
|
+
if (!block || typeof window === 'undefined') {
|
|
1008
|
+
return 'left'
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// 对齐样式可能挂在外层 `<hai-align>` 容器上,单读 block 的 inline style 会丢失真实状态。
|
|
1012
|
+
const alignHost = block.closest<HTMLElement>('.hai-md-align-block') || block
|
|
1013
|
+
const computedAlign = normalizeTextAlign(
|
|
1014
|
+
window.getComputedStyle(alignHost).textAlign,
|
|
1015
|
+
)
|
|
1016
|
+
const attributeAlignCandidate
|
|
1017
|
+
= alignHost.dataset.haiAlign
|
|
1018
|
+
|| alignHost.getAttribute('align')
|
|
1019
|
+
|| block.getAttribute('align')
|
|
1020
|
+
const attributeAlign = normalizeTextAlign(
|
|
1021
|
+
attributeAlignCandidate,
|
|
1022
|
+
)
|
|
1023
|
+
|
|
1024
|
+
return computedAlign || attributeAlign || 'left'
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
function readSelectionFormatState(selection: Selection): SelectionFormatState {
|
|
1028
|
+
const anchorElement = getSelectionAnchorElement(selection)
|
|
1029
|
+
const colorHost = anchorElement?.closest<HTMLElement>('[data-hai-color], [data-hai-bg]')
|
|
1030
|
+
const linkHost = anchorElement?.closest<HTMLAnchorElement>('a[href]')
|
|
1031
|
+
const codeHost = anchorElement?.closest<HTMLElement>('code')
|
|
1032
|
+
const highlightHost = anchorElement?.closest<HTMLElement>('mark')
|
|
1033
|
+
const inlineState = readComputedInlineState(anchorElement)
|
|
1034
|
+
const hasHighlight = Boolean((highlightHost && previewHost?.contains(highlightHost)) || colorHost?.dataset.haiBg?.trim())
|
|
1035
|
+
const textColor = colorHost?.dataset.haiColor?.trim()
|
|
1036
|
+
|| anchorElement?.closest<HTMLElement>('[data-hai-color]')?.dataset.haiColor
|
|
1037
|
+
|| null
|
|
1038
|
+
const backgroundColor = colorHost?.dataset.haiBg?.trim()
|
|
1039
|
+
|| anchorElement?.closest<HTMLElement>('[data-hai-bg]')?.dataset.haiBg
|
|
1040
|
+
|| null
|
|
1041
|
+
|
|
1042
|
+
return {
|
|
1043
|
+
blockFormat: readBlockFormat(anchorElement),
|
|
1044
|
+
alignment: readAlignment(anchorElement),
|
|
1045
|
+
bold: inlineState.bold,
|
|
1046
|
+
strike: inlineState.strike,
|
|
1047
|
+
italic: inlineState.italic,
|
|
1048
|
+
underline: inlineState.underline,
|
|
1049
|
+
highlight: hasHighlight,
|
|
1050
|
+
code: Boolean(codeHost && previewHost?.contains(codeHost)),
|
|
1051
|
+
linkHref:
|
|
1052
|
+
linkHost && previewHost?.contains(linkHost)
|
|
1053
|
+
? (linkHost.getAttribute('href') ?? '')
|
|
1054
|
+
: '',
|
|
1055
|
+
textColor,
|
|
1056
|
+
backgroundColor,
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
function readPreviewSelectionState(): PreviewSelectionState | null {
|
|
1061
|
+
if (typeof window === 'undefined' || !previewHost) {
|
|
1062
|
+
return null
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
const selection = window.getSelection()
|
|
1066
|
+
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
|
1067
|
+
return null
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const anchorNode = selection.anchorNode
|
|
1071
|
+
const focusNode = selection.focusNode
|
|
1072
|
+
if (
|
|
1073
|
+
!anchorNode
|
|
1074
|
+
|| !focusNode
|
|
1075
|
+
|| !previewHost.contains(anchorNode)
|
|
1076
|
+
|| !previewHost.contains(focusNode)
|
|
1077
|
+
) {
|
|
1078
|
+
return null
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
const text = selection.toString().trim()
|
|
1082
|
+
if (!text) {
|
|
1083
|
+
return null
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
return {
|
|
1087
|
+
selection,
|
|
1088
|
+
range: selection.getRangeAt(0),
|
|
1089
|
+
text,
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
function clearPendingSelectionToolbarClose(): void {
|
|
1094
|
+
if (typeof window === 'undefined' || !selectionToolbarCloseTimer) {
|
|
1095
|
+
return
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
window.clearTimeout(selectionToolbarCloseTimer)
|
|
1099
|
+
selectionToolbarCloseTimer = undefined
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
function scheduleSelectionToolbarClose(): void {
|
|
1103
|
+
if (typeof window === 'undefined') {
|
|
1104
|
+
closeSelectionToolbar()
|
|
1105
|
+
return
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
if (!selectionToolbarVisible) {
|
|
1109
|
+
closeSelectionToolbar()
|
|
1110
|
+
return
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
clearPendingSelectionToolbarClose()
|
|
1114
|
+
selectionToolbarCloseTimer = window.setTimeout(() => {
|
|
1115
|
+
selectionToolbarCloseTimer = undefined
|
|
1116
|
+
if (!readPreviewSelectionState()) {
|
|
1117
|
+
closeSelectionToolbar()
|
|
1118
|
+
}
|
|
1119
|
+
}, 120)
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
function queueSelectionRefresh(remeasured = false): void {
|
|
1123
|
+
if (typeof window === 'undefined') {
|
|
1124
|
+
return
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
selectionRefreshNeedsRemeasure ||= remeasured
|
|
1128
|
+
if (selectionRefreshFrame) {
|
|
1129
|
+
return
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
selectionRefreshFrame = window.requestAnimationFrame(() => {
|
|
1133
|
+
const nextRemeasured = selectionRefreshNeedsRemeasure
|
|
1134
|
+
selectionRefreshFrame = undefined
|
|
1135
|
+
selectionRefreshNeedsRemeasure = false
|
|
1136
|
+
handleSelectionChange(nextRemeasured)
|
|
1137
|
+
})
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
function estimateSelectionMenuWidth(menu: SelectionMenuKind): number {
|
|
1141
|
+
if (menu === 'color' || menu === 'link') {
|
|
1142
|
+
return 256
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
if (menu === 'rewrite') {
|
|
1146
|
+
return 320
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
return 288
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
function updateSelectionMenuAnchor(menu: SelectionMenuKind): void {
|
|
1153
|
+
if (!selectionToolbarEl || !activeSelectionMenuTrigger) {
|
|
1154
|
+
selectionMenuLeft = 0
|
|
1155
|
+
selectionMenuAlignment = 'center'
|
|
1156
|
+
return
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
const toolbarWidth = Math.max(
|
|
1160
|
+
selectionToolbarEl.offsetWidth,
|
|
1161
|
+
selectionToolbarEl.clientWidth,
|
|
1162
|
+
)
|
|
1163
|
+
const triggerCenter
|
|
1164
|
+
= activeSelectionMenuTrigger.offsetLeft
|
|
1165
|
+
+ activeSelectionMenuTrigger.offsetWidth / 2
|
|
1166
|
+
const estimatedHalfWidth = Math.min(
|
|
1167
|
+
estimateSelectionMenuWidth(menu) / 2,
|
|
1168
|
+
Math.max(112, (toolbarWidth - 16) / 2),
|
|
1169
|
+
)
|
|
1170
|
+
const minCenter = 8 + estimatedHalfWidth
|
|
1171
|
+
const maxCenter = Math.max(minCenter, toolbarWidth - 8 - estimatedHalfWidth)
|
|
1172
|
+
|
|
1173
|
+
if (triggerCenter <= minCenter) {
|
|
1174
|
+
selectionMenuLeft = 0
|
|
1175
|
+
selectionMenuAlignment = 'left'
|
|
1176
|
+
return
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
if (triggerCenter >= maxCenter) {
|
|
1180
|
+
selectionMenuLeft = toolbarWidth
|
|
1181
|
+
selectionMenuAlignment = 'right'
|
|
1182
|
+
return
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
selectionMenuLeft = triggerCenter
|
|
1186
|
+
selectionMenuAlignment = 'center'
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
function scheduleSelectionToolbarMeasurement(): void {
|
|
1190
|
+
if (
|
|
1191
|
+
typeof window === 'undefined'
|
|
1192
|
+
|| selectionToolbarMeasurePending
|
|
1193
|
+
|| !selectionToolbarVisible
|
|
1194
|
+
) {
|
|
1195
|
+
return
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
selectionToolbarMeasurePending = true
|
|
1199
|
+
window.requestAnimationFrame(() => {
|
|
1200
|
+
selectionToolbarMeasurePending = false
|
|
1201
|
+
if (selectionToolbarVisible) {
|
|
1202
|
+
handleSelectionChange(true)
|
|
1203
|
+
}
|
|
1204
|
+
})
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
function toggleSelectionMenu(menu: SelectionMenuKind, event?: MouseEvent): void {
|
|
1208
|
+
const opening = activeSelectionMenu !== menu
|
|
1209
|
+
activeSelectionMenu = opening ? menu : null
|
|
1210
|
+
activeSelectionMenuTrigger = opening && event?.currentTarget instanceof HTMLElement
|
|
1211
|
+
? event.currentTarget
|
|
1212
|
+
: null
|
|
1213
|
+
if (opening) {
|
|
1214
|
+
updateSelectionMenuAnchor(menu)
|
|
1215
|
+
}
|
|
1216
|
+
if (opening && menu === 'link') {
|
|
1217
|
+
linkDraft = selectionFormatState.linkHref || 'https://'
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
632
1221
|
function closeSelectionToolbar(): void {
|
|
1222
|
+
clearPendingSelectionToolbarClose()
|
|
633
1223
|
selectionToolbarVisible = false
|
|
634
|
-
|
|
1224
|
+
activeSelectionMenu = null
|
|
1225
|
+
activeSelectionMenuTrigger = null
|
|
1226
|
+
selectionMenuLeft = 0
|
|
1227
|
+
selectionMenuAlignment = 'center'
|
|
635
1228
|
selectedText = ''
|
|
1229
|
+
linkDraft = ''
|
|
1230
|
+
selectionFormatState = { ...DEFAULT_SELECTION_FORMAT_STATE }
|
|
636
1231
|
}
|
|
637
1232
|
|
|
638
1233
|
/**
|
|
@@ -683,9 +1278,8 @@ ${safeCode}
|
|
|
683
1278
|
return
|
|
684
1279
|
}
|
|
685
1280
|
|
|
686
|
-
const firstHeading
|
|
687
|
-
'[data-heading-id]'
|
|
688
|
-
)
|
|
1281
|
+
const firstHeading
|
|
1282
|
+
= previewHost.querySelector<HTMLElement>('[data-heading-id]')
|
|
689
1283
|
if (!firstHeading) {
|
|
690
1284
|
showPinnedTitle = true
|
|
691
1285
|
return
|
|
@@ -700,7 +1294,7 @@ ${safeCode}
|
|
|
700
1294
|
syncActiveHeadingFromScroll()
|
|
701
1295
|
syncPinnedTitleVisibility()
|
|
702
1296
|
if (selectionToolbarVisible) {
|
|
703
|
-
|
|
1297
|
+
queueSelectionRefresh(true)
|
|
704
1298
|
}
|
|
705
1299
|
ondocumentscroll?.(event)
|
|
706
1300
|
}
|
|
@@ -724,7 +1318,7 @@ ${safeCode}
|
|
|
724
1318
|
* 选区工具条依赖真实 DOM 选区范围,因此只在 selection 落在当前正文容器内时显示。
|
|
725
1319
|
* 一旦内容刷新或滚动位置变化,就主动关闭,避免把旧选区动作误用到新内容上。
|
|
726
1320
|
*/
|
|
727
|
-
function handleSelectionChange(): void {
|
|
1321
|
+
function handleSelectionChange(remeasured = false): void {
|
|
728
1322
|
if (
|
|
729
1323
|
!selectionToolsEnabled
|
|
730
1324
|
|| typeof window === 'undefined'
|
|
@@ -734,79 +1328,70 @@ ${safeCode}
|
|
|
734
1328
|
return
|
|
735
1329
|
}
|
|
736
1330
|
|
|
737
|
-
|
|
738
|
-
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
|
739
|
-
closeSelectionToolbar()
|
|
740
|
-
return
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
const anchorNode = selection.anchorNode
|
|
744
|
-
const focusNode = selection.focusNode
|
|
745
|
-
if (
|
|
746
|
-
!anchorNode
|
|
747
|
-
|| !focusNode
|
|
748
|
-
|| !previewHost.contains(anchorNode)
|
|
749
|
-
|| !previewHost.contains(focusNode)
|
|
750
|
-
) {
|
|
751
|
-
closeSelectionToolbar()
|
|
752
|
-
return
|
|
753
|
-
}
|
|
1331
|
+
clearPendingSelectionToolbarClose()
|
|
754
1332
|
|
|
755
|
-
const
|
|
756
|
-
if (!
|
|
757
|
-
|
|
1333
|
+
const previewSelection = readPreviewSelectionState()
|
|
1334
|
+
if (!previewSelection) {
|
|
1335
|
+
scheduleSelectionToolbarClose()
|
|
758
1336
|
return
|
|
759
1337
|
}
|
|
760
1338
|
|
|
761
|
-
const range =
|
|
1339
|
+
const { selection, range, text } = previewSelection
|
|
762
1340
|
const rect = range.getBoundingClientRect()
|
|
763
1341
|
const hostRect = editorScrollHost.getBoundingClientRect()
|
|
764
1342
|
// 浮层尺寸在首次渲染前拿不到精确高度,这里用稳定的经验值决定上下避让方向,避免直接盖住选中文本。
|
|
765
|
-
const estimatedToolbarHeight =
|
|
1343
|
+
const estimatedToolbarHeight = 60
|
|
766
1344
|
const offset = 12
|
|
767
1345
|
const topSpace = rect.top - hostRect.top
|
|
768
1346
|
const bottomSpace = hostRect.bottom - rect.bottom
|
|
769
|
-
const placement
|
|
770
|
-
= topSpace >= estimatedToolbarHeight + offset
|
|
1347
|
+
const placement: SelectionToolbarPosition['placement']
|
|
1348
|
+
= topSpace >= estimatedToolbarHeight + offset
|
|
1349
|
+
|| bottomSpace < estimatedToolbarHeight
|
|
771
1350
|
? 'top'
|
|
772
1351
|
: 'bottom'
|
|
773
1352
|
const center = rect.left - hostRect.left + rect.width / 2
|
|
774
1353
|
const horizontalPadding = 16
|
|
1354
|
+
const measuredToolbarHalfWidth = selectionToolbarEl
|
|
1355
|
+
? selectionToolbarEl.offsetWidth / 2
|
|
1356
|
+
: 320
|
|
775
1357
|
const estimatedToolbarHalfWidth = Math.min(
|
|
776
|
-
|
|
777
|
-
Math.max(
|
|
778
|
-
132,
|
|
779
|
-
(editorScrollHost.clientWidth - horizontalPadding * 2) / 2,
|
|
780
|
-
),
|
|
1358
|
+
Math.max(132, measuredToolbarHalfWidth),
|
|
1359
|
+
Math.max(132, (editorScrollHost.clientWidth - horizontalPadding * 2) / 2),
|
|
781
1360
|
)
|
|
782
1361
|
const minCenter = horizontalPadding + estimatedToolbarHalfWidth
|
|
783
1362
|
const maxCenter = editorScrollHost.clientWidth - minCenter
|
|
784
|
-
const alignment
|
|
1363
|
+
const alignment: SelectionToolbarPosition['alignment']
|
|
785
1364
|
= center <= minCenter
|
|
786
1365
|
? 'left'
|
|
787
1366
|
: center >= maxCenter
|
|
788
1367
|
? 'right'
|
|
789
1368
|
: 'center'
|
|
790
|
-
const toolbarLeft
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
? editorScrollHost.scrollTop + rect.top - hostRect.top - estimatedToolbarHeight - offset
|
|
799
|
-
: editorScrollHost.scrollTop + rect.bottom - hostRect.top + offset
|
|
1369
|
+
const toolbarLeft = alignment === 'left'
|
|
1370
|
+
? horizontalPadding
|
|
1371
|
+
: alignment === 'right'
|
|
1372
|
+
? editorScrollHost.clientWidth - horizontalPadding
|
|
1373
|
+
: center
|
|
1374
|
+
const toolbarTop = placement === 'top'
|
|
1375
|
+
? editorScrollHost.scrollTop + rect.top - hostRect.top - estimatedToolbarHeight - offset
|
|
1376
|
+
: editorScrollHost.scrollTop + rect.bottom - hostRect.top + offset
|
|
800
1377
|
|
|
801
1378
|
selectedText = text
|
|
802
1379
|
selectionToolbarVisible = true
|
|
803
|
-
|
|
1380
|
+
selectionFormatState = readSelectionFormatState(selection)
|
|
804
1381
|
toolbarPosition = {
|
|
805
1382
|
top: Math.max(12, toolbarTop),
|
|
806
1383
|
left: Math.max(horizontalPadding, toolbarLeft),
|
|
807
1384
|
placement,
|
|
808
1385
|
alignment,
|
|
809
1386
|
}
|
|
1387
|
+
|
|
1388
|
+
if (activeSelectionMenu) {
|
|
1389
|
+
updateSelectionMenuAnchor(activeSelectionMenu)
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (!remeasured) {
|
|
1393
|
+
scheduleSelectionToolbarMeasurement()
|
|
1394
|
+
}
|
|
810
1395
|
}
|
|
811
1396
|
|
|
812
1397
|
async function applyRewrite(actionId: string): Promise<void> {
|
|
@@ -814,7 +1399,8 @@ ${safeCode}
|
|
|
814
1399
|
return
|
|
815
1400
|
}
|
|
816
1401
|
|
|
817
|
-
|
|
1402
|
+
activeSelectionMenu = null
|
|
1403
|
+
activeSelectionMenuTrigger = null
|
|
818
1404
|
await onrewrite({
|
|
819
1405
|
actionId,
|
|
820
1406
|
selectedText,
|
|
@@ -825,26 +1411,63 @@ ${safeCode}
|
|
|
825
1411
|
|
|
826
1412
|
function applyBlockFormat(kind: MarkdownBlockFormatKind): void {
|
|
827
1413
|
onapplyblockformat?.(kind)
|
|
828
|
-
|
|
1414
|
+
activeSelectionMenu = null
|
|
1415
|
+
activeSelectionMenuTrigger = null
|
|
1416
|
+
queueSelectionRefresh()
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
function applyBlockStyle(kind: MarkdownBlockStyleKind): void {
|
|
1420
|
+
onapplyblockstyle?.(kind)
|
|
1421
|
+
activeSelectionMenu = null
|
|
1422
|
+
activeSelectionMenuTrigger = null
|
|
1423
|
+
queueSelectionRefresh()
|
|
829
1424
|
}
|
|
830
1425
|
|
|
831
1426
|
function applyInlineFormat(kind: MarkdownInlineFormatKind): void {
|
|
832
1427
|
onapplyinlineformat?.(kind)
|
|
833
|
-
|
|
1428
|
+
queueSelectionRefresh()
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
function applyAlignment(kind: MarkdownTextAlignKind): void {
|
|
1432
|
+
onapplyalignment?.(kind)
|
|
1433
|
+
activeSelectionMenu = null
|
|
1434
|
+
activeSelectionMenuTrigger = null
|
|
1435
|
+
queueSelectionRefresh()
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
function applyLink(): void {
|
|
1439
|
+
onapplylink?.(linkDraft.trim() || null)
|
|
1440
|
+
activeSelectionMenu = null
|
|
1441
|
+
activeSelectionMenuTrigger = null
|
|
1442
|
+
queueSelectionRefresh()
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
function removeLink(): void {
|
|
1446
|
+
onapplylink?.(null)
|
|
1447
|
+
activeSelectionMenu = null
|
|
1448
|
+
activeSelectionMenuTrigger = null
|
|
1449
|
+
queueSelectionRefresh()
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
function applyColor(request: MarkdownColorFormatRequest): void {
|
|
1453
|
+
onapplycolor?.(request)
|
|
1454
|
+
queueSelectionRefresh()
|
|
834
1455
|
}
|
|
835
1456
|
|
|
836
1457
|
async function copySelection(): Promise<void> {
|
|
837
1458
|
await oncopyselection?.()
|
|
838
|
-
|
|
1459
|
+
activeSelectionMenu = null
|
|
1460
|
+
activeSelectionMenuTrigger = null
|
|
839
1461
|
}
|
|
840
1462
|
|
|
841
1463
|
async function annotateSelection(): Promise<void> {
|
|
842
1464
|
await onannotation?.()
|
|
843
|
-
|
|
1465
|
+
activeSelectionMenu = null
|
|
1466
|
+
activeSelectionMenuTrigger = null
|
|
844
1467
|
}
|
|
845
1468
|
|
|
846
1469
|
function handlePreviewMouseUp(): void {
|
|
847
|
-
|
|
1470
|
+
queueSelectionRefresh()
|
|
848
1471
|
onpreviewmouseup?.()
|
|
849
1472
|
}
|
|
850
1473
|
|
|
@@ -853,7 +1476,7 @@ ${safeCode}
|
|
|
853
1476
|
}
|
|
854
1477
|
|
|
855
1478
|
function handlePreviewBlur(): void {
|
|
856
|
-
|
|
1479
|
+
queueSelectionRefresh(true)
|
|
857
1480
|
onpreviewblur?.()
|
|
858
1481
|
}
|
|
859
1482
|
</script>
|
|
@@ -893,6 +1516,7 @@ ${safeCode}
|
|
|
893
1516
|
type='button'
|
|
894
1517
|
class='hai-ai-doc-toolbar-icon'
|
|
895
1518
|
aria-label={uiM('markdown_undo')}
|
|
1519
|
+
title={`${uiM('markdown_undo')} (Ctrl/Cmd+Z)`}
|
|
896
1520
|
disabled={undoDisabled}
|
|
897
1521
|
onclick={onundo}
|
|
898
1522
|
>
|
|
@@ -909,6 +1533,7 @@ ${safeCode}
|
|
|
909
1533
|
type='button'
|
|
910
1534
|
class='hai-ai-doc-toolbar-icon'
|
|
911
1535
|
aria-label={uiM('markdown_redo')}
|
|
1536
|
+
title={`${uiM('markdown_redo')} (Ctrl/Cmd+Shift+Z)`}
|
|
912
1537
|
disabled={redoDisabled}
|
|
913
1538
|
onclick={onredo}
|
|
914
1539
|
>
|
|
@@ -951,12 +1576,12 @@ ${safeCode}
|
|
|
951
1576
|
</button>
|
|
952
1577
|
|
|
953
1578
|
<AiDocumentDownloadMenu
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1579
|
+
{content}
|
|
1580
|
+
{title}
|
|
1581
|
+
{sourceKind}
|
|
1582
|
+
{codeLanguage}
|
|
958
1583
|
actions={downloadActions}
|
|
959
|
-
|
|
1584
|
+
{ondownload}
|
|
960
1585
|
showLabel={true}
|
|
961
1586
|
iconOnly={false}
|
|
962
1587
|
triggerTitle={uiM('markdown_download')}
|
|
@@ -996,7 +1621,7 @@ ${safeCode}
|
|
|
996
1621
|
{/if}
|
|
997
1622
|
|
|
998
1623
|
<div
|
|
999
|
-
class:hai-ai-doc-layout-collapsed={outlineCollapsed}
|
|
1624
|
+
class:hai-ai-doc-layout-collapsed={!showOutline || outlineCollapsed}
|
|
1000
1625
|
class='hai-ai-doc-layout'
|
|
1001
1626
|
>
|
|
1002
1627
|
{#if showOutline && !outlineCollapsed}
|
|
@@ -1046,14 +1671,7 @@ ${safeCode}
|
|
|
1046
1671
|
class='hai-ai-doc-scroll'
|
|
1047
1672
|
onclick={handleClick}
|
|
1048
1673
|
onscroll={handleDocumentScroll}
|
|
1049
|
-
onkeyup={handleSelectionChange}
|
|
1050
|
-
onfocusout={() => {
|
|
1051
|
-
if (typeof window !== 'undefined') {
|
|
1052
|
-
window.setTimeout(() => {
|
|
1053
|
-
handleSelectionChange()
|
|
1054
|
-
}, 0)
|
|
1055
|
-
}
|
|
1056
|
-
}}
|
|
1674
|
+
onkeyup={() => handleSelectionChange()}
|
|
1057
1675
|
>
|
|
1058
1676
|
{#if selectionToolbarVisible}
|
|
1059
1677
|
<div
|
|
@@ -1063,189 +1681,521 @@ ${safeCode}
|
|
|
1063
1681
|
style={`top:${toolbarPosition.top}px; left:${toolbarPosition.left}px;`}
|
|
1064
1682
|
>
|
|
1065
1683
|
<div
|
|
1066
|
-
class='hai-ai-doc-selection-
|
|
1067
|
-
role='toolbar'
|
|
1068
|
-
tabindex='-1'
|
|
1069
|
-
onmousedown={event => event.preventDefault()}
|
|
1684
|
+
class='hai-ai-doc-selection-chrome'
|
|
1070
1685
|
>
|
|
1071
|
-
{#if onrewrite}
|
|
1072
|
-
<button
|
|
1073
|
-
type='button'
|
|
1074
|
-
class='hai-ai-doc-selection-chip'
|
|
1075
|
-
disabled={rewritePending}
|
|
1076
|
-
onclick={() => (rewriteMenuOpen = !rewriteMenuOpen)}
|
|
1077
|
-
>
|
|
1078
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1079
|
-
<path
|
|
1080
|
-
d='M12 3.25a.75.75 0 0 1 .72.55l1.06 3.62 3.63 1.06a.75.75 0 0 1 0 1.44l-3.63 1.06-1.06 3.63a.75.75 0 0 1-1.44 0l-1.06-3.63-3.63-1.06a.75.75 0 0 1 0-1.44l3.63-1.06 1.06-3.62a.75.75 0 0 1 .72-.55Zm6.5 11.5a.75.75 0 0 1 .72.55l.42 1.43 1.43.42a.75.75 0 0 1 0 1.44l-1.43.42-.42 1.43a.75.75 0 0 1-1.44 0l-.42-1.43-1.43-.42a.75.75 0 0 1 0-1.44l1.43-.42.42-1.43a.75.75 0 0 1 .72-.55Z'
|
|
1081
|
-
></path>
|
|
1082
|
-
</svg>
|
|
1083
|
-
<span>{uiM('markdown_rewrite')}</span>
|
|
1084
|
-
</button>
|
|
1085
|
-
{/if}
|
|
1086
|
-
|
|
1087
|
-
{#if onapplyblockformat}
|
|
1088
|
-
{#if onrewrite}
|
|
1089
|
-
<span class='hai-ai-doc-selection-divider'></span>
|
|
1090
|
-
{/if}
|
|
1091
|
-
<button
|
|
1092
|
-
type='button'
|
|
1093
|
-
class='hai-ai-doc-selection-btn'
|
|
1094
|
-
title={uiM('markdown_format_heading')}
|
|
1095
|
-
onclick={() => applyBlockFormat('heading')}
|
|
1096
|
-
>
|
|
1097
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1098
|
-
<path
|
|
1099
|
-
d='M5 5.25a.75.75 0 0 1 .75.75V11h6.5V6a.75.75 0 0 1 1.5 0v12a.75.75 0 0 1-1.5 0v-5.5h-6.5V18a.75.75 0 0 1-1.5 0V6A.75.75 0 0 1 5 5.25Zm11.25 2.5a.75.75 0 0 1 0 1.5h3a.75.75 0 0 1 0 1.5H18.5v8.5a.75.75 0 0 1-1.5 0v-8.5h-.75a.75.75 0 0 1 0-1.5h3Z'
|
|
1100
|
-
></path>
|
|
1101
|
-
</svg>
|
|
1102
|
-
</button>
|
|
1103
|
-
<button
|
|
1104
|
-
type='button'
|
|
1105
|
-
class='hai-ai-doc-selection-btn'
|
|
1106
|
-
title={uiM('markdown_format_bullet')}
|
|
1107
|
-
onclick={() => applyBlockFormat('bullet')}
|
|
1108
|
-
>
|
|
1109
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1110
|
-
<path
|
|
1111
|
-
d='M6.25 7.25a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Z'
|
|
1112
|
-
></path>
|
|
1113
|
-
</svg>
|
|
1114
|
-
</button>
|
|
1115
|
-
{/if}
|
|
1116
|
-
|
|
1117
|
-
{#if onapplyinlineformat}
|
|
1118
|
-
{#if onapplyblockformat}
|
|
1119
|
-
<span class='hai-ai-doc-selection-divider'></span>
|
|
1120
|
-
{/if}
|
|
1121
|
-
<button
|
|
1122
|
-
type='button'
|
|
1123
|
-
class='hai-ai-doc-selection-btn'
|
|
1124
|
-
title={uiM('markdown_format_bold')}
|
|
1125
|
-
onclick={() => applyInlineFormat('bold')}
|
|
1126
|
-
>
|
|
1127
|
-
<strong>B</strong>
|
|
1128
|
-
</button>
|
|
1129
|
-
<button
|
|
1130
|
-
type='button'
|
|
1131
|
-
class='hai-ai-doc-selection-btn'
|
|
1132
|
-
title={uiM('markdown_format_strike')}
|
|
1133
|
-
onclick={() => applyInlineFormat('strike')}
|
|
1134
|
-
>
|
|
1135
|
-
S
|
|
1136
|
-
</button>
|
|
1137
|
-
<button
|
|
1138
|
-
type='button'
|
|
1139
|
-
class='hai-ai-doc-selection-btn'
|
|
1140
|
-
title={uiM('markdown_format_italic')}
|
|
1141
|
-
onclick={() => applyInlineFormat('italic')}
|
|
1142
|
-
>
|
|
1143
|
-
<em>I</em>
|
|
1144
|
-
</button>
|
|
1145
|
-
<button
|
|
1146
|
-
type='button'
|
|
1147
|
-
class='hai-ai-doc-selection-btn'
|
|
1148
|
-
title={uiM('markdown_format_underline')}
|
|
1149
|
-
onclick={() => applyInlineFormat('underline')}
|
|
1150
|
-
>
|
|
1151
|
-
U
|
|
1152
|
-
</button>
|
|
1153
|
-
<button
|
|
1154
|
-
type='button'
|
|
1155
|
-
class='hai-ai-doc-selection-btn'
|
|
1156
|
-
title={uiM('markdown_format_link')}
|
|
1157
|
-
onclick={() => applyInlineFormat('link')}
|
|
1158
|
-
>
|
|
1159
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1160
|
-
<path
|
|
1161
|
-
d='M7.78 15.72a3.75 3.75 0 0 1 0-5.3l2.47-2.47a3.75 3.75 0 0 1 5.3 5.3l-.97.98a.75.75 0 0 1-1.06-1.06l.98-.97a2.25 2.25 0 0 0-3.19-3.19l-2.47 2.47a2.25 2.25 0 1 0 3.18 3.18l.49-.49a.75.75 0 0 1 1.06 1.06l-.49.49a3.75 3.75 0 0 1-5.3 0Zm8.44-7.44a.75.75 0 0 1 0 1.06l-8 8a.75.75 0 0 1-1.06-1.06l8-8a.75.75 0 0 1 1.06 0Z'
|
|
1162
|
-
></path>
|
|
1163
|
-
</svg>
|
|
1164
|
-
</button>
|
|
1165
|
-
<button
|
|
1166
|
-
type='button'
|
|
1167
|
-
class='hai-ai-doc-selection-btn'
|
|
1168
|
-
title={uiM('markdown_format_code')}
|
|
1169
|
-
onclick={() => applyInlineFormat('code')}
|
|
1170
|
-
>
|
|
1171
|
-
</>
|
|
1172
|
-
</button>
|
|
1173
|
-
<button
|
|
1174
|
-
type='button'
|
|
1175
|
-
class='hai-ai-doc-selection-btn'
|
|
1176
|
-
title={uiM('markdown_format_highlight')}
|
|
1177
|
-
onclick={() => applyInlineFormat('highlight')}
|
|
1178
|
-
>
|
|
1179
|
-
<span class='hai-ai-doc-selection-highlight-icon'>A</span>
|
|
1180
|
-
</button>
|
|
1181
|
-
{/if}
|
|
1182
|
-
|
|
1183
|
-
{#if oncopyselection || onannotation}
|
|
1184
|
-
{#if onapplyinlineformat}
|
|
1185
|
-
<span class='hai-ai-doc-selection-divider'></span>
|
|
1186
|
-
{/if}
|
|
1187
|
-
{/if}
|
|
1188
|
-
|
|
1189
|
-
{#if oncopyselection}
|
|
1190
|
-
<button
|
|
1191
|
-
type='button'
|
|
1192
|
-
class='hai-ai-doc-selection-btn hai-ai-doc-selection-btn-wide'
|
|
1193
|
-
title={uiM('markdown_copy_selection')}
|
|
1194
|
-
onclick={copySelection}
|
|
1195
|
-
>
|
|
1196
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1197
|
-
<path
|
|
1198
|
-
d='M8.75 4.25A2.75 2.75 0 0 0 6 7v8.25A2.75 2.75 0 0 0 8.75 18h7.5A2.75 2.75 0 0 0 19 15.25V7a2.75 2.75 0 0 0-2.75-2.75h-7.5Zm-4 3A2.75 2.75 0 0 1 7.5 4.5a.75.75 0 0 0 0-1.5A4.25 4.25 0 0 0 3.25 7.25v8.5A4.25 4.25 0 0 0 7.5 20a.75.75 0 0 0 0-1.5 2.75 2.75 0 0 1-2.75-2.75v-8.5Z'
|
|
1199
|
-
></path>
|
|
1200
|
-
</svg>
|
|
1201
|
-
</button>
|
|
1202
|
-
{/if}
|
|
1203
|
-
|
|
1204
|
-
{#if onannotation}
|
|
1205
|
-
<button
|
|
1206
|
-
type='button'
|
|
1207
|
-
class='hai-ai-doc-selection-btn hai-ai-doc-selection-btn-wide'
|
|
1208
|
-
title={uiM('markdown_annotation')}
|
|
1209
|
-
onclick={annotateSelection}
|
|
1210
|
-
>
|
|
1211
|
-
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1212
|
-
<path
|
|
1213
|
-
d='M6.75 4.25A2.75 2.75 0 0 0 4 7v7.75A2.75 2.75 0 0 0 6.75 17.5h1.72l2.3 2.01a1.75 1.75 0 0 0 2.3 0l2.3-2.01h1.88A2.75 2.75 0 0 0 20 14.75V7a2.75 2.75 0 0 0-2.75-2.75H6.75Zm1.5 4a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5H9a.75.75 0 0 1-.75-.75Zm0 3.5A.75.75 0 0 1 9 11h4a.75.75 0 0 1 0 1.5H9a.75.75 0 0 1-.75-.75Z'
|
|
1214
|
-
></path>
|
|
1215
|
-
</svg>
|
|
1216
|
-
</button>
|
|
1217
|
-
{/if}
|
|
1218
|
-
</div>
|
|
1219
|
-
|
|
1220
|
-
{#if rewriteMenuOpen}
|
|
1221
1686
|
<div
|
|
1222
|
-
|
|
1223
|
-
|
|
1687
|
+
bind:this={selectionToolbarEl}
|
|
1688
|
+
class='hai-ai-doc-selection-toolbar'
|
|
1689
|
+
role='toolbar'
|
|
1224
1690
|
tabindex='-1'
|
|
1225
1691
|
onmousedown={event => event.preventDefault()}
|
|
1226
1692
|
>
|
|
1227
|
-
{#
|
|
1693
|
+
{#if onrewrite}
|
|
1228
1694
|
<button
|
|
1229
1695
|
type='button'
|
|
1696
|
+
class={cn(
|
|
1697
|
+
'hai-ai-doc-selection-chip',
|
|
1698
|
+
(!directRewriteAction && activeSelectionMenu === 'rewrite')
|
|
1699
|
+
? 'hai-ai-doc-selection-chip--active'
|
|
1700
|
+
: '',
|
|
1701
|
+
)}
|
|
1230
1702
|
disabled={rewritePending}
|
|
1231
|
-
onclick={() =>
|
|
1703
|
+
onclick={(event) => {
|
|
1704
|
+
if (directRewriteAction) {
|
|
1705
|
+
void applyRewrite(directRewriteAction.id)
|
|
1706
|
+
return
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
toggleSelectionMenu('rewrite', event)
|
|
1710
|
+
}}
|
|
1232
1711
|
>
|
|
1233
|
-
|
|
1712
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1713
|
+
<path
|
|
1714
|
+
d='M12 3.25a.75.75 0 0 1 .72.55l1.06 3.62 3.63 1.06a.75.75 0 0 1 0 1.44l-3.63 1.06-1.06 3.63a.75.75 0 0 1-1.44 0l-1.06-3.63-3.63-1.06a.75.75 0 0 1 0-1.44l3.63-1.06 1.06-3.62a.75.75 0 0 1 .72-.55Zm6.5 11.5a.75.75 0 0 1 .72.55l.42 1.43 1.43.42a.75.75 0 0 1 0 1.44l-1.43.42-.42 1.43a.75.75 0 0 1-1.44 0l-.42-1.43-1.43-.42a.75.75 0 0 1 0-1.44l1.43-.42.42-1.43a.75.75 0 0 1 .72-.55Z'
|
|
1715
|
+
></path>
|
|
1716
|
+
</svg>
|
|
1717
|
+
<span>{uiM('markdown_rewrite')}</span>
|
|
1234
1718
|
</button>
|
|
1235
|
-
{/
|
|
1236
|
-
</div>
|
|
1237
|
-
{/if}
|
|
1238
|
-
</div>
|
|
1239
|
-
{/if}
|
|
1719
|
+
{/if}
|
|
1240
1720
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1721
|
+
{#if richBlockFormattingEnabled}
|
|
1722
|
+
{#if onrewrite}
|
|
1723
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1724
|
+
{/if}
|
|
1725
|
+
<button
|
|
1726
|
+
type='button'
|
|
1727
|
+
class={cn(
|
|
1728
|
+
'hai-ai-doc-selection-trigger',
|
|
1729
|
+
activeSelectionMenu === 'block'
|
|
1730
|
+
? 'hai-ai-doc-selection-trigger--active'
|
|
1731
|
+
: '',
|
|
1732
|
+
)}
|
|
1733
|
+
title={uiM('markdown_format_heading')}
|
|
1734
|
+
onclick={event => toggleSelectionMenu('block', event)}
|
|
1735
|
+
>
|
|
1736
|
+
<span class='hai-ai-doc-selection-trigger-label'>
|
|
1737
|
+
{activeBlockFormatOption.shortLabel}
|
|
1738
|
+
</span>
|
|
1739
|
+
<svg
|
|
1740
|
+
viewBox='0 0 24 24'
|
|
1741
|
+
aria-hidden='true'
|
|
1742
|
+
class='hai-ai-doc-selection-trigger-chevron'
|
|
1743
|
+
>
|
|
1744
|
+
<path
|
|
1745
|
+
d='M6.97 8.47a.75.75 0 0 1 1.06 0L12 12.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06Z'
|
|
1746
|
+
></path>
|
|
1747
|
+
</svg>
|
|
1748
|
+
</button>
|
|
1749
|
+
{:else if legacyBlockFormattingEnabled}
|
|
1750
|
+
{#if onrewrite}
|
|
1751
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1752
|
+
{/if}
|
|
1753
|
+
<button
|
|
1754
|
+
type='button'
|
|
1755
|
+
class='hai-ai-doc-selection-btn'
|
|
1756
|
+
title={uiM('markdown_format_heading')}
|
|
1757
|
+
onclick={() => applyBlockFormat('heading')}
|
|
1758
|
+
>
|
|
1759
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1760
|
+
<path
|
|
1761
|
+
d='M5 5.25a.75.75 0 0 1 .75.75V11h6.5V6a.75.75 0 0 1 1.5 0v12a.75.75 0 0 1-1.5 0v-5.5h-6.5V18a.75.75 0 0 1-1.5 0V6A.75.75 0 0 1 5 5.25Zm11.25 2.5a.75.75 0 0 1 0 1.5h3a.75.75 0 0 1 0 1.5H18.5v8.5a.75.75 0 0 1-1.5 0v-8.5h-.75a.75.75 0 0 1 0-1.5h3Z'
|
|
1762
|
+
></path>
|
|
1763
|
+
</svg>
|
|
1764
|
+
</button>
|
|
1765
|
+
<button
|
|
1766
|
+
type='button'
|
|
1767
|
+
class='hai-ai-doc-selection-btn'
|
|
1768
|
+
title={uiM('markdown_format_bullet')}
|
|
1769
|
+
onclick={() => applyBlockFormat('bullet')}
|
|
1770
|
+
>
|
|
1771
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1772
|
+
<path
|
|
1773
|
+
d='M6.25 7.25a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Zm-14 5.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm14 0a.75.75 0 0 1-.75.75H8.75a.75.75 0 0 1 0-1.5H19.5a.75.75 0 0 1 .75.75Z'
|
|
1774
|
+
></path>
|
|
1775
|
+
</svg>
|
|
1776
|
+
</button>
|
|
1777
|
+
{/if}
|
|
1778
|
+
|
|
1779
|
+
{#if onapplyalignment}
|
|
1780
|
+
{#if anyBlockFormattingEnabled || onrewrite}
|
|
1781
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1782
|
+
{/if}
|
|
1783
|
+
<button
|
|
1784
|
+
type='button'
|
|
1785
|
+
class={cn(
|
|
1786
|
+
'hai-ai-doc-selection-trigger',
|
|
1787
|
+
activeSelectionMenu === 'align'
|
|
1788
|
+
? 'hai-ai-doc-selection-trigger--active'
|
|
1789
|
+
: '',
|
|
1790
|
+
)}
|
|
1791
|
+
title={uiM('markdown_align')}
|
|
1792
|
+
onclick={event => toggleSelectionMenu('align', event)}
|
|
1793
|
+
>
|
|
1794
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1795
|
+
{#if selectionFormatState.alignment === 'center'}
|
|
1796
|
+
<path d='M5 6.25a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 6.25Zm2.75 4.75a.75.75 0 0 1 .75-.75h7a.75.75 0 0 1 0 1.5h-7a.75.75 0 0 1-.75-.75Zm-2 4.75a.75.75 0 0 1 .75-.75h11a.75.75 0 0 1 0 1.5h-11a.75.75 0 0 1-.75-.75Z'></path>
|
|
1797
|
+
{:else if selectionFormatState.alignment === 'right'}
|
|
1798
|
+
<path d='M5.75 5.5a.75.75 0 0 0 0 1.5h12.5a.75.75 0 0 0 0-1.5H5.75Zm4 4.75a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Zm-4 4.75a.75.75 0 0 0 0 1.5h12.5a.75.75 0 0 0 0-1.5H5.75Z'></path>
|
|
1799
|
+
{:else if selectionFormatState.alignment === 'justify'}
|
|
1800
|
+
<path d='M5 6.25a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 6.25Zm0 4.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 11Zm0 4.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 15.75Z'></path>
|
|
1801
|
+
{:else}
|
|
1802
|
+
<path d='M5 6.25a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 6.25Zm0 4.75a.75.75 0 0 1 .75-.75h8.5a.75.75 0 0 1 0 1.5h-8.5A.75.75 0 0 1 5 11Zm0 4.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 15.75Z'></path>
|
|
1803
|
+
{/if}
|
|
1804
|
+
</svg>
|
|
1805
|
+
<svg
|
|
1806
|
+
viewBox='0 0 24 24'
|
|
1807
|
+
aria-hidden='true'
|
|
1808
|
+
class='hai-ai-doc-selection-trigger-chevron'
|
|
1809
|
+
>
|
|
1810
|
+
<path
|
|
1811
|
+
d='M6.97 8.47a.75.75 0 0 1 1.06 0L12 12.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06Z'
|
|
1812
|
+
></path>
|
|
1813
|
+
</svg>
|
|
1814
|
+
</button>
|
|
1815
|
+
{/if}
|
|
1816
|
+
|
|
1817
|
+
{#if onapplyinlineformat || onapplylink || onapplycolor}
|
|
1818
|
+
{#if anyBlockFormattingEnabled || onapplyalignment || onrewrite}
|
|
1819
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1820
|
+
{/if}
|
|
1821
|
+
{/if}
|
|
1822
|
+
|
|
1823
|
+
{#if onapplyinlineformat}
|
|
1824
|
+
<button
|
|
1825
|
+
type='button'
|
|
1826
|
+
class={cn(
|
|
1827
|
+
'hai-ai-doc-selection-btn',
|
|
1828
|
+
selectionFormatState.bold
|
|
1829
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1830
|
+
: '',
|
|
1831
|
+
)}
|
|
1832
|
+
title={uiM('markdown_format_bold')}
|
|
1833
|
+
onclick={() => applyInlineFormat('bold')}
|
|
1834
|
+
>
|
|
1835
|
+
<strong>B</strong>
|
|
1836
|
+
</button>
|
|
1837
|
+
<button
|
|
1838
|
+
type='button'
|
|
1839
|
+
class={cn(
|
|
1840
|
+
'hai-ai-doc-selection-btn',
|
|
1841
|
+
selectionFormatState.strike
|
|
1842
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1843
|
+
: '',
|
|
1844
|
+
)}
|
|
1845
|
+
title={uiM('markdown_format_strike')}
|
|
1846
|
+
onclick={() => applyInlineFormat('strike')}
|
|
1847
|
+
>
|
|
1848
|
+
S
|
|
1849
|
+
</button>
|
|
1850
|
+
<button
|
|
1851
|
+
type='button'
|
|
1852
|
+
class={cn(
|
|
1853
|
+
'hai-ai-doc-selection-btn',
|
|
1854
|
+
selectionFormatState.italic
|
|
1855
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1856
|
+
: '',
|
|
1857
|
+
)}
|
|
1858
|
+
title={uiM('markdown_format_italic')}
|
|
1859
|
+
onclick={() => applyInlineFormat('italic')}
|
|
1860
|
+
>
|
|
1861
|
+
<em>I</em>
|
|
1862
|
+
</button>
|
|
1863
|
+
<button
|
|
1864
|
+
type='button'
|
|
1865
|
+
class={cn(
|
|
1866
|
+
'hai-ai-doc-selection-btn',
|
|
1867
|
+
selectionFormatState.underline
|
|
1868
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1869
|
+
: '',
|
|
1870
|
+
)}
|
|
1871
|
+
title={uiM('markdown_format_underline')}
|
|
1872
|
+
onclick={() => applyInlineFormat('underline')}
|
|
1873
|
+
>
|
|
1874
|
+
U
|
|
1875
|
+
</button>
|
|
1876
|
+
{/if}
|
|
1877
|
+
|
|
1878
|
+
{#if onapplylink || onapplyinlineformat}
|
|
1879
|
+
<button
|
|
1880
|
+
type='button'
|
|
1881
|
+
class={cn(
|
|
1882
|
+
'hai-ai-doc-selection-btn',
|
|
1883
|
+
selectionFormatState.linkHref
|
|
1884
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1885
|
+
: '',
|
|
1886
|
+
activeSelectionMenu === 'link'
|
|
1887
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1888
|
+
: '',
|
|
1889
|
+
)}
|
|
1890
|
+
title={uiM('markdown_format_link')}
|
|
1891
|
+
onclick={event =>
|
|
1892
|
+
onapplylink
|
|
1893
|
+
? toggleSelectionMenu('link', event)
|
|
1894
|
+
: applyInlineFormat('link')}
|
|
1895
|
+
>
|
|
1896
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1897
|
+
<path
|
|
1898
|
+
d='M7.78 15.72a3.75 3.75 0 0 1 0-5.3l2.47-2.47a3.75 3.75 0 0 1 5.3 5.3l-.97.98a.75.75 0 0 1-1.06-1.06l.98-.97a2.25 2.25 0 0 0-3.19-3.19l-2.47 2.47a2.25 2.25 0 1 0 3.18 3.18l.49-.49a.75.75 0 0 1 1.06 1.06l-.49.49a3.75 3.75 0 0 1-5.3 0Zm8.44-7.44a.75.75 0 0 1 0 1.06l-8 8a.75.75 0 0 1-1.06-1.06l8-8a.75.75 0 0 1 1.06 0Z'
|
|
1899
|
+
></path>
|
|
1900
|
+
</svg>
|
|
1901
|
+
</button>
|
|
1902
|
+
{/if}
|
|
1903
|
+
|
|
1904
|
+
{#if onapplyinlineformat}
|
|
1905
|
+
<button
|
|
1906
|
+
type='button'
|
|
1907
|
+
class={cn(
|
|
1908
|
+
'hai-ai-doc-selection-btn',
|
|
1909
|
+
selectionFormatState.code
|
|
1910
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1911
|
+
: '',
|
|
1912
|
+
)}
|
|
1913
|
+
title={uiM('markdown_format_code')}
|
|
1914
|
+
onclick={() => applyInlineFormat('code')}
|
|
1915
|
+
>
|
|
1916
|
+
</>
|
|
1917
|
+
</button>
|
|
1918
|
+
<button
|
|
1919
|
+
type='button'
|
|
1920
|
+
class={cn(
|
|
1921
|
+
'hai-ai-doc-selection-btn',
|
|
1922
|
+
selectionFormatState.highlight
|
|
1923
|
+
? 'hai-ai-doc-selection-btn--active'
|
|
1924
|
+
: '',
|
|
1925
|
+
)}
|
|
1926
|
+
title={uiM('markdown_format_highlight')}
|
|
1927
|
+
onclick={() => applyInlineFormat('highlight')}
|
|
1928
|
+
>
|
|
1929
|
+
<span class='hai-ai-doc-selection-highlight-icon'>A</span>
|
|
1930
|
+
</button>
|
|
1931
|
+
{/if}
|
|
1932
|
+
|
|
1933
|
+
{#if onapplycolor}
|
|
1934
|
+
<button
|
|
1935
|
+
type='button'
|
|
1936
|
+
class={cn(
|
|
1937
|
+
'hai-ai-doc-selection-trigger',
|
|
1938
|
+
activeSelectionMenu === 'color'
|
|
1939
|
+
? 'hai-ai-doc-selection-trigger--active'
|
|
1940
|
+
: '',
|
|
1941
|
+
)}
|
|
1942
|
+
style={`--hai-ai-doc-current-color:${selectionFormatState.textColor ?? '#0f172a'};`}
|
|
1943
|
+
title={uiM('markdown_text_color')}
|
|
1944
|
+
onclick={event => toggleSelectionMenu('color', event)}
|
|
1945
|
+
>
|
|
1946
|
+
<span class='hai-ai-doc-selection-highlight-icon'>A</span>
|
|
1947
|
+
<svg
|
|
1948
|
+
viewBox='0 0 24 24'
|
|
1949
|
+
aria-hidden='true'
|
|
1950
|
+
class='hai-ai-doc-selection-trigger-chevron'
|
|
1951
|
+
>
|
|
1952
|
+
<path
|
|
1953
|
+
d='M6.97 8.47a.75.75 0 0 1 1.06 0L12 12.44l3.97-3.97a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06Z'
|
|
1954
|
+
></path>
|
|
1955
|
+
</svg>
|
|
1956
|
+
</button>
|
|
1957
|
+
{/if}
|
|
1958
|
+
|
|
1959
|
+
{#if oncopyselection || onannotation}
|
|
1960
|
+
{#if onapplyinlineformat || onapplylink || onapplycolor}
|
|
1961
|
+
<span class='hai-ai-doc-selection-divider'></span>
|
|
1962
|
+
{/if}
|
|
1963
|
+
{/if}
|
|
1964
|
+
|
|
1965
|
+
{#if oncopyselection}
|
|
1966
|
+
<button
|
|
1967
|
+
type='button'
|
|
1968
|
+
class='hai-ai-doc-selection-btn hai-ai-doc-selection-btn-wide'
|
|
1969
|
+
title={uiM('markdown_copy_selection')}
|
|
1970
|
+
onclick={copySelection}
|
|
1971
|
+
>
|
|
1972
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1973
|
+
<path
|
|
1974
|
+
d='M8.75 4.25A2.75 2.75 0 0 0 6 7v8.25A2.75 2.75 0 0 0 8.75 18h7.5A2.75 2.75 0 0 0 19 15.25V7a2.75 2.75 0 0 0-2.75-2.75h-7.5Zm-4 3A2.75 2.75 0 0 1 7.5 4.5a.75.75 0 0 0 0-1.5A4.25 4.25 0 0 0 3.25 7.25v8.5A4.25 4.25 0 0 0 7.5 20a.75.75 0 0 0 0-1.5 2.75 2.75 0 0 1-2.75-2.75v-8.5Z'
|
|
1975
|
+
></path>
|
|
1976
|
+
</svg>
|
|
1977
|
+
<span>{uiM('markdown_copy_selection')}</span>
|
|
1978
|
+
</button>
|
|
1979
|
+
{/if}
|
|
1980
|
+
|
|
1981
|
+
{#if onannotation}
|
|
1982
|
+
<button
|
|
1983
|
+
type='button'
|
|
1984
|
+
class='hai-ai-doc-selection-btn hai-ai-doc-selection-btn-wide'
|
|
1985
|
+
title={uiM('markdown_annotation')}
|
|
1986
|
+
onclick={annotateSelection}
|
|
1987
|
+
>
|
|
1988
|
+
<svg viewBox='0 0 24 24' aria-hidden='true'>
|
|
1989
|
+
<path
|
|
1990
|
+
d='M6.75 4.25A2.75 2.75 0 0 0 4 7v7.75A2.75 2.75 0 0 0 6.75 17.5h1.72l2.3 2.01a1.75 1.75 0 0 0 2.3 0l2.3-2.01h1.88A2.75 2.75 0 0 0 20 14.75V7a2.75 2.75 0 0 0-2.75-2.75H6.75Zm1.5 4a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5H9a.75.75 0 0 1-.75-.75Zm0 3.5A.75.75 0 0 1 9 11h4a.75.75 0 0 1 0 1.5H9a.75.75 0 0 1-.75-.75Z'
|
|
1991
|
+
></path>
|
|
1992
|
+
</svg>
|
|
1993
|
+
</button>
|
|
1994
|
+
{/if}
|
|
1995
|
+
</div>
|
|
1996
|
+
|
|
1997
|
+
{#if activeSelectionMenu === 'rewrite' && resolvedRewriteActions.length > 1}
|
|
1998
|
+
<div
|
|
1999
|
+
class='hai-ai-doc-rewrite-menu'
|
|
2000
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
2001
|
+
role='menu'
|
|
2002
|
+
tabindex='-1'
|
|
2003
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
2004
|
+
onmousedown={event => event.preventDefault()}
|
|
2005
|
+
>
|
|
2006
|
+
{#each resolvedRewriteActions as action}
|
|
2007
|
+
<button
|
|
2008
|
+
type='button'
|
|
2009
|
+
class='hai-ai-doc-rewrite-menu-btn'
|
|
2010
|
+
disabled={rewritePending}
|
|
2011
|
+
onclick={() => applyRewrite(action.id)}
|
|
2012
|
+
>
|
|
2013
|
+
{action.label}
|
|
2014
|
+
</button>
|
|
2015
|
+
{/each}
|
|
2016
|
+
</div>
|
|
2017
|
+
{:else if activeSelectionMenu === 'block' && richBlockFormattingEnabled}
|
|
2018
|
+
<div
|
|
2019
|
+
class='hai-ai-doc-selection-panel'
|
|
2020
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
2021
|
+
role='menu'
|
|
2022
|
+
tabindex='-1'
|
|
2023
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
2024
|
+
onmousedown={event => event.preventDefault()}
|
|
2025
|
+
>
|
|
2026
|
+
{#each BLOCK_FORMAT_OPTIONS as option}
|
|
2027
|
+
<button
|
|
2028
|
+
type='button'
|
|
2029
|
+
class={cn(
|
|
2030
|
+
'hai-ai-doc-selection-menu-btn',
|
|
2031
|
+
selectionFormatState.blockFormat === option.value
|
|
2032
|
+
? 'hai-ai-doc-selection-menu-btn--active'
|
|
2033
|
+
: '',
|
|
2034
|
+
)}
|
|
2035
|
+
onclick={() => applyBlockStyle(option.value)}
|
|
2036
|
+
>
|
|
2037
|
+
<span class='hai-ai-doc-selection-menu-label'>
|
|
2038
|
+
<span class='hai-ai-doc-selection-menu-short'>
|
|
2039
|
+
{option.shortLabel}
|
|
2040
|
+
</span>
|
|
2041
|
+
<span>{uiM(option.labelKey)}</span>
|
|
2042
|
+
</span>
|
|
2043
|
+
{#if selectionFormatState.blockFormat === option.value}
|
|
2044
|
+
<span class='hai-ai-doc-selection-menu-check'>✓</span>
|
|
2045
|
+
{/if}
|
|
2046
|
+
</button>
|
|
2047
|
+
{/each}
|
|
2048
|
+
</div>
|
|
2049
|
+
{:else if activeSelectionMenu === 'align' && onapplyalignment}
|
|
2050
|
+
<div
|
|
2051
|
+
class='hai-ai-doc-selection-panel'
|
|
2052
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
2053
|
+
role='menu'
|
|
2054
|
+
tabindex='-1'
|
|
2055
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
2056
|
+
onmousedown={event => event.preventDefault()}
|
|
2057
|
+
>
|
|
2058
|
+
{#each ALIGN_OPTIONS as option}
|
|
2059
|
+
<button
|
|
2060
|
+
type='button'
|
|
2061
|
+
class={cn(
|
|
2062
|
+
'hai-ai-doc-selection-menu-btn',
|
|
2063
|
+
selectionFormatState.alignment === option.value
|
|
2064
|
+
? 'hai-ai-doc-selection-menu-btn--active'
|
|
2065
|
+
: '',
|
|
2066
|
+
)}
|
|
2067
|
+
onclick={() => applyAlignment(option.value)}
|
|
2068
|
+
>
|
|
2069
|
+
<span>{uiM(option.labelKey)}</span>
|
|
2070
|
+
{#if selectionFormatState.alignment === option.value}
|
|
2071
|
+
<span class='hai-ai-doc-selection-menu-check'>✓</span>
|
|
2072
|
+
{/if}
|
|
2073
|
+
</button>
|
|
2074
|
+
{/each}
|
|
2075
|
+
</div>
|
|
2076
|
+
{:else if activeSelectionMenu === 'link' && onapplylink}
|
|
2077
|
+
<div
|
|
2078
|
+
class='hai-ai-doc-selection-panel hai-ai-doc-selection-panel--link'
|
|
2079
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
2080
|
+
role='dialog'
|
|
2081
|
+
aria-label={uiM('markdown_link_dialog_label')}
|
|
2082
|
+
tabindex='-1'
|
|
2083
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
2084
|
+
onmousedown={event => event.preventDefault()}
|
|
2085
|
+
>
|
|
2086
|
+
<input
|
|
2087
|
+
class='hai-ai-doc-selection-input'
|
|
2088
|
+
bind:value={linkDraft}
|
|
2089
|
+
aria-label={uiM('markdown_link_input_label')}
|
|
2090
|
+
placeholder={uiM('markdown_link_placeholder')}
|
|
2091
|
+
onkeydown={(event) => {
|
|
2092
|
+
if (event.key === 'Enter') {
|
|
2093
|
+
event.preventDefault()
|
|
2094
|
+
applyLink()
|
|
2095
|
+
}
|
|
2096
|
+
}}
|
|
2097
|
+
/>
|
|
2098
|
+
<div class='hai-ai-doc-selection-panel-actions'>
|
|
2099
|
+
<button
|
|
2100
|
+
type='button'
|
|
2101
|
+
class='hai-ai-doc-selection-panel-btn hai-ai-doc-selection-panel-btn--primary'
|
|
2102
|
+
onclick={applyLink}
|
|
2103
|
+
>
|
|
2104
|
+
{uiM('markdown_link_apply')}
|
|
2105
|
+
</button>
|
|
2106
|
+
<button
|
|
2107
|
+
type='button'
|
|
2108
|
+
class='hai-ai-doc-selection-panel-btn'
|
|
2109
|
+
disabled={!selectionFormatState.linkHref}
|
|
2110
|
+
onclick={removeLink}
|
|
2111
|
+
>
|
|
2112
|
+
{uiM('markdown_link_remove')}
|
|
2113
|
+
</button>
|
|
2114
|
+
</div>
|
|
2115
|
+
</div>
|
|
2116
|
+
{:else if activeSelectionMenu === 'color' && onapplycolor}
|
|
2117
|
+
<div
|
|
2118
|
+
class='hai-ai-doc-selection-panel hai-ai-doc-selection-panel--color'
|
|
2119
|
+
data-menu-alignment={selectionMenuAlignment}
|
|
2120
|
+
role='dialog'
|
|
2121
|
+
aria-label={uiM('markdown_color_dialog_label')}
|
|
2122
|
+
tabindex='-1'
|
|
2123
|
+
style={`--hai-ai-doc-selection-menu-left:${selectionMenuLeft}px;`}
|
|
2124
|
+
onmousedown={event => event.preventDefault()}
|
|
2125
|
+
>
|
|
2126
|
+
<div class='hai-ai-doc-color-group'>
|
|
2127
|
+
<div class='hai-ai-doc-color-group-title'>
|
|
2128
|
+
{uiM('markdown_text_color')}
|
|
2129
|
+
</div>
|
|
2130
|
+
<div class='hai-ai-doc-color-grid'>
|
|
2131
|
+
{#each TEXT_COLOR_PRESETS as color}
|
|
2132
|
+
<button
|
|
2133
|
+
type='button'
|
|
2134
|
+
class={cn(
|
|
2135
|
+
'hai-ai-doc-color-swatch',
|
|
2136
|
+
selectionFormatState.textColor === color
|
|
2137
|
+
? 'hai-ai-doc-color-swatch--active'
|
|
2138
|
+
: '',
|
|
2139
|
+
)}
|
|
2140
|
+
title={color}
|
|
2141
|
+
onclick={() =>
|
|
2142
|
+
applyColor({ target: 'text', value: color })}
|
|
2143
|
+
>
|
|
2144
|
+
<span style={`background:${color};`}></span>
|
|
2145
|
+
</button>
|
|
2146
|
+
{/each}
|
|
2147
|
+
</div>
|
|
2148
|
+
</div>
|
|
2149
|
+
<div class='hai-ai-doc-color-group'>
|
|
2150
|
+
<div class='hai-ai-doc-color-group-title'>
|
|
2151
|
+
{uiM('markdown_background_color')}
|
|
2152
|
+
</div>
|
|
2153
|
+
<div class='hai-ai-doc-color-grid'>
|
|
2154
|
+
{#each BACKGROUND_COLOR_PRESETS as color}
|
|
2155
|
+
<button
|
|
2156
|
+
type='button'
|
|
2157
|
+
class={cn(
|
|
2158
|
+
'hai-ai-doc-color-swatch',
|
|
2159
|
+
selectionFormatState.backgroundColor === color
|
|
2160
|
+
? 'hai-ai-doc-color-swatch--active'
|
|
2161
|
+
: '',
|
|
2162
|
+
)}
|
|
2163
|
+
title={color}
|
|
2164
|
+
onclick={() =>
|
|
2165
|
+
applyColor({
|
|
2166
|
+
target: 'background',
|
|
2167
|
+
value: color,
|
|
2168
|
+
})}
|
|
2169
|
+
>
|
|
2170
|
+
<span style={`background:${color};`}></span>
|
|
2171
|
+
</button>
|
|
2172
|
+
{/each}
|
|
2173
|
+
</div>
|
|
2174
|
+
</div>
|
|
2175
|
+
<button
|
|
2176
|
+
type='button'
|
|
2177
|
+
class='hai-ai-doc-selection-panel-btn'
|
|
2178
|
+
onclick={() => {
|
|
2179
|
+
applyColor({ target: 'text', value: null })
|
|
2180
|
+
applyColor({ target: 'background', value: null })
|
|
2181
|
+
}}
|
|
2182
|
+
>
|
|
2183
|
+
{uiM('markdown_reset_default')}
|
|
2184
|
+
</button>
|
|
2185
|
+
</div>
|
|
2186
|
+
{/if}
|
|
2187
|
+
</div>
|
|
2188
|
+
</div>
|
|
2189
|
+
{/if}
|
|
2190
|
+
|
|
2191
|
+
<article
|
|
2192
|
+
bind:this={previewHost}
|
|
2193
|
+
class={readerDocumentClass}
|
|
2194
|
+
contenteditable={editable}
|
|
2195
|
+
role='document'
|
|
2196
|
+
onmouseup={handlePreviewMouseUp}
|
|
2197
|
+
oninput={handlePreviewInput}
|
|
2198
|
+
onblur={handlePreviewBlur}
|
|
1249
2199
|
>
|
|
1250
2200
|
<!-- eslint-disable-next-line svelte/no-at-html-tags -- Markdown HTML 渲染 -->
|
|
1251
2201
|
{@html html}
|
|
@@ -1265,8 +2215,12 @@ ${safeCode}
|
|
|
1265
2215
|
);
|
|
1266
2216
|
--hai-ai-doc-selection-fg: oklch(var(--bc, 0.22 0 0));
|
|
1267
2217
|
display: flex;
|
|
2218
|
+
width: 100%;
|
|
2219
|
+
min-width: 0;
|
|
1268
2220
|
min-height: 0;
|
|
1269
2221
|
height: 100%;
|
|
2222
|
+
container-type: inline-size;
|
|
2223
|
+
container-name: ai-doc-editor;
|
|
1270
2224
|
flex-direction: column;
|
|
1271
2225
|
border: 1px solid oklch(var(--bc) / 0.08);
|
|
1272
2226
|
border-radius: 1.5rem;
|
|
@@ -1280,8 +2234,10 @@ ${safeCode}
|
|
|
1280
2234
|
}
|
|
1281
2235
|
|
|
1282
2236
|
.hai-ai-doc-shell {
|
|
1283
|
-
display:
|
|
1284
|
-
|
|
2237
|
+
display: flex;
|
|
2238
|
+
flex-direction: column;
|
|
2239
|
+
width: 100%;
|
|
2240
|
+
min-width: 0;
|
|
1285
2241
|
min-height: 0;
|
|
1286
2242
|
height: 100%;
|
|
1287
2243
|
}
|
|
@@ -1394,9 +2350,9 @@ ${safeCode}
|
|
|
1394
2350
|
}
|
|
1395
2351
|
|
|
1396
2352
|
.hai-ai-doc-toolbar-icon:not(:disabled):hover,
|
|
1397
|
-
:global(.hai-ai-doc-toolbar-icon:hover),
|
|
2353
|
+
:global(.hai-ai-doc-toolbar-icon:not(:disabled):hover),
|
|
1398
2354
|
.hai-ai-doc-toolbar-pill:not(:disabled):hover,
|
|
1399
|
-
:global(.hai-ai-doc-toolbar-pill:hover),
|
|
2355
|
+
:global(.hai-ai-doc-toolbar-pill:not(:disabled):hover),
|
|
1400
2356
|
.hai-ai-doc-toolbar-action:hover,
|
|
1401
2357
|
.hai-ai-doc-toolbar-close:not(:disabled):hover,
|
|
1402
2358
|
.hai-ai-doc-version-toggle:hover,
|
|
@@ -1407,9 +2363,9 @@ ${safeCode}
|
|
|
1407
2363
|
}
|
|
1408
2364
|
|
|
1409
2365
|
.hai-ai-doc-toolbar-icon:not(:disabled):hover,
|
|
1410
|
-
:global(.hai-ai-doc-toolbar-icon:hover),
|
|
2366
|
+
:global(.hai-ai-doc-toolbar-icon:not(:disabled):hover),
|
|
1411
2367
|
.hai-ai-doc-toolbar-pill:not(:disabled):hover,
|
|
1412
|
-
:global(.hai-ai-doc-toolbar-pill:hover),
|
|
2368
|
+
:global(.hai-ai-doc-toolbar-pill:not(:disabled):hover),
|
|
1413
2369
|
.hai-ai-doc-toolbar-close:not(:disabled):hover {
|
|
1414
2370
|
transform: translateY(-1px);
|
|
1415
2371
|
box-shadow: 0 12px 28px -22px oklch(var(--bc) / 0.36);
|
|
@@ -1420,11 +2376,25 @@ ${safeCode}
|
|
|
1420
2376
|
.hai-ai-doc-toolbar-pill:disabled,
|
|
1421
2377
|
:global(.hai-ai-doc-toolbar-pill:disabled),
|
|
1422
2378
|
.hai-ai-doc-toolbar-close:disabled {
|
|
1423
|
-
opacity: 0.
|
|
2379
|
+
opacity: 0.72;
|
|
2380
|
+
color: oklch(var(--bc) / 0.36);
|
|
2381
|
+
border-color: oklch(var(--bc) / 0.12);
|
|
2382
|
+
background: oklch(var(--b2) / 0.58);
|
|
1424
2383
|
cursor: not-allowed;
|
|
1425
2384
|
box-shadow: none;
|
|
1426
2385
|
}
|
|
1427
2386
|
|
|
2387
|
+
.hai-ai-doc-toolbar-icon:disabled:hover,
|
|
2388
|
+
:global(.hai-ai-doc-toolbar-icon:disabled:hover),
|
|
2389
|
+
.hai-ai-doc-toolbar-pill:disabled:hover,
|
|
2390
|
+
:global(.hai-ai-doc-toolbar-pill:disabled:hover),
|
|
2391
|
+
.hai-ai-doc-toolbar-close:disabled:hover {
|
|
2392
|
+
cursor: not-allowed;
|
|
2393
|
+
transform: none;
|
|
2394
|
+
box-shadow: none;
|
|
2395
|
+
filter: grayscale(0.18);
|
|
2396
|
+
}
|
|
2397
|
+
|
|
1428
2398
|
.hai-ai-doc-toolbar-action,
|
|
1429
2399
|
.hai-ai-doc-version-toggle {
|
|
1430
2400
|
border: 1px solid oklch(var(--bc) / 0.08);
|
|
@@ -1461,18 +2431,23 @@ ${safeCode}
|
|
|
1461
2431
|
}
|
|
1462
2432
|
|
|
1463
2433
|
.hai-ai-doc-layout {
|
|
2434
|
+
width: 100%;
|
|
1464
2435
|
min-height: 0;
|
|
1465
|
-
|
|
1466
|
-
|
|
2436
|
+
min-width: 0;
|
|
2437
|
+
flex: 1 1 auto;
|
|
2438
|
+
display: flex;
|
|
2439
|
+
align-items: stretch;
|
|
1467
2440
|
position: relative;
|
|
1468
2441
|
overflow: hidden;
|
|
1469
2442
|
}
|
|
1470
2443
|
|
|
1471
2444
|
.hai-ai-doc-layout.hai-ai-doc-layout-collapsed {
|
|
1472
|
-
|
|
2445
|
+
display: flex;
|
|
1473
2446
|
}
|
|
1474
2447
|
|
|
1475
2448
|
.hai-ai-doc-outline {
|
|
2449
|
+
width: 220px;
|
|
2450
|
+
flex: 0 0 220px;
|
|
1476
2451
|
min-height: 0;
|
|
1477
2452
|
display: grid;
|
|
1478
2453
|
grid-template-rows: auto 1fr;
|
|
@@ -1571,62 +2546,92 @@ ${safeCode}
|
|
|
1571
2546
|
}
|
|
1572
2547
|
|
|
1573
2548
|
.hai-ai-doc-reader {
|
|
2549
|
+
width: 100%;
|
|
2550
|
+
flex: 1 1 auto;
|
|
1574
2551
|
min-width: 0;
|
|
1575
2552
|
min-height: 0;
|
|
1576
2553
|
position: relative;
|
|
1577
|
-
z-index:
|
|
2554
|
+
z-index: 2;
|
|
2555
|
+
isolation: isolate;
|
|
2556
|
+
display: flex;
|
|
2557
|
+
flex-direction: column;
|
|
1578
2558
|
}
|
|
1579
2559
|
|
|
1580
2560
|
.hai-ai-doc-scroll {
|
|
1581
2561
|
position: relative;
|
|
2562
|
+
width: 100%;
|
|
2563
|
+
min-width: 0;
|
|
1582
2564
|
height: 100%;
|
|
1583
2565
|
overflow: auto;
|
|
1584
2566
|
padding: 0.5rem 0 1.75rem;
|
|
2567
|
+
display: flex;
|
|
2568
|
+
flex-direction: column;
|
|
2569
|
+
flex: 1 1 auto;
|
|
2570
|
+
min-height: 0;
|
|
1585
2571
|
}
|
|
1586
2572
|
|
|
1587
2573
|
.hai-ai-doc-selection-layer {
|
|
1588
2574
|
position: absolute;
|
|
1589
|
-
z-index:
|
|
1590
|
-
display:
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
width: min(max-content, calc(100% - 2rem));
|
|
2575
|
+
z-index: 60;
|
|
2576
|
+
display: block;
|
|
2577
|
+
width: fit-content;
|
|
2578
|
+
max-width: calc(100% - 2rem);
|
|
1594
2579
|
transform: translateX(-50%);
|
|
2580
|
+
transition:
|
|
2581
|
+
top 0.14s cubic-bezier(0.2, 0.85, 0.24, 1),
|
|
2582
|
+
left 0.14s cubic-bezier(0.2, 0.85, 0.24, 1),
|
|
2583
|
+
transform 0.14s cubic-bezier(0.2, 0.85, 0.24, 1);
|
|
1595
2584
|
pointer-events: none;
|
|
1596
2585
|
}
|
|
1597
2586
|
|
|
1598
|
-
.hai-ai-doc-selection-layer[data-placement='top'] {
|
|
1599
|
-
flex-direction: column-reverse;
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
2587
|
.hai-ai-doc-selection-layer[data-alignment='left'] {
|
|
1603
|
-
transform:
|
|
2588
|
+
transform: translateX(0);
|
|
2589
|
+
justify-items: start;
|
|
1604
2590
|
}
|
|
1605
2591
|
|
|
1606
2592
|
.hai-ai-doc-selection-layer[data-alignment='right'] {
|
|
1607
2593
|
transform: translateX(-100%);
|
|
2594
|
+
justify-items: end;
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
.hai-ai-doc-selection-layer[data-alignment='center'] {
|
|
2598
|
+
justify-items: center;
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
.hai-ai-doc-selection-chrome {
|
|
2602
|
+
position: relative;
|
|
2603
|
+
display: inline-grid;
|
|
2604
|
+
width: fit-content;
|
|
2605
|
+
max-width: min(100%, calc(100vw - 2rem));
|
|
1608
2606
|
}
|
|
1609
2607
|
|
|
1610
2608
|
.hai-ai-doc-selection-toolbar {
|
|
1611
2609
|
display: flex;
|
|
1612
2610
|
align-items: center;
|
|
1613
2611
|
gap: 0.25rem;
|
|
1614
|
-
flex-wrap:
|
|
1615
|
-
|
|
2612
|
+
flex-wrap: nowrap;
|
|
2613
|
+
width: fit-content;
|
|
2614
|
+
max-width: calc(100% - 0.75rem);
|
|
2615
|
+
white-space: nowrap;
|
|
1616
2616
|
padding: 0.38rem;
|
|
1617
2617
|
border-radius: 1.2rem;
|
|
1618
|
-
background:
|
|
1619
|
-
|
|
2618
|
+
background-color: rgb(255 255 255 / 0.96);
|
|
2619
|
+
background: color-mix(in srgb, oklch(var(--b1, 1 0 0)) 94%, white 6%);
|
|
2620
|
+
border: 1px solid rgb(148 163 184 / 0.34);
|
|
2621
|
+
border-color: color-mix(in srgb, oklch(var(--bc, 0.22 0 0)) 16%, white 84%);
|
|
1620
2622
|
box-shadow:
|
|
1621
2623
|
0 30px 60px -34px rgb(15 23 42 / 0.28),
|
|
1622
2624
|
0 14px 26px -18px rgb(15 23 42 / 0.16),
|
|
1623
2625
|
0 0 0 1px rgb(255 255 255 / 0.94) inset;
|
|
1624
2626
|
pointer-events: auto;
|
|
1625
2627
|
isolation: isolate;
|
|
2628
|
+
position: relative;
|
|
2629
|
+
z-index: 2;
|
|
1626
2630
|
}
|
|
1627
2631
|
|
|
1628
2632
|
.hai-ai-doc-selection-chip,
|
|
1629
|
-
.hai-ai-doc-selection-btn
|
|
2633
|
+
.hai-ai-doc-selection-btn,
|
|
2634
|
+
.hai-ai-doc-selection-trigger {
|
|
1630
2635
|
min-height: 2.25rem;
|
|
1631
2636
|
border-radius: 0.9rem;
|
|
1632
2637
|
transition:
|
|
@@ -1640,6 +2645,7 @@ ${safeCode}
|
|
|
1640
2645
|
display: inline-flex;
|
|
1641
2646
|
align-items: center;
|
|
1642
2647
|
gap: 0.48rem;
|
|
2648
|
+
flex-shrink: 0;
|
|
1643
2649
|
padding: 0 0.88rem;
|
|
1644
2650
|
border: 1px solid oklch(var(--p) / 0.16);
|
|
1645
2651
|
background: oklch(var(--p) / 0.1);
|
|
@@ -1654,9 +2660,16 @@ ${safeCode}
|
|
|
1654
2660
|
fill: currentColor;
|
|
1655
2661
|
}
|
|
1656
2662
|
|
|
2663
|
+
.hai-ai-doc-selection-chip--active {
|
|
2664
|
+
border-color: oklch(var(--p) / 0.28);
|
|
2665
|
+
background: oklch(var(--p) / 0.16);
|
|
2666
|
+
color: oklch(var(--bc));
|
|
2667
|
+
}
|
|
2668
|
+
|
|
1657
2669
|
.hai-ai-doc-selection-chip:not(:disabled):hover,
|
|
1658
2670
|
.hai-ai-doc-selection-btn:hover,
|
|
1659
|
-
.hai-ai-doc-
|
|
2671
|
+
.hai-ai-doc-selection-trigger:hover,
|
|
2672
|
+
.hai-ai-doc-rewrite-menu-btn:hover {
|
|
1660
2673
|
transform: translateY(-1px);
|
|
1661
2674
|
}
|
|
1662
2675
|
|
|
@@ -1668,6 +2681,7 @@ ${safeCode}
|
|
|
1668
2681
|
.hai-ai-doc-selection-btn {
|
|
1669
2682
|
width: 2.25rem;
|
|
1670
2683
|
min-width: 2.25rem;
|
|
2684
|
+
flex-shrink: 0;
|
|
1671
2685
|
display: inline-flex;
|
|
1672
2686
|
align-items: center;
|
|
1673
2687
|
justify-content: center;
|
|
@@ -1679,21 +2693,61 @@ ${safeCode}
|
|
|
1679
2693
|
}
|
|
1680
2694
|
|
|
1681
2695
|
.hai-ai-doc-selection-btn-wide {
|
|
1682
|
-
|
|
2696
|
+
width: auto;
|
|
2697
|
+
min-width: 4.6rem;
|
|
2698
|
+
gap: 0.42rem;
|
|
2699
|
+
padding: 0 0.74rem;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
.hai-ai-doc-selection-trigger {
|
|
2703
|
+
min-width: 3.4rem;
|
|
2704
|
+
display: inline-flex;
|
|
2705
|
+
align-items: center;
|
|
2706
|
+
gap: 0.34rem;
|
|
2707
|
+
padding: 0 0.66rem;
|
|
2708
|
+
border: 1px solid transparent;
|
|
2709
|
+
background: transparent;
|
|
2710
|
+
color: oklch(var(--bc) / 0.78);
|
|
2711
|
+
cursor: pointer;
|
|
1683
2712
|
}
|
|
1684
2713
|
|
|
1685
|
-
.hai-ai-doc-selection-btn:hover
|
|
2714
|
+
.hai-ai-doc-selection-btn:hover,
|
|
2715
|
+
.hai-ai-doc-selection-trigger:hover {
|
|
1686
2716
|
border-color: oklch(var(--bc) / 0.1);
|
|
1687
2717
|
background: oklch(var(--bc) / 0.045);
|
|
1688
2718
|
color: oklch(var(--bc));
|
|
1689
2719
|
}
|
|
1690
2720
|
|
|
2721
|
+
.hai-ai-doc-selection-btn--active,
|
|
2722
|
+
.hai-ai-doc-selection-trigger--active {
|
|
2723
|
+
border-color: oklch(var(--p) / 0.22);
|
|
2724
|
+
background: oklch(var(--p) / 0.12);
|
|
2725
|
+
color: oklch(var(--bc));
|
|
2726
|
+
}
|
|
2727
|
+
|
|
1691
2728
|
.hai-ai-doc-selection-btn svg {
|
|
1692
2729
|
width: 1rem;
|
|
1693
2730
|
height: 1rem;
|
|
1694
2731
|
fill: currentColor;
|
|
1695
2732
|
}
|
|
1696
2733
|
|
|
2734
|
+
.hai-ai-doc-selection-trigger svg {
|
|
2735
|
+
width: 1rem;
|
|
2736
|
+
height: 1rem;
|
|
2737
|
+
fill: currentColor;
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2740
|
+
.hai-ai-doc-selection-trigger-label {
|
|
2741
|
+
font-weight: 600;
|
|
2742
|
+
line-height: 1;
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
.hai-ai-doc-selection-trigger-chevron {
|
|
2746
|
+
width: 0.8rem !important;
|
|
2747
|
+
height: 0.8rem !important;
|
|
2748
|
+
opacity: 0.72;
|
|
2749
|
+
}
|
|
2750
|
+
|
|
1697
2751
|
.hai-ai-doc-selection-divider {
|
|
1698
2752
|
width: 1px;
|
|
1699
2753
|
height: 1.45rem;
|
|
@@ -1705,6 +2759,7 @@ ${safeCode}
|
|
|
1705
2759
|
.hai-ai-doc-selection-highlight-icon {
|
|
1706
2760
|
position: relative;
|
|
1707
2761
|
font-weight: 700;
|
|
2762
|
+
color: var(--hai-ai-doc-current-color, currentColor);
|
|
1708
2763
|
}
|
|
1709
2764
|
|
|
1710
2765
|
.hai-ai-doc-selection-highlight-icon::after {
|
|
@@ -1715,41 +2770,213 @@ ${safeCode}
|
|
|
1715
2770
|
bottom: -0.02rem;
|
|
1716
2771
|
height: 0.36rem;
|
|
1717
2772
|
border-radius: 9999px;
|
|
1718
|
-
background:
|
|
2773
|
+
background: color-mix(
|
|
2774
|
+
in srgb,
|
|
2775
|
+
var(--hai-ai-doc-current-color, oklch(var(--wa, 0.9 0.14 90))) 22%,
|
|
2776
|
+
white 78%
|
|
2777
|
+
);
|
|
1719
2778
|
z-index: -1;
|
|
1720
2779
|
}
|
|
1721
2780
|
|
|
2781
|
+
.hai-ai-doc-selection-panel,
|
|
1722
2782
|
.hai-ai-doc-rewrite-menu {
|
|
1723
|
-
|
|
2783
|
+
position: absolute;
|
|
2784
|
+
left: var(--hai-ai-doc-selection-menu-left, 0px);
|
|
2785
|
+
top: calc(100% + 0.45rem);
|
|
1724
2786
|
display: grid;
|
|
1725
|
-
gap: 0.
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
border:
|
|
2787
|
+
gap: 0.34rem;
|
|
2788
|
+
width: min(18rem, calc(100vw - 2rem));
|
|
2789
|
+
max-width: calc(100vw - 2rem);
|
|
2790
|
+
padding: 0.42rem;
|
|
2791
|
+
border-radius: 1rem;
|
|
2792
|
+
background-color: rgb(255 255 255 / 0.96);
|
|
2793
|
+
background: color-mix(in srgb, oklch(var(--b1, 1 0 0)) 94%, white 6%);
|
|
2794
|
+
border: 1px solid rgb(148 163 184 / 0.3);
|
|
2795
|
+
border-color: color-mix(in srgb, oklch(var(--bc, 0.22 0 0)) 14%, white 86%);
|
|
1730
2796
|
box-shadow:
|
|
1731
|
-
0
|
|
1732
|
-
0
|
|
1733
|
-
0 0 0 1px rgb(255 255 255 / 0.94) inset;
|
|
2797
|
+
0 24px 40px -28px rgb(15 23 42 / 0.25),
|
|
2798
|
+
0 10px 20px -16px rgb(15 23 42 / 0.14);
|
|
1734
2799
|
pointer-events: auto;
|
|
1735
2800
|
isolation: isolate;
|
|
2801
|
+
z-index: 3;
|
|
1736
2802
|
}
|
|
1737
2803
|
|
|
1738
|
-
.hai-ai-doc-rewrite-menu
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
2804
|
+
.hai-ai-doc-rewrite-menu {
|
|
2805
|
+
width: fit-content;
|
|
2806
|
+
max-width: min(22rem, calc(100vw - 2rem));
|
|
2807
|
+
grid-template-columns: repeat(auto-fit, minmax(7.2rem, 1fr));
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
.hai-ai-doc-selection-layer[data-placement='bottom'] .hai-ai-doc-selection-panel,
|
|
2811
|
+
.hai-ai-doc-selection-layer[data-placement='bottom'] .hai-ai-doc-rewrite-menu {
|
|
2812
|
+
top: auto;
|
|
2813
|
+
bottom: calc(100% + 0.45rem);
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
.hai-ai-doc-selection-panel[data-menu-alignment='left'],
|
|
2817
|
+
.hai-ai-doc-rewrite-menu[data-menu-alignment='left'] {
|
|
2818
|
+
transform: translateX(0);
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
.hai-ai-doc-selection-panel[data-menu-alignment='center'],
|
|
2822
|
+
.hai-ai-doc-rewrite-menu[data-menu-alignment='center'] {
|
|
2823
|
+
transform: translateX(-50%);
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
.hai-ai-doc-selection-panel[data-menu-alignment='right'],
|
|
2827
|
+
.hai-ai-doc-rewrite-menu[data-menu-alignment='right'] {
|
|
2828
|
+
transform: translateX(-100%);
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
.hai-ai-doc-selection-panel--link,
|
|
2832
|
+
.hai-ai-doc-selection-panel--color {
|
|
2833
|
+
width: min(16rem, calc(100vw - 2rem));
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
.hai-ai-doc-selection-menu-btn,
|
|
2837
|
+
.hai-ai-doc-selection-panel-btn,
|
|
2838
|
+
.hai-ai-doc-rewrite-menu-btn {
|
|
2839
|
+
min-height: 2rem;
|
|
2840
|
+
display: inline-flex;
|
|
2841
|
+
align-items: center;
|
|
2842
|
+
justify-content: space-between;
|
|
2843
|
+
gap: 0.6rem;
|
|
2844
|
+
width: 100%;
|
|
2845
|
+
padding: 0 0.72rem;
|
|
2846
|
+
border-radius: 0.8rem;
|
|
2847
|
+
border: 1px solid oklch(var(--bc) / 0.14);
|
|
2848
|
+
background: color-mix(in srgb, oklch(var(--b1)) 92%, white 8%);
|
|
2849
|
+
color: oklch(var(--bc) / 0.86);
|
|
2850
|
+
font-size: 0.82rem;
|
|
2851
|
+
line-height: 1;
|
|
1745
2852
|
cursor: pointer;
|
|
2853
|
+
transition:
|
|
2854
|
+
background-color 0.14s ease,
|
|
2855
|
+
border-color 0.14s ease,
|
|
2856
|
+
color 0.14s ease,
|
|
2857
|
+
transform 0.14s ease;
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
.hai-ai-doc-selection-menu-btn--active,
|
|
2861
|
+
.hai-ai-doc-selection-panel-btn--primary {
|
|
2862
|
+
border-color: oklch(var(--p) / 0.28);
|
|
2863
|
+
background: oklch(var(--p) / 0.12);
|
|
2864
|
+
color: oklch(var(--bc));
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
.hai-ai-doc-selection-menu-btn:hover,
|
|
2868
|
+
.hai-ai-doc-selection-panel-btn:hover,
|
|
2869
|
+
.hai-ai-doc-rewrite-menu-btn:hover:not(:disabled) {
|
|
2870
|
+
border-color: oklch(var(--bc) / 0.22);
|
|
2871
|
+
background: color-mix(in srgb, oklch(var(--b2)) 68%, white 32%);
|
|
2872
|
+
color: oklch(var(--bc));
|
|
2873
|
+
transform: translateY(-1px);
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
.hai-ai-doc-selection-menu-label {
|
|
2877
|
+
display: inline-flex;
|
|
2878
|
+
align-items: center;
|
|
2879
|
+
gap: 0.62rem;
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
.hai-ai-doc-selection-menu-short {
|
|
2883
|
+
min-width: 2rem;
|
|
2884
|
+
color: oklch(var(--p) / 0.92);
|
|
2885
|
+
font-weight: 700;
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
.hai-ai-doc-selection-menu-check {
|
|
2889
|
+
color: oklch(var(--p) / 0.88);
|
|
2890
|
+
font-weight: 700;
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
.hai-ai-doc-selection-input {
|
|
2894
|
+
width: 100%;
|
|
2895
|
+
min-height: 2.25rem;
|
|
2896
|
+
padding: 0 0.78rem;
|
|
2897
|
+
border-radius: 0.85rem;
|
|
2898
|
+
border: 1px solid oklch(var(--bc) / 0.16);
|
|
2899
|
+
background: color-mix(in srgb, oklch(var(--b1)) 94%, white 6%);
|
|
2900
|
+
color: oklch(var(--bc));
|
|
2901
|
+
font-size: 0.84rem;
|
|
2902
|
+
outline: none;
|
|
1746
2903
|
}
|
|
1747
2904
|
|
|
1748
|
-
.hai-ai-doc-
|
|
2905
|
+
.hai-ai-doc-selection-input:focus {
|
|
2906
|
+
border-color: oklch(var(--p) / 0.34);
|
|
2907
|
+
box-shadow: 0 0 0 3px oklch(var(--p) / 0.12);
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2910
|
+
.hai-ai-doc-selection-panel-actions {
|
|
2911
|
+
display: flex;
|
|
2912
|
+
gap: 0.4rem;
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
.hai-ai-doc-selection-panel-actions .hai-ai-doc-selection-panel-btn {
|
|
2916
|
+
flex: 1 1 0;
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
.hai-ai-doc-selection-panel-btn:disabled,
|
|
2920
|
+
.hai-ai-doc-rewrite-menu-btn:disabled {
|
|
1749
2921
|
opacity: 0.55;
|
|
1750
2922
|
cursor: default;
|
|
1751
2923
|
}
|
|
1752
2924
|
|
|
2925
|
+
.hai-ai-doc-color-group {
|
|
2926
|
+
display: grid;
|
|
2927
|
+
gap: 0.42rem;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
.hai-ai-doc-color-group-title {
|
|
2931
|
+
font-size: 0.78rem;
|
|
2932
|
+
font-weight: 600;
|
|
2933
|
+
color: oklch(var(--bc) / 0.68);
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
.hai-ai-doc-color-grid {
|
|
2937
|
+
display: grid;
|
|
2938
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
2939
|
+
gap: 0.42rem;
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2942
|
+
.hai-ai-doc-color-swatch {
|
|
2943
|
+
width: 100%;
|
|
2944
|
+
aspect-ratio: 1;
|
|
2945
|
+
display: inline-flex;
|
|
2946
|
+
align-items: center;
|
|
2947
|
+
justify-content: center;
|
|
2948
|
+
padding: 0.18rem;
|
|
2949
|
+
border-radius: 0.7rem;
|
|
2950
|
+
border: 1px solid oklch(var(--bc) / 0.12);
|
|
2951
|
+
background: color-mix(in srgb, oklch(var(--b1)) 92%, white 8%);
|
|
2952
|
+
cursor: pointer;
|
|
2953
|
+
transition:
|
|
2954
|
+
transform 0.14s ease,
|
|
2955
|
+
border-color 0.14s ease,
|
|
2956
|
+
box-shadow 0.14s ease;
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
.hai-ai-doc-color-swatch:hover {
|
|
2960
|
+
transform: translateY(-1px);
|
|
2961
|
+
border-color: oklch(var(--bc) / 0.2);
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
.hai-ai-doc-color-swatch--active {
|
|
2965
|
+
border-color: oklch(var(--p) / 0.34);
|
|
2966
|
+
box-shadow: 0 0 0 3px oklch(var(--p) / 0.12);
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
.hai-ai-doc-color-swatch span {
|
|
2970
|
+
width: 100%;
|
|
2971
|
+
height: 100%;
|
|
2972
|
+
border-radius: 0.5rem;
|
|
2973
|
+
border: 1px solid rgb(15 23 42 / 0.08);
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
.hai-ai-doc-rewrite-menu-btn {
|
|
2977
|
+
justify-content: center;
|
|
2978
|
+
}
|
|
2979
|
+
|
|
1753
2980
|
.hai-markdown {
|
|
1754
2981
|
line-height: 1.9;
|
|
1755
2982
|
color: inherit;
|
|
@@ -1758,12 +2985,28 @@ ${safeCode}
|
|
|
1758
2985
|
}
|
|
1759
2986
|
|
|
1760
2987
|
.hai-markdown-document {
|
|
2988
|
+
width: 100%;
|
|
2989
|
+
min-width: 0;
|
|
1761
2990
|
max-width: 52.5rem;
|
|
1762
2991
|
margin: 0 auto;
|
|
1763
2992
|
padding: 1.25rem 2rem 6rem;
|
|
1764
2993
|
outline: none;
|
|
1765
2994
|
}
|
|
1766
2995
|
|
|
2996
|
+
.hai-markdown-document.hai-markdown-code-only {
|
|
2997
|
+
max-width: none !important;
|
|
2998
|
+
width: 100% !important;
|
|
2999
|
+
min-width: 0;
|
|
3000
|
+
margin: 0 !important;
|
|
3001
|
+
height: 100%;
|
|
3002
|
+
min-height: 100%;
|
|
3003
|
+
padding: 0.5rem 0.75rem 0.75rem;
|
|
3004
|
+
display: flex;
|
|
3005
|
+
flex-direction: column;
|
|
3006
|
+
flex: 1 1 auto;
|
|
3007
|
+
box-sizing: border-box;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
1767
3010
|
:global(.hai-markdown-document ::selection) {
|
|
1768
3011
|
background: var(--hai-ai-doc-selection-bg, rgb(59 130 246 / 0.22));
|
|
1769
3012
|
color: var(--hai-ai-doc-selection-fg, inherit);
|
|
@@ -1829,6 +3072,10 @@ ${safeCode}
|
|
|
1829
3072
|
margin-bottom: 1em;
|
|
1830
3073
|
}
|
|
1831
3074
|
|
|
3075
|
+
.hai-markdown :global(.hai-md-align-block) {
|
|
3076
|
+
width: 100%;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
1832
3079
|
.hai-markdown :global(a) {
|
|
1833
3080
|
color: oklch(var(--p));
|
|
1834
3081
|
text-decoration: none;
|
|
@@ -1852,6 +3099,23 @@ ${safeCode}
|
|
|
1852
3099
|
color: oklch(var(--bc) / 0.55);
|
|
1853
3100
|
}
|
|
1854
3101
|
|
|
3102
|
+
.hai-markdown :global(u) {
|
|
3103
|
+
text-decoration-thickness: 0.08em;
|
|
3104
|
+
text-underline-offset: 0.14em;
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
.hai-markdown :global(mark) {
|
|
3108
|
+
padding: 0 0.12em;
|
|
3109
|
+
border-radius: 0.25rem;
|
|
3110
|
+
background: oklch(var(--wa, 0.9 0.14 90) / 0.34);
|
|
3111
|
+
color: inherit;
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
.hai-markdown :global(.hai-md-inline-style) {
|
|
3115
|
+
border-radius: 0.2rem;
|
|
3116
|
+
padding: 0 0.04em;
|
|
3117
|
+
}
|
|
3118
|
+
|
|
1855
3119
|
.hai-markdown :global(:not(pre) > code) {
|
|
1856
3120
|
padding: 0.2em 0.4em;
|
|
1857
3121
|
margin: 0 0.1em;
|
|
@@ -1881,6 +3145,7 @@ ${safeCode}
|
|
|
1881
3145
|
gap: 0.75rem;
|
|
1882
3146
|
padding: 0.65rem 1rem;
|
|
1883
3147
|
min-height: 2.5rem;
|
|
3148
|
+
line-height: 1.2;
|
|
1884
3149
|
background: oklch(var(--n) / 0.94);
|
|
1885
3150
|
border-bottom: 1px solid oklch(var(--nc) / 0.1);
|
|
1886
3151
|
}
|
|
@@ -1889,6 +3154,7 @@ ${safeCode}
|
|
|
1889
3154
|
min-width: 0;
|
|
1890
3155
|
display: flex;
|
|
1891
3156
|
align-items: center;
|
|
3157
|
+
gap: 0.55rem;
|
|
1892
3158
|
}
|
|
1893
3159
|
|
|
1894
3160
|
.hai-markdown :global(.hai-md-code-actions) {
|
|
@@ -1900,12 +3166,54 @@ ${safeCode}
|
|
|
1900
3166
|
.hai-markdown :global(.hai-md-code-lang) {
|
|
1901
3167
|
font-size: 0.75rem;
|
|
1902
3168
|
font-weight: 600;
|
|
3169
|
+
line-height: 1;
|
|
1903
3170
|
text-transform: uppercase;
|
|
1904
3171
|
letter-spacing: 0.05em;
|
|
1905
3172
|
color: oklch(var(--nc) / 0.6);
|
|
1906
3173
|
user-select: none;
|
|
1907
3174
|
}
|
|
1908
3175
|
|
|
3176
|
+
.hai-markdown :global(.hai-md-code-view-switch) {
|
|
3177
|
+
display: inline-flex;
|
|
3178
|
+
align-items: center;
|
|
3179
|
+
gap: 0.16rem;
|
|
3180
|
+
padding: 0.15rem;
|
|
3181
|
+
border-radius: 9999px;
|
|
3182
|
+
border: 1px solid oklch(var(--nc) / 0.16);
|
|
3183
|
+
background: oklch(var(--nc) / 0.08);
|
|
3184
|
+
flex-shrink: 0;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
.hai-markdown :global(.hai-md-code-view-btn) {
|
|
3188
|
+
min-height: 1.7rem;
|
|
3189
|
+
padding: 0 0.72rem;
|
|
3190
|
+
border: none;
|
|
3191
|
+
border-radius: 9999px;
|
|
3192
|
+
background: transparent;
|
|
3193
|
+
color: oklch(var(--nc) / 0.72);
|
|
3194
|
+
font-size: 0.86rem;
|
|
3195
|
+
font-weight: 600;
|
|
3196
|
+
line-height: 1;
|
|
3197
|
+
cursor: pointer;
|
|
3198
|
+
transition:
|
|
3199
|
+
background-color 0.15s ease,
|
|
3200
|
+
color 0.15s ease;
|
|
3201
|
+
}
|
|
3202
|
+
|
|
3203
|
+
.hai-markdown :global(.hai-md-code-view-btn[aria-pressed='true']) {
|
|
3204
|
+
background: oklch(var(--nc) / 0.2);
|
|
3205
|
+
color: oklch(var(--nc));
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
.hai-markdown :global(.hai-md-code-preview-hint) {
|
|
3209
|
+
font-size: 0.75rem;
|
|
3210
|
+
line-height: 1;
|
|
3211
|
+
color: oklch(var(--nc) / 0.48);
|
|
3212
|
+
white-space: nowrap;
|
|
3213
|
+
overflow: hidden;
|
|
3214
|
+
text-overflow: ellipsis;
|
|
3215
|
+
}
|
|
3216
|
+
|
|
1909
3217
|
.hai-markdown :global(.hai-md-code-lang-empty) {
|
|
1910
3218
|
opacity: 0.7;
|
|
1911
3219
|
}
|
|
@@ -1945,8 +3253,21 @@ ${safeCode}
|
|
|
1945
3253
|
ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
|
|
1946
3254
|
'Liberation Mono', monospace;
|
|
1947
3255
|
font-size: 0.875rem;
|
|
1948
|
-
line-height: 1.
|
|
3256
|
+
line-height: 1.45;
|
|
1949
3257
|
tab-size: 2;
|
|
3258
|
+
|
|
3259
|
+
/* Shiki CSS Variables 主题(由 highlight.ts 的 createCssVariablesTheme 引用) */
|
|
3260
|
+
--hai-hl-foreground: oklch(var(--nc));
|
|
3261
|
+
--hai-hl-background: transparent;
|
|
3262
|
+
--hai-hl-token-keyword: oklch(0.7 0.15 280);
|
|
3263
|
+
--hai-hl-token-string: oklch(0.75 0.12 150);
|
|
3264
|
+
--hai-hl-token-string-expression: oklch(0.75 0.12 150);
|
|
3265
|
+
--hai-hl-token-constant: oklch(0.78 0.12 70);
|
|
3266
|
+
--hai-hl-token-comment: oklch(var(--nc) / 0.45);
|
|
3267
|
+
--hai-hl-token-function: oklch(0.72 0.14 220);
|
|
3268
|
+
--hai-hl-token-parameter: oklch(0.72 0.12 35);
|
|
3269
|
+
--hai-hl-token-punctuation: oklch(var(--nc) / 0.7);
|
|
3270
|
+
--hai-hl-token-link: oklch(0.7 0.15 280);
|
|
1950
3271
|
}
|
|
1951
3272
|
|
|
1952
3273
|
.hai-markdown :global(.hai-md-code-preview-slot) {
|
|
@@ -1954,6 +3275,76 @@ ${safeCode}
|
|
|
1954
3275
|
background: oklch(var(--b1));
|
|
1955
3276
|
}
|
|
1956
3277
|
|
|
3278
|
+
.hai-markdown :global(.hai-md-code-block[data-code-view='code'] .hai-md-code-preview-slot) {
|
|
3279
|
+
display: none;
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
.hai-markdown :global(.hai-md-code-block[data-code-view='preview'] pre) {
|
|
3283
|
+
display: none;
|
|
3284
|
+
}
|
|
3285
|
+
|
|
3286
|
+
.hai-markdown :global(.hai-md-code-block[data-code-view='preview'] .hai-md-code-preview-slot) {
|
|
3287
|
+
display: block;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
.hai-markdown-code-only :global(.hai-md-code-block) {
|
|
3291
|
+
width: 100% !important;
|
|
3292
|
+
max-width: none !important;
|
|
3293
|
+
min-width: 0;
|
|
3294
|
+
margin: 0;
|
|
3295
|
+
height: auto;
|
|
3296
|
+
min-height: 0;
|
|
3297
|
+
flex: 1 1 auto;
|
|
3298
|
+
display: flex !important;
|
|
3299
|
+
align-self: stretch;
|
|
3300
|
+
align-items: stretch;
|
|
3301
|
+
flex-direction: column;
|
|
3302
|
+
overflow: hidden;
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
.hai-markdown-code-only :global(.hai-md-code-header),
|
|
3306
|
+
.hai-markdown-code-only :global(.hai-md-code-block pre),
|
|
3307
|
+
.hai-markdown-code-only :global(.hai-md-code-preview-slot) {
|
|
3308
|
+
width: 100%;
|
|
3309
|
+
min-width: 0;
|
|
3310
|
+
min-height: 0;
|
|
3311
|
+
box-sizing: border-box;
|
|
3312
|
+
}
|
|
3313
|
+
|
|
3314
|
+
/* 代码/预览切换时统一固定 header 高度,避免视觉抖动。 */
|
|
3315
|
+
.hai-markdown-code-only :global(.hai-md-code-header) {
|
|
3316
|
+
flex: 0 0 3.1rem;
|
|
3317
|
+
height: 3.1rem;
|
|
3318
|
+
min-height: 3.1rem;
|
|
3319
|
+
padding: 0 1rem;
|
|
3320
|
+
align-items: center;
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3323
|
+
.hai-markdown-code-only :global(.hai-md-code-block pre),
|
|
3324
|
+
.hai-markdown-code-only :global(.hai-md-code-preview-slot) {
|
|
3325
|
+
flex: 1 1 auto;
|
|
3326
|
+
height: auto;
|
|
3327
|
+
min-height: 0;
|
|
3328
|
+
}
|
|
3329
|
+
|
|
3330
|
+
.hai-markdown-code-only :global(.hai-md-code-block pre) {
|
|
3331
|
+
overflow: auto;
|
|
3332
|
+
}
|
|
3333
|
+
|
|
3334
|
+
.hai-markdown-code-only :global(.hai-md-code-preview-slot) {
|
|
3335
|
+
background: oklch(var(--n));
|
|
3336
|
+
color: oklch(var(--nc));
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
.hai-markdown-code-only :global(.hai-md-code-block[data-code-view='preview']) {
|
|
3340
|
+
flex: 1 1 auto;
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
.hai-markdown-code-only :global(.hai-md-code-block[data-code-view='preview'] .hai-md-code-preview-slot) {
|
|
3344
|
+
flex: 1 1 auto;
|
|
3345
|
+
display: flex;
|
|
3346
|
+
}
|
|
3347
|
+
|
|
1957
3348
|
.hai-markdown :global(blockquote) {
|
|
1958
3349
|
margin: 1em 0;
|
|
1959
3350
|
padding: 0.65em 1.1em;
|
|
@@ -2071,14 +3462,29 @@ ${safeCode}
|
|
|
2071
3462
|
box-shadow: inset 0 -1px 0 oklch(var(--bc) / 0.1);
|
|
2072
3463
|
}
|
|
2073
3464
|
|
|
2074
|
-
.hai-md-preview-card {
|
|
3465
|
+
:global(.hai-md-preview-card) {
|
|
2075
3466
|
margin: 0;
|
|
2076
3467
|
padding: 1rem;
|
|
2077
3468
|
background: oklch(var(--b1));
|
|
2078
3469
|
color: oklch(var(--bc));
|
|
2079
3470
|
}
|
|
2080
3471
|
|
|
2081
|
-
.hai-md-preview-
|
|
3472
|
+
.hai-markdown-code-only :global(.hai-md-code-block[data-code-view='preview'] .hai-md-preview-card) {
|
|
3473
|
+
display: flex;
|
|
3474
|
+
flex-direction: column;
|
|
3475
|
+
flex: 1 1 auto;
|
|
3476
|
+
min-height: 0;
|
|
3477
|
+
padding: 0.95rem 1rem;
|
|
3478
|
+
background: oklch(var(--n));
|
|
3479
|
+
color: oklch(var(--nc));
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
.hai-markdown-code-only :global(.hai-md-code-block[data-code-view='preview'] .hai-md-preview-head),
|
|
3483
|
+
.hai-markdown-code-only :global(.hai-md-code-block[data-code-view='preview'] .hai-md-preview-desc) {
|
|
3484
|
+
display: none;
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3487
|
+
:global(.hai-md-preview-head) {
|
|
2082
3488
|
font-size: 0.8rem;
|
|
2083
3489
|
font-weight: 700;
|
|
2084
3490
|
letter-spacing: 0.04em;
|
|
@@ -2086,12 +3492,43 @@ ${safeCode}
|
|
|
2086
3492
|
color: oklch(var(--bc) / 0.7);
|
|
2087
3493
|
}
|
|
2088
3494
|
|
|
2089
|
-
.hai-md-preview-desc {
|
|
3495
|
+
:global(.hai-md-preview-desc) {
|
|
2090
3496
|
margin: 0.5rem 0 0;
|
|
2091
3497
|
font-size: 0.875rem;
|
|
2092
3498
|
color: oklch(var(--bc) / 0.7);
|
|
2093
3499
|
}
|
|
2094
3500
|
|
|
3501
|
+
:global(.hai-md-preview-empty) {
|
|
3502
|
+
min-height: 100%;
|
|
3503
|
+
display: flex;
|
|
3504
|
+
flex-direction: column;
|
|
3505
|
+
gap: 0.62rem;
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3508
|
+
:global(.hai-md-preview-empty-title) {
|
|
3509
|
+
margin: 0;
|
|
3510
|
+
font-size: 0.9rem;
|
|
3511
|
+
font-weight: 700;
|
|
3512
|
+
letter-spacing: 0.01em;
|
|
3513
|
+
color: oklch(var(--bc) / 0.85);
|
|
3514
|
+
}
|
|
3515
|
+
|
|
3516
|
+
:global(.hai-md-preview-empty-text) {
|
|
3517
|
+
margin: 0;
|
|
3518
|
+
font-size: 0.84rem;
|
|
3519
|
+
line-height: 1.58;
|
|
3520
|
+
white-space: pre-wrap;
|
|
3521
|
+
color: oklch(var(--bc) / 0.74);
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
.hai-markdown-code-only :global(.hai-md-preview-empty-title) {
|
|
3525
|
+
color: oklch(var(--nc) / 0.88);
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
.hai-markdown-code-only :global(.hai-md-preview-empty-text) {
|
|
3529
|
+
color: oklch(var(--nc) / 0.72);
|
|
3530
|
+
}
|
|
3531
|
+
|
|
2095
3532
|
:global(.hai-md-preview-card pre) {
|
|
2096
3533
|
margin: 0.85rem 0 0;
|
|
2097
3534
|
padding: 0.85rem 1rem;
|
|
@@ -2105,7 +3542,7 @@ ${safeCode}
|
|
|
2105
3542
|
color: oklch(var(--er));
|
|
2106
3543
|
}
|
|
2107
3544
|
|
|
2108
|
-
.hai-md-preview-frame {
|
|
3545
|
+
:global(.hai-md-preview-frame) {
|
|
2109
3546
|
display: block;
|
|
2110
3547
|
width: 100%;
|
|
2111
3548
|
min-height: 280px;
|
|
@@ -2115,10 +3552,19 @@ ${safeCode}
|
|
|
2115
3552
|
background: white;
|
|
2116
3553
|
}
|
|
2117
3554
|
|
|
2118
|
-
.hai-md-preview-
|
|
3555
|
+
.hai-markdown-code-only :global(.hai-md-code-block[data-code-view='preview'] .hai-md-preview-frame) {
|
|
3556
|
+
flex: 1 1 auto;
|
|
3557
|
+
height: 100%;
|
|
3558
|
+
min-height: 0;
|
|
3559
|
+
margin-top: 0;
|
|
3560
|
+
border: none;
|
|
3561
|
+
border-radius: 0;
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
:global(.hai-md-preview-loading) {
|
|
2119
3565
|
width: 100%;
|
|
2120
3566
|
height: 4px;
|
|
2121
|
-
margin-top: 0.
|
|
3567
|
+
margin-top: 0.5rem;
|
|
2122
3568
|
border-radius: 9999px;
|
|
2123
3569
|
background: linear-gradient(
|
|
2124
3570
|
90deg,
|
|
@@ -2130,27 +3576,10 @@ ${safeCode}
|
|
|
2130
3576
|
animation: hai-md-loading 1.2s linear infinite;
|
|
2131
3577
|
}
|
|
2132
3578
|
|
|
2133
|
-
.hai-md-preview-rendered :
|
|
3579
|
+
:global(.hai-md-preview-rendered > :first-child) {
|
|
2134
3580
|
margin-top: 0.85rem;
|
|
2135
3581
|
}
|
|
2136
3582
|
|
|
2137
|
-
/* Shiki CSS Variables 主题 — 代码高亮 token 颜色 */
|
|
2138
|
-
.hai-markdown :global(.hai-md-code-block code) {
|
|
2139
|
-
--hai-hl-fg: oklch(var(--nc));
|
|
2140
|
-
--hai-hl-bg: transparent;
|
|
2141
|
-
|
|
2142
|
-
/* token 颜色 */
|
|
2143
|
-
--hai-hl-token-keyword: oklch(0.7 0.15 280);
|
|
2144
|
-
--hai-hl-token-string: oklch(0.75 0.12 150);
|
|
2145
|
-
--hai-hl-token-string-expression: oklch(0.75 0.12 150);
|
|
2146
|
-
--hai-hl-token-constant: oklch(0.78 0.12 70);
|
|
2147
|
-
--hai-hl-token-comment: oklch(var(--nc) / 0.45);
|
|
2148
|
-
--hai-hl-token-function: oklch(0.72 0.14 220);
|
|
2149
|
-
--hai-hl-token-parameter: oklch(0.72 0.12 35);
|
|
2150
|
-
--hai-hl-token-punctuation: oklch(var(--nc) / 0.7);
|
|
2151
|
-
--hai-hl-token-link: oklch(0.7 0.15 280);
|
|
2152
|
-
}
|
|
2153
|
-
|
|
2154
3583
|
@keyframes hai-md-loading {
|
|
2155
3584
|
from {
|
|
2156
3585
|
background-position: 220px 0;
|
|
@@ -2161,16 +3590,31 @@ ${safeCode}
|
|
|
2161
3590
|
}
|
|
2162
3591
|
}
|
|
2163
3592
|
|
|
2164
|
-
@
|
|
2165
|
-
.hai-ai-doc-layout
|
|
2166
|
-
|
|
2167
|
-
|
|
3593
|
+
@container ai-doc-editor (max-width: 800px) {
|
|
3594
|
+
.hai-ai-doc-layout {
|
|
3595
|
+
display: flex;
|
|
3596
|
+
min-height: 0;
|
|
2168
3597
|
}
|
|
2169
3598
|
|
|
2170
3599
|
.hai-ai-doc-outline {
|
|
2171
|
-
|
|
3600
|
+
position: absolute;
|
|
3601
|
+
top: 0.65rem;
|
|
3602
|
+
left: 0.65rem;
|
|
3603
|
+
bottom: 0.85rem;
|
|
3604
|
+
width: min(220px, calc(100% - 1.3rem));
|
|
3605
|
+
max-width: 220px;
|
|
3606
|
+
z-index: 14;
|
|
3607
|
+
padding: 0.5rem 0.625rem 0.9rem 0.75rem;
|
|
3608
|
+
border: 1px solid oklch(var(--bc) / 0.12);
|
|
3609
|
+
border-radius: 0.95rem;
|
|
3610
|
+
background:
|
|
3611
|
+
linear-gradient(180deg, oklch(var(--b2) / 0.84), oklch(var(--b1) / 0.92));
|
|
3612
|
+
box-shadow: 0 20px 40px -28px oklch(var(--bc) / 0.35);
|
|
3613
|
+
backdrop-filter: blur(8px);
|
|
2172
3614
|
}
|
|
3615
|
+
}
|
|
2173
3616
|
|
|
3617
|
+
@media (max-width: 960px) {
|
|
2174
3618
|
.hai-ai-doc-topbar {
|
|
2175
3619
|
padding-left: 1rem;
|
|
2176
3620
|
padding-right: 1rem;
|
|
@@ -2203,7 +3647,7 @@ ${safeCode}
|
|
|
2203
3647
|
|
|
2204
3648
|
.hai-ai-doc-selection-toolbar {
|
|
2205
3649
|
max-width: calc(100vw - 2rem);
|
|
2206
|
-
overflow:
|
|
3650
|
+
overflow: hidden;
|
|
2207
3651
|
}
|
|
2208
3652
|
}
|
|
2209
3653
|
</style>
|