51 Commits

Author SHA1 Message Date
f5bfff80b7 🚨 Format code 2025-09-24 21:44:42 +08:00
1462d8a753 🐛 Fixed docker prettier plugin issue 2025-09-24 19:14:10 +08:00
39ee2d14f3 Optimize font size and add more fonts 2025-09-24 00:44:41 +08:00
e536cdd9ba 🐛 Fixed docker、shell prettier plugin issue 2025-09-23 19:43:26 +08:00
dc4b73406d 🐛 Fixed prettier plugin parser configuration issue 2025-09-21 23:23:43 +08:00
0012a5dc19 Added loading animation switch 2025-09-21 22:17:41 +08:00
3cda88371e 🐛 Fixed manual Chunks issue 2025-09-21 21:54:39 +08:00
0338351680 Improve app launch speed 2025-09-21 03:04:23 +08:00
e372a0dd7c 🎨 Modify the rendering logic of the checkbox 2025-09-21 01:14:33 +08:00
d597f379ff 🚚 Refactor directory structure 2025-09-21 00:11:40 +08:00
9222a52d91 Modified sql prettier plugin 2025-09-20 19:18:33 +08:00
c3670bb8cd Added dockerfile、lua prettier plugin 2025-09-20 01:30:16 +08:00
2ea3456ff7 Added dart prettier plugin 2025-09-19 19:41:48 +08:00
c9379f0edb Added python prettier plugin 2025-09-19 19:35:48 +08:00
f72010bd69 Added clang prettier plugin 2025-09-19 19:17:13 +08:00
cd027097f8 🐛 Fixed golang prettier plugin issue 2025-09-19 18:39:41 +08:00
9cbbf729c0 🔥 Remove powershell prettier plugin 2025-09-18 00:13:07 +08:00
landaiqing
c26c11e253 🐛 Fixed build issue 2025-09-17 09:54:43 +08:00
338ac358db 🚧 Modify toml,powershell prettier plugin(beta) 2025-09-17 00:12:39 +08:00
a83c7139c9 Added scala、powershell、groovy prettier plugin 2025-09-14 23:45:01 +08:00
42c7d11c09 📦 Optimized packaging 2025-09-13 20:25:19 +08:00
5ca5aa64c7 Added shell prettier plugin 2025-09-13 19:21:06 +08:00
eda7ef771e Added rust prettier plugin 2025-09-13 00:02:17 +08:00
593c4d7783 Added java prettier plugin 2025-09-12 23:01:19 +08:00
d24a522b32 Added php prettier plugin 2025-09-12 20:15:56 +08:00
41afb834ae Added sql prettier plugin 2025-09-12 00:52:19 +08:00
b745329e26 Added golang prettier plugin 2025-09-11 20:42:39 +08:00
1fb4f64cb3 Add update notifications 2025-09-06 01:21:02 +08:00
1f8e8981ce 🐛 Fixed version generation issues 2025-09-05 22:40:09 +08:00
a257d30dba 🎨 Modify configuration migration policy 2025-09-05 22:07:00 +08:00
97ee3b0667 🐛 Fixed configuration merge override issue 2025-09-05 00:36:33 +08:00
8e2bafba5f Optimize window snapping performance 2025-09-04 00:20:30 +08:00
6149bc133d 🐛 Fixed window pinning issue 2025-09-02 23:59:04 +08:00
5f22ee3b1f ♻️ Refactoring configuration migration service 2025-08-31 17:48:41 +08:00
fa72ff8061 Merge remote-tracking branch 'github/dependabot/go_modules/github.com/ulikunitz/xz-0.5.14' 2025-08-30 19:00:36 +08:00
65f24860e6 Added window snapping function toggle 2025-08-30 00:18:29 +08:00
dependabot[bot]
4881233211 ⬆️ Bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14
Bumps [github.com/ulikunitz/xz](https://github.com/ulikunitz/xz) from 0.5.12 to 0.5.14.
- [Commits](https://github.com/ulikunitz/xz/compare/v0.5.12...v0.5.14)

---
updated-dependencies:
- dependency-name: github.com/ulikunitz/xz
  dependency-version: 0.5.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-28 19:44:41 +00:00
bc01fdf362 Added window snapping feature 2025-08-24 16:07:48 +08:00
709998ff9c 🐛 Fixed hotkey crashes 2025-08-19 22:26:55 +08:00
6adeadeed4 🐛 Fixed document deadlock issue 2025-08-19 00:24:51 +08:00
7b70a39b23 🐛 Fixed hotkey service issues 2025-08-19 00:08:50 +08:00
873a3c0e60 Modify the theme storage schema 2025-08-17 19:34:35 +08:00
5b88efcfbe 🐛 Fixed the window toggle maximise issue 2025-08-17 14:51:39 +08:00
f37c659c89 🐛 Adjusted error message and icon clearing logic 2025-07-17 11:03:42 +08:00
9fff7bcfca Added the backup feature 2025-07-17 00:12:00 +08:00
b4b0ad9bba 🎨 Optimize storage logic 2025-07-13 22:32:58 +08:00
6d8fdf62f1 💡 Update docs 2025-07-13 11:58:53 +08:00
9f53d7421d Merge remote-tracking branch 'github/master' 2025-07-12 23:56:43 +08:00
80c8ecb4cf 💡 Update docs 2025-07-12 23:56:04 +08:00
d10059a82d Create CNAME 2025-07-12 22:25:19 +08:00
737f83cd5f 💡 Add docs 2025-07-12 22:14:35 +08:00
433 changed files with 38663 additions and 3955 deletions

View File

@@ -1,10 +1,10 @@
# <img src="./frontend/public/appicon.png" alt="VoidRaft Logo" width="32" height="32" style="vertical-align: middle;"> VoidRaft # <img src="./frontend/public/appicon.png" alt="voidraft Logo" width="32" height="32" style="vertical-align: middle;"> voidraft
[中文](README_ZH.md) | **English** [中文](README_ZH.md) | **English**
> *An elegant text snippet recording tool designed for developers.* > *An elegant text snippet recording tool designed for developers.*
VoidRaft is a modern developer-focused text editor that allows you to record, organize, and manage various text snippets anytime, anywhere. Whether it's temporary code snippets, API responses, meeting notes, or daily to-do lists, VoidRaft provides a smooth and elegant editing experience. voidraft is a modern developer-focused text editor that allows you to record, organize, and manage various text snippets anytime, anywhere. Whether it's temporary code snippets, API responses, meeting notes, or daily to-do lists, voidraft provides a smooth and elegant editing experience.
## Core Features ## Core Features
@@ -87,7 +87,7 @@ After building, the executable will be generated in the `bin` directory.
## Project Structure ## Project Structure
``` ```
Voidraft/ voidraft/
├── frontend/ # Vue 3 frontend application ├── frontend/ # Vue 3 frontend application
│ ├── src/ │ ├── src/
│ │ ├── views/editor/ # Editor core views │ │ ├── views/editor/ # Editor core views
@@ -121,19 +121,19 @@ Voidraft/
### Planned Features ### Planned Features
- ✅ Custom themes - Customize editor themes - ✅ Custom themes - Customize editor themes
- ✅ Multi-window support - Support editing multiple documents simultaneously - ✅ Multi-window support - Support editing multiple documents simultaneously
- ✅ Data synchronization - Cloud backup for documents
- [ ] Enhanced clipboard - Monitor and manage clipboard history - [ ] Enhanced clipboard - Monitor and manage clipboard history
- [ ] Data synchronization - Cloud backup for configurations and documents
- [ ] Extension system - Support for custom plugins - [ ] Extension system - Support for custom plugins
## Acknowledgments ## Acknowledgments
> Standing on the shoulders of giants, paying tribute to the open source spirit > Standing on the shoulders of giants, paying tribute to the open source spirit
The birth of VoidRaft is inseparable from the following excellent open source projects: The birth of voidraft is inseparable from the following excellent open source projects:
### Special Thanks ### Special Thanks
- **[Heynote](https://github.com/heyman/heynote/)** - VoidRaft is a feature-enhanced version based on Heynote's concept - **[Heynote](https://github.com/heyman/heynote/)** - voidraft is a feature-enhanced version based on Heynote's concept
- Inherits Heynote's elegant block editing philosophy - Inherits Heynote's elegant block editing philosophy
- Adds more practical features on the original foundation - Adds more practical features on the original foundation
- Rebuilt with modern technology stack - Rebuilt with modern technology stack
@@ -157,7 +157,7 @@ This project is open source under the [MIT License](LICENSE).
Welcome to Fork, Star, and contribute code. Welcome to Fork, Star, and contribute code.
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![GitHub stars](https://img.shields.io/github/stars/landaiqing/Voidraft.svg?style=social&label=Star)](https://github.com/yourusername/Voidraft) [![GitHub stars](https://img.shields.io/github/stars/landaiqing/voidraft.svg?style=social&label=Star)](https://github.com/yourusername/voidraft)
[![GitHub forks](https://img.shields.io/github/forks/landaiqing/Voidraft.svg?style=social&label=Fork)](https://github.com/yourusername/Voidraft) [![GitHub forks](https://img.shields.io/github/forks/landaiqing/voidraft.svg?style=social&label=Fork)](https://github.com/yourusername/voidraft)
*Made with ❤️ by landaiqing* *Made with ❤️ by landaiqing*

View File

@@ -1,10 +1,10 @@
# <img src="./frontend/public/appicon.png" alt="Voidraft Logo" width="32" height="32" style="vertical-align: middle;"> Voidraft # <img src="./frontend/public/appicon.png" alt="voidraft Logo" width="32" height="32" style="vertical-align: middle;"> voidraft
**中文** | [English](README.md) **中文** | [English](README.md)
> *一个专为开发者打造的优雅文本片段记录工具。* > *一个专为开发者打造的优雅文本片段记录工具。*
Voidraft 是一个现代化的开发者专用文本编辑器让你能够随时随地记录、整理和管理各种文本片段。无论是临时的代码片段、API 响应、会议笔记,还是日常的待办事项,Voidraft 都能为你提供流畅而优雅的编辑体验。 voidraft 是一个现代化的开发者专用文本编辑器让你能够随时随地记录、整理和管理各种文本片段。无论是临时的代码片段、API 响应、会议笔记,还是日常的待办事项,voidraft 都能为你提供流畅而优雅的编辑体验。
## 核心特性 ## 核心特性
@@ -88,7 +88,7 @@ wails3 package
## 项目结构 ## 项目结构
``` ```
Voidraft/ voidraft/
├── frontend/ # Vue 3 前端应用 ├── frontend/ # Vue 3 前端应用
│ ├── src/ │ ├── src/
│ │ ├── views/editor/ # 编辑器核心视图 │ │ ├── views/editor/ # 编辑器核心视图
@@ -122,8 +122,8 @@ Voidraft/
### 计划添加的功能 ### 计划添加的功能
- ✅ 自定义主题 - 自定义编辑器主题 - ✅ 自定义主题 - 自定义编辑器主题
- ✅ 多窗口支持 - 支持同时编辑多个文档 - ✅ 多窗口支持 - 支持同时编辑多个文档
- ✅ 数据同步 - 文档云端备份
- [ ] 剪切板增强 - 监听和管理剪切板历史 - [ ] 剪切板增强 - 监听和管理剪切板历史
- [ ] 数据同步 - 配置和文档云端备份
- [ ] 扩展系统 - 支持自定义插件 - [ ] 扩展系统 - 支持自定义插件
@@ -131,11 +131,11 @@ Voidraft/
> 站在巨人的肩膀上,致敬开源精神 > 站在巨人的肩膀上,致敬开源精神
Voidraft 的诞生离不开以下优秀的开源项目: voidraft 的诞生离不开以下优秀的开源项目:
### 特别感谢 ### 特别感谢
- **[Heynote](https://github.com/heyman/heynote/)** - Voidraft 是基于 Heynote 概念的功能增强版本 - **[Heynote](https://github.com/heyman/heynote/)** - voidraft 是基于 Heynote 概念的功能增强版本
- 继承了 Heynote 优雅的块状编辑理念 - 继承了 Heynote 优雅的块状编辑理念
- 在原有基础上增加了更多实用功能 - 在原有基础上增加了更多实用功能
- 采用现代化技术栈重新构建 - 采用现代化技术栈重新构建
@@ -159,7 +159,7 @@ Voidraft 的诞生离不开以下优秀的开源项目:
欢迎 Fork、Star 和贡献代码。 欢迎 Fork、Star 和贡献代码。
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![GitHub stars](https://img.shields.io/github/stars/landaiqing/Voidraft.svg?style=social&label=Star)](https://github.com/yourusername/Voidraft) [![GitHub stars](https://img.shields.io/github/stars/landaiqing/voidraft.svg?style=social&label=Star)](https://github.com/yourusername/voidraft)
[![GitHub forks](https://img.shields.io/github/forks/landaiqing/Voidraft.svg?style=social&label=Fork)](https://github.com/yourusername/Voidraft) [![GitHub forks](https://img.shields.io/github/forks/landaiqing/voidraft.svg?style=social&label=Fork)](https://github.com/yourusername/voidraft)
*Made with ❤️ by landaiqing* *Made with ❤️ by landaiqing*

View File

@@ -12,13 +12,25 @@ 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"

View File

@@ -5,12 +5,12 @@ version: '3'
# This information is used to generate the build assets. # This information is used to generate the build assets.
info: info:
companyName: "Voidraft" # The name of the company companyName: "voidraft" # The name of the company
productName: "Voidraft" # The name of the application productName: "voidraft" # The name of the application
productIdentifier: "landaiqing" # The unique product identifier productIdentifier: "landaiqing" # The unique product identifier
description: "Voidraft" # The application description description: "voidraft" # The application description
copyright: "© 2025 Voidraft. All rights reserved." # Copyright text copyright: "© 2025 voidraft. All rights reserved." # Copyright text
comments: "Voidraft" # Comments comments: "voidraft" # Comments
version: "0.0.1.0" # The application version version: "0.0.1.0" # The application version
# Dev mode configuration # Dev mode configuration

View File

@@ -4,15 +4,15 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>Voidraft</string> <string>voidraft</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>Voidraft</string> <string>voidraft</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>landaiqing</string> <string>landaiqing</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.0.1.0</string> <string>0.0.1.0</string>
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>Voidraft</string> <string>voidraft</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.0.1.0</string> <string>0.0.1.0</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
@@ -22,7 +22,7 @@
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
<string>true</string> <string>true</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>© 2025 Voidraft. All rights reserved.</string> <string>© 2025 voidraft. All rights reserved.</string>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsLocalNetworking</key> <key>NSAllowsLocalNetworking</key>

View File

@@ -4,15 +4,15 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>Voidraft</string> <string>voidraft</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>Voidraft</string> <string>voidraft</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>landaiqing</string> <string>landaiqing</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.0.1.0</string> <string>0.0.1.0</string>
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>Voidraft</string> <string>voidraft</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.0.1.0</string> <string>0.0.1.0</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
@@ -22,6 +22,6 @@
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
<string>true</string> <string>true</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>© 2025 Voidraft. All rights reserved.</string> <string>© 2025 voidraft. All rights reserved.</string>
</dict> </dict>
</plist> </plist>

View File

@@ -11,9 +11,12 @@ tasks:
- task: common:build:frontend - task: common:build:frontend
- task: common:generate:icons - task: common:generate:icons
cmds: cmds:
- go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} - go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.OUTPUT}}
vars: vars:
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
LDFLAGS: '{{if eq .PRODUCTION "true"}}-w -s{{else}}{{end}}'
VERSION_FLAGS:
sh: 'grep "VERSION=" version.txt | cut -d"=" -f2 | xargs -I {} echo "-X voidraft/internal/version.Version={}"'
DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
env: env:

View File

@@ -11,9 +11,12 @@ tasks:
- task: common:build:frontend - task: common:build:frontend
- task: common:generate:icons - task: common:generate:icons
cmds: cmds:
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}} - go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.BIN_DIR}}/{{.APP_NAME}}
vars: vars:
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
LDFLAGS: '{{if eq .PRODUCTION "true"}}-w -s{{else}}{{end}}'
VERSION_FLAGS:
sh: 'grep "VERSION=" version.txt | cut -d"=" -f2 | xargs -I {} echo "-X voidraft/internal/version.Version={}"'
env: env:
GOOS: linux GOOS: linux
CGO_ENABLED: 1 CGO_ENABLED: 1

View File

@@ -3,26 +3,26 @@
# #
# The lines below are called `modelines`. See `:help modeline` # The lines below are called `modelines`. See `:help modeline`
name: "Voidraft" name: "voidraft"
arch: ${GOARCH} arch: ${GOARCH}
platform: "linux" platform: "linux"
version: "0.0.1.0" version: "0.0.1.0"
section: "default" section: "default"
priority: "extra" priority: "extra"
maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}>
description: "Voidraft" description: "voidraft"
vendor: "Voidraft" vendor: "voidraft"
homepage: "https://wails.io" homepage: "https://voidraft.landaiqing.cn"
license: "MIT" license: "MIT"
release: "1" release: "1"
contents: contents:
- src: "./bin/Voidraft" - src: "./bin/voidraft"
dst: "/usr/local/bin/Voidraft" dst: "/usr/local/bin/voidraft"
- src: "./build/appicon.png" - src: "./build/appicon.png"
dst: "/usr/share/icons/hicolor/128x128/apps/Voidraft.png" dst: "/usr/share/icons/hicolor/128x128/apps/voidraft.png"
- src: "./build/linux/Voidraft.desktop" - src: "./build/linux/voidraft.desktop"
dst: "/usr/share/applications/Voidraft.desktop" dst: "/usr/share/applications/voidraft.desktop"
depends: depends:
- gtk3 - gtk3

View File

@@ -14,13 +14,16 @@ tasks:
- task: common:generate:icons - task: common:generate:icons
cmds: cmds:
- task: generate:syso - task: generate:syso
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}.exe - go build {{.BUILD_FLAGS}} -ldflags="{{.LDFLAGS}} {{.VERSION_FLAGS}}" -o {{.BIN_DIR}}/{{.APP_NAME}}.exe
- cmd: powershell Remove-item *.syso - cmd: powershell Remove-item *.syso
platforms: [windows] platforms: [windows]
- cmd: rm -f *.syso - cmd: rm -f *.syso
platforms: [linux, darwin] platforms: [linux, darwin]
vars: vars:
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false{{else}}-buildvcs=false -gcflags=all="-l"{{end}}'
LDFLAGS: '{{if eq .PRODUCTION "true"}}-w -s -H windowsgui{{else}}{{end}}'
VERSION_FLAGS:
sh: 'powershell -Command "(Get-Content version.txt) -replace ''VERSION='', ''-X voidraft/internal/version.Version=''"'
env: env:
GOOS: windows GOOS: windows
CGO_ENABLED: 1 CGO_ENABLED: 1

View File

@@ -5,11 +5,11 @@
"info": { "info": {
"0000": { "0000": {
"ProductVersion": "0.0.1.0", "ProductVersion": "0.0.1.0",
"CompanyName": "Voidraft", "CompanyName": "voidraft",
"FileDescription": "Voidraft", "FileDescription": "voidraft",
"LegalCopyright": "© 2025 Voidraft. All rights reserved.", "LegalCopyright": "© 2025 voidraft. All rights reserved.",
"ProductName": "Voidraft", "ProductName": "voidraft",
"Comments": "Voidraft" "Comments": "voidraft"
} }
} }
} }

