|
1 | 1 | <script setup lang="ts"> |
2 | 2 | // Framework |
3 | | - import { useBreakpoints } from '@vuetify/v0' |
| 3 | + import { IN_BROWSER, Scrim, useBreakpoints, useStack } from '@vuetify/v0' |
4 | 4 |
|
5 | 5 | // Composables |
6 | 6 | import { useAsk } from '@/composables/useAsk' |
7 | 7 | import { useDiscovery } from '@/composables/useDiscovery' |
8 | 8 | import { createLevelFilter } from '@/composables/useLevelFilter' |
9 | 9 | import { createNavConfig } from '@/composables/useNavConfig' |
10 | | - import { useNavigation } from '@/composables/useNavigation' |
11 | | - import { useScrollLock } from '@/composables/useScrollLock' |
12 | 10 | import { useSearch } from '@/composables/useSearch' |
13 | 11 | import { useSettings } from '@/composables/useSettings' |
14 | 12 |
|
15 | 13 | // Utilities |
16 | | - import { computed, defineAsyncComponent, toRef, watch } from 'vue' |
| 14 | + import { computed, defineAsyncComponent, onScopeDispose, toRef, watch } from 'vue' |
17 | 15 |
|
18 | 16 | // Stores |
19 | 17 | import { useAppStore } from '@/stores/app' |
|
33 | 31 | const breakpoints = useBreakpoints() |
34 | 32 | const discovery = useDiscovery() |
35 | 33 | const ask = useAsk() |
36 | | - const navigation = useNavigation() |
37 | 34 | const search = useSearch() |
38 | 35 | const settings = useSettings() |
| 36 | + const stack = useStack() |
39 | 37 |
|
40 | 38 | // Force reduced motion during tours so elements don't animate |
41 | 39 | watch(() => discovery.isActive.value, active => { |
42 | 40 | settings.forceReducedMotion.value = active |
43 | 41 | }) |
44 | 42 |
|
45 | | - const fadeTransition = toRef(() => settings.prefersReducedMotion.value ? undefined : 'fade') |
46 | 43 | const slideTransition = toRef(() => settings.prefersReducedMotion.value ? undefined : 'slide') |
47 | 44 |
|
48 | 45 | const isModalOpen = computed(() => { |
|
52 | 49 | return false |
53 | 50 | }) |
54 | 51 |
|
55 | | - const isMobileNavOpen = toRef(() => navigation.isOpen.value && !breakpoints.mdAndUp.value) |
| 52 | + // Unified scroll lock via stack |
| 53 | + watch(() => stack.isActive.value, active => { |
| 54 | + if (!IN_BROWSER) return |
| 55 | + document.body.style.overflow = active ? 'hidden' : '' |
| 56 | + }, { immediate: true }) |
56 | 57 |
|
57 | | - useScrollLock(settings.isOpen) |
58 | | - useScrollLock(isMobileNavOpen) |
| 58 | + onScopeDispose(() => { |
| 59 | + if (!IN_BROWSER) return |
| 60 | + document.body.style.overflow = '' |
| 61 | + }) |
59 | 62 | </script> |
60 | 63 |
|
61 | 64 | <template> |
|
79 | 82 |
|
80 | 83 | <DocsSearch /> |
81 | 84 |
|
82 | | - <!-- Mobile nav backdrop --> |
83 | | - <Transition :name="fadeTransition"> |
84 | | - <div |
85 | | - v-if="isMobileNavOpen" |
86 | | - class="fixed inset-0 bg-black/30 z-9" |
87 | | - @click="navigation.close()" |
88 | | - /> |
89 | | - </Transition> |
90 | | - |
91 | | - <!-- Settings backdrop --> |
92 | | - <Transition :name="fadeTransition"> |
93 | | - <div |
94 | | - v-if="settings.isOpen.value" |
95 | | - class="fixed inset-0 bg-black/30 z-40" |
96 | | - @click="settings.close" |
97 | | - /> |
98 | | - </Transition> |
| 85 | + <!-- Unified scrim for all overlays (teleport disabled to share stacking context) --> |
| 86 | + <Scrim class="fixed inset-0 bg-black/30 transition-opacity" :teleport="false" /> |
99 | 87 |
|
100 | 88 | <!-- Settings sheet --> |
101 | 89 | <Transition :name="slideTransition"> |
|
0 commit comments