Initial rearrangment of vuetom site source

This commit is contained in:
2024-10-09 08:23:08 +00:00
parent dbd456a517
commit e9d08bd263
233 changed files with 22841 additions and 1 deletions

View File

@@ -0,0 +1,10 @@
<template>
<main
class="page">
<div class="container">
<slot name="top" />
<Content class="content" />
<slot name="bottom" />
</div>
</main>
</template>

View File

@@ -0,0 +1,126 @@
<script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import docsearch from '@docsearch/js'
import { onMounted } from 'vue'
import { useRouter, useRoute, useData } from 'vitepress'
const router = useRouter()
const route = useRoute()
const { theme } = useData()
onMounted(() => {
initialize(theme.value.algolia)
setTimeout(poll, 16)
})
function poll() {
// programmatically open the search box after initialize
const e = new Event('keydown') as any
e.key = 'k'
e.metaKey = true
window.dispatchEvent(e)
setTimeout(() => {
if (!document.querySelector('.DocSearch-Modal')) {
poll()
}
}, 16)
}
function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
// note: multi-lang search support is removed since the theme
// doesn't support multiple locales as of now.
const options = Object.assign({}, userOptions, {
container: '#docsearch',
navigator: {
navigate({ itemUrl }: { itemUrl: string }) {
const { pathname: hitPathname } = new URL(
window.location.origin + itemUrl
)
// router doesn't handle same-page navigation so we use the native
// browser location API for anchor navigation
if (route.path === hitPathname) {
window.location.assign(window.location.origin + itemUrl)
} else {
router.go(itemUrl)
}
}
},
transformItems(items: any[]) {
return items.map((item) => {
return Object.assign({}, item, {
url: getRelativePath(item.url)
})
})
},
hitComponent({ hit, children }: { hit: any; children: any }) {
const relativeHit = hit.url.startsWith('http')
? getRelativePath(hit.url as string)
: hit.url
return {
__v: null,
type: 'a',
ref: undefined,
constructor: undefined,
key: undefined,
props: {
href: hit.url,
onClick(event: MouseEvent) {
if (isSpecialClick(event)) {
return
}
// we rely on the native link scrolling when user is already on
// the right anchor because Router doesn't support duplicated
// history entries.
if (route.path === relativeHit) {
return
}
// if the hits goes to another page, we prevent the native link
// behavior to leverage the Router loading feature.
if (route.path !== relativeHit) {
event.preventDefault()
}
router.go(relativeHit)
},
children
}
}
}
})
docsearch(options)
}
function isSpecialClick(event: MouseEvent) {
return (
event.button === 1 ||
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey
)
}
function getRelativePath(absoluteUrl: string) {
const { pathname, hash } = new URL(absoluteUrl)
return pathname + hash
}
</script>
<template>
<div id="docsearch" />
</template>

View File

@@ -0,0 +1,81 @@
<!-- @format -->
<script setup lang="ts">
import { useRoute, useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar.js'
import NotFound from '../layouts/NotFound.vue'
import VTHome from './VTHome.vue'
import VTDoc from './article/VTDoc.vue'
import VTDocList from './article/VTDocList.vue'
import VTSidebar from './sidebar/VTSidebar.vue'
const route = useRoute()
const { frontmatter } = useData()
const { hasSidebar } = useSidebar()
</script>
<template>
<div
class="VPContent"
id="VPContent"
:class="{
'has-sidebar': hasSidebar,
'is-home': frontmatter.layout === 'home',
}"
>
<NotFound v-if="route.component === NotFound" />
<VTHome
v-else-if="frontmatter.layout === 'home' || frontmatter.layout === 'doc'"
>
<template #sidebar><VTSidebar /></template>
<template #doclist>
<!-- 文章列表 -->
<VTDocList v-if="frontmatter.layout === 'home'" />
</template>
<template #docone>
<!-- 单个文章 -->
<VTDoc v-if="frontmatter.layout === 'doc'">
<Content />
</VTDoc>
</template>
</VTHome>
<div v-else>
<Content></Content>
</div>
</div>
</template>
<style scoped>
.VPContent {
flex-grow: 1;
flex-shrink: 0;
margin: 0 auto;
width: 100%;
}
.VPContent.is-home {
width: 100%;
max-width: 100%;
}
@media (min-width: 960px) {
.VPContent {
padding-top: var(--vp-nav-height);
}
.VPContent.has-sidebar {
margin: 0;
padding-left: var(--vp-sidebar-width);
}
}
@media (min-width: 1440px) {
.VPContent.has-sidebar {
padding-right: calc((100vw - var(--vp-layout-max-width)) / 2);
padding-left: calc(
(100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)
);
}
}
</style>

View File

@@ -0,0 +1,156 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { useFlyout } from '../composables/flyout.js'
import VPIconChevronDown from './icons/VPIconChevronDown.vue'
import VPIconMoreHorizontal from './icons/VPIconMoreHorizontal.vue'
import VPMenu from './VPMenu.vue'
defineProps<{
icon?: any
button?: string
label?: string
items?: any[]
}>()
const open = ref(false)
const el = ref<HTMLElement>()
useFlyout({ el, onBlur })
function onBlur() {
open.value = false
}
</script>
<template>
<div
class="VPFlyout"
ref="el"
@mouseenter="open = true"
@mouseleave="open = false"
>
<button
type="button"
class="button"
aria-haspopup="true"
:aria-expanded="open"
:aria-label="label"
@click="open = !open"
>
<span v-if="button || icon" class="text">
<component v-if="icon" :is="icon" class="option-icon" />
{{ button }}
<VPIconChevronDown class="text-icon" />
</span>
<VPIconMoreHorizontal v-else class="icon" />
</button>
<div class="menu">
<VPMenu :items="items">
<slot />
</VPMenu>
</div>
</div>
</template>
<style scoped>
.VPFlyout {
position: relative;
}
.VPFlyout:hover {
color: var(--vp-c-bland);
transition: color 0.25s;
}
.VPFlyout:hover .text {
color: var(--vp-c-text-2);
}
.VPFlyout:hover .icon {
fill: var(--vp-c-text-2);
}
.VPFlyout.active .text {
color: var(--vp-c-brand);
}
.VPFlyout.active:hover .text {
color: var(--vp-c-brand-dark);
}
.VPFlyout:hover .menu,
.button[aria-expanded="true"] + .menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.button {
display: flex;
align-items: center;
padding: 0 12px;
height: var(--vp-nav-height-mobile);
color: var(--vp-c-text-1);
transition: color 0.5s;
}
@media (min-width: 960px) {
.button {
height: var(--vp-nav-height-desktop);
}
}
.text {
display: flex;
align-items: center;
line-height: var(--vp-nav-height-mobile);
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-1);
transition: color 0.25s;
}
@media (min-width: 960px) {
.text {
line-height: var(--vp-nav-height-desktop);
}
}
.option-icon {
margin-right: 0px;
width: 16px;
height: 16px;
fill: currentColor;
}
.text-icon {
margin-left: 4px;
width: 14px;
height: 14px;
fill: currentColor;
}
.icon {
width: 20px;
height: 20px;
fill: currentColor;
transition: fill 0.25s;
}
.menu {
position: absolute;
top: calc(var(--vp-nav-height-mobile) / 2 + 20px);
right: 0;
opacity: 0;
visibility: hidden;
transition: opacity 0.25s, visibility 0.25s, transform 0.25s;
}
@media (min-width: 960px) {
.menu {
top: calc(var(--vp-nav-height-desktop) / 2 + 20px);
}
}
</style>