View File

@@ -5,19 +5,19 @@
!include "FileFunc.nsh" !include "FileFunc.nsh"
!ifndef INFO_PROJECTNAME !ifndef INFO_PROJECTNAME
!define INFO_PROJECTNAME "Voidraft" !define INFO_PROJECTNAME "voidraft"
!endif !endif
!ifndef INFO_COMPANYNAME !ifndef INFO_COMPANYNAME
!define INFO_COMPANYNAME "Voidraft" !define INFO_COMPANYNAME "voidraft"
!endif !endif
!ifndef INFO_PRODUCTNAME !ifndef INFO_PRODUCTNAME
!define INFO_PRODUCTNAME "Voidraft" !define INFO_PRODUCTNAME "voidraft"
!endif !endif
!ifndef INFO_PRODUCTVERSION !ifndef INFO_PRODUCTVERSION
!define INFO_PRODUCTVERSION "0.0.1.0" !define INFO_PRODUCTVERSION "0.0.1.0"
!endif !endif
!ifndef INFO_COPYRIGHT !ifndef INFO_COPYRIGHT
!define INFO_COPYRIGHT "© 2025 Voidraft. All rights reserved." !define INFO_COPYRIGHT "© 2025 voidraft. All rights reserved."
!endif !endif
!ifndef PRODUCT_EXECUTABLE !ifndef PRODUCT_EXECUTABLE
!define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"

