mirror of
https://github.com/PaiGramTeam/PaiGramDocs.git
synced 2024-11-22 07:07:47 +00:00
📝 Add quick-start env
This commit is contained in:
parent
fbc8bfb2cc
commit
2c48ede0be
9
.eslintignore
Normal file
9
.eslintignore
Normal file
@ -0,0 +1,9 @@
|
||||
dist/
|
||||
node_modules
|
||||
node_modules/
|
||||
types/
|
||||
cache/
|
||||
!docs/.vitepress
|
||||
!/.eslintrc.js
|
||||
!.test
|
||||
.temp
|
65
.eslintrc.cjs
Normal file
65
.eslintrc.cjs
Normal file
@ -0,0 +1,65 @@
|
||||
const restricted = [
|
||||
'..',
|
||||
'../..',
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
extends: '@antfu',
|
||||
rules: {
|
||||
'vue/no-deprecated-functional-template': 'off',
|
||||
'vue/one-component-per-file': 'off',
|
||||
'vue/no-template-shadow': 'off',
|
||||
'vue/require-prop-types': 'off',
|
||||
'spaced-comment': ['error', 'always', { exceptions: ['#__PURE__'] }],
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: restricted,
|
||||
},
|
||||
],
|
||||
'node/no-callback-literal': 'off',
|
||||
'import/namespace': 'off',
|
||||
'import/default': 'off',
|
||||
'import/no-named-as-default': 'off',
|
||||
'import/no-named-as-default-member': 'off',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.md', '**/*.md/*.*', 'demo.vue', 'demo.client.vue', 'scripts/*.ts', '*.test.ts', 'utils.ts'],
|
||||
rules: {
|
||||
'no-alert': 'off',
|
||||
'no-console': 'off',
|
||||
'no-undef': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'no-restricted-imports': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'off',
|
||||
'@typescript-eslint/no-invalid-this': 'off',
|
||||
'unused-imports/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-this-alias': [
|
||||
'error',
|
||||
{
|
||||
allowedNames: ['self', 'instance'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['docs/.vitepress/**/*.*'],
|
||||
rules: {
|
||||
'no-restricted-imports': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['docs/.vitepress/theme/plugins/**/*.*'],
|
||||
rules: {
|
||||
'prefer-rest-params': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
.vitepress/dist
|
||||
.vitepress/cache
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
node_modules/
|
||||
|
@ -1,28 +0,0 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "GramBot",
|
||||
description: "Telegram robot, query the official game information",
|
||||
themeConfig: {
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'Examples', link: '/markdown-examples' }
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Examples',
|
||||
items: [
|
||||
{ text: 'Markdown Examples', link: '/markdown-examples' },
|
||||
{ text: 'Runtime API Examples', link: '/api-examples' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
||||
]
|
||||
}
|
||||
})
|
@ -1,49 +0,0 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# Runtime API Examples
|
||||
|
||||
This page demonstrates usage of some of the runtime APIs provided by VitePress.
|
||||
|
||||
The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
|
||||
|
||||
```md
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
const { theme, page, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
## Results
|
||||
|
||||
### Theme Data
|
||||
<pre>{{ theme }}</pre>
|
||||
|
||||
### Page Data
|
||||
<pre>{{ page }}</pre>
|
||||
|
||||
### Page Frontmatter
|
||||
<pre>{{ frontmatter }}</pre>
|
||||
```
|
||||
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
const { site, theme, page, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
## Results
|
||||
|
||||
### Theme Data
|
||||
<pre>{{ theme }}</pre>
|
||||
|
||||
### Page Data
|
||||
<pre>{{ page }}</pre>
|
||||
|
||||
### Page Frontmatter
|
||||
<pre>{{ frontmatter }}</pre>
|
||||
|
||||
## More
|
||||
|
||||
Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).
|
23
docs/.vitepress/components.d.ts
vendored
Normal file
23
docs/.vitepress/components.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
Badge: typeof import('./theme/components/Badge.vue')['default']
|
||||
'Bi:fileEarmarkWordFill': typeof import('~icons/bi/file-earmark-word-fill')['default']
|
||||
Card: typeof import('./theme/components/Card.vue')['default']
|
||||
ChatMessage: typeof import('./theme/components/ChatMessage.vue')['default']
|
||||
ChatPanel: typeof import('./theme/components/ChatPanel.vue')['default']
|
||||
CopyRight: typeof import('./theme/components/CopyRight.vue')['default']
|
||||
DataPanel: typeof import('./theme/components/DataPanel.vue')['default']
|
||||
HomeContributors: typeof import('./theme/components/HomeContributors.vue')['default']
|
||||
NavCard: typeof import('./theme/components/NavCard.vue')['default']
|
||||
'Ooui:clock': typeof import('~icons/ooui/clock')['default']
|
||||
PageInfo: typeof import('./theme/components/PageInfo.vue')['default']
|
||||
VideoLink: typeof import('./theme/components/VideoLink.vue')['default']
|
||||
}
|
||||
}
|
87
docs/.vitepress/config.ts
Normal file
87
docs/.vitepress/config.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
import { withPwa } from '@vite-pwa/vitepress'
|
||||
import { description, docsVersion, github, keywords, name, site } from './meta'
|
||||
import { pwa } from './plugins/pwa'
|
||||
import sidebar from './sidebar'
|
||||
import socialLinks from './link'
|
||||
|
||||
export default withPwa(defineConfig({
|
||||
pwa,
|
||||
outDir: '../dist',
|
||||
title: name,
|
||||
description,
|
||||
appearance: true,
|
||||
lastUpdated: true,
|
||||
useWebFonts: false,
|
||||
markdown: {
|
||||
lineNumbers: true,
|
||||
},
|
||||
locales: {
|
||||
root: { label: '简体中文', lang: 'zh-CN' },
|
||||
},
|
||||
themeConfig: {
|
||||
logo: '/favicon.ico',
|
||||
outline: 2,
|
||||
docFooter: {
|
||||
prev: '上一篇',
|
||||
next: '下一篇',
|
||||
},
|
||||
returnToTopLabel: '返回顶部',
|
||||
outlineTitle: '导航栏',
|
||||
darkModeSwitchLabel: '外观',
|
||||
sidebarMenuLabel: '归档',
|
||||
editLink: {
|
||||
pattern: `${github}/tree/vp/docs/:path`,
|
||||
text: '在 GitHub 上编辑此页',
|
||||
},
|
||||
lastUpdatedText: '最后一次更新于',
|
||||
footer: {
|
||||
message: 'Telegram robot, query the official game information.',
|
||||
copyright: 'Copyright © 2023 PaigramTeam. All rights reserved.',
|
||||
},
|
||||
nav: [
|
||||
{
|
||||
text: ' 📦️ Repo',
|
||||
items: [
|
||||
{ text: '✨ PaiGram', link: 'https://github.com/PaiGramTeam/PaiGram' },
|
||||
{ text: '🚅 PamGram', link: 'https://github.com/PaiGramTeam/PamGram' },
|
||||
{ text: '🎮 MibooGram', link: 'https://github.com/PaiGramTeam/MibooGram' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: `v${docsVersion}`,
|
||||
items: [
|
||||
{ text: '📝 Docs', link: github },
|
||||
],
|
||||
},
|
||||
],
|
||||
sidebar,
|
||||
socialLinks,
|
||||
},
|
||||
head: [
|
||||
['meta', { name: 'referrer', content: 'no-referrer-when-downgrade' }],
|
||||
['meta', { name: 'keywords', content: keywords }],
|
||||
['meta', { name: 'author', content: 'PaigramTeam' }],
|
||||
['meta', { property: 'og:type', content: 'article' }],
|
||||
['meta', { name: 'application-name', content: name }],
|
||||
['meta', { name: 'apple-mobile-web-app-title', content: name }],
|
||||
['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'default' }],
|
||||
|
||||
['link', { rel: 'shortcut icon', href: '/favicon.ico' }],
|
||||
['link', { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
|
||||
['link', { rel: 'mask-icon', href: '/favicon.ico', color: '#06f' }],
|
||||
['meta', { name: 'theme-color', content: '#06f' }],
|
||||
|
||||
['link', { rel: 'apple-touch-icon', sizes: '120x120', href: '/images/icons/apple-touch-icon.png' }],
|
||||
|
||||
// webfont
|
||||
['link', { rel: 'dns-prefetch', href: 'https://fonts.googleapis.com' }],
|
||||
['link', { rel: 'dns-prefetch', href: 'https://fonts.gstatic.com' }],
|
||||
['link', { rel: 'preconnect', crossorigin: 'anonymous', href: 'https://fonts.googleapis.com' }],
|
||||
['link', { rel: 'preconnect', crossorigin: 'anonymous', href: 'https://fonts.gstatic.com' }],
|
||||
// og
|
||||
['meta', { property: 'og:description', content: description }],
|
||||
['meta', { property: 'og:url', content: site }],
|
||||
['meta', { property: 'og:locale', content: 'zh_CN' }],
|
||||
],
|
||||
}))
|
10
docs/.vitepress/link.ts
Normal file
10
docs/.vitepress/link.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { github } from './meta'
|
||||
|
||||
const socialLinks = [
|
||||
{
|
||||
icon: 'github',
|
||||
link: github,
|
||||
},
|
||||
]
|
||||
|
||||
export default socialLinks
|
21
docs/.vitepress/meta.ts
Normal file
21
docs/.vitepress/meta.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { version } from '../../package.json'
|
||||
|
||||
// base info
|
||||
export const name = 'GramBot'
|
||||
export const site = 'https://docs.paimon.vip/'
|
||||
export const logo = '../public/icon.png'
|
||||
export const keywords = 'docs,paimon,paigram,pomgram,telegram,bot'
|
||||
export const description = 'Telegram robot, query the official game information'
|
||||
|
||||
// social link
|
||||
export const github = 'https://github.com/PaiGramTeam/PaiGramDocs'
|
||||
|
||||
// docs version
|
||||
export const docsVersion = version
|
||||
|
||||
/* PWA runtime caching urlPattern regular expressions */
|
||||
/* eslint-disable prefer-regex-literals */
|
||||
export const githubSourceContentRegex = new RegExp('^https://(((raw|user-images|camo).githubusercontent.com))/.*', 'i')
|
||||
export const googleFontRegex = new RegExp('^https://fonts.googleapis.com/.*', 'i')
|
||||
export const googleStaticFontRegex = new RegExp('^https://fonts.gstatic.com/.*', 'i')
|
||||
export const jsdelivrCDNRegex = new RegExp('^https://cdn.jsdelivr.net/.*', 'i')
|
35
docs/.vitepress/plugins/markdownTransform.ts
Normal file
35
docs/.vitepress/plugins/markdownTransform.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import type { Plugin } from 'vite'
|
||||
import { getReadingTime } from './../theme/utils'
|
||||
|
||||
export function MarkdownTransform(): Plugin {
|
||||
return {
|
||||
name: 'md-transform',
|
||||
enforce: 'pre',
|
||||
async transform(code, id) {
|
||||
if (!id.match(/\.md\b/))
|
||||
return null
|
||||
|
||||
// convert img
|
||||
const imgRegex = /!\[(.+?)\]\((.+?)\)/g
|
||||
let imgMatches = imgRegex.exec(code)
|
||||
while (imgMatches) {
|
||||
const [text, link] = imgMatches.slice(1)
|
||||
code = code.replace(imgMatches[0], `<img src="${link}" alt="${text || 'img'}" />`)
|
||||
imgMatches = imgRegex.exec(code)
|
||||
}
|
||||
|
||||
// const { footer } = await getDocsMarkdown()
|
||||
// code = replacer(code, footer, 'FOOTER', 'tail')
|
||||
const { readTime, words } = getReadingTime(code)
|
||||
|
||||
code = code.replace(/(#\s\S.+)/, `$1\n\n<PageInfo readTime="${readTime}" words="${words}"/>\n`)
|
||||
|
||||
code = code.replace(/::: info([\s\S.]+)?:::/g, '::: info 📝 备注$1:::\n')
|
||||
code = code.replace(/::: warning([\s\S.]+)?:::/g, '::: warning 🚨 警告$1:::\n')
|
||||
code = code.replace(/::: tip([\s\S.]+)?:::/g, '::: tip 💡 提醒$1:::\n')
|
||||
code = code.replace(/::: danger([\s\S.]+)?:::/g, '::: danger 🔥 危险$1:::\n')
|
||||
|
||||
return code
|
||||
},
|
||||
}
|
||||
}
|
110
docs/.vitepress/plugins/pwa.ts
Normal file
110
docs/.vitepress/plugins/pwa.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import fg from 'fast-glob'
|
||||
import { resolve } from 'pathe'
|
||||
import type { VitePWAOptions } from 'vite-plugin-pwa'
|
||||
import {
|
||||
description,
|
||||
githubSourceContentRegex,
|
||||
googleFontRegex,
|
||||
googleStaticFontRegex,
|
||||
jsdelivrCDNRegex,
|
||||
name,
|
||||
} from '../meta'
|
||||
|
||||
/**
|
||||
* Vite Plugin PWA uses Workbox library to build the service worker
|
||||
* can find more information on Workbox section.
|
||||
* @see https://vite-plugin-pwa.netlify.app/
|
||||
*/
|
||||
export const pwa: Partial<VitePWAOptions> = {
|
||||
outDir: '../dist',
|
||||
registerType: 'autoUpdate',
|
||||
// include all static assets under public/
|
||||
includeAssets: fg.sync('**/*.{png,svg,gif,ico,txt}', { cwd: resolve(__dirname, '../../public') }),
|
||||
manifest: {
|
||||
id: '/',
|
||||
name,
|
||||
short_name: name,
|
||||
description,
|
||||
theme_color: '#06f',
|
||||
icons: [
|
||||
{
|
||||
src: '/images/icons/apple-touch-120x120.png',
|
||||
sizes: '120x120',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: '/images/icons/android-chrome-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: '/images/icons/android-chrome-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
workbox: {
|
||||
navigateFallbackDenylist: [/^\/new$/],
|
||||
globPatterns: ['**/*.{js,css,webp,png,svg,gif,ico,woff2}'],
|
||||
navigateFallback: null,
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: googleFontRegex,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'google-font-style-cache',
|
||||
expiration: {
|
||||
maxEntries: 10,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
urlPattern: googleStaticFontRegex,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'google-fonts-cache',
|
||||
expiration: {
|
||||
maxEntries: 10,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
urlPattern: jsdelivrCDNRegex,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'jsdelivr-cdn-cache',
|
||||
expiration: {
|
||||
maxEntries: 10,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
urlPattern: githubSourceContentRegex,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'githubusercontent-images-cache',
|
||||
expiration: {
|
||||
maxEntries: 10,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
14
docs/.vitepress/sidebar.ts
Normal file
14
docs/.vitepress/sidebar.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export default {
|
||||
'/': [
|
||||
{
|
||||
text: '🚀 快速上手',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: '环境检查', link: '/quick-start/env' },
|
||||
{ text: '克隆项目', link: '/quick-start/install' },
|
||||
{ text: '配置项目', link: '/quick-start/config' },
|
||||
{ text: '启动项目', link: '/quick-start/run' },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
64
docs/.vitepress/theme/components/Badge.vue
Normal file
64
docs/.vitepress/theme/components/Badge.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
text?: string
|
||||
type?: 'info' | 'tip' | 'warning' | 'danger'
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="VPBadge" :class="type ?? 'tip'">
|
||||
<slot>{{ text }}</slot>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPBadge {
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
padding: 0 8px;
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
h1 .VPBadge,
|
||||
h2 .VPBadge,
|
||||
h3 .VPBadge,
|
||||
h4 .VPBadge,
|
||||
h5 .VPBadge,
|
||||
h6 .VPBadge {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
h2 .VPBadge {
|
||||
border-radius: 11px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.VPBadge.info {
|
||||
border-color: var(--vp-badge-info-border);
|
||||
color: var(--vp-badge-info-text);
|
||||
background-color: var(--vp-badge-info-bg);
|
||||
}
|
||||
|
||||
.VPBadge.tip {
|
||||
border-color: var(--vp-badge-tip-border);
|
||||
color: var(--vp-badge-tip-text);
|
||||
background-color: var(--vp-badge-tip-bg);
|
||||
}
|
||||
|
||||
.VPBadge.warning {
|
||||
border-color: var(--vp-badge-warning-border);
|
||||
color: var(--vp-badge-warning-text);
|
||||
background-color: var(--vp-badge-warning-bg);
|
||||
}
|
||||
|
||||
.VPBadge.danger {
|
||||
border-color: var(--vp-badge-danger-border);
|
||||
color: var(--vp-badge-danger-text);
|
||||
background-color: var(--vp-badge-danger-bg);
|
||||
}
|
||||
</style>
|
139
docs/.vitepress/theme/components/Card.vue
Normal file
139
docs/.vitepress/theme/components/Card.vue
Normal file
@ -0,0 +1,139 @@
|
||||
<script setup lang="ts">
|
||||
import json from '../../../public/plugin_list.json'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div display="flex" flex-wrap="wrap">
|
||||
<div flex="~ wrap gap-1" justify-flex-start gap="20px">
|
||||
<a
|
||||
v-for="(item, index) in json.plugins" :key="index" :href="item.link"
|
||||
>
|
||||
<div class="card">
|
||||
<h3 class="card__title">{{ index }}<Badge :type="item.type" :text="item.content" />
|
||||
</h3>
|
||||
<p class="card__content">{{ item.info }} </p>
|
||||
<div class="so_top_icon">
|
||||
<img
|
||||
loading="lazy" :src="item.avatar" rounded-full min-w-10 min-h-10 h-10 w-10
|
||||
:alt="`${name}'s avatar`"
|
||||
>
|
||||
</div>
|
||||
<div class="card__arrow">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" height="15" width="15">
|
||||
<path fill="#fff" d="M13.4697 17.9697C13.1768 18.2626 13.1768 18.7374 13.4697 19.0303C13.7626 19.3232 14.2374 19.3232 14.5303 19.0303L20.3232 13.2374C21.0066 12.554 21.0066 11.446 20.3232 10.7626L14.5303 4.96967C14.2374 4.67678 13.7626 4.67678 13.4697 4.96967C13.1768 5.26256 13.1768 5.73744 13.4697 6.03033L18.6893 11.25H4C3.58579 11.25 3.25 11.5858 3.25 12C3.25 12.4142 3.58579 12.75 4 12.75H18.6893L13.4697 17.9697Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.card {
|
||||
--border-radius: 0.75rem;
|
||||
--primary-color: var(--vp-c-brand);
|
||||
--secondary-color: var(--vp-c-text-2);
|
||||
width: 210px;
|
||||
height: 130px;
|
||||
font-family: "Arial";
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--vp-c-bg-soft);
|
||||
box-shadow: 0px 8px 16px 0px rgb(0 0 0 / 3%);
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.card > * + * {
|
||||
margin-top: 1.1em;
|
||||
}
|
||||
|
||||
.card .card__content {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
display: flex;
|
||||
color: var(--secondary-color);
|
||||
font-size: 0.86rem;
|
||||
}
|
||||
|
||||
.card .card__title {
|
||||
position: absolute;
|
||||
top: -13px;
|
||||
left: 45px;
|
||||
color: var(--vp-c-text-1);
|
||||
padding: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card .card__date {
|
||||
color: #6e6b80;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.card .card__arrow {
|
||||
position: absolute;
|
||||
background: var(--primary-color);
|
||||
padding: 0.4rem;
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-bottom-right-radius: var(--border-radius);
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
transition: 0.2s;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card .so_top_icon {
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
background: #000;
|
||||
top: 0px;
|
||||
left: 10px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card .so_top_icon img {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.card svg {
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
/* hover */
|
||||
.card:hover {
|
||||
cursor: pointer;
|
||||
transition: transform 0.4s ease;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.card:hover .card__title {
|
||||
color: var(--primary-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.card:hover .card__arrow {
|
||||
background: #111;
|
||||
}
|
||||
|
||||
.card:hover .card__arrow svg {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
</style>
|
231
docs/.vitepress/theme/components/ChatMessage.vue
Normal file
231
docs/.vitepress/theme/components/ChatMessage.vue
Normal file
@ -0,0 +1,231 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, getCurrentInstance, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
nickname: string
|
||||
color: string
|
||||
avatar: string
|
||||
tag: string
|
||||
type: string
|
||||
}>()
|
||||
|
||||
const colorMap = {
|
||||
Alice: '#cc0066',
|
||||
Bob: '#00994d',
|
||||
Carol: '#1e90ff',
|
||||
Dave: '#f4a460',
|
||||
}
|
||||
|
||||
const avatarMap = {
|
||||
grambot: '',
|
||||
b: '',
|
||||
}
|
||||
|
||||
const typeMap = {
|
||||
grambot: 'tip',
|
||||
b: 'danger',
|
||||
}
|
||||
|
||||
const tagMap = {
|
||||
grambot: '机器人',
|
||||
b: '用户',
|
||||
}
|
||||
|
||||
const shown = ref(false)
|
||||
const active = ref(false)
|
||||
const moving = ref(false)
|
||||
const root = ref<HTMLElement>()
|
||||
|
||||
const backgroundColor = computed(() => props.color || colorMap[props.nickname])
|
||||
const avatar = computed(() => props.avatar || avatarMap[props.nickname])
|
||||
const tag = computed(() => props.tag || tagMap[props.nickname])
|
||||
const type = computed(() => props.type || typeMap[props.nickname])
|
||||
|
||||
function getPrevious() {
|
||||
let last: Element
|
||||
for (const current of document.querySelectorAll('.chat-message')) {
|
||||
if (current === root.value)
|
||||
return last
|
||||
last = current
|
||||
}
|
||||
}
|
||||
|
||||
watch(active, (value) => {
|
||||
if (!value)
|
||||
return shown.value = false
|
||||
const prev = getPrevious()
|
||||
if (!prev)
|
||||
return appear()
|
||||
const rect = prev.getBoundingClientRect()
|
||||
if (rect.bottom < 0)
|
||||
return appear()
|
||||
const prevExposed = prev.__vue__.exposed as typeof exposed
|
||||
if (prevExposed.moving.value || !prevExposed.shown.value)
|
||||
prevExposed.onappear(appear)
|
||||
else
|
||||
appear()
|
||||
})
|
||||
|
||||
let appearCallback = () => {}
|
||||
|
||||
function appear() {
|
||||
shown.value = true
|
||||
moving.value = true
|
||||
setTimeout(() => {
|
||||
moving.value = false
|
||||
appearCallback()
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function handleScroll() {
|
||||
const rect = root.value.getBoundingClientRect()
|
||||
if (rect.top < innerHeight)
|
||||
active.value = true
|
||||
// active.value = rect.top < innerHeight
|
||||
}
|
||||
|
||||
const instance = getCurrentInstance()
|
||||
|
||||
const exposed = {
|
||||
moving,
|
||||
shown,
|
||||
onappear(callback: any) {
|
||||
appearCallback = callback
|
||||
},
|
||||
}
|
||||
|
||||
defineExpose(exposed)
|
||||
|
||||
onMounted(() => {
|
||||
root.value.__vue__ = instance
|
||||
handleScroll()
|
||||
addEventListener('scroll', handleScroll)
|
||||
addEventListener('resize', handleScroll)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
removeEventListener('scroll', handleScroll)
|
||||
removeEventListener('resize', handleScroll)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="root" class="chat-message" :class="{ shown }">
|
||||
<img v-if="avatar" class="avatar" :src="avatar">
|
||||
<div v-else class="avatar" :style="{ backgroundColor }">
|
||||
{{ nickname[0] }}
|
||||
</div>
|
||||
<div class="nickname">
|
||||
{{ nickname }}
|
||||
<Badge :type="type" :text="tag" />
|
||||
</div>
|
||||
<div class="message-box">
|
||||
<slot> </slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
$avatar-size: 2.8rem;
|
||||
$msgbox-left: 4.2rem;
|
||||
|
||||
.chat-message {
|
||||
position: relative;
|
||||
margin: 1rem 0;
|
||||
opacity: 0;
|
||||
transform: translateX(-20%);
|
||||
transition: transform 0.3s ease-out, opacity 0.3s ease;
|
||||
|
||||
&.shown {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: $avatar-size;
|
||||
height: $avatar-size;
|
||||
position: absolute;
|
||||
border-radius: 100%;
|
||||
transform: translateY(-1px);
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
text-align: center;
|
||||
line-height: $avatar-size;
|
||||
font-size: 1.6rem;
|
||||
color: white;
|
||||
font-family: "Comic Sans MS";
|
||||
}
|
||||
|
||||
.nickname {
|
||||
user-select: none;
|
||||
position: relative;
|
||||
margin: 0 0 0.4rem $msgbox-left;
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-message:not(.no-padding) .message-box {
|
||||
padding: 0.5rem 0.7rem;
|
||||
}
|
||||
|
||||
.chat-message .message-box {
|
||||
position: relative;
|
||||
margin-left: $msgbox-left;
|
||||
width: fit-content;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--vp-c-bg);
|
||||
word-break: break-all;
|
||||
line-height: 26px !important;
|
||||
|
||||
> img {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
p > img {
|
||||
margin: 0.2rem 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
top: 0px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 0 solid transparent;
|
||||
border-bottom-width: 8px;
|
||||
border-bottom-color: currentColor;
|
||||
border-radius: 0 0 0 32px;
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 !important;
|
||||
line-height: 26px !important;
|
||||
}
|
||||
|
||||
p.indent-1 {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
p.indent-2 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
font-size: 0.9rem;
|
||||
margin: 0 0 0.2rem;
|
||||
background-color: #f3f6f9;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.2rem 0.6rem;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
}
|
||||
</style>
|
129
docs/.vitepress/theme/components/ChatPanel.vue
Normal file
129
docs/.vitepress/theme/components/ChatPanel.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: {
|
||||
controls: Boolean,
|
||||
title: String,
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
tab: 'default',
|
||||
}),
|
||||
|
||||
computed: {
|
||||
mini() {
|
||||
return !this.controls && !this.title
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="panel-view" :class="{ mini }">
|
||||
<div class="controls">
|
||||
<div class="circle red" />
|
||||
<div class="circle yellow" />
|
||||
<div class="circle green" />
|
||||
<div class="title">
|
||||
<span v-if="title" class="title-text">{{ title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
$circleRadius: 6px;
|
||||
$circleSpacing: 19px;
|
||||
$textShadow: 1px 1px 1px rgba(23, 31, 35, 0.5);
|
||||
|
||||
.panel-view {
|
||||
outline: 2px;
|
||||
outline-color: #ea1313;
|
||||
outline-style: auto;
|
||||
position: relative;
|
||||
border-radius: 6px;
|
||||
margin: 1rem 0;
|
||||
overflow: auto hidden;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
|
||||
&.manager, &.container {
|
||||
background-color: #032f62;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: initial;
|
||||
position: absolute;
|
||||
top: 0.8rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.circle {
|
||||
position: absolute;
|
||||
top: 8px - $circleRadius;
|
||||
width: 2 * $circleRadius;
|
||||
height: 2 * $circleRadius;
|
||||
border-radius: $circleRadius;
|
||||
&.red {
|
||||
left: 17px;
|
||||
background-color: #ff5f56;
|
||||
}
|
||||
&.yellow {
|
||||
left: 17px + $circleSpacing;
|
||||
background-color: #ffbd2e;
|
||||
}
|
||||
&.green {
|
||||
left: 17px + 2 * $circleSpacing;
|
||||
background-color: #27c93f;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
line-height: 1rem;
|
||||
|
||||
.tab {
|
||||
color: gray;
|
||||
cursor: pointer;
|
||||
transition: .3s ease;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: white;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.title-text:not(:last-child)::after {
|
||||
color: gray;
|
||||
content: " - ";
|
||||
}
|
||||
|
||||
.tab + .tab::before {
|
||||
cursor: default;
|
||||
content: " | ";
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0.2rem 1.2rem;
|
||||
|
||||
> p {
|
||||
font-size: 0.8rem;
|
||||
color: #909399;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
&.mini .controls {
|
||||
display: none;
|
||||
}
|
||||
&:not(.mini) .content {
|
||||
padding-top: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
22
docs/.vitepress/theme/components/CopyRight.vue
Normal file
22
docs/.vitepress/theme/components/CopyRight.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useData } from 'vitepress'
|
||||
|
||||
const defaultAuthor = 'PaigramTeam'
|
||||
const { frontmatter } = useData()
|
||||
|
||||
const author = ref(defaultAuthor)
|
||||
|
||||
if (frontmatter.value?.author)
|
||||
author.value = frontmatter.value?.author
|
||||
|
||||
function reName(name: string) {
|
||||
return name
|
||||
}
|
||||
|
||||
const pageHref = location.href
|
||||
|
||||
function getGithubLink(name: string) {
|
||||
return `https://github.com/${reName(name)}`
|
||||
}
|
||||
</script>
|
144
docs/.vitepress/theme/components/DataPanel.vue
Normal file
144
docs/.vitepress/theme/components/DataPanel.vue
Normal file
@ -0,0 +1,144 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="panel mt-[48px]">
|
||||
<div class="mx-auto container max-w-[1152px] min-h-[32px] bg-[var(--vp-c-bg-soft)] w-full rounded-[8px]">
|
||||
<section class="grid grid-cols-3 justify-items-center py-[12px] px-[24px] items-center">
|
||||
<h2 class="leading-[24px] text-[16px] font-[600]">
|
||||
本站总访问量 <span id="busuanzi_value_site_pv" class="font-bold" /> 次
|
||||
</h2>
|
||||
<fa6-solid:heart-pulse class="heart" />
|
||||
<h2 class="leading-[24px] text-[16px]">
|
||||
本站访客数 <span id="busuanzi_value_site_uv" class="font-bold" /> 人次
|
||||
</h2>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.panel {
|
||||
padding: 0 24px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.panel {
|
||||
padding: 0 48px;
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.panel {
|
||||
padding: 0 64px;
|
||||
margin-top: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.heart {
|
||||
color: red;
|
||||
animation: iconAnimate 1.33s ease-in-out infinite
|
||||
}
|
||||
|
||||
@-moz-keyframes iconAnimate {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1)
|
||||
}
|
||||
|
||||
10%,
|
||||
30% {
|
||||
transform: scale(.9)
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
|
||||
50%,
|
||||
70% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes iconAnimate {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1)
|
||||
}
|
||||
|
||||
10%,
|
||||
30% {
|
||||
transform: scale(.9)
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
|
||||
50%,
|
||||
70% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
}
|
||||
|
||||
@-o-keyframes iconAnimate {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1)
|
||||
}
|
||||
|
||||
10%,
|
||||
30% {
|
||||
transform: scale(.9)
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
|
||||
50%,
|
||||
70% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes iconAnimate {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1)
|
||||
}
|
||||
|
||||
10%,
|
||||
30% {
|
||||
transform: scale(.9)
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
|
||||
50%,
|
||||
70% {
|
||||
transform: scale(1.1)
|
||||
}
|
||||
}
|
||||
</style>
|
25
docs/.vitepress/theme/components/HomeContributors.vue
Normal file
25
docs/.vitepress/theme/components/HomeContributors.vue
Normal file
@ -0,0 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { contributors } from '../../../contributors'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-doc mx-auto">
|
||||
<h2 op50 font-normal pt-5 text-center>
|
||||
Contributors
|
||||
</h2>
|
||||
</div>
|
||||
<div text-lg max-w-100 text-center leading-7 p-10 mx-auto>
|
||||
<div flex="~ wrap gap-1" justify-center>
|
||||
<a
|
||||
v-for="{ name, avatar } of contributors" :key="name" :href="`https://github.com/${name}`" target="_blank" m-0
|
||||
rel="noopener noreferrer" :aria-label="`${name} on GitHub`"
|
||||
>
|
||||
<img
|
||||
loading="lazy" :src="avatar" width="40" height="40" rounded-full min-w-10 min-h-10 h-10 w-10
|
||||
:alt="`${name}'s avatar`"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</template>
|
28
docs/.vitepress/theme/components/NavCard.vue
Normal file
28
docs/.vitepress/theme/components/NavCard.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import type { navItem } from '../../../favorites/types'
|
||||
|
||||
defineProps<{
|
||||
navData: navItem[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid auto-rows-auto grid-cols-2 gap-[12px]">
|
||||
<section v-for="navItem of navData" :key="navItem.id">
|
||||
<a :href="navItem.link" rel="noreferrer" target="_blank" class="group">
|
||||
<section
|
||||
class="flex h-full flex-col border-1 border-solid border-[var(--vp-c-border)]/[.55] rounded-[8px] leading-[24px] px-[24px] py-[12px] group-hover:shadow"
|
||||
>
|
||||
<span class="text-gray-600 group-hover:text-gray-800 dark:text-gray-300 dark:group-hover:text-gray-100">
|
||||
{{ navItem.text }}
|
||||
</span>
|
||||
<span
|
||||
class="mb-auto text-sm text-gray-700 opacity-50 dark:text-gray-300 dark:group-hover:text-gray-50 min-h-[20px]"
|
||||
>
|
||||
{{ navItem.desc ?? navItem.text }}
|
||||
</span>
|
||||
</section>
|
||||
</a>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
39
docs/.vitepress/theme/components/PageInfo.vue
Normal file
39
docs/.vitepress/theme/components/PageInfo.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { useData } from 'vitepress'
|
||||
import { getDate, getFromNow } from '../utils'
|
||||
|
||||
defineProps<{
|
||||
readTime: string
|
||||
words: string
|
||||
}>()
|
||||
const defaultAuthor = 'Choi Yang'
|
||||
const author = ref(defaultAuthor)
|
||||
const { frontmatter, page } = useData()
|
||||
|
||||
const publishedTime = getDate(frontmatter.value?.date)
|
||||
|
||||
if (frontmatter.value?.author)
|
||||
author.value = frontmatter.value?.author
|
||||
|
||||
const lastUpdatedDate = computed(() => new Date(page.value.lastUpdated!))
|
||||
const isoDatetime = computed(() => lastUpdatedDate.value.toISOString())
|
||||
const timeFormNow = getFromNow(isoDatetime.value)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<section
|
||||
class="border-b-1 border-[var(--vp-c-divider)] w-full border-b-solid mt-[24px] pb-[12px] flex gap-[12px] mb-[12px] flex-wrap max-w-[85%]"
|
||||
>
|
||||
<div class="flex gap-[4px] items-center">
|
||||
<bi:file-earmark-word-fill />
|
||||
字数统计:<span>{{ words }} 字</span>
|
||||
</div>
|
||||
<div class="flex gap-[4px] items-center">
|
||||
<ooui:clock />
|
||||
阅读时长:<span>{{ readTime }} 分钟</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
15
docs/.vitepress/theme/components/VideoLink.vue
Normal file
15
docs/.vitepress/theme/components/VideoLink.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
bvId: string
|
||||
}>()
|
||||
const link = `https://www.bilibili.com/video/${props.bvId}/`
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="video_link">
|
||||
<a :href="link" target="_blank" bg-blue:10 px4 py3 rounded block mt2 flex items-center gap2>
|
||||
<div i-carbon:play-filled flex-none text-lg />
|
||||
<slot />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
52
docs/.vitepress/theme/index.ts
Normal file
52
docs/.vitepress/theme/index.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { inBrowser, useRoute } from 'vitepress'
|
||||
import type { EnhanceAppContext, Theme } from 'vitepress'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { nextTick, onMounted, watch } from 'vue'
|
||||
import busuanzi from 'busuanzi.pure.js'
|
||||
import mediumZoom from 'medium-zoom'
|
||||
import { registerAnalytics, siteIds, trackPageview } from './plugins/baidutongji'
|
||||
import './styles/main.css'
|
||||
import './styles/global.css'
|
||||
import './styles/demo.css'
|
||||
import './styles/utils.css'
|
||||
import './styles/vars.css'
|
||||
import './styles/custom-block.css'
|
||||
import './styles/scrollBar.scss'
|
||||
import 'uno.css'
|
||||
|
||||
if (inBrowser)
|
||||
import('./plugins/pwa')
|
||||
|
||||
const theme: Theme = {
|
||||
...DefaultTheme,
|
||||
enhanceApp({ router }: EnhanceAppContext) {
|
||||
if (inBrowser) {
|
||||
registerAnalytics(siteIds)
|
||||
|
||||
window.addEventListener('hashchange', () => {
|
||||
const { href: url } = window.location
|
||||
trackPageview(siteIds, url)
|
||||
})
|
||||
|
||||
router.onAfterRouteChanged = (to) => {
|
||||
trackPageview(siteIds, to)
|
||||
busuanzi.fetch()
|
||||
}
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const route = useRoute()
|
||||
const initZoom = () => {
|
||||
mediumZoom('.main img', { background: 'var(--vp-c-bg)' }) // Should there be a new?
|
||||
}
|
||||
onMounted(() => {
|
||||
initZoom()
|
||||
})
|
||||
watch(
|
||||
() => route.path,
|
||||
() => nextTick(() => initZoom()),
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export default theme
|
100
docs/.vitepress/theme/plugins/autoSidebarBeta.ts
Normal file
100
docs/.vitepress/theme/plugins/autoSidebarBeta.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import { join, resolve } from 'node:path'
|
||||
import matter from 'gray-matter'
|
||||
import fg from 'fast-glob'
|
||||
import fs from 'fs-extra'
|
||||
|
||||
export interface Options {
|
||||
base: string
|
||||
title?: string
|
||||
collapsed?: boolean
|
||||
}
|
||||
|
||||
export const DIR_ROOT = resolve(__dirname, '../../../../')
|
||||
export const DIR_SRC = resolve(DIR_ROOT, 'docs')
|
||||
|
||||
export function fastGlobSync(type: string, dir: string, ignore: string[] = []) {
|
||||
const files = fg.sync('*', {
|
||||
onlyDirectories: type === 'dir',
|
||||
onlyFiles: type === 'file',
|
||||
cwd: dir,
|
||||
ignore: [
|
||||
'_*',
|
||||
'dist',
|
||||
'node_modules',
|
||||
...ignore,
|
||||
],
|
||||
})
|
||||
files.sort()
|
||||
return files
|
||||
}
|
||||
|
||||
export const dirs = fastGlobSync('dir', DIR_SRC)
|
||||
|
||||
function getSidebar(dir: string, title: string | undefined) {
|
||||
const curDir = resolve(DIR_SRC, dir)
|
||||
const dirs = fastGlobSync('dir', curDir)
|
||||
const res = []
|
||||
if (dirs.length) {
|
||||
// TODO 多级目录
|
||||
dirs.forEach((e) => {
|
||||
const childDir = resolve(curDir, e)
|
||||
const mdFiles = fastGlobSync('file', childDir)
|
||||
const sidebar = {
|
||||
text: (e.charAt(0).toUpperCase() + e.slice(1)).replaceAll('-', ' '),
|
||||
collapsed: false,
|
||||
items: [] as any,
|
||||
}
|
||||
mdFiles.forEach((file) => {
|
||||
if (file.endsWith('.md')) {
|
||||
let prePath = join('/', dir, e, file)
|
||||
if (file === 'index.md')
|
||||
prePath = join('/', dir, e, '/')
|
||||
|
||||
const item = {
|
||||
text: file.slice(0, -3),
|
||||
link: prePath,
|
||||
}
|
||||
sidebar.items.push(item)
|
||||
}
|
||||
})
|
||||
res.push(sidebar)
|
||||
})
|
||||
}
|
||||
else {
|
||||
const mdFiles = fastGlobSync('file', curDir)
|
||||
const sidebar = {
|
||||
text: title,
|
||||
collapsed: false,
|
||||
items: [] as any,
|
||||
}
|
||||
mdFiles.filter(e => e !== 'index.md').forEach((file) => {
|
||||
if (file.endsWith('.md')) {
|
||||
const prePath = join('/', dir, file)
|
||||
const curDir = resolve(DIR_SRC, dir)
|
||||
const mdPath = resolve(curDir, file)
|
||||
const mdRaw = fs.readFileSync(mdPath, 'utf-8')
|
||||
const { content: md } = matter(mdRaw)
|
||||
const mdLine = md.split('\n').slice(0, 6)
|
||||
const mdTitle = mdLine.filter(e => e.match(/^#\s*/))[0]?.replace('#', '').trim()
|
||||
const item = {
|
||||
text: mdTitle || file.slice(0, -3),
|
||||
link: prePath,
|
||||
}
|
||||
sidebar.items.push(item)
|
||||
}
|
||||
})
|
||||
res.push(sidebar)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export default (options: Options) => {
|
||||
options.collapsed = options?.collapsed ?? false
|
||||
if (options.base !== '/') {
|
||||
const dir = dirs.filter((dir: string) => dir.includes(options.base))[0]
|
||||
if (dir) {
|
||||
const sidebar = getSidebar(dir, options.title)
|
||||
return sidebar
|
||||
}
|
||||
}
|
||||
}
|
49
docs/.vitepress/theme/plugins/baidutongji.ts
Normal file
49
docs/.vitepress/theme/plugins/baidutongji.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { inBrowser } from 'vitepress'
|
||||
|
||||
/**
|
||||
* 统计站点的 ID 列表
|
||||
*/
|
||||
export const siteIds = 'eb1ef90b1e9476b8d3d43088d3ac9c49'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
_hmt: any
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册统计
|
||||
*/
|
||||
export function registerAnalytics(siteId: string) {
|
||||
if (!inBrowser)
|
||||
return
|
||||
if (document.querySelector(`#analytics-plugin-${siteId}`))
|
||||
return
|
||||
window._hmt = window._hmt ? window._hmt : []
|
||||
const script = document.createElement('script')
|
||||
script.id = `analytics-${siteId}`
|
||||
script.async = true
|
||||
script.src = `https://hm.baidu.com/hm.js?${siteId}`
|
||||
document.querySelector('head')?.appendChild(script)
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报 PV 数据
|
||||
* @param siteId - 站点 ID
|
||||
* @param pageUrl - 页面 URL
|
||||
*/
|
||||
export function trackPageview(siteId: string, pageUrl: string) {
|
||||
if (!inBrowser)
|
||||
return
|
||||
if (!pageUrl || typeof pageUrl !== 'string')
|
||||
pageUrl = '/'
|
||||
|
||||
if (pageUrl.startsWith('http')) {
|
||||
const urlFragment = pageUrl.split('/')
|
||||
const origin = `${urlFragment[0]}//${urlFragment[2]}`
|
||||
pageUrl = pageUrl.replace(origin, '')
|
||||
}
|
||||
|
||||
window._hmt.push(['_setAccount', siteId])
|
||||
window._hmt.push(['_trackPageview', pageUrl])
|
||||
}
|
30
docs/.vitepress/theme/plugins/googleAnalytics.ts
Normal file
30
docs/.vitepress/theme/plugins/googleAnalytics.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import process from 'node:process'
|
||||
|
||||
declare const dataLayer: any[]
|
||||
declare const gtag: (...args: any[]) => void
|
||||
declare global {
|
||||
interface Window {
|
||||
dataLayer?: typeof dataLayer
|
||||
gtag?: typeof gtag
|
||||
}
|
||||
}
|
||||
|
||||
function mountGoogleAnalytics(id: string) {
|
||||
if (window.dataLayer && window.gtag)
|
||||
return
|
||||
|
||||
const gtagScript = document.createElement('script')
|
||||
gtagScript.src = `https://www.googletagmanager.com/gtag/js?id=${id}`
|
||||
gtagScript.async = true
|
||||
document.head.appendChild(gtagScript)
|
||||
window.dataLayer = window.dataLayer || []
|
||||
window.gtag = function () {
|
||||
dataLayer.push(arguments)
|
||||
}
|
||||
gtag('js', new Date())
|
||||
gtag('config', id)
|
||||
}
|
||||
export default ({ id }) => {
|
||||
if (process.env.NODE_ENV === 'production' && id && typeof window !== 'undefined')
|
||||
mountGoogleAnalytics(id)
|
||||
}
|
4
docs/.vitepress/theme/plugins/pwa.ts
Normal file
4
docs/.vitepress/theme/plugins/pwa.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { registerSW } from 'virtual:pwa-register'
|
||||
|
||||
/** @see https://vite-plugin-pwa.netlify.app/guide/auto-update.html#ssr-ssg */
|
||||
registerSW({ immediate: true })
|
5
docs/.vitepress/theme/styles/custom-block.css
Normal file
5
docs/.vitepress/theme/styles/custom-block.css
Normal file
@ -0,0 +1,5 @@
|
||||
.custom-block-title
|
||||
{
|
||||
font-weight: 1200;
|
||||
font-size: 20px;
|
||||
}
|
206
docs/.vitepress/theme/styles/demo.css
Normal file
206
docs/.vitepress/theme/styles/demo.css
Normal file
@ -0,0 +1,206 @@
|
||||
.demo {
|
||||
font-size: var(--vt-doc-code-font-size);
|
||||
background: var(--cho-code-block-bg);
|
||||
padding: 2em;
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 8px;
|
||||
transition: background-color 0.5s;
|
||||
}
|
||||
|
||||
.demo-source-link {
|
||||
color: var(--vp-c-text-2) !important;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
z-index: 2;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-dark-3);
|
||||
transition: color 0.5s;
|
||||
}
|
||||
|
||||
@media (min-width: 720px) {
|
||||
.demo {
|
||||
--width: calc(
|
||||
100vw - var(--sidebar-width) - var(--scrollbar-width)
|
||||
) !important;
|
||||
--content-width: min(48rem, var(--width)) !important;
|
||||
--margin-left: calc(
|
||||
calc(calc(var(--content-width) - var(--width)) / 2) - 1.5rem
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.note {
|
||||
opacity: 0.7;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: -0.2rem;
|
||||
}
|
||||
|
||||
.demo {
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 3px 15px;
|
||||
background-color: var(--vp-c-brand);
|
||||
border: none;
|
||||
outline: none;
|
||||
color: white;
|
||||
margin: 0.5rem 0;
|
||||
border-bottom: 2px solid var(--vp-c-brand-dark);
|
||||
text-shadow: 1px 1px 1px var(--vp-c-brand-dark);
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
button.small {
|
||||
padding: 0.25em 0.7em 0.2em 0.7em;
|
||||
}
|
||||
|
||||
button.orange {
|
||||
--vp-c-brand: #db8742;
|
||||
--vp-c-brand-dark: #ad6e39;
|
||||
--vp-c-brand-active: #d67e36;
|
||||
}
|
||||
|
||||
button.red {
|
||||
--c-brand: #f56c6c;
|
||||
--c-brand-dark: #e41c1c;
|
||||
--c-brand-active: #e94c4c;
|
||||
}
|
||||
|
||||
button.gray {
|
||||
color: var(--vp-c-disabled-fg);
|
||||
--vp-c-brand: var(--vp-c-disabled-bg);
|
||||
--vp-c-brand-dark: var(--vp-c-disabled-bg);
|
||||
--vp-c-brand-active: rgba(125,125,125,.2);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: var(--vp-c-brand-dark);
|
||||
}
|
||||
|
||||
button:active {
|
||||
border-bottom: 0;
|
||||
border-top: 2px solid var(--vp-c-brand-dark);
|
||||
}
|
||||
|
||||
button ~ button {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
button[disabled],
|
||||
button.disabled {
|
||||
cursor: default;
|
||||
background-color: var(--vp-c-disabled-bg);
|
||||
color: var(--vp-c-disabled-fg);
|
||||
border-bottom: 2px solid var(--vp-c-disabled-bg);
|
||||
pointer-events: none;
|
||||
text-shadow: none;
|
||||
border-top: 0;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
textarea {
|
||||
display: block;
|
||||
min-width: 20rem;
|
||||
font-size: 1.05rem;
|
||||
padding: 0.5em 1em 0.4em 1em;
|
||||
border-radius: 5px;
|
||||
box-shadow: var(--vp-c-divider) 0px 0px 0px 1px;
|
||||
margin: 0.5rem 0;
|
||||
outline: none;
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text);
|
||||
transition: background-color 0.5s;
|
||||
}
|
||||
|
||||
textarea[readonly] {
|
||||
background: var(--vp-c-bg-light);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="search"],
|
||||
input[type="number"] {
|
||||
display: block;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.5em 1em 0.4em 1em;
|
||||
border: 1px solid var(--vp-c-divider-light);
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text);
|
||||
min-width: 20rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
min-width: 15rem;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border: 1px solid var(--vp-c-divider-dark-1);
|
||||
}
|
||||
|
||||
pre,
|
||||
.code-block {
|
||||
opacity: 0.8;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
background-color: var(--vp-c-bg-mute) !important;
|
||||
padding: 4px 8px;
|
||||
margin: 12px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: var(--vp-c-bg-mute) !important;
|
||||
}
|
||||
|
||||
.resizer {
|
||||
resize: both;
|
||||
padding: 1rem;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid var(--vp-c-divider-light);
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
outline: none;
|
||||
white-space: pre;
|
||||
overflow-wrap: normal;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.float {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding: 1rem 2rem;
|
||||
border: 1px solid var(--vp-c-divider-light);
|
||||
background: var(--vp-c-bg);
|
||||
z-index: 100;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.area {
|
||||
border-width: 2px;
|
||||
border-style: dashed;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .demo {
|
||||
.resizer {
|
||||
background: #222;
|
||||
color: white;
|
||||
}
|
||||
}
|
4
docs/.vitepress/theme/styles/global.css
Normal file
4
docs/.vitepress/theme/styles/global.css
Normal file
@ -0,0 +1,4 @@
|
||||
iframe {
|
||||
width: 100%;
|
||||
min-height: 600px;
|
||||
}
|
47
docs/.vitepress/theme/styles/main.css
Normal file
47
docs/.vitepress/theme/styles/main.css
Normal file
@ -0,0 +1,47 @@
|
||||
html.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
.VPContent {
|
||||
background: url("/grid.svg") rgba(255, 255, 255, 0.6);
|
||||
background-blend-mode: difference;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.dark .VPContent {
|
||||
background: rgb(40, 40, 40, 0.6) url("/grid.svg");
|
||||
background-blend-mode: multiply;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.vp-doc h2 {
|
||||
border-top: 0px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.VPMenuLink .link {
|
||||
line-height: 28px !important;
|
||||
}
|
||||
|
||||
.VPSidebarGroup .link {
|
||||
padding: 3px 0 !important;
|
||||
}
|
||||
|
||||
.VPTeamPageTitle .title {
|
||||
line-height: 32px;
|
||||
font-size: 24px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.VPTeamPageTitle .lead {
|
||||
font-size: 14px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.medium-zoom-overlay {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.medium-zoom-image {
|
||||
z-index: 21;
|
||||
}
|
25
docs/.vitepress/theme/styles/scrollBar.scss
Normal file
25
docs/.vitepress/theme/styles/scrollBar.scss
Normal file
@ -0,0 +1,25 @@
|
||||
::-webkit-scrollbar
|
||||
{
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track-piece
|
||||
{
|
||||
background-color: white;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:vertical
|
||||
{
|
||||
background-color: #666;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:horizontal
|
||||
{
|
||||
background-color: #666;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
3
docs/.vitepress/theme/styles/utils.css
Normal file
3
docs/.vitepress/theme/styles/utils.css
Normal file
@ -0,0 +1,3 @@
|
||||
.text-orange {
|
||||
color: #db8742;
|
||||
}
|
90
docs/.vitepress/theme/styles/vars.css
Normal file
90
docs/.vitepress/theme/styles/vars.css
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Colors
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-c-accent: #35495e;
|
||||
--vp-c-brand: #d76be3;
|
||||
--vp-c-brand-dark: #3385ff;
|
||||
--vp-c-text-code: #5d6f5d;
|
||||
/* --vp-code-block-bg: rgba(125, 125, 125, 0.04); */
|
||||
--vp-c-disabled-bg: rgba(125, 125, 125, 0.2);
|
||||
/* fix contrast on gray cards: used by --vp-c-text-2 */
|
||||
--vp-c-brand-light: #ff8f91;
|
||||
--vp-c-text-light-2: rgba(30, 30, 30, 0.7);
|
||||
--cho-code-block-bg: rgba(125, 125, 125, 0.04);
|
||||
--vp-c-bg-alt: rgba(235, 235, 235, 0.6);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-code-block-bg: rgba(0, 0, 0, 0.2);
|
||||
--vp-c-text-code: #c0cec0;
|
||||
/* fix contrast on gray cards: check the same above (this is the default) */
|
||||
--vp-c-text-dark-2: rgba(235, 235, 235, 0.6);
|
||||
--vp-c-bg: rgb(10, 11, 10);
|
||||
--vp-c-bg-alt: rgba(10, 11, 10, 0.6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Code
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-code-line-highlight-color: rgba(125, 125, 125, 0.2);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-code-line-highlight-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Button
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-button-brand-border: var(--vp-c-brand-light);
|
||||
--vp-button-brand-bg: var(--vp-c-brand);
|
||||
--vp-button-brand-hover-border: var(--vp-c-brand-light);
|
||||
--vp-button-brand-hover-bg: var(--vp-c-brand-light);
|
||||
--vp-button-brand-active-border: var(--vp-c-brand-light);
|
||||
--vp-button-brand-active-bg: var(--vp-button-brand-bg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Home
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(
|
||||
120deg,
|
||||
#ffffff -80%,
|
||||
#ea0fff
|
||||
);
|
||||
--vp-home-hero-image-background-image: linear-gradient(
|
||||
-45deg,
|
||||
#ea0fff 30%,
|
||||
#35495e80
|
||||
);
|
||||
--vp-home-hero-image-filter: blur(30px);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(56px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(72px);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component: Algolia
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
.DocSearch {
|
||||
--docsearch-primary-color: var(--vp-c-brand) !important;
|
||||
}
|
4
docs/.vitepress/theme/types/index.ts
Normal file
4
docs/.vitepress/theme/types/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface PageInfo {
|
||||
readTime: number | string;
|
||||
words: number | string;
|
||||
}
|
26
docs/.vitepress/theme/utils/date.ts
Normal file
26
docs/.vitepress/theme/utils/date.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import dayjs from 'dayjs'
|
||||
import utc from 'dayjs/plugin/utc.js'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
|
||||
dayjs.extend(utc)
|
||||
dayjs.locale('zh-cn')
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export function getDate(date: string | Date | undefined): string | null {
|
||||
if (date) {
|
||||
const time = dayjs(date instanceof Date ? date : date.trim())
|
||||
if (time.isValid()) {
|
||||
const currentTime = dayjs(date).utc().local().format('YYYY-MM-DD')
|
||||
return currentTime
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function getFromNow(date: string | Date): string | null {
|
||||
if (date)
|
||||
return dayjs(date).utc().local().fromNow()
|
||||
|
||||
return null
|
||||
}
|
3
docs/.vitepress/theme/utils/index.ts
Normal file
3
docs/.vitepress/theme/utils/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './md'
|
||||
export * from './date'
|
||||
export * from './pageInfo'
|
22
docs/.vitepress/theme/utils/md.ts
Normal file
22
docs/.vitepress/theme/utils/md.ts
Normal file
@ -0,0 +1,22 @@
|
||||
export function renderMarkdown(markdownText = '') {
|
||||
const htmlText = markdownText
|
||||
.replace(/^### (.*$)/gim, '<h3>$1</h3>')
|
||||
.replace(/^## (.*$)/gim, '<h2>$1</h2>')
|
||||
.replace(/^# (.*$)/gim, '<h1>$1</h1>')
|
||||
.replace(/^\> (.*$)/gim, '<blockquote>$1</blockquote>')
|
||||
.replace(/\*\*(.*)\*\*/gim, '<b>$1</b>')
|
||||
.replace(/\*(.*)\*/gim, '<i>$1</i>')
|
||||
.replace(/!\[(.*?)\]\((.*?)\)/gim, '<img alt=\'$1\' src=\'$2\' />')
|
||||
.replace(/\[(.*?)\]\((.*?)\)/gim, '<a href=\'$2\'>$1</a>')
|
||||
.replace(/`(.*?)`/gim, '<code>$1</code>')
|
||||
.replace(/\n$/gim, '<br />')
|
||||
|
||||
return htmlText.trim()
|
||||
}
|
||||
|
||||
export const EXTERNAL_URL_RE = /^[a-z]+:/i
|
||||
export const PATHNAME_PROTOCOL_RE = /^pathname:\/\//
|
||||
|
||||
export function isExternal(path: string): boolean {
|
||||
return EXTERNAL_URL_RE.test(path)
|
||||
}
|
43
docs/.vitepress/theme/utils/pageInfo.ts
Normal file
43
docs/.vitepress/theme/utils/pageInfo.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import type { PageInfo } from '../types'
|
||||
|
||||
export function getWords(content: string): RegExpMatchArray | null {
|
||||
return content.match(/[\w\d\s,.\u00C0-\u024F\u0400-\u04FF]+/giu)
|
||||
}
|
||||
|
||||
export function getChinese(content: string): RegExpMatchArray | null {
|
||||
return content.match(/[\u4E00-\u9FD5]/gu)
|
||||
}
|
||||
|
||||
export function getEnWordCount(content: string): number {
|
||||
return getWords(content)?.reduce<number>(
|
||||
(accumulator, word) =>
|
||||
accumulator + (word.trim() === '' ? 0 : word.trim().split(/\s+/u).length),
|
||||
0,
|
||||
) || 0
|
||||
}
|
||||
|
||||
export function getCnWordCount(content: string): number {
|
||||
return getChinese(content)?.length || 0
|
||||
}
|
||||
|
||||
export function getWordNumber(content: string): number {
|
||||
return getEnWordCount(content) + getCnWordCount(content)
|
||||
}
|
||||
|
||||
export function getReadingTime(content: string,
|
||||
cnWordPerMinute = 350,
|
||||
enwordPerMinute = 160): PageInfo {
|
||||
const count = getWordNumber(content || '')
|
||||
const words = count >= 1000 ? `${Math.round(count / 100) / 10}k` : count
|
||||
|
||||
const enWord = getEnWordCount(content)
|
||||
const cnWord = getCnWordCount(content)
|
||||
|
||||
const readingTime = cnWord / cnWordPerMinute + enWord / enwordPerMinute
|
||||
const readTime = readingTime < 1 ? '1' : Number.parseInt(`${readingTime}`, 10)
|
||||
|
||||
return {
|
||||
readTime,
|
||||
words,
|
||||
}
|
||||
}
|
19
docs/contributors.json
Normal file
19
docs/contributors.json
Normal file
@ -0,0 +1,19 @@
|
||||
[
|
||||
"luoshuijs",
|
||||
"omg-xtao",
|
||||
"karakoo",
|
||||
"chuangbo",
|
||||
"CHxCOOH",
|
||||
"LittleMengBot",
|
||||
"sihuan",
|
||||
"zhxycn",
|
||||
"Billyzou0741326",
|
||||
"cworld1",
|
||||
"StellaCaerulea",
|
||||
"IJNKAWAKAZE",
|
||||
"daviszerro",
|
||||
"xr1s",
|
||||
"Nene07210721",
|
||||
"hakureiyuyuko",
|
||||
"AnotiaWang"
|
||||
]
|
31
docs/contributors.ts
Normal file
31
docs/contributors.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import contributors from './contributors.json'
|
||||
|
||||
export interface Contributor {
|
||||
name: string
|
||||
avatar: string
|
||||
}
|
||||
|
||||
export interface CoreTeam {
|
||||
avatar: string
|
||||
name: string
|
||||
github: string
|
||||
twitter?: string
|
||||
sponsors?: boolean
|
||||
description: string
|
||||
packages?: string[]
|
||||
functions?: string[]
|
||||
}
|
||||
|
||||
const contributorsAvatars: Record<string, string> = {}
|
||||
|
||||
function getAvatarUrl(name: string) {
|
||||
return `https://github.com/${name}.png`
|
||||
}
|
||||
|
||||
const contributorList = (contributors as string[]).reduce((acc, name) => {
|
||||
contributorsAvatars[name] = getAvatarUrl(name)
|
||||
acc.push({ name, avatar: contributorsAvatars[name] })
|
||||
return acc
|
||||
}, [] as Contributor[])
|
||||
|
||||
export { contributorList as contributors }
|
34
docs/index.md
Normal file
34
docs/index.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
layout: home
|
||||
|
||||
title: GramBot
|
||||
titleTemplate: Telegram robot, query the official game information
|
||||
|
||||
hero:
|
||||
name: "GramBot"
|
||||
text: ""
|
||||
tagline: |
|
||||
🔨 PaiGramTeam
|
||||
image:
|
||||
src: /icon_256px_round.png
|
||||
alt: fav
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 快速上手
|
||||
link: /quick-start/env
|
||||
features:
|
||||
- icon: 💻
|
||||
title: 支持多种设备
|
||||
details: windows、linux、mac...
|
||||
- icon: 🤖
|
||||
title: Telegram 平台
|
||||
details: Telegram BOT
|
||||
- icon: 🤝
|
||||
title: 异步开发
|
||||
details: 异步优先式开发,提高运行效率
|
||||
- icon: 🔌
|
||||
title: 插件系统
|
||||
details: 插件化开发,模块化管理
|
||||
---
|
||||
|
||||
<HomeContributors/>
|
BIN
docs/public/favicon.ico
Normal file
BIN
docs/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
5
docs/public/grid.svg
Normal file
5
docs/public/grid.svg
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
||||
<path d="M96,95h4v1H96v4H95V96H86v4H85V96H76v4H75V96H66v4H65V96H56v4H55V96H46v4H45V96H36v4H35V96H26v4H25V96H16v4H15V96H0V95H15V86H0V85H15V76H0V75H15V66H0V65H15V56H0V55H15V46H0V45H15V36H0V35H15V26H0V25H15V16H0V15H15V0h1V15h9V0h1V15h9V0h1V15h9V0h1V15h9V0h1V15h9V0h1V15h9V0h1V15h9V0h1V15h9V0h1V15h4v1H96v9h4v1H96v9h4v1H96v9h4v1H96v9h4v1H96v9h4v1H96v9h4v1H96v9h4v1H96Zm-1,0V86H86v9ZM85,95V86H76v9ZM75,95V86H66v9ZM65,95V86H56v9ZM55,95V86H46v9ZM45,95V86H36v9ZM35,95V86H26v9ZM25,95V86H16v9ZM16,85h9V76H16Zm10,0h9V76H26Zm10,0h9V76H36Zm10,0h9V76H46Zm10,0h9V76H56Zm10,0h9V76H66Zm10,0h9V76H76Zm10,0h9V76H86Zm9-10V66H86v9ZM85,75V66H76v9ZM75,75V66H66v9ZM65,75V66H56v9ZM55,75V66H46v9ZM45,75V66H36v9ZM35,75V66H26v9ZM25,75V66H16v9ZM16,65h9V56H16Zm10,0h9V56H26Zm10,0h9V56H36Zm10,0h9V56H46Zm10,0h9V56H56Zm10,0h9V56H66Zm10,0h9V56H76Zm10,0h9V56H86Zm9-10V46H86v9ZM85,55V46H76v9ZM75,55V46H66v9ZM65,55V46H56v9ZM55,55V46H46v9ZM45,55V46H36v9ZM35,55V46H26v9ZM25,55V46H16v9ZM16,45h9V36H16Zm10,0h9V36H26Zm10,0h9V36H36Zm10,0h9V36H46Zm10,0h9V36H56Zm10,0h9V36H66Zm10,0h9V36H76Zm10,0h9V36H86Zm9-10V26H86v9ZM85,35V26H76v9ZM75,35V26H66v9ZM65,35V26H56v9ZM55,35V26H46v9ZM45,35V26H36v9ZM35,35V26H26v9ZM25,35V26H16v9ZM16,25h9V16H16Zm10,0h9V16H26Zm10,0h9V16H36Zm10,0h9V16H46Zm10,0h9V16H56Zm10,0h9V16H66Zm10,0h9V16H76Zm10,0h9V16H86Z" fill="rgba(255,255,255,0.2)" fill-rule="evenodd" opacity="0.2"/>
|
||||
<path d="M6,5V0H5V5H0V6H5v94H6V6h94V5Z" fill="rgba(255,255,255,0.075)" fill-rule="evenodd"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
BIN
docs/public/icon.jpg
Normal file
BIN
docs/public/icon.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
BIN
docs/public/icon_256px.jpg
Normal file
BIN
docs/public/icon_256px.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
docs/public/icon_256px_round.png
Normal file
BIN
docs/public/icon_256px_round.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
56
docs/quick-start/env.md
Normal file
56
docs/quick-start/env.md
Normal file
@ -0,0 +1,56 @@
|
||||
# 环境检查<Badge type="tip" text="简单" />
|
||||
|
||||
## Python 环境检查教程
|
||||
|
||||
### 1.检查Python版本
|
||||
|
||||
首先,我们需要确认你的系统中是否已经安装了Python 3.8。打开终端或命令提示符,然后输入以下命令:
|
||||
|
||||
```bash
|
||||
python --version
|
||||
```
|
||||
|
||||
如果你的系统已经安装了Python 3.8+,那么你应该会看到类似于“Python 3.8.x” “Python 3.9.x” ... 的输出。
|
||||
|
||||
如果你看到的是其他版本的Python,或者你的系统提示你没有安装Python,那么你需要安装Python 3.8+。
|
||||
|
||||
GitHub Copilot: # Python Poetry环境检查教程
|
||||
|
||||
### 2.检查Poetry是否已安装
|
||||
|
||||
首先,我们需要确认你的系统中是否已经安装了Poetry。打开终端或命令提示符,然后输入以下命令:
|
||||
|
||||
```bash
|
||||
poetry --version
|
||||
```
|
||||
|
||||
如果你的系统已经安装了Poetry,那么你应该会看到类似于“Poetry version x.x.x”的输出。
|
||||
|
||||
如果你的系统提示你没有安装Poetry,那么你需要安装Poetry。
|
||||
|
||||
#### 安装Poetry
|
||||
|
||||
打开终端或命令提示符,然后输入以下命令:
|
||||
|
||||
```bash
|
||||
pip install poetry
|
||||
poetry --version
|
||||
```
|
||||
|
||||
现在你应该能看到“Poetry version x.x.x”的输出了。
|
||||
|
||||
GitHub Copilot: # Git环境检查教程
|
||||
|
||||
## 系统环境检查
|
||||
|
||||
### 1.检查Git是否已安装
|
||||
|
||||
首先,我们需要确认你的系统中是否已经安装了Git。打开终端或命令提示符,然后输入以下命令:
|
||||
|
||||
```bash
|
||||
git --version
|
||||
```
|
||||
|
||||
如果你的系统已经安装了Git,那么你应该会看到类似于“git version x.x.x”的输出。
|
||||
|
||||
如果你的系统提示你没有安装Git,那么你需要安装Git。
|
55
docs/vite.config.ts
Normal file
55
docs/vite.config.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { resolve } from 'node:path'
|
||||
import { createRequire } from 'node:module'
|
||||
import { defineConfig } from 'vite'
|
||||
import type { UserConfig } from 'vite'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import Icons from 'unplugin-icons/vite'
|
||||
import IconsResolver from 'unplugin-icons/resolver'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { MarkdownTransform } from './.vitepress/plugins/markdownTransform'
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
export default defineConfig(async () => {
|
||||
return <UserConfig>{
|
||||
server: {
|
||||
hmr: {
|
||||
overlay: false,
|
||||
},
|
||||
fs: {
|
||||
allow: [
|
||||
resolve(__dirname, '..'),
|
||||
],
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
// custom
|
||||
MarkdownTransform(),
|
||||
// plugins
|
||||
Components({
|
||||
dirs: resolve(__dirname, '.vitepress/theme/components'),
|
||||
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
|
||||
resolvers: [
|
||||
IconsResolver({
|
||||
componentPrefix: '',
|
||||
}),
|
||||
],
|
||||
dts: './.vitepress/components.d.ts',
|
||||
transformer: 'vue3',
|
||||
}),
|
||||
Icons({
|
||||
compiler: 'vue3',
|
||||
autoInstall: true,
|
||||
defaultStyle: 'display: inline-block',
|
||||
}),
|
||||
UnoCSS(),
|
||||
],
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
require('postcss-nested'),
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
25
index.md
25
index.md
@ -1,25 +0,0 @@
|
||||
---
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: "GramBot"
|
||||
text: "Telegram robot, query the official game information"
|
||||
tagline: My great project tagline
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Markdown Examples
|
||||
link: /markdown-examples
|
||||
- theme: alt
|
||||
text: API Examples
|
||||
link: /api-examples
|
||||
|
||||
features:
|
||||
- title: Feature A
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
- title: Feature B
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
- title: Feature C
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
---
|
||||
|
@ -1,85 +0,0 @@
|
||||
# Markdown Extension Examples
|
||||
|
||||
This page demonstrates some of the built-in markdown extensions provided by VitePress.
|
||||
|
||||
## Syntax Highlighting
|
||||
|
||||
VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:
|
||||
|
||||
**Input**
|
||||
|
||||
````
|
||||
```js{4}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Highlighted!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
**Output**
|
||||
|
||||
```js{4}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Highlighted!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Containers
|
||||
|
||||
**Input**
|
||||
|
||||
```md
|
||||
::: info
|
||||
This is an info box.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
This is a tip.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
This is a warning.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
This is a dangerous warning.
|
||||
:::
|
||||
|
||||
::: details
|
||||
This is a details block.
|
||||
:::
|
||||
```
|
||||
|
||||
**Output**
|
||||
|
||||
::: info
|
||||
This is an info box.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
This is a tip.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
This is a warning.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
This is a dangerous warning.
|
||||
:::
|
||||
|
||||
::: details
|
||||
This is a details block.
|
||||
:::
|
||||
|
||||
## More
|
||||
|
||||
Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).
|
58
package.json
58
package.json
@ -1,7 +1,59 @@
|
||||
{
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev",
|
||||
"docs:build": "vitepress build",
|
||||
"docs:preview": "vitepress preview"
|
||||
"dev": "vitepress dev docs --port 8080 --max-old-space-size=50000",
|
||||
"build": "vitepress build docs",
|
||||
"serve": "vitepress serve docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^0.42.0",
|
||||
"@antfu/ni": "^0.21.8",
|
||||
"@iconify/json": "^2.2.115",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/md5": "^2.3.2",
|
||||
"@vite-pwa/vitepress": "^0.2.1",
|
||||
"bumpp": "^9.2.0",
|
||||
"busuanzi.pure.js": "^1.0.3",
|
||||
"cloudinary-build-url": "^0.2.4",
|
||||
"dayjs": "^1.11.9",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"esno": "^0.17.0",
|
||||
"fast-glob": "^3.3.1",
|
||||
"feed": "^4.2.2",
|
||||
"fs-extra": "^11.1.1",
|
||||
"gray-matter": "^4.0.3",
|
||||
"less": "^4.2.0",
|
||||
"lint-staged": "^14.0.0",
|
||||
"md5": "^2.3.0",
|
||||
"medium-zoom": "^1.0.8",
|
||||
"moment": "^2.29.4",
|
||||
"ohmyfetch": "^0.4.21",
|
||||
"pathe": "^1.1.1",
|
||||
"postcss": "^8.4.29",
|
||||
"postcss-nested": "^6.0.1",
|
||||
"sass": "^1.69.3",
|
||||
"simple-git": "^3.19.1",
|
||||
"simple-git-hooks": "^2.9.0",
|
||||
"sitemap-ts": "^1.4.0",
|
||||
"typescript": "^5.2.2",
|
||||
"unocss": "^0.56.0",
|
||||
"unplugin-icons": "^0.17.0",
|
||||
"unplugin-vue-components": "^0.25.2",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-pwa": "^0.16.5",
|
||||
"vitepress": "1.0.0-rc.20",
|
||||
"vue": "^3.3.4"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "npx lint-staged"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,tsx,vue,md}": [
|
||||
"eslint --cache --fix"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"vue-custom-scrollbar": "^1.4.4"
|
||||
}
|
||||
}
|
9056
pnpm-lock.yaml
Normal file
9056
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
37
tsconfig.json
Normal file
37
tsconfig.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "esnext",
|
||||
"types": [
|
||||
"bun-types"
|
||||
],
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"moduleResolution": "Bundler",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"declaration": true,
|
||||
"resolveJsonModule": true,
|
||||
"rootDir": ".",
|
||||
"baseUrl": ".",
|
||||
"jsx": "preserve",
|
||||
"skipLibCheck": true,
|
||||
"skipDefaultLibCheck": true,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"include": [
|
||||
"docs",
|
||||
"docs/src/*.json",
|
||||
"docs/.vitepress/components/*.vue",
|
||||
"docs/.vitepress/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/dist/**"
|
||||
]
|
||||
}
|
36
unocss.config.ts
Normal file
36
unocss.config.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import {
|
||||
defineConfig,
|
||||
presetAttributify,
|
||||
presetIcons,
|
||||
presetUno,
|
||||
transformerDirectives,
|
||||
transformerVariantGroup,
|
||||
} from 'unocss'
|
||||
|
||||
export default defineConfig({
|
||||
shortcuts: {
|
||||
'border-main': 'border-gray-400 border-opacity-30',
|
||||
'bg-main': 'bg-gray-400',
|
||||
'bg-base': 'bg-white dark:bg-hex-1a1a1a',
|
||||
},
|
||||
presets: [
|
||||
presetUno(),
|
||||
presetAttributify(),
|
||||
presetIcons({
|
||||
scale: 1.2,
|
||||
warn: true,
|
||||
}),
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
primary: '#3eaf7c',
|
||||
},
|
||||
fontFamily: {
|
||||
mono: 'var(--vt-font-family-mono)',
|
||||
},
|
||||
},
|
||||
transformers: [
|
||||
transformerDirectives(),
|
||||
transformerVariantGroup(),
|
||||
],
|
||||
})
|
14
vite.config.ts.js
Normal file
14
vite.config.ts.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vitepress from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vitepress()],
|
||||
build: {
|
||||
// 指定输出目录,默认为 .vitepress/dist
|
||||
outDir: 'dist',
|
||||
// 指定静态资源目录,默认为 dist/assets
|
||||
assetsDir: 'assets',
|
||||
// 指定静态资源的基础路径,默认为 /
|
||||
base: '/',
|
||||
},
|
||||
})
|
Loading…
Reference in New Issue
Block a user