Initial rearrangment of vuetom site source
This commit is contained in:
158
packages/vuetom/README.md
Normal file
158
packages/vuetom/README.md
Normal file
@@ -0,0 +1,158 @@
|
||||
|
||||
<p align="center"><a href="https://gitee.com/lauset/vitepress-theme-vuetom" target="_blank" rel="noopener noreferrer"><img width="180" src="https://cdn.jsdelivr.net/gh/lauset/vitepress-theme-vuetom/packages/docs/public/logo/vuetom-logo.png" alt="logo"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/xugaoyi/vuepress-theme-vdoing/blob/master/LICENSE"><img src="https://img.shields.io/github/license/xugaoyi/vuepress-theme-vdoing
|
||||
" alt="License"></a>
|
||||
<a href="https://www.npmjs.com/package/vitepress-theme-vuetom"><img alt="npm" src="https://img.shields.io/npm/v/vitepress-theme-vuetom"></a>
|
||||
</p>
|
||||
|
||||
<h2 align="center">vitepress-theme-vuetom</h2>
|
||||
|
||||
## 简要说明
|
||||
|
||||
1. 为 vitepress 1.x 提供的主题
|
||||
2. 提供文档与博客两种风格的主题
|
||||
|
||||
[**更新日志**](CHANGELOG.md)
|
||||
|
||||
## 主题预览
|
||||
|
||||
* [**文档**风格 (*github.io*)](https://lauset.github.io/vitepress-theme-vuetom/)
|
||||
|
||||
* [**文档**风格 (*vercel.app*)](https://vitepress-theme-vuetom.vercel.app/vt/)
|
||||
|
||||
* [**博客**风格 (*开发中*)](https://vitepress-theme-vuetom-blog.vercel.app/myblog/)
|
||||
|
||||
## 快速上手
|
||||
|
||||
* 拉取项目
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lauset/vitepress-theme-vuetom.git
|
||||
|
||||
cd vitepress-theme-vuetom
|
||||
```
|
||||
|
||||
* 安装依赖
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
* 启动文档示例
|
||||
|
||||
```bash
|
||||
# 根目录运行
|
||||
pnpm dev:docs
|
||||
|
||||
# 文档目录运行
|
||||
cd packages/docs
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
* 启动博客示例
|
||||
|
||||
```bash
|
||||
# 根目录运行
|
||||
pnpm dev:blog
|
||||
|
||||
# 博客目录运行
|
||||
cd packages/blog
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
* 根目录构建操作
|
||||
|
||||
```bash
|
||||
# 清理已打包的文件
|
||||
pnpm clean:all
|
||||
|
||||
# 构建主题
|
||||
pnpm build:theme
|
||||
|
||||
# 构建文档
|
||||
pnpm build:docs
|
||||
|
||||
# 构建博客
|
||||
pnpm build:blog
|
||||
```
|
||||
|
||||
* 根目录预览操作
|
||||
|
||||
```bash
|
||||
# 预览文档
|
||||
pnpm preview:docs
|
||||
|
||||
# 预览博客
|
||||
pnpm preview:blog
|
||||
```
|
||||
|
||||
* 发布主题包
|
||||
|
||||
```bash
|
||||
cd packages/vuetom
|
||||
pnpm pub
|
||||
```
|
||||
|
||||
## 文档目录多语言
|
||||
|
||||
查看项目文件列表
|
||||
|
||||
```shell
|
||||
crowdin:list
|
||||
```
|
||||
|
||||
上传待翻译的源文件
|
||||
|
||||
```shell
|
||||
crowdin:upload
|
||||
```
|
||||
|
||||
查看预下载文件列表
|
||||
|
||||
```shell
|
||||
crowdin:dryrun
|
||||
```
|
||||
|
||||
下载en-US翻译文件
|
||||
|
||||
```shell
|
||||
crowdin:us
|
||||
```
|
||||
|
||||
下载zh-TW翻译文件
|
||||
|
||||
```shell
|
||||
crowdin:tw
|
||||
```
|
||||
|
||||
## 简单展示
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 仓库地址
|
||||
|
||||
[github](https://github.com/lauset/vitepress-theme-vuetom)
|
||||
|
||||
[gitee](https://gitee.com/lauset/vitepress-theme-vuetom)
|
||||
|
||||
## 感谢
|
||||
|
||||
[Vue](https://vuejs.org/)
|
||||
|
||||
[Vite](https://cn.vitejs.dev/)
|
||||
|
||||
[Vitepress](https://vitepress.vuejs.org/)
|
||||
|
||||
[Vercel](https://vercel.com/docs)
|
||||
|
||||
[ElementPlus](https://element-plus.gitee.io/zh-CN/)
|
||||
|
||||
[Crowdin](https://crowdin.com/)
|
||||
4
packages/vuetom/blog.d.ts
vendored
Normal file
4
packages/vuetom/blog.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Theme } from 'vitepress'
|
||||
|
||||
declare const BlogTheme: Theme
|
||||
export default BlogTheme
|
||||
10
packages/vuetom/blog/components/Page.vue
Normal file
10
packages/vuetom/blog/components/Page.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<main
|
||||
class="page">
|
||||
<div class="container">
|
||||
<slot name="top" />
|
||||
<Content class="content" />
|
||||
<slot name="bottom" />
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
126
packages/vuetom/blog/components/VPAlgoliaSearchBox.vue
Normal file
126
packages/vuetom/blog/components/VPAlgoliaSearchBox.vue
Normal 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>
|
||||
81
packages/vuetom/blog/components/VPContent.vue
Normal file
81
packages/vuetom/blog/components/VPContent.vue
Normal 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>
|
||||
156
packages/vuetom/blog/components/VPFlyout.vue
Normal file
156
packages/vuetom/blog/components/VPFlyout.vue
Normal 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>
|
||||
84
packages/vuetom/blog/components/VPFooter.vue
Normal file
84
packages/vuetom/blog/components/VPFooter.vue
Normal 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>
|
||||
38
packages/vuetom/blog/components/VPImage.vue
Normal file
38
packages/vuetom/blog/components/VPImage.vue
Normal 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>
|
||||
38
packages/vuetom/blog/components/VPLink.vue
Normal file
38
packages/vuetom/blog/components/VPLink.vue
Normal 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>
|
||||
74
packages/vuetom/blog/components/VPMenu.vue
Normal file
74
packages/vuetom/blog/components/VPMenu.vue
Normal 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>
|
||||
46
packages/vuetom/blog/components/VPMenuGroup.vue
Normal file
46
packages/vuetom/blog/components/VPMenuGroup.vue
Normal 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>
|
||||
55
packages/vuetom/blog/components/VPMenuLink.vue
Normal file
55
packages/vuetom/blog/components/VPMenuLink.vue
Normal 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>
|
||||
63
packages/vuetom/blog/components/VPSocialLink.vue
Normal file
63
packages/vuetom/blog/components/VPSocialLink.vue
Normal 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>
|
||||
27
packages/vuetom/blog/components/VPSocialLinks.vue
Normal file
27
packages/vuetom/blog/components/VPSocialLinks.vue
Normal 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>
|
||||
87
packages/vuetom/blog/components/VTBackground.vue
Normal file
87
packages/vuetom/blog/components/VTBackground.vue
Normal 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>
|
||||
93
packages/vuetom/blog/components/VTFloat.vue
Normal file
93
packages/vuetom/blog/components/VTFloat.vue
Normal 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>
|
||||
60
packages/vuetom/blog/components/VTHome.vue
Normal file
60
packages/vuetom/blog/components/VTHome.vue
Normal 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>
|
||||
383
packages/vuetom/blog/components/VTLeftButton.vue
Normal file
383
packages/vuetom/blog/components/VTLeftButton.vue
Normal 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>
|
||||
11
packages/vuetom/blog/components/article/VTDoc.vue
Normal file
11
packages/vuetom/blog/components/article/VTDoc.vue
Normal 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>
|
||||
56
packages/vuetom/blog/components/article/VTDocCard.vue
Normal file
56
packages/vuetom/blog/components/article/VTDocCard.vue
Normal 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>
|
||||
|
||||
{{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>
|
||||
18
packages/vuetom/blog/components/article/VTDocList.vue
Normal file
18
packages/vuetom/blog/components/article/VTDocList.vue
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconDiscord.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconDiscord.vue
Normal 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>
|
||||
6
packages/vuetom/blog/components/icons/VPIconEdit.vue
Normal file
6
packages/vuetom/blog/components/icons/VPIconEdit.vue
Normal 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>
|
||||
13
packages/vuetom/blog/components/icons/VPIconExternalLink.vue
Normal file
13
packages/vuetom/blog/components/icons/VPIconExternalLink.vue
Normal 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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconFacebook.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconFacebook.vue
Normal 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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconGitHub.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconGitHub.vue
Normal 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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconHeart.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconHeart.vue
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconLinkedIn.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconLinkedIn.vue
Normal 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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconMinus.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconMinus.vue
Normal 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>
|
||||
@@ -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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconMoon.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconMoon.vue
Normal 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>
|
||||
@@ -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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconPlus.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconPlus.vue
Normal 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>
|
||||
@@ -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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconSlack.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconSlack.vue
Normal 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>
|
||||
13
packages/vuetom/blog/components/icons/VPIconSun.vue
Normal file
13
packages/vuetom/blog/components/icons/VPIconSun.vue
Normal 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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconTwitter.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconTwitter.vue
Normal 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>
|
||||
5
packages/vuetom/blog/components/icons/VPIconYouTube.vue
Normal file
5
packages/vuetom/blog/components/icons/VPIconYouTube.vue
Normal 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>
|
||||
37
packages/vuetom/blog/components/sidebar/VTSidebar.vue
Normal file
37
packages/vuetom/blog/components/sidebar/VTSidebar.vue
Normal 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>
|
||||
76
packages/vuetom/blog/components/sidebar/VTSidebarBottom.vue
Normal file
76
packages/vuetom/blog/components/sidebar/VTSidebarBottom.vue
Normal 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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
24
packages/vuetom/blog/components/sidebar/VTSidebarLink.vue
Normal file
24
packages/vuetom/blog/components/sidebar/VTSidebarLink.vue
Normal 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>
|
||||
28
packages/vuetom/blog/components/sidebar/VTSidebarTop.vue
Normal file
28
packages/vuetom/blog/components/sidebar/VTSidebarTop.vue
Normal 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>
|
||||
66
packages/vuetom/blog/components/switch/VPSwitch.vue
Normal file
66
packages/vuetom/blog/components/switch/VPSwitch.vue
Normal 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>
|
||||
@@ -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>
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
packages/vuetom/blog/fonts/inter-cyrillic-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-cyrillic-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-cyrillic.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-cyrillic.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-greek-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-greek-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-greek.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-greek.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-italic-cyrillic-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-italic-cyrillic-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-italic-cyrillic.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-italic-cyrillic.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-italic-greek-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-italic-greek-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-italic-greek.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-italic-greek.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-italic-latin-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-italic-latin-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-italic-latin.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-italic-latin.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-italic-vietnamese.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-italic-vietnamese.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-latin-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-latin-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-latin.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-latin.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-roman-cyrillic-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-roman-cyrillic-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-roman-cyrillic.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-roman-cyrillic.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-roman-greek-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-roman-greek-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-roman-greek.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-roman-greek.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-roman-latin-ext.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-roman-latin-ext.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-roman-latin.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-roman-latin.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-roman-vietnamese.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-roman-vietnamese.woff2
Normal file
Binary file not shown.
BIN
packages/vuetom/blog/fonts/inter-vietnamese.woff2
Normal file
BIN
packages/vuetom/blog/fonts/inter-vietnamese.woff2
Normal file
Binary file not shown.
32
packages/vuetom/blog/index.ts
Normal file
32
packages/vuetom/blog/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// vitepress
|
||||
import 'vitepress/dist/client/theme-default/styles/fonts.css'
|
||||
import 'vitepress/dist/client/theme-default/styles/vars.css'
|
||||
import 'vitepress/dist/client/theme-default/styles/base.css'
|
||||
import 'vitepress/dist/client/theme-default/styles/utils.css'
|
||||
import 'vitepress/dist/client/theme-default/styles/components/custom-block.css'
|
||||
import 'vitepress/dist/client/theme-default/styles/components/vp-code.css'
|
||||
import 'vitepress/dist/client/theme-default/styles/components/vp-doc.css'
|
||||
import 'vitepress/dist/client/theme-default/styles/components/vp-sponsor.css'
|
||||
|
||||
// common styles
|
||||
import '../styles/index.scss'
|
||||
import '../styles/rewrite/index.scss'
|
||||
|
||||
// icon
|
||||
import '../styles/fa/font-awesome.css'
|
||||
|
||||
// tailwind
|
||||
import '../styles/tailwind/d.css'
|
||||
|
||||
// blog styles
|
||||
import './styles/blog.css'
|
||||
|
||||
import Layout from './layouts/Layout.vue'
|
||||
import NotFound from './layouts/NotFound.vue'
|
||||
|
||||
const BlogTheme = {
|
||||
Layout,
|
||||
NotFound
|
||||
}
|
||||
|
||||
export default BlogTheme
|
||||
114
packages/vuetom/blog/layouts/Layout.vue
Normal file
114
packages/vuetom/blog/layouts/Layout.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<script setup lang="ts">
|
||||
import { provide, onMounted, ref, computed, reactive } from 'vue'
|
||||
import VPNav from 'vitepress/dist/client/theme-default/components/VPNav.vue'
|
||||
// import VPNav from '../components/nav/VPNav.vue'
|
||||
import VTFloat from '../components/VTFloat.vue'
|
||||
import VPContent from '../components/VPContent.vue'
|
||||
import VTBackground from '../components/VTBackground.vue'
|
||||
import type { UseScrollReturn } from '@vueuse/core'
|
||||
import { useScriptTag } from '@vueuse/core'
|
||||
import { vScroll } from '@vueuse/components'
|
||||
import { useSidebar, useCloseSidebarOnEscape } from '../composables/sidebar.js'
|
||||
import { useHomeBg } from '../composables/homebg.js'
|
||||
|
||||
const { bgStyle, bgImgSrc } = useHomeBg()
|
||||
|
||||
const {
|
||||
isOpen: isSidebarOpen,
|
||||
// open: openSidebar,
|
||||
close: closeSidebar,
|
||||
} = useSidebar()
|
||||
|
||||
useCloseSidebarOnEscape(isSidebarOpen, closeSidebar)
|
||||
|
||||
provide('close-sidebar', closeSidebar)
|
||||
|
||||
const renderHomeBackground = () => {
|
||||
// const ds = document.documentElement.style
|
||||
// ds.setProperty('--vt-bg-light', lightStyle)
|
||||
|
||||
const vpHome = document.getElementById('VTLayoutScroll')
|
||||
const hs = vpHome.style
|
||||
hs.backgroundSize = 'cover'
|
||||
hs.backgroundAttachment = 'fixed'
|
||||
hs.backgroundPosition = 'center center'
|
||||
hs.backgroundImage = bgStyle
|
||||
}
|
||||
|
||||
// const handleScroll = () => {
|
||||
// const scrollTop = window.pageYOffset
|
||||
// || document.documentElement.scrollTop
|
||||
// || document.body.scrollTop
|
||||
// if (scrollTop <= 100) navOpacity.value = scrollTop / 100
|
||||
// }
|
||||
|
||||
onMounted(() => {
|
||||
renderHomeBackground()
|
||||
|
||||
// window.addEventListener('scroll', handleScroll)
|
||||
})
|
||||
|
||||
const navOpacity = ref(0)
|
||||
function onScroll(state: UseScrollReturn) {
|
||||
const arrivedTop = state.arrivedState.top
|
||||
const val = state.y.value / 200
|
||||
if (arrivedTop) navOpacity.value = 0
|
||||
else navOpacity.value <= 1 ? (navOpacity.value = val) : 1
|
||||
}
|
||||
|
||||
useScriptTag(
|
||||
'/js/leaf.js',
|
||||
(el: HTMLScriptElement) => {
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="Layout">
|
||||
<slot name="layout-top" />
|
||||
<!-- <VPSkipLink /> -->
|
||||
<!-- <VPBackdrop class="backdrop" :show="isSidebarOpen" @click="closeSidebar" /> -->
|
||||
<VPNav
|
||||
class="transition-opacity duration-1000"
|
||||
:style="[{ opacity: navOpacity }]" />
|
||||
<!-- <VPLocalNav :open="isSidebarOpen" @open-menu="openSidebar" /> -->
|
||||
<!-- <VPSidebar :open="isSidebarOpen" /> -->
|
||||
<div
|
||||
id="VTLayoutScroll"
|
||||
class="h-screen overflow-scroll"
|
||||
v-scroll="[onScroll, { throttle: 10 }]">
|
||||
<VTBackground>
|
||||
<VPContent class="h-full relative z-10" />
|
||||
</VTBackground>
|
||||
</div>
|
||||
|
||||
<!-- <VPContent>
|
||||
<template #home-hero-before><slot name="home-hero-before" /></template>
|
||||
<template #home-hero-after><slot name="home-hero-after" /></template>
|
||||
<template #home-features-before><slot name="home-features-before" /></template>
|
||||
<template #home-features-after><slot name="home-features-after" /></template>
|
||||
|
||||
<template #doc-before><slot name="doc-before" /></template>
|
||||
<template #doc-after><slot name="doc-after" /></template>
|
||||
|
||||
<template #aside-top><slot name="aside-top" /></template>
|
||||
<template #aside-bottom><slot name="aside-bottom" /></template>
|
||||
<template #aside-outline-before><slot name="aside-outline-before" /></template>
|
||||
<template #aside-outline-after><slot name="aside-outline-after" /></template>
|
||||
<template #aside-ads-before><slot name="aside-ads-before" /></template>
|
||||
<template #aside-ads-after><slot name="aside-ads-after" /></template>
|
||||
</VPContent> -->
|
||||
|
||||
<VTFloat />
|
||||
<slot name="layout-bottom" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.Layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
94
packages/vuetom/blog/layouts/NotFound.vue
Normal file
94
packages/vuetom/blog/layouts/NotFound.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<script setup lang="ts">
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
const { site } = useData()
|
||||
|
||||
const msgs = [
|
||||
'There\'s nothing here.',
|
||||
'How did we get here?',
|
||||
'That\'s a Four-Oh-Four.',
|
||||
'Looks like we\'ve got some broken links.'
|
||||
]
|
||||
|
||||
function getMsg() {
|
||||
return msgs[Math.floor(Math.random() * msgs.length)]
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="NotFound">
|
||||
<p class="code">404</p>
|
||||
<h1 class="title">PAGE NOT FOUND</h1>
|
||||
<div class="divider"></div>
|
||||
<blockquote class="quote">
|
||||
{{ getMsg() }}
|
||||
</blockquote>
|
||||
<div class="action">
|
||||
<a class="link" :href="site.base" aria-label="go to home">
|
||||
Take me home
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.NotFound {
|
||||
padding: 64px 24px 96px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.NotFound {
|
||||
padding: 96px 32px 168px;
|
||||
}
|
||||
}
|
||||
|
||||
.code {
|
||||
line-height: 64px;
|
||||
font-size: 64px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.title {
|
||||
padding-top: 12px;
|
||||
letter-spacing: 2px;
|
||||
line-height: 20px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 24px auto 18px;
|
||||
width: 64px;
|
||||
height: 1px;
|
||||
background-color: var(--vp-c-divider)
|
||||
}
|
||||
|
||||
.quote {
|
||||
margin: 0 auto;
|
||||
max-width: 256px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.action {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.link {
|
||||
display: inline-block;
|
||||
border: 1px solid var(--vp-c-brand);
|
||||
border-radius: 16px;
|
||||
padding: 3px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-brand);
|
||||
transition: border-color 0.25s, color .25s;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
border-color: var(--vp-c-brand-dark);
|
||||
color: var(--vp-c-brand-dark);
|
||||
}
|
||||
</style>
|
||||
11
packages/vuetom/blog/shared.ts
Normal file
11
packages/vuetom/blog/shared.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export const EXTERNAL_URL_RE = /^https?:/i
|
||||
export const APPEARANCE_KEY = 'vitepress-theme-appearance'
|
||||
export const inBrowser = typeof window !== 'undefined'
|
||||
export const notFoundPageData = {
|
||||
relativePath: '',
|
||||
title: '404',
|
||||
description: 'Not Found',
|
||||
headers: [],
|
||||
frontmatter: {},
|
||||
lastUpdated: 0
|
||||
}
|
||||
16
packages/vuetom/blog/styles/blog.css
Normal file
16
packages/vuetom/blog/styles/blog.css
Normal file
@@ -0,0 +1,16 @@
|
||||
:root {
|
||||
--vt-radius: 0.5rem;
|
||||
|
||||
/* sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
||||
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
|
||||
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
||||
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
||||
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
||||
'3xl': '0 35px 60px -15px rgba(0, 0, 0, 0.3)',*/
|
||||
/* --vt-shadow: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)'; */
|
||||
/* --vt-shadow: 'none'; */
|
||||
--vt-shadow: 0 35px 60px -15px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
body {
|
||||
cursor: url(https://cdn.jsdelivr.net/gh/sviptzk/HexoStaticFile@latest/Hexo/img/default.cur), default;
|
||||
}
|
||||
42
packages/vuetom/blog/support/sidebar.ts
Normal file
42
packages/vuetom/blog/support/sidebar.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { DefaultTheme } from 'vitepress/theme'
|
||||
import { ensureStartingSlash } from './utils.js'
|
||||
|
||||
/**
|
||||
* Get the `Sidebar` from sidebar option. This method will ensure to get correct
|
||||
* sidebar config from `MultiSideBarConfig` with various path combinations such
|
||||
* as matching `guide/` and `/guide/`. If no matching config was found, it will
|
||||
* return empty array.
|
||||
*/
|
||||
export function getSidebar(
|
||||
sidebar: DefaultTheme.Sidebar,
|
||||
path: string
|
||||
): DefaultTheme.SidebarGroup[] {
|
||||
if (Array.isArray(sidebar)) {
|
||||
return sidebar
|
||||
}
|
||||
|
||||
path = ensureStartingSlash(path)
|
||||
|
||||
for (const dir in sidebar) {
|
||||
// make sure the multi sidebar key starts with slash too
|
||||
if (path.startsWith(ensureStartingSlash(dir))) {
|
||||
return sidebar[dir]
|
||||
}
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export function getFlatSideBarLinks(
|
||||
sidebar: DefaultTheme.SidebarGroup[]
|
||||
): DefaultTheme.SidebarItem[] {
|
||||
const links: DefaultTheme.SidebarItem[] = []
|
||||
|
||||
for (const group of sidebar) {
|
||||
for (const link of group.items) {
|
||||
links.push(link)
|
||||
}
|
||||
}
|
||||
|
||||
return links
|
||||
}
|
||||
90
packages/vuetom/blog/support/utils.ts
Normal file
90
packages/vuetom/blog/support/utils.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
/** @format */
|
||||
|
||||
import { ref } from 'vue'
|
||||
import { withBase } from 'vitepress'
|
||||
import { EXTERNAL_URL_RE } from '../shared.js'
|
||||
|
||||
export const HASH_RE = /#.*$/
|
||||
export const EXT_RE = /(index)?\.(md|html)$/
|
||||
|
||||
const inBrowser = typeof window !== 'undefined'
|
||||
const hashRef = ref(inBrowser ? location.hash : '')
|
||||
|
||||
export function isExternal(path: string): boolean {
|
||||
return EXTERNAL_URL_RE.test(path)
|
||||
}
|
||||
|
||||
export function throttleAndDebounce(fn: () => void, delay: number): () => void {
|
||||
let timeout: any
|
||||
let called = false
|
||||
|
||||
return () => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
|
||||
if (!called) {
|
||||
fn()
|
||||
called = true
|
||||
setTimeout(() => {
|
||||
called = false
|
||||
}, delay)
|
||||
} else {
|
||||
timeout = setTimeout(fn, delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isActive(
|
||||
currentPath: string,
|
||||
matchPath?: string,
|
||||
asRegex: boolean = false
|
||||
): boolean {
|
||||
if (matchPath === undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
currentPath = normalize(`/${currentPath}`)
|
||||
|
||||
if (asRegex) {
|
||||
return new RegExp(matchPath).test(currentPath)
|
||||
}
|
||||
|
||||
if (normalize(matchPath) !== currentPath) {
|
||||
return false
|
||||
}
|
||||
|
||||
const hashMatch = matchPath.match(HASH_RE)
|
||||
|
||||
if (hashMatch) {
|
||||
return hashRef.value === hashMatch[0]
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export function ensureStartingSlash(path: string): string {
|
||||
return /^\//.test(path) ? path : `/${path}`
|
||||
}
|
||||
|
||||
export function normalize(path: string): string {
|
||||
return decodeURI(path).replace(HASH_RE, '').replace(EXT_RE, '')
|
||||
}
|
||||
|
||||
export function normalizeLink(url: string): string {
|
||||
if (isExternal(url)) {
|
||||
return url
|
||||
}
|
||||
|
||||
const { pathname, search, hash } = new URL(url, 'http://example.com')
|
||||
|
||||
const normalizedPath = pathname.endsWith('/') || pathname.endsWith('.html')
|
||||
? url
|
||||
: `${pathname.replace(/(\.md)?$/, '.html')}${search}${hash}`
|
||||
|
||||
return withBase(normalizedPath)
|
||||
}
|
||||
|
||||
export function fmt(inputTime: string) {
|
||||
return inputTime.replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
|
||||
}
|
||||
82
packages/vuetom/doc/components/VTLayout.vue
Normal file
82
packages/vuetom/doc/components/VTLayout.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, watch, nextTick } from 'vue'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { useData, useRoute } from 'vitepress'
|
||||
import {
|
||||
useFlash,
|
||||
useBackground,
|
||||
useFeatures,
|
||||
useHeroMove,
|
||||
} from '../composables/home.js'
|
||||
|
||||
const { Layout } = DefaultTheme
|
||||
// const route = useRoute()
|
||||
const { site, theme } = useData()
|
||||
const { base} = site.value
|
||||
const { logoImg } = theme.value
|
||||
const { flashEnable, flashStyle } = useFlash()
|
||||
const { bgEnable, bgStyle } = useBackground()
|
||||
const { ftStyle } = useFeatures()
|
||||
const { parallaxEnable, heroMove } = useHeroMove()
|
||||
|
||||
const pageBgEnable = theme.value.pageBgEnable || true
|
||||
const pageBgOpacity = theme.value.pageBgOpacity || 0.8
|
||||
|
||||
const logoSrc = `${base}${logoImg}`.replaceAll('//', '/')
|
||||
|
||||
const renderHomeBg = () => {
|
||||
const domStyle = document.documentElement.style
|
||||
// 首页闪烁动画样式设置
|
||||
if (flashEnable && flashStyle) {
|
||||
domStyle.setProperty('--vt-bg-light', flashStyle)
|
||||
}
|
||||
// 文章背景图设置
|
||||
if (pageBgEnable && pageBgOpacity) {
|
||||
domStyle.setProperty('--vt-bg-doc', `rgba(var(--vt-c-bg-rgb), ${pageBgOpacity})`)
|
||||
}
|
||||
// 首页背景图设置
|
||||
if (bgEnable && bgStyle) {
|
||||
domStyle.setProperty('--vt-bg-content', bgStyle)
|
||||
}
|
||||
if (ftStyle) {
|
||||
const vpFeat: any = document.getElementsByClassName('VPFeatures')[0]
|
||||
const fs = vpFeat?.style
|
||||
if (fs) fs.background = ftStyle
|
||||
}
|
||||
}
|
||||
|
||||
// const checkPath = (path: string) => {
|
||||
// const homePaths = [base, `${base}index.html`, `${base}${lang}/`]
|
||||
// const isHome = homePaths.includes(path)
|
||||
// if (isHome) {
|
||||
// nextTick(() => {
|
||||
// renderHomeBg()
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// watch(
|
||||
// () => route.path,
|
||||
// (path) => {
|
||||
// checkPath(path)
|
||||
// }
|
||||
// )
|
||||
|
||||
onMounted(() => {
|
||||
renderHomeBg()
|
||||
if (parallaxEnable) window.addEventListener('mousemove', heroMove)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (parallaxEnable) window.removeEventListener('mousemove', heroMove)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Layout>
|
||||
<template #home-hero-before>
|
||||
<img class="VPHeroLogo" :src="logoSrc" />
|
||||
<slot name="home-hero-before" />
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
144
packages/vuetom/doc/composables/home.ts
Normal file
144
packages/vuetom/doc/composables/home.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
export function useFlash() {
|
||||
const { site, theme } = useData()
|
||||
const { base } = site.value
|
||||
let { flashEnable, flashColor, bgImg } = theme.value
|
||||
if (flashColor === undefined) flashColor = ['0,0,0', '0,0,0']
|
||||
if (typeof flashColor === 'string') flashColor = [flashColor, flashColor]
|
||||
let flashStyle = ''
|
||||
|
||||
if (bgImg && flashEnable) {
|
||||
const bgImgSrc = (`${base}${bgImg}`).replaceAll('//', '/')
|
||||
flashStyle = `
|
||||
-webkit-linear-gradient(top,
|
||||
rgba(${flashColor[0]}, 0.8) 0%,
|
||||
rgba(${flashColor[0]}, 0.2) 20%,
|
||||
rgba(${flashColor[0]}, 0) 80%,
|
||||
rgba(${flashColor[0]}, 0) 100%
|
||||
),
|
||||
-webkit-linear-gradient(left,
|
||||
rgba(${flashColor[1]}, 0) 0%,
|
||||
rgba(${flashColor[1]}, 0) 20%,
|
||||
rgba(${flashColor[1]}, 0.2) 80%,
|
||||
rgba(${flashColor[1]}, 0.8) 100%),
|
||||
url(${bgImgSrc})
|
||||
`
|
||||
}
|
||||
|
||||
return {
|
||||
flashEnable,
|
||||
flashStyle,
|
||||
}
|
||||
}
|
||||
|
||||
export function useBackground() {
|
||||
const { site, theme } = useData()
|
||||
const { base } = site.value
|
||||
let { bgImg, bgColor, bgOpacity } = theme.value
|
||||
let bgEnable = false
|
||||
let bgStyle = ''
|
||||
let bgInnerOpacity = 0.3
|
||||
if (bgImg) bgEnable = true
|
||||
if (bgColor === undefined) bgColor = '0,0,0'
|
||||
if (bgOpacity === undefined) bgOpacity = 0.6
|
||||
bgInnerOpacity = bgOpacity - 0.3 <= 0 ? 0 : bgOpacity - 0.3
|
||||
if (bgEnable) {
|
||||
const bgImgSrc = (`${base}${bgImg}`).replaceAll('//', '/')
|
||||
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 {
|
||||
bgEnable,
|
||||
bgStyle,
|
||||
}
|
||||
}
|
||||
|
||||
export function useFeatures() {
|
||||
const { theme } = useData()
|
||||
let { featuresColor } = theme.value
|
||||
let ftStyle = 'rgba(255,255,255,0.8)'
|
||||
if (typeof featuresColor === 'string') {
|
||||
ftStyle = featuresColor
|
||||
} else if (typeof featuresColor === 'object') {
|
||||
if (featuresColor.length >= 2) {
|
||||
ftStyle = `
|
||||
linear-gradient(to right,
|
||||
${featuresColor[0]},
|
||||
${featuresColor[1]}
|
||||
)
|
||||
`
|
||||
}
|
||||
}
|
||||
return {
|
||||
ftStyle,
|
||||
}
|
||||
}
|
||||
|
||||
export function useHeroMove() {
|
||||
const { theme } = useData()
|
||||
const { parallaxEnable } = theme.value
|
||||
function heroMove(e: any) {
|
||||
document
|
||||
.querySelectorAll(
|
||||
`
|
||||
.VPHomeHero .name,
|
||||
.VPHomeHero .text,
|
||||
.VPHomeHero .tagline,
|
||||
.VPHomeHero .VPButton,
|
||||
.VPHome .VPHomeFeatures
|
||||
`
|
||||
)
|
||||
.forEach((h: Element) => {
|
||||
const hd: any = h
|
||||
const speed: any = hd.getAttribute('data-speed') || 10
|
||||
let x = (window.innerWidth - e.pageX * speed) / 100
|
||||
let y = (window.innerHeight - e.pageY * speed) / 100
|
||||
switch (hd.className.substring(0, 3).toUpperCase()) {
|
||||
case 'VPF':
|
||||
x /= 8
|
||||
y /= 8
|
||||
break
|
||||
case 'TAG':
|
||||
x /= 6
|
||||
y /= 6
|
||||
break
|
||||
case 'TEX':
|
||||
x /= 4
|
||||
y /= 4
|
||||
break
|
||||
case 'VPB':
|
||||
x /= 2
|
||||
y /= 2
|
||||
break
|
||||
case 'NAM':
|
||||
x /= 1
|
||||
y /= 1
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
const hds = hd?.style
|
||||
if (hds) {
|
||||
hds.transform = `translateX(${x}px) translateY(${y}px)`
|
||||
hds.transition = 'transform 0.2s ease-out'
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
parallaxEnable,
|
||||
heroMove,
|
||||
}
|
||||
}
|
||||
18
packages/vuetom/doc/index.ts
Normal file
18
packages/vuetom/doc/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
// vitepress styles ==> /dist/client/theme-default/styles
|
||||
import vitepressTheme from 'vitepress/theme'
|
||||
|
||||
// for dev (prod should import .css)
|
||||
import '../styles/index.scss'
|
||||
import '../styles/rewrite/index.scss'
|
||||
|
||||
import { Theme } from 'vitepress'
|
||||
import VTLayout from './components/VTLayout.vue'
|
||||
|
||||
const DocsTheme: Theme = {
|
||||
...vitepressTheme,
|
||||
Layout: VTLayout
|
||||
}
|
||||
|
||||
export * from 'vitepress/theme'
|
||||
|
||||
export default DocsTheme
|
||||
5
packages/vuetom/docs.d.ts
vendored
Normal file
5
packages/vuetom/docs.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { Theme } from 'vitepress'
|
||||
|
||||
declare const DocsTheme: Theme
|
||||
export * from 'vitepress/theme'
|
||||
export default DocsTheme
|
||||
99
packages/vuetom/gulpfile.ts
Normal file
99
packages/vuetom/gulpfile.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import path from 'path'
|
||||
import {
|
||||
src, dest, series, parallel
|
||||
} from 'gulp'
|
||||
import gulpSass from 'gulp-sass'
|
||||
import dartSass from 'sass'
|
||||
import autoprefixer from 'gulp-autoprefixer'
|
||||
import cleanCSS from 'gulp-clean-css'
|
||||
import rename from 'gulp-rename'
|
||||
|
||||
const distFolder = path.resolve(__dirname, './dist/styles')
|
||||
const distRewriteFolder = path.resolve(__dirname, './dist/styles/rewrite')
|
||||
|
||||
function buildRewriteStyles() {
|
||||
const sass = gulpSass(dartSass)
|
||||
const noPrefixFile = /(index|main)/
|
||||
return src(path.resolve(__dirname, 'styles/rewrite/*.scss'))
|
||||
.pipe(sass.sync())
|
||||
.pipe(
|
||||
autoprefixer({
|
||||
cascade: true // 是否美化属性值 默认 true
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
cleanCSS(
|
||||
{
|
||||
compatibility: 'ie9', // 压缩兼容模式IE9
|
||||
format: 'beautify'
|
||||
},
|
||||
(details) => {
|
||||
console.log(
|
||||
`${details.name}: ${details.stats.originalSize / 1000} KB -> ${
|
||||
details.stats.minifiedSize / 1000
|
||||
} KB`
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
.pipe(
|
||||
rename((file) => {
|
||||
if (!noPrefixFile.test(file.basename)) {
|
||||
file.basename = `vt-${file.basename}`
|
||||
}
|
||||
})
|
||||
)
|
||||
.pipe(dest(distRewriteFolder))
|
||||
}
|
||||
|
||||
function buildCommonStyles() {
|
||||
const sass = gulpSass(dartSass)
|
||||
const noPrefixFile = /(index|main)/
|
||||
return src(path.resolve(__dirname, 'styles/*.scss'))
|
||||
.pipe(sass.sync())
|
||||
.pipe(autoprefixer({ cascade: true }))
|
||||
.pipe(
|
||||
cleanCSS(
|
||||
{
|
||||
compatibility: 'ie9',
|
||||
format: 'beautify'
|
||||
},
|
||||
(details) => {
|
||||
console.log(
|
||||
`${details.name}: ${details.stats.originalSize / 1000} KB -> ${
|
||||
details.stats.minifiedSize / 1000
|
||||
} KB`
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
.pipe(
|
||||
rename((file) => {
|
||||
if (!noPrefixFile.test(file.basename)) {
|
||||
file.basename = `vt-${file.basename}`
|
||||
}
|
||||
})
|
||||
)
|
||||
.pipe(dest(distFolder))
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动图标、字体、tailwind样式文件至dist对应目录下
|
||||
*/
|
||||
function copyOtherResource() {
|
||||
return src([
|
||||
path.resolve(__dirname, 'styles/fa'),
|
||||
path.resolve(__dirname, 'styles/fonts'),
|
||||
path.resolve(__dirname, 'styles/tailwind')
|
||||
]).pipe(
|
||||
dest(distFolder)
|
||||
)
|
||||
}
|
||||
|
||||
export const build = parallel(
|
||||
buildRewriteStyles,
|
||||
buildCommonStyles,
|
||||
copyOtherResource
|
||||
)
|
||||
|
||||
export default build
|
||||
4
packages/vuetom/index.ts
Normal file
4
packages/vuetom/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import DocsTheme from './doc/index.js'
|
||||
|
||||
export * from './doc/index.js'
|
||||
export default DocsTheme
|
||||
82
packages/vuetom/package.json
Normal file
82
packages/vuetom/package.json
Normal file
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "vitepress-theme-vuetom",
|
||||
"version": "2.3.0",
|
||||
"description": "A Vitepress Theme, Have blog and document styles",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@7.9.0",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./dist/*": "./dist/*",
|
||||
"./package.json": "./package.json",
|
||||
"./docs": {
|
||||
"types": "./docs.d.ts",
|
||||
"default": "./dist/doc/index.js"
|
||||
},
|
||||
"./blog": {
|
||||
"types": "./blog.d.ts",
|
||||
"default": "./dist/blog/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"pub": "npm publish",
|
||||
"clean": "rimraf ./dist",
|
||||
"build": "pnpm clean && pnpm tailwind:css && pnpm build:scss && pnpm build:vt",
|
||||
"build:vt": "tsc -p . && cross-env NODE_ENV=build node ../../scripts/build-vt",
|
||||
"build:scss": "gulp --require @esbuild-kit/cjs-loader -f gulpfile.ts",
|
||||
"tailwind:css": "npx tailwindcss -i ./styles/tailwind/s.css -o ./styles/tailwind/d.css",
|
||||
"tailwind:watch": "npx tailwindcss -i ./styles/tailwind/s.css -o ./styles/tailwind/d.css --watch"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"types",
|
||||
"blog.d.ts",
|
||||
"docs.d.ts",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"keywords": [
|
||||
"vitepress",
|
||||
"theme"
|
||||
],
|
||||
"author": "lauset",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lauset/vitepress-theme-vuetom.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/lauset/vitepress-theme-vuetom/issues"
|
||||
},
|
||||
"homepage": "https://github.com/lauset/vitepress-theme-vuetom#readme",
|
||||
"devDependencies": {
|
||||
"@esbuild-kit/cjs-loader": "^2.2.1",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"postcss": "^8.4.19",
|
||||
"tailwindcss": "^3.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docsearch/css": "^3.3.0",
|
||||
"@docsearch/js": "^3.3.0",
|
||||
"@vueuse/components": "^9.6.0",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"body-scroll-lock": "^4.0.0-beta.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"shiki": "^0.11.1",
|
||||
"vite": "^3.2.5",
|
||||
"vitepress": "1.0.0-alpha.30",
|
||||
"vue": "^3.2.45"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vitepress": "1.0.0-alpha.30"
|
||||
}
|
||||
}
|
||||
7
packages/vuetom/postcss.config.cjs
Normal file
7
packages/vuetom/postcss.config.cjs
Normal file
@@ -0,0 +1,7 @@
|
||||
/* eslint-disable global-require */
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('postcss-import'),
|
||||
require('tailwindcss')
|
||||
]
|
||||
}
|
||||
136
packages/vuetom/styles/code-vt.scss
Normal file
136
packages/vuetom/styles/code-vt.scss
Normal file
@@ -0,0 +1,136 @@
|
||||
/** code macos */
|
||||
div[class*='language-'] {
|
||||
&.macos,&.light {
|
||||
margin: 0 0 24px;
|
||||
border-radius: 7px;
|
||||
box-shadow: var(--vp-shadow-4);
|
||||
&:hover {
|
||||
.line-numbers-wrapper {
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 600;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.line-numbers-wrapper {
|
||||
padding-top: 40px;
|
||||
width: 32px;
|
||||
border-right: 0px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
&::before {
|
||||
position: initial;
|
||||
display: block;
|
||||
color: var(--vp-c-text-2);
|
||||
background: var(--vp-c-bg-soft);
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: #fc625d;
|
||||
-webkit-box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
|
||||
box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
|
||||
content: ' ';
|
||||
}
|
||||
pre {
|
||||
code {
|
||||
padding-left: 32px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.token.comment,
|
||||
.token.block-comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #747474;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #743c3c;
|
||||
}
|
||||
|
||||
.token.tag,
|
||||
.token.attr-name,
|
||||
.token.namespace,
|
||||
.token.deleted {
|
||||
color: #e2777a;
|
||||
}
|
||||
|
||||
.token.function-name {
|
||||
color: #1a5997;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.function {
|
||||
color: #af4b09;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.class-name,
|
||||
.token.constant,
|
||||
.token.symbol {
|
||||
color: #a0710b;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.important,
|
||||
.token.atrule,
|
||||
.token.keyword,
|
||||
.token.builtin {
|
||||
color: #a241a3;
|
||||
}
|
||||
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.attr-value,
|
||||
.token.regex,
|
||||
.token.variable {
|
||||
color: #1e8545;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url {
|
||||
color: #168d8b;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
}
|
||||
.dark {
|
||||
div[class*='language-'] {
|
||||
&.macos {
|
||||
&::before {
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
.lang {
|
||||
background-color: transparent;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
260
packages/vuetom/styles/code.scss
Normal file
260
packages/vuetom/styles/code.scss
Normal file
@@ -0,0 +1,260 @@
|
||||
/** code default */
|
||||
|
||||
code .token.deleted {
|
||||
color: #ec5975;
|
||||
}
|
||||
|
||||
code .token.inserted {
|
||||
color: var(--c-brand);
|
||||
}
|
||||
|
||||
div[class*='language-'] {
|
||||
position: relative;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
transition: color 0.5s;
|
||||
border: 2px solid transparent;
|
||||
overflow-x: auto;
|
||||
.line-numbers-wrapper {
|
||||
border-right: 2px solid var(--vp-c-brand);
|
||||
transition: opacity 0.5s;
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
div[class*='language-']:hover {
|
||||
border: 2px solid var(--vp-c-brand);
|
||||
.line-numbers-wrapper {
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 600;
|
||||
opacity: 1;
|
||||
}
|
||||
&::before {
|
||||
opacity: 0;
|
||||
}
|
||||
&::after {
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
div[class*='language-']::after {
|
||||
content: '';
|
||||
height: 5px;
|
||||
width: 0;
|
||||
background: var(--vp-c-brand);
|
||||
transition: all 0.5s;
|
||||
opacity: 0.3;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div[class*='language-']::before {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
font-size: 0.8rem;
|
||||
color: #888;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
transition: opacity 0.5s;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dark {
|
||||
div[class*='language-'] {
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 420px) {
|
||||
div[class*='language-'] {
|
||||
margin: 1rem 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
li > div[class*='language-'] {
|
||||
margin: 1rem 0 1rem 0rem;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
div[class~='language-html']:before,
|
||||
div[class~='language-markup']:before {
|
||||
content: 'html';
|
||||
}
|
||||
|
||||
div[class~='language-md']:before,
|
||||
div[class~='language-markdown']:before {
|
||||
content: 'md';
|
||||
}
|
||||
|
||||
div[class~='language-css']:before {
|
||||
content: 'css';
|
||||
}
|
||||
|
||||
div[class~='language-sass']:before {
|
||||
content: 'sass';
|
||||
}
|
||||
|
||||
div[class~='language-scss']:before {
|
||||
content: 'scss';
|
||||
}
|
||||
|
||||
div[class~='language-less']:before {
|
||||
content: 'less';
|
||||
}
|
||||
|
||||
div[class~='language-stylus']:before {
|
||||
content: 'styl';
|
||||
}
|
||||
|
||||
div[class~='language-js']:before,
|
||||
div[class~='language-javascript']:before {
|
||||
content: 'js';
|
||||
}
|
||||
|
||||
div[class~='language-ts']:before,
|
||||
div[class~='language-typescript']:before {
|
||||
content: 'ts';
|
||||
}
|
||||
|
||||
div[class~='language-json']:before {
|
||||
content: 'json';
|
||||
}
|
||||
|
||||
div[class~='language-rb']:before,
|
||||
div[class~='language-ruby']:before {
|
||||
content: 'rb';
|
||||
}
|
||||
|
||||
div[class~='language-py']:before,
|
||||
div[class~='language-python']:before {
|
||||
content: 'py';
|
||||
}
|
||||
|
||||
div[class~='language-sh']:before,
|
||||
div[class~='language-bash']:before {
|
||||
content: 'sh';
|
||||
}
|
||||
|
||||
div[class~='language-php']:before {
|
||||
content: 'php';
|
||||
}
|
||||
|
||||
div[class~='language-go']:before {
|
||||
content: 'go';
|
||||
}
|
||||
|
||||
div[class~='language-rust']:before {
|
||||
content: 'rust';
|
||||
}
|
||||
|
||||
div[class~='language-java']:before {
|
||||
content: 'java';
|
||||
}
|
||||
|
||||
div[class~='language-c']:before {
|
||||
content: 'c';
|
||||
}
|
||||
|
||||
div[class~='language-yaml']:before {
|
||||
content: 'yaml';
|
||||
}
|
||||
|
||||
div[class~='language-dockerfile']:before {
|
||||
content: 'dockerfile';
|
||||
}
|
||||
|
||||
div[class~='language-vue']:before {
|
||||
content: 'vue';
|
||||
}
|
||||
|
||||
/**
|
||||
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML.
|
||||
* Based on https://github.com/chriskempson/tomorrow-theme
|
||||
*
|
||||
* @author Rose Pritchard
|
||||
*/
|
||||
.token.comment,
|
||||
.token.block-comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.token.tag,
|
||||
.token.attr-name,
|
||||
.token.namespace,
|
||||
.token.deleted {
|
||||
color: #e2777a;
|
||||
}
|
||||
|
||||
.token.function-name {
|
||||
color: #6196cc;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.function {
|
||||
color: #f08d49;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.class-name,
|
||||
.token.constant,
|
||||
.token.symbol {
|
||||
color: #f8c555;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.important,
|
||||
.token.atrule,
|
||||
.token.keyword,
|
||||
.token.builtin {
|
||||
color: #cc99cd;
|
||||
}
|
||||
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.attr-value,
|
||||
.token.regex,
|
||||
.token.variable {
|
||||
color: #7ec699;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url {
|
||||
color: #67cdcc;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: green;
|
||||
}
|
||||
|
||||
/* pre code */
|
||||
|
||||
.container pre {
|
||||
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
padding: 15px;
|
||||
margin-bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
78
packages/vuetom/styles/colors.scss
Normal file
78
packages/vuetom/styles/colors.scss
Normal file
@@ -0,0 +1,78 @@
|
||||
:root {
|
||||
|
||||
/**
|
||||
* Base Colors
|
||||
* --------------------------------------------------------------------- */
|
||||
|
||||
--c-white-rgb: 255,255,255;
|
||||
--c-black-rgb: 0,0,0;
|
||||
|
||||
--c-white: #ffffff;
|
||||
--c-white-dark: #f8f8f8;
|
||||
--c-black: #000000;
|
||||
|
||||
--c-divider-light: rgba(60, 60, 67, 0.12);
|
||||
--c-divider-dark: rgba(84, 84, 88, 0.48);
|
||||
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f9f9f9;
|
||||
--vt-c-white-mute: #f1f1f1;
|
||||
|
||||
--vt-c-black: #1a1a1a;
|
||||
--vt-c-black-pure: #000000;
|
||||
--vt-c-black-soft: #242424;
|
||||
--vt-c-black-mute: #2f2f2f;
|
||||
|
||||
--vt-c-indigo: #213547;
|
||||
--vt-c-indigo-soft: #476582;
|
||||
--vt-c-indigo-light: #aac8e4;
|
||||
|
||||
--vt-c-gray: #8e8e8e;
|
||||
--vt-c-gray-light-1: #aeaeae;
|
||||
--vt-c-gray-light-2: #c7c7c7;
|
||||
--vt-c-gray-light-3: #d1d1d1;
|
||||
--vt-c-gray-light-4: #e5e5e5;
|
||||
--vt-c-gray-light-5: #f2f2f2;
|
||||
--vt-c-gray-dark-1: #636363;
|
||||
--vt-c-gray-dark-2: #484848;
|
||||
--vt-c-gray-dark-3: #3a3a3a;
|
||||
--vt-c-gray-dark-4: #282828;
|
||||
--vt-c-gray-dark-5: #202020;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.70);
|
||||
--vt-c-text-light-3: rgba(60, 60, 60, 0.33);
|
||||
--vt-c-text-light-4: rgba(60, 60, 60, 0.18);
|
||||
--vt-c-text-light-code: var(--vt-c-indigo-soft);
|
||||
|
||||
--vt-c-text-dark-1: rgba(255, 255, 255, 0.87);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.60);
|
||||
--vt-c-text-dark-3: rgba(235, 235, 235, 0.38);
|
||||
--vt-c-text-dark-4: rgba(235, 235, 235, 0.18);
|
||||
--vt-c-text-dark-code: var(--vt-c-indigo-light);
|
||||
|
||||
--vp-c-blue: #16a0db;
|
||||
--vp-c-blue-light: #25beff;
|
||||
--vp-c-blue-lighter: #5cceff;
|
||||
--vp-c-blue-dark: #198aba;
|
||||
--vp-c-blue-darker: #13678a;
|
||||
--vp-c-blue-dimm-1: rgba(66, 145, 184, 0.5);
|
||||
--vp-c-blue-dimm-2: rgba(66, 145, 184, 0.4);
|
||||
--vp-c-blue-dimm-3: rgba(66, 145, 184, 0.3);
|
||||
--vp-c-blue-dimm-4: rgba(66, 147, 184, 0.2);
|
||||
--vp-c-blue-dimm-5: rgba(66, 139, 184, 0.1);
|
||||
|
||||
--vp-c-pink: #e44a8a;
|
||||
--vp-c-pink-light: #f962a1;
|
||||
--vp-c-pink-lighter: #ff91bf;
|
||||
--vp-c-pink-dark: #b31858;
|
||||
--vp-c-pink-darker: #720e37;
|
||||
--vp-c-pink-dimm-1: rgba(184, 66, 127, 0.5);
|
||||
--vp-c-pink-dimm-2: rgba(184, 66, 100, 0.25);
|
||||
--vp-c-pink-dimm-3: rgba(184, 66, 113, 0.05);
|
||||
}
|
||||
58
packages/vuetom/styles/custom-blocks.scss
Normal file
58
packages/vuetom/styles/custom-blocks.scss
Normal file
@@ -0,0 +1,58 @@
|
||||
:root {
|
||||
// custom-block.tip
|
||||
--vp-custom-block-tip-border: var(--vp-c-brand-light);
|
||||
--vp-custom-block-tip-text: var(--vp-c-brand);
|
||||
--vp-custom-block-tip-bg: transparent;
|
||||
// custom-block.warning
|
||||
--vp-custom-block-warning-border: #b99a02;
|
||||
--vp-custom-block-warning-text: #b49704;
|
||||
--vp-custom-block-warning-bg: #e7c00010;
|
||||
// custom-block.danger
|
||||
--vp-custom-block-danger-border: #b90e0e;
|
||||
--vp-custom-block-danger-text: #cf0b0b;
|
||||
--vp-custom-block-danger-bg: #cc000010;
|
||||
// custom-block.info
|
||||
--vp-custom-block-info-border: #05b640;
|
||||
--vp-custom-block-info-text: #05b740;
|
||||
--vp-custom-block-info-bg: #06ce4910;
|
||||
}
|
||||
|
||||
.custom-block.tip,
|
||||
.custom-block.info,
|
||||
.custom-block.warning,
|
||||
.custom-block.danger {
|
||||
margin: 1rem 0;
|
||||
border-width: 2px;
|
||||
border-left: 0.5rem solid;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 1.3rem;
|
||||
overflow-x: auto;
|
||||
&:hover {
|
||||
transition: all 0.5s;
|
||||
box-shadow: var(--vp-shadow-4);
|
||||
border-left: 2px solid;
|
||||
}
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
.custom-block-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-block.details {
|
||||
margin: 1rem 0;
|
||||
border-width: 2px;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 1.3rem;
|
||||
summary {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.custom-block.tip {
|
||||
background-color: #23232380;
|
||||
}
|
||||
}
|
||||
2337
packages/vuetom/styles/fa/font-awesome.css
vendored
Normal file
2337
packages/vuetom/styles/fa/font-awesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user