1
docs/CNAME Normal file
View File

@@ -0,0 +1 @@
voidraft.landaiqing.cn

75
docs/changelog.html Normal file
View File

@@ -0,0 +1,75 @@
<!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>

347
docs/css/changelog.css Normal file
View File

@@ -0,0 +1,347 @@
/* 更新日志页面样式 */
.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;
}

View File

@@ -0,0 +1,45 @@
/* 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;
}

View File

@@ -0,0 +1,27 @@
/* 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;
}

717
docs/css/styles.css Normal file
View File

@@ -0,0 +1,717 @@
@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;
}
}

Binary file not shown.

BIN
docs/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
docs/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

256
docs/index.html Normal file
View File

@@ -0,0 +1,256 @@
<!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>

705
docs/js/changelog.js Normal file
View File

@@ -0,0 +1,705 @@
/**
* 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(/&gt;\s*(.*?)(?=&gt;|$)/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();
});

443
docs/js/script.js Normal file
View File

@@ -0,0 +1,443 @@
/**
* 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();
});

View File

@@ -0,0 +1,64 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* Service represents the notifications service
* @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 application$0 from "../../application/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as $models from "./models.js";
/**
* RemoveBadge removes the badge label from the application icon.
*/
export function RemoveBadge(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2374916939) as any;
return $resultPromise;
}
/**
* ServiceName returns the name of the service.
*/
export function ServiceName(): Promise<string> & { cancel(): void } {
let $resultPromise = $Call.ByID(2428202016) as any;
return $resultPromise;
}
/**
* ServiceShutdown is called when the service is unloaded.
*/
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3893755233) as any;
return $resultPromise;
}
/**
* ServiceStartup is called when the service is loaded.
*/
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(4078800764, options) as any;
return $resultPromise;
}
/**
* SetBadge sets the badge label on the application icon.
*/
export function SetBadge(label: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(784276339, label) as any;
return $resultPromise;
}
export function SetCustomBadge(label: string, options: $models.Options): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3058653106, label, options) as any;
return $resultPromise;
}

View File

@@ -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 Service from "./service.js"; import * as BadgeService from "./badgeservice.js";
export { export {
Service BadgeService
}; };
export * from "./models.js"; export * from "./models.js";

View File

@@ -0,0 +1,58 @@
// 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";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as color$0 from "../../../../../../../image/color/models.js";
export class Options {
"TextColour": color$0.RGBA;
"BackgroundColour": color$0.RGBA;
"FontName": string;
"FontSize": number;
"SmallFontSize": number;
/** Creates a new Options instance. */
constructor($$source: Partial<Options> = {}) {
if (!("TextColour" in $$source)) {
this["TextColour"] = (new color$0.RGBA());
}
if (!("BackgroundColour" in $$source)) {
this["BackgroundColour"] = (new color$0.RGBA());
}
if (!("FontName" in $$source)) {
this["FontName"] = "";
}
if (!("FontSize" in $$source)) {
this["FontSize"] = 0;
}
if (!("SmallFontSize" in $$source)) {
this["SmallFontSize"] = 0;
}
Object.assign(this, $$source);
}
/**
* Creates a new Options instance from a string or object.
*/
static createFrom($$source: any = {}): Options {
const $$createField0_0 = $$createType0;
const $$createField1_0 = $$createType0;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("TextColour" in $$parsedSource) {
$$parsedSource["TextColour"] = $$createField0_0($$parsedSource["TextColour"]);
}
if ("BackgroundColour" in $$parsedSource) {
$$parsedSource["BackgroundColour"] = $$createField1_0($$parsedSource["BackgroundColour"]);
}
return new Options($$parsedSource as Partial<Options>);
}
}
// Private type creation functions
const $$createType0 = color$0.RGBA.createFrom;

View File

@@ -0,0 +1,9 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import * as NotificationService from "./notificationservice.js";
export {
NotificationService
};
export * from "./models.js";

View File

@@ -0,0 +1,107 @@
// 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";
/**
* NotificationAction represents an action button for a notification.
*/
export class NotificationAction {
"id"?: string;
"title"?: string;
/**
* (macOS-specific)
*/
"destructive"?: boolean;
/** Creates a new NotificationAction instance. */
constructor($$source: Partial<NotificationAction> = {}) {
Object.assign(this, $$source);
}
/**
* Creates a new NotificationAction instance from a string or object.
*/
static createFrom($$source: any = {}): NotificationAction {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new NotificationAction($$parsedSource as Partial<NotificationAction>);
}
}
/**
* NotificationCategory groups actions for notifications.
*/
export class NotificationCategory {
"id"?: string;
"actions"?: NotificationAction[];
"hasReplyField"?: boolean;
"replyPlaceholder"?: string;
"replyButtonTitle"?: string;
/** Creates a new NotificationCategory instance. */
constructor($$source: Partial<NotificationCategory> = {}) {
Object.assign(this, $$source);
}
/**
* Creates a new NotificationCategory instance from a string or object.
*/
static createFrom($$source: any = {}): NotificationCategory {
const $$createField1_0 = $$createType1;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("actions" in $$parsedSource) {
$$parsedSource["actions"] = $$createField1_0($$parsedSource["actions"]);
}
return new NotificationCategory($$parsedSource as Partial<NotificationCategory>);
}
}
/**
* NotificationOptions contains configuration for a notification
*/
export class NotificationOptions {
"id": string;
"title": string;
/**
* (macOS and Linux only)
*/
"subtitle"?: string;
"body"?: string;
"categoryId"?: string;
"data"?: { [_: string]: any };
/** Creates a new NotificationOptions instance. */
constructor($$source: Partial<NotificationOptions> = {}) {
if (!("id" in $$source)) {
this["id"] = "";
}
if (!("title" in $$source)) {
this["title"] = "";
}
Object.assign(this, $$source);
}
/**
* Creates a new NotificationOptions instance from a string or object.
*/
static createFrom($$source: any = {}): NotificationOptions {
const $$createField5_0 = $$createType2;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("data" in $$parsedSource) {
$$parsedSource["data"] = $$createField5_0($$parsedSource["data"]);
}
return new NotificationOptions($$parsedSource as Partial<NotificationOptions>);
}
}
// Private type creation functions
const $$createType0 = NotificationAction.createFrom;
const $$createType1 = $Create.Array($$createType0);
const $$createType2 = $Create.Map($Create.Any, $Create.Any);

