Initial rearrangment of vuetom site source

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

5
.eslintignore Normal file
View File

@ -0,0 +1,5 @@
node_modules
dist
pnpm-lock.yaml
CHANGELOG.en-US.md
!.*

76
.eslintrc.js Normal file
View File

@ -0,0 +1,76 @@
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'plugin:vue/essential',
'airbnb-base'
],
parserOptions: {
ecmaVersion: 13,
parser: '@typescript-eslint/parser',
sourceType: 'module'
},
plugins: [
'vue',
'@typescript-eslint'
],
rules: {
indent: ['error', 2],
// 'linebreak-style': ['error', 'unix'],
'linebreak-style': 'off',
quotes: ['error', 'single'],
semi: ['error', 'never'],
'no-console': 'warn',
'no-unused-vars': 0,
'arrow-parens': 0,
// 数组和对象键值对最后一个逗号, never参数不能带末尾的逗号, always参数必须带末尾的逗号
'comma-dangle': [2, 'never'],
// 控制逗号前后的空格
'comma-spacing': [2, { before: false, after: true }],
// 控制逗号在行尾出现还是在行首出现
'comma-style': [2, 'last'],
'no-tabs': 0,
'import/no-extraneous-dependencies': [1, { devDependencies: true }],
'import/no-unresolved': 0,
'import/no-absolute-path': 0,
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/html-self-closing': 'off',
'vue/no-multiple-template-root': 1,
'max-len': ['warn', 80],
'no-param-reassign': ['error', { props: false }],
'no-use-before-define': 1,
'no-unused-expressions': 0,
// add new line above comment
'lines-around-comment': [
'error',
{
beforeBlockComment: true,
beforeLineComment: true,
allowBlockStart: true,
allowClassStart: true,
allowObjectStart: true,
allowArrayStart: true
}
],
// 'newline-before-return': 'error',
'import/newline-after-import': ['error', { count: 1 }],
'import/extensions': [
'warn',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never'
}
]
}
}

9
.gitignore vendored
View File

@ -1 +1,10 @@
public
temp
fr-FR
es-ES
ja-JP
vuetom-test
dist
node_modules

61
package.json Normal file
View File

@ -0,0 +1,61 @@
{
"name": "@lauset/root",
"private": true,
"type": "module",
"scripts": {
"dev:blog": "pnpm run -C packages/blog dev",
"dev:docs": "pnpm run -C packages/docs dev",
"build:all": "pnpm build:theme && pnpm build:docs && pnpm build:blog",
"build:theme": "pnpm run -C packages/vuetom build",
"build:blog": "pnpm run -C packages/blog build",
"build:docs": "pnpm run -C packages/docs build",
"preview:blog": "pnpm run -C packages/blog preview",
"preview:docs": "pnpm run -C packages/docs preview",
"serve:blog": "pnpm run -C packages/blog serve",
"serve:docs": "pnpm run -C packages/docs serve",
"clean:all": "pnpm -r --filter=./packages/* run clean"
},
"engines": {
"node": ">=18.0.0"
},
"devDependencies": {
"@types/gulp": "^4.0.10",
"@types/gulp-autoprefixer": "0.0.33",
"@types/gulp-clean-css": "4.3.0",
"@types/gulp-rename": "2.0.1",
"@types/gulp-sass": "5.0.0",
"@typescript-eslint/eslint-plugin": "^5.46.0",
"@typescript-eslint/parser": "^5.46.0",
"chalk": "^5.2.0",
"consola": "^2.15.3",
"cross-env": "7.0.3",
"eslint": "^8.29.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-define-config": "1.12.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-vue": "^9.8.0",
"fast-glob": "^3.2.12",
"fs-extra": "^11.1.0",
"gulp": "^4.0.2",
"gulp-autoprefixer": "8.0.0",
"gulp-clean-css": "4.3.0",
"gulp-rename": "2.0.0",
"gulp-sass": "5.1.0",
"http-proxy-middleware": "^2.0.6",
"prettier": "2.8.1",
"rimraf": "^3.0.2",
"sass": "^1.56.2",
"tsx": "^3.12.1",
"typescript": "^4.9.4"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"react",
"react-dom",
"@types/react"
]
}
}
}

View File

@ -0,0 +1,7 @@
import path from 'path'
export const vpRoot = path.resolve(__dirname, '..')
export const blogRoot = path.resolve(vpRoot, '..')
export const pageRoot = path.resolve(blogRoot, 'posts')
export const pkgsRoot = path.resolve(blogRoot, '..')
export const projRoot = path.resolve(pkgsRoot, '..')

View File

@ -0,0 +1,26 @@
import fs from 'fs'
import { pageRoot } from './path'
const readDir = (dir) => {
const res = []
const files = fs.readdirSync(dir)
files.forEach(item => {
const filepath = `${dir}/${item}`
const stat = fs.statSync(filepath)
if (stat.isFile()) {
const name = item.replace('.md', '')
res.push({
text: name,
link: `/${name}`
})
}
})
return res
}
const getDefaultPage = () => ({
text: '',
link: ''
})
export default () => readDir(pageRoot)

View File

@ -0,0 +1,70 @@
import { defineConfigWithTheme } from 'vitepress'
import { VuetomThemeConfig } from 'vitepress-theme-vuetom'
import pages from './conf/posts'
export default defineConfigWithTheme<VuetomThemeConfig>({
lang: 'en-US',
title: 'Vuetom Blog',
titleTemplate: 'My Blog',
description: 'Just a blog',
base: '/myblog',
ignoreDeadLinks: true,
lastUpdated: true,
themeConfig: {
nav: [
{ text: '首页', link: '/' },
{ text: '指导', link: '/pages/guide' },
{
text: '更多',
items: [
{ text: '分类', link: '/categories/index' },
{ text: '标签', link: '/tags/index' }
]
}
],
sidebar: [
{
text: '首页',
link: '/'
},
{
text: '指导',
link: '/pages/guide'
},
{
text: '更多',
items: []
}
],
pages: pages(),
outlineTitle: 'In hac pagina',
socialLinks: [
{
icon: 'github',
link: 'https://github.com/lauset/vitepress-theme-vuetom'
}
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2021-present Vuetom'
},
lastUpdatedText: 'Updated Date',
docFooter: {
prev: 'Pagina prior',
next: 'Proxima pagina'
},
bgImg: '/imgs/blog-bg.png',
avatar: '/imgs/avatar.jpg',
author: 'Vuetom',
parallaxEnable: true,
},
markdown: {
theme: 'material-palenight',
lineNumbers: false
},
vite: {
ssr: {
noExternal: ["vitepress-theme-vuetom"]
}
}
})

View File

@ -0,0 +1,18 @@
// .vitepress/theme/index.js
// for prod
import BlogTheme from 'vitepress-theme-vuetom/blog'
// old
// import { BlogTheme } from 'vitepress-theme-vuetom'
import './custom.scss'
export default {
...BlogTheme,
enhanceApp({ app, router, siteData }) {
// globals.forEach(([name, Comp]) => {
// app.component(name, Comp)
// })
}
}

View File

@ -0,0 +1,6 @@
import path from 'path'
export const vpRoot = path.resolve(__dirname, '..')
export const docRoot = path.resolve(vpRoot, '..')
export const pkgsRoot = path.resolve(docRoot, '..')
export const projRoot = path.resolve(pkgsRoot, '..')

2
packages/blog/README.md Normal file
View File

@ -0,0 +1,2 @@
<h1 align="center">Vuetom Theme Blog</h1>

View File

@ -0,0 +1,15 @@
const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = (req, res) => {
let target = ''
if (req.url.startsWith('/myblog')) {
target = 'https://vitepress-theme-vuetom-blog.vercel.app'
}
createProxyMiddleware({
target,
changeOrigin: true,
pathRewrite: {
'^/myblog/': '/'
}
})(req, res)
}

View File

@ -0,0 +1,2 @@
Categories Index Page

14
packages/blog/index.md Normal file
View File

@ -0,0 +1,14 @@
---
title: 欢迎
layout: home
---
# {{ $frontmatter.title }}
<script setup>
import { useData } from 'vitepress'
const d = useData()
console.log(d)
</script>

View File

@ -0,0 +1,17 @@
{
"name": "@lauset/vuetom-blog",
"version": "2.2.1",
"scripts": {
"dev": "vitepress dev .",
"build": "vitepress build .",
"preview": "vitepress preview .",
"serve": "vitepress serve .",
"clean": "rimraf .vitepress/dist"
},
"devDependencies": {
"sass": "^1.56.1",
"vite": "^3.2.5",
"vitepress": "^1.0.0-alpha.30",
"vitepress-theme-vuetom": "workspace:*"
}
}

View File

@ -0,0 +1,2 @@
**Guide Page**: `/blog/pages/guide.md`

View File

@ -0,0 +1,180 @@
---
title: HelloWorld
tags: ui,front
categories: vue
time: 2022-08-31 16:21:11
layout: doc
---
# {{ $frontmatter.title }}
主题的配置在 `.vitepress/config.ts` 文件中的 themeConfig 属性中配置
下面是一些简要的配置项一览:
其中 head、sidebar、nav 对应的分别是 head脚本、侧边栏菜单、头部导航栏都可以默认为 []
<br>
以下是版本号满足 `vitepress >= 1.x.x` `vuetom-theme >= 2.x.x` 的配置
```js
// .vitepress/config.ts
export default defineConfigWithTheme<VuetomThemeConfig>({
lang: 'en-US',
base: '/vt',
title: 'Vuetom Theme',
description: 'Theme For Vitepress',
// head,
themeConfig: {
nav: nav(),
sidebar: {
'zh-CN/guide/': sidebarGuide(),
'zh-CN/mdshow/': sidebarMdShow()
},
socialLinks: [
{ icon: 'github', link: pkg.repository }
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2021-present Lauset'
},
logoImg: '/logo/vuetom-logo-m.png',
bgImg: '/imgs/homg-bg01.jpg',
bgColor: '0,0,0',
bgOpacity: 0.6,
flashEnable: true,
flashColor: ['238,17,17', '0,98,255'],
parallaxEnable: true,
pageBgEnable: true,
pageBgOpacity: 0.8,
featuresColor: ['#06cdff30', 'rgba(223,7,107,.3)']
},
markdown: {
lineNumbers: false,
config: (md) => mdPlugin(md)
},
lastUpdated: false
})
```
<br>
以下是版本号满足 `vitepress = 0.x.x` `vuetom-theme = 1.x.x` 的配置
```js light
import { defineConfigWithTheme } from 'vitepress'
import type { VuetomThemeConfig } from 'vitepress-theme-vuetom'
// .vitepress/config.ts
// 部分配置项
export default defineConfigWithTheme<VuetomThemeConfig>({
title: 'Vuetom',
base: '/',
head,
themeConfig: {
repo: 'GIT地址',
docsDir: 'docs',
sidebar,
nav,
bgImg: '/imgs/homg-bg01.jpg',
bgColor: '0,0,0',
bgOpacity: 0.6,
flashEnable: true,
flashColor: ['238,17,17', '0,98,255'],
pageBgEnable: true,
pageBgOpacity: 0.8,
featuresColor: ['#06cdff30', 'rgba(223,7,107,.3)']
},
// ...
})
```
以下是对配置项的简要说明
## 首页LOGO
**logoImg**
- 类型:`string`
- 默认值:`''`
首页上方LOGO路径中的首个 `/` 表示 `public` 目录
例如:`'/logo/homg-logo.jpg'`
## 首页背景图
**bgImg**
- 类型:`string`
- 默认值:`undefined`
首页全屏背景图,路径中的首个 `/` 表示 `public` 目录
例如:`'/imgs/homg-bg01.jpg'` 等同于 `/public/imgs/home-bg01.jpg`
**bgColor**
- 类型:`string`
- 默认值:`'0,0,0'`
背景图边缘的覆盖颜色,值是 `rgb` 的颜色值 `rgb(0,0,0)` 则写为 `'0,0,0'`,默认为黑色
**bgOpacity**
- 类型:`0 - 1`
- 默认值:`0.6`
覆盖颜色的透明度,搭配上面的覆盖颜色使用,图片中间透明度要比图片边缘透明度要小
图片中间透明度为 `当前bgOpacity - 0.3`,也就是说默认为 `0.3`
## 文章页背景图
注意:文章页背景图片与首页一致
**pageBgEnable**
- 类型:`boolean`
- 默认值:`true`
文章页面背景图是否开启,默认开启
**pageBgOpacity**
- 类型:`0 - 1`
- 默认值:`0.8`
文章页背景图透明度1将看不到背景图0能清晰看到背景图
**featuresColor**
- 类型:`string | Array`
- 默认值:`rgba(255,255,255,0.8)`
首页功能面板背景色,可以是单个颜色字符串,也可以是两个字符串组成的数组
**flashEnable**
- 类型:`boolean`
- 默认值:`false`
是否开启首页背景图闪烁功能,效果类似于朋克风故障
**flashColor**
- 类型:`string | Array`
- 默认值:`['0,0,0','0,0,0']`
首页背景闪烁时附加的色彩0: Top位置的颜色1: Right位置的颜色默认都是黑色
**parallaxEnable**
- 类型:`boolean`
- 默认值:`false`
是否开启首页部分元素视觉差效果

View File

@ -0,0 +1,14 @@
---
title: HelloWorld2
tags: java,spring
categories: java
time: 2022-08-31 16:21:22
layout: doc
---
# {{ $frontmatter.title }}
This is a word in posts/HelloWorld2.md
<script setup>
</script>

View File

