11import DefaultTheme from 'vitepress/theme'
2- import { defineComponent , h , onMounted , watch } from 'vue'
2+ import { defineComponent , h , nextTick , onMounted , watch } from 'vue'
33import type { Theme } from 'vitepress'
44import { useRoute } from 'vitepress'
55import MermaidDiagram from './MermaidDiagram.vue'
@@ -61,6 +61,75 @@ async function writeClipboard(value: string) {
6161 }
6262}
6363
64+
65+ function openDiagramLightbox ( source : Element ) {
66+ const existing = document . querySelector ( '.ac-lightbox' )
67+ if ( existing ) existing . remove ( )
68+
69+ const overlay = document . createElement ( 'div' )
70+ overlay . className = 'ac-lightbox'
71+ overlay . setAttribute ( 'role' , 'dialog' )
72+ overlay . setAttribute ( 'aria-modal' , 'true' )
73+
74+ const stage = document . createElement ( 'div' )
75+ stage . className = 'ac-lightbox__stage'
76+
77+ const close = document . createElement ( 'button' )
78+ close . className = 'ac-lightbox__close'
79+ close . type = 'button'
80+ close . textContent = '关闭'
81+
82+ const hint = document . createElement ( 'div' )
83+ hint . className = 'ac-lightbox__hint'
84+ hint . textContent = '滚动查看大图,按 Esc 关闭'
85+
86+ const clone = source . cloneNode ( true ) as Element
87+ clone . removeAttribute ( 'id' )
88+ stage . appendChild ( clone )
89+ overlay . append ( close , stage , hint )
90+ document . body . appendChild ( overlay )
91+ document . body . style . overflow = 'hidden'
92+
93+ const cleanup = ( ) => {
94+ document . body . style . overflow = ''
95+ document . removeEventListener ( 'keydown' , onKeydown )
96+ overlay . remove ( )
97+ }
98+
99+ const onKeydown = ( event : KeyboardEvent ) => {
100+ if ( event . key === 'Escape' ) cleanup ( )
101+ }
102+
103+ close . addEventListener ( 'click' , cleanup )
104+ overlay . addEventListener ( 'click' , ( event ) => {
105+ if ( event . target === overlay ) cleanup ( )
106+ } )
107+ document . addEventListener ( 'keydown' , onKeydown )
108+ }
109+
110+ function installDiagramLightbox ( ) {
111+ const targets = [
112+ ...document . querySelectorAll ( '.ac-mermaid__canvas svg' ) ,
113+ ...document . querySelectorAll ( 'img[src$="harness-engine-shift.svg"]' )
114+ ]
115+
116+ for ( const target of targets ) {
117+ const element = target as HTMLElement
118+ if ( element . dataset . lightboxReady === 'true' ) continue
119+ element . dataset . lightboxReady = 'true'
120+ element . tabIndex = 0
121+ element . setAttribute ( 'role' , 'button' )
122+ element . setAttribute ( 'aria-label' , '点击放大图表' )
123+ element . addEventListener ( 'click' , ( ) => openDiagramLightbox ( element ) )
124+ element . addEventListener ( 'keydown' , ( event ) => {
125+ if ( event . key === 'Enter' || event . key === ' ' ) {
126+ event . preventDefault ( )
127+ openDiagramLightbox ( element )
128+ }
129+ } )
130+ }
131+ }
132+
64133const CopyMarkdownButton = defineComponent ( {
65134 name : 'CopyMarkdownButton' ,
66135 setup ( ) {
@@ -70,6 +139,12 @@ const CopyMarkdownButton = defineComponent({
70139 const update = ( ) => {
71140 const existing = document . querySelector < HTMLButtonElement > ( '.ac-copy-md' )
72141 if ( existing ) existing . dataset . path = route . path
142+ const scheduleInstall = ( ) => {
143+ installDiagramLightbox ( )
144+ window . setTimeout ( installDiagramLightbox , 300 )
145+ window . setTimeout ( installDiagramLightbox , 1000 )
146+ }
147+ nextTick ( scheduleInstall )
73148 }
74149 update ( )
75150 watch ( ( ) => route . path , update )
0 commit comments