Compare commits
83 Commits
v1.4.1
...
4b0f39d747
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b0f39d747 | |||
| 096cc1da94 | |||
| 2d3200ad97 | |||
| 4e82e2f6f7 | |||
| 339ed53c2e | |||
| fc7c162e2f | |||
|
|
24f1549730 | ||
| 5584a46ca2 | |||
| 4471441d6f | |||
| 991a89147e | |||
| a08c0d8448 | |||
| 59db8dd177 | |||
| 29693f1baf | |||
| 5d6f157ae1 | |||
| afda3d5301 | |||
| 5d4ba757aa | |||
| d12d58b15a | |||
| 627c3dc71f | |||
| 26c7a3241c | |||
| 46c5e3dd1a | |||
|
|
92a6c6bfdb | ||
| 031aa49f9f | |||
| 1d7aee4cea | |||
| dec3ef5ef4 | |||
| d42f913250 | |||
| bae4e663fb | |||
| a17e060d16 | |||
| 71946965eb | |||
| d4cd22d234 | |||
| 05f2f7d46d | |||
| 9deb2744a9 | |||
| 6fac7c42d6 | |||
| 3393bc84e3 | |||
| 286b0159d7 | |||
| cc98e556c6 | |||
| 5902f482d9 | |||
| 551e7e2cfd | |||
| e0179b5838 | |||
| df79267e16 | |||
| 1f0254822f | |||
| e9b6fef3cd | |||
| 689b0d5d14 | |||
| a058e62595 | |||
| 8571fc0f5c | |||
| 4dad0a86b3 | |||
| 3168b7ff43 | |||
| d002a5be5a | |||
| 24a550463c | |||
| 14ae3e80c4 | |||
| e4d3969e95 | |||
| 0b16d1d4ac | |||
| 300514531d | |||
| 6a4780b002 | |||
| 5688304817 | |||
| 4380ad010c | |||
| 4fa6bb42e3 | |||
| 7aa3a7e37f | |||
| 94306497a9 | |||
| 93c85b800b | |||
| 8ac78e39f1 | |||
| 61a23fe7f2 | |||
| 87fea58102 | |||
|
|
edeac01bee | ||
| 852424356a | |||
| b704dd2438 | |||
| aa8139884b | |||
| 9a15df01ee | |||
| 03780b5bc7 | |||
| b5d90cc59a | |||
| d49ffc20df | |||
| c22e349181 | |||
| 45968cd353 | |||
| 2d02bf7f1f | |||
| 1216b0b67c | |||
| cf8bf688bf | |||
| 4d6a4ff79f | |||
| 3077d5a7c5 | |||
| bc0569af93 | |||
| 0188b618f2 | |||
| 08860e9a5c | |||
| a56d4ef379 | |||
| f5bfff80b7 | |||
| 1462d8a753 |
325
.github/workflows/build-release.yml
vendored
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
name: Build and Release Voidraft
|
||||||
|
|
||||||
|
on:
|
||||||
|
# 推送标签时触发(用于正式发布)
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*' # 触发条件:推送 v 开头的标签,如 v1.0.0
|
||||||
|
branches:
|
||||||
|
- main # 仅当标签在 main 分支时触发
|
||||||
|
|
||||||
|
# 手动触发(用于测试)
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release:
|
||||||
|
description: '是否创建 Release(测试时选 false)'
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
platforms:
|
||||||
|
description: '要构建的平台(用逗号分隔:windows,linux,macos-intel,macos-arm)'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: 'windows,linux'
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: "--max-old-space-size=4096" # 防止 Node.js 内存溢出
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# 准备构建配置
|
||||||
|
prepare:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
should_release: ${{ steps.check-release.outputs.should_release }}
|
||||||
|
steps:
|
||||||
|
- name: 确定构建平台
|
||||||
|
id: set-matrix
|
||||||
|
run: |
|
||||||
|
# 如果是手动触发,根据输入决定平台
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
PLATFORMS="${{ github.event.inputs.platforms }}"
|
||||||
|
else
|
||||||
|
# 标签触发,构建所有平台
|
||||||
|
PLATFORMS="windows,linux,macos-intel,macos-arm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "构建平台: $PLATFORMS"
|
||||||
|
|
||||||
|
# 构建矩阵 JSON
|
||||||
|
MATRIX='{"include":[]}'
|
||||||
|
|
||||||
|
if [[ "$PLATFORMS" == *"windows"* ]]; then
|
||||||
|
MATRIX=$(echo "$MATRIX" | jq -c '.include += [{"platform":"windows-latest","os":"windows","arch":"amd64","platform_dir":"windows","id":"windows"}]')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$PLATFORMS" == *"linux"* ]]; then
|
||||||
|
MATRIX=$(echo "$MATRIX" | jq -c '.include += [{"platform":"ubuntu-22.04","os":"linux","arch":"amd64","platform_dir":"linux","id":"linux"}]')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$PLATFORMS" == *"macos-intel"* ]]; then
|
||||||
|
MATRIX=$(echo "$MATRIX" | jq -c '.include += [{"platform":"macos-latest","os":"darwin","arch":"amd64","platform_dir":"darwin","id":"macos-intel"}]')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$PLATFORMS" == *"macos-arm"* ]]; then
|
||||||
|
MATRIX=$(echo "$MATRIX" | jq -c '.include += [{"platform":"macos-latest","os":"darwin","arch":"arm64","platform_dir":"darwin","id":"macos-arm"}]')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 使用 -c 确保输出紧凑的单行 JSON,符合 GitHub Actions 输出格式
|
||||||
|
echo "matrix=$(echo "$MATRIX" | jq -c .)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# 输出美化的 JSON 用于日志查看
|
||||||
|
echo "生成的矩阵:"
|
||||||
|
echo "$MATRIX" | jq .
|
||||||
|
|
||||||
|
- name: 检查是否创建 Release
|
||||||
|
id: check-release
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
# 手动触发,根据输入决定
|
||||||
|
echo "should_release=${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
# 标签触发,自动创建 Release
|
||||||
|
echo "should_release=true" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: prepare
|
||||||
|
if: ${{ fromJson(needs.prepare.outputs.matrix).include[0] != null }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix: ${{ fromJson(needs.prepare.outputs.matrix) }}
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 检出代码
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: 设置 Go 环境
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.21'
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: 设置 Node.js 环境
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: frontend/package-lock.json
|
||||||
|
|
||||||
|
# Linux 平台依赖
|
||||||
|
- name: 安装 Linux 依赖
|
||||||
|
if: matrix.os == 'linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
# Wails 3 + 项目特定依赖
|
||||||
|
sudo apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
pkg-config \
|
||||||
|
libgtk-3-dev \
|
||||||
|
libwebkit2gtk-4.1-dev \
|
||||||
|
libayatana-appindicator3-dev \
|
||||||
|
librsvg2-dev \
|
||||||
|
patchelf \
|
||||||
|
libx11-dev \
|
||||||
|
rpm \
|
||||||
|
fuse \
|
||||||
|
file
|
||||||
|
|
||||||
|
# 依赖说明:
|
||||||
|
# - build-essential: C/C++ 编译工具链
|
||||||
|
# - pkg-config: 包配置工具
|
||||||
|
# - libgtk-3-dev: GTK3 GUI 框架
|
||||||
|
# - libwebkit2gtk-4.1-dev: WebKit2GTK 4.1 (Wails 3 要求)
|
||||||
|
# - libayatana-appindicator3-dev: 系统托盘支持
|
||||||
|
# - librsvg2-dev: SVG 图标支持
|
||||||
|
# - patchelf: 修改 ELF 二进制文件
|
||||||
|
# - libx11-dev: X11 库 (热键服务依赖)
|
||||||
|
# - rpm: RPM 打包工具
|
||||||
|
# - fuse: AppImage 运行依赖
|
||||||
|
# - file: 文件类型检测工具
|
||||||
|
|
||||||
|
# Windows 平台依赖
|
||||||
|
- name: 设置 Windows 构建环境
|
||||||
|
if: matrix.os == 'windows'
|
||||||
|
run: |
|
||||||
|
# 安装 NSIS (用于创建安装程序)
|
||||||
|
choco install nsis -y
|
||||||
|
# 将 NSIS 添加到 PATH
|
||||||
|
echo "C:\Program Files (x86)\NSIS" >> $GITHUB_PATH
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
# macOS 平台依赖
|
||||||
|
- name: 设置 macOS 构建环境
|
||||||
|
if: matrix.os == 'darwin'
|
||||||
|
run: |
|
||||||
|
# Xcode 命令行工具通常已安装
|
||||||
|
xcode-select --install 2>/dev/null || true
|
||||||
|
|
||||||
|
# 安装 Wails CLI
|
||||||
|
- name: 安装 Wails CLI
|
||||||
|
run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest
|
||||||
|
|
||||||
|
# 安装前端依赖
|
||||||
|
- name: 安装前端依赖
|
||||||
|
working-directory: frontend
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
# 构建前端
|
||||||
|
- name: 构建前端
|
||||||
|
working-directory: frontend
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
# 使用 Wails Task 构建和打包应用
|
||||||
|
- name: 构建和打包 Wails 应用
|
||||||
|
run: wails3 task ${{ matrix.id }}:package PRODUCTION=true ARCH=${{ matrix.arch }}
|
||||||
|
env:
|
||||||
|
CGO_ENABLED: 1
|
||||||
|
APP_NAME: voidraft
|
||||||
|
BIN_DIR: bin
|
||||||
|
ROOT_DIR: .
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
# 整理构建产物
|
||||||
|
- name: 整理构建产物
|
||||||
|
id: organize_artifacts
|
||||||
|
run: |
|
||||||
|
echo "=== 构建产物列表 ==="
|
||||||
|
ls -lhR bin/ || echo "bin 目录不存在"
|
||||||
|
|
||||||
|
# 创建输出目录
|
||||||
|
mkdir -p artifacts
|
||||||
|
|
||||||
|
# 根据平台复制产物
|
||||||
|
if [ "${{ matrix.os }}" = "windows" ]; then
|
||||||
|
echo "Windows 平台:查找 NSIS 安装程序"
|
||||||
|
find . -name "*.exe" -type f
|
||||||
|
cp bin/*.exe artifacts/ 2>/dev/null || echo "未找到 .exe 文件"
|
||||||
|
|
||||||
|
elif [ "${{ matrix.os }}" = "linux" ]; then
|
||||||
|
echo "Linux 平台:查找 AppImage, deb, rpm, archlinux 包"
|
||||||
|
find bin -type f
|
||||||
|
cp bin/*.AppImage artifacts/ 2>/dev/null || echo "未找到 AppImage"
|
||||||
|
cp bin/*.deb artifacts/ 2>/dev/null || echo "未找到 deb"
|
||||||
|
cp bin/*.rpm artifacts/ 2>/dev/null || echo "未找到 rpm"
|
||||||
|
cp bin/*.pkg.tar.zst artifacts/ 2>/dev/null || echo "未找到 archlinux 包"
|
||||||
|
|
||||||
|
elif [ "${{ matrix.os }}" = "darwin" ]; then
|
||||||
|
echo "macOS 平台:查找 .app bundle"
|
||||||
|
find bin -name "*.app" -type d
|
||||||
|
# macOS: .app bundle,打包成 zip
|
||||||
|
if [ -d "bin/voidraft.app" ]; then
|
||||||
|
cd bin
|
||||||
|
zip -r ../artifacts/voidraft-darwin-${{ matrix.arch }}.app.zip voidraft.app
|
||||||
|
cd ..
|
||||||
|
else
|
||||||
|
echo "未找到 .app bundle"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== 最终产物 ==="
|
||||||
|
ls -lh artifacts/ || echo "artifacts 目录为空"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
# 上传构建产物到 Artifacts
|
||||||
|
- name: 上传构建产物
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: voidraft-${{ matrix.id }}
|
||||||
|
path: artifacts/*
|
||||||
|
if-no-files-found: warn
|
||||||
|
|
||||||
|
# 创建 GitHub Release 并上传所有构建产物
|
||||||
|
release:
|
||||||
|
needs: [prepare, build]
|
||||||
|
if: ${{ needs.prepare.outputs.should_release == 'true' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 检出代码
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 下载所有构建产物
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
- name: 显示下载的文件
|
||||||
|
run: |
|
||||||
|
echo "下载的构建产物:"
|
||||||
|
ls -R artifacts/
|
||||||
|
|
||||||
|
- name: 准备 Release 文件
|
||||||
|
run: |
|
||||||
|
mkdir -p release
|
||||||
|
find artifacts -type f -exec cp {} release/ \;
|
||||||
|
ls -lh release/
|
||||||
|
|
||||||
|
- name: 生成 Release 说明
|
||||||
|
id: release_notes
|
||||||
|
run: |
|
||||||
|
# 获取版本号
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
VERSION="${{ github.sha }}"
|
||||||
|
VERSION_NAME="测试构建 ${VERSION:0:7}"
|
||||||
|
else
|
||||||
|
VERSION="${{ github.ref_name }}"
|
||||||
|
VERSION_NAME="${VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > release_notes.md << EOF
|
||||||
|
## Voidraft ${VERSION_NAME}
|
||||||
|
|
||||||
|
### 📦 下载
|
||||||
|
|
||||||
|
根据你的操作系统选择对应的版本:
|
||||||
|
|
||||||
|
- **Windows (64位)**: \`voidraft-windows-amd64.exe\`
|
||||||
|
- **Linux (64位)**: \`voidraft-linux-amd64\`
|
||||||
|
- **macOS (Intel)**: \`voidraft-darwin-amd64.zip\`
|
||||||
|
- **macOS (Apple Silicon)**: \`voidraft-darwin-arm64.zip\`
|
||||||
|
|
||||||
|
### 📝 更新内容
|
||||||
|
|
||||||
|
请查看 [提交历史](../../commits/${{ github.ref_name }}) 了解本次更新的详细内容。
|
||||||
|
|
||||||
|
### 💡 使用说明
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
1. 下载 `voidraft-windows-amd64.exe`
|
||||||
|
2. 直接运行即可
|
||||||
|
|
||||||
|
#### Linux
|
||||||
|
1. 下载 `voidraft-linux-amd64`
|
||||||
|
2. 添加执行权限:`chmod +x voidraft-linux-amd64`
|
||||||
|
3. 运行:`./voidraft-linux-amd64`
|
||||||
|
|
||||||
|
#### macOS
|
||||||
|
1. 下载对应架构的 zip 文件
|
||||||
|
2. 解压后运行
|
||||||
|
3. 如果提示无法打开,请在 系统偏好设置 > 安全性与隐私 中允许运行
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
构建时间: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: 创建 GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: release/*
|
||||||
|
body_path: release_notes.md
|
||||||
|
draft: false
|
||||||
|
prerelease: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
|
tag_name: ${{ github.event_name == 'workflow_dispatch' && format('test-{0}', github.sha) || github.ref_name }}
|
||||||
|
name: ${{ github.event_name == 'workflow_dispatch' && format('测试构建 {0}', github.sha) || github.ref_name }}
|
||||||
|
generate_release_notes: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
67
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# 构建 VitePress 站点并将其部署到 GitHub Pages 的示例工作流程
|
||||||
|
#
|
||||||
|
name: Deploy VitePress site to Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
# 在针对 `main` 分支的推送上运行。如果你
|
||||||
|
# 使用 `master` 分支作为默认分支,请将其更改为 `master`
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
# 允许你从 Actions 选项卡手动运行此工作流程
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# 只允许同时进行一次部署,跳过正在运行和最新队列之间的运行队列
|
||||||
|
# 但是,不要取消正在进行的运行,因为我们希望允许这些生产部署完成
|
||||||
|
concurrency:
|
||||||
|
group: pages
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# 构建工作
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # 如果未启用 lastUpdated,则不需要
|
||||||
|
# - uses: pnpm/action-setup@v3 # 如果使用 pnpm,请取消此区域注释
|
||||||
|
# with:
|
||||||
|
# version: 9
|
||||||
|
# - uses: oven-sh/setup-bun@v1 # 如果使用 Bun,请取消注释
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: frontend/package-lock.json
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Install dependencies
|
||||||
|
run: cd frontend && npm ci
|
||||||
|
- name: Build with VitePress
|
||||||
|
run: cd frontend && npm run docs:build
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: frontend/docs/.vitepress/dist
|
||||||
|
|
||||||
|
# 部署工作
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
4
.gitignore
vendored
@@ -4,4 +4,6 @@ frontend/dist
|
|||||||
frontend/node_modules
|
frontend/node_modules
|
||||||
build/linux/appimage/build
|
build/linux/appimage/build
|
||||||
build/windows/nsis/MicrosoftEdgeWebview2Setup.exe
|
build/windows/nsis/MicrosoftEdgeWebview2Setup.exe
|
||||||
.idea
|
.idea
|
||||||
|
frontend/docs/.vitepress/cache/
|
||||||
|
frontend/docs/.vitepress/dist/
|
||||||
12
Taskfile.yml
@@ -12,25 +12,13 @@ vars:
|
|||||||
VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}'
|
VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}'
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
version:
|
|
||||||
summary: Generate version information
|
|
||||||
cmds:
|
|
||||||
- '{{if eq OS "windows"}}cmd /c ".\scripts\version.bat"{{else}}bash ./scripts/version.sh{{end}}'
|
|
||||||
sources:
|
|
||||||
- scripts/version.bat
|
|
||||||
- scripts/version.sh
|
|
||||||
generates:
|
|
||||||
- version.txt
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
summary: Builds the application
|
summary: Builds the application
|
||||||
deps: [version]
|
|
||||||
cmds:
|
cmds:
|
||||||
- task: "{{OS}}:build"
|
- task: "{{OS}}:build"
|
||||||
|
|
||||||
package:
|
package:
|
||||||
summary: Packages a production build of the application
|
summary: Packages a production build of the application
|
||||||
deps: [version]
|
|
||||||
cmds:
|
cmds:
|
||||||
- task: "{{OS}}:package"
|
- task: "{{OS}}:package"
|
||||||
|
|
||||||
|
|||||||
293
build/COMMANDS.md
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
# Wails 3 命令参考表
|
||||||
|
|
||||||
|
本文档列出了 Voidraft 项目中使用的所有 Wails 3 命令和参数。
|
||||||
|
|
||||||
|
## 📋 命令总览
|
||||||
|
|
||||||
|
| 类别 | 命令 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| 生成工具 | `wails3 generate` | 生成项目所需的各种资源文件 |
|
||||||
|
| 打包工具 | `wails3 tool package` | 使用 nfpm 打包应用程序 |
|
||||||
|
| 任务执行 | `wails3 task` | 执行 Taskfile.yml 中定义的任务 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 详细命令参数
|
||||||
|
|
||||||
|
### 1. `wails3 generate bindings`
|
||||||
|
**生成 TypeScript 绑定文件**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-f` | 构建标志 | `''` (空字符串) |
|
||||||
|
| `-clean` | 清理旧绑定 | `true` |
|
||||||
|
| `-ts` | 生成 TypeScript | 无需值 |
|
||||||
|
|
||||||
|
**使用位置:** `build/Taskfile.yml:53`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 generate bindings -f '' -clean=true -ts
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `wails3 generate icons`
|
||||||
|
**从单个图片生成多平台图标**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-input` | 输入图片路径 | `appicon.png` |
|
||||||
|
| `-macfilename` | macOS 图标输出路径 | `darwin/icons.icns` |
|
||||||
|
| `-windowsfilename` | Windows 图标输出路径 | `windows/icons.ico` |
|
||||||
|
|
||||||
|
**使用位置:** `build/Taskfile.yml:64`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 generate icons \
|
||||||
|
-input appicon.png \
|
||||||
|
-macfilename darwin/icons.icns \
|
||||||
|
-windowsfilename windows/icons.ico
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. `wails3 generate syso`
|
||||||
|
**生成 Windows .syso 资源文件**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-arch` | 目标架构 | `amd64` / `arm64` |
|
||||||
|
| `-icon` | 图标文件 | `windows/icon.ico` |
|
||||||
|
| `-manifest` | 清单文件 | `windows/wails.exe.manifest` |
|
||||||
|
| `-info` | 应用信息 JSON | `windows/info.json` |
|
||||||
|
| `-out` | 输出文件路径 | `../wails_windows_amd64.syso` |
|
||||||
|
|
||||||
|
**使用位置:** `build/windows/Taskfile.yml:42`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 generate syso \
|
||||||
|
-arch amd64 \
|
||||||
|
-icon windows/icon.ico \
|
||||||
|
-manifest windows/wails.exe.manifest \
|
||||||
|
-info windows/info.json \
|
||||||
|
-out ../wails_windows_amd64.syso
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. `wails3 generate webview2bootstrapper`
|
||||||
|
**生成 Windows WebView2 引导程序**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-dir` | 输出目录 | `build/windows/nsis` |
|
||||||
|
|
||||||
|
**使用位置:** `build/windows/Taskfile.yml:55`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 generate webview2bootstrapper -dir "build/windows/nsis"
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:** 下载 Microsoft Edge WebView2 运行时安装程序,用于 NSIS 打包。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. `wails3 generate .desktop`
|
||||||
|
**生成 Linux .desktop 桌面文件**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-name` | 应用名称 | `voidraft` |
|
||||||
|
| `-exec` | 可执行文件名 | `voidraft` |
|
||||||
|
| `-icon` | 图标名称 | `appicon` |
|
||||||
|
| `-outputfile` | 输出文件路径 | `build/linux/voidraft.desktop` |
|
||||||
|
| `-categories` | 应用分类 | `Development;` |
|
||||||
|
|
||||||
|
**使用位置:** `build/linux/Taskfile.yml:107`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 generate .desktop \
|
||||||
|
-name "voidraft" \
|
||||||
|
-exec "voidraft" \
|
||||||
|
-icon "appicon" \
|
||||||
|
-outputfile build/linux/voidraft.desktop \
|
||||||
|
-categories "Development;"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. `wails3 generate appimage`
|
||||||
|
**生成 Linux AppImage 包**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-binary` | 二进制文件名 | `voidraft` |
|
||||||
|
| `-icon` | 图标文件路径 | `../../appicon.png` |
|
||||||
|
| `-desktopfile` | .desktop 文件路径 | `../voidraft.desktop` |
|
||||||
|
| `-outputdir` | 输出目录 | `../../../bin` |
|
||||||
|
| `-builddir` | 构建临时目录 | `build/linux/appimage/build` |
|
||||||
|
|
||||||
|
**使用位置:** `build/linux/Taskfile.yml:49`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 generate appimage \
|
||||||
|
-binary voidraft \
|
||||||
|
-icon ../../appicon.png \
|
||||||
|
-desktopfile ../voidraft.desktop \
|
||||||
|
-outputdir ../../../bin \
|
||||||
|
-builddir build/linux/appimage/build
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:** 自动下载 linuxdeploy 工具并创建 AppImage。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. `wails3 tool package` (deb)
|
||||||
|
**创建 Debian/Ubuntu .deb 包**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-name` | 包名称 | `voidraft` |
|
||||||
|
| `-format` | 包格式 | `deb` |
|
||||||
|
| `-config` | nfpm 配置文件 | `./build/linux/nfpm/nfpm.yaml` |
|
||||||
|
| `-out` | 输出目录 | `./bin` |
|
||||||
|
|
||||||
|
**使用位置:** `build/linux/Taskfile.yml:90`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 tool package \
|
||||||
|
-name voidraft \
|
||||||
|
-format deb \
|
||||||
|
-config ./build/linux/nfpm/nfpm.yaml \
|
||||||
|
-out ./bin
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. `wails3 tool package` (rpm)
|
||||||
|
**创建 RedHat/CentOS/Fedora .rpm 包**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-name` | 包名称 | `voidraft` |
|
||||||
|
| `-format` | 包格式 | `rpm` |
|
||||||
|
| `-config` | nfpm 配置文件 | `./build/linux/nfpm/nfpm.yaml` |
|
||||||
|
| `-out` | 输出目录 | `./bin` |
|
||||||
|
|
||||||
|
**使用位置:** `build/linux/Taskfile.yml:95`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 tool package \
|
||||||
|
-name voidraft \
|
||||||
|
-format rpm \
|
||||||
|
-config ./build/linux/nfpm/nfpm.yaml \
|
||||||
|
-out ./bin
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. `wails3 tool package` (archlinux)
|
||||||
|
**创建 Arch Linux .pkg.tar.zst 包**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `-name` | 包名称 | `voidraft` |
|
||||||
|
| `-format` | 包格式 | `archlinux` |
|
||||||
|
| `-config` | nfpm 配置文件 | `./build/linux/nfpm/nfpm.yaml` |
|
||||||
|
| `-out` | 输出目录 | `./bin` |
|
||||||
|
|
||||||
|
**使用位置:** `build/linux/Taskfile.yml:100`
|
||||||
|
|
||||||
|
**完整命令:**
|
||||||
|
```bash
|
||||||
|
wails3 tool package \
|
||||||
|
-name voidraft \
|
||||||
|
-format archlinux \
|
||||||
|
-config ./build/linux/nfpm/nfpm.yaml \
|
||||||
|
-out ./bin
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10. `wails3 task`
|
||||||
|
**执行 Taskfile.yml 中定义的任务**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `[taskname]` | 任务名称 | `build`, `package`, `run` |
|
||||||
|
| `[VAR=value]` | 变量赋值 | `PRODUCTION=true`, `ARCH=amd64` |
|
||||||
|
|
||||||
|
**常用任务:**
|
||||||
|
|
||||||
|
| 任务 | 说明 | 命令 |
|
||||||
|
|------|------|------|
|
||||||
|
| `build` | 构建应用 | `wails3 task build PRODUCTION=true` |
|
||||||
|
| `package` | 打包应用 | `wails3 task package` |
|
||||||
|
| `run` | 运行应用 | `wails3 task run` |
|
||||||
|
|
||||||
|
**使用位置:** `build/config.yml`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 平台对应命令表
|
||||||
|
|
||||||
|
| 平台 | 主要命令 | 产物 |
|
||||||
|
|------|----------|------|
|
||||||
|
| **Windows** | `generate syso`<br>`generate webview2bootstrapper` | `.syso` 资源文件<br>NSIS 安装程序 |
|
||||||
|
| **Linux** | `generate .desktop`<br>`generate appimage`<br>`tool package -format deb/rpm/archlinux` | `.desktop` 文件<br>`.AppImage`<br>`.deb` / `.rpm` / `.pkg.tar.zst` |
|
||||||
|
| **macOS** | `generate icons` | `.icns` 图标<br>`.app` 应用包 |
|
||||||
|
| **通用** | `generate bindings`<br>`generate icons` | TypeScript 绑定<br>多平台图标 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 快速参考
|
||||||
|
|
||||||
|
### 完整构建流程
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 生成绑定和图标
|
||||||
|
wails3 task common:generate:bindings
|
||||||
|
wails3 task common:generate:icons
|
||||||
|
|
||||||
|
# 2. 构建前端
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# 3. 构建应用(各平台)
|
||||||
|
cd build/windows && wails3 task build PRODUCTION=true # Windows
|
||||||
|
cd build/linux && wails3 task build PRODUCTION=true # Linux
|
||||||
|
cd build/darwin && wails3 task build PRODUCTION=true # macOS
|
||||||
|
|
||||||
|
# 4. 打包应用(各平台)
|
||||||
|
cd build/windows && wails3 task package # NSIS 安装程序
|
||||||
|
cd build/linux && wails3 task package # AppImage + deb + rpm + archlinux
|
||||||
|
cd build/darwin && wails3 task package # .app bundle
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 注意事项
|
||||||
|
|
||||||
|
1. **变量传递:** Task 命令支持通过 `VAR=value` 格式传递变量
|
||||||
|
2. **路径问题:** 相对路径基于 Taskfile.yml 所在目录
|
||||||
|
3. **依赖顺序:** 某些任务有依赖关系(通过 `deps:` 定义)
|
||||||
|
4. **环境变量:** 使用 `env:` 定义的环境变量会自动设置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 相关文档
|
||||||
|
|
||||||
|
- [Wails 3 官方文档](https://v3alpha.wails.io/)
|
||||||
|
- [Taskfile 语法](https://taskfile.dev/)
|
||||||
|
- [nfpm 打包工具](https://nfpm.goreleaser.com/)
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
voidraft.landaiqing.cn
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>voidraft - Changelog</title>
|
|
||||||
<link rel="stylesheet" href="css/styles.css">
|
|
||||||
<link rel="stylesheet" href="css/changelog.css">
|
|
||||||
<link rel="icon" href="img/favicon.ico">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Space+Mono&display=swap" rel="stylesheet">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
||||||
</head>
|
|
||||||
<body class="theme-dark">
|
|
||||||
<div class="container">
|
|
||||||
<!-- 主卡片 -->
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h1 class="card-title" data-en="voidraft Changelog" data-zh="voidraft 更新日志">voidraft Changelog</h1>
|
|
||||||
<div class="card-controls">
|
|
||||||
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
|
||||||
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
|
||||||
</button>
|
|
||||||
<button id="lang-toggle" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-language"></i> 中/EN
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-content">
|
|
||||||
<!-- 导航区域 -->
|
|
||||||
<div class="nav-links">
|
|
||||||
<a href="index.html" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-home"></i> <span data-en="Home" data-zh="首页">Home</span>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/landaiqing/voidraft" class="btn btn-secondary">
|
|
||||||
<i class="fab fa-github"></i> <span data-en="Source Code" data-zh="源代码">Source Code</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 加载中提示 -->
|
|
||||||
<div id="loading" class="loading-container">
|
|
||||||
<div class="loading-spinner"></div>
|
|
||||||
<p data-en="Loading releases..." data-zh="正在加载版本信息...">Loading releases...</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 更新日志内容 -->
|
|
||||||
<div id="changelog" class="changelog-container">
|
|
||||||
<!-- 通过JavaScript动态填充内容 -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 错误信息 -->
|
|
||||||
<div id="error-message" class="error-container" style="display: none;">
|
|
||||||
<i class="fas fa-exclamation-triangle"></i>
|
|
||||||
<p data-en="Failed to load release information. Please try again later."
|
|
||||||
data-zh="加载版本信息失败,请稍后再试。">Failed to load release information. Please try again later.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 页脚 -->
|
|
||||||
<footer class="footer">
|
|
||||||
<p class="footer-text" data-en="© 2025 voidraft - An elegant text snippet recording tool designed for developers" data-zh="© 2025 voidraft - 专为开发者打造的优雅文本片段记录工具">© 2023-2024 voidraft - An elegant text snippet recording tool designed for developers</p>
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="https://github.com/landaiqing/voidraft" target="_blank" class="footer-link">GitHub</a>
|
|
||||||
<a href="https://github.com/landaiqing/voidraft/issues" target="_blank" class="footer-link" data-en="Issues" data-zh="问题反馈">Issues</a>
|
|
||||||
<a href="https://github.com/landaiqing/voidraft/releases" target="_blank" class="footer-link" data-en="Releases" data-zh="版本发布">Releases</a>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="js/script.js"></script>
|
|
||||||
<script src="js/changelog.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,347 +0,0 @@
|
|||||||
/* 更新日志页面样式 */
|
|
||||||
.nav-links {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-container {
|
|
||||||
text-align: center;
|
|
||||||
padding: 40px 0;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spinner {
|
|
||||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
|
||||||
border-left-color: var(--primary-color);
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
margin: 0 auto 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .loading-spinner {
|
|
||||||
border-color: rgba(255, 255, 255, 0.1);
|
|
||||||
border-left-color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-container {
|
|
||||||
text-align: center;
|
|
||||||
color: var(--error-color);
|
|
||||||
padding: 20px;
|
|
||||||
border: 2px dashed var(--error-color);
|
|
||||||
margin: 20px 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: rgba(var(--card-bg-rgb), 0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-container i {
|
|
||||||
font-size: 24px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 更新日志容器 */
|
|
||||||
.changelog-container {
|
|
||||||
display: none;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
border-left: 4px solid var(--primary-color);
|
|
||||||
padding-left: 20px;
|
|
||||||
background-color: rgba(var(--card-bg-rgb), 0.5);
|
|
||||||
padding: 15px 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-version {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-date {
|
|
||||||
color: var(--text-color);
|
|
||||||
opacity: 0.7;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-badge {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 3px 8px;
|
|
||||||
border-radius: 12px;
|
|
||||||
font-size: 12px;
|
|
||||||
margin-left: 10px;
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-badge.pre-release {
|
|
||||||
background-color: var(--warning-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-description {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-assets {
|
|
||||||
background-color: rgba(var(--light-bg-rgb), 0.7);
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 4px;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-assets-title {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-list {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 8px 0;
|
|
||||||
border-bottom: 1px solid rgba(128, 128, 128, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-item:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-icon {
|
|
||||||
margin-right: 10px;
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-name {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-size {
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--text-color);
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 资源下载按钮 */
|
|
||||||
.download-btn {
|
|
||||||
margin-left: 10px;
|
|
||||||
padding: 3px 10px;
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 12px;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
display: inline-block;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.download-btn:hover {
|
|
||||||
background-color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content {
|
|
||||||
line-height: 1.8;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content h1,
|
|
||||||
.markdown-content h2,
|
|
||||||
.markdown-content h3 {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content ul,
|
|
||||||
.markdown-content ol {
|
|
||||||
padding-left: 20px;
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content li {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content li:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content hr {
|
|
||||||
border: none;
|
|
||||||
border-top: 2px dashed var(--border-color);
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content br {
|
|
||||||
display: block;
|
|
||||||
content: "";
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content code {
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
background-color: rgba(128, 128, 128, 0.1);
|
|
||||||
padding: 2px 4px;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content pre {
|
|
||||||
background-color: rgba(128, 128, 128, 0.1);
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 15px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content pre code {
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content a {
|
|
||||||
color: var(--primary-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.data-source {
|
|
||||||
padding: 10px 15px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
background-color: rgba(var(--light-bg-rgb), 0.7);
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: right;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.data-source a {
|
|
||||||
color: var(--primary-color);
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.data-source a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown内容样式增强 */
|
|
||||||
.markdown-content blockquote {
|
|
||||||
border-left: 4px solid var(--primary-color);
|
|
||||||
padding: 10px 15px;
|
|
||||||
margin: 15px 0;
|
|
||||||
background-color: rgba(var(--light-bg-rgb), 0.5);
|
|
||||||
border-radius: 0 4px 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content ul,
|
|
||||||
.markdown-content ol {
|
|
||||||
padding-left: 20px;
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动设备响应式优化 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.release-header {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-assets {
|
|
||||||
padding: 12px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-item {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
padding: 12px 0;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-name {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-size {
|
|
||||||
margin-left: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.download-btn {
|
|
||||||
margin-left: 10px;
|
|
||||||
padding: 5px 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.release {
|
|
||||||
padding-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-item {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-icon {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-size {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.download-btn {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-top: 10px;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content pre {
|
|
||||||
padding: 10px;
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 确保日志页面页脚样式一致 */
|
|
||||||
.footer {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-text {
|
|
||||||
margin: 0 0 15px 0;
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/* cyrillic-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'IBM Plex Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/ibm-plex-mono/-F63fjptAgt5VM-kVkqdyU8n1iIq129k.woff2) format('woff2');
|
|
||||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
|
||||||
}
|
|
||||||
/* cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'IBM Plex Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/ibm-plex-mono/-F63fjptAgt5VM-kVkqdyU8n1isq129k.woff2) format('woff2');
|
|
||||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
||||||
}
|
|
||||||
/* vietnamese */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'IBM Plex Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/ibm-plex-mono/-F63fjptAgt5VM-kVkqdyU8n1iAq129k.woff2) format('woff2');
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'IBM Plex Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/ibm-plex-mono/-F63fjptAgt5VM-kVkqdyU8n1iEq129k.woff2) format('woff2');
|
|
||||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
/* latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'IBM Plex Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/ibm-plex-mono/-F63fjptAgt5VM-kVkqdyU8n1i8q1w.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/* vietnamese */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Space Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/space-mono/i7dPIFZifjKcF5UAWdDRYE58RWq7.woff2) format('woff2');
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Space Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/space-mono/i7dPIFZifjKcF5UAWdDRYE98RWq7.woff2) format('woff2');
|
|
||||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
/* latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Space Mono';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(../font/space-mono/i7dPIFZifjKcF5UAWdDRYEF8RQ.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
@@ -1,717 +0,0 @@
|
|||||||
@import url('./space-mono-font.css');
|
|
||||||
@import url('./ibm-plex-mono-font.css');
|
|
||||||
|
|
||||||
/* 浅色主题 */
|
|
||||||
:root {
|
|
||||||
--bg-color: #fefefe;
|
|
||||||
--text-color: #000000;
|
|
||||||
--primary-color: #F08080;
|
|
||||||
--primary-color-rgb: 240, 128, 128;
|
|
||||||
--secondary-color: #ff006e;
|
|
||||||
--accent-color: #073B4C;
|
|
||||||
--card-bg: #ffffff;
|
|
||||||
--card-bg-rgb: 255, 255, 255;
|
|
||||||
--border-color: #000000;
|
|
||||||
--light-bg: #f0f0f0;
|
|
||||||
--light-bg-rgb: 240, 240, 240;
|
|
||||||
--shadow-color: rgba(240, 128, 128, 0.5);
|
|
||||||
--success-color: #27c93f;
|
|
||||||
--warning-color: #FFD166;
|
|
||||||
--error-color: #ff006e;
|
|
||||||
--info-color: #118ab2;
|
|
||||||
--code-bg: #ffffff;
|
|
||||||
--code-bg-rgb: 255, 255, 255;
|
|
||||||
--preview-header-bg: #f0f0f0;
|
|
||||||
--preview-header-bg-rgb: 240, 240, 240;
|
|
||||||
--grid-color-1: rgba(0, 0, 0, 0.08);
|
|
||||||
--grid-color-2: rgba(0, 0, 0, 0.05);
|
|
||||||
--header-title-color: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 暗色主题变量 */
|
|
||||||
.theme-dark {
|
|
||||||
--bg-color: #121212;
|
|
||||||
--text-color: #ffffff;
|
|
||||||
--primary-color: #F08080;
|
|
||||||
--primary-color-rgb: 240, 128, 128;
|
|
||||||
--secondary-color: #ff006e;
|
|
||||||
--accent-color: #118ab2;
|
|
||||||
--card-bg: #1e1e1e;
|
|
||||||
--card-bg-rgb: 30, 30, 30;
|
|
||||||
--border-color: #ffffff;
|
|
||||||
--light-bg: #2a2a2a;
|
|
||||||
--light-bg-rgb: 42, 42, 42;
|
|
||||||
--shadow-color: rgba(240, 128, 128, 0.5);
|
|
||||||
--success-color: #27c93f;
|
|
||||||
--warning-color: #FFD166;
|
|
||||||
--error-color: #ff006e;
|
|
||||||
--info-color: #118ab2;
|
|
||||||
--code-bg: #1e1e1e;
|
|
||||||
--code-bg-rgb: 30, 30, 30;
|
|
||||||
--preview-header-bg: #252526;
|
|
||||||
--preview-header-bg-rgb: 37, 37, 38;
|
|
||||||
--grid-color-1: rgba(255, 255, 255, 0.08);
|
|
||||||
--grid-color-2: rgba(255, 255, 255, 0.05);
|
|
||||||
--header-title-color: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 主题切换和语言切换的过渡效果 */
|
|
||||||
.theme-transition,
|
|
||||||
.theme-transition *,
|
|
||||||
.lang-transition,
|
|
||||||
.lang-transition * {
|
|
||||||
transition: all 0.3s ease !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes gridMove {
|
|
||||||
0% {
|
|
||||||
background-position: 0px 0px, 0px 0px, 0px 0px, 0px 0px;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-position: 80px 80px, 80px 80px, 20px 20px, 20px 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
background-image:
|
|
||||||
linear-gradient(var(--grid-color-1) 1px, transparent 1px),
|
|
||||||
linear-gradient(90deg, var(--grid-color-1) 1px, transparent 1px),
|
|
||||||
linear-gradient(var(--grid-color-2) 0.5px, transparent 0.5px),
|
|
||||||
linear-gradient(90deg, var(--grid-color-2) 0.5px, transparent 0.5px);
|
|
||||||
background-size: 80px 80px, 80px 80px, 20px 20px, 20px 20px;
|
|
||||||
background-position: center;
|
|
||||||
animation: gridMove 40s linear infinite;
|
|
||||||
font-family: 'Space Mono', monospace;
|
|
||||||
color: var(--text-color);
|
|
||||||
line-height: 1.6;
|
|
||||||
padding: 20px;
|
|
||||||
transition: background-color 0.3s ease, color 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 卡片容器 */
|
|
||||||
.card {
|
|
||||||
background-color: var(--card-bg);
|
|
||||||
background-image:
|
|
||||||
linear-gradient(var(--grid-color-1) 1px, transparent 1px),
|
|
||||||
linear-gradient(90deg, var(--grid-color-1) 1px, transparent 1px),
|
|
||||||
linear-gradient(var(--grid-color-2) 0.5px, transparent 0.5px),
|
|
||||||
linear-gradient(90deg, var(--grid-color-2) 0.5px, transparent 0.5px);
|
|
||||||
background-size: 80px 80px, 80px 80px, 20px 20px, 20px 20px;
|
|
||||||
background-position: center;
|
|
||||||
border: 4px solid var(--border-color);
|
|
||||||
box-shadow: 12px 12px 0 var(--shadow-color);
|
|
||||||
margin-bottom: 40px;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
||||||
position: relative;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:hover {
|
|
||||||
transform: translateY(-5px);
|
|
||||||
box-shadow: 16px 16px 0 var(--shadow-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 卡片头部 */
|
|
||||||
.card-header {
|
|
||||||
background-color: rgba(var(--primary-color-rgb), 0.9);
|
|
||||||
border-bottom: 4px solid var(--border-color);
|
|
||||||
padding: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-title {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0;
|
|
||||||
color: var(--header-title-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-controls {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 10px 20px;
|
|
||||||
background: var(--secondary-color);
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: bold;
|
|
||||||
border: 3px solid var(--border-color);
|
|
||||||
box-shadow: 4px 4px 0 var(--shadow-color);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: 'Space Mono', monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:hover {
|
|
||||||
background: var(--card-bg);
|
|
||||||
color: var(--primary-color);
|
|
||||||
border: 3px solid var(--primary-color);
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary {
|
|
||||||
background: var(--light-bg);
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary:hover {
|
|
||||||
background: var(--card-bg);
|
|
||||||
color: var(--primary-color);
|
|
||||||
border: 3px solid var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 卡片内容 */
|
|
||||||
.card-content {
|
|
||||||
padding: 30px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
background-color: rgba(var(--card-bg-rgb), 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Logo区域 */
|
|
||||||
.logo-container {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-frame {
|
|
||||||
width: 150px;
|
|
||||||
height: 150px;
|
|
||||||
background: var(--card-bg);
|
|
||||||
border: 4px solid var(--border-color);
|
|
||||||
margin: 0 auto;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-image {
|
|
||||||
width: 130px;
|
|
||||||
height: 130px;
|
|
||||||
object-fit: contain;
|
|
||||||
border: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-text {
|
|
||||||
font-size: 32px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tagline {
|
|
||||||
font-size: 16px;
|
|
||||||
margin: 10px 0 0;
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 介绍区域 */
|
|
||||||
.intro-box {
|
|
||||||
border: 2px dashed var(--border-color);
|
|
||||||
padding: 20px;
|
|
||||||
background-color: rgba(var(--light-bg-rgb), 0.7);
|
|
||||||
margin-bottom: 30px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.intro-text {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮组 */
|
|
||||||
.button-group {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 20px;
|
|
||||||
margin: 30px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 特性网格 */
|
|
||||||
.features-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
||||||
gap: 30px;
|
|
||||||
margin: 40px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 特性卡片 */
|
|
||||||
.feature-card {
|
|
||||||
background-color: rgba(var(--card-bg-rgb), 0.8);
|
|
||||||
border: 3px solid var(--border-color);
|
|
||||||
box-shadow: 5px 5px 0 var(--shadow-color);
|
|
||||||
padding: 20px;
|
|
||||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-card:hover {
|
|
||||||
transform: translateY(-3px);
|
|
||||||
box-shadow: 7px 7px 0 var(--shadow-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-icon {
|
|
||||||
font-size: 24px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-desc {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 预览区域 */
|
|
||||||
.preview-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 20px;
|
|
||||||
margin: 30px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.preview-container {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 预览窗口 */
|
|
||||||
.preview-window {
|
|
||||||
border: 3px solid var(--border-color);
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 10px;
|
|
||||||
flex: 1;
|
|
||||||
min-width: 300px;
|
|
||||||
background-color: rgba(var(--card-bg-rgb), 0.7);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
box-shadow: 5px 5px 0 var(--shadow-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 预览头部 */
|
|
||||||
.preview-header {
|
|
||||||
background-color: rgba(var(--preview-header-bg-rgb), 0.9);
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-controls {
|
|
||||||
display: flex;
|
|
||||||
gap: 6px;
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-btn {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 0.5px solid rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-btn:nth-child(1) {
|
|
||||||
background-color: #ff5f56;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-btn:nth-child(2) {
|
|
||||||
background-color: #ffbd2e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-btn:nth-child(3) {
|
|
||||||
background-color: #27c93f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-title {
|
|
||||||
font-size: 13px;
|
|
||||||
opacity: 0.8;
|
|
||||||
color: var(--text-color);
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 预览内容 */
|
|
||||||
.preview-content {
|
|
||||||
padding: 15px;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: auto;
|
|
||||||
background-color: rgba(var(--code-bg-rgb), 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 代码块容器 */
|
|
||||||
.code-block-wrapper {
|
|
||||||
background-color: rgba(var(--code-bg-rgb), 0.8);
|
|
||||||
border: 2px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 块头部 */
|
|
||||||
.block-header {
|
|
||||||
background-color: rgba(var(--light-bg-rgb), 0.8);
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-bottom: 2px solid var(--border-color);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-language {
|
|
||||||
color: rgba(128, 128, 128, 0.8);
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-language::before {
|
|
||||||
content: '';
|
|
||||||
display: inline-block;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin-right: 5px;
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23888'%3E%3Cpath d='M9.7,16.7L5.3,12.3C4.9,11.9 4.9,11.1 5.3,10.7C5.7,10.3 6.3,10.3 6.7,10.7L10.5,14.5L17.3,7.7C17.7,7.3 18.3,7.3 18.7,7.7C19.1,8.1 19.1,8.7 18.7,9.1L11.3,16.7C10.9,17.1 10.1,17.1 9.7,16.7Z'/%3E%3C/svg%3E");
|
|
||||||
background-size: contain;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code-block {
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 1.6;
|
|
||||||
margin: 0;
|
|
||||||
white-space: pre;
|
|
||||||
tab-size: 4;
|
|
||||||
-moz-tab-size: 4;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .code-block-wrapper {
|
|
||||||
border-color: rgba(255, 255, 255, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .block-header {
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
border-color: rgba(255, 255, 255, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .block-language {
|
|
||||||
color: rgba(255, 255, 255, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .block-language::before {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23aaa'%3E%3Cpath d='M9.7,16.7L5.3,12.3C4.9,11.9 4.9,11.1 5.3,10.7C5.7,10.3 6.3,10.3 6.7,10.7L10.5,14.5L17.3,7.7C17.7,7.3 18.3,7.3 18.7,7.7C19.1,8.1 19.1,8.7 18.7,9.1L11.3,16.7C10.9,17.1 10.1,17.1 9.7,16.7Z'/%3E%3C/svg%3E");
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .code-block {
|
|
||||||
color: #d4d4d4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 代码高亮 */
|
|
||||||
.theme-dark .keyword { color: #c586c0; }
|
|
||||||
.theme-dark .function { color: #dcdcaa; }
|
|
||||||
.theme-dark .variable { color: #9cdcfe; }
|
|
||||||
.theme-dark .string { color: #ce9178; }
|
|
||||||
.theme-dark .comment { color: #6a9955; }
|
|
||||||
.theme-dark .class { color: #4ec9b0; }
|
|
||||||
.theme-dark .parameter { color: #9cdcfe; }
|
|
||||||
.theme-dark .built-in { color: #4ec9b0; }
|
|
||||||
|
|
||||||
/* 浅色主题代码高亮 */
|
|
||||||
.keyword { color: #af00db; }
|
|
||||||
.function { color: #795e26; }
|
|
||||||
.variable { color: #001080; }
|
|
||||||
.string { color: #a31515; }
|
|
||||||
.comment { color: #008000; }
|
|
||||||
.class { color: #267f99; }
|
|
||||||
.parameter { color: #001080; }
|
|
||||||
.built-in { color: #267f99; }
|
|
||||||
|
|
||||||
.preview-image {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
display: block;
|
|
||||||
border: none;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .light-theme-img {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .dark-theme-img {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
body:not(.theme-dark) .dark-theme-img {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
body:not(.theme-dark) .light-theme-img {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 技术栈列表 */
|
|
||||||
.tech-list {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 技术栈列表 */
|
|
||||||
.tech-item {
|
|
||||||
padding: 15px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border: 2px solid var(--border-color);
|
|
||||||
background-color: rgba(var(--light-bg-rgb), 0.7);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-icon {
|
|
||||||
margin-right: 15px;
|
|
||||||
color: var(--secondary-color);
|
|
||||||
font-size: 20px;
|
|
||||||
width: 30px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-name {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-desc {
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 页脚 */
|
|
||||||
.footer {
|
|
||||||
border-top: 2px solid var(--border-color);
|
|
||||||
padding: 20px 0;
|
|
||||||
margin-top: 40px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
background-color: transparent;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-text {
|
|
||||||
margin: 0 0 15px 0;
|
|
||||||
font-size: 14px;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-links {
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-link {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: color 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-link:hover {
|
|
||||||
color: var(--primary-color);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式设计 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.button-group {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.features-grid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.card-header {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-controls {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-frame {
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-image {
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 针对移动设备的响应式优化 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
body {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 15px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-controls {
|
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-group {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 预览区域优化 */
|
|
||||||
.preview-content {
|
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code-block {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-word;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-header {
|
|
||||||
padding: 6px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 日志界面导航链接优化 */
|
|
||||||
.nav-links {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-links .btn {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
/* 特性卡片优化 */
|
|
||||||
.features-grid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 预览窗口优化 */
|
|
||||||
.preview-container {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-window {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 技术栈列表小屏幕优化 */
|
|
||||||
.tech-item {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-desc {
|
|
||||||
width: 100%;
|
|
||||||
padding-left: 40px; /* 图标宽度+右边距 */
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 日志界面资源列表项优化 */
|
|
||||||
.asset-item {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
padding: 15px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-name {
|
|
||||||
width: 100%;
|
|
||||||
word-break: break-all;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset-size {
|
|
||||||
order: 2;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.download-btn {
|
|
||||||
order: 3;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-top: 10px;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 页脚链接优化 */
|
|
||||||
.footer {
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-links {
|
|
||||||
margin-top: 15px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 49 KiB |
256
docs/index.html
@@ -1,256 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>voidraft - An elegant text snippet recording tool designed for developers.</title>
|
|
||||||
<meta name="description" content="voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
|
||||||
<meta name="keywords" content="text editor, code snippets, developer tools, syntax highlighting, code formatting, multi-language, voidraft">
|
|
||||||
<meta name="author" content="voidraft Team">
|
|
||||||
<meta name="robots" content="index, follow">
|
|
||||||
<link rel="canonical" href="https://landaiqing.github.io/voidraft/">
|
|
||||||
|
|
||||||
<!-- Internationalization / hreflang -->
|
|
||||||
<link rel="alternate" hreflang="en" href="https://landaiqing.github.io/voidraft/">
|
|
||||||
<link rel="alternate" hreflang="zh" href="https://landaiqing.github.io/voidraft/?lang=zh">
|
|
||||||
<link rel="alternate" hreflang="x-default" href="https://landaiqing.github.io/voidraft/">
|
|
||||||
|
|
||||||
<!-- Open Graph / Facebook -->
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
<meta property="og:url" content="https://landaiqing.github.io/voidraft/">
|
|
||||||
<meta property="og:title" content="voidraft - An elegant text snippet recording tool designed for developers">
|
|
||||||
<meta property="og:description" content="voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
|
||||||
<meta property="og:image" content="https://landaiqing.github.io/voidraft/img/screenshot-dark.png">
|
|
||||||
<meta property="og:site_name" content="voidraft">
|
|
||||||
|
|
||||||
<!-- Twitter -->
|
|
||||||
<meta property="twitter:card" content="summary_large_image">
|
|
||||||
<meta property="twitter:url" content="https://landaiqing.github.io/voidraft/">
|
|
||||||
<meta property="twitter:title" content="voidraft - An elegant text snippet recording tool designed for developers">
|
|
||||||
<meta property="twitter:description" content="voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.">
|
|
||||||
<meta property="twitter:image" content="https://landaiqing.github.io/voidraft/img/screenshot-dark.png">
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="./css/styles.css">
|
|
||||||
<link rel="icon" href="./img/favicon.ico" type="image/x-icon">
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
||||||
|
|
||||||
<!-- Structured Data -->
|
|
||||||
<script type="application/ld+json">
|
|
||||||
{
|
|
||||||
"@context": "https://schema.org",
|
|
||||||
"@type": "SoftwareApplication",
|
|
||||||
"name": "voidraft",
|
|
||||||
"description": "An elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.",
|
|
||||||
"url": "https://landaiqing.github.io/voidraft/",
|
|
||||||
"downloadUrl": "https://github.com/landaiqing/voidraft/releases",
|
|
||||||
"author": {
|
|
||||||
"@type": "Organization",
|
|
||||||
"name": "voidraft"
|
|
||||||
},
|
|
||||||
"operatingSystem": ["Windows", "macOS", "Linux"],
|
|
||||||
"applicationCategory": "DeveloperApplication",
|
|
||||||
"offers": {
|
|
||||||
"@type": "Offer",
|
|
||||||
"price": "0",
|
|
||||||
"priceCurrency": "USD"
|
|
||||||
},
|
|
||||||
"screenshot": "https://landaiqing.github.io/voidraft/img/screenshot-dark.png",
|
|
||||||
"softwareVersion": "Latest",
|
|
||||||
"programmingLanguage": ["Go", "TypeScript", "Vue.js"],
|
|
||||||
"codeRepository": "https://github.com/landaiqing/voidraft"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body class="theme-dark">
|
|
||||||
<div class="container">
|
|
||||||
<!-- 主卡片 -->
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h1 class="card-title">voidraft</h1>
|
|
||||||
<div class="card-controls">
|
|
||||||
<button id="theme-toggle" class="btn btn-secondary" title="切换主题">
|
|
||||||
<i class="fas fa-sun"></i> <span data-en="Theme" data-zh="主题">Theme</span>
|
|
||||||
</button>
|
|
||||||
<button id="lang-toggle" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-language"></i> 中/EN
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-content">
|
|
||||||
<!-- Logo和介绍 -->
|
|
||||||
<div class="logo-container">
|
|
||||||
<div class="logo-frame">
|
|
||||||
<img src="img/logo.png" alt="voidraft Logo" class="logo-image">
|
|
||||||
</div>
|
|
||||||
<h2 class="logo-text" data-en="voidraft" data-zh="voidraft">voidraft</h2>
|
|
||||||
<p class="tagline" data-en="An elegant text snippet recording tool" data-zh="优雅的文本片段记录工具">An elegant text snippet recording tool</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="intro-box">
|
|
||||||
<p class="intro-text" data-en="Designed for developers to record, organize, and manage various text snippets anytime, anywhere." data-zh="专为开发者打造,随时随地记录、整理和管理各种文本片段。">Designed for developers to record, organize, and manage various text snippets anytime, anywhere.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<a href="https://github.com/landaiqing/voidraft/releases" class="btn" data-en="Download" data-zh="下载">
|
|
||||||
<i class="fas fa-download"></i> Download
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/landaiqing/voidraft" class="btn btn-secondary" data-en="Source Code" data-zh="源代码">
|
|
||||||
<i class="fab fa-github"></i> Source Code
|
|
||||||
</a>
|
|
||||||
<a href="changelog.html" class="btn btn-secondary" data-en="Changelog" data-zh="更新日志">
|
|
||||||
<i class="fas fa-history"></i> Changelog
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 特性部分 -->
|
|
||||||
<h2 data-en="Core Features" data-zh="核心特性">Core Features</h2>
|
|
||||||
|
|
||||||
<div class="features-grid">
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">
|
|
||||||
<i class="fas fa-code"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="feature-title" data-en="Developer-Friendly" data-zh="开发者友好">Developer-Friendly</h3>
|
|
||||||
<p class="feature-desc" data-en="Multi-language code blocks with syntax highlighting for 30+ programming languages" data-zh="多语言代码块支持,为30+种编程语言提供语法高亮">Multi-language code blocks with syntax highlighting for 30+ programming languages</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">
|
|
||||||
<i class="fas fa-magic"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="feature-title" data-en="Code Formatting" data-zh="代码格式化">Code Formatting</h3>
|
|
||||||
<p class="feature-desc" data-en="Built-in Prettier support for one-click code beautification" data-zh="内置Prettier支持,一键美化代码">Built-in Prettier support for one-click code beautification</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">
|
|
||||||
<i class="fas fa-palette"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="feature-title" data-en="Custom Themes" data-zh="自定义主题">Custom Themes</h3>
|
|
||||||
<p class="feature-desc" data-en="Dark/Light themes with full customization options" data-zh="深色/浅色主题,支持完全自定义">Dark/Light themes with full customization options</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">
|
|
||||||
<i class="fas fa-clone"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="feature-title" data-en="Multi-Window" data-zh="多窗口支持">Multi-Window</h3>
|
|
||||||
<p class="feature-desc" data-en="Edit multiple documents simultaneously" data-zh="同时编辑多个文档">Edit multiple documents simultaneously</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">
|
|
||||||
<i class="fas fa-layer-group"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="feature-title" data-en="Block Editing" data-zh="块状编辑">Block Editing</h3>
|
|
||||||
<p class="feature-desc" data-en="Split content into independent code blocks with different language settings" data-zh="将内容分割为独立的代码块,每个块可设置不同语言">Split content into independent code blocks with different language settings</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">
|
|
||||||
<i class="fas fa-puzzle-piece"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="feature-title" data-en="Extensions" data-zh="丰富扩展">Extensions</h3>
|
|
||||||
<p class="feature-desc" data-en="Rainbow brackets, VSCode-style search, color picker, translation tool, and more" data-zh="彩虹括号、VSCode风格搜索、颜色选择器、翻译工具等多种扩展">Rainbow brackets, VSCode-style search, color picker, translation tool, and more</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 预览部分 -->
|
|
||||||
<h2 data-en="Preview" data-zh="预览">Preview</h2>
|
|
||||||
|
|
||||||
<div class="preview-container">
|
|
||||||
<div class="preview-window">
|
|
||||||
<div class="preview-header">
|
|
||||||
<div class="preview-controls">
|
|
||||||
<span class="preview-btn"></span>
|
|
||||||
<span class="preview-btn"></span>
|
|
||||||
<span class="preview-btn"></span>
|
|
||||||
</div>
|
|
||||||
<div class="preview-title">voidraft</div>
|
|
||||||
</div>
|
|
||||||
<div class="preview-content">
|
|
||||||
<div class="code-block-wrapper">
|
|
||||||
<div class="block-header">
|
|
||||||
<div class="block-language">javascript</div>
|
|
||||||
</div>
|
|
||||||
<pre class="code-block">
|
|
||||||
<span class="keyword">function</span> <span class="function">createDocument</span>() {
|
|
||||||
<span class="keyword">const</span> <span class="variable">doc</span> = <span class="keyword">new</span> <span class="class">Document</span>();
|
|
||||||
|
|
||||||
<span class="variable">doc</span>.<span class="function">addCodeBlock</span>(<span class="string">'javascript'</span>, <span class="string">`
|
|
||||||
<span class="keyword">function</span> <span class="function">greeting</span>(<span class="parameter">name</span>) {
|
|
||||||
<span class="keyword">return</span> <span class="string">`Hello, </span>${<span class="parameter">name</span>}<span class="string">!`</span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
<span class="built-in">console</span>.<span class="function">log</span>(<span class="function">greeting</span>(<span class="string">'World'</span>));
|
|
||||||
`</span>);
|
|
||||||
|
|
||||||
<span class="keyword">return</span> <span class="variable">doc</span>;
|
|
||||||
}</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="code-block-wrapper" style="margin-top: 10px;">
|
|
||||||
<div class="block-header">
|
|
||||||
<div class="block-language">text</div>
|
|
||||||
</div>
|
|
||||||
<pre class="code-block">
|
|
||||||
<span class="comment">// voidraft - An elegant text snippet recording tool</span>
|
|
||||||
<span class="comment">// Multi-language support | Code formatting | Custom themes</span>
|
|
||||||
<span class="comment">// A modern text editor designed for developers</span></pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="preview-window">
|
|
||||||
<img src="img/screenshot-dark.png" alt="voidraft 界面预览" class="preview-image dark-theme-img">
|
|
||||||
<img src="img/screenshot-light.png" alt="voidraft 界面预览" class="preview-image light-theme-img" style="display: none;">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 技术栈部分 -->
|
|
||||||
<h2 data-en="Technical Stack" data-zh="技术栈">Technical Stack</h2>
|
|
||||||
|
|
||||||
<ul class="tech-list">
|
|
||||||
<li class="tech-item">
|
|
||||||
<div class="tech-icon"><i class="fas fa-desktop"></i></div>
|
|
||||||
<span class="tech-name">Wails3</span>
|
|
||||||
<span class="tech-desc" data-en="Cross-platform desktop application framework" data-zh="跨平台桌面应用框架">Cross-platform desktop application framework</span>
|
|
||||||
</li>
|
|
||||||
<li class="tech-item">
|
|
||||||
<div class="tech-icon"><i class="fas fa-cogs"></i></div>
|
|
||||||
<span class="tech-name">Go 1.21+</span>
|
|
||||||
<span class="tech-desc" data-en="Fast and efficient backend language" data-zh="快速高效的后端语言">Fast and efficient backend language</span>
|
|
||||||
</li>
|
|
||||||
<li class="tech-item">
|
|
||||||
<div class="tech-icon"><i class="fab fa-vuejs"></i></div>
|
|
||||||
<span class="tech-name">Vue 3 + TypeScript</span>
|
|
||||||
<span class="tech-desc" data-en="Modern frontend framework" data-zh="现代化前端框架">Modern frontend framework</span>
|
|
||||||
</li>
|
|
||||||
<li class="tech-item">
|
|
||||||
<div class="tech-icon"><i class="fas fa-edit"></i></div>
|
|
||||||
<span class="tech-name">CodeMirror 6</span>
|
|
||||||
<span class="tech-desc" data-en="Modern code editor with extension support" data-zh="支持扩展的现代化代码编辑器">Modern code editor with extension support</span>
|
|
||||||
</li>
|
|
||||||
<li class="tech-item">
|
|
||||||
<div class="tech-icon"><i class="fas fa-database"></i></div>
|
|
||||||
<span class="tech-name">SQLite</span>
|
|
||||||
<span class="tech-desc" data-en="Lightweight database for document storage" data-zh="轻量级文档存储数据库">Lightweight database for document storage</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 页脚 -->
|
|
||||||
<footer class="footer">
|
|
||||||
<p class="footer-text" data-en="© 2025 voidraft - An elegant text snippet recording tool designed for developers" data-zh="© 2025 voidraft - 专为开发者打造的优雅文本片段记录工具">© 2025 voidraft - An elegant text snippet recording tool designed for developers</p>
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="https://github.com/landaiqing/voidraft" target="_blank" class="footer-link">GitHub</a>
|
|
||||||
<a href="https://github.com/landaiqing/voidraft/issues" target="_blank" class="footer-link" data-en="Issues" data-zh="问题反馈">Issues</a>
|
|
||||||
<a href="https://github.com/landaiqing/voidraft/releases" target="_blank" class="footer-link" data-en="Releases" data-zh="版本发布">Releases</a>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="js/script.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,705 +0,0 @@
|
|||||||
/**
|
|
||||||
* voidraft - Changelog Script
|
|
||||||
* 从GitHub API获取发布信息,支持Gitea备用源
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仓库配置类
|
|
||||||
*/
|
|
||||||
class RepositoryConfig {
|
|
||||||
constructor() {
|
|
||||||
this.repos = {
|
|
||||||
github: {
|
|
||||||
owner: 'landaiqing',
|
|
||||||
name: 'voidraft',
|
|
||||||
apiUrl: 'https://api.github.com/repos/landaiqing/voidraft/releases',
|
|
||||||
releasesUrl: 'https://github.com/landaiqing/voidraft/releases'
|
|
||||||
},
|
|
||||||
gitea: {
|
|
||||||
owner: 'landaiqing',
|
|
||||||
name: 'voidraft',
|
|
||||||
domain: 'git.landaiqing.cn',
|
|
||||||
apiUrl: 'https://git.landaiqing.cn/api/v1/repos/landaiqing/voidraft/releases',
|
|
||||||
releasesUrl: 'https://git.landaiqing.cn/landaiqing/voidraft/releases'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取仓库配置
|
|
||||||
* @param {string} source - 'github' 或 'gitea'
|
|
||||||
*/
|
|
||||||
getRepo(source) {
|
|
||||||
return this.repos[source];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有仓库配置
|
|
||||||
*/
|
|
||||||
getAllRepos() {
|
|
||||||
return this.repos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国际化消息管理类
|
|
||||||
*/
|
|
||||||
class I18nMessages {
|
|
||||||
constructor() {
|
|
||||||
this.messages = {
|
|
||||||
loading: {
|
|
||||||
en: 'Loading releases...',
|
|
||||||
zh: '正在加载版本信息...'
|
|
||||||
},
|
|
||||||
noReleases: {
|
|
||||||
en: 'No release information found',
|
|
||||||
zh: '没有找到版本发布信息'
|
|
||||||
},
|
|
||||||
fetchError: {
|
|
||||||
en: 'Failed to load release information. Please try again later.',
|
|
||||||
zh: '无法获取版本信息,请稍后再试'
|
|
||||||
},
|
|
||||||
githubApiError: {
|
|
||||||
en: 'GitHub API returned an error status: ',
|
|
||||||
zh: 'GitHub API返回错误状态: '
|
|
||||||
},
|
|
||||||
giteaApiError: {
|
|
||||||
en: 'Gitea API returned an error status: ',
|
|
||||||
zh: 'Gitea API返回错误状态: '
|
|
||||||
},
|
|
||||||
dataSource: {
|
|
||||||
en: 'Data source: ',
|
|
||||||
zh: '数据来源: '
|
|
||||||
},
|
|
||||||
downloads: {
|
|
||||||
en: 'Downloads',
|
|
||||||
zh: '下载资源'
|
|
||||||
},
|
|
||||||
download: {
|
|
||||||
en: 'Download',
|
|
||||||
zh: '下载'
|
|
||||||
},
|
|
||||||
preRelease: {
|
|
||||||
en: 'Pre-release',
|
|
||||||
zh: '预发布'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取消息
|
|
||||||
* @param {string} key - 消息键
|
|
||||||
* @param {string} lang - 语言代码
|
|
||||||
*/
|
|
||||||
getMessage(key, lang = 'en') {
|
|
||||||
return this.messages[key] && this.messages[key][lang] || this.messages[key]['en'] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前语言
|
|
||||||
*/
|
|
||||||
getCurrentLang() {
|
|
||||||
return window.currentLang || 'en';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* API客户端类
|
|
||||||
*/
|
|
||||||
class APIClient {
|
|
||||||
constructor(repositoryConfig, i18nMessages) {
|
|
||||||
this.repositoryConfig = repositoryConfig;
|
|
||||||
this.i18nMessages = i18nMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从指定源获取发布信息
|
|
||||||
* @param {string} source - 'github' 或 'gitea'
|
|
||||||
*/
|
|
||||||
async fetchReleases(source) {
|
|
||||||
const repo = this.repositoryConfig.getRepo(source);
|
|
||||||
const errorMessageKey = source === 'github' ? 'githubApiError' : 'giteaApiError';
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
headers: { 'Accept': 'application/json' }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (source === 'github') {
|
|
||||||
return this.fetchFromGitHub(repo, options, errorMessageKey);
|
|
||||||
} else {
|
|
||||||
return this.fetchFromGitea(repo, options, errorMessageKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从GitHub获取数据
|
|
||||||
* @param {Object} repo - 仓库配置
|
|
||||||
* @param {Object} options - 请求选项
|
|
||||||
* @param {string} errorMessageKey - 错误消息键
|
|
||||||
*/
|
|
||||||
async fetchFromGitHub(repo, options, errorMessageKey) {
|
|
||||||
const controller = new AbortController();
|
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
||||||
|
|
||||||
options.signal = controller.signal;
|
|
||||||
options.headers['Accept'] = 'application/vnd.github.v3+json';
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(repo.apiUrl, options);
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`${this.i18nMessages.getMessage(errorMessageKey, this.i18nMessages.getCurrentLang())}${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const releases = await response.json();
|
|
||||||
|
|
||||||
if (!releases || releases.length === 0) {
|
|
||||||
throw new Error(this.i18nMessages.getMessage('noReleases', this.i18nMessages.getCurrentLang()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return releases;
|
|
||||||
} catch (error) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从Gitea获取数据
|
|
||||||
* @param {Object} repo - 仓库配置
|
|
||||||
* @param {Object} options - 请求选项
|
|
||||||
* @param {string} errorMessageKey - 错误消息键
|
|
||||||
*/
|
|
||||||
async fetchFromGitea(repo, options, errorMessageKey) {
|
|
||||||
const response = await fetch(repo.apiUrl, options);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`${this.i18nMessages.getMessage(errorMessageKey, this.i18nMessages.getCurrentLang())}${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const releases = await response.json();
|
|
||||||
|
|
||||||
if (!releases || releases.length === 0) {
|
|
||||||
throw new Error(this.i18nMessages.getMessage('noReleases', this.i18nMessages.getCurrentLang()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return releases;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UI管理类
|
|
||||||
*/
|
|
||||||
class UIManager {
|
|
||||||
constructor(i18nMessages) {
|
|
||||||
this.i18nMessages = i18nMessages;
|
|
||||||
this.elements = {
|
|
||||||
loading: document.getElementById('loading'),
|
|
||||||
changelog: document.getElementById('changelog'),
|
|
||||||
error: document.getElementById('error-message')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示加载状态
|
|
||||||
*/
|
|
||||||
showLoading() {
|
|
||||||
this.elements.loading.style.display = 'block';
|
|
||||||
this.elements.error.style.display = 'none';
|
|
||||||
this.elements.changelog.innerHTML = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 隐藏加载状态
|
|
||||||
*/
|
|
||||||
hideLoading() {
|
|
||||||
this.elements.loading.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示错误消息
|
|
||||||
* @param {string} message - 错误消息
|
|
||||||
*/
|
|
||||||
showError(message) {
|
|
||||||
const errorMessageElement = this.elements.error.querySelector('p');
|
|
||||||
if (errorMessageElement) {
|
|
||||||
errorMessageElement.textContent = message;
|
|
||||||
} else {
|
|
||||||
this.elements.error.textContent = message;
|
|
||||||
}
|
|
||||||
this.elements.error.style.display = 'block';
|
|
||||||
this.hideLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示发布信息
|
|
||||||
* @param {Array} releases - 发布信息数组
|
|
||||||
* @param {string} source - 数据源
|
|
||||||
*/
|
|
||||||
displayReleases(releases, source) {
|
|
||||||
this.hideLoading();
|
|
||||||
|
|
||||||
// 清除现有内容
|
|
||||||
this.elements.changelog.innerHTML = '';
|
|
||||||
|
|
||||||
// 创建数据源元素
|
|
||||||
const sourceElement = this.createSourceElement(source);
|
|
||||||
this.elements.changelog.appendChild(sourceElement);
|
|
||||||
|
|
||||||
// 创建发布信息元素
|
|
||||||
releases.forEach(release => {
|
|
||||||
const releaseElement = this.createReleaseElement(release, source);
|
|
||||||
this.elements.changelog.appendChild(releaseElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.elements.changelog.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建数据源元素
|
|
||||||
* @param {string} source - 数据源
|
|
||||||
*/
|
|
||||||
createSourceElement(source) {
|
|
||||||
const sourceElement = document.createElement('div');
|
|
||||||
sourceElement.className = 'data-source';
|
|
||||||
|
|
||||||
// 创建带有国际化支持的源标签
|
|
||||||
const sourceLabel = document.createElement('span');
|
|
||||||
sourceLabel.setAttribute('data-en', this.i18nMessages.getMessage('dataSource', 'en'));
|
|
||||||
sourceLabel.setAttribute('data-zh', this.i18nMessages.getMessage('dataSource', 'zh'));
|
|
||||||
sourceLabel.textContent = this.i18nMessages.getMessage('dataSource', this.i18nMessages.getCurrentLang());
|
|
||||||
|
|
||||||
// 创建链接
|
|
||||||
const sourceLink = document.createElement('a');
|
|
||||||
const repositoryConfig = new RepositoryConfig();
|
|
||||||
sourceLink.href = repositoryConfig.getRepo(source).releasesUrl;
|
|
||||||
sourceLink.textContent = source === 'github' ? 'GitHub' : 'Gitea';
|
|
||||||
sourceLink.target = '_blank';
|
|
||||||
|
|
||||||
// 组装元素
|
|
||||||
sourceElement.appendChild(sourceLabel);
|
|
||||||
sourceElement.appendChild(sourceLink);
|
|
||||||
|
|
||||||
return sourceElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建发布信息元素
|
|
||||||
* @param {Object} release - 发布信息对象
|
|
||||||
* @param {string} source - 数据源
|
|
||||||
*/
|
|
||||||
createReleaseElement(release, source) {
|
|
||||||
const releaseElement = document.createElement('div');
|
|
||||||
releaseElement.className = 'release';
|
|
||||||
|
|
||||||
// 格式化发布日期
|
|
||||||
const releaseDate = new Date(release.published_at || release.created_at);
|
|
||||||
const formattedDate = DateFormatter.formatDate(releaseDate);
|
|
||||||
|
|
||||||
// 创建头部
|
|
||||||
const headerElement = this.createReleaseHeader(release, formattedDate);
|
|
||||||
releaseElement.appendChild(headerElement);
|
|
||||||
|
|
||||||
// 添加发布说明
|
|
||||||
if (release.body) {
|
|
||||||
const descriptionElement = document.createElement('div');
|
|
||||||
descriptionElement.className = 'release-description markdown-content';
|
|
||||||
descriptionElement.innerHTML = MarkdownParser.parseMarkdown(release.body);
|
|
||||||
releaseElement.appendChild(descriptionElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加下载资源
|
|
||||||
const assets = AssetManager.getAssetsFromRelease(release, source);
|
|
||||||
if (assets && assets.length > 0) {
|
|
||||||
const assetsElement = this.createAssetsElement(assets);
|
|
||||||
releaseElement.appendChild(assetsElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
return releaseElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建发布信息头部
|
|
||||||
*/
|
|
||||||
createReleaseHeader(release, formattedDate) {
|
|
||||||
const headerElement = document.createElement('div');
|
|
||||||
headerElement.className = 'release-header';
|
|
||||||
|
|
||||||
// 版本元素
|
|
||||||
const versionElement = document.createElement('div');
|
|
||||||
versionElement.className = 'release-version';
|
|
||||||
|
|
||||||
// 版本文本
|
|
||||||
const versionText = document.createElement('span');
|
|
||||||
versionText.textContent = release.name || release.tag_name;
|
|
||||||
versionElement.appendChild(versionText);
|
|
||||||
|
|
||||||
// 预发布标记
|
|
||||||
if (release.prerelease) {
|
|
||||||
const preReleaseTag = document.createElement('span');
|
|
||||||
preReleaseTag.className = 'release-badge pre-release';
|
|
||||||
preReleaseTag.setAttribute('data-en', this.i18nMessages.getMessage('preRelease', 'en'));
|
|
||||||
preReleaseTag.setAttribute('data-zh', this.i18nMessages.getMessage('preRelease', 'zh'));
|
|
||||||
preReleaseTag.textContent = this.i18nMessages.getMessage('preRelease', this.i18nMessages.getCurrentLang());
|
|
||||||
versionElement.appendChild(preReleaseTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 日期元素
|
|
||||||
const dateElement = document.createElement('div');
|
|
||||||
dateElement.className = 'release-date';
|
|
||||||
dateElement.textContent = formattedDate;
|
|
||||||
|
|
||||||
headerElement.appendChild(versionElement);
|
|
||||||
headerElement.appendChild(dateElement);
|
|
||||||
|
|
||||||
return headerElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建资源文件元素
|
|
||||||
* @param {Array} assets - 资源文件数组
|
|
||||||
*/
|
|
||||||
createAssetsElement(assets) {
|
|
||||||
const assetsElement = document.createElement('div');
|
|
||||||
assetsElement.className = 'release-assets';
|
|
||||||
|
|
||||||
// 资源标题
|
|
||||||
const assetsTitle = document.createElement('div');
|
|
||||||
assetsTitle.className = 'release-assets-title';
|
|
||||||
assetsTitle.setAttribute('data-en', this.i18nMessages.getMessage('downloads', 'en'));
|
|
||||||
assetsTitle.setAttribute('data-zh', this.i18nMessages.getMessage('downloads', 'zh'));
|
|
||||||
assetsTitle.textContent = this.i18nMessages.getMessage('downloads', this.i18nMessages.getCurrentLang());
|
|
||||||
|
|
||||||
// 资源列表
|
|
||||||
const assetList = document.createElement('ul');
|
|
||||||
assetList.className = 'asset-list';
|
|
||||||
|
|
||||||
// 添加每个资源
|
|
||||||
assets.forEach(asset => {
|
|
||||||
const assetItem = this.createAssetItem(asset);
|
|
||||||
assetList.appendChild(assetItem);
|
|
||||||
});
|
|
||||||
|
|
||||||
assetsElement.appendChild(assetsTitle);
|
|
||||||
assetsElement.appendChild(assetList);
|
|
||||||
|
|
||||||
return assetsElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建资源文件项
|
|
||||||
* @param {Object} asset - 资源文件对象
|
|
||||||
*/
|
|
||||||
createAssetItem(asset) {
|
|
||||||
const assetItem = document.createElement('li');
|
|
||||||
assetItem.className = 'asset-item';
|
|
||||||
|
|
||||||
// 文件图标
|
|
||||||
const iconElement = document.createElement('i');
|
|
||||||
iconElement.className = `asset-icon fas fa-${FileIconHelper.getFileIcon(asset.name)}`;
|
|
||||||
|
|
||||||
// 文件名
|
|
||||||
const nameElement = document.createElement('span');
|
|
||||||
nameElement.className = 'asset-name';
|
|
||||||
nameElement.textContent = asset.name;
|
|
||||||
|
|
||||||
// 文件大小
|
|
||||||
const sizeElement = document.createElement('span');
|
|
||||||
sizeElement.className = 'asset-size';
|
|
||||||
sizeElement.textContent = FileSizeFormatter.formatFileSize(asset.size);
|
|
||||||
|
|
||||||
// 下载链接
|
|
||||||
const downloadLink = document.createElement('a');
|
|
||||||
downloadLink.className = 'download-btn';
|
|
||||||
downloadLink.href = asset.browser_download_url;
|
|
||||||
downloadLink.target = '_blank';
|
|
||||||
downloadLink.setAttribute('data-en', this.i18nMessages.getMessage('download', 'en'));
|
|
||||||
downloadLink.setAttribute('data-zh', this.i18nMessages.getMessage('download', 'zh'));
|
|
||||||
downloadLink.textContent = this.i18nMessages.getMessage('download', this.i18nMessages.getCurrentLang());
|
|
||||||
|
|
||||||
// 组装资源项
|
|
||||||
assetItem.appendChild(iconElement);
|
|
||||||
assetItem.appendChild(nameElement);
|
|
||||||
assetItem.appendChild(sizeElement);
|
|
||||||
assetItem.appendChild(downloadLink);
|
|
||||||
|
|
||||||
return assetItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 资源管理器类
|
|
||||||
*/
|
|
||||||
class AssetManager {
|
|
||||||
/**
|
|
||||||
* 从发布信息中获取资源文件
|
|
||||||
* @param {Object} release - 发布信息对象
|
|
||||||
* @param {string} source - 数据源
|
|
||||||
*/
|
|
||||||
static getAssetsFromRelease(release, source) {
|
|
||||||
let assets = [];
|
|
||||||
|
|
||||||
if (source === 'github') {
|
|
||||||
assets = release.assets || [];
|
|
||||||
} else { // Gitea
|
|
||||||
assets = release.assets || [];
|
|
||||||
// 检查Gitea特定的资源结构
|
|
||||||
if (!assets.length && release.attachments) {
|
|
||||||
assets = release.attachments.map(attachment => ({
|
|
||||||
name: attachment.name,
|
|
||||||
size: attachment.size,
|
|
||||||
browser_download_url: attachment.browser_download_url
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return assets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件图标助手类
|
|
||||||
*/
|
|
||||||
class FileIconHelper {
|
|
||||||
/**
|
|
||||||
* 根据文件扩展名获取图标
|
|
||||||
* @param {string} filename - 文件名
|
|
||||||
*/
|
|
||||||
static getFileIcon(filename) {
|
|
||||||
const extension = filename.split('.').pop().toLowerCase();
|
|
||||||
|
|
||||||
const iconMap = {
|
|
||||||
'exe': 'download',
|
|
||||||
'msi': 'download',
|
|
||||||
'dmg': 'download',
|
|
||||||
'pkg': 'download',
|
|
||||||
'deb': 'download',
|
|
||||||
'rpm': 'download',
|
|
||||||
'tar': 'file-archive',
|
|
||||||
'gz': 'file-archive',
|
|
||||||
'zip': 'file-archive',
|
|
||||||
'7z': 'file-archive',
|
|
||||||
'rar': 'file-archive',
|
|
||||||
'pdf': 'file-pdf',
|
|
||||||
'txt': 'file-alt',
|
|
||||||
'md': 'file-alt',
|
|
||||||
'json': 'file-code',
|
|
||||||
'xml': 'file-code',
|
|
||||||
'yml': 'file-code',
|
|
||||||
'yaml': 'file-code'
|
|
||||||
};
|
|
||||||
|
|
||||||
return iconMap[extension] || 'file';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件大小格式化器类
|
|
||||||
*/
|
|
||||||
class FileSizeFormatter {
|
|
||||||
/**
|
|
||||||
* 格式化文件大小
|
|
||||||
* @param {number} bytes - 字节数
|
|
||||||
*/
|
|
||||||
static formatFileSize(bytes) {
|
|
||||||
if (!bytes) return '';
|
|
||||||
|
|
||||||
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
||||||
|
|
||||||
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日期格式化器类
|
|
||||||
*/
|
|
||||||
class DateFormatter {
|
|
||||||
/**
|
|
||||||
* 格式化日期
|
|
||||||
* @param {Date} date - 日期对象
|
|
||||||
*/
|
|
||||||
static formatDate(date) {
|
|
||||||
const options = {
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
day: 'numeric'
|
|
||||||
};
|
|
||||||
|
|
||||||
const lang = window.currentLang || 'en';
|
|
||||||
const locale = lang === 'zh' ? 'zh-CN' : 'en-US';
|
|
||||||
|
|
||||||
return date.toLocaleDateString(locale, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Markdown解析器类
|
|
||||||
*/
|
|
||||||
class MarkdownParser {
|
|
||||||
/**
|
|
||||||
* 简单的Markdown解析
|
|
||||||
* @param {string} markdown - Markdown文本
|
|
||||||
*/
|
|
||||||
static parseMarkdown(markdown) {
|
|
||||||
if (!markdown) return '';
|
|
||||||
|
|
||||||
// 预处理:保留原始换行符,用特殊标记替换
|
|
||||||
const preservedLineBreaks = '___LINE_BREAK___';
|
|
||||||
markdown = markdown.replace(/\n/g, preservedLineBreaks);
|
|
||||||
|
|
||||||
// 引用块 - > text
|
|
||||||
markdown = markdown.replace(/>\s*(.*?)(?=>|$)/g, '<blockquote>$1</blockquote>');
|
|
||||||
markdown = markdown.replace(/>\s*(.*?)(?=>|$)/g, '<blockquote>$1</blockquote>');
|
|
||||||
|
|
||||||
// 链接 - [text](url)
|
|
||||||
markdown = markdown.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>');
|
|
||||||
|
|
||||||
// 标题 - # Heading
|
|
||||||
markdown = markdown.replace(/^### (.*?)(?=___LINE_BREAK___|$)/gm, '<h3>$1</h3>');
|
|
||||||
markdown = markdown.replace(/^## (.*?)(?=___LINE_BREAK___|$)/gm, '<h2>$1</h2>');
|
|
||||||
markdown = markdown.replace(/^# (.*?)(?=___LINE_BREAK___|$)/gm, '<h1>$1</h1>');
|
|
||||||
|
|
||||||
// 粗体 - **text**
|
|
||||||
markdown = markdown.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
|
||||||
|
|
||||||
// 斜体 - *text*
|
|
||||||
markdown = markdown.replace(/\*(.*?)\*/g, '<em>$1</em>');
|
|
||||||
|
|
||||||
// 代码块 - ```code```
|
|
||||||
markdown = markdown.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
|
|
||||||
|
|
||||||
// 行内代码 - `code`
|
|
||||||
markdown = markdown.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
||||||
|
|
||||||
// 处理列表项
|
|
||||||
// 先将每个列表项转换为HTML
|
|
||||||
markdown = markdown.replace(/- (.*?)(?=___LINE_BREAK___- |___LINE_BREAK___$|$)/g, '<li>$1</li>');
|
|
||||||
markdown = markdown.replace(/\* (.*?)(?=___LINE_BREAK___\* |___LINE_BREAK___$|$)/g, '<li>$1</li>');
|
|
||||||
markdown = markdown.replace(/\d+\. (.*?)(?=___LINE_BREAK___\d+\. |___LINE_BREAK___$|$)/g, '<li>$1</li>');
|
|
||||||
|
|
||||||
// 然后将连续的列表项包装在ul或ol中
|
|
||||||
const listItemRegex = /<li>.*?<\/li>/g;
|
|
||||||
const listItems = markdown.match(listItemRegex) || [];
|
|
||||||
|
|
||||||
if (listItems.length > 0) {
|
|
||||||
// 将连续的列表项组合在一起
|
|
||||||
let lastIndex = 0;
|
|
||||||
let result = '';
|
|
||||||
let inList = false;
|
|
||||||
|
|
||||||
listItems.forEach(item => {
|
|
||||||
const itemIndex = markdown.indexOf(item, lastIndex);
|
|
||||||
|
|
||||||
// 添加列表项之前的内容
|
|
||||||
if (itemIndex > lastIndex) {
|
|
||||||
result += markdown.substring(lastIndex, itemIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果不在列表中,开始一个新列表
|
|
||||||
if (!inList) {
|
|
||||||
result += '<ul>';
|
|
||||||
inList = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加列表项
|
|
||||||
result += item;
|
|
||||||
|
|
||||||
// 更新lastIndex
|
|
||||||
lastIndex = itemIndex + item.length;
|
|
||||||
|
|
||||||
// 检查下一个内容是否是列表项
|
|
||||||
const nextItemIndex = markdown.indexOf('<li>', lastIndex);
|
|
||||||
if (nextItemIndex === -1 || nextItemIndex > lastIndex + 20) { // 如果下一个列表项不紧邻
|
|
||||||
result += '</ul>';
|
|
||||||
inList = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 添加剩余内容
|
|
||||||
if (lastIndex < markdown.length) {
|
|
||||||
result += markdown.substring(lastIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
markdown = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理水平分隔线
|
|
||||||
markdown = markdown.replace(/---/g, '<hr>');
|
|
||||||
|
|
||||||
// 恢复换行符
|
|
||||||
markdown = markdown.replace(/___LINE_BREAK___/g, '<br>');
|
|
||||||
|
|
||||||
// 处理段落
|
|
||||||
markdown = markdown.replace(/<br><br>/g, '</p><p>');
|
|
||||||
|
|
||||||
// 包装在段落标签中
|
|
||||||
if (!markdown.startsWith('<p>')) {
|
|
||||||
markdown = `<p>${markdown}</p>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return markdown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新日志主应用类
|
|
||||||
*/
|
|
||||||
class ChangelogApp {
|
|
||||||
constructor() {
|
|
||||||
this.repositoryConfig = new RepositoryConfig();
|
|
||||||
this.i18nMessages = new I18nMessages();
|
|
||||||
this.apiClient = new APIClient(this.repositoryConfig, this.i18nMessages);
|
|
||||||
this.uiManager = new UIManager(this.i18nMessages);
|
|
||||||
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化应用
|
|
||||||
*/
|
|
||||||
init() {
|
|
||||||
this.uiManager.showLoading();
|
|
||||||
|
|
||||||
// 首先尝试GitHub API
|
|
||||||
this.apiClient.fetchReleases('github')
|
|
||||||
.then(releases => {
|
|
||||||
this.uiManager.displayReleases(releases, 'github');
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
// GitHub失败时尝试Gitea
|
|
||||||
return this.apiClient.fetchReleases('gitea')
|
|
||||||
.then(releases => {
|
|
||||||
this.uiManager.displayReleases(releases, 'gitea');
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('获取发布信息失败:', error);
|
|
||||||
this.uiManager.showError(this.i18nMessages.getMessage('fetchError', this.i18nMessages.getCurrentLang()));
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听语言变化事件
|
|
||||||
document.addEventListener('languageChanged', () => this.updateUI());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新UI元素(当语言变化时)
|
|
||||||
*/
|
|
||||||
updateUI() {
|
|
||||||
const elementsToUpdate = document.querySelectorAll('[data-en][data-zh]');
|
|
||||||
const currentLang = this.i18nMessages.getCurrentLang();
|
|
||||||
|
|
||||||
elementsToUpdate.forEach(element => {
|
|
||||||
const text = element.getAttribute(`data-${currentLang}`);
|
|
||||||
if (text) {
|
|
||||||
element.textContent = text;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当DOM加载完成时初始化应用
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
new ChangelogApp();
|
|
||||||
});
|
|
||||||
@@ -1,443 +0,0 @@
|
|||||||
/**
|
|
||||||
* voidraft - Website Script
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主题管理类
|
|
||||||
*/
|
|
||||||
class ThemeManager {
|
|
||||||
constructor() {
|
|
||||||
this.themeToggle = document.getElementById('theme-toggle');
|
|
||||||
this.currentTheme = this.getInitialTheme();
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取初始主题
|
|
||||||
*/
|
|
||||||
getInitialTheme() {
|
|
||||||
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
||||||
const savedTheme = localStorage.getItem('theme');
|
|
||||||
return savedTheme || (prefersDarkScheme.matches ? 'dark' : 'light');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化主题管理器
|
|
||||||
*/
|
|
||||||
init() {
|
|
||||||
if (!this.themeToggle) return;
|
|
||||||
|
|
||||||
this.setTheme(this.currentTheme);
|
|
||||||
this.bindEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 绑定事件
|
|
||||||
*/
|
|
||||||
bindEvents() {
|
|
||||||
this.themeToggle.addEventListener('click', () => {
|
|
||||||
this.toggleTheme();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 切换主题
|
|
||||||
*/
|
|
||||||
toggleTheme() {
|
|
||||||
document.body.classList.add('theme-transition');
|
|
||||||
|
|
||||||
const newTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
|
|
||||||
this.setTheme(newTheme);
|
|
||||||
this.saveTheme(newTheme);
|
|
||||||
|
|
||||||
setTimeout(() => document.body.classList.remove('theme-transition'), 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置主题
|
|
||||||
* @param {string} theme - 'dark' 或 'light'
|
|
||||||
*/
|
|
||||||
setTheme(theme) {
|
|
||||||
this.currentTheme = theme;
|
|
||||||
const isDark = theme === 'dark';
|
|
||||||
|
|
||||||
document.body.classList.toggle('theme-dark', isDark);
|
|
||||||
document.body.classList.toggle('theme-light', !isDark);
|
|
||||||
|
|
||||||
this.updateToggleIcon(isDark);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新切换按钮图标
|
|
||||||
* @param {boolean} isDark - 是否为暗色主题
|
|
||||||
*/
|
|
||||||
updateToggleIcon(isDark) {
|
|
||||||
if (this.themeToggle) {
|
|
||||||
const icon = this.themeToggle.querySelector('i');
|
|
||||||
if (icon) {
|
|
||||||
icon.className = isDark ? 'fas fa-sun' : 'fas fa-moon';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存主题到本地存储
|
|
||||||
* @param {string} theme - 主题名称
|
|
||||||
*/
|
|
||||||
saveTheme(theme) {
|
|
||||||
localStorage.setItem('theme', theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 语言管理类
|
|
||||||
*/
|
|
||||||
class LanguageManager {
|
|
||||||
constructor() {
|
|
||||||
this.langToggle = document.getElementById('lang-toggle');
|
|
||||||
this.currentLang = this.getInitialLanguage();
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取初始语言
|
|
||||||
*/
|
|
||||||
getInitialLanguage() {
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
const urlLang = urlParams.get('lang');
|
|
||||||
const savedLang = localStorage.getItem('lang');
|
|
||||||
const browserLang = navigator.language.startsWith('zh') ? 'zh' : 'en';
|
|
||||||
return urlLang || savedLang || browserLang;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化语言管理器
|
|
||||||
*/
|
|
||||||
init() {
|
|
||||||
if (!this.langToggle) return;
|
|
||||||
|
|
||||||
window.currentLang = this.currentLang;
|
|
||||||
this.setLanguage(this.currentLang);
|
|
||||||
this.bindEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 绑定事件
|
|
||||||
*/
|
|
||||||
bindEvents() {
|
|
||||||
this.langToggle.addEventListener('click', () => {
|
|
||||||
this.toggleLanguage();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 切换语言
|
|
||||||
*/
|
|
||||||
toggleLanguage() {
|
|
||||||
document.body.classList.add('lang-transition');
|
|
||||||
|
|
||||||
const newLang = this.currentLang === 'zh' ? 'en' : 'zh';
|
|
||||||
this.setLanguage(newLang);
|
|
||||||
this.saveLanguage(newLang);
|
|
||||||
this.updateURL(newLang);
|
|
||||||
this.notifyLanguageChange(newLang);
|
|
||||||
|
|
||||||
setTimeout(() => document.body.classList.remove('lang-transition'), 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置页面语言
|
|
||||||
* @param {string} lang - 'zh' 或 'en'
|
|
||||||
*/
|
|
||||||
setLanguage(lang) {
|
|
||||||
this.currentLang = lang;
|
|
||||||
window.currentLang = lang;
|
|
||||||
|
|
||||||
this.updatePageElements(lang);
|
|
||||||
this.updateHTMLLang(lang);
|
|
||||||
this.updateToggleButton(lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新页面元素文本
|
|
||||||
* @param {string} lang - 语言代码
|
|
||||||
*/
|
|
||||||
updatePageElements(lang) {
|
|
||||||
document.querySelectorAll('[data-zh][data-en]').forEach(el => {
|
|
||||||
el.textContent = el.getAttribute(`data-${lang}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新HTML语言属性
|
|
||||||
* @param {string} lang - 语言代码
|
|
||||||
*/
|
|
||||||
updateHTMLLang(lang) {
|
|
||||||
document.documentElement.lang = lang === 'zh' ? 'zh-CN' : 'en';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新切换按钮文本
|
|
||||||
* @param {string} lang - 语言代码
|
|
||||||
*/
|
|
||||||
updateToggleButton(lang) {
|
|
||||||
if (this.langToggle) {
|
|
||||||
const text = lang === 'zh' ? 'EN/中' : '中/EN';
|
|
||||||
this.langToggle.innerHTML = `<i class="fas fa-language"></i> ${text}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存语言到本地存储
|
|
||||||
* @param {string} lang - 语言代码
|
|
||||||
*/
|
|
||||||
saveLanguage(lang) {
|
|
||||||
localStorage.setItem('lang', lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新URL参数
|
|
||||||
* @param {string} lang - 语言代码
|
|
||||||
*/
|
|
||||||
updateURL(lang) {
|
|
||||||
const newUrl = new URL(window.location);
|
|
||||||
if (lang === 'zh') {
|
|
||||||
newUrl.searchParams.set('lang', 'zh');
|
|
||||||
} else {
|
|
||||||
newUrl.searchParams.delete('lang');
|
|
||||||
}
|
|
||||||
window.history.replaceState({}, '', newUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通知语言变更
|
|
||||||
* @param {string} lang - 语言代码
|
|
||||||
*/
|
|
||||||
notifyLanguageChange(lang) {
|
|
||||||
window.dispatchEvent(new CustomEvent('languageChanged', { detail: { lang } }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前语言
|
|
||||||
*/
|
|
||||||
getCurrentLanguage() {
|
|
||||||
return this.currentLang;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SEO管理类
|
|
||||||
*/
|
|
||||||
class SEOManager {
|
|
||||||
constructor(languageManager) {
|
|
||||||
this.languageManager = languageManager;
|
|
||||||
this.metaTexts = {
|
|
||||||
en: {
|
|
||||||
description: 'voidraft is an elegant text snippet recording tool designed for developers. Features multi-language code blocks, syntax highlighting, code formatting, custom themes, and more.',
|
|
||||||
title: 'voidraft - An elegant text snippet recording tool designed for developers.',
|
|
||||||
ogTitle: 'voidraft - An elegant text snippet recording tool designed for developers'
|
|
||||||
},
|
|
||||||
zh: {
|
|
||||||
description: 'voidraft 是专为开发者打造的优雅文本片段记录工具。支持多语言代码块、语法高亮、代码格式化、自定义主题等功能。',
|
|
||||||
title: 'voidraft - 专为开发者打造的优雅文本片段记录工具',
|
|
||||||
ogTitle: 'voidraft - 专为开发者打造的优雅文本片段记录工具'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化SEO管理器
|
|
||||||
*/
|
|
||||||
init() {
|
|
||||||
this.bindEvents();
|
|
||||||
this.updateMetaTags(this.languageManager.getCurrentLanguage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 绑定事件
|
|
||||||
*/
|
|
||||||
bindEvents() {
|
|
||||||
window.addEventListener('languageChanged', (event) => {
|
|
||||||
this.updateMetaTags(event.detail.lang);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新SEO元标签
|
|
||||||
* @param {string} lang - 当前语言
|
|
||||||
*/
|
|
||||||
updateMetaTags(lang) {
|
|
||||||
const texts = this.metaTexts[lang];
|
|
||||||
|
|
||||||
this.updateMetaDescription(texts.description);
|
|
||||||
this.updateOpenGraphTags(texts.ogTitle, texts.description);
|
|
||||||
this.updateTwitterCardTags(texts.ogTitle, texts.description);
|
|
||||||
this.updatePageTitle(texts.title);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新meta描述
|
|
||||||
* @param {string} description - 描述文本
|
|
||||||
*/
|
|
||||||
updateMetaDescription(description) {
|
|
||||||
const metaDesc = document.querySelector('meta[name="description"]');
|
|
||||||
if (metaDesc) {
|
|
||||||
metaDesc.content = description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新Open Graph标签
|
|
||||||
* @param {string} title - 标题
|
|
||||||
* @param {string} description - 描述
|
|
||||||
*/
|
|
||||||
updateOpenGraphTags(title, description) {
|
|
||||||
const ogTitle = document.querySelector('meta[property="og:title"]');
|
|
||||||
const ogDesc = document.querySelector('meta[property="og:description"]');
|
|
||||||
|
|
||||||
if (ogTitle) ogTitle.content = title;
|
|
||||||
if (ogDesc) ogDesc.content = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新Twitter Card标签
|
|
||||||
* @param {string} title - 标题
|
|
||||||
* @param {string} description - 描述
|
|
||||||
*/
|
|
||||||
updateTwitterCardTags(title, description) {
|
|
||||||
const twitterTitle = document.querySelector('meta[property="twitter:title"]');
|
|
||||||
const twitterDesc = document.querySelector('meta[property="twitter:description"]');
|
|
||||||
|
|
||||||
if (twitterTitle) twitterTitle.content = title;
|
|
||||||
if (twitterDesc) twitterDesc.content = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新页面标题
|
|
||||||
* @param {string} title - 标题
|
|
||||||
*/
|
|
||||||
updatePageTitle(title) {
|
|
||||||
document.title = title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UI效果管理类
|
|
||||||
*/
|
|
||||||
class UIEffects {
|
|
||||||
constructor() {
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化UI效果
|
|
||||||
*/
|
|
||||||
init() {
|
|
||||||
this.initCardEffects();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化卡片悬停效果
|
|
||||||
*/
|
|
||||||
initCardEffects() {
|
|
||||||
const cards = document.querySelectorAll('.feature-card');
|
|
||||||
|
|
||||||
cards.forEach(card => {
|
|
||||||
card.addEventListener('mouseenter', () => {
|
|
||||||
this.animateCardHover(card, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
card.addEventListener('mouseleave', () => {
|
|
||||||
this.animateCardHover(card, false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片悬停动画
|
|
||||||
* @param {Element} card - 卡片元素
|
|
||||||
* @param {boolean} isHover - 是否悬停
|
|
||||||
*/
|
|
||||||
animateCardHover(card, isHover) {
|
|
||||||
if (isHover) {
|
|
||||||
card.style.transform = 'translateY(-8px)';
|
|
||||||
card.style.boxShadow = '7px 7px 0 var(--shadow-color)';
|
|
||||||
} else {
|
|
||||||
card.style.transform = 'translateY(0)';
|
|
||||||
card.style.boxShadow = '5px 5px 0 var(--shadow-color)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* voidraft主应用类
|
|
||||||
*/
|
|
||||||
class voidraftApp {
|
|
||||||
constructor() {
|
|
||||||
this.themeManager = null;
|
|
||||||
this.languageManager = null;
|
|
||||||
this.seoManager = null;
|
|
||||||
this.uiEffects = null;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化应用
|
|
||||||
*/
|
|
||||||
init() {
|
|
||||||
this.initializeManagers();
|
|
||||||
this.showConsoleBranding();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化各个管理器
|
|
||||||
*/
|
|
||||||
initializeManagers() {
|
|
||||||
this.themeManager = new ThemeManager();
|
|
||||||
this.languageManager = new LanguageManager();
|
|
||||||
this.seoManager = new SEOManager(this.languageManager);
|
|
||||||
this.uiEffects = new UIEffects();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示控制台品牌信息
|
|
||||||
*/
|
|
||||||
showConsoleBranding() {
|
|
||||||
console.log('%c voidraft', 'color: #ff006e; font-size: 20px; font-family: "Space Mono", monospace;');
|
|
||||||
console.log('%c An elegant text snippet recording tool designed for developers.', 'color: #073B4C; font-family: "Space Mono", monospace;');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取主题管理器
|
|
||||||
*/
|
|
||||||
getThemeManager() {
|
|
||||||
return this.themeManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取语言管理器
|
|
||||||
*/
|
|
||||||
getLanguageManager() {
|
|
||||||
return this.languageManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取SEO管理器
|
|
||||||
*/
|
|
||||||
getSEOManager() {
|
|
||||||
return this.seoManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取UI效果管理器
|
|
||||||
*/
|
|
||||||
getUIEffects() {
|
|
||||||
return this.uiEffects;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当DOM加载完成时初始化应用
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
window.voidRaftApp = new voidraftApp();
|
|
||||||
});
|
|
||||||
@@ -5,303 +5,6 @@
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import {Create as $Create} from "@wailsio/runtime";
|
import {Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore: Unused imports
|
|
||||||
import * as slog$0 from "../../../../../../log/slog/models.js";
|
|
||||||
|
|
||||||
export class App {
|
|
||||||
/**
|
|
||||||
* Manager pattern for organized API
|
|
||||||
*/
|
|
||||||
"Window": WindowManager | null;
|
|
||||||
"ContextMenu": ContextMenuManager | null;
|
|
||||||
"KeyBinding": KeyBindingManager | null;
|
|
||||||
"Browser": BrowserManager | null;
|
|
||||||
"Env": EnvironmentManager | null;
|
|
||||||
"Dialog": DialogManager | null;
|
|
||||||
"Event": EventManager | null;
|
|
||||||
"Menu": MenuManager | null;
|
|
||||||
"Screen": ScreenManager | null;
|
|
||||||
"Clipboard": ClipboardManager | null;
|
|
||||||
"SystemTray": SystemTrayManager | null;
|
|
||||||
"Logger": slog$0.Logger | null;
|
|
||||||
|
|
||||||
/** Creates a new App instance. */
|
|
||||||
constructor($$source: Partial<App> = {}) {
|
|
||||||
if (!("Window" in $$source)) {
|
|
||||||
this["Window"] = null;
|
|
||||||
}
|
|
||||||
if (!("ContextMenu" in $$source)) {
|
|
||||||
this["ContextMenu"] = null;
|
|
||||||
}
|
|
||||||
if (!("KeyBinding" in $$source)) {
|
|
||||||
this["KeyBinding"] = null;
|
|
||||||
}
|
|
||||||
if (!("Browser" in $$source)) {
|
|
||||||
this["Browser"] = null;
|
|
||||||
}
|
|
||||||
if (!("Env" in $$source)) {
|
|
||||||
this["Env"] = null;
|
|
||||||
}
|
|
||||||
if (!("Dialog" in $$source)) {
|
|
||||||
this["Dialog"] = null;
|
|
||||||
}
|
|
||||||
if (!("Event" in $$source)) {
|
|
||||||
this["Event"] = null;
|
|
||||||
}
|
|
||||||
if (!("Menu" in $$source)) {
|
|
||||||
this["Menu"] = null;
|
|
||||||
}
|
|
||||||
if (!("Screen" in $$source)) {
|
|
||||||
this["Screen"] = null;
|
|
||||||
}
|
|
||||||
if (!("Clipboard" in $$source)) {
|
|
||||||
this["Clipboard"] = null;
|
|
||||||
}
|
|
||||||
if (!("SystemTray" in $$source)) {
|
|
||||||
this["SystemTray"] = null;
|
|
||||||
}
|
|
||||||
if (!("Logger" in $$source)) {
|
|
||||||
this["Logger"] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new App instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): App {
|
|
||||||
const $$createField0_0 = $$createType1;
|
|
||||||
const $$createField1_0 = $$createType3;
|
|
||||||
const $$createField2_0 = $$createType5;
|
|
||||||
const $$createField3_0 = $$createType7;
|
|
||||||
const $$createField4_0 = $$createType9;
|
|
||||||
const $$createField5_0 = $$createType11;
|
|
||||||
const $$createField6_0 = $$createType13;
|
|
||||||
const $$createField7_0 = $$createType15;
|
|
||||||
const $$createField8_0 = $$createType17;
|
|
||||||
const $$createField9_0 = $$createType19;
|
|
||||||
const $$createField10_0 = $$createType21;
|
|
||||||
const $$createField11_0 = $$createType23;
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
if ("Window" in $$parsedSource) {
|
|
||||||
$$parsedSource["Window"] = $$createField0_0($$parsedSource["Window"]);
|
|
||||||
}
|
|
||||||
if ("ContextMenu" in $$parsedSource) {
|
|
||||||
$$parsedSource["ContextMenu"] = $$createField1_0($$parsedSource["ContextMenu"]);
|
|
||||||
}
|
|
||||||
if ("KeyBinding" in $$parsedSource) {
|
|
||||||
$$parsedSource["KeyBinding"] = $$createField2_0($$parsedSource["KeyBinding"]);
|
|
||||||
}
|
|
||||||
if ("Browser" in $$parsedSource) {
|
|
||||||
$$parsedSource["Browser"] = $$createField3_0($$parsedSource["Browser"]);
|
|
||||||
}
|
|
||||||
if ("Env" in $$parsedSource) {
|
|
||||||
$$parsedSource["Env"] = $$createField4_0($$parsedSource["Env"]);
|
|
||||||
}
|
|
||||||
if ("Dialog" in $$parsedSource) {
|
|
||||||
$$parsedSource["Dialog"] = $$createField5_0($$parsedSource["Dialog"]);
|
|
||||||
}
|
|
||||||
if ("Event" in $$parsedSource) {
|
|
||||||
$$parsedSource["Event"] = $$createField6_0($$parsedSource["Event"]);
|
|
||||||
}
|
|
||||||
if ("Menu" in $$parsedSource) {
|
|
||||||
$$parsedSource["Menu"] = $$createField7_0($$parsedSource["Menu"]);
|
|
||||||
}
|
|
||||||
if ("Screen" in $$parsedSource) {
|
|
||||||
$$parsedSource["Screen"] = $$createField8_0($$parsedSource["Screen"]);
|
|
||||||
}
|
|
||||||
if ("Clipboard" in $$parsedSource) {
|
|
||||||
$$parsedSource["Clipboard"] = $$createField9_0($$parsedSource["Clipboard"]);
|
|
||||||
}
|
|
||||||
if ("SystemTray" in $$parsedSource) {
|
|
||||||
$$parsedSource["SystemTray"] = $$createField10_0($$parsedSource["SystemTray"]);
|
|
||||||
}
|
|
||||||
if ("Logger" in $$parsedSource) {
|
|
||||||
$$parsedSource["Logger"] = $$createField11_0($$parsedSource["Logger"]);
|
|
||||||
}
|
|
||||||
return new App($$parsedSource as Partial<App>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BrowserManager manages browser-related operations
|
|
||||||
*/
|
|
||||||
export class BrowserManager {
|
|
||||||
|
|
||||||
/** Creates a new BrowserManager instance. */
|
|
||||||
constructor($$source: Partial<BrowserManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new BrowserManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): BrowserManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new BrowserManager($$parsedSource as Partial<BrowserManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ClipboardManager manages clipboard operations
|
|
||||||
*/
|
|
||||||
export class ClipboardManager {
|
|
||||||
|
|
||||||
/** Creates a new ClipboardManager instance. */
|
|
||||||
constructor($$source: Partial<ClipboardManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ClipboardManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): ClipboardManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new ClipboardManager($$parsedSource as Partial<ClipboardManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ContextMenuManager manages all context menu operations
|
|
||||||
*/
|
|
||||||
export class ContextMenuManager {
|
|
||||||
|
|
||||||
/** Creates a new ContextMenuManager instance. */
|
|
||||||
constructor($$source: Partial<ContextMenuManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ContextMenuManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): ContextMenuManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new ContextMenuManager($$parsedSource as Partial<ContextMenuManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DialogManager manages dialog-related operations
|
|
||||||
*/
|
|
||||||
export class DialogManager {
|
|
||||||
|
|
||||||
/** Creates a new DialogManager instance. */
|
|
||||||
constructor($$source: Partial<DialogManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new DialogManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): DialogManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new DialogManager($$parsedSource as Partial<DialogManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EnvironmentManager manages environment-related operations
|
|
||||||
*/
|
|
||||||
export class EnvironmentManager {
|
|
||||||
|
|
||||||
/** Creates a new EnvironmentManager instance. */
|
|
||||||
constructor($$source: Partial<EnvironmentManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new EnvironmentManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): EnvironmentManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new EnvironmentManager($$parsedSource as Partial<EnvironmentManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EventManager manages event-related operations
|
|
||||||
*/
|
|
||||||
export class EventManager {
|
|
||||||
|
|
||||||
/** Creates a new EventManager instance. */
|
|
||||||
constructor($$source: Partial<EventManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new EventManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): EventManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new EventManager($$parsedSource as Partial<EventManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KeyBindingManager manages all key binding operations
|
|
||||||
*/
|
|
||||||
export class KeyBindingManager {
|
|
||||||
|
|
||||||
/** Creates a new KeyBindingManager instance. */
|
|
||||||
constructor($$source: Partial<KeyBindingManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new KeyBindingManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): KeyBindingManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new KeyBindingManager($$parsedSource as Partial<KeyBindingManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MenuManager manages menu-related operations
|
|
||||||
*/
|
|
||||||
export class MenuManager {
|
|
||||||
|
|
||||||
/** Creates a new MenuManager instance. */
|
|
||||||
constructor($$source: Partial<MenuManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new MenuManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): MenuManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new MenuManager($$parsedSource as Partial<MenuManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ScreenManager {
|
|
||||||
|
|
||||||
/** Creates a new ScreenManager instance. */
|
|
||||||
constructor($$source: Partial<ScreenManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ScreenManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): ScreenManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new ScreenManager($$parsedSource as Partial<ScreenManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServiceOptions provides optional parameters for calls to [NewService].
|
* ServiceOptions provides optional parameters for calls to [NewService].
|
||||||
*/
|
*/
|
||||||
@@ -359,85 +62,4 @@ export class ServiceOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export type Window = any;
|
||||||
* SystemTrayManager manages system tray-related operations
|
|
||||||
*/
|
|
||||||
export class SystemTrayManager {
|
|
||||||
|
|
||||||
/** Creates a new SystemTrayManager instance. */
|
|
||||||
constructor($$source: Partial<SystemTrayManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new SystemTrayManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): SystemTrayManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new SystemTrayManager($$parsedSource as Partial<SystemTrayManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WebviewWindow {
|
|
||||||
|
|
||||||
/** Creates a new WebviewWindow instance. */
|
|
||||||
constructor($$source: Partial<WebviewWindow> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new WebviewWindow instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): WebviewWindow {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new WebviewWindow($$parsedSource as Partial<WebviewWindow>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WindowManager manages all window-related operations
|
|
||||||
*/
|
|
||||||
export class WindowManager {
|
|
||||||
|
|
||||||
/** Creates a new WindowManager instance. */
|
|
||||||
constructor($$source: Partial<WindowManager> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new WindowManager instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): WindowManager {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new WindowManager($$parsedSource as Partial<WindowManager>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private type creation functions
|
|
||||||
const $$createType0 = WindowManager.createFrom;
|
|
||||||
const $$createType1 = $Create.Nullable($$createType0);
|
|
||||||
const $$createType2 = ContextMenuManager.createFrom;
|
|
||||||
const $$createType3 = $Create.Nullable($$createType2);
|
|
||||||
const $$createType4 = KeyBindingManager.createFrom;
|
|
||||||
const $$createType5 = $Create.Nullable($$createType4);
|
|
||||||
const $$createType6 = BrowserManager.createFrom;
|
|
||||||
const $$createType7 = $Create.Nullable($$createType6);
|
|
||||||
const $$createType8 = EnvironmentManager.createFrom;
|
|
||||||
const $$createType9 = $Create.Nullable($$createType8);
|
|
||||||
const $$createType10 = DialogManager.createFrom;
|
|
||||||
const $$createType11 = $Create.Nullable($$createType10);
|
|
||||||
const $$createType12 = EventManager.createFrom;
|
|
||||||
const $$createType13 = $Create.Nullable($$createType12);
|
|
||||||
const $$createType14 = MenuManager.createFrom;
|
|
||||||
const $$createType15 = $Create.Nullable($$createType14);
|
|
||||||
const $$createType16 = ScreenManager.createFrom;
|
|
||||||
const $$createType17 = $Create.Nullable($$createType16);
|
|
||||||
const $$createType18 = ClipboardManager.createFrom;
|
|
||||||
const $$createType19 = $Create.Nullable($$createType18);
|
|
||||||
const $$createType20 = SystemTrayManager.createFrom;
|
|
||||||
const $$createType21 = $Create.Nullable($$createType20);
|
|
||||||
const $$createType22 = slog$0.Logger.createFrom;
|
|
||||||
const $$createType23 = $Create.Nullable($$createType22);
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service represents the notifications service
|
* Service represents the dock service
|
||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -18,11 +18,19 @@ import * as application$0 from "../../application/models.js";
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as $models from "./models.js";
|
import * as $models from "./models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HideAppIcon hides the app icon in the dock/taskbar.
|
||||||
|
*/
|
||||||
|
export function HideAppIcon(): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3413658144) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RemoveBadge removes the badge label from the application icon.
|
* RemoveBadge removes the badge label from the application icon.
|
||||||
*/
|
*/
|
||||||
export function RemoveBadge(): Promise<void> & { cancel(): void } {
|
export function RemoveBadge(): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(2374916939) as any;
|
let $resultPromise = $Call.ByID(2752757297) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +38,7 @@ export function RemoveBadge(): Promise<void> & { cancel(): void } {
|
|||||||
* ServiceName returns the name of the service.
|
* ServiceName returns the name of the service.
|
||||||
*/
|
*/
|
||||||
export function ServiceName(): Promise<string> & { cancel(): void } {
|
export function ServiceName(): Promise<string> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(2428202016) as any;
|
let $resultPromise = $Call.ByID(2949906614) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +46,7 @@ export function ServiceName(): Promise<string> & { cancel(): void } {
|
|||||||
* ServiceShutdown is called when the service is unloaded.
|
* ServiceShutdown is called when the service is unloaded.
|
||||||
*/
|
*/
|
||||||
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(3893755233) as any;
|
let $resultPromise = $Call.ByID(307064411) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +54,7 @@ export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
|||||||
* ServiceStartup is called when the service is loaded.
|
* ServiceStartup is called when the service is loaded.
|
||||||
*/
|
*/
|
||||||
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(4078800764, options) as any;
|
let $resultPromise = $Call.ByID(1350118426, options) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,11 +62,22 @@ export function ServiceStartup(options: application$0.ServiceOptions): Promise<v
|
|||||||
* SetBadge sets the badge label on the application icon.
|
* SetBadge sets the badge label on the application icon.
|
||||||
*/
|
*/
|
||||||
export function SetBadge(label: string): Promise<void> & { cancel(): void } {
|
export function SetBadge(label: string): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(784276339, label) as any;
|
let $resultPromise = $Call.ByID(1717705661, label) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SetCustomBadge(label: string, options: $models.Options): Promise<void> & { cancel(): void } {
|
/**
|
||||||
let $resultPromise = $Call.ByID(3058653106, label, options) as any;
|
* SetCustomBadge sets the badge label on the application icon with custom options.
|
||||||
|
*/
|
||||||
|
export function SetCustomBadge(label: string, options: $models.BadgeOptions): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(2730169760, label, options) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShowAppIcon shows the app icon in the dock/taskbar.
|
||||||
|
*/
|
||||||
|
export function ShowAppIcon(): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3409697379) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
import * as BadgeService from "./badgeservice.js";
|
import * as DockService from "./dockservice.js";
|
||||||
export {
|
export {
|
||||||
BadgeService
|
DockService
|
||||||
};
|
};
|
||||||
|
|
||||||
export * from "./models.js";
|
export * from "./models.js";
|
||||||
@@ -9,15 +9,18 @@ import {Create as $Create} from "@wailsio/runtime";
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as color$0 from "../../../../../../../image/color/models.js";
|
import * as color$0 from "../../../../../../../image/color/models.js";
|
||||||
|
|
||||||
export class Options {
|
/**
|
||||||
|
* BadgeOptions represents options for customizing badge appearance
|
||||||
|
*/
|
||||||
|
export class BadgeOptions {
|
||||||
"TextColour": color$0.RGBA;
|
"TextColour": color$0.RGBA;
|
||||||
"BackgroundColour": color$0.RGBA;
|
"BackgroundColour": color$0.RGBA;
|
||||||
"FontName": string;
|
"FontName": string;
|
||||||
"FontSize": number;
|
"FontSize": number;
|
||||||
"SmallFontSize": number;
|
"SmallFontSize": number;
|
||||||
|
|
||||||
/** Creates a new Options instance. */
|
/** Creates a new BadgeOptions instance. */
|
||||||
constructor($$source: Partial<Options> = {}) {
|
constructor($$source: Partial<BadgeOptions> = {}) {
|
||||||
if (!("TextColour" in $$source)) {
|
if (!("TextColour" in $$source)) {
|
||||||
this["TextColour"] = (new color$0.RGBA());
|
this["TextColour"] = (new color$0.RGBA());
|
||||||
}
|
}
|
||||||
@@ -38,9 +41,9 @@ export class Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Options instance from a string or object.
|
* Creates a new BadgeOptions instance from a string or object.
|
||||||
*/
|
*/
|
||||||
static createFrom($$source: any = {}): Options {
|
static createFrom($$source: any = {}): BadgeOptions {
|
||||||
const $$createField0_0 = $$createType0;
|
const $$createField0_0 = $$createType0;
|
||||||
const $$createField1_0 = $$createType0;
|
const $$createField1_0 = $$createType0;
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
@@ -50,7 +53,7 @@ export class Options {
|
|||||||
if ("BackgroundColour" in $$parsedSource) {
|
if ("BackgroundColour" in $$parsedSource) {
|
||||||
$$parsedSource["BackgroundColour"] = $$createField1_0($$parsedSource["BackgroundColour"]);
|
$$parsedSource["BackgroundColour"] = $$createField1_0($$parsedSource["BackgroundColour"]);
|
||||||
}
|
}
|
||||||
return new Options($$parsedSource as Partial<Options>);
|
return new BadgeOptions($$parsedSource as Partial<BadgeOptions>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
|
||||||
// This file is automatically generated. DO NOT EDIT
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore: Unused imports
|
|
||||||
import {Create as $Create} from "@wailsio/runtime";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Logger records structured information about each call to its
|
|
||||||
* Log, Debug, Info, Warn, and Error methods.
|
|
||||||
* For each call, it creates a [Record] and passes it to a [Handler].
|
|
||||||
*
|
|
||||||
* To create a new Logger, call [New] or a Logger method
|
|
||||||
* that begins "With".
|
|
||||||
*/
|
|
||||||
export class Logger {
|
|
||||||
|
|
||||||
/** Creates a new Logger instance. */
|
|
||||||
constructor($$source: Partial<Logger> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Logger instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): Logger {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new Logger($$parsedSource as Partial<Logger>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
frontend/bindings/net/http/models.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import {Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Header represents the key-value pairs in an HTTP header.
|
||||||
|
*
|
||||||
|
* The keys should be in canonical form, as returned by
|
||||||
|
* [CanonicalHeaderKey].
|
||||||
|
*/
|
||||||
|
export type Header = { [_: string]: string[] };
|
||||||
@@ -68,4 +68,9 @@ export enum TranslatorType {
|
|||||||
* DeeplTranslatorType DeepL翻译器
|
* DeeplTranslatorType DeepL翻译器
|
||||||
*/
|
*/
|
||||||
DeeplTranslatorType = "deepl",
|
DeeplTranslatorType = "deepl",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TartuNLPTranslatorType TartuNLP翻译器
|
||||||
|
*/
|
||||||
|
TartuNLPTranslatorType = "tartunlp",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,10 +5,6 @@
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import {Create as $Create} from "@wailsio/runtime";
|
import {Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore: Unused imports
|
|
||||||
import * as time$0 from "../../../time/models.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppConfig 应用配置 - 按照前端设置页面分类组织
|
* AppConfig 应用配置 - 按照前端设置页面分类组织
|
||||||
*/
|
*/
|
||||||
@@ -114,6 +110,11 @@ export class AppearanceConfig {
|
|||||||
*/
|
*/
|
||||||
"systemTheme": SystemThemeType;
|
"systemTheme": SystemThemeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前选择的预设主题名称
|
||||||
|
*/
|
||||||
|
"currentTheme": string;
|
||||||
|
|
||||||
/** Creates a new AppearanceConfig instance. */
|
/** Creates a new AppearanceConfig instance. */
|
||||||
constructor($$source: Partial<AppearanceConfig> = {}) {
|
constructor($$source: Partial<AppearanceConfig> = {}) {
|
||||||
if (!("language" in $$source)) {
|
if (!("language" in $$source)) {
|
||||||
@@ -122,6 +123,9 @@ export class AppearanceConfig {
|
|||||||
if (!("systemTheme" in $$source)) {
|
if (!("systemTheme" in $$source)) {
|
||||||
this["systemTheme"] = ("" as SystemThemeType);
|
this["systemTheme"] = ("" as SystemThemeType);
|
||||||
}
|
}
|
||||||
|
if (!("currentTheme" in $$source)) {
|
||||||
|
this["currentTheme"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
Object.assign(this, $$source);
|
||||||
}
|
}
|
||||||
@@ -196,8 +200,8 @@ export class Document {
|
|||||||
"id": number;
|
"id": number;
|
||||||
"title": string;
|
"title": string;
|
||||||
"content": string;
|
"content": string;
|
||||||
"createdAt": time$0.Time;
|
"createdAt": string;
|
||||||
"updatedAt": time$0.Time;
|
"updatedAt": string;
|
||||||
"is_deleted": boolean;
|
"is_deleted": boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -217,10 +221,10 @@ export class Document {
|
|||||||
this["content"] = "";
|
this["content"] = "";
|
||||||
}
|
}
|
||||||
if (!("createdAt" in $$source)) {
|
if (!("createdAt" in $$source)) {
|
||||||
this["createdAt"] = null;
|
this["createdAt"] = "";
|
||||||
}
|
}
|
||||||
if (!("updatedAt" in $$source)) {
|
if (!("updatedAt" in $$source)) {
|
||||||
this["updatedAt"] = null;
|
this["updatedAt"] = "";
|
||||||
}
|
}
|
||||||
if (!("is_deleted" in $$source)) {
|
if (!("is_deleted" in $$source)) {
|
||||||
this["is_deleted"] = false;
|
this["is_deleted"] = false;
|
||||||
@@ -490,6 +494,11 @@ export class GeneralConfig {
|
|||||||
*/
|
*/
|
||||||
"enableLoadingAnimation": boolean;
|
"enableLoadingAnimation": boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用标签页模式
|
||||||
|
*/
|
||||||
|
"enableTabs": boolean;
|
||||||
|
|
||||||
/** Creates a new GeneralConfig instance. */
|
/** Creates a new GeneralConfig instance. */
|
||||||
constructor($$source: Partial<GeneralConfig> = {}) {
|
constructor($$source: Partial<GeneralConfig> = {}) {
|
||||||
if (!("alwaysOnTop" in $$source)) {
|
if (!("alwaysOnTop" in $$source)) {
|
||||||
@@ -516,6 +525,9 @@ export class GeneralConfig {
|
|||||||
if (!("enableLoadingAnimation" in $$source)) {
|
if (!("enableLoadingAnimation" in $$source)) {
|
||||||
this["enableLoadingAnimation"] = false;
|
this["enableLoadingAnimation"] = false;
|
||||||
}
|
}
|
||||||
|
if (!("enableTabs" in $$source)) {
|
||||||
|
this["enableTabs"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
Object.assign(this, $$source);
|
||||||
}
|
}
|
||||||
@@ -1143,8 +1155,8 @@ export class Theme {
|
|||||||
"type": ThemeType;
|
"type": ThemeType;
|
||||||
"colors": ThemeColorConfig;
|
"colors": ThemeColorConfig;
|
||||||
"isDefault": boolean;
|
"isDefault": boolean;
|
||||||
"createdAt": time$0.Time;
|
"createdAt": string;
|
||||||
"updatedAt": time$0.Time;
|
"updatedAt": string;
|
||||||
|
|
||||||
/** Creates a new Theme instance. */
|
/** Creates a new Theme instance. */
|
||||||
constructor($$source: Partial<Theme> = {}) {
|
constructor($$source: Partial<Theme> = {}) {
|
||||||
@@ -1158,16 +1170,16 @@ export class Theme {
|
|||||||
this["type"] = ("" as ThemeType);
|
this["type"] = ("" as ThemeType);
|
||||||
}
|
}
|
||||||
if (!("colors" in $$source)) {
|
if (!("colors" in $$source)) {
|
||||||
this["colors"] = (new ThemeColorConfig());
|
this["colors"] = ({} as ThemeColorConfig);
|
||||||
}
|
}
|
||||||
if (!("isDefault" in $$source)) {
|
if (!("isDefault" in $$source)) {
|
||||||
this["isDefault"] = false;
|
this["isDefault"] = false;
|
||||||
}
|
}
|
||||||
if (!("createdAt" in $$source)) {
|
if (!("createdAt" in $$source)) {
|
||||||
this["createdAt"] = null;
|
this["createdAt"] = "";
|
||||||
}
|
}
|
||||||
if (!("updatedAt" in $$source)) {
|
if (!("updatedAt" in $$source)) {
|
||||||
this["updatedAt"] = null;
|
this["updatedAt"] = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
Object.assign(this, $$source);
|
||||||
@@ -1187,212 +1199,9 @@ export class Theme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThemeColorConfig 主题颜色配置
|
* ThemeColorConfig 使用与前端 ThemeColors 相同的结构,存储任意主题键值
|
||||||
*/
|
*/
|
||||||
export class ThemeColorConfig {
|
export type ThemeColorConfig = { [_: string]: any };
|
||||||
/**
|
|
||||||
* 基础色调
|
|
||||||
* 主背景色
|
|
||||||
*/
|
|
||||||
"background": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 次要背景色
|
|
||||||
*/
|
|
||||||
"backgroundSecondary": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 面板背景
|
|
||||||
*/
|
|
||||||
"surface": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主文本色
|
|
||||||
*/
|
|
||||||
"foreground": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 次要文本色
|
|
||||||
*/
|
|
||||||
"foregroundSecondary": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 语法高亮
|
|
||||||
* 注释色
|
|
||||||
*/
|
|
||||||
"comment": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关键字
|
|
||||||
*/
|
|
||||||
"keyword": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符串
|
|
||||||
*/
|
|
||||||
"string": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 函数名
|
|
||||||
*/
|
|
||||||
"function": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数字
|
|
||||||
*/
|
|
||||||
"number": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作符
|
|
||||||
*/
|
|
||||||
"operator": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 变量
|
|
||||||
*/
|
|
||||||
"variable": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类型
|
|
||||||
*/
|
|
||||||
"type": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 界面元素
|
|
||||||
* 光标
|
|
||||||
*/
|
|
||||||
"cursor": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 选中背景
|
|
||||||
*/
|
|
||||||
"selection": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失焦选中背景
|
|
||||||
*/
|
|
||||||
"selectionBlur": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前行高亮
|
|
||||||
*/
|
|
||||||
"activeLine": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 行号
|
|
||||||
*/
|
|
||||||
"lineNumber": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 活动行号
|
|
||||||
*/
|
|
||||||
"activeLineNumber": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 边框分割线
|
|
||||||
* 边框色
|
|
||||||
*/
|
|
||||||
"borderColor": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 浅色边框
|
|
||||||
*/
|
|
||||||
"borderLight": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 搜索匹配
|
|
||||||
* 搜索匹配
|
|
||||||
*/
|
|
||||||
"searchMatch": string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 匹配括号
|
|
||||||
*/
|
|
||||||
"matchingBracket": string;
|
|
||||||
|
|
||||||
/** Creates a new ThemeColorConfig instance. */
|
|
||||||
constructor($$source: Partial<ThemeColorConfig> = {}) {
|
|
||||||
if (!("background" in $$source)) {
|
|
||||||
this["background"] = "";
|
|
||||||
}
|
|
||||||
if (!("backgroundSecondary" in $$source)) {
|
|
||||||
this["backgroundSecondary"] = "";
|
|
||||||
}
|
|
||||||
if (!("surface" in $$source)) {
|
|
||||||
this["surface"] = "";
|
|
||||||
}
|
|
||||||
if (!("foreground" in $$source)) {
|
|
||||||
this["foreground"] = "";
|
|
||||||
}
|
|
||||||
if (!("foregroundSecondary" in $$source)) {
|
|
||||||
this["foregroundSecondary"] = "";
|
|
||||||
}
|
|
||||||
if (!("comment" in $$source)) {
|
|
||||||
this["comment"] = "";
|
|
||||||
}
|
|
||||||
if (!("keyword" in $$source)) {
|
|
||||||
this["keyword"] = "";
|
|
||||||
}
|
|
||||||
if (!("string" in $$source)) {
|
|
||||||
this["string"] = "";
|
|
||||||
}
|
|
||||||
if (!("function" in $$source)) {
|
|
||||||
this["function"] = "";
|
|
||||||
}
|
|
||||||
if (!("number" in $$source)) {
|
|
||||||
this["number"] = "";
|
|
||||||
}
|
|
||||||
if (!("operator" in $$source)) {
|
|
||||||
this["operator"] = "";
|
|
||||||
}
|
|
||||||
if (!("variable" in $$source)) {
|
|
||||||
this["variable"] = "";
|
|
||||||
}
|
|
||||||
if (!("type" in $$source)) {
|
|
||||||
this["type"] = "";
|
|
||||||
}
|
|
||||||
if (!("cursor" in $$source)) {
|
|
||||||
this["cursor"] = "";
|
|
||||||
}
|
|
||||||
if (!("selection" in $$source)) {
|
|
||||||
this["selection"] = "";
|
|
||||||
}
|
|
||||||
if (!("selectionBlur" in $$source)) {
|
|
||||||
this["selectionBlur"] = "";
|
|
||||||
}
|
|
||||||
if (!("activeLine" in $$source)) {
|
|
||||||
this["activeLine"] = "";
|
|
||||||
}
|
|
||||||
if (!("lineNumber" in $$source)) {
|
|
||||||
this["lineNumber"] = "";
|
|
||||||
}
|
|
||||||
if (!("activeLineNumber" in $$source)) {
|
|
||||||
this["activeLineNumber"] = "";
|
|
||||||
}
|
|
||||||
if (!("borderColor" in $$source)) {
|
|
||||||
this["borderColor"] = "";
|
|
||||||
}
|
|
||||||
if (!("borderLight" in $$source)) {
|
|
||||||
this["borderLight"] = "";
|
|
||||||
}
|
|
||||||
if (!("searchMatch" in $$source)) {
|
|
||||||
this["searchMatch"] = "";
|
|
||||||
}
|
|
||||||
if (!("matchingBracket" in $$source)) {
|
|
||||||
this["matchingBracket"] = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ThemeColorConfig instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): ThemeColorConfig {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new ThemeColorConfig($$parsedSource as Partial<ThemeColorConfig>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThemeType 主题类型枚举
|
* ThemeType 主题类型枚举
|
||||||
@@ -1533,6 +1342,11 @@ var $$createType6 = (function $$initCreateType6(...args): any {
|
|||||||
});
|
});
|
||||||
const $$createType7 = $Create.Map($Create.Any, $Create.Any);
|
const $$createType7 = $Create.Map($Create.Any, $Create.Any);
|
||||||
const $$createType8 = HotkeyCombo.createFrom;
|
const $$createType8 = HotkeyCombo.createFrom;
|
||||||
const $$createType9 = ThemeColorConfig.createFrom;
|
var $$createType9 = (function $$initCreateType9(...args): any {
|
||||||
|
if ($$createType9 === $$initCreateType9) {
|
||||||
|
$$createType9 = $$createType7;
|
||||||
|
}
|
||||||
|
return $$createType9(...args);
|
||||||
|
});
|
||||||
const $$createType10 = GithubConfig.createFrom;
|
const $$createType10 = GithubConfig.createFrom;
|
||||||
const $$createType11 = GiteaConfig.createFrom;
|
const $$createType11 = GiteaConfig.createFrom;
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as models$0 from "../models/models.js";
|
import * as models$0 from "../models/models.js";
|
||||||
@@ -54,6 +57,11 @@ export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
|||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(2900331732, options) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StartAutoBackup 启动自动备份定时器
|
* StartAutoBackup 启动自动备份定时器
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,10 +10,17 @@
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as models$0 from "../models/models.js";
|
import * as models$0 from "../models/models.js";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as $models from "./models.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get 获取配置项
|
* Get 获取配置项
|
||||||
*/
|
*/
|
||||||
@@ -34,22 +41,6 @@ export function GetConfig(): Promise<models$0.AppConfig | null> & { cancel(): vo
|
|||||||
return $typingPromise;
|
return $typingPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* GetConfigDir 获取配置目录
|
|
||||||
*/
|
|
||||||
export function GetConfigDir(): Promise<string> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(2275626561) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GetSettingsPath 获取设置文件路径
|
|
||||||
*/
|
|
||||||
export function GetSettingsPath(): Promise<string> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(2175583370) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MigrateConfig 执行配置迁移
|
* MigrateConfig 执行配置迁移
|
||||||
*/
|
*/
|
||||||
@@ -74,6 +65,14 @@ export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
|||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServiceStartup initializes the service when the application starts
|
||||||
|
*/
|
||||||
|
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3311949428, options) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set 设置配置项
|
* Set 设置配置项
|
||||||
*/
|
*/
|
||||||
@@ -83,34 +82,18 @@ export function Set(key: string, value: any): Promise<void> & { cancel(): void }
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SetBackupConfigChangeCallback 设置备份配置变更回调
|
* Watch 注册配置变更监听器
|
||||||
*/
|
*/
|
||||||
export function SetBackupConfigChangeCallback(callback: any): Promise<void> & { cancel(): void } {
|
export function Watch(path: string, callback: $models.ObserverCallback): Promise<$models.CancelFunc> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(3264871659, callback) as any;
|
let $resultPromise = $Call.ByID(1143583035, path, callback) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SetDataPathChangeCallback 设置数据路径配置变更回调
|
* WatchWithContext 使用 Context 注册监听器
|
||||||
*/
|
*/
|
||||||
export function SetDataPathChangeCallback(callback: any): Promise<void> & { cancel(): void } {
|
export function WatchWithContext(path: string, callback: $models.ObserverCallback): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(393017412, callback) as any;
|
let $resultPromise = $Call.ByID(1454973098, path, callback) as any;
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SetHotkeyChangeCallback 设置热键配置变更回调
|
|
||||||
*/
|
|
||||||
export function SetHotkeyChangeCallback(callback: any): Promise<void> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(283872321, callback) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SetWindowSnapConfigChangeCallback 设置窗口吸附配置变更回调
|
|
||||||
*/
|
|
||||||
export function SetWindowSnapConfigChangeCallback(callback: any): Promise<void> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(2324961653, callback) as any;
|
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,6 @@ import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
||||||
|
|
||||||
/**
|
|
||||||
* OnDataPathChanged handles data path changes
|
|
||||||
*/
|
|
||||||
export function OnDataPathChanged(): Promise<void> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(3652863491) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RegisterModel 注册模型与表的映射关系
|
* RegisterModel 注册模型与表的映射关系
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,10 +10,6 @@
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore: Unused imports
|
|
||||||
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SelectDirectory 打开目录选择对话框
|
* SelectDirectory 打开目录选择对话框
|
||||||
*/
|
*/
|
||||||
@@ -29,11 +25,3 @@ export function SelectFile(): Promise<string> & { cancel(): void } {
|
|||||||
let $resultPromise = $Call.ByID(37302920) as any;
|
let $resultPromise = $Call.ByID(37302920) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* SetWindow 设置绑定的窗口
|
|
||||||
*/
|
|
||||||
export function SetWindow(window: application$0.WebviewWindow | null): Promise<void> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(968177170, window) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -49,14 +49,6 @@ export function GetDocumentByID(id: number): Promise<models$0.Document | null> &
|
|||||||
return $typingPromise;
|
return $typingPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* GetFirstDocumentID gets the first active document's ID for frontend initialization
|
|
||||||
*/
|
|
||||||
export function GetFirstDocumentID(): Promise<number> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(2970773833) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ListAllDocumentsMeta lists all active (non-deleted) document metadata
|
* ListAllDocumentsMeta lists all active (non-deleted) document metadata
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HotkeyService Windows全局热键服务
|
* HotkeyService 全局热键服务
|
||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ export function GetCurrentHotkey(): Promise<models$0.HotkeyCombo | null> & { can
|
|||||||
/**
|
/**
|
||||||
* Initialize 初始化热键服务
|
* Initialize 初始化热键服务
|
||||||
*/
|
*/
|
||||||
export function Initialize(app: application$0.App | null, mainWindow: application$0.WebviewWindow | null): Promise<void> & { cancel(): void } {
|
export function Initialize(): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(3671360458, app, mainWindow) as any;
|
let $resultPromise = $Call.ByID(3671360458) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,8 +48,8 @@ export function IsRegistered(): Promise<boolean> & { cancel(): void } {
|
|||||||
/**
|
/**
|
||||||
* RegisterHotkey 注册全局热键
|
* RegisterHotkey 注册全局热键
|
||||||
*/
|
*/
|
||||||
export function RegisterHotkey(hotkey: models$0.HotkeyCombo | null): Promise<void> & { cancel(): void } {
|
export function RegisterHotkey(combo: models$0.HotkeyCombo | null): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(1103945691, hotkey) as any;
|
let $resultPromise = $Call.ByID(1103945691, combo) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +61,14 @@ export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
|||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServiceStartup 服务启动时初始化
|
||||||
|
*/
|
||||||
|
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3079990808, options) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UnregisterHotkey 取消注册全局热键
|
* UnregisterHotkey 取消注册全局热键
|
||||||
*/
|
*/
|
||||||
@@ -72,8 +80,8 @@ export function UnregisterHotkey(): Promise<void> & { cancel(): void } {
|
|||||||
/**
|
/**
|
||||||
* UpdateHotkey 更新热键配置
|
* UpdateHotkey 更新热键配置
|
||||||
*/
|
*/
|
||||||
export function UpdateHotkey(enable: boolean, hotkey: models$0.HotkeyCombo | null): Promise<void> & { cancel(): void } {
|
export function UpdateHotkey(enable: boolean, combo: models$0.HotkeyCombo | null): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(823285555, enable, hotkey) as any;
|
let $resultPromise = $Call.ByID(823285555, enable, combo) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpClientService HTTP客户端服务
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as $models from "./models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExecuteRequest 执行HTTP请求
|
||||||
|
*/
|
||||||
|
export function ExecuteRequest(request: $models.HttpRequest | null): Promise<$models.HttpResponse | null> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3143343977, request) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType1($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private type creation functions
|
||||||
|
const $$createType0 = $models.HttpResponse.createFrom;
|
||||||
|
const $$createType1 = $Create.Nullable($$createType0);
|
||||||
@@ -8,6 +8,7 @@ import * as DialogService from "./dialogservice.js";
|
|||||||
import * as DocumentService from "./documentservice.js";
|
import * as DocumentService from "./documentservice.js";
|
||||||
import * as ExtensionService from "./extensionservice.js";
|
import * as ExtensionService from "./extensionservice.js";
|
||||||
import * as HotkeyService from "./hotkeyservice.js";
|
import * as HotkeyService from "./hotkeyservice.js";
|
||||||
|
import * as HttpClientService from "./httpclientservice.js";
|
||||||
import * as KeyBindingService from "./keybindingservice.js";
|
import * as KeyBindingService from "./keybindingservice.js";
|
||||||
import * as MigrationService from "./migrationservice.js";
|
import * as MigrationService from "./migrationservice.js";
|
||||||
import * as SelfUpdateService from "./selfupdateservice.js";
|
import * as SelfUpdateService from "./selfupdateservice.js";
|
||||||
@@ -26,6 +27,7 @@ export {
|
|||||||
DocumentService,
|
DocumentService,
|
||||||
ExtensionService,
|
ExtensionService,
|
||||||
HotkeyService,
|
HotkeyService,
|
||||||
|
HttpClientService,
|
||||||
KeyBindingService,
|
KeyBindingService,
|
||||||
MigrationService,
|
MigrationService,
|
||||||
SelfUpdateService,
|
SelfUpdateService,
|
||||||
|
|||||||
@@ -7,7 +7,118 @@ import {Create as $Create} from "@wailsio/runtime";
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
import * as http$0 from "../../../net/http/models.js";
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as time$0 from "../../../time/models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CancelFunc 取消订阅函数
|
||||||
|
* 调用此函数可以取消对配置的监听
|
||||||
|
*/
|
||||||
|
export type CancelFunc = any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpRequest HTTP请求结构
|
||||||
|
*/
|
||||||
|
export class HttpRequest {
|
||||||
|
"method": string;
|
||||||
|
"url": string;
|
||||||
|
"headers": { [_: string]: string };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* json, formdata, urlencoded, text, params, xml, html, javascript, binary
|
||||||
|
*/
|
||||||
|
"bodyType"?: string;
|
||||||
|
"body"?: any;
|
||||||
|
|
||||||
|
/** Creates a new HttpRequest instance. */
|
||||||
|
constructor($$source: Partial<HttpRequest> = {}) {
|
||||||
|
if (!("method" in $$source)) {
|
||||||
|
this["method"] = "";
|
||||||
|
}
|
||||||
|
if (!("url" in $$source)) {
|
||||||
|
this["url"] = "";
|
||||||
|
}
|
||||||
|
if (!("headers" in $$source)) {
|
||||||
|
this["headers"] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new HttpRequest instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): HttpRequest {
|
||||||
|
const $$createField2_0 = $$createType0;
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
if ("headers" in $$parsedSource) {
|
||||||
|
$$parsedSource["headers"] = $$createField2_0($$parsedSource["headers"]);
|
||||||
|
}
|
||||||
|
return new HttpRequest($$parsedSource as Partial<HttpRequest>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpResponse HTTP响应结构
|
||||||
|
*/
|
||||||
|
export class HttpResponse {
|
||||||
|
/**
|
||||||
|
* 使用resp.Status()返回完整状态如"200 OK"
|
||||||
|
*/
|
||||||
|
"status": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应时间(毫秒)
|
||||||
|
*/
|
||||||
|
"time": number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求大小
|
||||||
|
*/
|
||||||
|
"requestSize": string;
|
||||||
|
"body": any;
|
||||||
|
"headers": http$0.Header;
|
||||||
|
"timestamp": time$0.Time;
|
||||||
|
"error"?: any;
|
||||||
|
|
||||||
|
/** Creates a new HttpResponse instance. */
|
||||||
|
constructor($$source: Partial<HttpResponse> = {}) {
|
||||||
|
if (!("status" in $$source)) {
|
||||||
|
this["status"] = "";
|
||||||
|
}
|
||||||
|
if (!("time" in $$source)) {
|
||||||
|
this["time"] = 0;
|
||||||
|
}
|
||||||
|
if (!("requestSize" in $$source)) {
|
||||||
|
this["requestSize"] = "";
|
||||||
|
}
|
||||||
|
if (!("body" in $$source)) {
|
||||||
|
this["body"] = null;
|
||||||
|
}
|
||||||
|
if (!("headers" in $$source)) {
|
||||||
|
this["headers"] = ({} as http$0.Header);
|
||||||
|
}
|
||||||
|
if (!("timestamp" in $$source)) {
|
||||||
|
this["timestamp"] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new HttpResponse instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): HttpResponse {
|
||||||
|
const $$createField4_0 = $$createType1;
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
if ("headers" in $$parsedSource) {
|
||||||
|
$$parsedSource["headers"] = $$createField4_0($$parsedSource["headers"]);
|
||||||
|
}
|
||||||
|
return new HttpResponse($$parsedSource as Partial<HttpResponse>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MemoryStats 内存统计信息
|
* MemoryStats 内存统计信息
|
||||||
@@ -119,6 +230,47 @@ export enum MigrationStatus {
|
|||||||
MigrationStatusFailed = "failed",
|
MigrationStatusFailed = "failed",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OSInfo 操作系统信息
|
||||||
|
*/
|
||||||
|
export class OSInfo {
|
||||||
|
"id": string;
|
||||||
|
"name": string;
|
||||||
|
"version": string;
|
||||||
|
"branding": string;
|
||||||
|
|
||||||
|
/** Creates a new OSInfo instance. */
|
||||||
|
constructor($$source: Partial<OSInfo> = {}) {
|
||||||
|
if (!("id" in $$source)) {
|
||||||
|
this["id"] = "";
|
||||||
|
}
|
||||||
|
if (!("name" in $$source)) {
|
||||||
|
this["name"] = "";
|
||||||
|
}
|
||||||
|
if (!("version" in $$source)) {
|
||||||
|
this["version"] = "";
|
||||||
|
}
|
||||||
|
if (!("branding" in $$source)) {
|
||||||
|
this["branding"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new OSInfo instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): OSInfo {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new OSInfo($$parsedSource as Partial<OSInfo>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ObserverCallback 观察者回调函数
|
||||||
|
*/
|
||||||
|
export type ObserverCallback = any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SelfUpdateResult 自我更新结果
|
* SelfUpdateResult 自我更新结果
|
||||||
*/
|
*/
|
||||||
@@ -203,61 +355,63 @@ export class SelfUpdateResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WindowInfo 窗口信息(简化版)
|
* SystemInfo 系统信息
|
||||||
*/
|
*/
|
||||||
export class WindowInfo {
|
export class SystemInfo {
|
||||||
"Window": application$0.WebviewWindow | null;
|
"os": string;
|
||||||
"DocumentID": number;
|
"arch": string;
|
||||||
"Title": string;
|
"debug": boolean;
|
||||||
|
"osInfo": OSInfo | null;
|
||||||
|
"platformInfo": { [_: string]: any };
|
||||||
|
|
||||||
/** Creates a new WindowInfo instance. */
|
/** Creates a new SystemInfo instance. */
|
||||||
constructor($$source: Partial<WindowInfo> = {}) {
|
constructor($$source: Partial<SystemInfo> = {}) {
|
||||||
if (!("Window" in $$source)) {
|
if (!("os" in $$source)) {
|
||||||
this["Window"] = null;
|
this["os"] = "";
|
||||||
}
|
}
|
||||||
if (!("DocumentID" in $$source)) {
|
if (!("arch" in $$source)) {
|
||||||
this["DocumentID"] = 0;
|
this["arch"] = "";
|
||||||
}
|
}
|
||||||
if (!("Title" in $$source)) {
|
if (!("debug" in $$source)) {
|
||||||
this["Title"] = "";
|
this["debug"] = false;
|
||||||
|
}
|
||||||
|
if (!("osInfo" in $$source)) {
|
||||||
|
this["osInfo"] = null;
|
||||||
|
}
|
||||||
|
if (!("platformInfo" in $$source)) {
|
||||||
|
this["platformInfo"] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
Object.assign(this, $$source);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new WindowInfo instance from a string or object.
|
* Creates a new SystemInfo instance from a string or object.
|
||||||
*/
|
*/
|
||||||
static createFrom($$source: any = {}): WindowInfo {
|
static createFrom($$source: any = {}): SystemInfo {
|
||||||
const $$createField0_0 = $$createType1;
|
const $$createField3_0 = $$createType5;
|
||||||
|
const $$createField4_0 = $$createType6;
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
if ("Window" in $$parsedSource) {
|
if ("osInfo" in $$parsedSource) {
|
||||||
$$parsedSource["Window"] = $$createField0_0($$parsedSource["Window"]);
|
$$parsedSource["osInfo"] = $$createField3_0($$parsedSource["osInfo"]);
|
||||||
}
|
}
|
||||||
return new WindowInfo($$parsedSource as Partial<WindowInfo>);
|
if ("platformInfo" in $$parsedSource) {
|
||||||
}
|
$$parsedSource["platformInfo"] = $$createField4_0($$parsedSource["platformInfo"]);
|
||||||
}
|
}
|
||||||
|
return new SystemInfo($$parsedSource as Partial<SystemInfo>);
|
||||||
/**
|
|
||||||
* WindowSnapService 窗口吸附服务
|
|
||||||
*/
|
|
||||||
export class WindowSnapService {
|
|
||||||
|
|
||||||
/** Creates a new WindowSnapService instance. */
|
|
||||||
constructor($$source: Partial<WindowSnapService> = {}) {
|
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new WindowSnapService instance from a string or object.
|
|
||||||
*/
|
|
||||||
static createFrom($$source: any = {}): WindowSnapService {
|
|
||||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
|
||||||
return new WindowSnapService($$parsedSource as Partial<WindowSnapService>);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private type creation functions
|
// Private type creation functions
|
||||||
const $$createType0 = application$0.WebviewWindow.createFrom;
|
const $$createType0 = $Create.Map($Create.Any, $Create.Any);
|
||||||
const $$createType1 = $Create.Nullable($$createType0);
|
var $$createType1 = (function $$initCreateType1(...args): any {
|
||||||
|
if ($$createType1 === $$initCreateType1) {
|
||||||
|
$$createType1 = $$createType3;
|
||||||
|
}
|
||||||
|
return $$createType1(...args);
|
||||||
|
});
|
||||||
|
const $$createType2 = $Create.Array($Create.Any);
|
||||||
|
const $$createType3 = $Create.Map($Create.Any, $$createType2);
|
||||||
|
const $$createType4 = OSInfo.createFrom;
|
||||||
|
const $$createType5 = $Create.Nullable($$createType4);
|
||||||
|
const $$createType6 = $Create.Map($Create.Any, $Create.Any);
|
||||||
|
|||||||
@@ -34,6 +34,18 @@ export function GetMemoryStats(): Promise<$models.MemoryStats> & { cancel(): voi
|
|||||||
return $typingPromise;
|
return $typingPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetSystemInfo 获取系统环境信息
|
||||||
|
*/
|
||||||
|
export function GetSystemInfo(): Promise<$models.SystemInfo | null> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(2629436820) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TriggerGC 手动触发垃圾回收
|
* TriggerGC 手动触发垃圾回收
|
||||||
*/
|
*/
|
||||||
@@ -44,3 +56,5 @@ export function TriggerGC(): Promise<void> & { cancel(): void } {
|
|||||||
|
|
||||||
// Private type creation functions
|
// Private type creation functions
|
||||||
const $$createType0 = $models.MemoryStats.createFrom;
|
const $$createType0 = $models.MemoryStats.createFrom;
|
||||||
|
const $$createType1 = $models.SystemInfo.createFrom;
|
||||||
|
const $$createType2 = $Create.Nullable($$createType1);
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/applic
|
|||||||
import * as models$0 from "../models/models.js";
|
import * as models$0 from "../models/models.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CreateTheme 创建新主题
|
* GetThemeByName 通过名称获取主题覆盖,若不存在则返回 nil
|
||||||
*/
|
*/
|
||||||
export function CreateTheme(theme: models$0.Theme | null): Promise<models$0.Theme | null> & { cancel(): void } {
|
export function GetThemeByName(name: string): Promise<models$0.Theme | null> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(3274757686, theme) as any;
|
let $resultPromise = $Call.ByID(1938954770, name) as any;
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
return $$createType1($result);
|
return $$createType1($result);
|
||||||
}) as any;
|
}) as any;
|
||||||
@@ -30,46 +30,10 @@ export function CreateTheme(theme: models$0.Theme | null): Promise<models$0.Them
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetAllThemes 获取所有主题
|
* ResetTheme 删除指定主题的覆盖配置
|
||||||
*/
|
*/
|
||||||
export function GetAllThemes(): Promise<(models$0.Theme | null)[]> & { cancel(): void } {
|
export function ResetTheme(name: string): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(2425053076) as any;
|
let $resultPromise = $Call.ByID(1806334457, name) as any;
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
|
||||||
return $$createType2($result);
|
|
||||||
}) as any;
|
|
||||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
|
||||||
return $typingPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GetDefaultThemes 获取默认主题
|
|
||||||
*/
|
|
||||||
export function GetDefaultThemes(): Promise<{ [_: string]: models$0.Theme | null }> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(3801788118) as any;
|
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
|
||||||
return $$createType3($result);
|
|
||||||
}) as any;
|
|
||||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
|
||||||
return $typingPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GetThemeByType 根据类型获取默认主题
|
|
||||||
*/
|
|
||||||
export function GetThemeByType(themeType: models$0.ThemeType): Promise<models$0.Theme | null> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(1680465265, themeType) as any;
|
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
|
||||||
return $$createType1($result);
|
|
||||||
}) as any;
|
|
||||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
|
||||||
return $typingPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ResetThemeColors 重置主题颜色为默认值
|
|
||||||
*/
|
|
||||||
export function ResetThemeColors(themeType: models$0.ThemeType): Promise<void> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(342461245, themeType) as any;
|
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +46,7 @@ export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServiceStartup 服务启动时初始化
|
* ServiceStartup 服务启动
|
||||||
*/
|
*/
|
||||||
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(2915959937, options) as any;
|
let $resultPromise = $Call.ByID(2915959937, options) as any;
|
||||||
@@ -90,15 +54,13 @@ export function ServiceStartup(options: application$0.ServiceOptions): Promise<v
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UpdateThemeColors 更新主题颜色
|
* UpdateTheme 保存或更新主题覆盖
|
||||||
*/
|
*/
|
||||||
export function UpdateThemeColors(themeType: models$0.ThemeType, colors: models$0.ThemeColorConfig): Promise<void> & { cancel(): void } {
|
export function UpdateTheme(name: string, colors: models$0.ThemeColorConfig): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(2750902529, themeType, colors) as any;
|
let $resultPromise = $Call.ByID(70189749, name, colors) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private type creation functions
|
// Private type creation functions
|
||||||
const $$createType0 = models$0.Theme.createFrom;
|
const $$createType0 = models$0.Theme.createFrom;
|
||||||
const $$createType1 = $Create.Nullable($$createType0);
|
const $$createType1 = $Create.Nullable($$createType0);
|
||||||
const $$createType2 = $Create.Array($$createType1);
|
|
||||||
const $$createType3 = $Create.Map($Create.Any, $$createType1);
|
|
||||||
|
|||||||
@@ -14,27 +14,6 @@ import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as translator$0 from "../common/translator/models.js";
|
import * as translator$0 from "../common/translator/models.js";
|
||||||
|
|
||||||
/**
|
|
||||||
* GetAvailableTranslators 获取所有可用翻译器类型
|
|
||||||
* @returns {[]string} 翻译器类型列表
|
|
||||||
*/
|
|
||||||
export function GetAvailableTranslators(): Promise<string[]> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(1186597995) as any;
|
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
|
||||||
return $$createType0($result);
|
|
||||||
}) as any;
|
|
||||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
|
||||||
return $typingPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GetStandardLanguageCode 获取标准化的语言代码
|
|
||||||
*/
|
|
||||||
export function GetStandardLanguageCode(translatorType: translator$0.TranslatorType, languageCode: string): Promise<string> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(1158131995, translatorType, languageCode) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetTranslatorLanguages 获取翻译器的语言列表
|
* GetTranslatorLanguages 获取翻译器的语言列表
|
||||||
* @param {string} translatorType - 翻译器类型 ("google", "bing", "youdao", "deepl")
|
* @param {string} translatorType - 翻译器类型 ("google", "bing", "youdao", "deepl")
|
||||||
@@ -43,6 +22,19 @@ export function GetStandardLanguageCode(translatorType: translator$0.TranslatorT
|
|||||||
*/
|
*/
|
||||||
export function GetTranslatorLanguages(translatorType: translator$0.TranslatorType): Promise<{ [_: string]: translator$0.LanguageInfo }> & { cancel(): void } {
|
export function GetTranslatorLanguages(translatorType: translator$0.TranslatorType): Promise<{ [_: string]: translator$0.LanguageInfo }> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(3976114458, translatorType) as any;
|
let $resultPromise = $Call.ByID(3976114458, translatorType) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType1($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetTranslators 获取所有可用翻译器类型
|
||||||
|
* @returns {[]string} 翻译器类型列表
|
||||||
|
*/
|
||||||
|
export function GetTranslators(): Promise<string[]> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(3720069432) as any;
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
return $$createType2($result);
|
return $$createType2($result);
|
||||||
}) as any;
|
}) as any;
|
||||||
@@ -73,6 +65,6 @@ export function TranslateWith(text: string, $from: string, to: string, translato
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Private type creation functions
|
// Private type creation functions
|
||||||
const $$createType0 = $Create.Array($Create.Any);
|
const $$createType0 = translator$0.LanguageInfo.createFrom;
|
||||||
const $$createType1 = translator$0.LanguageInfo.createFrom;
|
const $$createType1 = $Create.Map($Create.Any, $$createType0);
|
||||||
const $$createType2 = $Create.Map($Create.Any, $$createType1);
|
const $$createType2 = $Create.Array($Create.Any);
|
||||||
|
|||||||
@@ -10,9 +10,13 @@
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
/**
|
||||||
// @ts-ignore: Unused imports
|
* AutoShowHide 自动显示/隐藏主窗口
|
||||||
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
*/
|
||||||
|
export function AutoShowHide(): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(4044219428) as any;
|
||||||
|
return $resultPromise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HandleWindowClose 处理窗口关闭事件
|
* HandleWindowClose 处理窗口关闭事件
|
||||||
@@ -38,14 +42,6 @@ export function MinimizeButtonClicked(): Promise<void> & { cancel(): void } {
|
|||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* SetAppReferences 设置应用引用
|
|
||||||
*/
|
|
||||||
export function SetAppReferences(app: application$0.App | null, mainWindow: application$0.WebviewWindow | null): Promise<void> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(3544515719, app, mainWindow) as any;
|
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ShouldMinimizeToTray 检查是否应该最小化到托盘
|
* ShouldMinimizeToTray 检查是否应该最小化到托盘
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WindowService 窗口管理服务(专注于窗口生命周期管理)
|
* WindowService 窗口管理服务
|
||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -14,17 +14,13 @@ import {Call as $Call, Create as $Create} from "@wailsio/runtime";
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore: Unused imports
|
|
||||||
import * as $models from "./models.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetOpenWindows 获取所有打开的窗口信息
|
* GetOpenWindows 获取所有打开的文档窗口
|
||||||
*/
|
*/
|
||||||
export function GetOpenWindows(): Promise<$models.WindowInfo[]> & { cancel(): void } {
|
export function GetOpenWindows(): Promise<application$0.Window[]> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(1464997251) as any;
|
let $resultPromise = $Call.ByID(1464997251) as any;
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
return $$createType1($result);
|
return $$createType0($result);
|
||||||
}) as any;
|
}) as any;
|
||||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
return $typingPromise;
|
return $typingPromise;
|
||||||
@@ -55,21 +51,12 @@ export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SetAppReferences 设置应用和主窗口引用
|
* ServiceStartup 服务启动时初始化
|
||||||
*/
|
*/
|
||||||
export function SetAppReferences(app: application$0.App | null, mainWindow: application$0.WebviewWindow | null): Promise<void> & { cancel(): void } {
|
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(1120840759, app, mainWindow) as any;
|
let $resultPromise = $Call.ByID(2432987694, options) as any;
|
||||||
return $resultPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SetWindowSnapService 设置窗口吸附服务引用
|
|
||||||
*/
|
|
||||||
export function SetWindowSnapService(snapService: $models.WindowSnapService | null): Promise<void> & { cancel(): void } {
|
|
||||||
let $resultPromise = $Call.ByID(1105193745, snapService) as any;
|
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private type creation functions
|
// Private type creation functions
|
||||||
const $$createType0 = $models.WindowInfo.createFrom;
|
const $$createType0 = $Create.Array($Create.Any);
|
||||||
const $$createType1 = $Create.Array($$createType0);
|
|
||||||
|
|||||||
8
frontend/components.d.ts
vendored
@@ -1,8 +1,11 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
// oxlint-disable
|
||||||
|
// ------
|
||||||
// Generated by unplugin-vue-components
|
// Generated by unplugin-vue-components
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
// biome-ignore lint: disable
|
|
||||||
export {}
|
export {}
|
||||||
|
|
||||||
/* prettier-ignore */
|
/* prettier-ignore */
|
||||||
@@ -16,6 +19,9 @@ declare module 'vue' {
|
|||||||
MemoryMonitor: typeof import('./src/components/monitor/MemoryMonitor.vue')['default']
|
MemoryMonitor: typeof import('./src/components/monitor/MemoryMonitor.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
TabContainer: typeof import('./src/components/tabs/TabContainer.vue')['default']
|
||||||
|
TabContextMenu: typeof import('./src/components/tabs/TabContextMenu.vue')['default']
|
||||||
|
TabItem: typeof import('./src/components/tabs/TabItem.vue')['default']
|
||||||
Toolbar: typeof import('./src/components/toolbar/Toolbar.vue')['default']
|
Toolbar: typeof import('./src/components/toolbar/Toolbar.vue')['default']
|
||||||
WindowsTitleBar: typeof import('./src/components/titlebar/WindowsTitleBar.vue')['default']
|
WindowsTitleBar: typeof import('./src/components/titlebar/WindowsTitleBar.vue')['default']
|
||||||
WindowTitleBar: typeof import('./src/components/titlebar/WindowTitleBar.vue')['default']
|
WindowTitleBar: typeof import('./src/components/titlebar/WindowTitleBar.vue')['default']
|
||||||
|
|||||||
130
frontend/docs/.vitepress/config.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import {defineConfig} from 'vitepress'
|
||||||
|
const base = '/'
|
||||||
|
// https://vitepress.dev/reference/site-config
|
||||||
|
export default defineConfig({
|
||||||
|
base: base,
|
||||||
|
title: "voidraft",
|
||||||
|
description: "An elegant text snippet recording tool designed for developers.",
|
||||||
|
srcDir: 'src',
|
||||||
|
assetsDir: 'assets',
|
||||||
|
cacheDir: './.vitepress/cache',
|
||||||
|
outDir: './.vitepress/dist',
|
||||||
|
srcExclude: [],
|
||||||
|
ignoreDeadLinks: false,
|
||||||
|
head: [
|
||||||
|
["link", {rel: "icon", type: "image/png", href: "/icon/favicon-96x96.png", sizes: "96x96"}],
|
||||||
|
["link", {rel: "icon", type: "image/svg+xml", href: "/icon/favicon.svg"}],
|
||||||
|
["link", {rel: "shortcut icon", href: "/icon/favicon.ico"}],
|
||||||
|
["link", {rel: "apple-touch-icon", sizes: "180x180", href: "/icon/apple-touch-icon.png"}],
|
||||||
|
["meta", {name: "apple-mobile-web-app-title", content: "voidraft"}],
|
||||||
|
["link", {rel: "manifest", href: "/icon/site.webmanifest"}],
|
||||||
|
['meta', {name: 'viewport', content: 'width=device-width,initial-scale=1'}]
|
||||||
|
],
|
||||||
|
|
||||||
|
// 国际化配置
|
||||||
|
locales: {
|
||||||
|
root: {
|
||||||
|
label: 'English',
|
||||||
|
lang: 'en-US',
|
||||||
|
description: 'An elegant text snippet recording tool designed for developers.',
|
||||||
|
themeConfig: {
|
||||||
|
logo: '/icon/logo.png',
|
||||||
|
siteTitle: 'voidraft',
|
||||||
|
nav: [
|
||||||
|
{text: 'Home', link: '/'},
|
||||||
|
{text: 'Guide', link: '/guide/introduction'}
|
||||||
|
],
|
||||||
|
sidebar: {
|
||||||
|
'/guide/': [
|
||||||
|
{
|
||||||
|
text: 'Getting Started',
|
||||||
|
items: [
|
||||||
|
{text: 'Introduction', link: '/guide/introduction'},
|
||||||
|
{text: 'Installation', link: '/guide/installation'},
|
||||||
|
{text: 'Quick Start', link: '/guide/getting-started'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Features',
|
||||||
|
items: [
|
||||||
|
{text: 'Overview', link: '/guide/features'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
socialLinks: [
|
||||||
|
{icon: 'github', link: 'https://github.com/landaiqing/voidraft'}
|
||||||
|
],
|
||||||
|
outline: {
|
||||||
|
label: 'On this page'
|
||||||
|
},
|
||||||
|
lastUpdated: {
|
||||||
|
text: 'Last updated'
|
||||||
|
},
|
||||||
|
docFooter: {
|
||||||
|
prev: 'Previous',
|
||||||
|
next: 'Next'
|
||||||
|
},
|
||||||
|
darkModeSwitchLabel: 'Appearance',
|
||||||
|
sidebarMenuLabel: 'Menu',
|
||||||
|
returnToTopLabel: 'Return to top',
|
||||||
|
footer: {
|
||||||
|
message: 'Released under the MIT License.',
|
||||||
|
copyright: 'Copyright © 2025-present landaiqing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
zh: {
|
||||||
|
label: '简体中文',
|
||||||
|
lang: 'zh-CN',
|
||||||
|
link: '/zh/',
|
||||||
|
description: '一个为开发者设计的优雅文本片段记录工具',
|
||||||
|
themeConfig: {
|
||||||
|
logo: '/icon/logo.png',
|
||||||
|
siteTitle: 'voidraft',
|
||||||
|
nav: [
|
||||||
|
{text: '首页', link: '/zh/'},
|
||||||
|
{text: '指南', link: '/zh/guide/introduction'}
|
||||||
|
],
|
||||||
|
sidebar: {
|
||||||
|
'/zh/guide/': [
|
||||||
|
{
|
||||||
|
text: '开始使用',
|
||||||
|
items: [
|
||||||
|
{text: '简介', link: '/zh/guide/introduction'},
|
||||||
|
{text: '安装', link: '/zh/guide/installation'},
|
||||||
|
{text: '快速开始', link: '/zh/guide/getting-started'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '功能特性',
|
||||||
|
items: [
|
||||||
|
{text: '功能概览', link: '/zh/guide/features'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
socialLinks: [
|
||||||
|
{icon: 'github', link: 'https://github.com/landaiqing/voidraft'}
|
||||||
|
],
|
||||||
|
outline: {
|
||||||
|
label: '本页目录'
|
||||||
|
},
|
||||||
|
lastUpdated: {
|
||||||
|
text: '最后更新'
|
||||||
|
},
|
||||||
|
docFooter: {
|
||||||
|
prev: '上一页',
|
||||||
|
next: '下一页'
|
||||||
|
},
|
||||||
|
darkModeSwitchLabel: '外观',
|
||||||
|
sidebarMenuLabel: '菜单',
|
||||||
|
returnToTopLabel: '返回顶部',
|
||||||
|
footer: {
|
||||||
|
message: 'Released under the MIT License.',
|
||||||
|
copyright: 'Copyright © 2025-present landaiqing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
6
frontend/docs/.vitepress/theme/index.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@import "style/var.css";
|
||||||
|
@import "style/blur.css";
|
||||||
|
@import "style/badge.css";
|
||||||
|
@import "style/grid.css";
|
||||||
|
|
||||||
|
|
||||||
17
frontend/docs/.vitepress/theme/index.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// https://vitepress.dev/guide/custom-theme
|
||||||
|
import { h } from 'vue'
|
||||||
|
import type { Theme } from 'vitepress'
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import './index.css'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
extends: DefaultTheme,
|
||||||
|
Layout: () => {
|
||||||
|
return h(DefaultTheme.Layout, null, {
|
||||||
|
// https://vitepress.dev/guide/extending-default-theme#layout-slots
|
||||||
|
})
|
||||||
|
},
|
||||||
|
enhanceApp({ app, router, siteData }) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
} satisfies Theme
|
||||||
21
frontend/docs/.vitepress/theme/style/badge.css
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/* 提示框背景颜色 */
|
||||||
|
:root {
|
||||||
|
--vp-custom-block-tip-bg: var(--vp-c-green-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 提示框 */
|
||||||
|
.custom-block.tip {
|
||||||
|
border-color: var(--vp-c-green-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 警告框 */
|
||||||
|
.custom-block.warning {
|
||||||
|
/* border-color: #d97706; */
|
||||||
|
border-color: var(--vp-c-yellow-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 危险框 */
|
||||||
|
.custom-block.danger {
|
||||||
|
/* border-color: #f43f5e; */
|
||||||
|
border-color: var(--vp-c-red-2);
|
||||||
|
}
|
||||||
73
frontend/docs/.vitepress/theme/style/blur.css
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/* .vitepress/theme/style/blur.css */
|
||||||
|
:root {
|
||||||
|
/* 首页导航 */
|
||||||
|
.VPNavBar {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文档页导航两侧 */
|
||||||
|
.VPNavBar:not(.home) {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
/* 文档页导航两侧 */
|
||||||
|
.VPNavBar:not(.home) {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 首页下滑后导航两侧 */
|
||||||
|
.VPNavBar:not(.has-sidebar):not(.home.top) {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
/* 文档页导航中间 */
|
||||||
|
.VPNavBar:not(.home.top) .content-body {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 首页下滑后导航中间 */
|
||||||
|
.VPNavBar:not(.has-sidebar):not(.home.top) .content-body {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分割线 */
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
/* 文档页分割线 */
|
||||||
|
.VPNavBar:not(.home.top) .divider-line {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 首页分割线 */
|
||||||
|
.VPNavBar:not(.has-sidebar):not(.home.top) .divider {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索框 VPNavBarSearchButton.vue */
|
||||||
|
.DocSearch-Button {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端大纲栏 */
|
||||||
|
.VPLocalNav {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
/* 隐藏分割线 */
|
||||||
|
/* border-bottom: 5px solid var(--vp-c-gutter); */
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
frontend/docs/.vitepress/theme/style/grid.css
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Grid Background
|
||||||
|
* 网格背景样式 - 为文档页面添加简约的网格背景
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
.VPDoc,
|
||||||
|
.VPHome {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.VPDoc::before,
|
||||||
|
.VPHome::before {
|
||||||
|
content: '';
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 亮色模式网格 */
|
||||||
|
:root:not(.dark) .VPDoc::before,
|
||||||
|
:root:not(.dark) .VPHome::before {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(0, 0, 0, 0.05) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(0, 0, 0, 0.05) 1px, transparent 1px);
|
||||||
|
background-size: 60px 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 暗色模式网格 */
|
||||||
|
.dark .VPDoc::before,
|
||||||
|
.dark .VPHome::before {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(255, 255, 255, 0.06) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
|
||||||
|
background-size: 60px 60px;
|
||||||
|
}
|
||||||
|
|
||||||
137
frontend/docs/.vitepress/theme/style/var.css
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
/**
|
||||||
|
* Customize default theme styling by overriding CSS variables:
|
||||||
|
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colors
|
||||||
|
*
|
||||||
|
* Each colors have exact same color scale system with 3 levels of solid
|
||||||
|
* colors with different brightness, and 1 soft color.
|
||||||
|
*
|
||||||
|
* - `XXX-1`: The most solid color used mainly for colored text. It must
|
||||||
|
* satisfy the contrast ratio against when used on top of `XXX-soft`.
|
||||||
|
*
|
||||||
|
* - `XXX-2`: The color used mainly for hover state of the button.
|
||||||
|
*
|
||||||
|
* - `XXX-3`: The color for solid background, such as bg color of the button.
|
||||||
|
* It must satisfy the contrast ratio with pure white (#ffffff) text on
|
||||||
|
* top of it.
|
||||||
|
*
|
||||||
|
* - `XXX-soft`: The color used for subtle background such as custom container
|
||||||
|
* or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
|
||||||
|
* on top of it.
|
||||||
|
*
|
||||||
|
* The soft color must be semi transparent alpha channel. This is crucial
|
||||||
|
* because it allows adding multiple "soft" colors on top of each other
|
||||||
|
* to create an accent, such as when having inline code block inside
|
||||||
|
* custom containers.
|
||||||
|
*
|
||||||
|
* - `default`: The color used purely for subtle indication without any
|
||||||
|
* special meanings attached to it such as bg color for menu hover state.
|
||||||
|
*
|
||||||
|
* - `brand`: Used for primary brand colors, such as link text, button with
|
||||||
|
* brand theme, etc.
|
||||||
|
*
|
||||||
|
* - `tip`: Used to indicate useful information. The default theme uses the
|
||||||
|
* brand color for this by default.
|
||||||
|
*
|
||||||
|
* - `warning`: Used to indicate warning to the users. Used in custom
|
||||||
|
* container, badges, etc.
|
||||||
|
*
|
||||||
|
* - `danger`: Used to show error, or dangerous message to the users. Used
|
||||||
|
* in custom container, badges, etc.
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
:root {
|
||||||
|
--vp-c-default-1: var(--vp-c-gray-1);
|
||||||
|
--vp-c-default-2: var(--vp-c-gray-2);
|
||||||
|
--vp-c-default-3: var(--vp-c-gray-3);
|
||||||
|
--vp-c-default-soft: var(--vp-c-gray-soft);
|
||||||
|
|
||||||
|
--vp-c-brand-1: var(--vp-c-indigo-1);
|
||||||
|
--vp-c-brand-2: var(--vp-c-indigo-2);
|
||||||
|
--vp-c-brand-3: var(--vp-c-indigo-3);
|
||||||
|
--vp-c-brand-soft: var(--vp-c-indigo-soft);
|
||||||
|
|
||||||
|
--vp-c-tip-1: var(--vp-c-brand-1);
|
||||||
|
--vp-c-tip-2: var(--vp-c-brand-2);
|
||||||
|
--vp-c-tip-3: var(--vp-c-brand-3);
|
||||||
|
--vp-c-tip-soft: var(--vp-c-brand-soft);
|
||||||
|
|
||||||
|
--vp-c-warning-1: var(--vp-c-yellow-1);
|
||||||
|
--vp-c-warning-2: var(--vp-c-yellow-2);
|
||||||
|
--vp-c-warning-3: var(--vp-c-yellow-3);
|
||||||
|
--vp-c-warning-soft: var(--vp-c-yellow-soft);
|
||||||
|
|
||||||
|
--vp-c-danger-1: var(--vp-c-red-1);
|
||||||
|
--vp-c-danger-2: var(--vp-c-red-2);
|
||||||
|
--vp-c-danger-3: var(--vp-c-red-3);
|
||||||
|
--vp-c-danger-soft: var(--vp-c-red-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Button
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--vp-button-brand-border: transparent;
|
||||||
|
--vp-button-brand-text: var(--vp-c-white);
|
||||||
|
--vp-button-brand-bg: var(--vp-c-brand-3);
|
||||||
|
--vp-button-brand-hover-border: transparent;
|
||||||
|
--vp-button-brand-hover-text: var(--vp-c-white);
|
||||||
|
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
|
||||||
|
--vp-button-brand-active-border: transparent;
|
||||||
|
--vp-button-brand-active-text: var(--vp-c-white);
|
||||||
|
--vp-button-brand-active-bg: var(--vp-c-brand-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Home
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--vp-home-hero-name-color: transparent;
|
||||||
|
--vp-home-hero-name-background: -webkit-linear-gradient(
|
||||||
|
120deg,
|
||||||
|
#bd34fe 30%,
|
||||||
|
#41d1ff
|
||||||
|
);
|
||||||
|
|
||||||
|
--vp-home-hero-image-background-image: linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
#bd34fe 50%,
|
||||||
|
#47caff 50%
|
||||||
|
);
|
||||||
|
--vp-home-hero-image-filter: blur(44px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
:root {
|
||||||
|
--vp-home-hero-image-filter: blur(56px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
:root {
|
||||||
|
--vp-home-hero-image-filter: blur(68px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Custom Block
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--vp-custom-block-tip-border: transparent;
|
||||||
|
--vp-custom-block-tip-text: var(--vp-c-text-1);
|
||||||
|
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
|
||||||
|
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Algolia
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
.DocSearch {
|
||||||
|
--docsearch-primary-color: var(--vp-c-brand-1) !important;
|
||||||
|
}
|
||||||
163
frontend/docs/src/guide/features.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# Features
|
||||||
|
|
||||||
|
Explore the powerful features that make voidraft a great tool for developers.
|
||||||
|
|
||||||
|
## Block-Based Editing
|
||||||
|
|
||||||
|
voidraft's core feature is its block-based editing system:
|
||||||
|
|
||||||
|
- Each block can have a different programming language
|
||||||
|
- Blocks are separated by delimiters (`∞∞∞language`)
|
||||||
|
- Navigate quickly between blocks
|
||||||
|
- Format each block independently
|
||||||
|
|
||||||
|
## Syntax Highlighting
|
||||||
|
|
||||||
|
Professional syntax highlighting for 30+ languages:
|
||||||
|
|
||||||
|
- Automatic language detection
|
||||||
|
- Customizable color schemes
|
||||||
|
- Support for nested languages
|
||||||
|
- Code folding support
|
||||||
|
|
||||||
|
## HTTP Client
|
||||||
|
|
||||||
|
Built-in HTTP client for API testing:
|
||||||
|
|
||||||
|
### Request Types
|
||||||
|
- GET, POST, PUT, DELETE, PATCH
|
||||||
|
- Custom headers
|
||||||
|
- Multiple body formats: JSON, FormData, URL-encoded, XML, Text
|
||||||
|
|
||||||
|
### Request Variables
|
||||||
|
Define and reuse variables:
|
||||||
|
|
||||||
|
```http
|
||||||
|
@var {
|
||||||
|
baseUrl: "https://api.example.com",
|
||||||
|
token: "your-api-token"
|
||||||
|
}
|
||||||
|
|
||||||
|
GET "{{baseUrl}}/users" {
|
||||||
|
authorization: "Bearer {{token}}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response Handling
|
||||||
|
- View formatted JSON responses
|
||||||
|
- See response time and size
|
||||||
|
- Inspect headers
|
||||||
|
- Save responses for later
|
||||||
|
|
||||||
|
## Code Formatting
|
||||||
|
|
||||||
|
Integrated Prettier support:
|
||||||
|
|
||||||
|
- Format on save (optional)
|
||||||
|
- Format selection or entire block
|
||||||
|
- Supports JavaScript, TypeScript, CSS, HTML, JSON, and more
|
||||||
|
- Customizable formatting rules
|
||||||
|
|
||||||
|
## Editor Extensions
|
||||||
|
|
||||||
|
### VSCode-Style Search
|
||||||
|
- Find and replace with regex support
|
||||||
|
- Case-sensitive and whole word options
|
||||||
|
- Search across all blocks
|
||||||
|
|
||||||
|
### Minimap
|
||||||
|
- Bird's-eye view of your document
|
||||||
|
- Quick navigation
|
||||||
|
- Customizable size and position
|
||||||
|
|
||||||
|
### Rainbow Brackets
|
||||||
|
- Color-coded bracket pairs
|
||||||
|
- Easier to match brackets
|
||||||
|
- Customizable colors
|
||||||
|
|
||||||
|
### Color Picker
|
||||||
|
- Visual color selection
|
||||||
|
- Supports hex, RGB, HSL
|
||||||
|
- Live preview
|
||||||
|
|
||||||
|
### Translation Tool
|
||||||
|
- Translate selected text
|
||||||
|
- Multiple language support
|
||||||
|
- Quick keyboard access
|
||||||
|
|
||||||
|
### Text Highlighting
|
||||||
|
- Highlight important text
|
||||||
|
- Multiple highlight colors
|
||||||
|
- Persistent highlights
|
||||||
|
|
||||||
|
## Multi-Window Support
|
||||||
|
|
||||||
|
Work efficiently with multiple windows:
|
||||||
|
|
||||||
|
- Each window is independent
|
||||||
|
- Separate documents
|
||||||
|
- Synchronized settings
|
||||||
|
- Window state persistence
|
||||||
|
|
||||||
|
## Theme Customization
|
||||||
|
|
||||||
|
Full control over editor appearance:
|
||||||
|
|
||||||
|
### Built-in Themes
|
||||||
|
- Dark mode
|
||||||
|
- Light mode
|
||||||
|
- Auto-switch based on system
|
||||||
|
|
||||||
|
### Custom Themes
|
||||||
|
- Create your own themes
|
||||||
|
- Customize every color
|
||||||
|
- Save and share themes
|
||||||
|
- Import community themes
|
||||||
|
|
||||||
|
## Auto-Update System
|
||||||
|
|
||||||
|
Stay current with automatic updates:
|
||||||
|
|
||||||
|
- Background update checks
|
||||||
|
- Notification of new versions
|
||||||
|
- One-click update
|
||||||
|
- Update history
|
||||||
|
- Support for multiple update sources (GitHub, Gitea)
|
||||||
|
|
||||||
|
## Data Backup
|
||||||
|
|
||||||
|
Secure your data with Git-based backup:
|
||||||
|
|
||||||
|
- Automatic backups
|
||||||
|
- Manual backup triggers
|
||||||
|
- Support for GitHub and Gitea
|
||||||
|
- Multiple authentication methods (SSH, Token, Password)
|
||||||
|
- Configurable backup intervals
|
||||||
|
|
||||||
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
|
Extensive keyboard support:
|
||||||
|
|
||||||
|
- Customizable shortcuts
|
||||||
|
- Vim/Emacs keybindings (planned)
|
||||||
|
- Quick command palette
|
||||||
|
- Context-aware shortcuts
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Built for speed:
|
||||||
|
|
||||||
|
- Fast startup time
|
||||||
|
- Smooth scrolling
|
||||||
|
- Efficient memory usage
|
||||||
|
- Large file support
|
||||||
|
|
||||||
|
## Privacy & Security
|
||||||
|
|
||||||
|
Your data is safe:
|
||||||
|
|
||||||
|
- Local-first storage
|
||||||
|
- Optional cloud backup
|
||||||
|
- No telemetry or tracking
|
||||||
|
- Open source codebase
|
||||||
|
|
||||||
107
frontend/docs/src/guide/getting-started.md
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# Getting Started
|
||||||
|
|
||||||
|
Learn the basics of using voidraft and create your first document.
|
||||||
|
|
||||||
|
## The Editor Interface
|
||||||
|
|
||||||
|
When you open voidraft, you'll see:
|
||||||
|
|
||||||
|
- **Main Editor**: The central area where you write and edit
|
||||||
|
- **Toolbar**: Quick access to common actions
|
||||||
|
- **Status Bar**: Shows current block language and other info
|
||||||
|
|
||||||
|
## Creating Code Blocks
|
||||||
|
|
||||||
|
voidraft uses a block-based editing system. Each block can have a different language:
|
||||||
|
|
||||||
|
1. Press `Ctrl+Enter` to create a new block
|
||||||
|
2. Type `∞∞∞` followed by a language name (e.g., `∞∞∞javascript`)
|
||||||
|
3. Start coding in that block
|
||||||
|
|
||||||
|
### Supported Languages
|
||||||
|
|
||||||
|
voidraft supports 30+ programming languages including:
|
||||||
|
- JavaScript, TypeScript
|
||||||
|
- Python, Go, Rust
|
||||||
|
- HTML, CSS, Sass
|
||||||
|
- SQL, YAML, JSON
|
||||||
|
- And many more...
|
||||||
|
|
||||||
|
## Basic Operations
|
||||||
|
|
||||||
|
### Navigation
|
||||||
|
|
||||||
|
- `Ctrl+Up/Down`: Move between blocks
|
||||||
|
- `Ctrl+Home/End`: Jump to first/last block
|
||||||
|
- `Ctrl+F`: Search within document
|
||||||
|
|
||||||
|
### Editing
|
||||||
|
|
||||||
|
- `Ctrl+D`: Duplicate current line
|
||||||
|
- `Ctrl+/`: Toggle comment
|
||||||
|
- `Alt+Up/Down`: Move line up/down
|
||||||
|
- `Ctrl+Shift+F`: Format code (if language supports Prettier)
|
||||||
|
|
||||||
|
### Block Management
|
||||||
|
|
||||||
|
- `Ctrl+Enter`: Create new block
|
||||||
|
- `Ctrl+Shift+Enter`: Create block above
|
||||||
|
- `Alt+Delete`: Delete current block
|
||||||
|
|
||||||
|
## Using the HTTP Client
|
||||||
|
|
||||||
|
voidraft includes a built-in HTTP client for testing APIs:
|
||||||
|
|
||||||
|
1. Create a block with HTTP language
|
||||||
|
2. Write your HTTP request:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST "https://api.example.com/users" {
|
||||||
|
content-type: "application/json"
|
||||||
|
|
||||||
|
@json {
|
||||||
|
name: "John Doe",
|
||||||
|
email: "john@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Click the run button to execute the request
|
||||||
|
4. View the response inline
|
||||||
|
|
||||||
|
## Multi-Window Support
|
||||||
|
|
||||||
|
Work on multiple documents simultaneously:
|
||||||
|
|
||||||
|
1. Go to `File > New Window` (or `Ctrl+Shift+N`)
|
||||||
|
2. Each window is independent
|
||||||
|
3. Changes are saved automatically
|
||||||
|
|
||||||
|
## Customizing Themes
|
||||||
|
|
||||||
|
Personalize your editor:
|
||||||
|
|
||||||
|
1. Open Settings (`Ctrl+,`)
|
||||||
|
2. Go to Appearance
|
||||||
|
3. Choose a theme or create your own
|
||||||
|
4. Customize colors to your preference
|
||||||
|
|
||||||
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
|
Learn essential shortcuts:
|
||||||
|
|
||||||
|
| Action | Shortcut |
|
||||||
|
|--------|----------|
|
||||||
|
| New Window | `Ctrl+Shift+N` |
|
||||||
|
| Search | `Ctrl+F` |
|
||||||
|
| Replace | `Ctrl+H` |
|
||||||
|
| Format Code | `Ctrl+Shift+F` |
|
||||||
|
| Toggle Theme | `Ctrl+Shift+T` |
|
||||||
|
| Command Palette | `Ctrl+Shift+P` |
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
Now that you know the basics:
|
||||||
|
|
||||||
|
- Explore [Features](/guide/features) in detail
|
||||||
|
|
||||||
63
frontend/docs/src/guide/installation.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
This guide will help you install voidraft on your system.
|
||||||
|
|
||||||
|
## System Requirements
|
||||||
|
|
||||||
|
- **Operating System**: Windows 10 or later (macOS and Linux support planned)
|
||||||
|
- **RAM**: 4GB minimum, 8GB recommended
|
||||||
|
- **Disk Space**: 200MB free space
|
||||||
|
|
||||||
|
## Download
|
||||||
|
|
||||||
|
Visit the [releases page](https://github.com/landaiqing/voidraft/releases) and download the latest version for your platform:
|
||||||
|
|
||||||
|
- **Windows**: `voidraft-windows-amd64-installer.exe`
|
||||||
|
|
||||||
|
## Installation Steps
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
1. Download the installer from the releases page
|
||||||
|
2. Run the `voidraft-windows-amd64-installer.exe` file
|
||||||
|
3. Follow the installation wizard
|
||||||
|
4. Launch voidraft from the Start menu or desktop shortcut
|
||||||
|
|
||||||
|
## First Launch
|
||||||
|
|
||||||
|
When you first launch voidraft:
|
||||||
|
|
||||||
|
1. The application will create a data directory to store your documents
|
||||||
|
2. You'll see the main editor interface with a welcome block
|
||||||
|
3. Start typing or create your first code block!
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
voidraft stores its configuration and data in:
|
||||||
|
|
||||||
|
- **Windows**: `%APPDATA%/voidraft/`
|
||||||
|
|
||||||
|
You can customize various settings including:
|
||||||
|
- Editor theme (dark/light mode)
|
||||||
|
- Code formatting preferences
|
||||||
|
- Backup settings
|
||||||
|
- Keyboard shortcuts
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
|
voidraft includes an auto-update feature that will notify you when new versions are available. You can:
|
||||||
|
|
||||||
|
- Check for updates manually from the settings
|
||||||
|
- Enable automatic updates
|
||||||
|
- Choose your preferred update source
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If you encounter any issues during installation:
|
||||||
|
|
||||||
|
1. Make sure you have administrator privileges
|
||||||
|
2. Check that your antivirus isn't blocking the installation
|
||||||
|
3. Visit our [GitHub issues](https://github.com/landaiqing/voidraft/issues) page for help
|
||||||
|
|
||||||
|
Next: [Getting Started →](/guide/getting-started)
|
||||||
|
|
||||||
50
frontend/docs/src/guide/introduction.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Introduction
|
||||||
|
|
||||||
|
Welcome to voidraft - an elegant text snippet recording tool designed specifically for developers.
|
||||||
|
|
||||||
|
## What is voidraft?
|
||||||
|
|
||||||
|
voidraft is a modern desktop application that helps developers manage text snippets, code blocks, API responses, meeting notes, and daily to-do lists. It provides a smooth and elegant editing experience with powerful features tailored for development workflows.
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
### Block-Based Editing
|
||||||
|
|
||||||
|
voidraft uses a unique block-based editing system inspired by Heynote. You can split your content into independent code blocks, each with:
|
||||||
|
- Different programming language settings
|
||||||
|
- Syntax highlighting
|
||||||
|
- Independent formatting
|
||||||
|
- Easy navigation between blocks
|
||||||
|
|
||||||
|
### Developer Tools
|
||||||
|
|
||||||
|
- **HTTP Client**: Test APIs directly within the editor
|
||||||
|
- **Code Formatting**: Built-in Prettier support for multiple languages
|
||||||
|
- **Syntax Highlighting**: Support for 30+ programming languages
|
||||||
|
- **Auto Language Detection**: Automatically recognizes code block language types
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
|
||||||
|
- **Custom Themes**: Create and save your own editor themes
|
||||||
|
- **Extensions**: Rich set of editor extensions including minimap, rainbow brackets, color picker, and more
|
||||||
|
- **Multi-Window**: Work on multiple documents simultaneously
|
||||||
|
|
||||||
|
### Data Management
|
||||||
|
|
||||||
|
- **Git-Based Backup**: Automatic backup using Git repositories
|
||||||
|
- **Cloud Sync**: Sync your data across devices
|
||||||
|
- **Auto-Update**: Stay up-to-date with the latest features
|
||||||
|
|
||||||
|
## Why voidraft?
|
||||||
|
|
||||||
|
- **Developer-Focused**: Built with developers' needs in mind
|
||||||
|
- **Modern Stack**: Uses cutting-edge technologies (Wails3, Vue 3, CodeMirror 6)
|
||||||
|
- **Cross-Platform**: Works on Windows (macOS and Linux support planned)
|
||||||
|
- **Open Source**: MIT licensed, community-driven development
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Ready to start? Download the latest version from our [releases page](https://github.com/landaiqing/voidraft/releases) or continue reading the documentation to learn more.
|
||||||
|
|
||||||
|
Next: [Installation →](/guide/installation)
|
||||||
|
|
||||||
56
frontend/docs/src/index.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: "voidraft"
|
||||||
|
text: "An elegant text snippet recording tool"
|
||||||
|
tagline: Designed for developers, built with modern technology
|
||||||
|
image:
|
||||||
|
src: /img/hero.png
|
||||||
|
alt: "voidraft"
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: Get Started
|
||||||
|
link: https://github.com/landaiqing/voidraft/releases
|
||||||
|
- theme: alt
|
||||||
|
text: Documentation
|
||||||
|
link: /guide/introduction
|
||||||
|
|
||||||
|
features:
|
||||||
|
- icon: 📝
|
||||||
|
title: Block-Based Editing
|
||||||
|
details: Split your content into independent code blocks, each with different language settings. Inspired by Heynote's innovative design philosophy.
|
||||||
|
|
||||||
|
- icon: 🎨
|
||||||
|
title: Syntax Highlighting
|
||||||
|
details: Built-in support for 30+ programming languages with automatic language detection and Prettier integration for code formatting.
|
||||||
|
|
||||||
|
- icon: 🌐
|
||||||
|
title: HTTP Client
|
||||||
|
details: Integrated HTTP client with support for multiple request formats including JSON, FormData, XML, and more. Test APIs directly within the editor.
|
||||||
|
|
||||||
|
- icon: 🎯
|
||||||
|
title: Multi-Window Support
|
||||||
|
details: Work on multiple documents simultaneously with independent windows. Each window maintains its own state and configuration.
|
||||||
|
|
||||||
|
- icon: 🎭
|
||||||
|
title: Customizable Themes
|
||||||
|
details: Full theme customization support with dark/light modes. Create and save your own editor themes to match your preferences.
|
||||||
|
|
||||||
|
- icon: 🔧
|
||||||
|
title: Rich Extensions
|
||||||
|
details: VSCode-style search and replace, rainbow brackets, minimap, color picker, translation tool, text highlighting, and more.
|
||||||
|
|
||||||
|
- icon: 🔄
|
||||||
|
title: Auto-Update System
|
||||||
|
details: Built-in self-update mechanism with support for multiple update sources. Stay up-to-date with the latest features and improvements.
|
||||||
|
|
||||||
|
- icon: ☁️
|
||||||
|
title: Git-Based Backup
|
||||||
|
details: Automatic data backup using Git repositories. Supports GitHub, Gitea, with multiple authentication methods including SSH and tokens.
|
||||||
|
|
||||||
|
- icon: ⚡
|
||||||
|
title: Modern Architecture
|
||||||
|
details: Built with Wails3, Vue 3, and CodeMirror 6. Cross-platform desktop application with native performance and modern UI.
|
||||||
|
|
||||||
|
---
|
||||||
BIN
frontend/docs/src/public/icon/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
frontend/docs/src/public/icon/favicon-96x96.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
frontend/docs/src/public/icon/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
3
frontend/docs/src/public/icon/favicon.svg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
21
frontend/docs/src/public/icon/site.webmanifest
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "voidraft",
|
||||||
|
"short_name": "voidraft",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/img/web-app-manifest-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/img/web-app-manifest-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
BIN
frontend/docs/src/public/icon/web-app-manifest-192x192.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
frontend/docs/src/public/icon/web-app-manifest-512x512.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
frontend/docs/src/public/img/hero.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
163
frontend/docs/src/zh/guide/features.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# 功能特性
|
||||||
|
|
||||||
|
探索 voidraft 的强大功能,让它成为开发者的优秀工具。
|
||||||
|
|
||||||
|
## 块状编辑
|
||||||
|
|
||||||
|
voidraft 的核心功能是其块状编辑系统:
|
||||||
|
|
||||||
|
- 每个块可以有不同的编程语言
|
||||||
|
- 块之间由分隔符分隔(`∞∞∞语言`)
|
||||||
|
- 快速在块之间导航
|
||||||
|
- 独立格式化每个块
|
||||||
|
|
||||||
|
## 语法高亮
|
||||||
|
|
||||||
|
支持 30+ 种语言的专业语法高亮:
|
||||||
|
|
||||||
|
- 自动语言检测
|
||||||
|
- 可自定义配色方案
|
||||||
|
- 支持嵌套语言
|
||||||
|
- 代码折叠支持
|
||||||
|
|
||||||
|
## HTTP 客户端
|
||||||
|
|
||||||
|
用于 API 测试的内置 HTTP 客户端:
|
||||||
|
|
||||||
|
### 请求类型
|
||||||
|
- GET、POST、PUT、DELETE、PATCH
|
||||||
|
- 自定义请求头
|
||||||
|
- 多种请求体格式:JSON、FormData、URL 编码、XML、文本
|
||||||
|
|
||||||
|
### 请求变量
|
||||||
|
定义和重用变量:
|
||||||
|
|
||||||
|
```http
|
||||||
|
@var {
|
||||||
|
baseUrl: "https://api.example.com",
|
||||||
|
token: "your-api-token"
|
||||||
|
}
|
||||||
|
|
||||||
|
GET "{{baseUrl}}/users" {
|
||||||
|
authorization: "Bearer {{token}}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应处理
|
||||||
|
- 查看格式化的 JSON 响应
|
||||||
|
- 查看响应时间和大小
|
||||||
|
- 检查响应头
|
||||||
|
- 保存响应以供日后使用
|
||||||
|
|
||||||
|
## 代码格式化
|
||||||
|
|
||||||
|
集成 Prettier 支持:
|
||||||
|
|
||||||
|
- 保存时格式化(可选)
|
||||||
|
- 格式化选区或整个块
|
||||||
|
- 支持 JavaScript、TypeScript、CSS、HTML、JSON 等
|
||||||
|
- 可自定义格式化规则
|
||||||
|
|
||||||
|
## 编辑器扩展
|
||||||
|
|
||||||
|
### VSCode 风格搜索
|
||||||
|
- 查找和替换,支持正则表达式
|
||||||
|
- 区分大小写和全字匹配选项
|
||||||
|
- 跨所有块搜索
|
||||||
|
|
||||||
|
### 小地图
|
||||||
|
- 文档的鸟瞰图
|
||||||
|
- 快速导航
|
||||||
|
- 可自定义大小和位置
|
||||||
|
|
||||||
|
### 彩虹括号
|
||||||
|
- 彩色括号配对
|
||||||
|
- 更容易匹配括号
|
||||||
|
- 可自定义颜色
|
||||||
|
|
||||||
|
### 颜色选择器
|
||||||
|
- 可视化颜色选择
|
||||||
|
- 支持 hex、RGB、HSL
|
||||||
|
- 实时预览
|
||||||
|
|
||||||
|
### 翻译工具
|
||||||
|
- 翻译选定的文本
|
||||||
|
- 支持多种语言
|
||||||
|
- 快速键盘访问
|
||||||
|
|
||||||
|
### 文本高亮
|
||||||
|
- 高亮重要文本
|
||||||
|
- 多种高亮颜色
|
||||||
|
- 持久化高亮
|
||||||
|
|
||||||
|
## 多窗口支持
|
||||||
|
|
||||||
|
高效使用多个窗口:
|
||||||
|
|
||||||
|
- 每个窗口都是独立的
|
||||||
|
- 独立的文档
|
||||||
|
- 同步的设置
|
||||||
|
- 窗口状态持久化
|
||||||
|
|
||||||
|
## 主题自定义
|
||||||
|
|
||||||
|
完全控制编辑器外观:
|
||||||
|
|
||||||
|
### 内置主题
|
||||||
|
- 深色模式
|
||||||
|
- 浅色模式
|
||||||
|
- 根据系统自动切换
|
||||||
|
|
||||||
|
### 自定义主题
|
||||||
|
- 创建你自己的主题
|
||||||
|
- 自定义每种颜色
|
||||||
|
- 保存和分享主题
|
||||||
|
- 导入社区主题
|
||||||
|
|
||||||
|
## 自动更新系统
|
||||||
|
|
||||||
|
通过自动更新保持最新:
|
||||||
|
|
||||||
|
- 后台更新检查
|
||||||
|
- 新版本通知
|
||||||
|
- 一键更新
|
||||||
|
- 更新历史
|
||||||
|
- 支持多个更新源(GitHub、Gitea)
|
||||||
|
|
||||||
|
## 数据备份
|
||||||
|
|
||||||
|
使用基于 Git 的备份保护你的数据:
|
||||||
|
|
||||||
|
- 自动备份
|
||||||
|
- 手动触发备份
|
||||||
|
- 支持 GitHub 和 Gitea
|
||||||
|
- 多种认证方式(SSH、Token、密码)
|
||||||
|
- 可配置备份间隔
|
||||||
|
|
||||||
|
## 键盘快捷键
|
||||||
|
|
||||||
|
广泛的键盘支持:
|
||||||
|
|
||||||
|
- 可自定义快捷键
|
||||||
|
- Vim/Emacs 按键绑定(计划中)
|
||||||
|
- 快速命令面板
|
||||||
|
- 上下文感知快捷键
|
||||||
|
|
||||||
|
## 性能
|
||||||
|
|
||||||
|
专为速度而构建:
|
||||||
|
|
||||||
|
- 快速启动时间
|
||||||
|
- 流畅滚动
|
||||||
|
- 高效内存使用
|
||||||
|
- 支持大文件
|
||||||
|
|
||||||
|
## 隐私与安全
|
||||||
|
|
||||||
|
你的数据是安全的:
|
||||||
|
|
||||||
|
- 本地优先存储
|
||||||
|
- 可选云备份
|
||||||
|
- 无遥测或跟踪
|
||||||
|
- 开源代码库
|
||||||
|
|
||||||
107
frontend/docs/src/zh/guide/getting-started.md
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# 快速开始
|
||||||
|
|
||||||
|
学习使用 voidraft 的基础知识并创建你的第一个文档。
|
||||||
|
|
||||||
|
## 编辑器界面
|
||||||
|
|
||||||
|
当你打开 voidraft 时,你将看到:
|
||||||
|
|
||||||
|
- **主编辑器**:编写和编辑的中心区域
|
||||||
|
- **工具栏**:快速访问常用操作
|
||||||
|
- **状态栏**:显示当前块的语言和其他信息
|
||||||
|
|
||||||
|
## 创建代码块
|
||||||
|
|
||||||
|
voidraft 使用基于块的编辑系统。每个块可以有不同的语言:
|
||||||
|
|
||||||
|
1. 按 `Ctrl+Enter` 创建新块
|
||||||
|
2. 输入 `∞∞∞` 后跟语言名称(例如 `∞∞∞javascript`)
|
||||||
|
3. 在该块中开始编码
|
||||||
|
|
||||||
|
### 支持的语言
|
||||||
|
|
||||||
|
voidraft 支持 30+ 种编程语言,包括:
|
||||||
|
- JavaScript、TypeScript
|
||||||
|
- Python、Go、Rust
|
||||||
|
- HTML、CSS、Sass
|
||||||
|
- SQL、YAML、JSON
|
||||||
|
- 以及更多...
|
||||||
|
|
||||||
|
## 基本操作
|
||||||
|
|
||||||
|
### 导航
|
||||||
|
|
||||||
|
- `Ctrl+Up/Down`:在块之间移动
|
||||||
|
- `Ctrl+Home/End`:跳转到第一个/最后一个块
|
||||||
|
- `Ctrl+F`:在文档中搜索
|
||||||
|
|
||||||
|
### 编辑
|
||||||
|
|
||||||
|
- `Ctrl+D`:复制当前行
|
||||||
|
- `Ctrl+/`:切换注释
|
||||||
|
- `Alt+Up/Down`:向上/向下移动行
|
||||||
|
- `Ctrl+Shift+F`:格式化代码(如果语言支持 Prettier)
|
||||||
|
|
||||||
|
### 块管理
|
||||||
|
|
||||||
|
- `Ctrl+Enter`:创建新块
|
||||||
|
- `Ctrl+Shift+Enter`:在上方创建块
|
||||||
|
- `Alt+Delete`:删除当前块
|
||||||
|
|
||||||
|
## 使用 HTTP 客户端
|
||||||
|
|
||||||
|
voidraft 包含用于测试 API 的内置 HTTP 客户端:
|
||||||
|
|
||||||
|
1. 创建一个 HTTP 语言的块
|
||||||
|
2. 编写你的 HTTP 请求:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST "https://api.example.com/users" {
|
||||||
|
content-type: "application/json"
|
||||||
|
|
||||||
|
@json {
|
||||||
|
name: "张三",
|
||||||
|
email: "zhangsan@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 点击运行按钮执行请求
|
||||||
|
4. 内联查看响应
|
||||||
|
|
||||||
|
## 多窗口支持
|
||||||
|
|
||||||
|
同时处理多个文档:
|
||||||
|
|
||||||
|
1. 转到 `文件 > 新建窗口`(或 `Ctrl+Shift+N`)
|
||||||
|
2. 每个窗口都是独立的
|
||||||
|
3. 更改会自动保存
|
||||||
|
|
||||||
|
## 自定义主题
|
||||||
|
|
||||||
|
个性化你的编辑器:
|
||||||
|
|
||||||
|
1. 打开设置(`Ctrl+,`)
|
||||||
|
2. 转到外观
|
||||||
|
3. 选择主题或创建自己的主题
|
||||||
|
4. 根据你的偏好自定义颜色
|
||||||
|
|
||||||
|
## 键盘快捷键
|
||||||
|
|
||||||
|
学习基本快捷键:
|
||||||
|
|
||||||
|
| 操作 | 快捷键 |
|
||||||
|
|-----|--------|
|
||||||
|
| 新建窗口 | `Ctrl+Shift+N` |
|
||||||
|
| 搜索 | `Ctrl+F` |
|
||||||
|
| 替换 | `Ctrl+H` |
|
||||||
|
| 格式化代码 | `Ctrl+Shift+F` |
|
||||||
|
| 切换主题 | `Ctrl+Shift+T` |
|
||||||
|
| 命令面板 | `Ctrl+Shift+P` |
|
||||||
|
|
||||||
|
## 下一步
|
||||||
|
|
||||||
|
现在你已经了解了基础知识:
|
||||||
|
|
||||||
|
- 详细探索[功能特性](/zh/guide/features)
|
||||||
|
|
||||||
63
frontend/docs/src/zh/guide/installation.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 安装
|
||||||
|
|
||||||
|
本指南将帮助你在系统上安装 voidraft。
|
||||||
|
|
||||||
|
## 系统要求
|
||||||
|
|
||||||
|
- **操作系统**:Windows 10 或更高版本(macOS 和 Linux 支持计划中)
|
||||||
|
- **内存**:最低 4GB,推荐 8GB
|
||||||
|
- **磁盘空间**:200MB 可用空间
|
||||||
|
|
||||||
|
## 下载
|
||||||
|
|
||||||
|
访问[发布页面](https://github.com/landaiqing/voidraft/releases)并下载适合你平台的最新版本:
|
||||||
|
|
||||||
|
- **Windows**:`voidraft-windows-amd64-installer.exe`
|
||||||
|
|
||||||
|
## 安装步骤
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
1. 从发布页面下载安装程序
|
||||||
|
2. 运行 `voidraft-windows-amd64-installer.exe` 文件
|
||||||
|
3. 按照安装向导操作
|
||||||
|
4. 从开始菜单或桌面快捷方式启动 voidraft
|
||||||
|
|
||||||
|
## 首次启动
|
||||||
|
|
||||||
|
首次启动 voidraft 时:
|
||||||
|
|
||||||
|
1. 应用程序将创建一个数据目录来存储你的文档
|
||||||
|
2. 你将看到带有欢迎块的主编辑器界面
|
||||||
|
3. 开始输入或创建你的第一个代码块!
|
||||||
|
|
||||||
|
## 配置
|
||||||
|
|
||||||
|
voidraft 将其配置和数据存储在:
|
||||||
|
|
||||||
|
- **Windows**:`%APPDATA%/voidraft/`
|
||||||
|
|
||||||
|
你可以自定义各种设置,包括:
|
||||||
|
- 编辑器主题(深色/浅色模式)
|
||||||
|
- 代码格式化偏好
|
||||||
|
- 备份设置
|
||||||
|
- 键盘快捷键
|
||||||
|
|
||||||
|
## 更新
|
||||||
|
|
||||||
|
voidraft 包含自动更新功能,会在有新版本时通知你。你可以:
|
||||||
|
|
||||||
|
- 从设置中手动检查更新
|
||||||
|
- 启用自动更新
|
||||||
|
- 选择首选的更新源
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
如果在安装过程中遇到任何问题:
|
||||||
|
|
||||||
|
1. 确保你有管理员权限
|
||||||
|
2. 检查杀毒软件是否阻止了安装
|
||||||
|
3. 访问我们的 [GitHub issues](https://github.com/landaiqing/voidraft/issues) 页面寻求帮助
|
||||||
|
|
||||||
|
下一步:[快速开始 →](/zh/guide/getting-started)
|
||||||
|
|
||||||
50
frontend/docs/src/zh/guide/introduction.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# 简介
|
||||||
|
|
||||||
|
欢迎使用 voidraft —— 一个专为开发者设计的优雅文本片段记录工具。
|
||||||
|
|
||||||
|
## 什么是 voidraft?
|
||||||
|
|
||||||
|
voidraft 是一个现代化的桌面应用程序,帮助开发者管理文本片段、代码块、API 响应、会议笔记和日常待办事项。它为开发工作流程提供了流畅而优雅的编辑体验和强大的功能。
|
||||||
|
|
||||||
|
## 核心特性
|
||||||
|
|
||||||
|
### 块状编辑模式
|
||||||
|
|
||||||
|
voidraft 使用受 Heynote 启发的独特块状编辑系统。你可以将内容分割为独立的代码块,每个块具有:
|
||||||
|
- 不同的编程语言设置
|
||||||
|
- 语法高亮
|
||||||
|
- 独立格式化
|
||||||
|
- 轻松在块之间导航
|
||||||
|
|
||||||
|
### 开发者工具
|
||||||
|
|
||||||
|
- **HTTP 客户端**:直接在编辑器中测试 API
|
||||||
|
- **代码格式化**:内置 Prettier 支持多种语言
|
||||||
|
- **语法高亮**:支持 30+ 种编程语言
|
||||||
|
- **自动语言检测**:自动识别代码块语言类型
|
||||||
|
|
||||||
|
### 自定义
|
||||||
|
|
||||||
|
- **自定义主题**:创建并保存你自己的编辑器主题
|
||||||
|
- **扩展功能**:丰富的编辑器扩展,包括小地图、彩虹括号、颜色选择器等
|
||||||
|
- **多窗口**:同时处理多个文档
|
||||||
|
|
||||||
|
### 数据管理
|
||||||
|
|
||||||
|
- **Git 备份**:使用 Git 仓库自动备份
|
||||||
|
- **云同步**:跨设备同步你的数据
|
||||||
|
- **自动更新**:及时获取最新功能
|
||||||
|
|
||||||
|
## 为什么选择 voidraft?
|
||||||
|
|
||||||
|
- **专注开发者**:考虑开发者需求而构建
|
||||||
|
- **现代技术栈**:使用前沿技术(Wails3、Vue 3、CodeMirror 6)
|
||||||
|
- **跨平台**:支持 Windows(macOS 和 Linux 支持计划中)
|
||||||
|
- **开源**:MIT 许可证,社区驱动开发
|
||||||
|
|
||||||
|
## 开始使用
|
||||||
|
|
||||||
|
准备好开始了吗?从我们的[发布页面](https://github.com/landaiqing/voidraft/releases)下载最新版本,或继续阅读文档了解更多。
|
||||||
|
|
||||||
|
下一步:[安装 →](/zh/guide/installation)
|
||||||
|
|
||||||
56
frontend/docs/src/zh/index.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: "voidraft"
|
||||||
|
text: "优雅的文本片段记录工具"
|
||||||
|
tagline: 为开发者设计,用现代技术打造
|
||||||
|
image:
|
||||||
|
src: /img/hero.png
|
||||||
|
alt: "voidraft"
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: 开始使用
|
||||||
|
link: https://github.com/landaiqing/voidraft/releases
|
||||||
|
- theme: alt
|
||||||
|
text: 使用文档
|
||||||
|
link: /zh/guide/introduction
|
||||||
|
|
||||||
|
features:
|
||||||
|
- icon: 📝
|
||||||
|
title: 块状编辑模式
|
||||||
|
details: 将内容分割为独立的代码块,每个块可设置不同语言。继承了 Heynote 优雅的块状编辑理念。
|
||||||
|
|
||||||
|
- icon: 🎨
|
||||||
|
title: 语法高亮
|
||||||
|
details: 内置支持 30+ 种编程语言的语法高亮,自动语言检测,集成 Prettier 代码格式化工具。
|
||||||
|
|
||||||
|
- icon: 🌐
|
||||||
|
title: HTTP 客户端
|
||||||
|
details: 集成 HTTP 客户端,支持 JSON、FormData、XML 等多种请求格式。直接在编辑器中测试 API。
|
||||||
|
|
||||||
|
- icon: 🎯
|
||||||
|
title: 多窗口支持
|
||||||
|
details: 同时编辑多个文档,每个窗口独立维护自己的状态和配置。
|
||||||
|
|
||||||
|
- icon: 🎭
|
||||||
|
title: 主题自定义
|
||||||
|
details: 完整的主题自定义支持,支持深色/浅色模式。创建并保存你自己的编辑器主题。
|
||||||
|
|
||||||
|
- icon: 🔧
|
||||||
|
title: 丰富的扩展
|
||||||
|
details: VSCode 风格搜索替换、彩虹括号、小地图、颜色选择器、翻译工具、文本高亮等实用扩展。
|
||||||
|
|
||||||
|
- icon: 🔄
|
||||||
|
title: 自动更新系统
|
||||||
|
details: 内置自我更新机制,支持多个更新源。及时获取最新功能和改进。
|
||||||
|
|
||||||
|
- icon: ☁️
|
||||||
|
title: Git 备份
|
||||||
|
details: 基于 Git 的自动数据备份。支持 GitHub、Gitea,提供 SSH、Token 等多种认证方式。
|
||||||
|
|
||||||
|
- icon: ⚡
|
||||||
|
title: 现代化架构
|
||||||
|
details: 采用 Wails3、Vue 3 和 CodeMirror 6 构建。跨平台桌面应用,原生性能,现代化界面。
|
||||||
|
|
||||||
|
---
|
||||||
@@ -50,7 +50,11 @@ export default defineConfig([
|
|||||||
'.local',
|
'.local',
|
||||||
'/bin',
|
'/bin',
|
||||||
'Dockerfile',
|
'Dockerfile',
|
||||||
'**/bindings/'
|
'**/bindings/',
|
||||||
|
'*.js',
|
||||||
|
'**/*.js',
|
||||||
|
'**/*.cjs',
|
||||||
|
'**/*.mjs',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
6028
frontend/package-lock.json
generated
@@ -9,82 +9,102 @@
|
|||||||
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vue-tsc && cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vite build --mode production",
|
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vue-tsc && cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vite build --mode production",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
"lint:fix": "eslint --fix"
|
"lint:fix": "eslint --fix",
|
||||||
|
"build:lang-parser": "node src/views/editor/extensions/codeblock/lang-parser/build-parser.js",
|
||||||
|
"build:mermaid-parser": "node src/views/editor/language/mermaid/build-parsers.js",
|
||||||
|
"test": "vitest",
|
||||||
|
"docs:dev": "vitepress dev docs",
|
||||||
|
"docs:build": "vitepress build docs",
|
||||||
|
"docs:preview": "vitepress preview docs",
|
||||||
|
"app:dev": "cd .. &&wails3 dev",
|
||||||
|
"app:build": "cd .. && wails3 task build",
|
||||||
|
"app:package": "cd .. && wails3 package",
|
||||||
|
"app:generate": "cd .. && wails3 generate bindings -ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.18.7",
|
"@codemirror/autocomplete": "^6.19.1",
|
||||||
"@codemirror/commands": "^6.8.1",
|
"@codemirror/commands": "^6.10.0",
|
||||||
"@codemirror/lang-angular": "^0.1.4",
|
"@codemirror/lang-angular": "^0.1.4",
|
||||||
"@codemirror/lang-cpp": "^6.0.3",
|
"@codemirror/lang-cpp": "^6.0.3",
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
"@codemirror/lang-go": "^6.0.1",
|
"@codemirror/lang-go": "^6.0.1",
|
||||||
"@codemirror/lang-html": "^6.4.10",
|
"@codemirror/lang-html": "^6.4.11",
|
||||||
"@codemirror/lang-java": "^6.0.2",
|
"@codemirror/lang-java": "^6.0.2",
|
||||||
"@codemirror/lang-javascript": "^6.2.4",
|
"@codemirror/lang-javascript": "^6.2.4",
|
||||||
"@codemirror/lang-json": "^6.0.2",
|
"@codemirror/lang-json": "^6.0.2",
|
||||||
"@codemirror/lang-less": "^6.0.2",
|
"@codemirror/lang-less": "^6.0.2",
|
||||||
"@codemirror/lang-lezer": "^6.0.2",
|
"@codemirror/lang-lezer": "^6.0.2",
|
||||||
"@codemirror/lang-liquid": "^6.3.0",
|
"@codemirror/lang-liquid": "^6.3.0",
|
||||||
"@codemirror/lang-markdown": "^6.3.4",
|
"@codemirror/lang-markdown": "^6.5.0",
|
||||||
"@codemirror/lang-php": "^6.0.2",
|
"@codemirror/lang-php": "^6.0.2",
|
||||||
"@codemirror/lang-python": "^6.2.1",
|
"@codemirror/lang-python": "^6.2.1",
|
||||||
"@codemirror/lang-rust": "^6.0.2",
|
"@codemirror/lang-rust": "^6.0.2",
|
||||||
"@codemirror/lang-sass": "^6.0.2",
|
"@codemirror/lang-sass": "^6.0.2",
|
||||||
"@codemirror/lang-sql": "^6.9.1",
|
"@codemirror/lang-sql": "^6.10.0",
|
||||||
"@codemirror/lang-vue": "^0.1.3",
|
"@codemirror/lang-vue": "^0.1.3",
|
||||||
"@codemirror/lang-wast": "^6.0.2",
|
"@codemirror/lang-wast": "^6.0.2",
|
||||||
"@codemirror/lang-yaml": "^6.1.2",
|
"@codemirror/lang-yaml": "^6.1.2",
|
||||||
"@codemirror/language": "^6.11.3",
|
"@codemirror/language": "^6.11.3",
|
||||||
"@codemirror/language-data": "^6.5.1",
|
"@codemirror/language-data": "^6.5.2",
|
||||||
"@codemirror/legacy-modes": "^6.5.1",
|
"@codemirror/legacy-modes": "^6.5.2",
|
||||||
"@codemirror/lint": "^6.8.5",
|
"@codemirror/lint": "^6.9.2",
|
||||||
"@codemirror/search": "^6.5.11",
|
"@codemirror/search": "^6.5.11",
|
||||||
"@codemirror/state": "^6.5.2",
|
"@codemirror/state": "^6.5.2",
|
||||||
"@codemirror/view": "^6.38.2",
|
"@codemirror/view": "^6.38.6",
|
||||||
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
||||||
"@lezer/highlight": "^1.2.1",
|
"@lezer/highlight": "^1.2.3",
|
||||||
"@lezer/lr": "^1.4.2",
|
"@lezer/lr": "^1.4.3",
|
||||||
|
"@mdit/plugin-katex": "^0.23.2",
|
||||||
|
"@mdit/plugin-tasklist": "^0.22.2",
|
||||||
"@prettier/plugin-xml": "^3.4.2",
|
"@prettier/plugin-xml": "^3.4.2",
|
||||||
|
"@replit/codemirror-lang-svelte": "^6.0.0",
|
||||||
"@toml-tools/lexer": "^1.0.0",
|
"@toml-tools/lexer": "^1.0.0",
|
||||||
"@toml-tools/parser": "^1.0.0",
|
"@toml-tools/parser": "^1.0.0",
|
||||||
|
"@types/markdown-it": "^14.1.2",
|
||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
"codemirror-lang-elixir": "^4.0.0",
|
"codemirror-lang-elixir": "^4.0.0",
|
||||||
"colors-named": "^1.0.2",
|
"colors-named": "^1.0.2",
|
||||||
"colors-named-hex": "^1.0.2",
|
"colors-named-hex": "^1.0.2",
|
||||||
"franc-min": "^6.2.0",
|
|
||||||
"groovy-beautify": "^0.0.17",
|
"groovy-beautify": "^0.0.17",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
"hsl-matcher": "^1.2.4",
|
"hsl-matcher": "^1.2.4",
|
||||||
"java-parser": "^3.0.1",
|
"java-parser": "^3.0.1",
|
||||||
"jsox": "^1.2.123",
|
"linguist-languages": "^9.1.0",
|
||||||
"linguist-languages": "^9.0.0",
|
"markdown-it": "^14.1.0",
|
||||||
|
"mermaid": "^11.12.1",
|
||||||
|
"npm": "^11.6.2",
|
||||||
"php-parser": "^3.2.5",
|
"php-parser": "^3.2.5",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.4",
|
||||||
"pinia-plugin-persistedstate": "^4.5.0",
|
"pinia-plugin-persistedstate": "^4.7.1",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"remarkable": "^2.0.1",
|
"sass": "^1.94.0",
|
||||||
"sass": "^1.92.1",
|
"vue": "^3.5.24",
|
||||||
"vue": "^3.5.21",
|
|
||||||
"vue-i18n": "^11.1.12",
|
"vue-i18n": "^11.1.12",
|
||||||
"vue-pick-colors": "^1.8.0",
|
"vue-pick-colors": "^1.8.0",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.6.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.35.0",
|
"@eslint/js": "^9.39.1",
|
||||||
"@lezer/generator": "^1.8.0",
|
"@lezer/generator": "^1.8.0",
|
||||||
"@types/node": "^24.3.1",
|
"@types/node": "^24.9.2",
|
||||||
"@types/remarkable": "^2.0.8",
|
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@wailsio/runtime": "latest",
|
"@wailsio/runtime": "latest",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^10.1.0",
|
||||||
"eslint": "^9.35.0",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-vue": "^10.4.0",
|
"eslint-plugin-vue": "^10.5.1",
|
||||||
"globals": "^16.4.0",
|
"globals": "^16.5.0",
|
||||||
"typescript": "^5.9.2",
|
"happy-dom": "^20.0.10",
|
||||||
"typescript-eslint": "^8.43.0",
|
"typescript": "^5.9.3",
|
||||||
"unplugin-vue-components": "^29.0.0",
|
"typescript-eslint": "^8.46.4",
|
||||||
"vite": "^7.1.5",
|
"unplugin-vue-components": "^30.0.0",
|
||||||
|
"vite": "npm:rolldown-vite@latest",
|
||||||
"vite-plugin-node-polyfills": "^0.24.0",
|
"vite-plugin-node-polyfills": "^0.24.0",
|
||||||
|
"vitepress": "^2.0.0-alpha.12",
|
||||||
|
"vitest": "^4.0.8",
|
||||||
"vue-eslint-parser": "^10.2.0",
|
"vue-eslint-parser": "^10.2.0",
|
||||||
"vue-tsc": "^3.0.6"
|
"vue-tsc": "^3.1.3"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"vite": "npm:rolldown-vite@latest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {onMounted} from 'vue';
|
import {onBeforeMount} from 'vue';
|
||||||
import {useConfigStore} from '@/stores/configStore';
|
import {useConfigStore} from '@/stores/configStore';
|
||||||
import {useSystemStore} from '@/stores/systemStore';
|
import {useSystemStore} from '@/stores/systemStore';
|
||||||
import {useKeybindingStore} from '@/stores/keybindingStore';
|
import {useKeybindingStore} from '@/stores/keybindingStore';
|
||||||
import {useThemeStore} from '@/stores/themeStore';
|
import {useThemeStore} from '@/stores/themeStore';
|
||||||
import {useUpdateStore} from '@/stores/updateStore';
|
import {useUpdateStore} from '@/stores/updateStore';
|
||||||
import {useBackupStore} from '@/stores/backupStore';
|
|
||||||
import WindowTitleBar from '@/components/titlebar/WindowTitleBar.vue';
|
import WindowTitleBar from '@/components/titlebar/WindowTitleBar.vue';
|
||||||
|
import {useTranslationStore} from "@/stores/translationStore";
|
||||||
|
|
||||||
const configStore = useConfigStore();
|
const configStore = useConfigStore();
|
||||||
const systemStore = useSystemStore();
|
const systemStore = useSystemStore();
|
||||||
const keybindingStore = useKeybindingStore();
|
const keybindingStore = useKeybindingStore();
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const updateStore = useUpdateStore();
|
const updateStore = useUpdateStore();
|
||||||
const backupStore = useBackupStore();
|
const translationStore = useTranslationStore();
|
||||||
|
|
||||||
// 应用启动时加载配置和初始化系统信息
|
onBeforeMount(async () => {
|
||||||
onMounted(async () => {
|
|
||||||
// 并行初始化配置、系统信息和快捷键配置
|
// 并行初始化配置、系统信息和快捷键配置
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
configStore.initConfig(),
|
configStore.initConfig(),
|
||||||
@@ -26,11 +25,9 @@ onMounted(async () => {
|
|||||||
|
|
||||||
// 初始化语言和主题
|
// 初始化语言和主题
|
||||||
await configStore.initializeLanguage();
|
await configStore.initializeLanguage();
|
||||||
themeStore.initializeTheme();
|
await themeStore.initializeTheme();
|
||||||
|
await translationStore.loadTranslators();
|
||||||
// 初始化备份服务
|
|
||||||
await backupStore.initialize();
|
|
||||||
|
|
||||||
// 启动时检查更新
|
// 启动时检查更新
|
||||||
await updateStore.checkOnStartup();
|
await updateStore.checkOnStartup();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,254 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
鸿蒙字体压缩工具
|
|
||||||
使用 fonttools 库压缩 TTF 字体文件,减小文件大小
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import List, Tuple
|
|
||||||
|
|
||||||
def check_dependencies():
|
|
||||||
"""检查必要的依赖是否已安装"""
|
|
||||||
missing_packages = []
|
|
||||||
|
|
||||||
# 检查 fonttools
|
|
||||||
try:
|
|
||||||
import fontTools
|
|
||||||
except ImportError:
|
|
||||||
missing_packages.append('fonttools')
|
|
||||||
|
|
||||||
# 检查 brotli
|
|
||||||
try:
|
|
||||||
import brotli
|
|
||||||
except ImportError:
|
|
||||||
missing_packages.append('brotli')
|
|
||||||
|
|
||||||
# 检查 pyftsubset 命令是否可用
|
|
||||||
try:
|
|
||||||
result = subprocess.run(['pyftsubset', '--help'], capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
missing_packages.append('fonttools[subset]')
|
|
||||||
except FileNotFoundError:
|
|
||||||
if 'fonttools' not in missing_packages:
|
|
||||||
missing_packages.append('fonttools[subset]')
|
|
||||||
|
|
||||||
if missing_packages:
|
|
||||||
print(f"缺少必要的依赖包: {', '.join(missing_packages)}")
|
|
||||||
print("请运行以下命令安装:")
|
|
||||||
print(f"pip install {' '.join(missing_packages)}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_file_size(file_path: str) -> int:
|
|
||||||
"""获取文件大小(字节)"""
|
|
||||||
return os.path.getsize(file_path)
|
|
||||||
|
|
||||||
def format_file_size(size_bytes: int) -> str:
|
|
||||||
"""格式化文件大小显示"""
|
|
||||||
if size_bytes < 1024:
|
|
||||||
return f"{size_bytes} B"
|
|
||||||
elif size_bytes < 1024 * 1024:
|
|
||||||
return f"{size_bytes / 1024:.2f} KB"
|
|
||||||
else:
|
|
||||||
return f"{size_bytes / (1024 * 1024):.2f} MB"
|
|
||||||
|
|
||||||
def compress_font(input_path: str, output_path: str, compression_level: str = "basic") -> bool:
|
|
||||||
"""
|
|
||||||
压缩单个字体文件
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input_path: 输入字体文件路径
|
|
||||||
output_path: 输出字体文件路径
|
|
||||||
compression_level: 压缩级别 ("basic", "medium", "aggressive")
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 压缩是否成功
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 基础压缩参数
|
|
||||||
base_args = [
|
|
||||||
"pyftsubset", input_path,
|
|
||||||
"--output-file=" + output_path,
|
|
||||||
"--flavor=woff2", # 输出为 WOFF2 格式,压缩率更高
|
|
||||||
"--with-zopfli", # 使用 Zopfli 算法进一步压缩
|
|
||||||
]
|
|
||||||
|
|
||||||
# 根据压缩级别设置不同的参数
|
|
||||||
if compression_level == "basic":
|
|
||||||
# 基础压缩:保留常用字符和功能
|
|
||||||
args = base_args + [
|
|
||||||
"--unicodes=U+0020-007F,U+00A0-00FF,U+2000-206F,U+2070-209F,U+20A0-20CF", # 基本拉丁字符、标点符号等
|
|
||||||
"--layout-features=*", # 保留所有布局特性
|
|
||||||
"--glyph-names", # 保留字形名称
|
|
||||||
"--symbol-cmap", # 保留符号映射
|
|
||||||
"--legacy-cmap", # 保留传统字符映射
|
|
||||||
"--notdef-glyph", # 保留 .notdef 字形
|
|
||||||
"--recommended-glyphs", # 保留推荐字形
|
|
||||||
"--name-IDs=*", # 保留所有名称ID
|
|
||||||
"--name-legacy", # 保留传统名称
|
|
||||||
]
|
|
||||||
elif compression_level == "medium":
|
|
||||||
# 中等压缩:移除一些不常用的功能
|
|
||||||
args = base_args + [
|
|
||||||
"--unicodes=U+0020-007F,U+00A0-00FF,U+2000-206F", # 减少字符范围
|
|
||||||
"--layout-features=kern,liga,clig", # 只保留关键布局特性
|
|
||||||
"--no-glyph-names", # 移除字形名称
|
|
||||||
"--notdef-glyph",
|
|
||||||
"--name-IDs=1,2,3,4,5,6", # 只保留基本名称ID
|
|
||||||
]
|
|
||||||
else: # aggressive
|
|
||||||
# 激进压缩:最大程度减小文件大小
|
|
||||||
args = base_args + [
|
|
||||||
"--unicodes=U+0020-007F", # 只保留基本ASCII字符
|
|
||||||
"--no-layout-features", # 移除所有布局特性
|
|
||||||
"--no-glyph-names", # 移除字形名称
|
|
||||||
"--no-symbol-cmap", # 移除符号映射
|
|
||||||
"--no-legacy-cmap", # 移除传统映射
|
|
||||||
"--notdef-glyph",
|
|
||||||
"--name-IDs=1,2", # 只保留最基本的名称
|
|
||||||
"--desubroutinize", # 去子程序化(可能减小CFF字体大小)
|
|
||||||
]
|
|
||||||
|
|
||||||
# 执行压缩命令
|
|
||||||
result = subprocess.run(args, capture_output=True, text=True)
|
|
||||||
|
|
||||||
if result.returncode == 0:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f"压缩失败: {result.stderr}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"压缩过程中出现错误: {str(e)}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def find_font_files(directory: str) -> List[str]:
|
|
||||||
"""查找目录中的所有字体文件"""
|
|
||||||
font_extensions = ['.ttf', '.otf', '.woff', '.woff2']
|
|
||||||
font_files = []
|
|
||||||
|
|
||||||
for root, dirs, files in os.walk(directory):
|
|
||||||
for file in files:
|
|
||||||
if any(file.lower().endswith(ext) for ext in font_extensions):
|
|
||||||
font_files.append(os.path.join(root, file))
|
|
||||||
|
|
||||||
return font_files
|
|
||||||
|
|
||||||
def compress_fonts_batch(font_directory: str, compression_level: str = "basic"):
|
|
||||||
"""
|
|
||||||
批量压缩字体文件
|
|
||||||
|
|
||||||
Args:
|
|
||||||
font_directory: 字体文件目录
|
|
||||||
compression_level: 压缩级别
|
|
||||||
"""
|
|
||||||
if not os.path.exists(font_directory):
|
|
||||||
print(f"错误: 目录 {font_directory} 不存在")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 查找所有字体文件
|
|
||||||
font_files = find_font_files(font_directory)
|
|
||||||
|
|
||||||
if not font_files:
|
|
||||||
print("未找到字体文件")
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"找到 {len(font_files)} 个字体文件")
|
|
||||||
print(f"压缩级别: {compression_level}")
|
|
||||||
print(f"压缩后的文件将与源文件放在同一目录,扩展名为 .woff2")
|
|
||||||
print("-" * 60)
|
|
||||||
|
|
||||||
total_original_size = 0
|
|
||||||
total_compressed_size = 0
|
|
||||||
successful_compressions = 0
|
|
||||||
|
|
||||||
for i, font_file in enumerate(font_files, 1):
|
|
||||||
print(f"[{i}/{len(font_files)}] 处理: {os.path.basename(font_file)}")
|
|
||||||
|
|
||||||
# 获取原始文件大小
|
|
||||||
original_size = get_file_size(font_file)
|
|
||||||
total_original_size += original_size
|
|
||||||
|
|
||||||
# 生成输出文件名(保持原文件名,只改变扩展名)
|
|
||||||
file_dir = os.path.dirname(font_file)
|
|
||||||
base_name = os.path.splitext(os.path.basename(font_file))[0]
|
|
||||||
output_file = os.path.join(file_dir, f"{base_name}.woff2")
|
|
||||||
|
|
||||||
# 压缩字体
|
|
||||||
if compress_font(font_file, output_file, compression_level):
|
|
||||||
if os.path.exists(output_file):
|
|
||||||
compressed_size = get_file_size(output_file)
|
|
||||||
total_compressed_size += compressed_size
|
|
||||||
successful_compressions += 1
|
|
||||||
|
|
||||||
# 计算压缩率
|
|
||||||
compression_ratio = (1 - compressed_size / original_size) * 100
|
|
||||||
|
|
||||||
print(f" ✓ 成功: {format_file_size(original_size)} → {format_file_size(compressed_size)} "
|
|
||||||
f"(压缩 {compression_ratio:.1f}%)")
|
|
||||||
else:
|
|
||||||
print(f" ✗ 失败: 输出文件未生成")
|
|
||||||
else:
|
|
||||||
print(f" ✗ 失败: 压缩过程出错")
|
|
||||||
|
|
||||||
print()
|
|
||||||
|
|
||||||
# 显示总结
|
|
||||||
print("=" * 60)
|
|
||||||
print("压缩完成!")
|
|
||||||
print(f"成功压缩: {successful_compressions}/{len(font_files)} 个文件")
|
|
||||||
|
|
||||||
if successful_compressions > 0:
|
|
||||||
total_compression_ratio = (1 - total_compressed_size / total_original_size) * 100
|
|
||||||
print(f"总大小: {format_file_size(total_original_size)} → {format_file_size(total_compressed_size)}")
|
|
||||||
print(f"总压缩率: {total_compression_ratio:.1f}%")
|
|
||||||
print(f"节省空间: {format_file_size(total_original_size - total_compressed_size)}")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""主函数"""
|
|
||||||
print("鸿蒙字体压缩工具")
|
|
||||||
print("=" * 60)
|
|
||||||
|
|
||||||
# 检查依赖
|
|
||||||
if not check_dependencies():
|
|
||||||
return
|
|
||||||
|
|
||||||
# 获取当前脚本所在目录
|
|
||||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
|
|
||||||
# 设置默认字体目录
|
|
||||||
font_directory = current_dir
|
|
||||||
|
|
||||||
print(f"字体目录: {font_directory}")
|
|
||||||
|
|
||||||
# 让用户选择压缩级别
|
|
||||||
print("\n请选择压缩级别:")
|
|
||||||
print("1. 基础压缩 (保留大部分功能,适合网页使用)")
|
|
||||||
print("2. 中等压缩 (平衡文件大小和功能)")
|
|
||||||
print("3. 激进压缩 (最小文件大小,可能影响显示效果)")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
choice = input("\n请输入选择 (1-3): ").strip()
|
|
||||||
if choice == "1":
|
|
||||||
compression_level = "basic"
|
|
||||||
break
|
|
||||||
elif choice == "2":
|
|
||||||
compression_level = "medium"
|
|
||||||
break
|
|
||||||
elif choice == "3":
|
|
||||||
compression_level = "aggressive"
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("无效选择,请输入 1、2 或 3")
|
|
||||||
|
|
||||||
# 开始批量压缩
|
|
||||||
compress_fonts_batch(font_directory, compression_level=compression_level)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||