View File

@@ -0,0 +1,110 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* Service represents the notifications service
* @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 application$0 from "../../application/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as $models from "./models.js";
export function CheckNotificationAuthorization(): Promise<boolean> & { cancel(): void } {
let $resultPromise = $Call.ByID(2216952893) as any;
return $resultPromise;
}
/**
* OnNotificationResponse registers a callback function that will be called when
* a notification response is received from the user.
*/
export function OnNotificationResponse(callback: any): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1642697808, callback) as any;
return $resultPromise;
}
export function RegisterNotificationCategory(category: $models.NotificationCategory): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2917562919, category) as any;
return $resultPromise;
}
export function RemoveAllDeliveredNotifications(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3956282340) as any;
return $resultPromise;
}
export function RemoveAllPendingNotifications(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(108821341) as any;
return $resultPromise;
}
export function RemoveDeliveredNotification(identifier: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(975691940, identifier) as any;
return $resultPromise;
}
export function RemoveNotification(identifier: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3966653866, identifier) as any;
return $resultPromise;
}
export function RemoveNotificationCategory(categoryID: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2032615554, categoryID) as any;
return $resultPromise;
}
export function RemovePendingNotification(identifier: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3729049703, identifier) as any;
return $resultPromise;
}
/**
* Public methods that delegate to the implementation.
*/
export function RequestNotificationAuthorization(): Promise<boolean> & { cancel(): void } {
let $resultPromise = $Call.ByID(3933442950) as any;
return $resultPromise;
}
export function SendNotification(options: $models.NotificationOptions): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3968228732, options) as any;
return $resultPromise;
}
export function SendNotificationWithActions(options: $models.NotificationOptions): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1886542847, options) as any;
return $resultPromise;
}
/**
* ServiceName returns the name of the service.
*/
export function ServiceName(): Promise<string> & { cancel(): void } {
let $resultPromise = $Call.ByID(2704532675) as any;
return $resultPromise;
}
/**
* ServiceShutdown is called when the service is unloaded.
*/
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2550195434) as any;
return $resultPromise;
}
/**
* ServiceStartup is called when the service is loaded.
*/
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(4047820929, options) as any;
return $resultPromise;
}

View File

@@ -1,51 +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";
export class Config {
/**
* DBSource is the database URI to use.
* The string ":memory:" can be used to create an in-memory database.
* The sqlite driver can be configured through query parameters.
* For more details see https://pkg.go.dev/modernc.org/sqlite#Driver.Open
*/
"DBSource": string;
/** Creates a new Config instance. */
constructor($$source: Partial<Config> = {}) {
if (!("DBSource" in $$source)) {
this["DBSource"] = "";
}
Object.assign(this, $$source);
}
/**
* Creates a new Config instance from a string or object.
*/
static createFrom($$source: any = {}): Config {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new Config($$parsedSource as Partial<Config>);
}
}
/**
* Row holds a single row in the result of a query.
* It is a key-value map where keys are column names.
*/
export type Row = { [_: string]: any };
/**
* Rows holds the result of a query
* as an array of key-value maps where keys are column names.
*/
export type Rows = Row[];
/**
* Stmt wraps a prepared sql statement pointer.
* It provides the same methods as the [sql.Stmt] type.
*/
export type Stmt = string;

View File

@@ -1,223 +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 {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 "../../application/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as $models from "./models.js";
export {
ExecContext as Execute,
QueryContext as Query
};
import { Stmt } from "./stmt.js";
/**
* Prepare creates a prepared statement for later queries or executions.
* Multiple queries or executions may be run concurrently from the returned statement.
*
* The caller must call the statement's Close method when it is no longer needed.
* Statements are closed automatically
* when the connection they are associated with is closed.
*
* Prepare supports early cancellation.
*/
export function Prepare(query: string): Promise<Stmt | null> & { cancel(): void } {
const promise = PrepareContext(query);
const wrapper: any = (promise.then(function (id) {
return id == null ? null : new Stmt(
ClosePrepared.bind(null, id),
ExecPrepared.bind(null, id),
QueryPrepared.bind(null, id));
}));
wrapper.cancel = promise.cancel;
return wrapper;
}
/**
* Close closes the current database connection if one is open, otherwise has no effect.
* Additionally, Close closes all open prepared statements associated to the connection.
*
* Even when a non-nil error is returned,
* the database service is left in a consistent state,
* ready for a call to [Service.Open].
*/
export function Close(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1888105376) as any;
return $resultPromise;
}
/**
* ClosePrepared closes a prepared statement
* obtained with [Service.Prepare] or [Service.PrepareContext].
* ClosePrepared is idempotent:
* it has no effect on prepared statements that are already closed.
*/
function ClosePrepared(stmt: $models.Stmt | null): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2526200629, stmt) as any;
return $resultPromise;
}
/**
* Configure changes the database service configuration.
* The connection state at call time is preserved.
* Consumers will need to call [Service.Open] manually after Configure
* in order to reconnect with the new configuration.
*
* See [NewWithConfig] for details on configuration.
*/
export function Configure(config: $models.Config | null): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1939578712, config) as any;
return $resultPromise;
}
/**
* ExecContext executes a query without returning any rows.
* It supports early cancellation.
*/
function ExecContext(query: string, ...args: any[]): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(674944556, query, args) as any;
return $resultPromise;
}
/**
* ExecPrepared executes a prepared statement
* obtained with [Service.Prepare] or [Service.PrepareContext]
* without returning any rows.
* It supports early cancellation.
*/
function ExecPrepared(stmt: $models.Stmt | null, ...args: any[]): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2086877656, stmt, args) as any;
return $resultPromise;
}
/**
* Execute executes a query without returning any rows.
*/
export function Execute(query: string, ...args: any[]): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3811930203, query, args) as any;
return $resultPromise;
}
/**
* Open validates the current configuration,
* closes the current connection if one is present,
* then opens and validates a new connection.
*
* Even when a non-nil error is returned,
* the database service is left in a consistent state,
* ready for a new call to Open.
*/
export function Open(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2012175612) as any;
return $resultPromise;
}
/**
* Prepare creates a prepared statement for later queries or executions.
* Multiple queries or executions may be run concurrently from the returned statement.
*
* The caller should call the statement's Close method when it is no longer needed.
* Statements are closed automatically
* when the connection they are associated with is closed.
*/
export function Prepare(query: string): Promise<$models.Stmt | null> & { cancel(): void } {
let $resultPromise = $Call.ByID(1801965143, query) as any;
return $resultPromise;
}
/**
* PrepareContext creates a prepared statement for later queries or executions.
* Multiple queries or executions may be run concurrently from the returned statement.
*
* The caller must call the statement's Close method when it is no longer needed.
* Statements are closed automatically
* when the connection they are associated with is closed.
*
* PrepareContext supports early cancellation.
*/
function PrepareContext(query: string): Promise<$models.Stmt | null> & { cancel(): void } {
let $resultPromise = $Call.ByID(570941694, query) as any;
return $resultPromise;
}
/**
* Query executes a query and returns a slice of key-value records,
* one per row, with column names as keys.
*/
export function Query(query: string, ...args: any[]): Promise<$models.Rows> & { cancel(): void } {
let $resultPromise = $Call.ByID(860757720, query, args) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType1($result);
}) as any;
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
}
/**
* QueryContext executes a query and returns a slice of key-value records,
* one per row, with column names as keys.
* It supports early cancellation, returning the slice of results fetched so far.
*/
function QueryContext(query: string, ...args: any[]): Promise<$models.Rows> & { cancel(): void } {
let $resultPromise = $Call.ByID(4115542347, query, args) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType1($result);
}) as any;
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
}
/**
* QueryPrepared executes a prepared statement
* obtained with [Service.Prepare] or [Service.PrepareContext]
* and returns a slice of key-value records, one per row, with column names as keys.
* It supports early cancellation, returning the slice of results fetched so far.
*/
function QueryPrepared(stmt: $models.Stmt | null, ...args: any[]): Promise<$models.Rows> & { cancel(): void } {
let $resultPromise = $Call.ByID(3885083725, stmt, args) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType1($result);
}) as any;
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
}
/**
* ServiceName returns the name of the plugin.
* You should use the go module format e.g. github.com/myuser/myplugin
*/
export function ServiceName(): Promise<string> & { cancel(): void } {
let $resultPromise = $Call.ByID(1637123084) as any;
return $resultPromise;
}
/**
* ServiceShutdown closes the database connection.
* It returns a non-nil error in case of failures.
*/
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3650435925) as any;
return $resultPromise;
}
/**
* ServiceStartup opens the database connection.
* It returns a non-nil error in case of failures.
*/
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1113159936, options) as any;
return $resultPromise;
}
// Private type creation functions
const $$createType0 = $Create.Map($Create.Any, $Create.Any);
const $$createType1 = $Create.Array($$createType0);

