11<script setup lang="ts">
2+ import { ref } from ' vue' ;
23import { usePdfiumEngine } from ' @embedpdf/engines/vue' ;
34import { EmbedPDF } from ' @embedpdf/core/vue' ;
45import { createPluginRegistration , PluginRegistry } from ' @embedpdf/core' ;
@@ -32,34 +33,35 @@ import {
3233import type { AnnotationTool } from ' @embedpdf/plugin-annotation/vue' ;
3334import { PdfAnnotationSubtype } from ' @embedpdf/models' ;
3435import type { PdfStampAnnoObject } from ' @embedpdf/models' ;
35-
3636import Toolbar from ' ./Toolbar.vue' ;
37- import DrawerProvider from ' ./drawer-system/DrawerProvider.vue' ;
38- import Drawer from ' ./drawer-system/Drawer.vue' ;
39- import Search from ' ./Search.vue' ;
40- import Sidebar from ' ./Sidebar.vue' ;
4137import PageControls from ' ./PageControls.vue' ;
4238import RedactionSelectionMenu from ' ./RedactionSelectionMenu.vue' ;
4339import AnnotationSelectionMenu from ' ./AnnotationSelectionMenu.vue' ;
4440
45- // Define drawer components
46- const drawerComponents = [
47- {
48- id: ' search' ,
49- component: Search ,
50- icon: ' mdi-magnify' ,
51- label: ' Search' ,
52- position: ' right' as const ,
53- },
54- {
55- id: ' sidebar' ,
56- component: Sidebar ,
57- icon: ' mdi-dock-left' ,
58- label: ' Sidebar' ,
59- position: ' left' as const ,
60- },
61- ];
41+ import Search from ' ./Search.vue' ;
42+ import Sidebar from ' ./Sidebar.vue' ;
43+
44+ const leftDrawerOpen = ref (false );
45+ const rightDrawerOpen = ref (false );
6246
47+ const toggleLeftDrawer = () => {
48+ leftDrawerOpen .value = ! leftDrawerOpen .value ;
49+ if (leftDrawerOpen .value && rightDrawerOpen .value ) {
50+ rightDrawerOpen .value = false ;
51+ }
52+ };
53+
54+ const toggleRightDrawer = () => {
55+ rightDrawerOpen .value = ! rightDrawerOpen .value ;
56+ if (leftDrawerOpen .value && rightDrawerOpen .value ) {
57+ leftDrawerOpen .value = false ;
58+ }
59+ };
60+
61+ const closeDrawers = () => {
62+ leftDrawerOpen .value = false ;
63+ rightDrawerOpen .value = false ;
64+ };
6365const { engine, isLoading : engineLoading, error : engineError } = usePdfiumEngine ();
6466
6567const handleInitialized = async (registry : PluginRegistry ) => {
@@ -99,11 +101,12 @@ const handleInitialized = async (registry: PluginRegistry) => {
99101 </div >
100102
101103 <!-- Main application -->
102- <div v-else-if =" engine" class =" fit" >
103- <EmbedPDF
104- :engine =" engine"
105- :on-initialized =" handleInitialized"
106- :plugins =" [
104+ <div v-else-if =" engine" class =" application__root" >
105+ <div class =" application__embed" >
106+ <EmbedPDF
107+ :engine =" engine"
108+ :on-initialized =" handleInitialized"
109+ :plugins =" [
107110 createPluginRegistration(LoaderPluginPackage, {
108111 loadingOptions: {
109112 type: 'url',
@@ -149,17 +152,27 @@ const handleInitialized = async (registry: PluginRegistry) => {
149152 createPluginRegistration(RedactionPluginPackage),
150153 createPluginRegistration(AnnotationPluginPackage),
151154 ]"
152- >
153- <template #default =" { pluginsReady } " >
154- <DrawerProvider :components =" drawerComponents" >
155- <q-layout view =" hHh Lpr fFf" class =" application__layout" >
156- <Toolbar />
155+ >
156+ <template #default =" { pluginsReady } " >
157+ <div class =" application__shell" >
158+ <Toolbar
159+ :left-drawer-open =" leftDrawerOpen"
160+ :right-drawer-open =" rightDrawerOpen"
161+ @toggle-left-drawer =" toggleLeftDrawer"
162+ @toggle-right-drawer =" toggleRightDrawer"
163+ />
157164
158- <Drawer position =" left" />
165+ <div class =" application__body" >
166+ <aside
167+ class =" application__drawer application__drawer--left"
168+ :class =" { 'is-open': leftDrawerOpen }"
169+ aria-hidden =" true"
170+ >
171+ <Sidebar />
172+ </aside >
159173
160- <q-page-container class =" application__page-container" >
161- <q-page class =" application__page q-pa-none" >
162- <GlobalPointerProvider >
174+ <div class =" application__main" >
175+ <GlobalPointerProvider class =" application__pointer-provider" >
163176 <Viewport class =" application__viewport" >
164177 <div
165178 v-if =" !pluginsReady"
@@ -219,7 +232,9 @@ const handleInitialized = async (registry: PluginRegistry) => {
219232 :scale =" page.scale"
220233 :rotation =" page.rotation"
221234 >
222- <template #selection-menu =" { item , selected , menuWrapperProps , rect } " >
235+ <template
236+ #selection-menu =" { item , selected , menuWrapperProps , rect } "
237+ >
223238 <RedactionSelectionMenu
224239 v-if =" selected"
225240 :item =" item"
@@ -237,14 +252,28 @@ const handleInitialized = async (registry: PluginRegistry) => {
237252 <PageControls />
238253 </Viewport >
239254 </GlobalPointerProvider >
240- </q-page >
241- </q-page-container >
242-
243- <Drawer position =" right" />
244- </q-layout >
245- </DrawerProvider >
246- </template >
247- </EmbedPDF >
255+ </div >
256+
257+ <aside
258+ class =" application__drawer application__drawer--right"
259+ :class =" { 'is-open': rightDrawerOpen }"
260+ aria-hidden =" true"
261+ >
262+ <Search />
263+ </aside >
264+
265+ <button
266+ v-if =" leftDrawerOpen || rightDrawerOpen"
267+ type =" button"
268+ class =" application__drawer-overlay"
269+ aria-label =" Close drawers"
270+ @click =" closeDrawers"
271+ />
272+ </div >
273+ </div >
274+ </template >
275+ </EmbedPDF >
276+ </div >
248277 </div >
249278
250279 <!-- Engine not ready state -->
@@ -257,20 +286,95 @@ const handleInitialized = async (registry: PluginRegistry) => {
257286<style scoped>
258287.application {
259288 user-select : none ;
289+ height : 100vh ;
290+ display : flex ;
291+ flex-direction : column ;
292+ min-height : 0 ;
260293}
261294
262- .application__layout {
263- background-color : #f5f5f5 ;
295+ .application__root {
296+ flex : 1 1 auto ;
297+ min-height : 0 ;
298+ display : flex ;
299+ height : 100% ;
264300}
265301
266- .application__page-container ,
267- .application__page {
302+ .application__embed {
303+ flex : 1 1 auto ;
304+ min-height : 0 ;
305+ display : flex ;
268306 height : 100% ;
269307}
270308
271- .application__viewport {
309+ .application__shell {
310+ flex : 1 1 auto ;
311+ min-height : 0 ;
312+ display : flex ;
313+ flex-direction : column ;
272314 height : 100% ;
273315 background-color : #f5f5f5 ;
316+ }
317+
318+ .application__body {
319+ flex : 1 1 auto ;
320+ min-height : 0 ;
321+ display : flex ;
322+ position : relative ;
323+ overflow : hidden ;
324+ }
325+
326+ .application__drawer {
327+ width : 300px ;
328+ flex : 0 0 auto ;
329+ background-color : #ffffff ;
330+ border-right : 1px solid var (--q-color-grey-4 );
331+ overflow : auto ;
332+ transform : translateX (-100% );
333+ transition : transform 0.2s ease ;
334+ z-index : 2 ;
335+ }
336+
337+ .application__drawer--right {
338+ border-right : none ;
339+ border-left : 1px solid var (--q-color-grey-4 );
340+ transform : translateX (100% );
341+ }
342+
343+ .application__drawer.is-open {
344+ transform : translateX (0 );
345+ }
346+
347+ .application__drawer-overlay {
348+ position : absolute ;
349+ inset : 0 ;
350+ background : rgba (0 , 0 , 0 , 0.25 );
351+ border : none ;
352+ padding : 0 ;
353+ margin : 0 ;
354+ cursor : pointer ;
355+ z-index : 1 ;
356+ }
357+
358+ .application__drawer-overlay :focus {
359+ outline : 2px solid var (--q-color-primary );
360+ }
361+
362+ .application__main {
363+ flex : 1 1 auto ;
364+ min-height : 0 ;
365+ display : flex ;
366+ }
367+
368+ .application__pointer-provider {
369+ flex : 1 1 auto ;
370+ min-height : 0 ;
371+ display : flex ;
372+ }
373+
374+ .application__viewport {
375+ flex : 1 1 auto ;
376+ min-height : 0 ;
377+ background-color : #f5f5f5 ;
274378 overflow : auto ;
275379 position : relative ;
276380}
0 commit comments