View File

@@ -0,0 +1,84 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar.js'
import VTLeftButton from './VTLeftButton.vue'
const { theme } = useData()
const { hasSidebar } = useSidebar()
const brandColor = ref('')
const colorRef = ref(null)
const changeBrandColor = (color: string) => {
brandColor.value = color
document.documentElement.style.setProperty('--vp-c-brand', color)
}
</script>
<template>
<footer
v-if="theme.footer"
class="VTFooter relative left-0 right-0 bottom-0 container mx-auto w-full pb-8"
:class="{ 'has-sidebar': hasSidebar }"
>
<!-- <div class="grid grid-cols-4 gap-10"> -->
<div class="flex">
<div
id="VTFooterLeft"
class="rounded-vt hidden w-64 px-4 flex-none md:block">
<VTLeftButton>
<div ref="colorRef">
<span @click="changeBrandColor('red')">red</span>
<span @click="changeBrandColor('green')" >green</span>
</div>
</VTLeftButton>
</div>
<div
id="VTFooterMiddle"
class="rounded-vt w-full mt-8 px-4 md:w-1/2 flex-grow">
<div class="rounded-vt bg-cbg w-4/5 mx-auto text-center py-8">
<p class="message">{{ theme.footer.message }}</p>
<p class="copyright">{{ theme.footer.copyright }}</p>
</div>
</div>
</div>
</footer>
</template>
<style scoped>
/* .VPFooter {
position: absolute;
z-index: var(--vp-z-index-footer);
border-top: 1px solid var(--vp-c-divider-light);
padding: 32px 24px;
background-color: var(--vp-c-bg);
width: 80%;
left: 10%;
border-radius: 10px;
bottom: 20px;
} */
.VPFooter.has-sidebar {
display: none;
}
@media (min-width: 768px) {
.VPFooter {
/* padding: 32px; */
}
}
.message,
.copyright {
line-height: 24px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-2);
}
.message {
order: 2;
}
.copyright {
order: 1;
}
</style>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import { withBase } from 'vitepress'
defineProps<{
image: DefaultTheme.ThemeableImage
}>()
</script>
<script lang="ts">
export default {
inheritAttrs: false
}
</script>
<template>
<template v-if="image">
<img
v-if="typeof image === 'string' || 'src' in image"
class="VPImage"
v-bind="typeof image === 'string' ? $attrs : { ...image, ...$attrs }"
:src="withBase(typeof image === 'string' ? image : image.src)"
/>
<template v-else>
<VPImage class="dark" :image="image.dark" v-bind="$attrs" />
<VPImage class="light" :image="image.light" v-bind="$attrs" />
</template>
</template>
</template>
<style scoped>
html:not(.dark) .VPImage.dark {
display: none;
}
.dark .VPImage.light {
display: none;
}
</style>

View File

@@ -0,0 +1,38 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { normalizeLink } from '../support/utils.js'
import VPIconExternalLink from './icons/VPIconExternalLink.vue'
const props = defineProps<{
href?: string
noIcon?: boolean
}>()
const isExternal = computed(() => props.href && /^[a-z]+:/i.test(props.href))
</script>
<template>
<component
:is="href ? 'a' : 'span'"
class="VPLink"
:class="{ link: href }"
:href="href ? normalizeLink(href) : undefined"
:target="isExternal ? '_blank' : undefined"
:rel="isExternal ? 'noopener noreferrer' : undefined"
>
<slot />
<VPIconExternalLink v-if="isExternal && !noIcon" class="icon" />
</component>
</template>
<style scoped>
.icon {
display: inline-block;
margin-top: -1px;
margin-left: 4px;
width: 11px;
height: 11px;
fill: var(--vp-c-text-3);
transition: fill 0.25s;
}
</style>

View File

@@ -0,0 +1,74 @@
<script lang="ts" setup>
import VPMenuLink from './VPMenuLink.vue'
import VPMenuGroup from './VPMenuGroup.vue'
defineProps<{
items?: any[]
}>()
</script>
<template>
<div class="VPMenu">
<div v-if="items" class="items">
<template v-for="item in items" :key="item.text">
<VPMenuLink v-if="'link' in item" :item="item" />
<VPMenuGroup v-else :text="item.text" :items="item.items" />
</template>
</div>
<slot />
</div>
</template>
<style scoped>
.VPMenu {
border-radius: 12px;
padding: 12px;
min-width: 128px;
border: 1px solid var(--vp-c-divider-light);
background-color: var(--vp-c-bg);
box-shadow: var(--vp-shadow-3);
transition: background-color 0.5s;
}
.dark .VPMenu {
box-shadow: var(--vp-shadow-2);
}
.VPMenu :deep(.group) {
margin: 0 -12px;
padding: 0 12px 12px;
}
.VPMenu :deep(.group + .group) {
border-top: 1px solid var(--vp-c-divider-light);
padding: 11px 12px 12px;
}
.VPMenu :deep(.group:last-child) {
padding-bottom: 0;
}
.VPMenu :deep(.group + .item) {
border-top: 1px solid var(--vp-c-divider-light);
padding: 11px 16px 0;
}
.VPMenu :deep(.item) {
padding: 0 16px;
white-space: nowrap;
}
.VPMenu :deep(.label) {
flex-grow: 1;
line-height: 28px;
font-size: 12px;
font-weight: 500;
color: var(--vp-c-text-2);
transition: color .5s;
}
.VPMenu :deep(.action) {
padding-left: 24px;
}
</style>

View File

