test/node_modules/@vuepress/theme-default/lib/client/components/VPNavbar.vue
2024-08-13 09:27:52 +08:00

126 lines
3.2 KiB
Vue

<script setup lang="ts">
import { useThemeLocaleData } from '@theme/useThemeData'
import { DeviceType, useUpdateDeviceStatus } from '@theme/useUpdateDeviceStatus'
import VPNavbarBrand from '@theme/VPNavbarBrand.vue'
import VPNavbarItems from '@theme/VPNavbarItems.vue'
import VPToggleColorModeButton from '@theme/VPToggleColorModeButton.vue'
import VPToggleSidebarButton from '@theme/VPToggleSidebarButton.vue'
import { computed, ref } from 'vue'
defineEmits<(e: 'toggle-sidebar') => void>()
defineSlots<{
before?: (props: Record<never, never>) => any
after?: (props: Record<never, never>) => any
}>()
const themeLocale = useThemeLocaleData()
const navbar = ref<HTMLElement | null>(null)
const navbarBrand = ref<HTMLElement | null>(null)
const linksWrapperMaxWidth = ref(0)
const linksWrapperStyle = computed(() => {
if (!linksWrapperMaxWidth.value) {
return {}
}
return {
maxWidth: linksWrapperMaxWidth.value + 'px',
}
})
const getCssValue = (el: HTMLElement | null, property: string): number => {
// NOTE: Known bug, will return 'auto' if style value is 'auto'
const val = el?.ownerDocument?.defaultView?.getComputedStyle(el, null)?.[
property
]
const num = Number.parseInt(val, 10)
return Number.isNaN(num) ? 0 : num
}
useUpdateDeviceStatus(
DeviceType.MOBILE,
(mobileDesktopBreakpoint: number): void => {
// avoid overlapping of long title and long navbar links
const navbarHorizontalPadding =
getCssValue(navbar.value, 'paddingLeft') +
getCssValue(navbar.value, 'paddingRight')
if (window.innerWidth < mobileDesktopBreakpoint) {
linksWrapperMaxWidth.value = 0
} else {
linksWrapperMaxWidth.value =
navbar.value!.offsetWidth -
navbarHorizontalPadding -
(navbarBrand.value?.offsetWidth || 0)
}
},
)
</script>
<template>
<header ref="navbar" class="vp-navbar">
<VPToggleSidebarButton @toggle="$emit('toggle-sidebar')" />
<span ref="navbarBrand">
<VPNavbarBrand />
</span>
<div class="vp-navbar-items-wrapper" :style="linksWrapperStyle">
<slot name="before" />
<VPNavbarItems class="vp-hide-mobile" />
<slot name="after" />
<VPToggleColorModeButton v-if="themeLocale.colorModeSwitch" />
<VPSearch />
</div>
</header>
</template>
<style lang="scss">
@import '../styles/variables';
.vp-navbar {
--navbar-line-height: calc(
var(--navbar-height) - 2 * var(--navbar-padding-v)
);
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: 20;
box-sizing: border-box;
height: var(--navbar-height);
padding: var(--navbar-padding-v) var(--navbar-padding-h);
border-bottom: 1px solid var(--c-border);
background-color: var(--c-bg-navbar);
line-height: var(--navbar-line-height);
transition:
background-color var(--t-color),
border-color var(--t-color);
@media screen and (max-width: $MQMobile) {
padding-left: 4rem;
}
}
.vp-navbar-items-wrapper {
position: absolute;
top: var(--navbar-padding-v);
right: var(--navbar-padding-h);
display: flex;
box-sizing: border-box;
height: var(--navbar-line-height);
padding-left: var(--navbar-padding-h);
font-size: 0.9rem;
white-space: nowrap;
}
</style>