Initial rearrangment of vuetom site source
This commit is contained in:
60
packages/vuetom/blog/composables/flyout.ts
Normal file
60
packages/vuetom/blog/composables/flyout.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import {
|
||||
Ref, ref, watch, readonly, onUnmounted
|
||||
} from 'vue'
|
||||
|
||||
interface UseFlyoutOptions {
|
||||
el: Ref<HTMLElement | undefined>
|
||||
onFocus?(): void
|
||||
onBlur?(): void
|
||||
}
|
||||
|
||||
export const focusedElement = ref<HTMLElement>()
|
||||
|
||||
let active = false
|
||||
let listeners = 0
|
||||
|
||||
export function useFlyout(options: UseFlyoutOptions) {
|
||||
const focus = ref(false)
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
!active && activateFocusTracking()
|
||||
|
||||
listeners++
|
||||
|
||||
const unwatch = watch(focusedElement, (el) => {
|
||||
if (el === options.el.value || options.el.value?.contains(el as Node)) {
|
||||
focus.value = true
|
||||
options.onFocus?.()
|
||||
} else {
|
||||
focus.value = false
|
||||
options.onBlur?.()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
unwatch()
|
||||
|
||||
listeners--
|
||||
|
||||
if (!listeners) {
|
||||
deactivateFocusTracking()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return readonly(focus)
|
||||
}
|
||||
|
||||
function activateFocusTracking() {
|
||||
document.addEventListener('focusin', handleFocusIn)
|
||||
active = true
|
||||
focusedElement.value = document.activeElement as HTMLElement
|
||||
}
|
||||
|
||||
function deactivateFocusTracking() {
|
||||
document.removeEventListener('focusin', handleFocusIn)
|
||||
}
|
||||
|
||||
function handleFocusIn() {
|
||||
focusedElement.value = document.activeElement as HTMLElement
|
||||
}
|
77
packages/vuetom/blog/composables/homebg.ts
Normal file
77
packages/vuetom/blog/composables/homebg.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
export function useHomeBg() {
|
||||
const { site, theme } = useData()
|
||||
const { base } = site.value
|
||||
const {
|
||||
logoImg, bgImg
|
||||
} = theme.value
|
||||
let { bgColor, flashColor, bgOpacity } = theme.value
|
||||
let baseUrl = base
|
||||
let bgStyle = ''
|
||||
let bgImgSrc = ''
|
||||
let bgInnerOpacity = 0.3
|
||||
// let ftStyle = 'rgba(255,255,255,0.8)'
|
||||
|
||||
if (base === '/' || base.endsWith('/')) {
|
||||
baseUrl = base.substring(0, base.length - 1)
|
||||
}
|
||||
|
||||
// hero logo
|
||||
const homeLogoSrc = `${baseUrl}/${logoImg}`.replaceAll('//', '/')
|
||||
|
||||
// feat color check
|
||||
// if (typeof featuresColor === 'string') {
|
||||
// ftStyle = featuresColor
|
||||
// } else if (typeof featuresColor === 'object') {
|
||||
// if (featuresColor.length >= 2) {
|
||||
// ftStyle = `
|
||||
// linear-gradient(to right,
|
||||
// ${featuresColor[0]},
|
||||
// ${featuresColor[1]}
|
||||
// )
|
||||
// `
|
||||
// }
|
||||
// }
|
||||
|
||||
// 背景色默认黑色
|
||||
if (bgColor === undefined) bgColor = '0,0,0'
|
||||
// 背景图透明度
|
||||
if (bgOpacity === undefined) bgOpacity = 0
|
||||
if (flashColor === undefined) flashColor = ['0,0,0', '0,0,0']
|
||||
if (typeof flashColor === 'string') flashColor = [flashColor, flashColor]
|
||||
|
||||
if (bgImg) {
|
||||
bgImgSrc = `${baseUrl}/${bgImg}`.replaceAll('//', '/')
|
||||
bgInnerOpacity = bgOpacity - 0.3 <= 0 ? 0 : bgOpacity - 0.3
|
||||
bgStyle = `
|
||||
-webkit-linear-gradient(top,
|
||||
rgba(${bgColor},${bgOpacity}) 0%,
|
||||
rgba(${bgColor},${bgInnerOpacity}) 20%,
|
||||
rgba(${bgColor},${bgInnerOpacity}) 80%,
|
||||
rgba(${bgColor},${bgOpacity}) 100%
|
||||
),
|
||||
-webkit-linear-gradient(left,
|
||||
rgba(${bgColor},${bgOpacity}) 0%,
|
||||
rgba(${bgColor},${bgInnerOpacity}) 20%,
|
||||
rgba(${bgColor},${bgInnerOpacity}) 80%,
|
||||
rgba(${bgColor},${bgOpacity}) 100%),
|
||||
url(${bgImgSrc})
|
||||
`
|
||||
}
|
||||
|
||||
return {
|
||||
homeLogoSrc,
|
||||
bgStyle,
|
||||
bgImgSrc
|
||||
}
|
||||
}
|
||||
|
||||
export function useHomeParallax() {
|
||||
const { theme } = useData()
|
||||
// const { base } = site.value
|
||||
const { parallaxEnable } = theme.value
|
||||
return {
|
||||
parallaxEnable
|
||||
}
|
||||
}
|
69
packages/vuetom/blog/composables/nav.ts
Normal file
69
packages/vuetom/blog/composables/nav.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import type { DefaultTheme } from 'vitepress/theme'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useData, useRoute } from 'vitepress'
|
||||
|
||||
export function useNav() {
|
||||
const isScreenOpen = ref(false)
|
||||
|
||||
function openScreen() {
|
||||
isScreenOpen.value = true
|
||||
window.addEventListener('resize', closeScreenOnTabletWindow)
|
||||
}
|
||||
|
||||
function closeScreen() {
|
||||
isScreenOpen.value = false
|
||||
window.removeEventListener('resize', closeScreenOnTabletWindow)
|
||||
}
|
||||
|
||||
function toggleScreen() {
|
||||
isScreenOpen.value ? closeScreen() : openScreen()
|
||||
}
|
||||
|
||||
/**
|
||||
* Close screen when the user resizes the window wider than tablet size.
|
||||
*/
|
||||
function closeScreenOnTabletWindow() {
|
||||
window.outerWidth >= 768 && closeScreen()
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
watch(() => route.path, closeScreen)
|
||||
|
||||
return {
|
||||
isScreenOpen,
|
||||
openScreen,
|
||||
closeScreen,
|
||||
toggleScreen
|
||||
}
|
||||
}
|
||||
|
||||
export function useLanguageLinks() {
|
||||
const { site, localePath, theme } = useData()
|
||||
|
||||
return computed(() => {
|
||||
const { langs } = site.value
|
||||
const localePaths = Object.keys(langs)
|
||||
|
||||
// one language
|
||||
if (localePaths.length < 2) {
|
||||
return null
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// intentionally remove the leading slash because each locale has one
|
||||
const currentPath = route.path.replace(localePath.value, '')
|
||||
|
||||
const candidates = localePaths.map((localePath) => ({
|
||||
text: langs[localePath].label,
|
||||
link: `${localePath}${currentPath}`
|
||||
}))
|
||||
|
||||
const selectText = theme.value.selectText || 'Languages'
|
||||
|
||||
return {
|
||||
text: selectText,
|
||||
items: candidates
|
||||
} as DefaultTheme.NavItemWithChildren
|
||||
})
|
||||
}
|
77
packages/vuetom/blog/composables/sidebar.ts
Normal file
77
packages/vuetom/blog/composables/sidebar.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
computed, onMounted, onUnmounted, Ref, ref, watchEffect
|
||||
} from 'vue'
|
||||
import { useData, useRoute } from 'vitepress'
|
||||
import { getSidebar } from '../support/sidebar.js'
|
||||
|
||||
export function useSidebar() {
|
||||
const route = useRoute()
|
||||
const { theme, frontmatter } = useData()
|
||||
|
||||
const isOpen = ref(false)
|
||||
|
||||
const sidebar = computed(() => {
|
||||
const sidebarConfig = theme.value.sidebar
|
||||
return sidebarConfig ? getSidebar(sidebarConfig, route.path) : []
|
||||
})
|
||||
|
||||
const hasSidebar = computed(() => (
|
||||
frontmatter.value.sidebar !== false
|
||||
&& sidebar.value.length > 0
|
||||
&& frontmatter.value.layout !== 'home'
|
||||
&& frontmatter.value.layout !== 'doc'
|
||||
))
|
||||
|
||||
function open() {
|
||||
isOpen.value = true
|
||||
}
|
||||
|
||||
function close() {
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
isOpen.value ? close() : open()
|
||||
}
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
sidebar,
|
||||
hasSidebar,
|
||||
open,
|
||||
close,
|
||||
toggle
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a11y: cache the element that opened the Sidebar (the menu button) then
|
||||
* focus that button again when Menu is closed with Escape key.
|
||||
*/
|
||||
export function useCloseSidebarOnEscape(
|
||||
isOpen: Ref<boolean>,
|
||||
close: () => void
|
||||
) {
|
||||
let triggerElement: HTMLButtonElement | undefined
|
||||
|
||||
watchEffect(() => {
|
||||
triggerElement = isOpen.value
|
||||
? (document.activeElement as HTMLButtonElement)
|
||||
: undefined
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keyup', onEscape)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keyup', onEscape)
|
||||
})
|
||||
|
||||
function onEscape(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape' && isOpen.value) {
|
||||
close()
|
||||
triggerElement?.focus()
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user