View File

@@ -1,79 +0,0 @@
//@ts-check
//@ts-ignore: Unused imports
import * as $models from "./models.js";
const execSymbol = Symbol("exec"),
querySymbol = Symbol("query"),
closeSymbol = Symbol("close");
/**
* Stmt represents a prepared statement for later queries or executions.
* Multiple queries or executions may be run concurrently on the same statement.
*
* The caller must call the statement's Close method when it is no longer needed.
* Statements are closed automatically
* when the connection they are associated with is closed.
*/
export class Stmt {
/**
* Constructs a new prepared statement instance.
* @param {(...args: any[]) => Promise<void>} close
* @param {(...args: any[]) => Promise<void> & { cancel(): void }} exec
* @param {(...args: any[]) => Promise<$models.Rows> & { cancel(): void }} query
*/
constructor(close, exec, query) {
/**
* @member
* @private
* @type {typeof close}
*/
this[closeSymbol] = close;
/**
* @member
* @private
* @type {typeof exec}
*/
this[execSymbol] = exec;
/**
* @member
* @private
* @type {typeof query}
*/
this[querySymbol] = query;
}
/**
* Closes the prepared statement.
* It has no effect when the statement is already closed.
* @returns {Promise<void>}
*/
Close() {
return this[closeSymbol]();
}
/**
* Executes the prepared statement without returning any rows.
* It supports early cancellation.
*
* @param {any[]} args
* @returns {Promise<void> & { cancel(): void }}
*/
Exec(...args) {
return this[execSymbol](...args);
}
/**
* Executes the prepared statement
* and returns a slice of key-value records, one per row, with column names as keys.
* It supports early cancellation, returning the array of results fetched so far.
*
* @param {any[]} args
* @returns {Promise<$models.Rows> & { cancel(): void }}
*/
Query(...args) {
return this[querySymbol](...args);
}
}

View File

@@ -0,0 +1,4 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export * from "./models.js";

View File

@@ -0,0 +1,46 @@
// 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";
/**
* RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
* bits for each of red, green, blue and alpha.
*
* An alpha-premultiplied color component C has been scaled by alpha (A), so
* has valid values 0 <= C <= A.
*/
export class RGBA {
"R": number;
"G": number;
"B": number;
"A": number;
/** Creates a new RGBA instance. */
constructor($$source: Partial<RGBA> = {}) {
if (!("R" in $$source)) {
this["R"] = 0;
}
if (!("G" in $$source)) {
this["G"] = 0;
}
if (!("B" in $$source)) {
this["B"] = 0;
}
if (!("A" in $$source)) {
this["A"] = 0;
}
Object.assign(this, $$source);
}
/**
* Creates a new RGBA instance from a string or object.
*/
static createFrom($$source: any = {}): RGBA {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new RGBA($$parsedSource as Partial<RGBA>);
}
}

View File