@ -0,0 +1,99 @@
---
title: 代码块展示
tags: example
categories: md
time: 2022-10-31 20:21:11
layout: doc
---
# {{ $frontmatter.title }}
## MD语法展示
使用三个 ` 符号将代码包裹其中便是展示代码块
<br/>
**亮/暗主题切换**
根据文档主题模式切换
**代码块主题 macos**
可以在 language_key(语言标识) 后加入 `macos`
输入内容:
<div>
```java macos
</div>
String language = "Java";
<div>
```
</div>
展示效果:
```java macos
String language = "Java";
```
<br/>
**默认主题**
默认主题是以暗色系为主的
输入内容:
<div>
```js
</div>
String language = "JS";
<div>
```
</div>
输出内容:
```java
String language = "JS";
```
<br/>
**示例展示**
- javascript ( js macos )
```js macos
function fun(){
echo "Hello, World!";
}
fun();
```
- Java ( java )
```java
System.out.print(1);
```
- Python ( py macos )
```py macos
#!/usr/bin/env python3
print("Hello, World!");
```
- SQL ( sql )
```sql
select user_name from user_info
```
- Shell ( bash, shell )
```bash
echo '1'
```

View File

@ -0,0 +1,2 @@
Tags Index Page

View File

@ -0,0 +1,8 @@
{
"rewrites": [
{
"source": "/myblog/(.*)",
"destination": "/api/proxy"
}
]
}

View File

@ -0,0 +1,32 @@
import path from 'path'
import { defineConfig } from 'vite'
import type { Alias } from 'vite'
import { projRoot } from './.vitepress/utils/paths'
const alias: Alias[] = []
if (process.env.DOC_ENV !== 'production') {
alias.push(
{
find: /^vitepress-theme-vuetom\/docs$/,
replacement: path.resolve(projRoot, 'packages/vuetom/doc'),
},
{
find: /^vitepress-theme-vuetom\/blog$/,
replacement: path.resolve(projRoot, 'packages/vuetom/blog'),
}
)
}
export default defineConfig({
server: {
host: true,
fs: {
strict: true,
allow: ['../../']
}
},
resolve: {
alias,
},
})

View File

@ -0,0 +1,112 @@
import fs from 'fs'
import path from 'path'
import chalk from 'chalk'
import consola from 'consola'
import { docRoot } from '../utils/paths'
import { errorAndExit } from '../utils/log'
// NB: this file is only for generating files that enables developers to develop the website.
const componentLocaleRoot = path.resolve(docRoot, '.vitepress/crowdin')
const exists = 'File already exists'
async function main() {
const localeOutput = path.resolve(docRoot, '.vitepress/i18n')
if (fs.existsSync(localeOutput)) {
throw new Error(exists)
}
consola.trace(chalk.cyan('Starting for build doc for developing'))
// all language should be identical since it is mirrored from crowdin.
const dirs = await fs.promises.readdir(componentLocaleRoot, {
withFileTypes: true
})
const languages = dirs.map((dir) => dir.name)
const langWithoutEn = languages.filter((l) => l !== '.DS_Store')
await fs.promises.mkdir(localeOutput)
// build lang.json for telling `header>language-select` how many languages are there
await fs.promises.writeFile(
path.resolve(localeOutput, 'lang.json'),
JSON.stringify(languages),
'utf-8'
)
// loop through en-US
const enUS = path.resolve(componentLocaleRoot, 'en-US')
// we do not include en-US since we are currently using it as template
const languagePaths = langWithoutEn.map((l) => ({
name: l,
pathname: path.resolve(componentLocaleRoot, l)
}))
consola.debug(languagePaths)
await traverseDir(enUS, languagePaths, localeOutput)
}
async function traverseDir(
dir: string,
paths: { name: string; pathname: string }[],
targetPath: string
) {
const contents = await fs.promises.readdir(dir, { withFileTypes: true })
await Promise.all(
contents.map(async (c) => {
if (c.isDirectory()) {
await fs.promises.mkdir(path.resolve(targetPath, c.name), {
recursive: true
})
return traverseDir(
path.resolve(dir, c.name),
paths.map((p) => ({
...p,
pathname: path.resolve(p.pathname, c.name)
})),
path.resolve(targetPath, c.name)
)
} if (c.isFile()) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const content = require(path.resolve(dir, c.name))
const contentToWrite = {
'en-US': content
}
await Promise.all(
paths.map(async (p) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const content = require(path.resolve(p.pathname, c.name))
contentToWrite[p.name] = content
})
)
return fs.promises.writeFile(
path.resolve(targetPath, c.name),
JSON.stringify(contentToWrite, null, 2),
{
encoding: 'utf-8'
}
)
}
})
)
}
main()
.then(() => {
consola.success(chalk.green('Locale for website development generated'))
})
.catch((err) => {
if (err.message === exists) {
// do nothing
} else {
errorAndExit(err)
}
})

View File

@ -0,0 +1,57 @@
import { build, defineConfigWithTheme, useData } from 'vitepress'
import { VuetomThemeConfig } from 'vitepress-theme-vuetom'
import pkg from '../package.json'
import { getNav, getSidebar, head, locales } from './menus'
const nav = getNav('en-US')
const sidebar = getSidebar('en-US')
export default defineConfigWithTheme<VuetomThemeConfig>({
base: `/vt/`,
ignoreDeadLinks: true,
lastUpdated: true,
head,
locales: locales.vitepressConfig,
themeConfig: {
nav,
sidebar,
localeLinks: {
text: '',
items: [
{
text: 'English',
link: '/lang/enus'
}
]
},
socialLinks: [
{ icon: 'github', link: pkg.repository }
],
footer: {
message: 'Using the Vuetom Vitepress Theme.',
copyright: 'Copyright © 2021-present Lauset'
},
logoImg: '/imgs/Avatar.jpg',
bgImg: '/imgs/homg-bg01-200k.jpg',
bgColor: '0,0,0',
bgOpacity: 0.6,
flashEnable: true,
flashColor: ['238,17,17', '0,98,255'],
parallaxEnable: true,
pageBgEnable: true,
pageBgOpacity: 0.8,
featuresColor: ['#06cdff30', 'rgba(223,7,107,.3)']
},
markdown: {
lineNumbers: true
},
appearance: true,
vite: {
ssr: {
noExternal: ["vitepress-theme-vuetom"]
}
}
})

View File

@ -0,0 +1,14 @@
---
title: What's the Vitepress
head:
- - meta
- name: description
content: vuetom info
- - meta
- name: keywords
content: vuetom theme
---
# {{ $frontmatter.title }}
developing...

View File

@ -0,0 +1,149 @@
---
layout: home
title: Vuetom
titleTemplate: Vite & Vue Powered Static Site Generator
hero:
name: Vuetom
text:
tagline: vitepress flat theme
actions:
- theme: brand big
text: Quick Start
link: /en-US/guide/info
- theme: alt big
text: Config
link: /en-US/guide/config
features:
- title: 📦 优化的构建
details: 可选 “多页应用” 或 “库” 模式的预配置 Rollup 构建
- title: 🔩 通用的插件
details: 在开发和构建之间共享 Rollup-superset 插件接口。
- title: 🔑 完全类型化的API
details: 灵活的 API 和完整 TypeScript 类型。
---
<div class="frontpage sponsors">
<h2>Thanks</h2>
<div class="platinum-sponsors">
<a v-for="{ href, src, name, id } of sponsors.filter(s => s.tier === 'platinum')" :href="href" target="_blank" rel="noopener" aria-label="sponsor-img">
<img :src="src" :alt="name" :id="`sponsor-${id}`">
<p>{{ name }}</p>
</a>
</div>
<div class="gold-sponsors">
<a v-for="{ href, src, name, id } of sponsors.filter(s => s.tier !== 'platinum')" :href="href" target="_blank" rel="noopener" aria-label="sponsor-img">
<img :src="src" :alt="name" :id="`sponsor-${id}`">
<p>{{ name }}</p>
</a>
</div>
</div>
<script setup>
import { onMounted } from 'vue'
const sponsors = [
{
"id": "vue",
"name": "Vue",
"href": "https://v3.cn.vuejs.org/",
"src": "https://v3.cn.vuejs.org/logo.png",
"tier": "platinum"
},
{
"id": "vite",
"name": "Vite",
"href": "https://vitejs.cn/",
"src": "https://vitejs.cn/logo.svg"
},
{
"id": "vitepress",
"name": "Vitepress",
"href": "https://fttp.jjf-tech.cn/vitepress/",
"src": "https://v3.cn.vuejs.org/logo.png"
},
{
"id": "elementplus",
"name": "Element Plus",
"href": "https://element-plus.gitee.io/zh-CN/",
"src": "https://element-plus.gitee.io/images/element-plus-logo.svg"
}
]
function fetchReleaseTag() {
onMounted(() => {
fetch('https://api.github.com/repos/vitejs/docs-cn/releases/latest')
.then((res) => res.json())
.then((json) => {
const dom = document.getElementsByClassName('name')
const mainTitle = dom[0]
mainTitle.style.position = 'relative'
const docsReleaseTag = document.createElement('span')
docsReleaseTag.classList.add('release-tag')
const releaseTagName = json.tag_name
docsReleaseTag.innerText = releaseTagName
if (releaseTagName !== undefined) {
mainTitle.appendChild(docsReleaseTag)
}
})
})
}
fetchReleaseTag()
</script>
<style>
.sponsors {
padding: 0 1.5rem 2rem;
font-size: 0.8rem;
}
.sponsors a {
color: #999;
margin: 1em;
display: block;
}
.sponsors img {
max-width: 160px;
max-height: 40px;
}
.sponsors.frontpage {
text-align: center;
}
.sponsors.frontpage img {
display: inline-block;
vertical-align: middle;
}
.sponsors.frontpage h2 {
color: #999;
font-size: 1.2rem;
border: none;
}
.sponsors.sidebar a img {
max-height: 36px;
}
.platinum-sponsors {
margin-bottom: 1.5em;
}
.platinum-sponsors a img {
max-width: 240px;
max-height: 60px;
}
.gold-sponsors {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: center;
}
</style>

View File

@ -0,0 +1,17 @@
---
title: 留言反馈
---
# {{ $frontmatter.title }}
> 该页面是在 Markdown 中引入 Vue 组件简单的展示
页面文件: `.vitepress/views/vt/vt-feedback.vue`
<ClientOnly>
<VtFeedback />
</ClientOnly>
::: tip
正在开发中,你以后可以把想说的话写在这里
:::

View File

@ -0,0 +1,182 @@
---
title: 主题配置
head:
- - meta
- name: description
content: vuetom 主题配置项
- - meta
- name: keywords
content: vuetom theme config
---
# {{ $frontmatter.title }}
主题的配置在 `.vitepress/config.ts` 文件中的 themeConfig 属性中配置
下面是一些简要的配置项一览:
其中 head、sidebar、nav 对应的分别是 head脚本、侧边栏菜单、头部导航栏都可以默认为 []
<br>
以下是版本号满足 `vitepress >= 1.x.x` `vuetom-theme >= 2.x.x` 的配置
```js macos
// .vitepress/config.ts
export default defineConfigWithTheme<VuetomThemeConfig>({
lang: 'en-US',
base: '/vt',
title: 'Vuetom Theme',
description: 'Theme For Vitepress',
// head,
themeConfig: {
nav: nav(),
sidebar: {
'zh-CN/guide/': sidebarGuide(),
'zh-CN/mdshow/': sidebarMdShow()
},
socialLinks: [
{ icon: 'github', link: pkg.repository }
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2021-present Lauset'
},
logoImg: '/logo/vuetom-logo-m.png',
bgImg: '/imgs/homg-bg01.jpg',
bgColor: '0,0,0',
bgOpacity: 0.6,
flashEnable: true,
flashColor: ['238,17,17', '0,98,255'],
parallaxEnable: true,
pageBgEnable: true,
pageBgOpacity: 0.8,
featuresColor: ['#06cdff30', 'rgba(223,7,107,.3)']
},
markdown: {
lineNumbers: false,
config: (md) => mdPlugin(md)
},
lastUpdated: false
})
```
<br>
以下是版本号满足 `vitepress = 0.x.x` `vuetom-theme = 1.x.x` 的配置
```js macos
import { defineConfigWithTheme } from 'vitepress'
import type { VuetomThemeConfig } from 'vitepress-theme-vuetom'
// .vitepress/config.ts
// 部分配置项
export default defineConfigWithTheme<VuetomThemeConfig>({
title: 'Vuetom',
base: '/',
head,
themeConfig: {
repo: 'GIT地址',
docsDir: 'docs',
sidebar,
nav,
bgImg: '/imgs/homg-bg01.jpg',
bgColor: '0,0,0',
bgOpacity: 0.6,
flashEnable: true,
flashColor: ['238,17,17', '0,98,255'],
pageBgEnable: true,
pageBgOpacity: 0.8,
featuresColor: ['#06cdff30', 'rgba(223,7,107,.3)']
},
// ...
})
```
以下是对配置项的简要说明
## 首页LOGO
**logoImg**
- 类型:`string`
- 默认值:`''`
首页上方LOGO路径中的首个 `/` 表示 `public` 目录
例如:`'/logo/homg-logo.jpg'`
## 首页背景图
**bgImg**
- 类型:`string`
- 默认值:`undefined`
首页全屏背景图,路径中的首个 `/` 表示 `public` 目录
例如:`'/imgs/homg-bg01.jpg'` 等同于 `/public/imgs/home-bg01.jpg`
**bgColor**
- 类型:`string`
- 默认值:`'0,0,0'`
背景图边缘的覆盖颜色,值是 `rgb` 的颜色值 `rgb(0,0,0)` 则写为 `'0,0,0'`,默认为黑色
**bgOpacity**
- 类型:`0 - 1`
- 默认值:`0.6`
覆盖颜色的透明度,搭配上面的覆盖颜色使用,图片中间透明度要比图片边缘透明度要小
图片中间透明度为 `当前bgOpacity - 0.3`,也就是说默认为 `0.3`
## 文章页背景图
注意:文章页背景图片与首页一致
**pageBgEnable**
- 类型:`boolean`
- 默认值:`true`
文章页面背景图是否开启,默认开启
**pageBgOpacity**
- 类型:`0 - 1`
- 默认值:`0.8`
文章页背景图透明度1将看不到背景图0能清晰看到背景图
**featuresColor**
- 类型:`string | Array`
- 默认值:`rgba(255,255,255,0.8)`
首页功能面板背景色,可以是单个颜色字符串,也可以是两个字符串组成的数组
**flashEnable**
- 类型:`boolean`
- 默认值:`false`
是否开启首页背景图闪烁功能,效果类似于朋克风故障
**flashColor**
- 类型:`string | Array`
- 默认值:`['0,0,0','0,0,0']`
首页背景闪烁时附加的色彩0: Top位置的颜色1: Right位置的颜色默认都是黑色
**parallaxEnable**
- 类型:`boolean`
- 默认值:`false`
是否开启首页部分元素视觉差效果

View File

@ -0,0 +1,49 @@
---
title: 夜间模式
lang: en-US
---
# {{ $frontmatter.title }}
默认的话夜间模式切换按钮是一直有的,右上角那个太阳图标
## 原理
开关操作修改的是 HTML 根标签的样式,会加上 dark 样式
```html
<html class="dark" lang="zh-CN"></html>
```
我们可以事先定义一些 css变量来完成不同语言下或者不同模式下的样式变换
## 主题色覆盖
修改 theme/custom.scss 文件即可
简单展示部分
```css
:root {
// 重写主题色
// 主色
--vp-c-brand: var(--vp-c-blue);
--vp-c-brand-light: var(--vp-c-blue-light);
--vp-c-brand-lighter: var(--vp-c-blue-lighter);
--vp-c-brand-dark: var(--vp-c-blue-dark);
--vp-c-brand-darker: var(--vp-c-blue-darker);
// 副色
--vp-c-second: var(--vp-c-pink);
--vp-c-second-light: var(--vp-c-pink-light);
--vp-c-second-lighter: var(--vp-c-pink-lighter);
--vp-c-second-dark: var(--vp-c-pink-dark);
--vp-c-second-darker: var(--vp-c-pink-darker);
}
.dark {
}
```

View File

@ -0,0 +1,17 @@
# 指引
`info` : 介绍
`start` : 快速开始
`question` : 问题一览
`prodir` : 主题项目结构
`config` : 主题配置
`lang` : 国际化配置
::: tip
这里展示的是指引菜单下所有的子菜单
:::

View File

@ -0,0 +1,50 @@
---
title: 什么是Vitepress
head:
- - meta
- name: description
content: vuetom 介绍
- - meta
- name: keywords
content: vuetom theme
---
# {{ $frontmatter.title }}
VitePress 是 VuePress 的升级,以 Vite 为基础构建的。是一款快速搭建文档静态网站的框架。
Vite法语意为 "快速的",发音 `/vit/` ,发音同 "veet"是一种新型前端构建工具能够显著提升前端开发体验。Vite 意在提供开箱即用的配置,同时它的 插件 API 和 JavaScript API 带来了高度的可扩展性,并有完整的类型支持。它主要由两部分组成:
- 一个开发服务器,它基于 原生 ES 模块 提供了 丰富的内建功能,如速度快到惊人的 模块热更新HMR
- 一套构建指令,它使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。
## vuetom 呢?
是的,是一款主题,因 vitepress 而诞生。建立在 Vue3 与 Vite 之上的一款文档框架的主题。含有 `文档``博客` 两种风格模板。其推出目的是为了让大家体验并使用到更多美丽而又有趣的 vitepress 主题,进而大家可以发挥想象展示出更多优美的文档。
## 有什么特点
使用现代扁平化的设计风格,部分 UI 尽量接近于 macos 界面风格
该主题包含了以下相关技术
- [nodejs](http://nodejs.cn/)
- [vite](https://vitejs.cn/)
- [vue3](https://v3.vuejs.org/)
- [vitepress](https://vitejs.cn/vitepress/)
- [tailwindcss](https://www.tailwindcss.cn/docs)
该主题包含了一下功能模块
**内置UI组件:** 扁平化数据组织,方便编写。含有按钮,弹框,卡片等基础组件
**主题与样式:** 主要包含布局,间距,排版,颜色,边框
**API与指令:** 可搭配组件使用,实现不同组件不同指令效果
## 推荐开发工具?
这就无所谓了吧哈哈。
[vscode编辑器](https://code.visualstudio.com/) => [下载地址](https://blog.csdn.net/bielaiwuyang1999/article/details/117814237)

View File

@ -0,0 +1,109 @@
---
title: 多国语言配置
lang: en-US
---
# {{ $frontmatter.title }}
:::warning
适配于 vitepress 1.x.x 版本的功能正在制作,下面是 0.x.x 版本的国际化方案
:::
你也可以配置多国语言,以首页为例,先在配置文件里配置下 locales然后创建对应的语言文件夹与文件
## 改配置文件
需要在 config.ts 中配置 locales注意 themeConfig 属性里也要配,两个 locales 内容是不一样的
themeConfig 中的 locales 配置是为了展示下拉菜单的展示内容
根Config 中的 locales 配置是为了展示头部标题内容description属性可有可无
```js
// .vitepress/config.ts
export default defineConfigWithTheme<VuetomThemeConfig>({
// ...
themeConfig: {
// ...
locales: {
'/zh-CN/': {
label: '简体中文',
selectText: '多国语言'
},
'/en-US/': {
label: 'English',
selectText: 'Languages'
}
}
},
locales: {
'/zh-CN/': {
lang: 'zh-CN',
title: 'Vuetom 主题',
description: '为 Vitepress 提供的一款主题'
},
'/en-US/': {
lang: 'en-US',
title: 'Vuetom Theme',
description: 'Theme For Vitepress'
}
}
})
```
**locales** 中的属性介绍
<b>lang</b>: 会直接设置给 `<html>` 标签
<b>title</b>: 不同语言时网站的标题,会替换之前定义的 title
<b>description</b>: 不同语言时网站的描述
<b>label</b>: 语言选择时展示出来的文本内容例如中文或English
<b>selectText</b>: 语言选择时下拉菜单的文本例如多国语言或者Languages
## 改首页
在 .vitepress 同级目录新建 `zh-CN``en-US` 文件夹,然后在这个文件夹中分别创建一个 `index.md` 文件
**zh-CN/index.md** 中写入 **中文首页** 要展示的内容
**en-US/index.md** 中写入 **英文首页** 要展示的内容
原来与 .vitepress 同级的 `index.md` 文件中可以改为转发至 `zh-CN/index` 或者 `en-US/index`
例如下方的代码,会直接将 `/` 转发到 `/zh-CN/` 这样就会直接前往中文首页了
```markdown
---
title: 'Vuetom Theme'
lang: en-US
page: true
---
<script setup>
if (typeof window !== 'undefined') {
const preferredLang = 'zh-CN'
window.location.pathname = `/${preferredLang}/`
}
</script>
```
::: warning
其实原理就是路径前加了一个语言标识,那么就在页面文件外加个语言文件夹就好了<br>
需要处理的就是书写导航栏和菜单栏时记得要在 link 属性前加上语言标识
:::
下面试试访问一下:
访问 localhost:3000/zh-CN/ 会前往中文首页
访问 localhost:3000/en-US/ 会前往英文首页
访问 localhost:3000 会前往 localhost:3000/zh-CN/

View File

@ -0,0 +1,57 @@
---
title: 框架目录
head:
- - meta
- name: description
content: Vuetom 主题目录结构
- - meta
- name: keywords
content: project dir.
---
# 主题目录
在使用一个框架,其实也要简单了解下该框架的项目文件结构,请向下看吧。
```bash
vuetom
├─ blog 博客主题Vue组件 文件夹
├─ doc 新版文档适配vp1.x 文件夹
├─ docs 旧版文档主题组件 文件夹
│ ├─ components 主题Vue组件 文件夹
│ ├─ composables 组件脚本 文件夹
│ ├─ layouts 布局组件 文件夹
│ └─ index.ts 主题入口 文件
├─ icons 共用图标Vue组件 文件夹
├─ styles 全局SCSS样式 文件夹
├─ support 供支持脚本 文件夹
├─ types 规范描述 文件夹
├─ constant.ts 常量定义 文件
└─ index.ts 主题入口文件 文件
```
接下来介绍本文档**docs**文件夹
```bash
docs
├─ .vitepress
│ └─ config.ts 主题主要配置文件
├─ public 静态资源文件
├─ zh-CN 中文页面
│ ├─ feedback 留言反馈
│ ├─ guide 指引
│ ├─ mdshow Markdown示例
│ ├─ menu UI组件
│ ├─ styl 主题与样式
│ └─ index.md 中文首页
├─ crowdin.yml 多国语言配置
├─ index.md 项目首页
├─ CHANGELOG.md 更新日志
├─ package.json 包配置
├─ README.md 项目说明
├─ tsconfig.json ts配置
└─ vite.config.ts vite配置
```

View File

@ -0,0 +1,53 @@
---
title: 常见问题
head:
- - meta
- name: description
content: 常见问题汇总
- - meta
- name: keywords
content: question
---
# {{ $frontmatter.title }}
是否经常卡在一些莫名其妙的问题上?让我们来汇总一下问题并给出相应的解决方案吧!
## 问题列表
- [版本多久更新一次?](#q01)
- [我的样式没有起作用。](#q02)
- [我不想要背景图咋办啊?](#q03)
## 问题解答
以下是针对于近期问题所作的答复
- <h3 id="q01">版本多久更新一次?</h3>
目前进度较慢,但是每周都会更新主要内容的
- <h3 id="q02">我的样式没有起作用。</h3>
查看 `.vitepress/config.js` 文件进中 `theme` 项是否配置正确
- <h3 id="q03">我不想要背景图咋办啊?</h3>
你可以用一张纯白色的图片作为背景图啊嘿嘿嘿
## 开发进度
| 功能组件 | 开发进度 | 预估 |
| - | - | - |
| 文档风格主题 vitepress 0.x.x | 开发中80% | 2022.5 |
| 文档风格主题 vitepress 1.x.x | 开发中80% | 2022.8 |
| 博客风格主题 vitepress 1.x.x | 开发中50% | 2022.11 |
## 需要帮助?
可点击 [留言反馈](/zh-CN/feedback/) 前往问题反馈界面对问题进行简单的描述
::: tip
目前 vitepress 版本已进入 1.0.0 , vuetom-theme 版本已进入 2.0.0
:::

View File

@ -0,0 +1,158 @@
---
title: 快速使用
head:
- - meta
- name: description
content: 教你如何掌握框架的工作流程,快速上手。
- - meta
- name: keywords
content: 开始使用
---
# {{ $frontmatter.title }}
请确保你已经用过 Vitepress 框架,因为主题是建立在框架的基础上使用的。
请确保你使用的 vue 版本是 3+ 且 vitepress 是 1.x 哦。
## 最方便的方式
直接拉取本项目至本地packages/docs 和 packages/blog 目录下分别是文档和博客示例,修改内容打包编译即可
## 其他方式
### **1.** 脚手架初始化
可以使用脚手架 vuetom-cli 脚手架来进行主题的初始化,会在你本地初始化一个项目
网速慢可以再次尝试或者直接前往模版仓库拉取 [模版仓库](https://github.com/lauset/vuetom-cli)
1. 首先安装脚手架NPM安装前请确保开启管理员身份运行保证有权限
```js light
npm i -g vuetom-cli
```
2. 查看是否安装成功,黑窗口运行一下命令,返回版本号 x.x.x 则表示安装成功
```js light
vuetom-cli -v
```
1. 初始化模版,可以选择是否新建目录、仓息、作者、模版仓库等
```js light
vuetom-cli init
```
1. 然后便会下载模版,下载完成后,执行以下命令安装依赖并运行文档网站
```js light
pnpm i
pnpm dev
```
::: warning
模版是从 github 上拉取的,可能有时候会有网速的困惑,也可手动前往拉取下载本地启用
文档模版:<https://github.com/lauset/vuetom-cli/tree/temp-docs>
博客模版:<https://github.com/lauset/vuetom-cli/tree/temp-blog>
:::
<br/>
### **2.** 通过NPM下载安装主题已弃用
:::danger ⚠️ 已弃用
上传至远程仓库,作为三方依赖使用打包时会出现样式引入问题,暂时放弃使用
从 vitepress-theme-vuetom v2.2.x 开始不再上传远程仓库而是作为目录加至模版项目中
:::
使用这个方式首先你要搭建一个 vitepress 项目,主题只是会覆盖默认样式而已,所以项目还是得搭起来的,可以前往下面 vitepress 官网链接查看并开始搭建
[vitepress搭建文档](https://vitepress.vuejs.org/guide/getting-started.html)
搭建完后最简单的样子就是项目目录里有个 index.md 文件,那么开始下一步
1. 安装主题依赖
使用 NPM 安装最新版本的 vitepress-theme-vuetom 主题依赖包,在你的 vitepress 项目下安装主题包,打开 `终端DOS` 输入
```js light
npm i -D vitepress-theme-vuetom
```
2. 开始引入主题
先在 .vitepress (这个文件夹和首页 index.md 是同级目录,没有的自己创建或者去 vitepress 官网看文档)中新建一个名为 theme 的文件夹,在该文件下新建一个 index.ts 文件,当然用 js 还是 ts 文件就看你自己项目的决定了。
大致内容如下:
`VuetomTheme` 是主要的主题布局
`VuetomUI` 是内置的UI组件
```javascript light
// .vitepress/theme/index.ts
// 默认导出文档类型的主题
import VuetomTheme from 'vitepress-theme-vuetom'
export default {
...VuetomTheme,
enhanceApp({ app, router, siteData }) {
// app.use(VuetomUI)
}
}
```
引入了主题,然后你的 index.md 里写上一些内容应该就可以看出效果了
```html light
---
home: true
heroImage: /logo/vuetom-logo-m.png
heroAlt: LOGO
heroText: Vuetom
tagline: vitepress flat theme
actionText: 快 速 开 始
actionLink: /zh-CN/guide/info
altActionText: 配 置
altActionLink: /zh-CN/guide/config
features:
- title: 📦 优化的构建
details: 可选 “多页应用” 或 “库” 模式的预配置 Rollup 构建
- title: 🔩 通用的插件
details: 在开发和构建之间共享 Rollup-superset 插件接口。
- title: 🔑 完全类型化的API
details: 灵活的 API 和完整 TypeScript 类型。
footer: MIT Licensed
---
<div class="frontpage sponsors">
<h2>{{ data.text }}</h2>
</div>
<script setup>
import { onMounted, reactive } from 'vue'
const data = reactive({
text: '自定义内容'
})
onMounted(() => {
})
</script>
<style>
</style>
```
运行项目后,在 [localhost:3000] 中进入首页
至少到这里主题已经安装完成了,下一步就是主题的配置了,主题什么样还是要看你配的什么样子哦。

View File

@ -0,0 +1,160 @@
---
layout: home
title: Vuetom
titleTemplate: Vite & Vue Powered Static Site Generator
hero:
name: Vuetom
text:
tagline: vitepress flat theme
actions:
- theme: brand big
text: 快 速 开 始
link: /zh-CN/guide/info
- theme: alt big
text: 配 置
link: /zh-CN/guide/config
features:
- title: 📦 优化的构建
details: 可选 “多页应用” 或 “库” 模式的预配置 Rollup 构建
- title: 🔩 通用的插件
details: 在开发和构建之间共享 Rollup-superset 插件接口。
- title: 🔑 完全类型化的API
details: 灵活的 API 和完整 TypeScript 类型。
---
<div class="frontpage sponsors">
<h2>感 谢</h2>
<div class="platinum-sponsors">
<a v-for="{ href, src, name, id } of sponsors.filter(s => s.tier === 'platinum')" :href="href" target="_blank" rel="noopener" aria-label="sponsor-img">
<img :src="src" :alt="name" :id="`sponsor-${id}`">
<p>{{ name }}</p>
</a>
</div>
<div class="gold-sponsors">
<a v-for="{ href, src, name, id } of sponsors.filter(s => s.tier !== 'platinum')" :href="href" target="_blank" rel="noopener" aria-label="sponsor-img">
<img :src="src" :alt="name" :id="`sponsor-${id}`">
<p>{{ name }}</p>
</a>
</div>
</div>
<script setup>
import { onMounted } from 'vue'
import pk from 'vitepress-theme-vuetom/package.json'
const sponsors = [
{
"id": "vue",
"name": "Vue",
"href": "https://v3.cn.vuejs.org/",
"src": "https://v3.cn.vuejs.org/logo.png",
"tier": "platinum"
},
{
"id": "vite",
"name": "Vite",
"href": "https://vitejs.cn/",
"src": "https://vitejs.cn/logo.svg"
},
{
"id": "vitepress",
"name": "Vitepress",
"href": "https://fttp.jjf-tech.cn/vitepress/",
"src": "https://v3.cn.vuejs.org/logo.png"
},
{
"id": "elementplus",
"name": "Element Plus",
"href": "https://element-plus.gitee.io/zh-CN/",
"src": "https://element-plus.gitee.io/images/element-plus-logo.svg"
}
]
function fetchReleaseTag() {
onMounted(() => {
const dom = document.getElementsByClassName('name')
const mainTitle = dom[0]
const docsReleaseTag = document.createElement('span')
docsReleaseTag.classList.add('release-tag')
const releaseTagName = `v${pk.version}`
docsReleaseTag.innerText = releaseTagName
if (releaseTagName !== undefined) {
mainTitle.appendChild(docsReleaseTag)
}
// fetch('https://api.github.com/repos/vitejs/docs-cn/releases/latest')
// .then((res) => res.json())
// .then((json) => {
// const mainTitle = document.getElementById('main-title')
// mainTitle.style.position = 'relative'
// const docsReleaseTag = document.createElement('span')
// docsReleaseTag.classList.add('release-tag')
// const releaseTagName = json.tag_name
// docsReleaseTag.innerText = releaseTagName
// if (releaseTagName !== undefined) {
// mainTitle.appendChild(docsReleaseTag)
// }
// })
})
}
fetchReleaseTag()
</script>
<style>
.sponsors {
padding: 0 1.5rem 2rem;
font-size: 0.8rem;
}
.sponsors a {
color: #999;
margin: 1em;
display: block;
}
.sponsors img {
max-width: 160px;
max-height: 40px;
}
.sponsors.frontpage {
text-align: center;
}
.sponsors.frontpage img {
display: inline-block;
vertical-align: middle;
}
.sponsors.frontpage h2 {
color: #999;
font-size: 1.2rem;
border: none;
}
.sponsors.sidebar a img {
max-height: 36px;
}
.platinum-sponsors {
margin-bottom: 1.5em;
}
.platinum-sponsors a img {
max-width: 240px;
max-height: 60px;
}
.gold-sponsors {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: center;
}
</style>

View File

@ -0,0 +1,102 @@
---
title: 代码块展示
head:
- - meta
- name: description
content: 代码块展示
- - meta
- name: keywords
content: code
---
# {{ $frontmatter.title }}
## MD语法展示
使用三个 ` 符号将代码包裹其中便是展示代码块
<br/>
**亮/暗主题切换**
根据文档主题模式切换
**代码块主题 macos**
可以在 language_key(语言标识) 后加入 `macos`
输入内容:
<div>
```java macos
</div>
String language = "Java";
<div>
```
</div>
展示效果:
```java macos
String language = "Java";
```
<br/>
**默认主题**
默认主题是以暗色系为主的
输入内容:
<div>
```js
</div>
String language = "JS";
<div>
```
</div>
输出内容:
```java
String language = "JS";
```
<br/>
**示例展示**
- javascript ( js macos )
```js macos
function fun(){
echo "Hello, World!";
}
fun();
```
- Java ( java )
```java
System.out.print(1);
```
- Python ( py macos )
```py macos
#!/usr/bin/env python3
print("Hello, World!");
```
- SQL ( sql )
```sql
select user_name from user_info
```
- Shell ( bash, shell )
```bash
echo '1'
```