@@ -0,0 +1,46 @@
<script lang="ts" setup>
import VPMenuLink from './VPMenuLink.vue'
defineProps<{
text?: string
items: any[]
}>()
</script>
<template>
<div class="VPMenuGroup">
<p v-if="text" class="title">{{ text }}</p>
<template v-for="item in items">
<VPMenuLink v-if="'link' in item" :item="item" />
</template>
</div>
</template>
<style scoped>
.VPMenuGroup {
margin: 12px -12px 0;
border-top: 1px solid var(--vp-c-divider-light);
padding: 12px 12px 0;
}
.VPMenuGroup:first-child {
margin-top: 0;
border-top: 0;
padding-top: 0;
}
.VPMenuGroup + .VPMenuGroup {
margin-top: 12px;
border-top: 1px solid var(--vp-c-divider-light);
}
.title {
padding: 0 12px;
line-height: 32px;
font-size: 14px;
font-weight: 600;
color: var(--vp-c-text-2);
transition: color 0.25s;
}
</style>

View File

@@ -0,0 +1,55 @@
<script lang="ts" setup>
import { useData } from 'vitepress'
import { isActive } from '../support/utils.js'
import VPLink from './VPLink.vue'
defineProps<{
item: any
}>()
const { page } = useData()
</script>
<template>
<div class="VPMenuLink">
<VPLink
:class="{ active: isActive(page.relativePath, item.activeMatch || item.link) }"
:href="item.link"
>
{{ item.text }}
</VPLink>
</div>
</template>
<style scoped>
.VPMenuGroup + .VPMenuLink {
margin: 12px -12px 0;
border-top: 1px solid var(--vp-c-divider-light);
padding: 12px 12px 0;
}
.link {
display: block;
border-radius: 6px;
padding: 0 12px;
line-height: 32px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-1);
white-space: nowrap;
transition: background-color 0.25s, color 0.25s;
}
.link:hover {
color: var(--vp-c-brand);
background-color: var(--vp-c-bg-mute);
}
.dark .link:hover {
background-color: var(--vp-c-bg-soft);
}
.link.active {
color: var(--vp-c-brand);
}
</style>

View File

@@ -0,0 +1,63 @@
<script lang="ts" setup>
import type { DefaultTheme } from 'vitepress/theme'
import VPIconDiscord from './icons/VPIconDiscord.vue'
import VPIconFacebook from './icons/VPIconFacebook.vue'
import VPIconGitHub from './icons/VPIconGitHub.vue'
import VPIconLinkedIn from './icons/VPIconLinkedIn.vue'
import VPIconInstagram from './icons/VPIconInstagram.vue'
import VPIconSlack from './icons/VPIconSlack.vue'
import VPIconTwitter from './icons/VPIconTwitter.vue'
import VPIconYouTube from './icons/VPIconYouTube.vue'
defineProps<{
icon: DefaultTheme.SocialLinkIcon
link: string
}>()
const icons = {
discord: VPIconDiscord,
facebook: VPIconFacebook,
github: VPIconGitHub,
instagram: VPIconInstagram,
linkedin: VPIconLinkedIn,
slack: VPIconSlack,
twitter: VPIconTwitter,
youtube: VPIconYouTube
}
</script>
<template>
<a
class="VPSocialLink"
:href="link"
:title="icon"
target="_blank"
rel="noopener noreferrer"
>
<component :is="icons[icon]" class="icon" />
<span class="visually-hidden">{{ icon }}</span>
</a>
</template>
<style scoped>
.VPSocialLink {
display: flex;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
color: var(--vp-c-text-2);
transition: color .5s;
}
.VPSocialLink:hover {
color: var(--vp-c-text-1);
transition: color .25s;
}
.icon {
width: 20px;
height: 20px;
fill: currentColor;
}
</style>

View File