@@ -33,6 +33,11 @@ export class AppConfig {
*/ */
"updates": UpdatesConfig; "updates": UpdatesConfig;
/**
* Git备份设置
*/
"backup": GitBackupConfig;
/** /**
* 配置元数据 * 配置元数据
*/ */
@@ -52,6 +57,9 @@ export class AppConfig {
if (!("updates" in $$source)) { if (!("updates" in $$source)) {
this["updates"] = (new UpdatesConfig()); this["updates"] = (new UpdatesConfig());
} }
if (!("backup" in $$source)) {
this["backup"] = (new GitBackupConfig());
}
if (!("metadata" in $$source)) { if (!("metadata" in $$source)) {
this["metadata"] = (new ConfigMetadata()); this["metadata"] = (new ConfigMetadata());
} }
@@ -68,6 +76,7 @@ export class AppConfig {
const $$createField2_0 = $$createType2; const $$createField2_0 = $$createType2;
const $$createField3_0 = $$createType3; const $$createField3_0 = $$createType3;
const $$createField4_0 = $$createType4; const $$createField4_0 = $$createType4;
const $$createField5_0 = $$createType5;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("general" in $$parsedSource) { if ("general" in $$parsedSource) {
$$parsedSource["general"] = $$createField0_0($$parsedSource["general"]); $$parsedSource["general"] = $$createField0_0($$parsedSource["general"]);
@@ -81,8 +90,11 @@ export class AppConfig {
if ("updates" in $$parsedSource) { if ("updates" in $$parsedSource) {
$$parsedSource["updates"] = $$createField3_0($$parsedSource["updates"]); $$parsedSource["updates"] = $$createField3_0($$parsedSource["updates"]);
} }
if ("backup" in $$parsedSource) {
$$parsedSource["backup"] = $$createField4_0($$parsedSource["backup"]);
}
if ("metadata" in $$parsedSource) { if ("metadata" in $$parsedSource) {
$$parsedSource["metadata"] = $$createField4_0($$parsedSource["metadata"]); $$parsedSource["metadata"] = $$createField5_0($$parsedSource["metadata"]);
} }
return new AppConfig($$parsedSource as Partial<AppConfig>); return new AppConfig($$parsedSource as Partial<AppConfig>);
} }
@@ -102,11 +114,6 @@ export class AppearanceConfig {
*/ */
"systemTheme": SystemThemeType; "systemTheme": SystemThemeType;
/**
* 自定义主题配置
*/
"customTheme": CustomThemeConfig;
/** 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)) {
@@ -115,9 +122,6 @@ export class AppearanceConfig {
if (!("systemTheme" in $$source)) { if (!("systemTheme" in $$source)) {
this["systemTheme"] = ("" as SystemThemeType); this["systemTheme"] = ("" as SystemThemeType);
} }
if (!("customTheme" in $$source)) {
this["customTheme"] = (new CustomThemeConfig());
}
Object.assign(this, $$source); Object.assign(this, $$source);
} }
@@ -126,15 +130,30 @@ export class AppearanceConfig {
* Creates a new AppearanceConfig instance from a string or object. * Creates a new AppearanceConfig instance from a string or object.
*/ */
static createFrom($$source: any = {}): AppearanceConfig { static createFrom($$source: any = {}): AppearanceConfig {
const $$createField2_0 = $$createType5;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("customTheme" in $$parsedSource) {
$$parsedSource["customTheme"] = $$createField2_0($$parsedSource["customTheme"]);
}
return new AppearanceConfig($$parsedSource as Partial<AppearanceConfig>); return new AppearanceConfig($$parsedSource as Partial<AppearanceConfig>);
} }
} }
/**
* Git备份相关类型定义
*
* AuthMethod 定义Git认证方式
*/
export enum AuthMethod {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* 认证方式
*/
Token = "token",
SSHKey = "ssh_key",
UserPass = "user_pass",
};
/** /**
* ConfigMetadata 配置元数据 * ConfigMetadata 配置元数据
*/ */
@@ -170,49 +189,6 @@ export class ConfigMetadata {
} }
} }
/**
* CustomThemeConfig 自定义主题配置
*/
export class CustomThemeConfig {
/**
* 深色主题配置
*/
"darkTheme": ThemeColorConfig;
/**
* 浅色主题配置
*/
"lightTheme": ThemeColorConfig;
/** Creates a new CustomThemeConfig instance. */
constructor($$source: Partial<CustomThemeConfig> = {}) {
if (!("darkTheme" in $$source)) {
this["darkTheme"] = (new ThemeColorConfig());
}
if (!("lightTheme" in $$source)) {
this["lightTheme"] = (new ThemeColorConfig());
}
Object.assign(this, $$source);
}
/**
* Creates a new CustomThemeConfig instance from a string or object.
*/
static createFrom($$source: any = {}): CustomThemeConfig {
const $$createField0_0 = $$createType6;
const $$createField1_0 = $$createType6;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("darkTheme" in $$parsedSource) {
$$parsedSource["darkTheme"] = $$createField0_0($$parsedSource["darkTheme"]);
}
if ("lightTheme" in $$parsedSource) {
$$parsedSource["lightTheme"] = $$createField1_0($$parsedSource["lightTheme"]);
}
return new CustomThemeConfig($$parsedSource as Partial<CustomThemeConfig>);
}
}
/** /**
* Document represents a document in the system * Document represents a document in the system
*/ */
@@ -224,6 +200,11 @@ export class Document {
"updatedAt": time$0.Time; "updatedAt": time$0.Time;
"is_deleted": boolean; "is_deleted": boolean;
/**
* 锁定标志,锁定的文档无法被删除
*/
"is_locked": boolean;
/** Creates a new Document instance. */ /** Creates a new Document instance. */
constructor($$source: Partial<Document> = {}) { constructor($$source: Partial<Document> = {}) {
if (!("id" in $$source)) { if (!("id" in $$source)) {
@@ -244,6 +225,9 @@ export class Document {
if (!("is_deleted" in $$source)) { if (!("is_deleted" in $$source)) {
this["is_deleted"] = false; this["is_deleted"] = false;
} }
if (!("is_locked" in $$source)) {
this["is_locked"] = false;
}
Object.assign(this, $$source); Object.assign(this, $$source);
} }
@@ -389,7 +373,7 @@ export class Extension {
* Creates a new Extension instance from a string or object. * Creates a new Extension instance from a string or object.
*/ */
static createFrom($$source: any = {}): Extension { static createFrom($$source: any = {}): Extension {
const $$createField3_0 = $$createType7; const $$createField3_0 = $$createType6;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("config" in $$parsedSource) { if ("config" in $$parsedSource) {
$$parsedSource["config"] = $$createField3_0($$parsedSource["config"]); $$parsedSource["config"] = $$createField3_0($$parsedSource["config"]);
@@ -483,6 +467,12 @@ export class GeneralConfig {
*/ */
"startAtLogin": boolean; "startAtLogin": boolean;
/**
* 窗口吸附设置
* 是否启用窗口吸附功能(阈值现在是自适应的)
*/
"enableWindowSnap": boolean;
/** /**
* 全局热键设置 * 全局热键设置
* 是否启用全局热键 * 是否启用全局热键
@@ -494,6 +484,12 @@ export class GeneralConfig {
*/ */
"globalHotkey": HotkeyCombo; "globalHotkey": HotkeyCombo;
/**
* 界面设置
* 是否启用加载动画
*/
"enableLoadingAnimation": 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)) {
@@ -508,12 +504,18 @@ export class GeneralConfig {
if (!("startAtLogin" in $$source)) { if (!("startAtLogin" in $$source)) {
this["startAtLogin"] = false; this["startAtLogin"] = false;
} }
if (!("enableWindowSnap" in $$source)) {
this["enableWindowSnap"] = false;
}
if (!("enableGlobalHotkey" in $$source)) { if (!("enableGlobalHotkey" in $$source)) {
this["enableGlobalHotkey"] = false; this["enableGlobalHotkey"] = false;
} }
if (!("globalHotkey" in $$source)) { if (!("globalHotkey" in $$source)) {
this["globalHotkey"] = (new HotkeyCombo()); this["globalHotkey"] = (new HotkeyCombo());
} }
if (!("enableLoadingAnimation" in $$source)) {
this["enableLoadingAnimation"] = false;
}
Object.assign(this, $$source); Object.assign(this, $$source);
} }
@@ -522,15 +524,64 @@ export class GeneralConfig {
* Creates a new GeneralConfig instance from a string or object. * Creates a new GeneralConfig instance from a string or object.
*/ */
static createFrom($$source: any = {}): GeneralConfig { static createFrom($$source: any = {}): GeneralConfig {
const $$createField5_0 = $$createType9; const $$createField6_0 = $$createType8;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("globalHotkey" in $$parsedSource) { if ("globalHotkey" in $$parsedSource) {
$$parsedSource["globalHotkey"] = $$createField5_0($$parsedSource["globalHotkey"]); $$parsedSource["globalHotkey"] = $$createField6_0($$parsedSource["globalHotkey"]);
} }
return new GeneralConfig($$parsedSource as Partial<GeneralConfig>); return new GeneralConfig($$parsedSource as Partial<GeneralConfig>);
} }
} }
/**
* GitBackupConfig Git备份配置
*/
export class GitBackupConfig {
"enabled": boolean;
"repo_url": string;
"auth_method": AuthMethod;
"username"?: string;
"password"?: string;
"token"?: string;
"ssh_key_path"?: string;
"ssh_key_passphrase"?: string;
/**
* 分钟
*/
"backup_interval": number;
"auto_backup": boolean;
/** Creates a new GitBackupConfig instance. */
constructor($$source: Partial<GitBackupConfig> = {}) {
if (!("enabled" in $$source)) {
this["enabled"] = false;
}
if (!("repo_url" in $$source)) {
this["repo_url"] = "";
}
if (!("auth_method" in $$source)) {
this["auth_method"] = ("" as AuthMethod);
}
if (!("backup_interval" in $$source)) {
this["backup_interval"] = 0;
}
if (!("auto_backup" in $$source)) {
this["auto_backup"] = false;
}
Object.assign(this, $$source);
}
/**
* Creates a new GitBackupConfig instance from a string or object.
*/
static createFrom($$source: any = {}): GitBackupConfig {
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
return new GitBackupConfig($$parsedSource as Partial<GitBackupConfig>);
}
}
/** /**
* GiteaConfig Gitea配置 * GiteaConfig Gitea配置
*/ */
@@ -1083,6 +1134,58 @@ export enum TabType {
TabTypeTab = "tab", TabTypeTab = "tab",
}; };
/**
* Theme 主题数据库模型
*/
export class Theme {
"id": number;
"name": string;
"type": ThemeType;
"colors": ThemeColorConfig;
"isDefault": boolean;
"createdAt": time$0.Time;
"updatedAt": time$0.Time;
/** Creates a new Theme instance. */
constructor($$source: Partial<Theme> = {}) {
if (!("id" in $$source)) {
this["id"] = 0;
}
if (!("name" in $$source)) {
this["name"] = "";
}
if (!("type" in $$source)) {
this["type"] = ("" as ThemeType);
}
if (!("colors" in $$source)) {
this["colors"] = (new ThemeColorConfig());
}
if (!("isDefault" in $$source)) {
this["isDefault"] = false;
}
if (!("createdAt" in $$source)) {
this["createdAt"] = null;
}
if (!("updatedAt" in $$source)) {
this["updatedAt"] = null;
}
Object.assign(this, $$source);
}
/**
* Creates a new Theme instance from a string or object.
*/
static createFrom($$source: any = {}): Theme {
const $$createField3_0 = $$createType9;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("colors" in $$parsedSource) {
$$parsedSource["colors"] = $$createField3_0($$parsedSource["colors"]);
}
return new Theme($$parsedSource as Partial<Theme>);
}
}
/** /**
* ThemeColorConfig 主题颜色配置 * ThemeColorConfig 主题颜色配置
*/ */
@@ -1291,6 +1394,19 @@ export class ThemeColorConfig {
} }
} }
/**
* ThemeType 主题类型枚举
*/
export enum ThemeType {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
ThemeTypeDark = "dark",
ThemeTypeLight = "light",
};
/** /**
* UpdateSourceType 更新源类型 * UpdateSourceType 更新源类型
*/ */
@@ -1407,16 +1523,16 @@ const $$createType0 = GeneralConfig.createFrom;
const $$createType1 = EditingConfig.createFrom; const $$createType1 = EditingConfig.createFrom;
const $$createType2 = AppearanceConfig.createFrom; const $$createType2 = AppearanceConfig.createFrom;
const $$createType3 = UpdatesConfig.createFrom; const $$createType3 = UpdatesConfig.createFrom;
const $$createType4 = ConfigMetadata.createFrom; const $$createType4 = GitBackupConfig.createFrom;
const $$createType5 = CustomThemeConfig.createFrom; const $$createType5 = ConfigMetadata.createFrom;
const $$createType6 = ThemeColorConfig.createFrom; var $$createType6 = (function $$initCreateType6(...args): any {
var $$createType7 = (function $$initCreateType7(...args): any { if ($$createType6 === $$initCreateType6) {
if ($$createType7 === $$initCreateType7) { $$createType6 = $$createType7;
$$createType7 = $$createType8;
} }
return $$createType7(...args); return $$createType6(...args);
}); });
const $$createType8 = $Create.Map($Create.Any, $Create.Any); const $$createType7 = $Create.Map($Create.Any, $Create.Any);
const $$createType9 = HotkeyCombo.createFrom; const $$createType8 = HotkeyCombo.createFrom;
const $$createType9 = ThemeColorConfig.createFrom;
const $$createType10 = GithubConfig.createFrom; const $$createType10 = GithubConfig.createFrom;
const $$createType11 = GiteaConfig.createFrom; const $$createType11 = GiteaConfig.createFrom;

View File

@@ -0,0 +1,71 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* BackupService 提供基于Git的备份功能
* @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$0 from "../models/models.js";
/**
* HandleConfigChange 处理备份配置变更
*/
export function HandleConfigChange(config: models$0.GitBackupConfig | null): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(395287784, config) as any;
return $resultPromise;
}
/**
* Initialize 初始化备份服务
*/
export function Initialize(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1052437974) as any;
return $resultPromise;
}
/**
* PushToRemote 推送本地更改到远程仓库
*/
export function PushToRemote(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(262644139) as any;
return $resultPromise;
}
/**
* Reinitialize 重新初始化备份服务,用于响应配置变更
*/
export function Reinitialize(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(301562543) as any;
return $resultPromise;
}
/**
* ServiceShutdown 服务关闭时的清理工作
*/
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(422131801) as any;
return $resultPromise;
}
/**
* StartAutoBackup 启动自动备份定时器
*/
export function StartAutoBackup(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3035755449) as any;
return $resultPromise;
}
/**
* StopAutoBackup 停止自动备份
*/
export function StopAutoBackup(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2641894021) as any;
return $resultPromise;
}

