📝 Add quick-start

This commit is contained in:
xtaodada 2023-10-21 13:28:21 +08:00
parent 2c48ede0be
commit bea098349b
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
15 changed files with 387 additions and 15 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
docs/.vitepress/dist docs/.vitepress/dist
docs/.vitepress/cache docs/.vitepress/cache
node_modules/ node_modules/
.eslintcache

View File

@ -0,0 +1,11 @@
export default {
appId: 'AU4G7FKYJF',
apiKey: 'e934cbf9d54f02be212594ad8b5a1373',
indexName: 'grambot',
placeholder: '请输入关键词',
translations: {
button: {
buttonText: '搜索',
},
},
}

View File

@ -12,12 +12,14 @@ declare module 'vue' {
Card: typeof import('./theme/components/Card.vue')['default'] Card: typeof import('./theme/components/Card.vue')['default']
ChatMessage: typeof import('./theme/components/ChatMessage.vue')['default'] ChatMessage: typeof import('./theme/components/ChatMessage.vue')['default']
ChatPanel: typeof import('./theme/components/ChatPanel.vue')['default'] ChatPanel: typeof import('./theme/components/ChatPanel.vue')['default']
Contributors: typeof import('./theme/components/Contributors.vue')['default']
CopyRight: typeof import('./theme/components/CopyRight.vue')['default'] CopyRight: typeof import('./theme/components/CopyRight.vue')['default']
DataPanel: typeof import('./theme/components/DataPanel.vue')['default'] DataPanel: typeof import('./theme/components/DataPanel.vue')['default']
HomeContributors: typeof import('./theme/components/HomeContributors.vue')['default'] HomeContributors: typeof import('./theme/components/HomeContributors.vue')['default']
NavCard: typeof import('./theme/components/NavCard.vue')['default'] NavCard: typeof import('./theme/components/NavCard.vue')['default']
'Ooui:clock': typeof import('~icons/ooui/clock')['default'] 'Ooui:clock': typeof import('~icons/ooui/clock')['default']
PageInfo: typeof import('./theme/components/PageInfo.vue')['default'] PageInfo: typeof import('./theme/components/PageInfo.vue')['default']
'RadixIcons:update': typeof import('~icons/radix-icons/update')['default']
VideoLink: typeof import('./theme/components/VideoLink.vue')['default'] VideoLink: typeof import('./theme/components/VideoLink.vue')['default']
} }
} }

View File

@ -4,6 +4,7 @@ import { description, docsVersion, github, keywords, name, site } from './meta'
import { pwa } from './plugins/pwa' import { pwa } from './plugins/pwa'
import sidebar from './sidebar' import sidebar from './sidebar'
import socialLinks from './link' import socialLinks from './link'
import algolia from './algolia'
export default withPwa(defineConfig({ export default withPwa(defineConfig({
pwa, pwa,
@ -55,6 +56,7 @@ export default withPwa(defineConfig({
], ],
}, },
], ],
algolia,
sidebar, sidebar,
socialLinks, socialLinks,
}, },

View File

@ -1,4 +1,5 @@
import type { Plugin } from 'vite' import type { Plugin } from 'vite'
import { replacer } from '../../../scripts/utils'
import { getReadingTime } from './../theme/utils' import { getReadingTime } from './../theme/utils'
export function MarkdownTransform(): Plugin { export function MarkdownTransform(): Plugin {
@ -9,6 +10,8 @@ export function MarkdownTransform(): Plugin {
if (!id.match(/\.md\b/)) if (!id.match(/\.md\b/))
return null return null
const [_name, i] = id.split('/').slice(-2)
// convert img // convert img
const imgRegex = /!\[(.+?)\]\((.+?)\)/g const imgRegex = /!\[(.+?)\]\((.+?)\)/g
let imgMatches = imgRegex.exec(code) let imgMatches = imgRegex.exec(code)
@ -18,8 +21,11 @@ export function MarkdownTransform(): Plugin {
imgMatches = imgRegex.exec(code) imgMatches = imgRegex.exec(code)
} }
// const { footer } = await getDocsMarkdown() if (_name === 'docs' && i === 'index.md')
// code = replacer(code, footer, 'FOOTER', 'tail') return code
const { footer } = await getDocsMarkdown()
code = replacer(code, footer, 'FOOTER', 'tail')
const { readTime, words } = getReadingTime(code) const { readTime, words } = getReadingTime(code)
code = code.replace(/(#\s\S.+)/, `$1\n\n<PageInfo readTime="${readTime}" words="${words}"/>\n`) code = code.replace(/(#\s\S.+)/, `$1\n\n<PageInfo readTime="${readTime}" words="${words}"/>\n`)
@ -33,3 +39,14 @@ export function MarkdownTransform(): Plugin {
}, },
} }
} }
export async function getDocsMarkdown() {
const ContributorsSection = `## Contributors
<Contributors/>`
const footer = `${ContributorsSection}\n`
return {
footer,
}
}