@@ -0,0 +1,27 @@
<script lang="ts" setup>
import type { DefaultTheme } from 'vitepress/theme'
import VPSocialLink from './VPSocialLink.vue'
defineProps<{
links: DefaultTheme.SocialLink[]
}>()
</script>
<template>
<div class="VPSocialLinks">
<VPSocialLink
v-for="{ link, icon } in links"
:key="link"
:icon="icon"
:link="link"
/>
</div>
</template>
<style scoped>
.VPSocialLinks {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
</style>

View File

@@ -0,0 +1,87 @@
<script setup lang="ts">
import { onMounted, ref, computed, reactive } from 'vue'
import { useMediaQuery, useParallax } from '@vueuse/core'
import type { CSSProperties } from 'vue'
import { useHomeParallax } from '../composables/homebg.js'
const { parallaxEnable } = useHomeParallax()
onMounted(() => {})
const parallaxRef = ref(null)
const isMobile = useMediaQuery('(max-width: 700px)')
const parallax = reactive(useParallax(parallaxRef))
const cardWindowStyle: CSSProperties = {
overflow: 'hidden',
fontSize: '1rem',
position: 'absolute',
top: '0',
left: '0',
height: '100%',
width: '100%',
}
const layerBase: CSSProperties = {
position: 'absolute',
height: '100%',
width: '100%',
transition: '.3s ease-out all',
}
const layerBg = computed(() => ({
...layerBase,
transform: `translateX(${parallax.tilt * 10}px) translateY(${
parallax.roll * 10
}px) scale(1.1)`,
}))
const layerCloud = computed(() => ({
...layerBase,
transform: `translateX(${parallax.tilt * 200}px) translateY(${
parallax.roll * 30 - 100
}px) scale(1)`,
}))
const layerHuman = computed(() => ({
...layerBase,
transform: `translateX(${parallax.tilt * -50}px) translateY(${
parallax.roll * 30
}px) scale(1.2)`,
}))
const layerGrass = computed(() => ({
...layerBase,
transform: `translateX(${parallax.tilt * -200}px) translateY(${
parallax.roll * 100 - 120
}px) scale(1.5)`,
}))
const cardStyle = computed(() => ({
position: 'absolute',
zIndex: 1,
background: '#00000000',
height: '100%',
width: '100%',
borderRadius: '5px',
overflow: 'hidden',
transition: '.3s ease-out all',
boxShadow: '0 0 20px 0 rgba(255, 255, 255, 0.25)',
// transform: `rotateX(${parallax.roll * 20}deg) rotateY(${
// parallax.tilt * 20
// }deg)`
}))
</script>
<template>
<div class="VTBackgroud" ref="parallaxRef">
<div v-if="parallaxEnable" :style="cardStyle">
<div :style="cardWindowStyle">
<img :style="layerBg" src="/imgs/blog-bg-cloud.png" alt="" />
<img :style="layerCloud" src="/imgs/cloud2.png" alt="" />
<img :style="layerHuman" src="/imgs/blog-bg-human.png" alt="" />
<img :style="layerGrass" src="/imgs/blog-bg-grass.png" alt="" />
</div>
</div>
<slot />
</div>
</template>
<style scoped>
.VTBackground {
}
</style>

View File

@@ -0,0 +1,93 @@
<script lang="ts" setup>
import { ref } from 'vue'
import VPSwitchAppearance from './switch/VPSwitchAppearance.vue'
defineProps<{
icon?: any
button?: string
label?: string
items?: any[]
}>()
const open = ref(false)
const el = ref<HTMLElement>()
</script>
<template>
<div
class="VTFloat"
ref="el"
@mouseenter="open = true"
@mouseleave="open = false"
>
<div class="box hover:animate-wiggle">
<VPSwitchAppearance />
</div>
<div class="box hover:animate-wiggle">
Set
</div>
</div>
</template>
<style scoped>
.VTFloat {
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
right: 20px;
bottom: 100px;
width: 60px;
height: max-content;
height: -moz-max-content;
z-index: 1000;
transition: all .3s ease;
}
.VTFloat:hover {
color: var(--vp-c-bland);
transition: color 0.25s;
}
.VTFloat:hover .text {
color: var(--vp-c-text-2);
}
.VTFloat:hover .icon {
fill: var(--vp-c-text-2);
}
.VTFloat.active .text {
color: var(--vp-c-brand);
}
.VTFloat.active:hover .text {
color: var(--vp-c-brand-dark);
}
.box {
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
margin: 5px;
transition: opacity 0.25s, border-color 0.5s, transform 0.25s;
border-radius: 10px;
border: 1px solid var(--vp-c-divider-light);
background-color: var(--vp-c-bg);
}
.box:hover {
border-color: var(--vp-c-gray);
}
@media (min-width: 960px) {
.menu {
top: calc(var(--vp-nav-height-desktop) / 2 + 20px);
}
}
</style>

View File

@@ -0,0 +1,60 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import VPFooter from './VPFooter.vue'
onMounted(() => {
const homeDown = document.getElementById('home-down')
const top = homeDown.clientHeight - 110
window.scroll({
top,
left: 0,
behavior: 'smooth'
})
})
</script>
<template>
<div class="VTHome">
<div id="home-down" class="min-h-eight relative">
<div :class="[
'absolute bottom-5 left-0 right-0 animate-bounce ',
'mx-auto w-10 text-3xl text-white'
]">
<i class="fa fa-chevron-down"></i>
</div>
</div>
<div id="VTContainer" class="container mx-auto w-11/12 pb-8">
<div class="flex">
<!-- <div class="grid grid-cols-4 gap-10"> -->
<div id="VTLeft" :class="[
'rounded-vt hidden w-64 px-4 flex-none',
'md:block'
]">
<slot name="sidebar"></slot>
</div>
<div id="VTContent" class="rounded-vt w-full px-4 md:w-1/2 flex-grow">
<slot name="doclist"></slot>
<slot name="docone"></slot>
</div>
</div>
<VPFooter />
</div>
</div>
</template>
<style scoped>
.VTHome {
}
.VTHome :deep(.VTHomeSponsors) {
margin-top: 112px;
margin-bottom: -128px;
}
@media (min-width: 768px) {
.VTHome {
}
}
.home-vtp-btn-up {
}
</style>

View File