View File

@@ -34,6 +34,30 @@ 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 执行配置迁移
*/
export function MigrateConfig(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(434292783) as any;
return $resultPromise;
}
/** /**
* ResetConfig 强制重置所有配置为默认值 * ResetConfig 强制重置所有配置为默认值
*/ */
@@ -58,6 +82,14 @@ export function Set(key: string, value: any): Promise<void> & { cancel(): void }
return $resultPromise; return $resultPromise;
} }
/**
* SetBackupConfigChangeCallback 设置备份配置变更回调
*/
export function SetBackupConfigChangeCallback(callback: any): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3264871659, callback) as any;
return $resultPromise;
}
/** /**
* SetDataPathChangeCallback 设置数据路径配置变更回调 * SetDataPathChangeCallback 设置数据路径配置变更回调
*/ */
@@ -74,6 +106,14 @@ export function SetHotkeyChangeCallback(callback: any): Promise<void> & { cancel
return $resultPromise; return $resultPromise;
} }
/**
* SetWindowSnapConfigChangeCallback 设置窗口吸附配置变更回调
*/
export function SetWindowSnapConfigChangeCallback(callback: any): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2324961653, callback) as any;
return $resultPromise;
}
// Private type creation functions // Private type creation functions
const $$createType0 = models$0.AppConfig.createFrom; const $$createType0 = models$0.AppConfig.createFrom;
const $$createType1 = $Create.Nullable($$createType0); const $$createType1 = $Create.Nullable($$createType0);

View File

@@ -22,6 +22,14 @@ export function OnDataPathChanged(): Promise<void> & { cancel(): void } {
return $resultPromise; return $resultPromise;
} }
/**
* RegisterModel 注册模型与表的映射关系
*/
export function RegisterModel(tableName: string, model: any): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(175397515, tableName, model) as any;
return $resultPromise;
}
/** /**
* ServiceShutdown shuts down the service when the application closes * ServiceShutdown shuts down the service when the application closes
*/ */

View File

@@ -22,6 +22,14 @@ export function SelectDirectory(): Promise<string> & { cancel(): void } {
return $resultPromise; return $resultPromise;
} }
/**
* SelectFile 打开文件选择对话框
*/
export function SelectFile(): Promise<string> & { cancel(): void } {
let $resultPromise = $Call.ByID(37302920) as any;
return $resultPromise;
}
/** /**
* SetWindow 设置绑定的窗口 * SetWindow 设置绑定的窗口
*/ */

View File

@@ -81,6 +81,14 @@ export function ListDeletedDocumentsMeta(): Promise<(models$0.Document | null)[]
return $typingPromise; return $typingPromise;
} }
/**
* LockDocument 锁定文档,防止删除
*/
export function LockDocument(id: number): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1889494473, id) as any;
return $resultPromise;
}
/** /**
* RestoreDocument restores a deleted document * RestoreDocument restores a deleted document
*/ */
@@ -97,6 +105,14 @@ export function ServiceStartup(options: application$0.ServiceOptions): Promise<v
return $resultPromise; return $resultPromise;
} }
/**
* UnlockDocument 解锁文档
*/
export function UnlockDocument(id: number): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(222307930, id) as any;
return $resultPromise;
}
/** /**
* UpdateDocumentContent updates the content of a document * UpdateDocumentContent updates the content of a document
*/ */

View File

@@ -32,8 +32,8 @@ export function GetCurrentHotkey(): Promise<models$0.HotkeyCombo | null> & { can
/** /**
* Initialize 初始化热键服务 * Initialize 初始化热键服务
*/ */
export function Initialize(app: application$0.App | null): Promise<void> & { cancel(): void } { export function Initialize(app: application$0.App | null, mainWindow: application$0.WebviewWindow | null): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3671360458, app) as any; let $resultPromise = $Call.ByID(3671360458, app, mainWindow) as any;
return $resultPromise; return $resultPromise;
} }

View File

@@ -1,6 +1,7 @@
// 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 BackupService from "./backupservice.js";
import * as ConfigService from "./configservice.js"; import * as ConfigService from "./configservice.js";
import * as DatabaseService from "./databaseservice.js"; import * as DatabaseService from "./databaseservice.js";
import * as DialogService from "./dialogservice.js"; import * as DialogService from "./dialogservice.js";
@@ -12,10 +13,13 @@ import * as MigrationService from "./migrationservice.js";
import * as SelfUpdateService from "./selfupdateservice.js"; import * as SelfUpdateService from "./selfupdateservice.js";
import * as StartupService from "./startupservice.js"; import * as StartupService from "./startupservice.js";
import * as SystemService from "./systemservice.js"; import * as SystemService from "./systemservice.js";
import * as TestService from "./testservice.js";
import * as ThemeService from "./themeservice.js";
import * as TranslationService from "./translationservice.js"; import * as TranslationService from "./translationservice.js";
import * as TrayService from "./trayservice.js"; import * as TrayService from "./trayservice.js";
import * as WindowService from "./windowservice.js"; import * as WindowService from "./windowservice.js";
export { export {
BackupService,
ConfigService, ConfigService,
DatabaseService, DatabaseService,
DialogService, DialogService,
@@ -27,6 +31,8 @@ export {
SelfUpdateService, SelfUpdateService,
StartupService, StartupService,
SystemService, SystemService,
TestService,
ThemeService,
TranslationService, TranslationService,
TrayService, TrayService,
WindowService WindowService

View File

@@ -203,7 +203,7 @@ export class SelfUpdateResult {
} }
/** /**
* WindowInfo 窗口信息 * WindowInfo 窗口信息(简化版)
*/ */
export class WindowInfo { export class WindowInfo {
"Window": application$0.WebviewWindow | null; "Window": application$0.WebviewWindow | null;
@@ -238,6 +238,26 @@ export class WindowInfo {
} }
} }
/**
* 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 = application$0.WebviewWindow.createFrom;
const $$createType1 = $Create.Nullable($$createType0); const $$createType1 = $Create.Nullable($$createType0);

View File

@@ -0,0 +1,55 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* TestService 测试服务 - 仅在开发环境使用
* @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 application$0 from "../../../github.com/wailsapp/wails/v3/pkg/application/models.js";
/**
* ClearAll 清除所有测试状态
*/
export function ClearAll(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2179720854) as any;
return $resultPromise;
}
/**
* ServiceStartup 服务启动时调用
*/
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(617408198, options) as any;
return $resultPromise;
}
/**
* TestBadge 测试Badge功能
*/
export function TestBadge(text: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(4242952145, text) as any;
return $resultPromise;
}
/**
* TestNotification 测试通知功能
*/
export function TestNotification(title: string, subtitle: string, body: string): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1697553289, title, subtitle, body) as any;
return $resultPromise;
}
/**
* TestUpdateNotification 测试更新通知
*/
export function TestUpdateNotification(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(3091730060) as any;
return $resultPromise;
}

View File

@@ -0,0 +1,104 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* ThemeService 主题服务
* @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 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$0 from "../models/models.js";
/**
* CreateTheme 创建新主题
*/
export function CreateTheme(theme: models$0.Theme | null): Promise<models$0.Theme | null> & { cancel(): void } {
let $resultPromise = $Call.ByID(3274757686, theme) as any;
let $typingPromise = $resultPromise.then(($result: any) => {
return $$createType1($result);
}) as any;
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
}
/**
* GetAllThemes 获取所有主题
*/
export function GetAllThemes(): Promise<(models$0.Theme | null)[]> & { cancel(): void } {
let $resultPromise = $Call.ByID(2425053076) 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;
}
/**
* ServiceShutdown 服务关闭
*/
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1676749034) as any;
return $resultPromise;
}
/**
* ServiceStartup 服务启动时初始化
*/
export function ServiceStartup(options: application$0.ServiceOptions): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2915959937, options) as any;
return $resultPromise;
}
/**
* UpdateThemeColors 更新主题颜色
*/
export function UpdateThemeColors(themeType: models$0.ThemeType, colors: models$0.ThemeColorConfig): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(2750902529, themeType, colors) as any;
return $resultPromise;
}
// Private type creation functions
const $$createType0 = models$0.Theme.createFrom;
const $$createType1 = $Create.Nullable($$createType0);
const $$createType2 = $Create.Array($$createType1);
const $$createType3 = $Create.Map($Create.Any, $$createType1);

