@jvs-milkdown/components 1.2.29 → 1.2.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jvs-milkdown/components",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.30",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"milkdown",
|
|
6
6
|
"milkdown plugin"
|
|
@@ -55,15 +55,15 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@codemirror/merge": "^6.12.1",
|
|
57
57
|
"@floating-ui/dom": "^1.5.1",
|
|
58
|
-
"@jvs-milkdown/core": "^1.2.
|
|
59
|
-
"@jvs-milkdown/ctx": "^1.2.
|
|
60
|
-
"@jvs-milkdown/exception": "^1.2.
|
|
61
|
-
"@jvs-milkdown/plugin-tooltip": "^1.2.
|
|
62
|
-
"@jvs-milkdown/preset-commonmark": "^1.2.
|
|
63
|
-
"@jvs-milkdown/preset-gfm": "^1.2.
|
|
64
|
-
"@jvs-milkdown/prose": "^1.2.
|
|
65
|
-
"@jvs-milkdown/transformer": "^1.2.
|
|
66
|
-
"@jvs-milkdown/utils": "^1.2.
|
|
58
|
+
"@jvs-milkdown/core": "^1.2.30",
|
|
59
|
+
"@jvs-milkdown/ctx": "^1.2.30",
|
|
60
|
+
"@jvs-milkdown/exception": "^1.2.30",
|
|
61
|
+
"@jvs-milkdown/plugin-tooltip": "^1.2.30",
|
|
62
|
+
"@jvs-milkdown/preset-commonmark": "^1.2.30",
|
|
63
|
+
"@jvs-milkdown/preset-gfm": "^1.2.30",
|
|
64
|
+
"@jvs-milkdown/prose": "^1.2.30",
|
|
65
|
+
"@jvs-milkdown/transformer": "^1.2.30",
|
|
66
|
+
"@jvs-milkdown/utils": "^1.2.30",
|
|
67
67
|
"@types/lodash-es": "^4.17.12",
|
|
68
68
|
"clsx": "^2.0.0",
|
|
69
69
|
"dompurify": "^3.2.5",
|
|
@@ -222,12 +222,6 @@ export const ImageViewer = defineComponent<MilkdownImageBlockProps>({
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
// --- Crop box interaction ---
|
|
225
|
-
const borderStyleOptions = [
|
|
226
|
-
{ label: 'none', value: 'none' },
|
|
227
|
-
{ label: 'solid', value: 'solid' },
|
|
228
|
-
{ label: 'dashed', value: 'dashed' },
|
|
229
|
-
{ label: 'dotted', value: 'dotted' },
|
|
230
|
-
]
|
|
231
225
|
|
|
232
226
|
const onToggleCropPanel = (e: MouseEvent) => {
|
|
233
227
|
e.preventDefault()
|
|
@@ -241,11 +235,352 @@ export const ImageViewer = defineComponent<MilkdownImageBlockProps>({
|
|
|
241
235
|
}
|
|
242
236
|
}
|
|
243
237
|
|
|
244
|
-
const
|
|
238
|
+
const onToggleBorder = (e: MouseEvent) => {
|
|
245
239
|
e.preventDefault()
|
|
246
240
|
e.stopPropagation()
|
|
247
241
|
if (readonly.value) return
|
|
248
|
-
|
|
242
|
+
|
|
243
|
+
const isSolid =
|
|
244
|
+
borderStyle.value === 'solid' && (borderWidth.value ?? 0) === 1
|
|
245
|
+
if (isSolid) {
|
|
246
|
+
setAttr('borderStyle', 'none')
|
|
247
|
+
setAttr('borderWidth', 0)
|
|
248
|
+
} else {
|
|
249
|
+
setAttr('borderStyle', 'solid')
|
|
250
|
+
setAttr('borderWidth', 1)
|
|
251
|
+
if (!borderColor.value) {
|
|
252
|
+
setAttr('borderColor', '#000000')
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const openLightbox = (images: string[], startIndex: number) => {
|
|
258
|
+
let currentIndex = startIndex
|
|
259
|
+
let scale = 1.0
|
|
260
|
+
let rotate = 0
|
|
261
|
+
const doc = wrapperRef.value?.ownerDocument || document
|
|
262
|
+
|
|
263
|
+
const overlay = doc.createElement('div')
|
|
264
|
+
overlay.style.position = 'fixed'
|
|
265
|
+
overlay.style.inset = '0'
|
|
266
|
+
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
|
267
|
+
overlay.style.zIndex = '99999'
|
|
268
|
+
overlay.style.display = 'flex'
|
|
269
|
+
overlay.style.flexDirection = 'column'
|
|
270
|
+
overlay.style.alignItems = 'center'
|
|
271
|
+
overlay.style.justifyContent = 'center'
|
|
272
|
+
overlay.style.userSelect = 'none'
|
|
273
|
+
|
|
274
|
+
// Image container
|
|
275
|
+
const imgContainer = doc.createElement('div')
|
|
276
|
+
imgContainer.style.position = 'relative'
|
|
277
|
+
imgContainer.style.display = 'flex'
|
|
278
|
+
imgContainer.style.alignItems = 'center'
|
|
279
|
+
imgContainer.style.justifyContent = 'center'
|
|
280
|
+
imgContainer.style.maxWidth = '90%'
|
|
281
|
+
imgContainer.style.maxHeight = '80%'
|
|
282
|
+
|
|
283
|
+
const img = doc.createElement('img')
|
|
284
|
+
img.src = images[currentIndex] || ''
|
|
285
|
+
img.style.maxWidth = '100%'
|
|
286
|
+
img.style.maxHeight = '100%'
|
|
287
|
+
img.style.objectFit = 'contain'
|
|
288
|
+
img.style.borderRadius = '4px'
|
|
289
|
+
img.style.transition = 'transform 0.2s ease-out, opacity 0.2s ease-out'
|
|
290
|
+
imgContainer.appendChild(img)
|
|
291
|
+
|
|
292
|
+
const applyTransform = () => {
|
|
293
|
+
img.style.transform = `scale(${scale}) rotate(${rotate}deg)`
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Navigation controls
|
|
297
|
+
const createArrow = (direction: 'left' | 'right') => {
|
|
298
|
+
const arrow = doc.createElement('div')
|
|
299
|
+
arrow.style.position = 'absolute'
|
|
300
|
+
arrow.style.top = '50%'
|
|
301
|
+
arrow.style.transform = 'translateY(-50%)'
|
|
302
|
+
arrow.style.width = '48px'
|
|
303
|
+
arrow.style.height = '48px'
|
|
304
|
+
arrow.style.borderRadius = '50%'
|
|
305
|
+
arrow.style.backgroundColor = 'rgba(0, 0, 0, 0.4)'
|
|
306
|
+
arrow.style.backdropFilter = 'blur(8px)'
|
|
307
|
+
;(arrow.style as any).webkitBackdropFilter = 'blur(8px)'
|
|
308
|
+
arrow.style.color = '#ffffff'
|
|
309
|
+
arrow.style.display = 'flex'
|
|
310
|
+
arrow.style.alignItems = 'center'
|
|
311
|
+
arrow.style.justifyContent = 'center'
|
|
312
|
+
arrow.style.cursor = 'pointer'
|
|
313
|
+
arrow.style.transition = 'background-color 0.2s, transform 0.2s'
|
|
314
|
+
arrow.style.zIndex = '15'
|
|
315
|
+
|
|
316
|
+
const chevronSvg =
|
|
317
|
+
direction === 'left'
|
|
318
|
+
? `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>`
|
|
319
|
+
: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>`
|
|
320
|
+
|
|
321
|
+
arrow.innerHTML = chevronSvg
|
|
322
|
+
|
|
323
|
+
if (direction === 'left') {
|
|
324
|
+
arrow.style.left = '24px'
|
|
325
|
+
} else {
|
|
326
|
+
arrow.style.right = '24px'
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
arrow.addEventListener('mouseenter', () => {
|
|
330
|
+
arrow.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'
|
|
331
|
+
arrow.style.transform = 'translateY(-50%) scale(1.05)'
|
|
332
|
+
})
|
|
333
|
+
arrow.addEventListener('mouseleave', () => {
|
|
334
|
+
arrow.style.backgroundColor = 'rgba(0, 0, 0, 0.4)'
|
|
335
|
+
arrow.style.transform = 'translateY(-50%) scale(1)'
|
|
336
|
+
})
|
|
337
|
+
return arrow
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const leftArrow = createArrow('left')
|
|
341
|
+
const rightArrow = createArrow('right')
|
|
342
|
+
overlay.appendChild(leftArrow)
|
|
343
|
+
overlay.appendChild(rightArrow)
|
|
344
|
+
|
|
345
|
+
const updateArrowsVisibility = () => {
|
|
346
|
+
leftArrow.style.display = currentIndex > 0 ? 'flex' : 'none'
|
|
347
|
+
rightArrow.style.display =
|
|
348
|
+
currentIndex < images.length - 1 ? 'flex' : 'none'
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const showImage = (index: number) => {
|
|
352
|
+
if (index < 0 || index >= images.length) return
|
|
353
|
+
currentIndex = index
|
|
354
|
+
scale = 1.0
|
|
355
|
+
rotate = 0
|
|
356
|
+
img.style.transform = `scale(0.95) rotate(0deg)`
|
|
357
|
+
img.style.opacity = '0.5'
|
|
358
|
+
setTimeout(() => {
|
|
359
|
+
img.src = images[currentIndex] || ''
|
|
360
|
+
img.style.transform = `scale(1) rotate(0deg)`
|
|
361
|
+
img.style.opacity = '1'
|
|
362
|
+
}, 150)
|
|
363
|
+
updateArrowsVisibility()
|
|
364
|
+
updateIndicator()
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
leftArrow.addEventListener('click', (e) => {
|
|
368
|
+
e.stopPropagation()
|
|
369
|
+
showImage(currentIndex - 1)
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
rightArrow.addEventListener('click', (e) => {
|
|
373
|
+
e.stopPropagation()
|
|
374
|
+
showImage(currentIndex + 1)
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
// Bottom Container
|
|
378
|
+
const bottomContainer = doc.createElement('div')
|
|
379
|
+
bottomContainer.style.position = 'absolute'
|
|
380
|
+
bottomContainer.style.bottom = '24px'
|
|
381
|
+
bottomContainer.style.left = '50%'
|
|
382
|
+
bottomContainer.style.transform = 'translateX(-50%)'
|
|
383
|
+
bottomContainer.style.display = 'flex'
|
|
384
|
+
bottomContainer.style.flexDirection = 'column'
|
|
385
|
+
bottomContainer.style.alignItems = 'center'
|
|
386
|
+
bottomContainer.style.gap = '12px'
|
|
387
|
+
bottomContainer.style.zIndex = '15'
|
|
388
|
+
|
|
389
|
+
// Image Indicator
|
|
390
|
+
const indicator = doc.createElement('div')
|
|
391
|
+
indicator.style.color = '#ffffff'
|
|
392
|
+
indicator.style.fontSize = '14px'
|
|
393
|
+
indicator.style.fontFamily = 'system-ui, sans-serif'
|
|
394
|
+
indicator.style.fontWeight = '500'
|
|
395
|
+
|
|
396
|
+
const updateIndicator = () => {
|
|
397
|
+
indicator.textContent = `${currentIndex + 1} / ${images.length}`
|
|
398
|
+
}
|
|
399
|
+
updateIndicator()
|
|
400
|
+
updateArrowsVisibility()
|
|
401
|
+
|
|
402
|
+
// Pill Toolbar Container
|
|
403
|
+
const pillToolbar = doc.createElement('div')
|
|
404
|
+
pillToolbar.style.display = 'flex'
|
|
405
|
+
pillToolbar.style.alignItems = 'center'
|
|
406
|
+
pillToolbar.style.gap = '8px'
|
|
407
|
+
pillToolbar.style.padding = '6px 12px'
|
|
408
|
+
pillToolbar.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'
|
|
409
|
+
pillToolbar.style.backdropFilter = 'blur(12px)'
|
|
410
|
+
;(pillToolbar.style as any).webkitBackdropFilter = 'blur(12px)'
|
|
411
|
+
pillToolbar.style.borderRadius = '24px'
|
|
412
|
+
pillToolbar.style.border = '1px solid rgba(255, 255, 255, 0.1)'
|
|
413
|
+
pillToolbar.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.3)'
|
|
414
|
+
|
|
415
|
+
const createPillButton = (
|
|
416
|
+
svgContent: string,
|
|
417
|
+
btnTitle: string,
|
|
418
|
+
onClickHandler: () => void
|
|
419
|
+
) => {
|
|
420
|
+
const btn = doc.createElement('div')
|
|
421
|
+
btn.style.width = '32px'
|
|
422
|
+
btn.style.height = '32px'
|
|
423
|
+
btn.style.borderRadius = '50%'
|
|
424
|
+
btn.style.display = 'flex'
|
|
425
|
+
btn.style.alignItems = 'center'
|
|
426
|
+
btn.style.justifyContent = 'center'
|
|
427
|
+
btn.style.cursor = 'pointer'
|
|
428
|
+
btn.style.color = '#ffffff'
|
|
429
|
+
btn.style.transition = 'background-color 0.2s, transform 0.1s'
|
|
430
|
+
btn.title = btnTitle
|
|
431
|
+
btn.innerHTML = svgContent
|
|
432
|
+
|
|
433
|
+
btn.addEventListener('mouseenter', () => {
|
|
434
|
+
btn.style.backgroundColor = 'rgba(255, 255, 255, 0.15)'
|
|
435
|
+
})
|
|
436
|
+
btn.addEventListener('mouseleave', () => {
|
|
437
|
+
btn.style.backgroundColor = 'transparent'
|
|
438
|
+
})
|
|
439
|
+
btn.addEventListener('click', (e) => {
|
|
440
|
+
e.stopPropagation()
|
|
441
|
+
onClickHandler()
|
|
442
|
+
})
|
|
443
|
+
return btn
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Pill Buttons
|
|
447
|
+
const zoomOutSvg = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`
|
|
448
|
+
const zoomInSvg = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`
|
|
449
|
+
const resetSvg = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"></path></svg>`
|
|
450
|
+
const rotateLeftSvg = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><polyline points="3 3 3 8 8 8"></polyline></svg>`
|
|
451
|
+
const rotateRightSvg = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path><polyline points="21 3 21 8 16 8"></polyline></svg>`
|
|
452
|
+
|
|
453
|
+
const btnZoomOut = createPillButton(zoomOutSvg, '缩小', () => {
|
|
454
|
+
scale = Math.max(0.2, Number((scale - 0.2).toFixed(2)))
|
|
455
|
+
applyTransform()
|
|
456
|
+
})
|
|
457
|
+
const btnZoomIn = createPillButton(zoomInSvg, '放大', () => {
|
|
458
|
+
scale = Math.min(5.0, Number((scale + 0.2).toFixed(2)))
|
|
459
|
+
applyTransform()
|
|
460
|
+
})
|
|
461
|
+
const btnReset = createPillButton(resetSvg, '还原', () => {
|
|
462
|
+
scale = 1.0
|
|
463
|
+
rotate = 0
|
|
464
|
+
applyTransform()
|
|
465
|
+
})
|
|
466
|
+
const btnRotateLeft = createPillButton(rotateLeftSvg, '向左旋转', () => {
|
|
467
|
+
rotate -= 90
|
|
468
|
+
applyTransform()
|
|
469
|
+
})
|
|
470
|
+
const btnRotateRight = createPillButton(
|
|
471
|
+
rotateRightSvg,
|
|
472
|
+
'向右旋转',
|
|
473
|
+
() => {
|
|
474
|
+
rotate += 90
|
|
475
|
+
applyTransform()
|
|
476
|
+
}
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
pillToolbar.appendChild(btnZoomOut)
|
|
480
|
+
pillToolbar.appendChild(btnZoomIn)
|
|
481
|
+
pillToolbar.appendChild(btnReset)
|
|
482
|
+
pillToolbar.appendChild(btnRotateLeft)
|
|
483
|
+
pillToolbar.appendChild(btnRotateRight)
|
|
484
|
+
|
|
485
|
+
bottomContainer.appendChild(indicator)
|
|
486
|
+
bottomContainer.appendChild(pillToolbar)
|
|
487
|
+
|
|
488
|
+
// Close button
|
|
489
|
+
const closeBtn = doc.createElement('div')
|
|
490
|
+
closeBtn.style.position = 'absolute'
|
|
491
|
+
closeBtn.style.top = '24px'
|
|
492
|
+
closeBtn.style.right = '24px'
|
|
493
|
+
closeBtn.style.width = '40px'
|
|
494
|
+
closeBtn.style.height = '40px'
|
|
495
|
+
closeBtn.style.borderRadius = '50%'
|
|
496
|
+
closeBtn.style.color = '#ffffff'
|
|
497
|
+
closeBtn.style.display = 'flex'
|
|
498
|
+
closeBtn.style.alignItems = 'center'
|
|
499
|
+
closeBtn.style.justifyContent = 'center'
|
|
500
|
+
closeBtn.style.cursor = 'pointer'
|
|
501
|
+
closeBtn.style.fontSize = '28px'
|
|
502
|
+
closeBtn.style.transition = 'background-color 0.2s'
|
|
503
|
+
closeBtn.style.zIndex = '15'
|
|
504
|
+
closeBtn.innerHTML = '×'
|
|
505
|
+
closeBtn.addEventListener('mouseenter', () => {
|
|
506
|
+
closeBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.1)'
|
|
507
|
+
})
|
|
508
|
+
closeBtn.addEventListener('mouseleave', () => {
|
|
509
|
+
closeBtn.style.backgroundColor = 'transparent'
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
const closeLightbox = () => {
|
|
513
|
+
doc.removeEventListener('keydown', handleKeyDown)
|
|
514
|
+
overlay.style.opacity = '0'
|
|
515
|
+
overlay.style.transition = 'opacity 0.2s ease-out'
|
|
516
|
+
setTimeout(() => {
|
|
517
|
+
overlay.remove()
|
|
518
|
+
}, 200)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
closeBtn.addEventListener('click', (e) => {
|
|
522
|
+
e.stopPropagation()
|
|
523
|
+
closeLightbox()
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
overlay.addEventListener('click', () => {
|
|
527
|
+
closeLightbox()
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
531
|
+
if (e.key === 'Escape') {
|
|
532
|
+
closeLightbox()
|
|
533
|
+
} else if (e.key === 'ArrowLeft' && currentIndex > 0) {
|
|
534
|
+
showImage(currentIndex - 1)
|
|
535
|
+
} else if (e.key === 'ArrowRight' && currentIndex < images.length - 1) {
|
|
536
|
+
showImage(currentIndex + 1)
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
doc.addEventListener('keydown', handleKeyDown)
|
|
541
|
+
|
|
542
|
+
overlay.appendChild(closeBtn)
|
|
543
|
+
overlay.appendChild(imgContainer)
|
|
544
|
+
overlay.appendChild(bottomContainer)
|
|
545
|
+
|
|
546
|
+
overlay.style.opacity = '0'
|
|
547
|
+
overlay.style.transition = 'opacity 0.2s ease-out'
|
|
548
|
+
doc.body.appendChild(overlay)
|
|
549
|
+
requestAnimationFrame(() => {
|
|
550
|
+
overlay.style.opacity = '1'
|
|
551
|
+
})
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const onImageDoubleClick = (e: MouseEvent) => {
|
|
555
|
+
e.preventDefault()
|
|
556
|
+
e.stopPropagation()
|
|
557
|
+
|
|
558
|
+
const currentImg = imageRef.value
|
|
559
|
+
const currentSrc = currentImg ? currentImg.src : src.value
|
|
560
|
+
|
|
561
|
+
const rootNode =
|
|
562
|
+
(wrapperRef.value?.getRootNode() as Document | ShadowRoot | null) ||
|
|
563
|
+
document
|
|
564
|
+
const allImageElements = rootNode.querySelectorAll('img')
|
|
565
|
+
const images: string[] = []
|
|
566
|
+
allImageElements.forEach((img: any) => {
|
|
567
|
+
// Exclude cover images and header decorations
|
|
568
|
+
if (
|
|
569
|
+
img.closest('.milkdown-document-cover, .milkdown-document-header')
|
|
570
|
+
) {
|
|
571
|
+
return
|
|
572
|
+
}
|
|
573
|
+
if (img.src && !images.includes(img.src)) {
|
|
574
|
+
images.push(img.src)
|
|
575
|
+
}
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
if (images.length === 0 && currentSrc) {
|
|
579
|
+
images.push(currentSrc)
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const startIndex = currentSrc ? images.indexOf(currentSrc) : 0
|
|
583
|
+
openLightbox(images, startIndex >= 0 ? startIndex : 0)
|
|
249
584
|
}
|
|
250
585
|
|
|
251
586
|
const closePanels = () => {
|
|
@@ -525,106 +860,13 @@ export const ImageViewer = defineComponent<MilkdownImageBlockProps>({
|
|
|
525
860
|
) : null}
|
|
526
861
|
{config.borderIcon ? (
|
|
527
862
|
<div
|
|
528
|
-
class=
|
|
863
|
+
class={`image-toolbar-item ${borderStyle.value === 'solid' && (borderWidth.value ?? 0) >= 1 ? 'active' : ''}`}
|
|
529
864
|
title="边框"
|
|
530
|
-
onClick={
|
|
865
|
+
onClick={onToggleBorder}
|
|
531
866
|
>
|
|
532
867
|
<Icon icon={config.borderIcon} />
|
|
533
868
|
</div>
|
|
534
869
|
) : null}
|
|
535
|
-
|
|
536
|
-
{showBorderPanel.value ? (
|
|
537
|
-
<div
|
|
538
|
-
class="setting-panel border-panel"
|
|
539
|
-
draggable="true"
|
|
540
|
-
onClick={(e) => e.stopPropagation()}
|
|
541
|
-
onMousedown={(e) => e.stopPropagation()}
|
|
542
|
-
onPointerdown={(e) => e.stopPropagation()}
|
|
543
|
-
onDragstart={(e) => {
|
|
544
|
-
e.preventDefault()
|
|
545
|
-
e.stopPropagation()
|
|
546
|
-
}}
|
|
547
|
-
>
|
|
548
|
-
<div class="setting-panel-title">{'边框设置'}</div>
|
|
549
|
-
<div class="setting-row">
|
|
550
|
-
<span class="setting-label">{'样式'}</span>
|
|
551
|
-
<div class="border-style-options">
|
|
552
|
-
{borderStyleOptions.map((opt) => (
|
|
553
|
-
<div
|
|
554
|
-
class={`border-style-option ${currentBorderStyle === opt.value ? 'active' : ''}`}
|
|
555
|
-
onClick={(e: MouseEvent) => {
|
|
556
|
-
e.stopPropagation()
|
|
557
|
-
setAttr('borderStyle', opt.value)
|
|
558
|
-
}}
|
|
559
|
-
>
|
|
560
|
-
{opt.label === 'none'
|
|
561
|
-
? '无'
|
|
562
|
-
: opt.label === 'solid'
|
|
563
|
-
? '实线'
|
|
564
|
-
: opt.label === 'dashed'
|
|
565
|
-
? '虚线'
|
|
566
|
-
: '点线'}
|
|
567
|
-
</div>
|
|
568
|
-
))}
|
|
569
|
-
</div>
|
|
570
|
-
</div>
|
|
571
|
-
{currentBorderStyle !== 'none' ? (
|
|
572
|
-
<div class="setting-row">
|
|
573
|
-
<span class="setting-label">{'宽度'}</span>
|
|
574
|
-
<input
|
|
575
|
-
draggable="true"
|
|
576
|
-
type="range"
|
|
577
|
-
min="1"
|
|
578
|
-
max="10"
|
|
579
|
-
value={currentBorderWidth}
|
|
580
|
-
onInput={(e: Event) => {
|
|
581
|
-
const target = e.target as HTMLInputElement
|
|
582
|
-
localBorderWidth.value = Number(target.value)
|
|
583
|
-
}}
|
|
584
|
-
onChange={(e: Event) => {
|
|
585
|
-
const target = e.target as HTMLInputElement
|
|
586
|
-
setAttr('borderWidth', Number(target.value))
|
|
587
|
-
localBorderWidth.value = null
|
|
588
|
-
}}
|
|
589
|
-
onClick={(e: MouseEvent) => e.stopPropagation()}
|
|
590
|
-
onMousedown={(e: MouseEvent) => e.stopPropagation()}
|
|
591
|
-
onPointerdown={(e: PointerEvent) => e.stopPropagation()}
|
|
592
|
-
onDragstart={(e: DragEvent) => {
|
|
593
|
-
e.preventDefault()
|
|
594
|
-
e.stopPropagation()
|
|
595
|
-
}}
|
|
596
|
-
/>
|
|
597
|
-
<span class="setting-value">{currentBorderWidth}px</span>
|
|
598
|
-
</div>
|
|
599
|
-
) : null}
|
|
600
|
-
{currentBorderStyle !== 'none' ? (
|
|
601
|
-
<div class="setting-row">
|
|
602
|
-
<span class="setting-label">{'颜色'}</span>
|
|
603
|
-
<input
|
|
604
|
-
draggable="true"
|
|
605
|
-
type="color"
|
|
606
|
-
value={currentBorderColor}
|
|
607
|
-
onInput={(e: Event) => {
|
|
608
|
-
const target = e.target as HTMLInputElement
|
|
609
|
-
localBorderColor.value = target.value
|
|
610
|
-
}}
|
|
611
|
-
onChange={(e: Event) => {
|
|
612
|
-
const target = e.target as HTMLInputElement
|
|
613
|
-
setAttr('borderColor', target.value)
|
|
614
|
-
localBorderColor.value = null
|
|
615
|
-
}}
|
|
616
|
-
onClick={(e: MouseEvent) => e.stopPropagation()}
|
|
617
|
-
onMousedown={(e: MouseEvent) => e.stopPropagation()}
|
|
618
|
-
onPointerdown={(e: PointerEvent) => e.stopPropagation()}
|
|
619
|
-
onDragstart={(e: DragEvent) => {
|
|
620
|
-
e.preventDefault()
|
|
621
|
-
e.stopPropagation()
|
|
622
|
-
}}
|
|
623
|
-
/>
|
|
624
|
-
</div>
|
|
625
|
-
) : null}
|
|
626
|
-
</div>
|
|
627
|
-
) : null}
|
|
628
870
|
</div>
|
|
629
871
|
) : null}
|
|
630
872
|
|
|
@@ -633,6 +875,7 @@ export const ImageViewer = defineComponent<MilkdownImageBlockProps>({
|
|
|
633
875
|
ref={wrapperRef}
|
|
634
876
|
style={wrapperStyle}
|
|
635
877
|
onClick={closePanels}
|
|
878
|
+
onDblclick={onImageDoubleClick}
|
|
636
879
|
>
|
|
637
880
|
{cropClipStyle ? (
|
|
638
881
|
<div class="crop-clip" style={cropClipStyle}>
|