@@ -0,0 +1,383 @@
<template>
<div class="vt-btn-up-wrapper">
<input type="checkbox" />
<div class="btn"></div>
<div class="tooltip ">
<slot>
</slot>
</div>
<svg>
<use xlink:href="#shape-01" class="shape shape-01" />
<use xlink:href="#shape-02" class="shape shape-02" />
<use xlink:href="#shape-03" class="shape shape-03" />
<use xlink:href="#shape-04" class="shape shape-04" />
<use xlink:href="#shape-05" class="shape shape-05" />
<use xlink:href="#shape-06" class="shape shape-06" />
<use xlink:href="#shape-07" class="shape shape-07" />
<use xlink:href="#shape-08" class="shape shape-08" />
<use xlink:href="#shape-09" class="shape shape-09" />
</svg>
</div>
</template>
<style scoped>
.vt-btn-up-wrapper {
--background: #62abff;
--icon-color: #414856;
--shape-color-01: #b8cbee;
--shape-color-02: #7691e8;
--shape-color-03: #fdd053;
--width: 40px;
--height: 40px;
--border-radius: var(--height);
width: var(--width);
height: var(--height);
position: relative;
border-radius: var(--border-radius);
display: -webkit-box;
display: flex;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
}
.vt-btn-up-wrapper .btn {
background: var(--background);
width: var(--width);
height: var(--height);
position: relative;
z-index: 3;
border-radius: var(--border-radius);
box-shadow: 0 10px 30px rgba(65, 72, 86, 0.05);
display: -webkit-box;
display: flex;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
-webkit-animation: plus-animation-reverse 0.5s ease-out forwards;
animation: plus-animation-reverse 0.5s ease-out forwards;
}
.vt-btn-up-wrapper .btn::before,
.vt-btn-up-wrapper .btn::after {
content: '';
display: block;
position: absolute;
border-radius: 4px;
background: #fff;
}
.vt-btn-up-wrapper .btn::before {
width: 4px;
height: 14px;
}
.vt-btn-up-wrapper .btn::after {
width: 14px;
height: 4px;
}
.vt-btn-up-wrapper .tooltip {
/* width: 90px;
height: 75px; */
border-radius: 50px;
position: absolute;
background: #fff;
z-index: 2;
padding: 0 15px;
box-shadow: 0 10px 30px rgba(65, 72, 86, 0.1);
opacity: 0;
top: 0;
display: -webkit-box;
display: flex;
justify-content: space-around;
-webkit-box-align: center;
align-items: center;
-webkit-transition: opacity 0.15s ease-in, top 0.15s ease-in,
width 0.15s ease-in;
transition: opacity 0.15s ease-in, top 0.15s ease-in, width 0.15s ease-in;
}
.vt-btn-up-wrapper .tooltip:hover {
box-shadow: 0 10px 30px rgba(65, 72, 86, 0.2);
}
.vt-btn-up-wrapper .tooltip > svg {
width: 100%;
height: 26px;
display: -webkit-box;
display: flex;
justify-content: space-around;
-webkit-box-align: center;
align-items: center;
cursor: pointer;
}
.vt-btn-up-wrapper .tooltip > svg .icon {
fill: none;
stroke: var(--icon-color);
stroke-width: 2px;
stroke-linecap: round;
stroke-linejoin: round;
opacity: 0.4;
-webkit-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
}
.vt-btn-up-wrapper .tooltip > svg:hover .icon {
opacity: 1;
}
.vt-btn-up-wrapper .tooltip::after {
content: '';
width: 20px;
height: 20px;
background: #fff;
border-radius: 3px;
position: absolute;
left: 2.6rem;
bottom: -0.5rem;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
z-index: 0;
}
.vt-btn-up-wrapper > svg {
width: 30px;
height: 30px;
position: absolute;
z-index: 1;
-webkit-transform: scale(0);
transform: scale(0);
}
.vt-btn-up-wrapper > svg .shape {
fill: none;
stroke: none;
stroke-width: 3px;
stroke-linecap: round;
stroke-linejoin: round;
-webkit-transform-origin: 50% 20%;
transform-origin: 50% 20%;
}
.vt-btn-up-wrapper input {
height: 100%;
width: 100%;
border-radius: var(--border-radius);
cursor: pointer;
position: absolute;
z-index: 5;
opacity: 0;
}
.vt-btn-up-wrapper input:checked ~ svg {
-webkit-animation: pang-animation 1.2s ease-out forwards;
animation: pang-animation 1.2s ease-out forwards;
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(1) {
-webkit-transform: translate(-17px, 30%) rotate(40deg);
transform: translate(-17px, 30%) rotate(40deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(2) {
-webkit-transform: translate(15px, 30%) rotate(80deg);
transform: translate(15px, 30%) rotate(80deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(3) {
-webkit-transform: translate(11px, 30%) rotate(120deg);
transform: translate(11px, 30%) rotate(120deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(4) {
-webkit-transform: translate(20px, 30%) rotate(160deg);
transform: translate(20px, 30%) rotate(160deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(5) {
-webkit-transform: translate(-20px, 30%) rotate(200deg);
transform: translate(-20px, 30%) rotate(200deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(6) {
-webkit-transform: translate(10px, 30%) rotate(240deg);
transform: translate(10px, 30%) rotate(240deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(7) {
-webkit-transform: translate(3px, 30%) rotate(280deg);
transform: translate(3px, 30%) rotate(280deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(8) {
-webkit-transform: translate(0px, 30%) rotate(320deg);
transform: translate(0px, 30%) rotate(320deg);
}
.vt-btn-up-wrapper input:checked ~ svg .shape:nth-of-type(9) {
-webkit-transform: translate(25px, 30%) rotate(360deg);
transform: translate(25px, 30%) rotate(360deg);
}
.vt-btn-up-wrapper input:checked ~ .btn {
-webkit-animation: plus-animation 0.5s ease-out forwards;
animation: plus-animation 0.5s ease-out forwards;
}
.vt-btn-up-wrapper input:checked ~ .tooltip {
width: 20rem;
height: 20rem;
-webkit-animation: stretch-animation 1s ease-out forwards 0.15s;
animation: stretch-animation 1s ease-out forwards 0.15s;
top: -22rem;
left: -2rem;
opacity: 1;
}
@-webkit-keyframes pang-animation {
0% {
-webkit-transform: scale(0);
transform: scale(0);
opacity: 0;
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
100% {
-webkit-transform: scale(1.1);
transform: scale(1.1);
opacity: 0;
}
}
@keyframes pang-animation {
0% {
-webkit-transform: scale(0);
transform: scale(0);
opacity: 0;
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
100% {
-webkit-transform: scale(1.1);
transform: scale(1.1);
opacity: 0;
}
}
@-webkit-keyframes plus-animation {
0% {
-webkit-transform: rotate(0) scale(1);
transform: rotate(0) scale(1);
}
20% {
-webkit-transform: rotate(60deg) scale(0.93);
transform: rotate(60deg) scale(0.93);
}
55% {
-webkit-transform: rotate(35deg) scale(0.97);
transform: rotate(35deg) scale(0.97);
}
80% {
-webkit-transform: rotate(48deg) scale(0.94);
transform: rotate(48deg) scale(0.94);
}
100% {
-webkit-transform: rotate(45deg) scale(0.95);
transform: rotate(45deg) scale(0.95);
}
}
@keyframes plus-animation {
0% {
-webkit-transform: rotate(0) scale(1);
transform: rotate(0) scale(1);
}
20% {
-webkit-transform: rotate(60deg) scale(0.93);
transform: rotate(60deg) scale(0.93);
}
55% {
-webkit-transform: rotate(35deg) scale(0.97);
transform: rotate(35deg) scale(0.97);
}
80% {
-webkit-transform: rotate(48deg) scale(0.94);
transform: rotate(48deg) scale(0.94);
}
100% {
-webkit-transform: rotate(45deg) scale(0.95);
transform: rotate(45deg) scale(0.95);
}
}
@-webkit-keyframes plus-animation-reverse {
0% {
-webkit-transform: rotate(45deg) scale(0.95);
transform: rotate(45deg) scale(0.95);
}
20% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
55% {
-webkit-transform: rotate(10deg);
transform: rotate(10deg);
}
80% {
-webkit-transform: rotate(-3deg);
transform: rotate(-3deg);
}
100% {
-webkit-transform: rotate(0) scale(1);
transform: rotate(0) scale(1);
}
}
@keyframes plus-animation-reverse {
0% {
-webkit-transform: rotate(45deg) scale(0.95);
transform: rotate(45deg) scale(0.95);
}
20% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
55% {
-webkit-transform: rotate(10deg);
transform: rotate(10deg);
}
80% {
-webkit-transform: rotate(-3deg);
transform: rotate(-3deg);
}
100% {
-webkit-transform: rotate(0) scale(1);
transform: rotate(0) scale(1);
}
}
@-webkit-keyframes stretch-animation {
0% {
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
10% {
-webkit-transform: scale(1.1, 0.9);
transform: scale(1.1, 0.9);
}
30% {
-webkit-transform: scale(0.9, 1.1);
transform: scale(0.9, 1.1);
}
50% {
-webkit-transform: scale(1.05, 0.95);
transform: scale(1.05, 0.95);
}
100% {
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
}
@keyframes stretch-animation {
0% {
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
10% {
-webkit-transform: scale(1.1, 0.9);
transform: scale(1.1, 0.9);
}
30% {
-webkit-transform: scale(0.9, 1.1);
transform: scale(0.9, 1.1);
}
50% {
-webkit-transform: scale(1.05, 0.95);
transform: scale(1.05, 0.95);
}
100% {
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
}
</style>

View File

@@ -0,0 +1,11 @@
<template>
<div class="bg-cbg rounded-vt shadow-vt p-10">
<div class="vp-doc">
<slot></slot>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,56 @@
<script setup lang="ts">
import { normalizeLink, fmt } from '../../support/utils.js'
const props = defineProps<{
data: any
}>()
const f = props.data.data.frontmatter
const tags = f.tags.split(',')
const timeStr = fmt(f.time)
const togo = (url: string) => {
if (!url) url = ''
window.location.href = normalizeLink(url)
}
</script>
<template>
<div class="VTDocCard">
<div class="rounded-vt h-80 w-full mb-6 bg-gray-700" @click="togo(data.path)">
<div class="pic h-1/2 text-white relative text-center">
<div class="title absolute w-4/5 bottom-2 left-0 right-0 mx-auto">
<h1 class="font-black text-xl antialiased tracking-wide">{{f.title}}</h1>
<p class="m-1">{{timeStr}}</p>
</div>
</div>
<div class="text h-1/2 bg-cbg rounded-vt px-10 py-6">
<div class="desc h-3/4">
<!-- {{data}} -->
</div>
<div class="tag h-1/4">
<span class="inline-block w-24 font-bold
hover:text-brand transition-colors duration-300">
<i class="fa fa-star-half-o" aria-hidden="true"></i>
&nbsp;
{{f.categories}}
</span>
<span>
<i class="fa fa-tags" aria-hidden="true"></i>
<span
class="px-1.5 m-1 inline-block text-center
bg-cbgs border-2 border-cbgs rounded-vt
hover:border-brand transition-colors duration-300
"
v-for="t in tags" :key="t">{{t}}</span>
</span>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import { getRoutes } from '../../../support/pages.js'
import VTDocCard from './VTDocCard.vue'
const { routes } = getRoutes()
</script>
<template>
<div class="VTDoc">
<div v-for="(r,i) in routes" :key="r.__hmrId">
<VTDocCard :data="r" />
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,8 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M21,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,11,21,11z" />
<path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z" />
<path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z" />
<path d="M21,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,19,21,19z" />
</svg>
</template>

View File

@@ -0,0 +1,8 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z" />
<path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z" />
<path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z" />
<path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z" />
</svg>
</template>

View File

@@ -0,0 +1,8 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M21,11H7c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S21.6,11,21,11z" />
<path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z" />
<path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z" />
<path d="M21,19H7c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S21.6,19,21,19z" />
</svg>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M19,11H7.4l5.3-5.3c0.4-0.4,0.4-1,0-1.4s-1-0.4-1.4,0l-7,7c-0.1,0.1-0.2,0.2-0.2,0.3c-0.1,0.2-0.1,0.5,0,0.8c0.1,0.1,0.1,0.2,0.2,0.3l7,7c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L7.4,13H19c0.6,0,1-0.4,1-1S19.6,11,19,11z"
/>
</svg>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M19.9,12.4c0.1-0.2,0.1-0.5,0-0.8c-0.1-0.1-0.1-0.2-0.2-0.3l-7-7c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l5.3,5.3H5c-0.6,0-1,0.4-1,1s0.4,1,1,1h11.6l-5.3,5.3c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3l7-7C19.8,12.6,19.9,12.5,19.9,12.4z"
/>
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M15,19c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4l6-6c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4L10.4,12l5.3,5.3c0.4,0.4,0.4,1,0,1.4C15.5,18.9,15.3,19,15,19z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M18,16c-0.3,0-0.5-0.1-0.7-0.3L12,10.4l-5.3,5.3c-0.4,0.4-1,0.4-1.4,0s-0.4-1,0-1.4l6-6c0.4-0.4,1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4C18.5,15.9,18.3,16,18,16z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M20.222 0c1.406 0 2.54 1.137 2.607 2.475V24l-2.677-2.273-1.47-1.338-1.604-1.398.67 2.205H3.71c-1.402 0-2.54-1.065-2.54-2.476V2.48C1.17 1.142 2.31.003 3.715.003h16.5L20.222 0zm-6.118 5.683h-.03l-.202.2c2.073.6 3.076 1.537 3.076 1.537-1.336-.668-2.54-1.002-3.744-1.137-.87-.135-1.74-.064-2.475 0h-.2c-.47 0-1.47.2-2.81.735-.467.203-.735.336-.735.336s1.002-1.002 3.21-1.537l-.135-.135s-1.672-.064-3.477 1.27c0 0-1.805 3.144-1.805 7.02 0 0 1 1.74 3.743 1.806 0 0 .4-.533.805-1.002-1.54-.468-2.14-1.404-2.14-1.404s.134.066.335.2h.06c.03 0 .044.015.06.03v.006c.016.016.03.03.06.03.33.136.66.27.93.4.466.202 1.065.403 1.8.536.93.135 1.996.2 3.21 0 .6-.135 1.2-.267 1.8-.535.39-.2.87-.4 1.397-.737 0 0-.6.936-2.205 1.404.33.466.795 1 .795 1 2.744-.06 3.81-1.8 3.87-1.726 0-3.87-1.815-7.02-1.815-7.02-1.635-1.214-3.165-1.26-3.435-1.26l.056-.02zm.168 4.413c.703 0 1.27.6 1.27 1.335 0 .74-.57 1.34-1.27 1.34-.7 0-1.27-.6-1.27-1.334.002-.74.573-1.338 1.27-1.338zm-4.543 0c.7 0 1.266.6 1.266 1.335 0 .74-.57 1.34-1.27 1.34-.7 0-1.27-.6-1.27-1.334 0-.74.57-1.338 1.27-1.338z" />
</svg>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z" />
<path d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z" />
</svg>
</template>

View File

@@ -0,0 +1,13 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
focusable="false"
height="24px"
viewBox="0 0 24 24"
width="24px"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12,22.2c-0.3,0-0.5-0.1-0.7-0.3l-8.8-8.8c-2.5-2.5-2.5-6.7,0-9.2c2.5-2.5,6.7-2.5,9.2,0L12,4.3l0.4-0.4c0,0,0,0,0,0C13.6,2.7,15.2,2,16.9,2c0,0,0,0,0,0c1.7,0,3.4,0.7,4.6,1.9l0,0c1.2,1.2,1.9,2.9,1.9,4.6c0,1.7-0.7,3.4-1.9,4.6l-8.8,8.8C12.5,22.1,12.3,22.2,12,22.2zM7,4C5.9,4,4.7,4.4,3.9,5.3c-1.8,1.8-1.8,4.6,0,6.4l8.1,8.1l8.1-8.1c0.9-0.9,1.3-2,1.3-3.2c0-1.2-0.5-2.3-1.3-3.2l0,0C19.3,4.5,18.2,4,17,4c0,0,0,0,0,0c-1.2,0-2.3,0.5-3.2,1.3c0,0,0,0,0,0l-1.1,1.1c-0.4,0.4-1,0.4-1.4,0l-1.1-1.1C9.4,4.4,8.2,4,7,4z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M12 0C8.74 0 8.333.015 7.053.072 5.775.132 4.905.333 4.14.63c-.789.306-1.459.717-2.126 1.384S.935 3.35.63 4.14C.333 4.905.131 5.775.072 7.053.012 8.333 0 8.74 0 12s.015 3.667.072 4.947c.06 1.277.261 2.148.558 2.913.306.788.717 1.459 1.384 2.126.667.666 1.336 1.079 2.126 1.384.766.296 1.636.499 2.913.558C8.333 23.988 8.74 24 12 24s3.667-.015 4.947-.072c1.277-.06 2.148-.262 2.913-.558.788-.306 1.459-.718 2.126-1.384.666-.667 1.079-1.335 1.384-2.126.296-.765.499-1.636.558-2.913.06-1.28.072-1.687.072-4.947s-.015-3.667-.072-4.947c-.06-1.277-.262-2.149-.558-2.913-.306-.789-.718-1.459-1.384-2.126C21.319 1.347 20.651.935 19.86.63c-.765-.297-1.636-.499-2.913-.558C15.667.012 15.26 0 12 0zm0 2.16c3.203 0 3.585.016 4.85.071 1.17.055 1.805.249 2.227.415.562.217.96.477 1.382.896.419.42.679.819.896 1.381.164.422.36 1.057.413 2.227.057 1.266.07 1.646.07 4.85s-.015 3.585-.074 4.85c-.061 1.17-.256 1.805-.421 2.227-.224.562-.479.96-.899 1.382-.419.419-.824.679-1.38.896-.42.164-1.065.36-2.235.413-1.274.057-1.649.07-4.859.07-3.211 0-3.586-.015-4.859-.074-1.171-.061-1.816-.256-2.236-.421-.569-.224-.96-.479-1.379-.899-.421-.419-.69-.824-.9-1.38-.165-.42-.359-1.065-.42-2.235-.045-1.26-.061-1.649-.061-4.844 0-3.196.016-3.586.061-4.861.061-1.17.255-1.814.42-2.234.21-.57.479-.96.9-1.381.419-.419.81-.689 1.379-.898.42-.166 1.051-.361 2.221-.421 1.275-.045 1.65-.06 4.859-.06l.045.03zm0 3.678c-3.405 0-6.162 2.76-6.162 6.162 0 3.405 2.76 6.162 6.162 6.162 3.405 0 6.162-2.76 6.162-6.162 0-3.405-2.76-6.162-6.162-6.162zM12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm7.846-10.405c0 .795-.646 1.44-1.44 1.44-.795 0-1.44-.646-1.44-1.44 0-.794.646-1.439 1.44-1.439.793-.001 1.44.645 1.44 1.439z" />
</svg>
</template>

View File

@@ -0,0 +1,9 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"></path>
<path
d=" M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z "
class="css-c4d79v"
></path>
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M22,13H2a1,1,0,0,1,0-2H22a1,1,0,0,1,0,2Z" />
</svg>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<path d="M19,2H5C3.3,2,2,3.3,2,5v14c0,1.7,1.3,3,3,3h14c1.7,0,3-1.3,3-3V5C22,3.3,20.7,2,19,2zM20,19c0,0.6-0.4,1-1,1H5c-0.6,0-1-0.4-1-1V5c0-0.6,0.4-1,1-1h14c0.6,0,1,0.4,1,1V19z" />
<path d="M16,11H8c-0.6,0-1,0.4-1,1s0.4,1,1,1h8c0.6,0,1-0.4,1-1S16.6,11,16,11z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z" />
</svg>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="2" />
<circle cx="19" cy="12" r="2" />
<circle cx="5" cy="12" r="2" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M18.9,10.9h-6v-6c0-0.6-0.4-1-1-1s-1,0.4-1,1v6h-6c-0.6,0-1,0.4-1,1s0.4,1,1,1h6v6c0,0.6,0.4,1,1,1s1-0.4,1-1v-6h6c0.6,0,1-0.4,1-1S19.5,10.9,18.9,10.9z" />
</svg>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M19,2H5C3.3,2,2,3.3,2,5v14c0,1.7,1.3,3,3,3h14c1.7,0,3-1.3,3-3V5C22,3.3,20.7,2,19,2z M20,19c0,0.6-0.4,1-1,1H5c-0.6,0-1-0.4-1-1V5c0-0.6,0.4-1,1-1h14c0.6,0,1,0.4,1,1V19z" />
<path d="M16,11h-3V8c0-0.6-0.4-1-1-1s-1,0.4-1,1v3H8c-0.6,0-1,0.4-1,1s0.4,1,1,1h3v3c0,0.6,0.4,1,1,1s1-0.4,1-1v-3h3c0.6,0,1-0.4,1-1S16.6,11,16,11z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" />
</svg>
</template>

View File

@@ -0,0 +1,13 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z" />
<path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z" />
<path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z" />
<path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z" />
<path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z" />
<path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z" />
<path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z" />
<path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z" />
<path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z" />
</svg>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
</svg>
</template>

View File

@@ -0,0 +1,37 @@
<script setup lang="ts">
import { useData } from 'vitepress'
import { useSidebar } from '../../composables/sidebar.js'
import VTSidebarTop from './VTSidebarTop.vue'
import VTSidebarBottom from './VTSidebarBottom.vue'
const { site, theme } = useData()
const { hasSidebar } = useSidebar()
const { base } = site.value
let { avatar, author } = theme.value
let baseUrl = base
if (base === '/' || base.endsWith('/')) {
baseUrl = base.substring(0, base.length - 1)
}
avatar = `${baseUrl}${avatar}`
author += ' '
</script>
<template>
<div
class="VTSidebar"
:class="{ 'has-sidebar': hasSidebar }"
>
<VTSidebarTop />
<div class="h-6"></div>
<VTSidebarBottom
:avatar="avatar"
:author="author"
/>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,76 @@
<script setup lang="ts">
const d = defineProps<{
avatar?: string,
author?: string
}>()
</script>
<template>
<div class="VTSidebarBottom">
<div class="rounded-vt shadow-vt bg-cbg p-6">
<div class="avatar w-full pt-6">
<div
class="bg-cover bg-center rounded-full h-24 w-24 bg-green-100 mx-auto"
:style="{'background-image': `url(${d.avatar})`}"
>
</div>
</div>
<div class="author">
<p class="text-center py-6 text-xl font-bold">{{d.author}}</p>
</div>
<div class="tag">
<div class="grid grid-cols-3 w-4/5 mx-auto text-center">
<div>
<p class="font-bold">1</p>
<p class="text-sm hover:text-brand-d hover:font-bold">文章</p>
</div>
<div>
<p class="font-bold">0</p>
<p class="text-sm hover:text-brand-d hover:font-bold">分类</p>
</div>
<div>
<p class="font-bold">10</p>
<p class="text-sm hover:text-brand-d hover:font-bold">标签</p>
</div>
</div>
</div>
<div class="self-links">
<div class="py-6 flex flex-wrap text-left text-sm">
<div class="w-1/2 py-1.5 pl-2 mt-1 hover:bg-cbgs rounded-vt">
<i class="w-3 h-3 text-sm mr-1 fa fa-ambulance"></i>&nbsp;
<span>Gitee</span>
</div>
<div class="w-1/2 py-1.5 pl-2 mt-1 hover:bg-cbgs rounded-vt">
<i class="w-3 h-3 text-sm mr-1 fa fa-github-alt"></i>&nbsp;
<span>Github</span>
</div>
<div class="w-1/2 py-1.5 pl-2 mt-1 hover:bg-cbgs rounded-vt">
<i class="w-3 h-3 text-sm mr-1 fa fa-envelope-o"></i>&nbsp;
<span>Email</span>
</div>
</div>
</div>
<!-- <div class="friend-links">
<div class="py-6 border-t-2 border-gray-100 border-opacity-50 text-center">
<div>
<a
class="border-b-2 border-gray-200 inline-block m-1 px-1 hover:border-gray-500 transition duration-500 border-opacity-50"
href="https://github.com/lauset"
>LauSET</a
>
</div>
<div>
<a
class="border-b-2 border-gray-200 inline-block m-1 px-1 hover:border-gray-500 transition duration-500 border-opacity-50"
href="https://github.com/lauset"
>Vuetom</a
>
</div>
</div>
</div> -->
</div>
</div>
</template>
<style scoped></style>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import { normalizeLink } from '../../support/utils.js'
const props = defineProps<{
text: string,
link: string,
items: any
}>()
const togo = (url: string) => {
if (!url) url = ''
window.location.href = normalizeLink(url)
}
</script>
<template>
<div>
<div class="rounded-md w-full py-1 px-4 border-2 border-transparent
hover:border-brand transition-colors"
@click="togo(link)">
{{text}}
</div>
</div>
</template>

View File

@@ -0,0 +1,28 @@
<script setup lang="ts">
import VTSidebarLink from './VTSidebarLink.vue'
import { useSidebar } from '../../composables/sidebar.js'
const { sidebar } = useSidebar()
</script>
<template>
<div class="VTSidebarTop">
<div class="rounded-vt shadow-vt overflow-hidden bg-cbg">
<div class="h-20 px-6 py-3 bg-brand">
<p class="font-bold py-1">公告</p>
<p class="text-sm">暂无</p>
</div>
<div class="h-60 px-6 py-4">
<div v-for="s in sidebar" :key="s.text">
<VTSidebarLink
:text="s.text"
:items="s.items"
:link="s.link" />
</div>
</div>
</div>
</div >
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,66 @@
<template>
<button class="VPSwitch" type="button" role="switch">
<span class="check">
<span class="icon" v-if="$slots.default">
<slot />
</span>
</span>
</button>
</template>
<style scoped>
.VPSwitch {
position: relative;
border-radius: 11px;
display: block;
width: 40px;
height: 40px;
flex-shrink: 0;
/* border: 1px solid var(--vp-c-divider); */
/* background-color: var(--vp-c-bg-mute); */
transition: border-color 0.25s, background-color 0.25s;
}
.VPSwitch:hover {
/* border-color: var(--vp-c-gray); */
}
.check {
position: absolute;
top: 5px;
left: 5px;
width: 30px;
height: 30px;
border-radius: 50%;
/* background-color: var(--vp-c-white);
box-shadow: var(--vp-shadow-1); */
transition: background-color 0.25s, transform 0.25s;
}
.dark .check {
/* background-color: var(--vp-c-black); */
}
.icon {
position: relative;
display: block;
width: 30px;
height: 30px;
border-radius: 50%;
overflow: hidden;
}
.icon :deep(svg) {
position: absolute;
top: 3px;
left: 3px;
width: 24px;
height: 24px;
fill: var(--vp-c-text-2);
}
.dark .icon :deep(svg) {
fill: var(--vp-c-text-1);
transition: opacity 0.25s;
}
</style>

View File

@@ -0,0 +1,74 @@
<script lang="ts" setup>
import { APPEARANCE_KEY } from '../../shared.js'
import VPSwitch from './VPSwitch.vue'
import VPIconSun from '../icons/VPIconSun.vue'
import VPIconMoon from '../icons/VPIconMoon.vue'
const toggle = typeof localStorage !== 'undefined' ? useAppearance() : () => {}
function useAppearance() {
const query = window.matchMedia('(prefers-color-scheme: dark)')
const { classList } = document.documentElement
let userPreference = localStorage.getItem(APPEARANCE_KEY) || 'auto'
let isDark = userPreference === 'auto'
? query.matches
: userPreference === 'dark'
query.onchange = (e) => {
if (userPreference === 'auto') {
setClass((isDark = e.matches))
}
}
function toggle() {
setClass((isDark = !isDark))
userPreference = isDark
? query.matches ? 'auto' : 'dark'
: query.matches ? 'light' : 'auto'
localStorage.setItem(APPEARANCE_KEY, userPreference)
}
function setClass(dark: boolean): void {
classList[dark ? 'add' : 'remove']('dark')
}
return toggle
}
</script>
<template>
<VPSwitch
class="VPSwitchAppearance"
aria-label="toggle dark mode"
@click="toggle"
>
<VPIconSun class="sun" />
<VPIconMoon class="moon" />
</VPSwitch>
</template>
<style scoped>
.sun {
opacity: 1;
}
.moon {
opacity: 0;
}
.dark .sun {
opacity: 0;
}
.dark .moon {
opacity: 1;
}
.dark .VPSwitchAppearance :deep(.check) {
/* transform: translateX(18px); */
}
</style>