View File

@ -0,0 +1,58 @@
---
title: 自定义语法
head:
- - meta
- name: description
content: 自定义 Markdown 语法
- - meta
- name: keywords
content: markdown custom
---
# {{ $frontmatter.title }}
## 信息框
```md
::: tip 使用TIPS代替
提示信息
:::
::: info
信息消息
:::
::: warning
警告消息
:::
::: danger
危险消息
:::
::: details Details
详细信息
:::
```
效果如下:
::: tip 使用TIPS代替
提示内容
:::
::: info
INFO消息
:::
::: warning
WARNING消息 <a>a链接</a>
:::
::: danger
DANGER消息 [md链接](./example.md)
:::
::: details Details
详细信息
:::

View File

@ -0,0 +1,72 @@
---
title: 效果示例
head:
- - meta
- name: description
content: 来看看 MD 会变成什么样子
- - meta
- name: keywords
content: markdown example
---
# Markdown 效果示例
-------------------- 手动分割线 --------------------
# This is an h1 tag
## This is an h2 tag
### This is an h3 tag
#### This is an h4 tag
##### This is an h5 tag
###### This is an h6 tag
*这是斜体*
_这是斜体_
**这是黑体**
__这是黑体__
*斜体里加**黑体***
**黑体里加*斜体***
* Item 1
* Item 2
* Item 2a
* Item 2b
1. Item 1
1. Item 2
1. Item 3
1. Item 3a
1. Item 3b
![Yaktocat的图片](/logo/vuetom-logo.png)
http://github.com - automatic!
[GitHub](http://github.com)
As Kanye West said:
> We're living the future so
> the present is our past.
I think you should use an
`<addr>` element here instead.
First Header | Second Header
------------ | -------------
Content from cell 1 | Content from cell 2
Content in the first column | Content in the second column
~~this~~
😝🌟🐫✨🚶

View File

@ -0,0 +1,31 @@
---
title: UI组件
head:
- - meta
- name: description
content: 各种各样的扁平化UI组件
- - meta
- name: keywords
content: components
---
# {{ $frontmatter.title }}
### `Vuetom UI`
[ui 文档](http://ui.tomhub.cn)
[ui github](https://github.com/lauset/vuetom-ui)
::: tip
UI 文档正在不断完善中请客观耐心等待一下吧T-T
:::
### Markdown 语法示例
这里将会展示在该文档中markdown所呈现的效果
`Example` : Markdown 语法示例
`Custom md` : 自定义语法

View File

@ -0,0 +1,7 @@
{
"view-source": "Code",
"edit-on-github": "Edit on Github",
"copy-code": "Copy Code",
"copy-success": "Copy Success",
"copy-error": "Copy Error"
}

View File

@ -0,0 +1,30 @@
[
{
"text": "Guide",
"link": "/guide/info",
"activeMatch": "/guide/info"
},
{
"text": "Components",
"link": "/mdshow/",
"activeMatch": "/mdshow/"
},
{
"text": "Links",
"items": [
{
"text": "FeedBack",
"link": "/feedback/",
"activeMatch": "/feedback/"
},
{
"text": "Gitee",
"link": "https://gitee.com/lauset/vitepress-theme-vuetom"
},
{
"text": "Vitepress",
"link": "https://vitepress.vuejs.org/"
}
]
}
]

View File

@ -0,0 +1,34 @@
[
{
"text": "Basic",
"items": [
{ "text": "What's the Vitepress?", "link": "/guide/info" },
{ "text": "Quick Start", "link": "/guide/start" },
{
"text": "Questions",
"link": "/guide/question"
},
{
"text": "Project Dir",
"link": "/guide/prodir"
}
]
},
{
"text": "Advanced",
"items": [
{
"text": "Theme Config",
"link": "/guide/config"
},
{
"text": "Languages",
"link": "/guide/lang"
},
{
"text": "Dark Mode",
"link": "/guide/dark"
}
]
}
]

View File

@ -0,0 +1,19 @@
{
"langshow": {
"text": "MD Show",
"items": [
{
"link": "/mdshow/example",
"text": "Example"
},
{
"link": "/mdshow/custom",
"text": "Custom"
},
{
"link": "/comp/codeblock",
"text": "Code Block"
}
]
}
}

View File

@ -0,0 +1,20 @@
{
"label": "English",
"selectText": "Languages",
"editLinkText": "Suggest changes to this page",
"lastUpdatedText": "Last Updated",
"localeLinks": {
"text": "",
"items": [
{
"text": "Chinese",
"link": "/zh-CN/"
},
{
"text": "English",
"link": "/en-US/"
}
]
},
"socialLinks": [{ "icon": "github", "link": "" }]
}

View File

@ -0,0 +1,5 @@
{
"title": "Vuetom Theme",
"lang": "en-US",
"description": "Theme for Vitepress"
}

View File

@ -0,0 +1,7 @@
{
"view-source": "代码",
"edit-on-github": "前往 Github 编辑",
"copy-code": "复制",
"copy-success": "复制成功",
"copy-error": "复制出现了一些问题"
}

View File

@ -0,0 +1,30 @@
[
{
"text": "指引",
"link": "/guide/info",
"activeMatch": "/guide/"
},
{
"text": "组件",
"link": "/mdshow/",
"activeMatch": "/mdshow/"
},
{
"text": "链接",
"items": [
{
"text": "反馈",
"link": "/feedback/",
"activeMatch": "/feedback/"
},
{
"text": "码云",
"link": "https://gitee.com/lauset/vitepress-theme-vuetom"
},
{
"text": "Vitepress官网",
"link": "https://vitepress.vuejs.org/"
}
]
}
]

View File

@ -0,0 +1,34 @@
[
{
"text": "基础",
"items": [
{ "text": "什么是Vitepress?", "link": "/guide/info" },
{ "text": "快速开始", "link": "/guide/start" },
{
"text": "问题一览",
"link": "/guide/question"
},
{
"text": "主题目录",
"link": "/guide/prodir"
}
]
},
{
"text": "进阶",
"items": [
{
"text": "主题配置",
"link": "/guide/config"
},
{
"text": "国际化",
"link": "/guide/lang"
},
{
"text": "夜间模式",
"link": "/guide/dark"
}
]
}
]

View File

@ -0,0 +1,19 @@
[
{
"text": "语法",
"items": [
{
"link": "/mdshow/example",
"text": "MD语法示例"
},
{
"link": "/mdshow/custom",
"text": "自定义语法"
},
{
"link": "/mdshow/codeblock",
"text": "代码块展示"
}
]
}
]

View File

@ -0,0 +1,20 @@
{
"label": "简体中文",
"selectText": "选择语言",
"editLinkText": "对本页提出修改建议",
"lastUpdatedText": "最后更新",
"localeLinks": {
"text": "",
"items": [
{
"text": "简体中文",
"link": "/zh-CN/"
},
{
"text": "English",
"link": "/en-US/"
}
]
},
"socialLinks": [{ "icon": "github", "link": "" }]
}

View File

@ -0,0 +1,5 @@
{
"title": "Vuetom 主题",
"lang": "zh-CN",
"description": "一款为 Vitepress 而生的主题"
}

View File

@ -0,0 +1,16 @@
{
"en-US": {
"view-source": "Code",
"edit-on-github": "Edit on Github",
"copy-code": "Copy Code",
"copy-success": "Copy Success",
"copy-error": "Copy Error"
},
"zh-CN": {
"view-source": "代码",
"edit-on-github": "前往 Github 编辑",
"copy-code": "复制",
"copy-success": "复制成功",
"copy-error": "复制出现了一些问题"
}
}

View File

@ -0,0 +1 @@
["en-US","zh-CN"]

View File

@ -0,0 +1,33 @@
{
"en-US": [
{
"text": "Resume",
"link": "https://docs.google.com/document/d/1MTTfAx80EzWvtgmxFADdMrCS9R72ZwZPTLuBAaqtGNo/edit?usp=sharing",
},
{
"text": "Gitea",
"link": "https://git.vertinext.com/roryejinn",
},
{
"text": "Github",
"link": "https://github.com/ccubed"
}
{
"text": "Links",
"items": [
{
"text": "Linkedin",
"link": "/feedback/",
},
{
"text": "Twitch.tv",
"link": "https://gitee.com/lauset/vitepress-theme-vuetom"
},
{
"text": "Anilist Profile",
"link": "https://anilist.co/user/TakeshiKO/"
}
]
}
]
}

View File

@ -0,0 +1,82 @@
{
"en-US": [
{
"text": "Basic",
"items": [
{
"text": "What's the Vitepress?",
"link": "/guide/info"
},
{
"text": "Quick Start",
"link": "/guide/start"
},
{
"text": "Questions",
"link": "/guide/question"
},
{
"text": "Project Dir",
"link": "/guide/prodir"
}
]
},
{
"text": "Advanced",
"items": [
{
"text": "Theme Config",
"link": "/guide/config"
},
{
"text": "Languages",
"link": "/guide/lang"
},
{
"text": "Dark Mode",
"link": "/guide/dark"
}
]
}
],
"zh-CN": [
{
"text": "基础",
"items": [
{
"text": "什么是Vitepress?",
"link": "/guide/info"
},
{
"text": "快速开始",
"link": "/guide/start"
},
{
"text": "问题一览",
"link": "/guide/question"
},
{
"text": "主题目录",
"link": "/guide/prodir"
}
]
},
{
"text": "进阶",
"items": [
{
"text": "主题配置",
"link": "/guide/config"
},
{
"text": "国际化",
"link": "/guide/lang"
},
{
"text": "夜间模式",
"link": "/guide/dark"
}
]
}
]
}

View File

@ -0,0 +1,40 @@
{
"en-US": {
"langshow": {
"text": "MD Show",
"items": [
{
"link": "/mdshow/example",
"text": "Example"
},
{
"link": "/mdshow/custom",
"text": "Custom"
},
{
"link": "/comp/codeblock",
"text": "Code Block"
}
]
}
},
"zh-CN": [
{
"text": "语法",
"items": [
{
"link": "/mdshow/example",
"text": "MD语法示例"
},
{
"link": "/mdshow/custom",
"text": "自定义语法"
},
{
"link": "/mdshow/codeblock",
"text": "代码块展示"
}
]
}
]
}

View File

@ -0,0 +1,52 @@
{
"en-US": {
"label": "English",
"selectText": "Languages",
"editLinkText": "Suggest changes to this page",
"lastUpdatedText": "Last Updated",
"localeLinks": {
"text": "",
"items": [
{
"text": "Chinese",
"link": "/zh-CN/"
},
{
"text": "English",
"link": "/en-US/"
}
]
},
"socialLinks": [
{
"icon": "github",
"link": ""
}
]
},
"zh-CN": {
"label": "简体中文",
"selectText": "选择语言",
"editLinkText": "对本页提出修改建议",
"lastUpdatedText": "最后更新",
"localeLinks": {
"text": "",
"items": [
{
"text": "简体中文",
"link": "/zh-CN/"
},
{
"text": "English",
"link": "/en-US/"
}
]
},
"socialLinks": [
{
"icon": "github",
"link": ""
}
]
}
}

View File

@ -0,0 +1,12 @@
{
"en-US": {
"title": "Vuetom Theme",
"lang": "en-US",
"description": "Theme for Vitepress"
},
"zh-CN": {
"title": "Vuetom 主题",
"lang": "zh-CN",
"description": "一款为 Vitepress 而生的主题"
}
}

View File

@ -0,0 +1,150 @@
import type { HeadConfig } from 'vitepress'
import { languages } from './utils/lang'
import navJson from './i18n/nav.json'
import guideSidebarJson from './i18n/sidebars/guide.json'
import mdshowSidebarJson from './i18n/sidebars/mdshow.json'
import vitepressConfigJson from './i18n/vitepress-config.json'
import themeConfigJson from './i18n/theme-config.json'
type langType = 'zh-CN' | 'en-US'
const getVitepressConfigLocales = (lang: langType = 'zh-CN') => (vitepressConfigJson[lang])
const getThemeConfigLocales = (lang: langType = 'zh-CN') => {
const sidebar = {}
sidebar[`/${lang}/guide/`] = guideSidebarJson[lang]
sidebar[`/${lang}/mdshow/`] = mdshowSidebarJson[lang]
return {
nav: navJson[lang],
sidebar,
...themeConfigJson[lang]
}
}
const getLocales = (langs: langType[] = []) => {
const config = {
vitepressConfig: {},
themeConfig: {}
}
langs.forEach(lang => {
config.vitepressConfig[`/${lang}/`] = getVitepressConfigLocales(lang)
config.themeConfig[`/${lang}/`] = getThemeConfigLocales(lang)
})
return config
}
const getNav = (lang: 'zh-CN' | 'en-US' = 'zh-CN') => (navJson[lang])
const getSidebar = (lang: 'zh-CN' | 'en-US' = 'zh-CN') => ({
'/guide/': guideSidebarJson[lang],
'/mdshow/': mdshowSidebarJson[lang]
})
const head: HeadConfig[] = [
[
'meta',
{
name: 'viewport',
content: 'width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no'
}
],
['link', { rel: 'icon', href: '/logo/vuetom-logo-m.png' }],
[
'script', {}, ';(() => { })()'
],
[
'script',
{},
`;(() => {
const supportedLangs = ${JSON.stringify(languages)}
const cacheKey = 'vuetom_langs'
localStorage.setItem(cacheKey, supportedLangs)
})()`
]
]
// const nav = (lang: '/zh-CN' | '/en-US' | '' = '') => [
// { text: '指引', link: `${lang}/guide/info`, activeMatch: '/guide/' },
// { text: '组件', link: `${lang}/mdshow/`, activeMatch: '/mdshow/' },
// {
// text: '链接',
// items: [
// {
// text: '反馈',
// link: `${lang}/feedback/`,
// activeMatch: '/feedback/',
// },
// {
// text: '码云',
// link: 'https://gitee.com/lauset/vitepress-theme-vuetom',
// },
// {
// text: 'Vitepress官网',
// link: 'https://vitepress.vuejs.org/',
// },
// ],
// },
// ]
// const sidebarGuide = (lang: '/zh-CN' | '/en-US' | '' = '') => [
// {
// text: '基础',
// collapsible: true,
// items: [
// { text: '什么是Vitepress?', link: `${lang}/guide/info` },
// { text: '快速开始', link: `${lang}/guide/start` },
// {
// text: '问题一览',
// link: `${lang}/guide/question`,
// },
// {
// text: '主题目录',
// link: `${lang}/guide/prodir`,
// },
// ],
// },
// {
// text: '进阶',
// collapsible: true,
// items: [
// {
// text: '主题配置',
// link: `${lang}/guide/config`,
// },
// {
// text: '国际化',
// link: `${lang}/guide/lang`,
// },
// {
// text: '夜间模式',
// link: `${lang}/guide/dark`,
// },
// ],
// },
// ]
// const sidebarMdShow = (lang: '/zh-CN' | '/en-US' | '' = '') => [
// {
// text: '语法',
// collapsible: true,
// items: [
// {
// link: `${lang}/mdshow/example`,
// text: 'MD语法示例',
// },
// {
// link: `${lang}/mdshow/custom`,
// text: '自定义语法',
// },
// {
// link: `${lang}/mdshow/codeblock`,
// text: '代码块展示',
// },
// ],
// },
// ]
const nav = getNav()
const sidebar = getSidebar()
const locales = getLocales(['zh-CN', 'en-US'])
export { nav, sidebar, head, locales, getNav, getSidebar }

View File

@ -0,0 +1,17 @@
:root{
// 重写主题色
// 主色
--vp-c-brand: var(--vp-c-blue);
--vp-c-brand-light: var(--vp-c-blue-light);
--vp-c-brand-lighter: var(--vp-c-blue-lighter);
--vp-c-brand-dark: var(--vp-c-blue-dark);
--vp-c-brand-darker: var(--vp-c-blue-darker);
// 副色
--vp-c-second: var(--vp-c-pink);
--vp-c-second-light: var(--vp-c-pink-light);
--vp-c-second-lighter: var(--vp-c-pink-lighter);
--vp-c-second-dark: var(--vp-c-pink-dark);
--vp-c-second-darker: var(--vp-c-pink-darker);
}

View File

@ -0,0 +1,24 @@
// .vitepress/theme/index.ts
// theme
import VuetomTheme from 'vitepress-theme-vuetom/docs'
// components
import { globals } from '../views'
// rewrite css
import './custom.scss'
export default {
...VuetomTheme,
// NotFound,
// Layout,
enhanceApp({ app, router, siteData }) {
// app.use(VuetomUI)
globals.forEach(([name, Comp]) => {
app.component(name, Comp)
})
},
}

View File

@ -0,0 +1,8 @@
import fs from 'fs'
import path from 'path'
export const languages = fs.readdirSync(
path.resolve(__dirname, '../crowdin')
)
export const changeLang = (lang: string) => `/${lang}`

View File

@ -0,0 +1,23 @@
import process from 'process'
import chalk from 'chalk'
export function cyan(str: string) {
console.log(chalk.cyan(str))
}
export function yellow(str: string) {
console.log(chalk.yellow(str))
}
export function green(str: string) {
console.log(chalk.green(str))
}
export function red(str: string) {
console.error(chalk.red(str))
}
export function errorAndExit(e: Error): never {
red(e.stack ?? e.message)
process.exit(1)
}

View File

@ -0,0 +1,6 @@
import path from 'path'
export const vpRoot = path.resolve(__dirname, '..')
export const docRoot = path.resolve(vpRoot, '..')
export const pkgsRoot = path.resolve(docRoot, '..')
export const projRoot = path.resolve(pkgsRoot, '..')

View File

@ -0,0 +1,18 @@
import { computed } from 'vue'
import { useRoute } from 'vitepress'
export const useLang = () => {
const route = useRoute()
return computed(() => {
// the first part of the first slash
const path = route.data?.relativePath
let lang: string
if (path?.includes('/')) {
lang = path.split('/').shift()
} else {
lang = 'zh-CN'
}
return lang
})
}

View File

@ -0,0 +1,18 @@
import { isRef, ref } from 'vue'
import { isBoolean } from '@vueuse/core'
import type { MaybeRef } from '@vueuse/core'
export const useToggle = (getToggled?: MaybeRef<boolean>) => {
const val = isRef(getToggled)
? getToggled
: ref(isBoolean(getToggled) ? getToggled : false)
return [
val,
(toggle?: boolean) => {
val.value = isBoolean(toggle) ? toggle : !val.value
}
] as const
}
export default {}

View File

@ -0,0 +1,8 @@
import VtFeedback from './vt/vt-feedback.vue'
// export default VtApp
export const globals = [
['VtFeedback', VtFeedback],
]
export default {}

View File

@ -0,0 +1,426 @@
<template>
<div class="box" :style="{}" :class="getExtBoxClasses()">
<div class="box-center">
<div class="box-center-left"></div>
<div class="box-center-center loader">
<div class="app-bar" :style="{ backgroundColor: '#fff' }">
<div class="controll">
<div class="close"></div>
<div class="min"></div>
<div class="full"></div>
</div>
<div class="title" :style="{ color: '#000' }">标题</div>
</div>
<div class="app-body">
<div class="feedback-container">
<div class="row">
<input
class="txt"
type="text"
v-model="email"
placeholder="邮箱"
/>
</div>
<textarea
class="txt"
v-model="txt"
cols="30"
rows="3"
placeholder="留言内容"
></textarea>
<div class="btns row">
<button class="btn" @click="goFeeback">留言</button>
<button class="rest btn" @click="reset">重置</button>
</div>
<h3 class="row">留言列表</h3>
<ul>
<li v-for="item in list" :key="item.fd_id">
<div class="title">
来自-{{ item.f_address || '未知地区' }}
<span>{{ item.time }}</span>
</div>
<div class="content" v-text="item.f_context"></div>
<div
class="replay"
v-text="item.f_back"
v-if="item.f_back"
></div>
</li>
</ul>
<div class="nolist" v-if="list.length === 0">暂无留言~</div>
<br/>
<button class="more btn" @click="getList" :disabled="isDown">
加载更多
</button>
</div>
</div>
</div>
<div class="box-center-right"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
// import { ElMessage } from "element-plus";
// import "element-plus/lib/theme-chalk/el-message.css";
// import "element-plus/lib/theme-chalk/el-icon.css";
const postUrl = ''
const getListUrl = ''
const isBoxResizing = ref(false)
const isMaxShowing = ref(false)
const isFullScreen = ref(false)
const txt = ref('')
const email = ref('')
const page = ref(1)
const pagesize = ref(10)
const isDown = ref(false)
const list = ref([])
const reset = () => {
txt.value = ''
email.value = ''
}
const goFeeback = () => {
alert('开发中!')
return
if (!txt.value || !email.value) {
alert("你还未填写内容");
return
}
axios
.post(postUrl, { text: txt.value.trim(), email: email.value })
.then((res) => {
const { status, msg } = res.data
if (status === 0) {
reset()
}
})
.catch((err) => {
})
}
const getExtBoxClasses = () => {
let str = ''
if (isMaxShowing) {
str += 'isMaxShowing '
}
if (isFullScreen) {
str += 'isFullScreen '
}
return str
}
const getList = (tip = false) => {
if (isDown.value) {
alert("没有更多数据了");
return null
}
axios
.post(getListUrl, { page: page.value, pagesize: pagesize.value })
.then((res) => {
const {
data: { status, msg, data },
} = res
if (status === 0) {
list.value.push(...data)
page.value += 1
if (data.length < pagesize.value) {
isDown.value = true
}
return
}
isDown.value = true
})
.catch((err) => {
})
}
onMounted(getList)
</script>
<style lang="scss" scoped>
.row {
margin-bottom: 20px;
}
.txt {
max-width: 100%;
height: auto;
min-height: 32px;
line-height: 1.5715;
vertical-align: bottom;
transition: all 0.3s, height 0s;
box-sizing: border-box;
margin: 0;
font-variant: tabular-nums;
list-style: none;
font-feature-settings: "tnum";
position: relative;
display: inline-block;
width: 100%;
min-width: 0;
padding: 4px 11px;
color: #000000d9;
font-size: 14px;
line-height: 1.5715;
background-color: #fff;
background-image: none;
border: 1px solid #d9d9d9;
border-radius: 2px;
transition: all 0.3s;
}
.txt:focus {
border-color: #40a9ff;
border-right-width: 1px !important;
outline: 0;
box-shadow: 0 0 0 2px #1890ff33;
}
.btns {
margin-top: 20px;
}
.btn {
line-height: 1.5715;
position: relative;
display: inline-block;
font-weight: 400;
white-space: nowrap;
text-align: center;
background-image: none;
border: 1px solid transparent;
box-shadow: 0 2px #00000004;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
touch-action: manipulation;
height: 32px;
padding: 4px 15px;
font-size: 14px;
border-radius: 2px;
color: #000000d9;
background: #fff;
border-color: #d9d9d9;
color: #fff;
background: #1890ff;
border-color: #1890ff;
text-shadow: 0 -1px 0 rgb(0 0 0 / 12%);
box-shadow: 0 2px #0000000b;
}
.btn:active {
outline: 0;
box-shadow: none;
color: #fff;
background: #096dd9;
border-color: #096dd9;
text-decoration: none;
}
.btn:focus,
.btn:hover {
color: #fff;
background: #40a9ff;
border-color: #40a9ff;
text-decoration: none;
}
.rest {
margin-left: 10px;
}
.title span {
margin-left: 10px;
font-size: 12px;
color: #d9d9d9;
}
.title {
color: #000;
}
.replay,.content {
padding: 10px;
white-space: pre-line;
color: #00000073;
}
.btn.more {
width: 100%;
}
.btn[disabled] {
color: #00000040;
background: #f5f5f5;
border-color: #d9d9d9;
text-shadow: none;
box-shadow: none;
cursor: not-allowed;
}
.replay{
padding:0 15px 10px;
color: red;
}
.box {
--resize: 5px;
--resize-bg: transparent;
--resize-main: transparent;
--resize-bg-main: transparent;
}
.box {
display: flex;
flex-direction: column;
position: relative;
pointer-events: auto;
.box-top {
display: flex;
flex-direction: row;
.box-top-left {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: nw-resize;
}
.box-top-center {
height: var(--resize);
background: var(--resize-bg-main);
cursor: n-resize;
flex-grow: 1;
}
.box-top-right {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: ne-resize;
}
}
.box-center {
display: flex;
flex-direction: row;
flex-grow: 1;
.loader {
display: flex;
flex-grow: 1;
flex-direction: column;
width: 100%;
}
.box-center-left {
width: var(--resize);
height: 100%;
background: var(--resize-bg-main);
cursor: w-resize;
}
.box-center-center {
height: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
border-radius: 10px;
box-shadow: 0px 0px 3px rgb(201, 196, 196);
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
overflow: hidden;
// filter: grayscale(1) brightness(0.9);
.app-bar {
height: 40px;
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(20px);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
.title {
flex-grow: 1;
text-align: center;
margin-right: 84px;
font-weight: 500;
text-shadow: none;
font-size: 13px;
cursor: move;
color: #333;
}
.controll {
display: flex;
justify-content: center;
align-items: center;
margin-left: 15px;
div {
border-radius: 100%;
height: 14px;
width: 14px;
margin-right: 8px;
cursor: pointer;
}
.close {
background: #fc605c;
}
.close:hover {
background: #cc2c26;
}
.min {
background: #fcbb40;
}
.min:hover {
background: #c28719;
}
.full {
background: #34c648;
}
.full:hover {
background: #1f942e;
}
.full-disabled {
background: #ccc !important;
}
}
}
.app-body {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 50px 0;
}
}
.box-center-right {
width: var(--resize);
height: 100%;
background: var(--resize-bg-main);
cursor: e-resize;
}
}
.box-bottom {
display: flex;
flex-direction: row;
.box-bottom-left {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: sw-resize;
}
.box-bottom-center {
height: var(--resize);
background: var(--resize-bg-main);
cursor: s-resize;
flex-grow: 1;
}
.box-bottom-right {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: se-resize;
}
}
}
</style>

2
packages/docs/README.md Normal file
View File

@ -0,0 +1,2 @@
<h1 align="center">Vuetom Theme Documents</h1>

View File

@ -0,0 +1,15 @@
const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = (req, res) => {
let target = ''
if (req.url.startsWith('/vt')) {
target = 'https://vitepress-theme-vuetom.vercel.app'
}
createProxyMiddleware({
target,
changeOrigin: true,
pathRewrite: {
'^/vt/': '/'
}
})(req, res)
}

130
packages/docs/crowdin.yml Normal file
View File

@ -0,0 +1,130 @@
#
# Your Crowdin credentials
#
'project_id': '493499'
'api_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJ3UUVxdmhVM3ZMT2EyWGljbVV5VCIsImp0aSI6IjAxOTUwYzkxMzYwZjA2ZGRmZmIzMWI2NWEyYTcyMTFlM2U3MmEzN2M0OThmMGEzYzE2NjJmNmM0ZTVkODY1OTY0ZGZjZjJmMWYzYmU3NjAyIiwiaWF0IjoxNjQxNzUwMzc2LCJuYmYiOjE2NDE3NTAzNzYsImV4cCI6MTY0NDM0MjM3Niwic3ViIjoiMTQ5ODY1NTUiLCJkb21haW4iOm51bGwsInNjb3BlcyI6WyJwcm9qZWN0Il0sImFzc29jaWF0aW9ucyI6WyIqIl0sInNlc3Npb24iOjB9.PT_rMlnABrRc9DPwQjZ14RqPrwRxtn-dER1AjEomPVLPobm8PeVfopTe7KQeFMFKbUjzuuPPJbWh3doEkFDHifcvKHHdqjwrT6A0VYdQDFOXglrWNTE33J3k7hJn2FwXXMIFF709y9jJnUVWSeRyO5gXV5Z41ozadHi4bNNikyXoREnWZHdSfZXN7BoubXeo1JsxVSHTXbhEXV-u-gUwUPQ6k4lXkpqCf3B8xYP0p7SlYWWN3zEoajKvAVAsCnEC9kBj0X1LRhuk7jfXAkS3xR6pVY7tyawsdzsUGF-gVLvUKn8M3-1R92DRAo566IVBUmfG4YhnXXGWO30rht-XFWxVcqSFVSpiDFCQdBRKwclzeSveh__ljuVEcFDTAO-bMz4s2uzJFGfJgrVfNkKk4NnNV3iyQfpaZiDU-QxLh0aCIhj4zJZgF3NkLp-rBONM3t1fyIfK8JCYrbrG-nDy-SqyHYsWnG0SvjcsDCEBk4eoyioTX3VBIeB7AL5dHiryiB-74DV9XQxk65VOmt6HDhbfddmeqSa668QPKa3LzvIauW8BLyrz9XnYcK6RqxAZm14zls2_1DG0JmPymrx2KmX2snnX2MuLGaicRPkd2o9OwUxd_1aMQssjLRCHawtrTu6PCyfwi_0wFJtW9qB-f4dPUdVK23yarLWjjjLmzzQ'
'base_path': '.'
'base_url': 'https://api.crowdin.com'
#
# Choose file structure in Crowdin
# e.g. true or false
#
'preserve_hierarchy': true
#
# Files configuration
#
files: [
{
'source': '.vitepress/crowdin/zh-CN/**/*.json',
'translation': '.vitepress/crowdin/%locale%/**/%original_file_name%',
},
{
#
# Source files filter
# e.g. "/resources/en/*.json"
#
'source': 'zh-CN/**/*.md',
#
# Where translations will be placed
# e.g. "/resources/%two_letters_code%/%original_file_name%"
#
'translation': '%locale%/**/%original_file_name%',
#
# Files or directories for ignore
# e.g. ["/**/?.txt", "/**/[0-9].txt", "/**/*\?*.txt"]
#
#"ignore" : [],
#
# The dest allows you to specify a file name in Crowdin
# e.g. "/messages.json"
#
#"dest" : "",
#
# File type
# e.g. "json"
#
#"type" : "",
#
# The parameter "update_option" is optional. If it is not set, after the files update the translations for changed strings will be removed. Use to fix typos and for minor changes in the source strings
# e.g. "update_as_unapproved" or "update_without_changes"
#
#"update_option" : "",
#
# Start block (for XML only)
#
#
# Defines whether to translate tags attributes.
# e.g. 0 or 1 (Default is 1)
#
# "translate_attributes" : 1,
#
# Defines whether to translate texts placed inside the tags.
# e.g. 0 or 1 (Default is 1)
#
# "translate_content" : 1,
#
# This is an array of strings, where each item is the XPaths to DOM element that should be imported
# e.g. ["/content/text", "/content/text[@value]"]
#
# "translatable_elements" : [],
#
# Defines whether to split long texts into smaller text segments
# e.g. 0 or 1 (Default is 1)
#
# "content_segmentation" : 1,
#
# End block (for XML only)
#
#
# Start .properties block
#
#
# Defines whether single quote should be escaped by another single quote or backslash in exported translations
# e.g. 0 or 1 or 2 or 3 (Default is 3)
# 0 - do not escape single quote;
# 1 - escape single quote by another single quote;
# 2 - escape single quote by backslash;
# 3 - escape single quote by another single quote only in strings containing variables ( {0} ).
#
# "escape_quotes" : 3,
#
# Defines whether any special characters (=, :, ! and #) should be escaped by backslash in exported translations.
# e.g. 0 or 1 (Default is 0)
# 0 - do not escape special characters
# 1 - escape special characters by a backslash
#
# "escape_special_characters": 0
#
#
# End .properties block
#
#
# Does the first line contain header?
# e.g. true or false
#
#"first_line_contains_header" : true,
#
# for spreadsheets
# e.g. "identifier,source_phrase,context,uk,ru,fr"
#
# "scheme" : "",
},
]

View File

@ -0,0 +1,17 @@
---
title: 留言反馈
---
# {{ $frontmatter.title }}
> 该页面是在 Markdown 中引入 Vue 组件简单的展示
页面文件: `.vitepress/views/vt/vt-feedback.vue`
<ClientOnly>
<VtFeedback />
</ClientOnly>
::: tip
正在开发中,你以后可以把想说的话写在这里
:::

View File

@ -0,0 +1,201 @@
---
title: 主题配置
head:
- - meta
- name: description
content: vuetom 主题配置项
- - meta
- name: keywords
content: vuetom theme config
---
# {{ $frontmatter.title }}
主题的配置要写在 `.vitepress/config.ts` 文件中的 themeConfig 属性中
<br>
下面是一些简要的配置项一览:
其中 head、sidebar、nav 对应的分别是 页面head脚本、侧边栏菜单、头部导航栏(都可以默认为[])
<br>
以下是版本号满足 `vitepress >= 1.0.0` `vuetom-theme >= 2.3.0` 的配置
```js macos
// .vitepress/config.ts
// import ...
export default defineConfigWithTheme<VuetomThemeConfig>({
base: `/vt/`,
ignoreDeadLinks: true,
lastUpdated: true,
head,
locales: locales.vitepressConfig,
themeConfig: {
nav,
sidebar,
localeLinks: {
text: '',
items: [
{
text: '中文',
link: '/lang/zhcn'
},
{
text: 'English',
link: '/lang/enus'
}
]
},
socialLinks: [
{ icon: 'github', link: pkg.repository }
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2021-present Lauset'
},
algolia: {
appId: '8Q3CNX0EF2',
apiKey: 'd44e3c8ec76aff9c758ef34f2cefe24d',
indexName: 'dev_vuetom'
},
logoImg: '/logo/vuetom-logo-m.png',
bgImg: '/imgs/homg-bg01.jpg',
bgColor: '0,0,0',
bgOpacity: 0.6,
flashEnable: true,
flashColor: ['238,17,17', '0,98,255'],
parallaxEnable: true,
pageBgEnable: true,
pageBgOpacity: 0.8,
featuresColor: ['#06cdff30', 'rgba(223,7,107,.3)']
},
markdown: {
lineNumbers: true
},
appearance: true,
vite: {
ssr: {
noExternal: ["vitepress-theme-vuetom"]
}
}
})
```
:::warning 注意
需要将主题配置成防止被 SSR 外部化的依赖项
```js
vite: {
ssr: {
noExternal: ["vitepress-theme-vuetom"]
}
}
```
:::
<br>
:::danger 过期提示
vitepress-theme-vuetom 1.x 版本已弃用
请升级版本 `vitepress>=1.0` `vitepress-theme-vuetom>=2.3.0`
:::
<br />
以下是对配置项的简要说明
## 首页LOGO
**logoImg**
- 类型:`string`
- 默认值:`''`
首页上方LOGO路径中的首个 `/` 表示 `public` 目录
例如:`'/logo/homg-logo.jpg'`
## 首页背景图
**bgImg**
- 类型:`string`
- 默认值:`undefined`
首页全屏背景图,路径中的首个 `/` 表示 `public` 目录
例如:`'/imgs/homg-bg01.jpg'` 等同于 `/public/imgs/home-bg01.jpg`
**bgColor**
- 类型:`string`
- 默认值:`'0,0,0'`
背景图边缘的覆盖颜色,值是 `rgb` 的颜色值 `rgb(0,0,0)` 则写为 `'0,0,0'`,默认为黑色
**bgOpacity**
- 类型:`0 - 1`
- 默认值:`0.6`
覆盖颜色的透明度,搭配上面的覆盖颜色使用,图片中间透明度要比图片边缘透明度要小
图片中间透明度为 `当前bgOpacity - 0.3`,也就是说默认为 `0.3`
## 文章页背景图
注意:文章页背景图片与首页一致
**pageBgEnable**
- 类型:`boolean`
- 默认值:`true`
文章页面背景图是否开启,默认开启
**pageBgOpacity**
- 类型:`0 - 1`
- 默认值:`0.8`
文章页背景图透明度1将看不到背景图0能清晰看到背景图
**featuresColor**
- 类型:`string | Array`
- 默认值:`rgba(255,255,255,0.8)`
首页功能面板背景色,可以是单个颜色字符串,也可以是两个字符串组成的数组
**flashEnable**
- 类型:`boolean`
- 默认值:`false`
是否开启首页背景图闪烁功能,效果类似于朋克风故障
**flashColor**
- 类型:`string | Array`
- 默认值:`['0,0,0','0,0,0']`
首页背景闪烁时附加的色彩0: Top位置的颜色1: Right位置的颜色默认都是黑色
**parallaxEnable**
- 类型:`boolean`
- 默认值:`false`
是否开启首页部分元素视觉差效果
## 博客配置项
博客开发中...

View File

@ -0,0 +1,49 @@
---
title: 夜间模式
lang: en-US
---
# {{ $frontmatter.title }}
默认的话夜间模式切换按钮是一直有的,右上角那个太阳图标
## 原理
开关操作修改的是 HTML 根标签的样式,会加上 dark 样式
```html
<html class="dark" lang="zh-CN"></html>
```
我们可以事先定义一些 css变量来完成不同语言下或者不同模式下的样式变换
## 主题色覆盖
修改 theme/custom.scss 文件即可
简单展示部分
```css
:root {
// 重写主题色
// 主色
--vp-c-brand: var(--vp-c-blue);
--vp-c-brand-light: var(--vp-c-blue-light);
--vp-c-brand-lighter: var(--vp-c-blue-lighter);
--vp-c-brand-dark: var(--vp-c-blue-dark);
--vp-c-brand-darker: var(--vp-c-blue-darker);
// 副色
--vp-c-second: var(--vp-c-pink);
--vp-c-second-light: var(--vp-c-pink-light);
--vp-c-second-lighter: var(--vp-c-pink-lighter);
--vp-c-second-dark: var(--vp-c-pink-dark);
--vp-c-second-darker: var(--vp-c-pink-darker);
}
.dark {
}
```

View File

@ -0,0 +1,17 @@
# 指引
`info` : 介绍
`start` : 快速开始
`question` : 问题一览
`prodir` : 主题项目结构
`config` : 主题配置
`lang` : 国际化配置
::: tip
这里展示的是指引菜单下所有的子菜单
:::

View File

@ -0,0 +1,50 @@
---
title: 什么是Vitepress
head:
- - meta
- name: description
content: vuetom 介绍
- - meta
- name: keywords
content: vuetom theme
---
# {{ $frontmatter.title }}
VitePress 是 VuePress 的升级,以 Vite 为基础构建的。是一款快速搭建文档静态网站的框架。
Vite法语意为 "快速的",发音 `/vit/` ,发音同 "veet"是一种新型前端构建工具能够显著提升前端开发体验。Vite 意在提供开箱即用的配置,同时它的 插件 API 和 JavaScript API 带来了高度的可扩展性,并有完整的类型支持。它主要由两部分组成:
- 一个开发服务器,它基于 原生 ES 模块 提供了 丰富的内建功能,如速度快到惊人的 模块热更新HMR
- 一套构建指令,它使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。
## vuetom 呢?
是的,是一款主题,因 vitepress 而诞生。建立在 Vue3 与 Vite 之上的一款文档框架的主题。含有 `文档``博客` 两种风格模板。其推出目的是为了让大家体验并使用到更多美丽而又有趣的 vitepress 主题,进而大家可以发挥想象展示出更多优美的文档。
## 有什么特点
使用现代扁平化的设计风格,部分 UI 尽量接近于 macos 界面风格
该主题包含了以下相关技术
- [nodejs](http://nodejs.cn/)
- [vite](https://vitejs.cn/)
- [vue3](https://v3.vuejs.org/)
- [vitepress](https://vitejs.cn/vitepress/)
- [tailwindcss](https://www.tailwindcss.cn/docs)
该主题包含了一下功能模块
**内置UI组件:** 扁平化数据组织,方便编写。含有按钮,弹框,卡片等基础组件
**主题与样式:** 主要包含布局,间距,排版,颜色,边框
**API与指令:** 可搭配组件使用,实现不同组件不同指令效果
## 推荐开发工具?
这就无所谓了吧哈哈。
[vscode编辑器](https://code.visualstudio.com/) => [下载地址](https://blog.csdn.net/bielaiwuyang1999/article/details/117814237)

111
packages/docs/guide/lang.md Normal file
View File

@ -0,0 +1,111 @@
---
title: 多国语言配置
---
# {{ $frontmatter.title }}
vitepress 1.x 版本采用 0.x 版本的多国语言配置打包 NavBar 会出现错乱问题,暂时放弃研究
目前可将 `.vitepress/crowdin-docs/` 目录下 `zh-CN``en-US` 中的md直接文件复制取出并覆盖docs目录下的md文件
:::danger
适配于 vitepress 1.x.x 版本的功能正在制作,下面是 0.x.x 版本的国际化方案
:::
## Vitepress 0.22.x 多国语言配置
你也可以配置多国语言,以首页为例,先在配置文件里配置下 locales然后创建对应的语言文件夹与文件
## 改配置文件
需要在 config.ts 中配置 locales注意 themeConfig 属性里也要配,两个 locales 内容是不一样的
themeConfig 中的 locales 配置是为了展示下拉菜单的展示内容
根Config 中的 locales 配置是为了展示头部标题内容description属性可有可无
```js
// .vitepress/config.ts
export default defineConfigWithTheme<VuetomThemeConfig>({
// ...
themeConfig: {
// ...
locales: {
'/zh-CN/': {
label: '简体中文',
selectText: '多国语言'
},
'/en-US/': {
label: 'English',
selectText: 'Languages'
}
}
},
locales: {
'/zh-CN/': {
lang: 'zh-CN',
title: 'Vuetom 主题',
description: '为 Vitepress 提供的一款主题'
},
'/en-US/': {
lang: 'en-US',
title: 'Vuetom Theme',
description: 'Theme For Vitepress'
}
}
})
```
**locales** 中的属性介绍
<b>lang</b>: 会直接设置给 `<html>` 标签
<b>title</b>: 不同语言时网站的标题,会替换之前定义的 title
<b>description</b>: 不同语言时网站的描述
<b>label</b>: 语言选择时展示出来的文本内容例如中文或English
<b>selectText</b>: 语言选择时下拉菜单的文本例如多国语言或者Languages
## 改首页
在 .vitepress 同级目录新建 `zh-CN``en-US` 文件夹,然后在这个文件夹中分别创建一个 `index.md` 文件
**zh-CN/index.md** 中写入 **中文首页** 要展示的内容
**en-US/index.md** 中写入 **英文首页** 要展示的内容
原来与 .vitepress 同级的 `index.md` 文件中可以改为转发至 `zh-CN/index` 或者 `en-US/index`
例如下方的代码,会直接将 `/` 转发到 `/zh-CN/` 这样就会直接前往中文首页了
```markdown
---
title: 'Vuetom Theme'
lang: en-US
page: true
---
<script setup>
if (typeof window !== 'undefined') {
const preferredLang = 'zh-CN'
window.location.pathname = `/${preferredLang}/`
}
</script>
```
::: warning
其实原理就是路径前加了一个语言标识,那么就在页面文件外加个语言文件夹就好了<br>
需要处理的就是书写导航栏和菜单栏时记得要在 link 属性前加上语言标识
:::
下面试试访问一下:
访问 localhost:3000/zh-CN/ 会前往中文首页
访问 localhost:3000/en-US/ 会前往英文首页
访问 localhost:3000 会前往 localhost:3000/zh-CN/

View File

@ -0,0 +1,57 @@
---
title: 框架目录
head:
- - meta
- name: description
content: Vuetom 主题目录结构
- - meta
- name: keywords
content: project dir.
---
# 主题目录
在使用一个框架,其实也要简单了解下该框架的项目文件结构,请向下看吧。
```bash
vuetom
├─ blog 博客主题Vue组件 文件夹
├─ doc 新版文档适配vp1.x 文件夹
├─ docs 旧版文档主题组件 文件夹
│ ├─ components 主题Vue组件 文件夹
│ ├─ composables 组件脚本 文件夹
│ ├─ layouts 布局组件 文件夹
│ └─ index.ts 主题入口 文件
├─ icons 共用图标Vue组件 文件夹
├─ styles 全局SCSS样式 文件夹
├─ support 供支持脚本 文件夹
├─ types 规范描述 文件夹
├─ constant.ts 常量定义 文件
└─ index.ts 主题入口文件 文件
```
接下来介绍本文档**docs**文件夹
```bash
docs
├─ .vitepress
│ └─ config.ts 主题主要配置文件
├─ public 静态资源文件
├─ zh-CN 中文页面
│ ├─ feedback 留言反馈
│ ├─ guide 指引
│ ├─ mdshow Markdown示例
│ ├─ menu UI组件
│ ├─ styl 主题与样式
│ └─ index.md 中文首页
├─ crowdin.yml 多国语言配置
├─ index.md 项目首页
├─ CHANGELOG.md 更新日志
├─ package.json 包配置
├─ README.md 项目说明
├─ tsconfig.json ts配置
└─ vite.config.ts vite配置
```

View File

@ -0,0 +1,53 @@
---
title: 常见问题
head:
- - meta
- name: description
content: 常见问题汇总
- - meta
- name: keywords
content: question
---
# {{ $frontmatter.title }}
是否经常卡在一些莫名其妙的问题上?让我们来汇总一下问题并给出相应的解决方案吧!
## 问题列表
- [版本多久更新一次?](#q01)
- [我的样式没有起作用。](#q02)
- [我不想要背景图咋办啊?](#q03)
## 问题解答
以下是针对于近期问题所作的答复
- <h3 id="q01">版本多久更新一次?</h3>
目前进度较慢,但是每周都会更新主要内容的
- <h3 id="q02">我的样式没有起作用。</h3>
查看 `.vitepress/config.js` 文件进中 `theme` 项是否配置正确
- <h3 id="q03">我不想要背景图咋办啊?</h3>
你可以用一张纯白色的图片作为背景图啊嘿嘿嘿
## 开发进度
| 功能组件 | 开发进度 | 预估 |
| - | - | - |
| 文档风格主题 vitepress 0.x.x | 开发中80% | 2022.5 |
| 文档风格主题 vitepress 1.x.x | 开发中80% | 2022.8 |
| 博客风格主题 vitepress 1.x.x | 开发中50% | 2022.11 |
## 需要帮助?
可点击 [留言反馈](/feedback/) 前往问题反馈界面对问题进行简单的描述
::: tip
目前 vitepress 版本已进入 1.0.0 , vuetom-theme 版本已进入 2.0.0
:::

View File

@ -0,0 +1,178 @@
---
title: 快速使用
head:
- - meta
- name: description
content: 教你如何掌握框架的工作流程,快速上手。
- - meta
- name: keywords
content: 开始使用
---
# {{ $frontmatter.title }}
使用主题前请确保你已经搭建了一个 Vitepress 文档项目,因为主题是建立在该框架的基础上使用的。
请确保你使用的 vue >= 3.2 且 vitepress >= 1.x 哦。
## 最快捷的方式
直接拉取本项目至本地packages/docs 和 packages/blog 目录下分别是文档和博客示例,根据 `README.md` 进行依赖安装、构件、打包、预览即可
## 其他方式
### **1.** 使用脚手架初始化
可用脚手架 `vuetom-cli` 来进行主题的初始化,这会在你本地初始化一个模版
网速慢可以再次尝试或者直接前往模版仓库拉取 [模版仓库](https://github.com/lauset/vuetom-cli)
- 分支1: **temp-docs** (文档模版)
- 分支2: **temp-blog** (博客模版)
1. 首先安装脚手架NPM安装前请确保开启管理员身份运行保证有权限
```sh light
npm i -g vuetom-cli
```
2. 查看是否安装成功,黑窗口运行一下命令,返回版本号 x.x.x 则表示安装成功
```bash light
vuetom-cli -v
```
1. 初始化模版,可以选择是否新建目录、仓息、作者、模版仓库等。
初始化选择从 github 源拉取模版可以保证模版是最新的代码
```bash light
vuetom-cli init
```
1. 然后便会下载模版,下载完成后,执行以下命令安装依赖并运行文档网站
```bash macos
# 安装依赖
pnpm i
# 本地运行
pnpm dev
```
::: warning
模版是从 github 上拉取的,可能有时候会有网速的困惑,也可手动前往拉取下载本地启用
文档模版:<https://github.com/lauset/vuetom-cli/tree/temp-docs>
博客模版:<https://github.com/lauset/vuetom-cli/tree/temp-blog>
:::
<br/>
### **2.** 通过NPM下载安装主题最新版本为 2.3.0
:::danger ⚠️ 写在前面
正常引入主题后,还需在 .vitepress/config.ts 文件中配置以下内容
```js macos
vite: {
ssr: {
noExternal: ["vitepress-theme-vuetom"]
}
}
```
:::
使用这个方式首先你要搭建一个 vitepress 项目,主题是会覆盖文档默认样式而已,所以项目还是得搭起来的,可以前往下面 vitepress 官网链接从头开始搭建
[vitepress搭建文档](https://vitepress.vuejs.org/guide/getting-started.html)
搭建完后最简单的样子就是项目目录里有个 index.md 文件,那么开始下一步
1. 安装主题依赖
使用 NPM 安装最新版本的 vitepress-theme-vuetom 主题包,在你的 vitepress 项目下安装,打开 `终端DOS` 输入
```sh light
npm i -D vitepress-theme-vuetom
```
2. 开始引入主题
先在 .vitepress (这个文件夹和首页 index.md 是同级目录,没有的自己创建)中新建一个名为 theme 的文件夹,在该文件下新建一个 index.ts 文件,当然用 js 还是 ts 文件就看你自己项目的决定了。
大致内容如下:
`VuetomTheme` 是主要的主题布局
`VuetomUI` 是内置的UI组件
```javascript light
// .vitepress/theme/index.ts
// 文档风格引入 2.3.0 版本之后改为 /docs 中引入了
import VuetomTheme from 'vitepress-theme-vuetom/docs'
// 博客风格引入
// import BlogTheme from 'vitepress-theme-vuetom/blog'
export default {
...VuetomTheme,
enhanceApp({ app, router, siteData }) {
}
}
```
引入了主题,然后你的 index.md 里写上一些内容应该就可以看出效果了
```html light
---
home: true
heroImage: /logo/vuetom-logo-m.png
heroAlt: LOGO
heroText: Vuetom
tagline: vitepress flat theme
actionText: 快 速 开 始
actionLink: /guide/info
altActionText: 配 置
altActionLink: /guide/config
features:
- title: 📦 优化的构建
details: 可选 “多页应用” 或 “库” 模式的预配置 Rollup 构建
- title: 🔩 通用的插件
details: 在开发和构建之间共享 Rollup-superset 插件接口。
- title: 🔑 完全类型化的API
details: 灵活的 API 和完整 TypeScript 类型。
footer: MIT Licensed
---
<div class="frontpage sponsors">
<h2>{{ data.text }}</h2>
</div>
<script setup>
import { onMounted, reactive } from 'vue'
const data = reactive({
text: '自定义内容'
})
onMounted(() => {
})
</script>
<style>
</style>
```
运行项目后,在 [localhost:3000] 中进入首页
:::tip
至少到这里主题已经安装完成了,下一步就是主题的配置了,主题什么样还是要看你配的什么样子哦。
:::

154
packages/docs/index.md Normal file
View File

@ -0,0 +1,154 @@
---
layout: home
title: Charles Click
titleTemplate: Portfolio
hero:
name: Charles
text:
tagline: Software Developer
actions:
- theme: brand big
text: Projects
link: /pages/projects
- theme: alt big
text: Watching
link: /pages/watching
features:
- title: 📦 Software Developer
details: I have developed several libraries and tools used across many projects.
- title: 🔩 Focused on Interconnectivity
details: I have a passion for applications that explore ways to spread information across the internet.
- title: 🔑 Keybase Verification
details: You can find my Keybase verification [here](https://keybase.io/cclick).
---
<div class="frontpage sponsors">
<h2>感 谢</h2>
<div class="platinum-sponsors">
<a v-for="{ href, src, name, id } of sponsors.filter(s => s.tier === 'platinum')" :href="href" target="_blank" rel="noopener" aria-label="sponsor-img">
<img :src="src" :alt="name" :id="`sponsor-${id}`">
<p>{{ name }}</p>
</a>
</div>
<div class="gold-sponsors">
<a v-for="{ href, src, name, id } of sponsors.filter(s => s.tier !== 'platinum')" :href="href" target="_blank" rel="noopener" aria-label="sponsor-img">
<img :src="src" :alt="name" :id="`sponsor-${id}`">
<p>{{ name }}</p>
</a>
</div>
</div>
<script setup>
import { onMounted } from 'vue'
import pk from 'vitepress-theme-vuetom/package.json'
const sponsors = [
{
"id": "vue",
"name": "Vue",
"href": "https://vuejs.org/",
"src": "https://vuejs.org/logo.svg",
"tier": "platinum"
},
{
"id": "vite",
"name": "Vite",
"href": "https://v2.vitejs.dev/",
"src": "https://v2.vitejs.dev/logo.svg"
},
{
"id": "vitepress",
"name": "Vitepress",
"href": "https://vitepress.dev/",
"src": "https://vitepress.dev/vitepress-logo-mini.svg"
}
]
function fetchReleaseTag() {
onMounted(() => {
const dom = document.getElementsByClassName('name')
const mainTitle = dom[0]
const docsReleaseTag = document.createElement('span')
docsReleaseTag.classList.add('release-tag')
const releaseTagName = `v${pk.version}`
docsReleaseTag.innerText = releaseTagName
if (releaseTagName !== undefined) {
mainTitle.appendChild(docsReleaseTag)
}
// fetch('https://api.github.com/repos/vitejs/docs-cn/releases/latest')
// .then((res) => res.json())
// .then((json) => {
// const mainTitle = document.getElementById('main-title')
// mainTitle.style.position = 'relative'
// const docsReleaseTag = document.createElement('span')
// docsReleaseTag.classList.add('release-tag')
// const releaseTagName = json.tag_name
// docsReleaseTag.innerText = releaseTagName
// if (releaseTagName !== undefined) {
// mainTitle.appendChild(docsReleaseTag)
// }
// })
})
}
fetchReleaseTag()
</script>
<style>
.sponsors {
padding: 0 1.5rem 2rem;
font-size: 0.8rem;
}
.sponsors a {
color: #999;
margin: 1em;
display: block;
}
.sponsors img {
max-width: 160px;
max-height: 40px;
}
.sponsors.frontpage {
text-align: center;
}
.sponsors.frontpage img {
display: inline-block;
vertical-align: middle;
}
.sponsors.frontpage h2 {
color: #999;
font-size: 1.2rem;
border: none;
}
.sponsors.sidebar a img {
max-height: 36px;
}
.platinum-sponsors {
margin-bottom: 1.5em;
}
.platinum-sponsors a img {
max-width: 240px;
max-height: 60px;
}
.gold-sponsors {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: center;
}
</style>

View File

@ -0,0 +1,4 @@
:::tip
Documentation coming soon...
:::

View File

@ -0,0 +1,4 @@
:::tip
当前文档已经是中文文档了 [首页](/)
:::

View File

@ -0,0 +1,102 @@
---
title: 代码块展示
head:
- - meta
- name: description
content: 代码块展示
- - meta
- name: keywords
content: code
---
# {{ $frontmatter.title }}
## MD语法展示
使用三个 ` 符号将代码包裹其中便是展示代码块
<br/>
**亮/暗主题切换**
根据文档主题模式切换
**代码块主题 macos**
可以在 language_key(语言标识) 后加入 `macos`
输入内容:
<div>
```java macos
</div>
String language = "Java";
<div>
```
</div>
展示效果:
```java macos
String language = "Java";
```
<br/>
**默认主题**
默认主题是以暗色系为主的
输入内容:
<div>
```js
</div>
String language = "JS";
<div>
```
</div>
输出内容:
```java
String language = "JS";
```
<br/>
**示例展示**
- javascript ( js macos )
```js macos
function fun(){
echo "Hello, World!";
}
fun();
```
- Java ( java )
```java
System.out.print(1);
```
- Python ( py macos )
```py macos
#!/usr/bin/env python3
print("Hello, World!");
```
- SQL ( sql )
```sql
select user_name from user_info
```
- Shell ( bash, shell )
```bash
echo '1'
```

View File

@ -0,0 +1,58 @@
---
title: 自定义语法
head:
- - meta
- name: description
content: 自定义 Markdown 语法
- - meta
- name: keywords
content: markdown custom
---
# {{ $frontmatter.title }}
## 信息框
```md
::: tip 使用TIPS代替
提示信息
:::
::: info
信息消息
:::
::: warning
警告消息
:::
::: danger
危险消息
:::
::: details Details
详细信息
:::
```
效果如下:
::: tip 使用TIPS代替
提示内容
:::
::: info
INFO消息
:::
::: warning
WARNING消息 <a>a链接</a>
:::
::: danger
DANGER消息 [md链接](./example.md)
:::
::: details Details
详细信息
:::

View File

@ -0,0 +1,72 @@
---
title: 效果示例
head:
- - meta
- name: description
content: 来看看 MD 会变成什么样子
- - meta
- name: keywords
content: markdown example
---
# Markdown 效果示例
-------------------- 手动分割线 --------------------
# This is an h1 tag
## This is an h2 tag
### This is an h3 tag
#### This is an h4 tag
##### This is an h5 tag
###### This is an h6 tag
*这是斜体*
_这是斜体_
**这是黑体**
__这是黑体__
*斜体里加**黑体***
**黑体里加*斜体***
* Item 1
* Item 2
* Item 2a
* Item 2b
1. Item 1
1. Item 2
1. Item 3
1. Item 3a
1. Item 3b
![Yaktocat的图片](/logo/vuetom-logo.png)
http://github.com - automatic!
[GitHub](http://github.com)
As Kanye West said:
> We're living the future so
> the present is our past.
I think you should use an
`<addr>` element here instead.
First Header | Second Header
------------ | -------------
Content from cell 1 | Content from cell 2
Content in the first column | Content in the second column
~~this~~
😝🌟🐫✨🚶

View File

@ -0,0 +1,31 @@
---
title: UI组件
head:
- - meta
- name: description
content: 各种各样的扁平化UI组件
- - meta
- name: keywords
content: components
---
# {{ $frontmatter.title }}
### `Vuetom UI`
[ui 文档](http://ui.tomhub.cn)
[ui github](https://github.com/lauset/vuetom-ui)
::: tip
UI 文档正在不断完善中请客观耐心等待一下吧T-T
:::
### Markdown 语法示例
这里将会展示在该文档中markdown所呈现的效果
`Example` : Markdown 语法示例
`Custom md` : 自定义语法

View File

@ -0,0 +1,41 @@
{
"name": "@lauset/vuetom-doc",
"version": "2.3.0",
"scripts": {
"dev": "pnpm gen:lang && vitepress dev .",
"build": "pnpm gen:lang && vitepress build .",
"preview": "vitepress preview .",
"serve": "vitepress serve .",
"clean": "rimraf .vitepress/dist",
"gen:lang": "rimraf .vitepress/i18n && tsx .vitepress/build/crowdin-generate.ts",
"crowdin:list": "crowdin list project",
"crowdin:upload": "crowdin upload sources",
"crowdin:us": "crowdin download -l en-US",
"crowdin:tw": "crowdin download -l zh-TW",
"crowdin:dryrun": "crowdin download --dryrun"
},
"dependencies": {
"@vueuse/core": "^9.6.0",
"axios": "1.2.1",
"clipboard-copy": "4.0.1",
"element-plus": "^2.2.26",
"marked": "^4.2.4",
"normalize.css": "8.0.1",
"nprogress": "0.2.0",
"prismjs": "^1.29.0",
"vue": "^3.2.45"
},
"devDependencies": {
"@crowdin/cli": "^3.9.1",
"@types/markdown-it": "12.2.3",
"chalk": "4.1.2",
"escape-html": "1.0.3",
"lodash": "^4.17.20",
"markdown-it": "13.0.1",
"markdown-it-container": "3.0.0",
"rimraf": "^3.0.2",
"sass": "^1.56.2",
"vitepress": "^1.0.0-alpha.30",
"vitepress-theme-vuetom": "^2.3.0"
}
}

View File

@ -0,0 +1 @@
HI FROM PROJECTS

View File

@ -0,0 +1 @@
HI FROM WATCHING

View File

@ -0,0 +1,85 @@
{
"compilerOptions": {
// "incremental": true,
// "composite": true,
// "tsBuildInfoFile": "./",
// "disableSourceOfProjectReferenceRedirect": true,
// "disableSolutionSearching": true,
// "disableReferencedProjectLoad": true,
"target": "ESNext",
// "lib": [],
// "jsx": "preserve",
// "experimentalDecorators": true,
// "emitDecoratorMetadata": true,
// "jsxFactory": "",
// "jsxFragmentFactory": "",
// "jsxImportSource": "",
// "reactNamespace": "",
// "noLib": true,
// "useDefineForClassFields": true,
"module": "ESNext",
// "rootDir": "./",
"moduleResolution": "node",
// "baseUrl": "./",
// "paths": {},
// "rootDirs": [],
// "typeRoots": [],
// "types": [],
// "allowUmdGlobalAccess": true,
"resolveJsonModule": true,
// "noResolve": true,
// "allowJs": true,
// "checkJs": true,
// "maxNodeModuleJsDepth": 1,
// "declaration": true,
// "declarationMap": true,
// "emitDeclarationOnly": true,
// "sourceMap": true,
// "outFile": "./",
// "outDir": "./",
// "removeComments": true,
// "noEmit": true,
// "importHelpers": true,
// "importsNotUsedAsValues": "remove",
// "downlevelIteration": true,
// "sourceRoot": "",
// "mapRoot": "",
// "inlineSourceMap": true,
// "inlineSources": true,
// "emitBOM": true,
// "newLine": "crlf",
// "stripInternal": true,
// "noEmitHelpers": true,
// "noEmitOnError": true,
// "preserveConstEnums": true,
// "declarationDir": "./",
// "isolatedModules": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
// "preserveSymlinks": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": false,
// "strictNullChecks": true,
// "strictFunctionTypes": true,
// "strictBindCallApply": true,
// "strictPropertyInitialization": true,
// "noImplicitThis": true,
// "useUnknownInCatchVariables": true,
// "alwaysStrict": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "exactOptionalPropertyTypes": true,
// "noImplicitReturns": true,
// "noFallthroughCasesInSwitch": true,
// "noUncheckedIndexedAccess": true,
// "noImplicitOverride": true,
// "noPropertyAccessFromIndexSignature": true,
// "allowUnusedLabels": true,
// "allowUnreachableCode": true,
// "skipDefaultLibCheck": true,
"skipLibCheck": true
},
"include": ["**/*", ".vitepress/**/*"],
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,8 @@
{
"rewrites": [
{
"source": "/vt/(.*)",
"destination": "/api/proxy"
}
]
}

View File

@ -0,0 +1,35 @@
import path from 'path'
import { defineConfig } from 'vite'
import type { Alias } from 'vite'
import { projRoot } from './.vitepress/utils/paths'
const alias: Alias[] = []
if (process.env.DOC_ENV !== 'production') {
alias.push(
{
find: /^vitepress-theme-vuetom\/docs$/,
replacement: path.resolve(projRoot, 'packages/vuetom/doc'),
},
{
find: /^vitepress-theme-vuetom\/blog$/,
replacement: path.resolve(projRoot, 'packages/vuetom/blog'),
}
)
}
export default defineConfig({
server: {
host: true,
fs: {
strict: true,
allow: [projRoot]
}
},
resolve: {
alias,
},
optimizeDeps: {
include: ['@vueuse/core']
}
})

158
packages/vuetom/README.md Normal file
View 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
```
## 简单展示
![首页](/resources/pic01.png)
![暗黑主题](/resources/pic02.png)
![语法示例](/resources/pic03.png)
![其他](/resources/pic04.png)
## 仓库地址
[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
View File

@ -0,0 +1,4 @@
import { Theme } from 'vitepress'
declare const BlogTheme: Theme
export default BlogTheme

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More