View File

@ -5,7 +5,7 @@ export default {
collapsed: true, collapsed: true,
items: [ items: [
{ text: '环境检查', link: '/quick-start/env' }, { text: '环境检查', link: '/quick-start/env' },
{ text: '克隆项目', link: '/quick-start/install' }, { text: '安装项目', link: '/quick-start/install' },
{ text: '配置项目', link: '/quick-start/config' }, { text: '配置项目', link: '/quick-start/config' },
{ text: '启动项目', link: '/quick-start/run' }, { text: '启动项目', link: '/quick-start/run' },
], ],

View File

@ -0,0 +1,42 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useData } from 'vitepress'
const defaultAuthor = 'PaigramTeam'
const { frontmatter } = useData()
const contributorsArr = [frontmatter.value?.author, ...frontmatter.value.contributors || []].filter(x => x)
const contributors = ref(contributorsArr)
function reName(name: string) {
return name
}
function getAvatarUrl(name: string) {
return `https://github.com/${reName(name)}.png`
}
function getGithubLink(name: string) {
return `https://github.com/${reName(name)}`
}
function isNotEmpty(arr: string | string[]) {
return Array.isArray(arr) && arr.length
}
</script>
<template>
<div v-if="isNotEmpty(contributors)" class="flex flex-wrap gap-4">
<div v-for="contributor of contributors" :key="contributor" class="flex gap-2 items-center">
<a :href="getGithubLink(contributor)" rel="noreferrer" target="_blank">
<img :src="getAvatarUrl(contributor)" class="w-8 h-8 rounded-full">
</a>
{{ contributor }}
</div>
</div>
<div v-else class="flex gap-2 items-center">
<a :href="getGithubLink(defaultAuthor)" rel="noreferrer" target="_blank">
<img :src="getAvatarUrl(defaultAuthor)" class="w-8 h-8 rounded-full">
</a>
{{ 'PaigramTeam' }}
</div>
</template>

View File

@ -7,7 +7,7 @@ defineProps<{
readTime: string readTime: string
words: string words: string
}>() }>()
const defaultAuthor = 'Choi Yang' const defaultAuthor = 'PaigramTeam'
const author = ref(defaultAuthor) const author = ref(defaultAuthor)
const { frontmatter, page } = useData() const { frontmatter, page } = useData()
@ -26,6 +26,10 @@ const timeFormNow = getFromNow(isoDatetime.value)
<section <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%]" 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">
<radix-icons:update />
更新于:<span>{{ timeFormNow }}</span>
</div>
<div class="flex gap-[4px] items-center"> <div class="flex gap-[4px] items-center">
<bi:file-earmark-word-fill /> <bi:file-earmark-word-fill />
字数统计:<span>{{ words }} </span> 字数统计:<span>{{ words }} </span>

View File