View File

@@ -2,7 +2,7 @@
// This file is automatically generated. DO NOT EDIT // This file is automatically generated. DO NOT EDIT
/** /**
* WindowService 窗口管理服务 * WindowService 窗口管理服务(专注于窗口生命周期管理)
* @module * @module
*/ */
@@ -46,6 +46,14 @@ export function OpenDocumentWindow(documentID: number): Promise<void> & { cancel
return $resultPromise; return $resultPromise;
} }
/**
* ServiceShutdown 实现服务关闭接口
*/
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(202192783) as any;
return $resultPromise;
}
/** /**
* SetAppReferences 设置应用和主窗口引用 * SetAppReferences 设置应用和主窗口引用
*/ */
@@ -54,6 +62,14 @@ export function SetAppReferences(app: application$0.App | null, mainWindow: appl
return $resultPromise; return $resultPromise;
} }
/**
* SetWindowSnapService 设置窗口吸附服务引用
*/
export function SetWindowSnapService(snapService: $models.WindowSnapService | null): Promise<void> & { cancel(): void } {
let $resultPromise = $Call.ByID(1105193745, snapService) as any;
return $resultPromise;
}
// Private type creation functions // Private type creation functions
const $$createType0 = $models.WindowInfo.createFrom; const $$createType0 = $models.WindowInfo.createFrom;
const $$createType1 = $Create.Array($$createType0); const $$createType1 = $Create.Array($$createType0);

View File

@@ -50,7 +50,11 @@ export default defineConfig([
'.local', '.local',
'/bin', '/bin',
'Dockerfile', 'Dockerfile',
'**/bindings/' '**/bindings/',
'*.js',
'**/*.js',
'**/*.cjs',
'**/*.mjs',
], ],
} }
]); ]);

View File

@@ -9,5 +9,6 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
<script src="/math.js"></script>
</body> </body>
</html> </html>

File diff suppressed because it is too large Load Diff

View File

@@ -5,78 +5,86 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host --mode development", "dev": "vite --host --mode development",
"build:dev": "vue-tsc && vite build --minify false --mode development", "build:dev": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vue-tsc && cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" vite build --minify false --mode development",
"build": "vue-tsc && 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"
}, },
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.18.6", "@codemirror/autocomplete": "^6.18.7",
"@codemirror/commands": "^6.8.1", "@codemirror/commands": "^6.8.1",
"@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.9", "@codemirror/lang-html": "^6.4.10",
"@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.2.3", "@codemirror/lang-liquid": "^6.3.0",
"@codemirror/lang-markdown": "^6.3.3", "@codemirror/lang-markdown": "^6.3.4",
"@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.0", "@codemirror/lang-sql": "^6.9.1",
"@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-xml": "^6.1.0",
"@codemirror/lang-yaml": "^6.1.2", "@codemirror/lang-yaml": "^6.1.2",
"@codemirror/language": "^6.11.2", "@codemirror/language": "^6.11.3",
"@codemirror/language-data": "^6.5.1", "@codemirror/language-data": "^6.5.1",
"@codemirror/legacy-modes": "^6.5.1", "@codemirror/legacy-modes": "^6.5.1",
"@codemirror/lint": "^6.8.5", "@codemirror/lint": "^6.8.5",
"@codemirror/search": "^6.5.11", "@codemirror/search": "^6.5.11",
"@codemirror/state": "^6.5.2", "@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.38.0", "@codemirror/view": "^6.38.2",
"@cospaia/prettier-plugin-clojure": "^0.0.2",
"@lezer/highlight": "^1.2.1", "@lezer/highlight": "^1.2.1",
"@lezer/lr": "^1.4.2", "@lezer/lr": "^1.4.2",
"@prettier/plugin-xml": "^3.4.2",
"@toml-tools/lexer": "^1.0.0",
"@toml-tools/parser": "^1.0.0",
"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", "franc-min": "^6.2.0",
"groovy-beautify": "^0.0.17",
"hsl-matcher": "^1.2.4", "hsl-matcher": "^1.2.4",
"lezer": "^0.13.5", "java-parser": "^3.0.1",
"jsox": "^1.2.123",
"linguist-languages": "^9.0.0",
"php-parser": "^3.2.5",
"pinia": "^3.0.3", "pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.4.1", "pinia-plugin-persistedstate": "^4.5.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"remarkable": "^2.0.1", "remarkable": "^2.0.1",
"sass": "^1.89.2", "sass": "^1.92.1",
"vue": "^3.5.17", "vue": "^3.5.21",
"vue-i18n": "^11.1.9", "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.5.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.30.1", "@eslint/js": "^9.35.0",
"@lezer/generator": "^1.8.0", "@lezer/generator": "^1.8.0",
"@types/lodash": "^4.17.20", "@types/node": "^24.3.1",
"@types/node": "^24.0.12",
"@types/remarkable": "^2.0.8", "@types/remarkable": "^2.0.8",
"@vitejs/plugin-vue": "^6.0.0", "@vitejs/plugin-vue": "^6.0.1",
"@wailsio/runtime": "latest", "@wailsio/runtime": "latest",
"eslint": "^9.30.1", "cross-env": "^7.0.3",
"eslint-plugin-vue": "^10.3.0", "eslint": "^9.35.0",
"globals": "^16.3.0", "eslint-plugin-vue": "^10.4.0",
"typescript": "^5.8.3", "globals": "^16.4.0",
"typescript-eslint": "^8.36.0", "typescript": "^5.9.2",
"unplugin-vue-components": "^28.8.0", "typescript-eslint": "^8.43.0",
"vite": "^7.0.3", "unplugin-vue-components": "^29.0.0",
"vite": "^7.1.5",
"vite-plugin-node-polyfills": "^0.24.0",
"vue-eslint-parser": "^10.2.0", "vue-eslint-parser": "^10.2.0",
"vue-tsc": "^3.0.1" "vue-tsc": "^3.0.6"
} }
} }

View File

@@ -1,7 +1,5 @@
importScripts("guesslang.min.js") importScripts("guesslang.min.js")
const LANGUAGES = ["json", "py", "html", "sql", "md", "java", "php", "css", "xml", "cpp", "rs", "cs", "rb", "sh", "yaml", "toml", "go", "clj", "ex", "erl", "js", "ts", "swift", "kt", "groovy", "ps1", "dart", "scala"]
const guessLang = new self.GuessLang() const guessLang = new self.GuessLang()
function sendResult(language, confidence, idx) { function sendResult(language, confidence, idx) {
@@ -27,20 +25,13 @@ onmessage = (event) => {
guessLang.runModel(content).then((result) => { guessLang.runModel(content).then((result) => {
if (result.length > 0) { if (result.length > 0) {
const lang = result[0] // 返回置信度最高的结果
if (LANGUAGES.includes(lang.languageId) && lang.confidence > 0.15) { const bestResult = result[0]
sendResult(lang.languageId, lang.confidence, idx) if (bestResult.confidence > 0.15) {
sendResult(bestResult.languageId, bestResult.confidence, idx)
return return
} }
} }
for (let lang of result) {
if (LANGUAGES.includes(lang.languageId) && lang.confidence > 0.5) {
sendResult(lang.languageId, lang.confidence, idx)
return
}
}
sendResult("text", 0.0, idx) sendResult("text", 0.0, idx)
}).catch(() => { }).catch(() => {
sendResult("text", 0.0, idx) sendResult("text", 0.0, idx)

3
frontend/public/math.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,10 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue'; import {onMounted} 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';
const configStore = useConfigStore(); const configStore = useConfigStore();
@@ -12,6 +13,7 @@ const systemStore = useSystemStore();
const keybindingStore = useKeybindingStore(); const keybindingStore = useKeybindingStore();
const themeStore = useThemeStore(); const themeStore = useThemeStore();
const updateStore = useUpdateStore(); const updateStore = useUpdateStore();
const backupStore = useBackupStore();
// 应用启动时加载配置和初始化系统信息 // 应用启动时加载配置和初始化系统信息
onMounted(async () => { onMounted(async () => {
@@ -26,6 +28,9 @@ onMounted(async () => {
await configStore.initializeLanguage(); await configStore.initializeLanguage();
themeStore.initializeTheme(); themeStore.initializeTheme();
// 初始化备份服务
await backupStore.initialize();
// 启动时检查更新 // 启动时检查更新
await updateStore.checkOnStartup(); await updateStore.checkOnStartup();
}); });
@@ -33,7 +38,7 @@ onMounted(async () => {
<template> <template>
<div class="app-container"> <div class="app-container">
<WindowTitleBar /> <WindowTitleBar/>
<div class="app-content"> <div class="app-content">
<router-view/> <router-view/>
</div> </div>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,254 @@
#!/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()

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