diff --git a/docs/.vitepress/components/DocCommunity.vue b/docs/.vitepress/components/DocCommunity.vue index 7a987db58..af046fc51 100644 --- a/docs/.vitepress/components/DocCommunity.vue +++ b/docs/.vitepress/components/DocCommunity.vue @@ -34,12 +34,12 @@ const links = computed(() => [ transition-colors duration-200 ease-in-out > {{ link.label }} diff --git a/docs/.vitepress/components/DocTopbar.vue b/docs/.vitepress/components/DocTopbar.vue index 14ba8cb44..207b2339d 100644 --- a/docs/.vitepress/components/DocTopbar.vue +++ b/docs/.vitepress/components/DocTopbar.vue @@ -6,7 +6,6 @@ import { useScroll } from '@vueuse/core' import { DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger } from 'reka-ui' import { useData, useRoute, withBase } from 'vitepress' import { computed, ref, toRefs, watch } from 'vue' -import { useI18n } from 'vue-i18n' import DocSidebarItem from '../components/DocSidebarItem.vue' @@ -14,7 +13,6 @@ import { flatten } from '../utils/flatten' const { path } = toRefs(useRoute()) const { page, theme } = useData() -const { t } = useI18n() const isSidebarOpen = ref(false) const sidebar = computed(() => (theme.value.sidebar as (DefaultTheme.SidebarItem & { icon?: string })[])) @@ -24,17 +22,18 @@ const sectionTabs = computed(() => sidebar.value return { label: val.text, link: flatten(val.items ?? [], 'items').filter(i => !!i?.link)?.[0]?.link ?? val.link, + // Highlight by the section's own link; tab.link points at the first + // child page and would narrow the highlight to it. + highlight: val.link, icon: val.icon, } }) .filter(i => !!i?.link), ) -function isCharacterPage(link?: string) { - if (!link) - return false - - return link.includes('/characters') || link.includes('/characters/') +function isTabActive(tab: { link?: string, highlight?: string }): boolean { + const prefix = (tab.highlight ?? tab.link)?.split('/').slice(0, -1).join('/') ?? '' + return withBase(`/${page.value.relativePath}`).includes(prefix) } const { arrivedState } = useScroll(globalThis.window) @@ -55,28 +54,10 @@ watch(path, () => {
- - {{ tab.label }} - -
- - diff --git a/docs/.vitepress/components/Home.vue b/docs/.vitepress/components/Home.vue index 9b7596a80..a4e547dc2 100644 --- a/docs/.vitepress/components/Home.vue +++ b/docs/.vitepress/components/Home.vue @@ -192,8 +192,12 @@ const buttons = computed(() => theme.value.homepage?.buttons || []) diff --git a/docs/.vitepress/components/Navbar.vue b/docs/.vitepress/components/Navbar.vue index 49973944e..bb3f3f946 100644 --- a/docs/.vitepress/components/Navbar.vue +++ b/docs/.vitepress/components/Navbar.vue @@ -1,5 +1,6 @@ diff --git a/docs/.vitepress/components/ThemeToggle.vue b/docs/.vitepress/components/ThemeToggle.vue index 9bdf7c0f6..54cfa19af 100644 --- a/docs/.vitepress/components/ThemeToggle.vue +++ b/docs/.vitepress/components/ThemeToggle.vue @@ -4,6 +4,12 @@ import { SwitchRoot, SwitchThumb } from 'reka-ui' import { useData } from 'vitepress' import { ref, watchPostEffect } from 'vue' +defineOptions({ + // DropdownMenuItem as-child passes item attrs here; ClientOnly (fragment) + // can't inherit them, so bind $attrs onto SwitchRoot manually. + inheritAttrs: false, +}) + const { isDark } = useData() const switchTitle = ref('') @@ -13,15 +19,35 @@ watchPostEffect(() => { ? 'Switch to light theme' : 'Switch to dark theme' }) + +/** + * Wraps the theme switch in a View Transition so the browser cross-fades the + * whole page snapshots, keeping every element in sync. Falls back to an + * instant switch where `startViewTransition` is unsupported (e.g. Firefox). + */ +function onToggle(value: boolean) { + if (value === isDark.value) + return + if (typeof document !== 'undefined' && 'startViewTransition' in document) { + document.startViewTransition(() => { + isDark.value = value + }) + } + else { + isDark.value = value + } +}