@ -13,7 +13,7 @@
--vp-c-brand-light: #ff8f91; --vp-c-brand-light: #ff8f91;
--vp-c-text-light-2: rgba(30, 30, 30, 0.7); --vp-c-text-light-2: rgba(30, 30, 30, 0.7);
--cho-code-block-bg: rgba(125, 125, 125, 0.04); --cho-code-block-bg: rgba(125, 125, 125, 0.04);
--vp-c-bg-alt: rgba(235, 235, 235, 0.6); --vp-c-bg-alt: rgba(235, 235, 235);
} }
.dark { .dark {
@ -22,7 +22,7 @@
/* fix contrast on gray cards: check the same above (this is the default) */ /* 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-text-dark-2: rgba(235, 235, 235, 0.6);
--vp-c-bg: rgb(10, 11, 10); --vp-c-bg: rgb(10, 11, 10);
--vp-c-bg-alt: rgba(10, 11, 10, 0.6); --vp-c-bg-alt: rgba(10, 11, 10);
} }
/** /**

183
docs/quick-start/config.md Normal file
View File

@ -0,0 +1,183 @@
---
contributors: ["cworld1"]
---
# 配置项目
## 复制配置模板
```bash
cp .env.example .env
```
## 修改配置
### 基础设置
#### Debug 功能
提供更多日志反馈和网页模板测试功能。可选参数:`true` / `false`
```env
DEBUG=false
```
#### MySQL 数据库
必填。如果使用容器构建,请查阅侧栏的容器构建部分。
```env
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USERNAME=user
DB_PASSWORD="password"
DB_DATABASE=paimon
```
#### Redis 数据库
可选。用于缓存生成图片的不必要数据。
```env
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_DB=0
REDIS_PASSWORD=""
```
#### Telegram Bot Token
必填。联系 [Telegram@BotFather](https://t.me/BotFather) 使用 /newbot 命令创建机器人并获取 token。
```env
BOT_TOKEN="xxxxxxx"
```
#### Bot 管理员
可选。`username` 来自 Telegram 用户信息界面;`user_id` 可通过 [Telegram@IDBot](https://t.me/username_to_id_bot) 获取。
```env
ADMINS=[{ "username": "", "user_id": -1 }]
```
### 其他功能
#### 自动记录错误并发送消息通知开发人员
可选。
```env
ERROR_NOTIFICATION_CHAT_ID=chat_id
```
#### 文章推送群组 可选配置项
可选。
```env
CHANNELS=[{ "name": "", "chat_id": 1}]
```
#### 允许机器人邀请到其他群
可选。默认不允许;如果允许,可以允许全部人或有认证选项。
```env
JOIN_GROUPS = "NO_ALLOW"
```
#### 群验证功能
可选。
```env
VERIFY_GROUPS=[]
```
#### Loger 日志输出
可选。
```env
LOGGER_NAME="TGPaimon"
# 打印时的宽度
LOGGER_WIDTH=180
# log 文件存放目录
LOGGER_LOG_PATH="logs"
# log 时间格式,参考 datetime.strftime
LOGGER_TIME_FORMAT="[%Y-%m-%d %X]"
# log 高亮关键词
LOGGER_RENDER_KEYWORDS=["BOT"]
# traceback 相关配置
LOGGER_TRACEBACK_MAX_FRAMES=20
LOGGER_LOCALS_MAX_DEPTH=0
LOGGER_LOCALS_MAX_LENGTH=10
LOGGER_LOCALS_MAX_STRING=80
# 可被 logger 打印的 record 的名称(默认包含了 LOGGER_NAME
LOGGER_FILTERED_NAMES=["uvicorn","ErrorPush","ApiHelper"]
```
#### 超时配置
可选。
```env
TIMEOUT = 10
READ_TIMEOUT = 2
WRITE_TIMEOUT = 10
CONNECT_TIMEOUT = 10
POOL_TIMEOUT = 10
```
#### mtp 客户端
可选。
```env
API_ID=12345
API_HASH="abcdefg"
```
#### Enka API 配置
可选。默认无,可能会影响 `/player_card` 指令。
```env
ENKA_NETWORK_API_AGENT="TGPaimonBot/3.0"
```
#### Web Server
可选。目前只用于预览模板,仅开发环境启动。
```env
WEB_URL=http://localhost:8080/
WEB_HOST=localhost
WEB_PORT=8080
```
#### 错误信息 Log
可选。
```env
ERROR_PB_URL=https://fars.ee
ERROR_PB_SUNSET=43200
ERROR_PB_MAX_LINES=1000
ERROR_SENTRY_DSN=
```
#### Notice
可选。会作用于 Telegram 中权限不足时的提示。
```env
NOTICE_USER_MISMATCH="再乱点我叫西风骑士团、千岩军、天领奉行、三十人团和风纪官了!"
```
## 初始化数据库
```bash
alembic upgrade head
```

View File

@ -4,7 +4,7 @@
### 1.检查Python版本 ### 1.检查Python版本
首先我们需要确认你的系统中是否已经安装了Python 3.8。打开终端或命令提示符,然后输入以下命令: 首先,我们需要确认你的系统中是否已经安装了 Python 3.8+ 。打开终端或命令提示符,然后输入以下命令:
```bash ```bash
python --version python --version
@ -12,9 +12,7 @@ python --version
如果你的系统已经安装了Python 3.8+那么你应该会看到类似于“Python 3.8.x” “Python 3.9.x” ... 的输出。 如果你的系统已经安装了Python 3.8+那么你应该会看到类似于“Python 3.8.x” “Python 3.9.x” ... 的输出。
如果你看到的是其他版本的Python或者你的系统提示你没有安装Python那么你需要安装Python 3.8+。 如果系统提示你没有安装Python那么你需要安装 Python 3.8+。
GitHub Copilot: # Python Poetry环境检查教程
### 2.检查Poetry是否已安装 ### 2.检查Poetry是否已安装
@ -28,7 +26,7 @@ poetry --version
如果你的系统提示你没有安装Poetry那么你需要安装Poetry。 如果你的系统提示你没有安装Poetry那么你需要安装Poetry。
#### 安装Poetry #### 通过 pip 安装Poetry
打开终端或命令提示符,然后输入以下命令: 打开终端或命令提示符,然后输入以下命令:
@ -37,9 +35,7 @@ pip install poetry
poetry --version poetry --version
``` ```
现在你应该能看到“Poetry version x.x.x”的输出了。 现在你应该能看到 “Poetry version x.x.x” 的输出了。
GitHub Copilot: # Git环境检查教程
## 系统环境检查 ## 系统环境检查

View File

@ -0,0 +1,55 @@
# 安装项目
::: tip
此处以 PaiGram 为例,其余项目同理
:::
## 克隆项目
```bash
git clone https://github.com/PaiGramTeam/PaiGram.git
cd PaiGram
git submodule update --init --recursive
```
## 创建虚拟环境
```bash
python -m venv venv
```
## 激活虚拟环境
### linux
```bash
source venv/bin/activate
```
### windows
```cmd
venv\Scripts\activate.bat
```
### windows powershell
```powershell
.\venv\Scripts\Activate.ps1
```
## 安装项目依赖
### 使用 poetry
```bash
poetry install --extras all
```
### 使用 pip
```bash
pip install -r requirements.txt
```

27
docs/quick-start/run.md Normal file
View File

@ -0,0 +1,27 @@
# 启动项目
## 激活虚拟环境
### linux
```bash
source venv/bin/activate
```
### windows
```cmd
venv\Scripts\activate.bat
```
### windows powershell
```powershell
.\venv\Scripts\Activate.ps1
```
## 运行
```bash
python run.py
```

View File

@ -1,6 +1,6 @@
{ {
"type": "module", "type": "module",
"version": "0.0.1", "version": "4.0.0",
"scripts": { "scripts": {
"dev": "vitepress dev docs --port 8080 --max-old-space-size=50000", "dev": "vitepress dev docs --port 8080 --max-old-space-size=50000",
"build": "vitepress build docs", "build": "vitepress build docs",

32
scripts/utils.ts Normal file
View File

@ -0,0 +1,32 @@
import { resolve } from 'node:path'
import Git from 'simple-git'
export const git = Git()
export const DOCS_URL = 'https://docs.paimon.vip/'
export const DIR_ROOT = resolve(__dirname, '..')
export const DIR_SRC = resolve(__dirname, '../docs')
export function replacer(code: string, value: string, key: string, insert: 'head' | 'tail' | 'none' = 'none') {
const START = `<!--${key}_STARTS-->`
const END = `<!--${key}_ENDS-->`
const regex = new RegExp(`${START}[\\s\\S]*?${END}`, 'im')
const target = value ? `${START}\n${value}\n${END}` : `${START}${END}`
if (!code.match(regex)) {
if (insert === 'none')
return code
else if (insert === 'head')
return `${target}\n\n${code}`
else
return `${code}\n\n${target}`
}
return code.replace(regex, target)
}
export function uniq<T extends any[]>(a: T) {
return Array.from(new Set(a))
}