⚡ Optimize font size and add more fonts
This commit is contained in:
BIN
frontend/src/assets/fonts/Hack/hack-bold.woff
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-bold.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/Hack/hack-bold.woff2
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-bold.woff2
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/Hack/hack-bolditalic.woff
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-bolditalic.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/Hack/hack-bolditalic.woff2
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-bolditalic.woff2
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/Hack/hack-italic.woff
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-italic.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/Hack/hack-italic.woff2
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-italic.woff2
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/Hack/hack-regular.woff
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-regular.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/Hack/hack-regular.woff2
Normal file
BIN
frontend/src/assets/fonts/Hack/hack-regular.woff2
Normal file
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.
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.
254
frontend/src/assets/fonts/HarmonyOS/font_compressor.py
Normal file
254
frontend/src/assets/fonts/HarmonyOS/font_compressor.py
Normal 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()
|
||||||
BIN
frontend/src/assets/fonts/OpenSans/Bold/OpenSans-Bold.woff
Normal file
BIN
frontend/src/assets/fonts/OpenSans/Bold/OpenSans-Bold.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/OpenSans/Bold/OpenSans-Bold.woff2
Normal file
BIN
frontend/src/assets/fonts/OpenSans/Bold/OpenSans-Bold.woff2
Normal file
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.
BIN
frontend/src/assets/fonts/OpenSans/Italic/OpenSans-Italic.woff
Normal file
BIN
frontend/src/assets/fonts/OpenSans/Italic/OpenSans-Italic.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/OpenSans/Italic/OpenSans-Italic.woff2
Normal file
BIN
frontend/src/assets/fonts/OpenSans/Italic/OpenSans-Italic.woff2
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/OpenSans/Light/OpenSans-Light.woff
Normal file
BIN
frontend/src/assets/fonts/OpenSans/Light/OpenSans-Light.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/fonts/OpenSans/Light/OpenSans-Light.woff2
Normal file
BIN
frontend/src/assets/fonts/OpenSans/Light/OpenSans-Light.woff2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
frontend/src/assets/fonts/OpenSans/Regular/OpenSans-Regular.woff
Normal file
BIN
frontend/src/assets/fonts/OpenSans/Regular/OpenSans-Regular.woff
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,146 +0,0 @@
|
|||||||
/* HarmonyOS Sans 字体定义 */
|
|
||||||
|
|
||||||
/* HarmonyOS Sans Regular */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Regular.ttf') format('truetype');
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans Light */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Light.ttf') format('truetype');
|
|
||||||
font-weight: 300;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans Medium */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Medium.ttf') format('truetype');
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans Semibold */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Semibold.ttf') format('truetype');
|
|
||||||
font-weight: 600;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans Bold */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Bold.ttf') format('truetype');
|
|
||||||
font-weight: 700;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans Black */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Black.ttf') format('truetype');
|
|
||||||
font-weight: 900;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans Thin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_Sans/HarmonyOS_Sans_Thin.ttf') format('truetype');
|
|
||||||
font-weight: 100;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC 简体中文字体 */
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC Regular */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans SC';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Regular.ttf') format('truetype');
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC Light */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans SC';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Light.ttf') format('truetype');
|
|
||||||
font-weight: 300;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC Medium */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans SC';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Medium.ttf') format('truetype');
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC Semibold */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans SC';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Semibold.ttf') format('truetype');
|
|
||||||
font-weight: 600;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC Bold */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans SC';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Bold.ttf') format('truetype');
|
|
||||||
font-weight: 700;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC Black */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans SC';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Black.ttf') format('truetype');
|
|
||||||
font-weight: 900;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HarmonyOS Sans SC Thin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'HarmonyOS Sans SC';
|
|
||||||
src: url('../fonts/HarmonyOS Sans/HarmonyOS_SansSC/HarmonyOS_SansSC_Thin.ttf') format('truetype');
|
|
||||||
font-weight: 100;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 字体加载优化 */
|
|
||||||
.font-loading {
|
|
||||||
font-family: system-ui, -apple-system, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-loaded {
|
|
||||||
font-family: 'HarmonyOS Sans SC', 'HarmonyOS Sans', 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CodeMirror 专用字体类 */
|
|
||||||
.cm-harmonyos-font {
|
|
||||||
font-family: 'HarmonyOS Sans SC', 'HarmonyOS Sans', 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif !important;
|
|
||||||
font-feature-settings: 'liga' 1, 'calt' 1;
|
|
||||||
font-variant-ligatures: contextual;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
}
|
|
||||||
31
frontend/src/assets/styles/hack_fonts.css
Normal file
31
frontend/src/assets/styles/hack_fonts.css
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Hack';
|
||||||
|
src: url('../fonts/Hack/hack-regular.woff2') format('woff2'),
|
||||||
|
url('../fonts/Hack/hack-regular.woff') format('woff');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Hack';
|
||||||
|
src: url('../fonts/Hack/hack-bold.woff2') format('woff2'),
|
||||||
|
url('../fonts/Hack/hack-bold.woff') format('woff');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Hack';
|
||||||
|
src: url('../fonts/Hack/hack-italic.woff2') format('woff2'),
|
||||||
|
url('../fonts/Hack/hack-italic.woff') format('woff');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Hack';
|
||||||
|
src: url('../fonts/Hack/hack-bolditalic.woff2') format('woff2'),
|
||||||
|
url('../fonts/Hack/hack-bolditalic.woff') format('woff');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
134
frontend/src/assets/styles/harmony_fonts.css
Normal file
134
frontend/src/assets/styles/harmony_fonts.css
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/* HarmonyOS 字体定义 */
|
||||||
|
|
||||||
|
/* HarmonyOS Regular */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_Sans/HarmonyOS_Sans_Regular.woff2') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS Light */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_Sans/HarmonyOS_Sans_Light.woff2') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS Medium */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_Sans/HarmonyOS_Sans_Medium.woff2') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS Semibold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_Sans/HarmonyOS_Sans_Semibold.woff2') format('truetype');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS Bold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_Sans/HarmonyOS_Sans_Bold.woff2') format('truetype');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS Black */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_Sans/HarmonyOS_Sans_Black.woff2') format('truetype');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS Thin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_Sans/HarmonyOS_Sans_Thin.woff2') format('truetype');
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS SC 简体中文字体 */
|
||||||
|
|
||||||
|
/* HarmonyOS SC Regular */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_SansSC/HarmonyOS_SansSC_Regular.woff2') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS SC Light */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_SansSC/HarmonyOS_SansSC_Light.woff2') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS SC Medium */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_SansSC/HarmonyOS_SansSC_Medium.woff2') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS SC Semibold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_SansSC/HarmonyOS_SansSC_Semibold.woff2') format('truetype');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS SC Bold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_SansSC/HarmonyOS_SansSC_Bold.woff2') format('truetype');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS SC Black */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_SansSC/HarmonyOS_SansSC_Black.woff2') format('truetype');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HarmonyOS SC Thin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'HarmonyOS';
|
||||||
|
src: url('../fonts/HarmonyOS/HarmonyOS_SansSC/HarmonyOS_SansSC_Thin.woff2') format('truetype');
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 字体加载优化 */
|
||||||
|
.font-loading {
|
||||||
|
font-family: system-ui, -apple-system, sans-serif;
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
/* 导入所有CSS文件 */
|
/* 导入所有CSS文件 */
|
||||||
@import 'normalize.css';
|
@import 'normalize.css';
|
||||||
@import 'variables.css';
|
@import 'variables.css';
|
||||||
@import "fonts.css";
|
@import "harmony_fonts.css";
|
||||||
@import 'scrollbar.css';
|
@import 'scrollbar.css';
|
||||||
|
@import 'hack_fonts.css';
|
||||||
|
@import 'opensans_fonts.css';
|
||||||
80
frontend/src/assets/styles/opensans_fonts.css
Normal file
80
frontend/src/assets/styles/opensans_fonts.css
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/* BEGIN Light */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/Light/OpenSans-Light.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/Light/OpenSans-Light.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* END Light */
|
||||||
|
/* BEGIN Light Italic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/LightItalic/OpenSans-LightItalic.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/LightItalic/OpenSans-LightItalic.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
/* END Light Italic */
|
||||||
|
/* BEGIN Regular */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/Regular/OpenSans-Regular.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/Regular/OpenSans-Regular.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* END Regular */
|
||||||
|
/* BEGIN Italic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/Italic/OpenSans-Italic.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/Italic/OpenSans-Italic.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
/* END Italic */
|
||||||
|
/* BEGIN Semibold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/Semibold/OpenSans-Semibold.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/Semibold/OpenSans-Semibold.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* END Semibold */
|
||||||
|
/* BEGIN Semibold Italic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/SemiboldItalic/OpenSans-SemiboldItalic.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/SemiboldItalic/OpenSans-SemiboldItalic.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
/* END Semibold Italic */
|
||||||
|
/* BEGIN Bold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/Bold/OpenSans-Bold.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/Bold/OpenSans-Bold.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* END Bold */
|
||||||
|
/* BEGIN Bold Italic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/BoldItalic/OpenSans-BoldItalic.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/BoldItalic/OpenSans-BoldItalic.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
/* END Bold Italic */
|
||||||
|
/* BEGIN Extrabold */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/ExtraBold/OpenSans-ExtraBold.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/ExtraBold/OpenSans-ExtraBold.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* END Extrabold */
|
||||||
|
/* BEGIN Extrabold Italic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
src: url("../fonts/OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff2?v=1.1.0") format("woff2"), url("../fonts/OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff?v=1.1.0") format("woff");
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
/* END Extrabold Italic */
|
||||||
164
frontend/src/common/constant/config.ts
Normal file
164
frontend/src/common/constant/config.ts
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import {
|
||||||
|
AppConfig,
|
||||||
|
AppearanceConfig,
|
||||||
|
EditingConfig,
|
||||||
|
GeneralConfig,
|
||||||
|
LanguageType,
|
||||||
|
SystemThemeType,
|
||||||
|
TabType,
|
||||||
|
UpdatesConfig,
|
||||||
|
UpdateSourceType,
|
||||||
|
GitBackupConfig,
|
||||||
|
AuthMethod
|
||||||
|
} from '@/../bindings/voidraft/internal/models/models';
|
||||||
|
import {FONT_OPTIONS} from './fonts';
|
||||||
|
|
||||||
|
// 配置键映射和限制的类型定义
|
||||||
|
export type GeneralConfigKeyMap = {
|
||||||
|
readonly [K in keyof GeneralConfig]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EditingConfigKeyMap = {
|
||||||
|
readonly [K in keyof EditingConfig]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AppearanceConfigKeyMap = {
|
||||||
|
readonly [K in keyof AppearanceConfig]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdatesConfigKeyMap = {
|
||||||
|
readonly [K in keyof UpdatesConfig]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BackupConfigKeyMap = {
|
||||||
|
readonly [K in keyof GitBackupConfig]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NumberConfigKey = 'fontSize' | 'tabSize' | 'lineHeight';
|
||||||
|
|
||||||
|
// 配置键映射
|
||||||
|
export const GENERAL_CONFIG_KEY_MAP: GeneralConfigKeyMap = {
|
||||||
|
alwaysOnTop: 'general.alwaysOnTop',
|
||||||
|
dataPath: 'general.dataPath',
|
||||||
|
enableSystemTray: 'general.enableSystemTray',
|
||||||
|
startAtLogin: 'general.startAtLogin',
|
||||||
|
enableGlobalHotkey: 'general.enableGlobalHotkey',
|
||||||
|
globalHotkey: 'general.globalHotkey',
|
||||||
|
enableWindowSnap: 'general.enableWindowSnap',
|
||||||
|
enableLoadingAnimation: 'general.enableLoadingAnimation',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const EDITING_CONFIG_KEY_MAP: EditingConfigKeyMap = {
|
||||||
|
fontSize: 'editing.fontSize',
|
||||||
|
fontFamily: 'editing.fontFamily',
|
||||||
|
fontWeight: 'editing.fontWeight',
|
||||||
|
lineHeight: 'editing.lineHeight',
|
||||||
|
enableTabIndent: 'editing.enableTabIndent',
|
||||||
|
tabSize: 'editing.tabSize',
|
||||||
|
tabType: 'editing.tabType',
|
||||||
|
autoSaveDelay: 'editing.autoSaveDelay'
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const APPEARANCE_CONFIG_KEY_MAP: AppearanceConfigKeyMap = {
|
||||||
|
language: 'appearance.language',
|
||||||
|
systemTheme: 'appearance.systemTheme'
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const UPDATES_CONFIG_KEY_MAP: UpdatesConfigKeyMap = {
|
||||||
|
version: 'updates.version',
|
||||||
|
autoUpdate: 'updates.autoUpdate',
|
||||||
|
primarySource: 'updates.primarySource',
|
||||||
|
backupSource: 'updates.backupSource',
|
||||||
|
backupBeforeUpdate: 'updates.backupBeforeUpdate',
|
||||||
|
updateTimeout: 'updates.updateTimeout',
|
||||||
|
github: 'updates.github',
|
||||||
|
gitea: 'updates.gitea'
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const BACKUP_CONFIG_KEY_MAP: BackupConfigKeyMap = {
|
||||||
|
enabled: 'backup.enabled',
|
||||||
|
repo_url: 'backup.repo_url',
|
||||||
|
auth_method: 'backup.auth_method',
|
||||||
|
username: 'backup.username',
|
||||||
|
password: 'backup.password',
|
||||||
|
token: 'backup.token',
|
||||||
|
ssh_key_path: 'backup.ssh_key_path',
|
||||||
|
ssh_key_passphrase: 'backup.ssh_key_passphrase',
|
||||||
|
backup_interval: 'backup.backup_interval',
|
||||||
|
auto_backup: 'backup.auto_backup',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 配置限制
|
||||||
|
export const CONFIG_LIMITS = {
|
||||||
|
fontSize: {min: 12, max: 28, default: 13},
|
||||||
|
tabSize: {min: 2, max: 8, default: 4},
|
||||||
|
lineHeight: {min: 1.0, max: 3.0, default: 1.5},
|
||||||
|
tabType: {values: [TabType.TabTypeSpaces, TabType.TabTypeTab], default: TabType.TabTypeSpaces}
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 默认配置
|
||||||
|
export const DEFAULT_CONFIG: AppConfig = {
|
||||||
|
general: {
|
||||||
|
alwaysOnTop: false,
|
||||||
|
dataPath: '',
|
||||||
|
enableSystemTray: true,
|
||||||
|
startAtLogin: false,
|
||||||
|
enableGlobalHotkey: false,
|
||||||
|
globalHotkey: {
|
||||||
|
ctrl: false,
|
||||||
|
shift: false,
|
||||||
|
alt: true,
|
||||||
|
win: false,
|
||||||
|
key: 'X'
|
||||||
|
},
|
||||||
|
enableWindowSnap: true,
|
||||||
|
enableLoadingAnimation: true,
|
||||||
|
},
|
||||||
|
editing: {
|
||||||
|
fontSize: CONFIG_LIMITS.fontSize.default,
|
||||||
|
fontFamily: FONT_OPTIONS[0].value,
|
||||||
|
fontWeight: 'normal',
|
||||||
|
lineHeight: CONFIG_LIMITS.lineHeight.default,
|
||||||
|
enableTabIndent: true,
|
||||||
|
tabSize: CONFIG_LIMITS.tabSize.default,
|
||||||
|
tabType: CONFIG_LIMITS.tabType.default,
|
||||||
|
autoSaveDelay: 5000
|
||||||
|
},
|
||||||
|
appearance: {
|
||||||
|
language: LanguageType.LangZhCN,
|
||||||
|
systemTheme: SystemThemeType.SystemThemeAuto
|
||||||
|
},
|
||||||
|
updates: {
|
||||||
|
version: "1.0.0",
|
||||||
|
autoUpdate: true,
|
||||||
|
primarySource: UpdateSourceType.UpdateSourceGithub,
|
||||||
|
backupSource: UpdateSourceType.UpdateSourceGitea,
|
||||||
|
backupBeforeUpdate: true,
|
||||||
|
updateTimeout: 30,
|
||||||
|
github: {
|
||||||
|
owner: "landaiqing",
|
||||||
|
repo: "voidraft",
|
||||||
|
},
|
||||||
|
gitea: {
|
||||||
|
baseURL: "https://git.landaiqing.cn",
|
||||||
|
owner: "landaiqing",
|
||||||
|
repo: "voidraft",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backup: {
|
||||||
|
enabled: false,
|
||||||
|
repo_url: "",
|
||||||
|
auth_method: AuthMethod.UserPass,
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
token: "",
|
||||||
|
ssh_key_path: "",
|
||||||
|
ssh_key_passphrase: "",
|
||||||
|
backup_interval: 60,
|
||||||
|
auto_backup: true,
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
version: '1.0.0',
|
||||||
|
lastUpdated: new Date().toString(),
|
||||||
|
}
|
||||||
|
};
|
||||||
101
frontend/src/common/constant/fonts.ts
Normal file
101
frontend/src/common/constant/fonts.ts
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
// Font options with popular programming and common fonts
|
||||||
|
export const FONT_OPTIONS = [
|
||||||
|
// Custom fonts
|
||||||
|
{
|
||||||
|
label: 'HarmonyOS',
|
||||||
|
value: 'HarmonyOS'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hack',
|
||||||
|
value: 'Hack'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open Sans',
|
||||||
|
value: '"Open Sans"'
|
||||||
|
},
|
||||||
|
// Common system fonts
|
||||||
|
{
|
||||||
|
label: 'Arial',
|
||||||
|
value: 'Arial'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Helvetica',
|
||||||
|
value: 'Helvetica'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Times New Roman',
|
||||||
|
value: '"Times New Roman"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Georgia',
|
||||||
|
value: 'Georgia'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Verdana',
|
||||||
|
value: 'Verdana'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Tahoma',
|
||||||
|
value: 'Tahoma'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Segoe UI',
|
||||||
|
value: '"Segoe UI"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'System UI',
|
||||||
|
value: 'system-ui'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Chinese fonts
|
||||||
|
{
|
||||||
|
label: 'Microsoft YaHei',
|
||||||
|
value: '"Microsoft YaHei"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'PingFang SC',
|
||||||
|
value: '"PingFang SC"'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Popular programming fonts
|
||||||
|
{
|
||||||
|
label: 'JetBrains Mono',
|
||||||
|
value: '"JetBrains Mono"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fira Code',
|
||||||
|
value: '"Fira Code"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Source Code Pro',
|
||||||
|
value: '"Source Code Pro"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cascadia Code',
|
||||||
|
value: '"Cascadia Code"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Consolas',
|
||||||
|
value: 'Consolas'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Monaco',
|
||||||
|
value: 'Monaco'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Menlo',
|
||||||
|
value: 'Menlo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Roboto Mono',
|
||||||
|
value: '"Roboto Mono"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Inconsolata',
|
||||||
|
value: 'Inconsolata'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Ubuntu Mono',
|
||||||
|
value: '"Ubuntu Mono"'
|
||||||
|
}
|
||||||
|
];
|
||||||
13
frontend/src/common/constant/locales.ts
Normal file
13
frontend/src/common/constant/locales.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export type SupportedLocaleType = 'zh-CN' | 'en-US';
|
||||||
|
|
||||||
|
// 支持的语言列表
|
||||||
|
export const SUPPORTED_LOCALES = [
|
||||||
|
{
|
||||||
|
code: 'zh-CN' as SupportedLocaleType,
|
||||||
|
name: '简体中文'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'en-US' as SupportedLocaleType,
|
||||||
|
name: 'English'
|
||||||
|
}
|
||||||
|
] as const;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LanguageType } from '../../../bindings/voidraft/internal/models/models';
|
import { LanguageType } from '@/../bindings/voidraft/internal/models/models';
|
||||||
import type { SupportedLocaleType } from '@/stores/configStore';
|
import type { SupportedLocaleType } from '@/common/constant/locales';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置工具类
|
* 配置工具类
|
||||||
|
|||||||
@@ -370,6 +370,12 @@ onUnmounted(() => {
|
|||||||
<div class="document-selector">
|
<div class="document-selector">
|
||||||
<!-- 选择器按钮 -->
|
<!-- 选择器按钮 -->
|
||||||
<button class="doc-btn" @click="toggleMenu">
|
<button class="doc-btn" @click="toggleMenu">
|
||||||
|
<span class="doc-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path>
|
||||||
|
<polyline points="14,2 14,8 20,8"></polyline>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
<span class="doc-name">{{ currentDocName }}</span>
|
<span class="doc-name">{{ currentDocName }}</span>
|
||||||
<span class="arrow" :class="{ open: showMenu }">▲</span>
|
<span class="arrow" :class="{ open: showMenu }">▲</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -519,6 +525,11 @@ onUnmounted(() => {
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.doc-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.doc-name {
|
.doc-name {
|
||||||
max-width: 80px;
|
max-width: 80px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@@ -144,23 +144,9 @@ export default {
|
|||||||
resetDefault: 'Reset Default',
|
resetDefault: 'Reset Default',
|
||||||
resetToDefaultPath: 'Reset to default path',
|
resetToDefaultPath: 'Reset to default path',
|
||||||
fontSize: 'Font Size',
|
fontSize: 'Font Size',
|
||||||
fontSizeDescription: 'Editor font size',
|
|
||||||
fontSettings: 'Font Settings',
|
fontSettings: 'Font Settings',
|
||||||
fontFamily: 'Font Family',
|
fontFamily: 'Font Family',
|
||||||
fontFamilyDescription: 'Choose editor font family',
|
|
||||||
fontWeight: 'Font Weight',
|
fontWeight: 'Font Weight',
|
||||||
fontWeightDescription: 'Set the thickness of the font',
|
|
||||||
fontWeights: {
|
|
||||||
'100': 'Thin (100)',
|
|
||||||
'200': 'Extra Light (200)',
|
|
||||||
'300': 'Light (300)',
|
|
||||||
'normal': 'Regular (400)',
|
|
||||||
'500': 'Medium (500)',
|
|
||||||
'600': 'Semi Bold (600)',
|
|
||||||
'bold': 'Bold (700)',
|
|
||||||
'800': 'Extra Bold (800)',
|
|
||||||
'900': 'Black (900)'
|
|
||||||
},
|
|
||||||
customThemeColors: 'Custom Theme Colors',
|
customThemeColors: 'Custom Theme Colors',
|
||||||
resetToDefault: 'Reset to Default',
|
resetToDefault: 'Reset to Default',
|
||||||
colorValue: 'Color Value',
|
colorValue: 'Color Value',
|
||||||
@@ -195,17 +181,7 @@ export default {
|
|||||||
searchMatch: 'Search Match',
|
searchMatch: 'Search Match',
|
||||||
matchingBracket: 'Matching Bracket'
|
matchingBracket: 'Matching Bracket'
|
||||||
},
|
},
|
||||||
fontFamilies: {
|
|
||||||
harmonyOS: 'HarmonyOS Sans',
|
|
||||||
microsoftYahei: 'Microsoft YaHei',
|
|
||||||
pingfang: 'PingFang SC',
|
|
||||||
jetbrainsMono: 'JetBrains Mono',
|
|
||||||
firaCode: 'Fira Code',
|
|
||||||
sourceCodePro: 'Source Code Pro',
|
|
||||||
cascadiaCode: 'Cascadia Code'
|
|
||||||
},
|
|
||||||
lineHeight: 'Line Height',
|
lineHeight: 'Line Height',
|
||||||
lineHeightDescription: 'Set the spacing between text lines',
|
|
||||||
tabSettings: 'Tab Settings',
|
tabSettings: 'Tab Settings',
|
||||||
tabSize: 'Tab Size',
|
tabSize: 'Tab Size',
|
||||||
tabType: 'Tab Type',
|
tabType: 'Tab Type',
|
||||||
|
|||||||
@@ -145,14 +145,10 @@ export default {
|
|||||||
resetDefault: '恢复默认',
|
resetDefault: '恢复默认',
|
||||||
resetToDefaultPath: '恢复为默认路径',
|
resetToDefaultPath: '恢复为默认路径',
|
||||||
fontSize: '字体大小',
|
fontSize: '字体大小',
|
||||||
fontSizeDescription: '编辑器字体大小',
|
|
||||||
fontSettings: '字体设置',
|
fontSettings: '字体设置',
|
||||||
fontFamily: '字体',
|
fontFamily: '字体',
|
||||||
fontFamilyDescription: '选择编辑器字体',
|
|
||||||
fontWeight: '字体粗细',
|
fontWeight: '字体粗细',
|
||||||
fontWeightDescription: '设置字体的粗细程度',
|
|
||||||
lineHeight: '行高',
|
lineHeight: '行高',
|
||||||
lineHeightDescription: '设置文本行之间的间距',
|
|
||||||
tabSettings: 'Tab 设置',
|
tabSettings: 'Tab 设置',
|
||||||
tabSize: 'Tab 大小',
|
tabSize: 'Tab 大小',
|
||||||
tabType: 'Tab 类型',
|
tabType: 'Tab 类型',
|
||||||
@@ -190,17 +186,7 @@ export default {
|
|||||||
configuration: '配置',
|
configuration: '配置',
|
||||||
resetToDefault: '重置为默认配置',
|
resetToDefault: '重置为默认配置',
|
||||||
},
|
},
|
||||||
fontWeights: {
|
|
||||||
'100': '极细 (100)',
|
|
||||||
'200': '超细 (200)',
|
|
||||||
'300': '细 (300)',
|
|
||||||
'normal': '正常 (400)',
|
|
||||||
'500': '中等 (500)',
|
|
||||||
'600': '半粗 (600)',
|
|
||||||
'bold': '粗体 (700)',
|
|
||||||
'800': '超粗 (800)',
|
|
||||||
'900': '极粗 (900)'
|
|
||||||
},
|
|
||||||
customThemeColors: '自定义主题颜色',
|
customThemeColors: '自定义主题颜色',
|
||||||
resetToDefault: '重置为默认',
|
resetToDefault: '重置为默认',
|
||||||
colorValue: '颜色值',
|
colorValue: '颜色值',
|
||||||
@@ -235,15 +221,7 @@ export default {
|
|||||||
searchMatch: '搜索匹配',
|
searchMatch: '搜索匹配',
|
||||||
matchingBracket: '匹配括号'
|
matchingBracket: '匹配括号'
|
||||||
},
|
},
|
||||||
fontFamilies: {
|
|
||||||
harmonyOS: '鸿蒙字体',
|
|
||||||
microsoftYahei: '微软雅黑',
|
|
||||||
pingfang: '苹方字体',
|
|
||||||
jetbrainsMono: 'JetBrains Mono',
|
|
||||||
firaCode: 'Fira Code',
|
|
||||||
sourceCodePro: 'Source Code Pro',
|
|
||||||
cascadiaCode: 'Cascadia Code'
|
|
||||||
},
|
|
||||||
hotkeyPreview: '预览:',
|
hotkeyPreview: '预览:',
|
||||||
none: '无',
|
none: '无',
|
||||||
backup: {
|
backup: {
|
||||||
|
|||||||
@@ -10,146 +10,24 @@ import {
|
|||||||
SystemThemeType,
|
SystemThemeType,
|
||||||
TabType,
|
TabType,
|
||||||
UpdatesConfig,
|
UpdatesConfig,
|
||||||
UpdateSourceType,
|
|
||||||
GitBackupConfig,
|
GitBackupConfig,
|
||||||
AuthMethod
|
AuthMethod
|
||||||
} from '@/../bindings/voidraft/internal/models/models';
|
} from '@/../bindings/voidraft/internal/models/models';
|
||||||
import {useI18n} from 'vue-i18n';
|
import {useI18n} from 'vue-i18n';
|
||||||
import {ConfigUtils} from '@/common/utils/configUtils';
|
import {ConfigUtils} from '@/common/utils/configUtils';
|
||||||
|
import {FONT_OPTIONS} from '@/common/constant/fonts';
|
||||||
|
import {SupportedLocaleType, SUPPORTED_LOCALES} from '@/common/constant/locales';
|
||||||
|
import {
|
||||||
|
NumberConfigKey,
|
||||||
|
GENERAL_CONFIG_KEY_MAP,
|
||||||
|
EDITING_CONFIG_KEY_MAP,
|
||||||
|
APPEARANCE_CONFIG_KEY_MAP,
|
||||||
|
UPDATES_CONFIG_KEY_MAP,
|
||||||
|
BACKUP_CONFIG_KEY_MAP,
|
||||||
|
CONFIG_LIMITS,
|
||||||
|
DEFAULT_CONFIG
|
||||||
|
} from '@/common/constant/config';
|
||||||
import * as runtime from '@wailsio/runtime';
|
import * as runtime from '@wailsio/runtime';
|
||||||
// 国际化相关导入
|
|
||||||
export type SupportedLocaleType = 'zh-CN' | 'en-US';
|
|
||||||
|
|
||||||
// 支持的语言列表
|
|
||||||
export const SUPPORTED_LOCALES = [
|
|
||||||
{
|
|
||||||
code: 'zh-CN' as SupportedLocaleType,
|
|
||||||
name: '简体中文'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'en-US' as SupportedLocaleType,
|
|
||||||
name: 'English'
|
|
||||||
}
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
// 配置键映射和限制的类型定义
|
|
||||||
type GeneralConfigKeyMap = {
|
|
||||||
readonly [K in keyof GeneralConfig]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type EditingConfigKeyMap = {
|
|
||||||
readonly [K in keyof EditingConfig]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type AppearanceConfigKeyMap = {
|
|
||||||
readonly [K in keyof AppearanceConfig]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type UpdatesConfigKeyMap = {
|
|
||||||
readonly [K in keyof UpdatesConfig]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type BackupConfigKeyMap = {
|
|
||||||
readonly [K in keyof GitBackupConfig]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type NumberConfigKey = 'fontSize' | 'tabSize' | 'lineHeight';
|
|
||||||
|
|
||||||
// 配置键映射
|
|
||||||
const GENERAL_CONFIG_KEY_MAP: GeneralConfigKeyMap = {
|
|
||||||
alwaysOnTop: 'general.alwaysOnTop',
|
|
||||||
dataPath: 'general.dataPath',
|
|
||||||
enableSystemTray: 'general.enableSystemTray',
|
|
||||||
startAtLogin: 'general.startAtLogin',
|
|
||||||
enableGlobalHotkey: 'general.enableGlobalHotkey',
|
|
||||||
globalHotkey: 'general.globalHotkey',
|
|
||||||
enableWindowSnap: 'general.enableWindowSnap',
|
|
||||||
enableLoadingAnimation: 'general.enableLoadingAnimation',
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const EDITING_CONFIG_KEY_MAP: EditingConfigKeyMap = {
|
|
||||||
fontSize: 'editing.fontSize',
|
|
||||||
fontFamily: 'editing.fontFamily',
|
|
||||||
fontWeight: 'editing.fontWeight',
|
|
||||||
lineHeight: 'editing.lineHeight',
|
|
||||||
enableTabIndent: 'editing.enableTabIndent',
|
|
||||||
tabSize: 'editing.tabSize',
|
|
||||||
tabType: 'editing.tabType',
|
|
||||||
autoSaveDelay: 'editing.autoSaveDelay'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const APPEARANCE_CONFIG_KEY_MAP: AppearanceConfigKeyMap = {
|
|
||||||
language: 'appearance.language',
|
|
||||||
systemTheme: 'appearance.systemTheme'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const UPDATES_CONFIG_KEY_MAP: UpdatesConfigKeyMap = {
|
|
||||||
version: 'updates.version',
|
|
||||||
autoUpdate: 'updates.autoUpdate',
|
|
||||||
primarySource: 'updates.primarySource',
|
|
||||||
backupSource: 'updates.backupSource',
|
|
||||||
backupBeforeUpdate: 'updates.backupBeforeUpdate',
|
|
||||||
updateTimeout: 'updates.updateTimeout',
|
|
||||||
github: 'updates.github',
|
|
||||||
gitea: 'updates.gitea'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const BACKUP_CONFIG_KEY_MAP: BackupConfigKeyMap = {
|
|
||||||
enabled: 'backup.enabled',
|
|
||||||
repo_url: 'backup.repo_url',
|
|
||||||
auth_method: 'backup.auth_method',
|
|
||||||
username: 'backup.username',
|
|
||||||
password: 'backup.password',
|
|
||||||
token: 'backup.token',
|
|
||||||
ssh_key_path: 'backup.ssh_key_path',
|
|
||||||
ssh_key_passphrase: 'backup.ssh_key_passphrase',
|
|
||||||
backup_interval: 'backup.backup_interval',
|
|
||||||
auto_backup: 'backup.auto_backup',
|
|
||||||
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// 配置限制
|
|
||||||
const CONFIG_LIMITS = {
|
|
||||||
fontSize: {min: 12, max: 28, default: 13},
|
|
||||||
tabSize: {min: 2, max: 8, default: 4},
|
|
||||||
lineHeight: {min: 1.0, max: 3.0, default: 1.5},
|
|
||||||
tabType: {values: [TabType.TabTypeSpaces, TabType.TabTypeTab], default: TabType.TabTypeSpaces}
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// 创建获取翻译的函数
|
|
||||||
export const createFontOptions = (t: (key: string) => string) => [
|
|
||||||
{
|
|
||||||
label: t('settings.fontFamilies.harmonyOS'),
|
|
||||||
value: '"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('settings.fontFamilies.microsoftYahei'),
|
|
||||||
value: '"Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('settings.fontFamilies.pingfang'),
|
|
||||||
value: '"PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('settings.fontFamilies.jetbrainsMono'),
|
|
||||||
value: '"JetBrains Mono", "Fira Code", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('settings.fontFamilies.firaCode'),
|
|
||||||
value: '"Fira Code", "JetBrains Mono", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('settings.fontFamilies.sourceCodePro'),
|
|
||||||
value: '"Source Code Pro", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('settings.fontFamilies.cascadiaCode'),
|
|
||||||
value: '"Cascadia Code", "SF Mono", Monaco, Consolas, "Ubuntu Mono", monospace'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 常用字体选项
|
|
||||||
export const FONT_OPTIONS = createFontOptions((key) => key);
|
|
||||||
|
|
||||||
// 获取浏览器的默认语言
|
// 获取浏览器的默认语言
|
||||||
const getBrowserLanguage = (): SupportedLocaleType => {
|
const getBrowserLanguage = (): SupportedLocaleType => {
|
||||||
@@ -164,74 +42,6 @@ const getBrowserLanguage = (): SupportedLocaleType => {
|
|||||||
return supportedLang?.code || 'zh-CN';
|
return supportedLang?.code || 'zh-CN';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 默认配置
|
|
||||||
const DEFAULT_CONFIG: AppConfig = {
|
|
||||||
general: {
|
|
||||||
alwaysOnTop: false,
|
|
||||||
dataPath: '',
|
|
||||||
enableSystemTray: true,
|
|
||||||
startAtLogin: false,
|
|
||||||
enableGlobalHotkey: false,
|
|
||||||
globalHotkey: {
|
|
||||||
ctrl: false,
|
|
||||||
shift: false,
|
|
||||||
alt: true,
|
|
||||||
win: false,
|
|
||||||
key: 'X'
|
|
||||||
},
|
|
||||||
enableWindowSnap: true,
|
|
||||||
enableLoadingAnimation: true,
|
|
||||||
},
|
|
||||||
editing: {
|
|
||||||
fontSize: CONFIG_LIMITS.fontSize.default,
|
|
||||||
fontFamily: FONT_OPTIONS[0].value,
|
|
||||||
fontWeight: 'normal',
|
|
||||||
lineHeight: CONFIG_LIMITS.lineHeight.default,
|
|
||||||
enableTabIndent: true,
|
|
||||||
tabSize: CONFIG_LIMITS.tabSize.default,
|
|
||||||
tabType: CONFIG_LIMITS.tabType.default,
|
|
||||||
autoSaveDelay: 5000
|
|
||||||
},
|
|
||||||
appearance: {
|
|
||||||
language: LanguageType.LangZhCN,
|
|
||||||
systemTheme: SystemThemeType.SystemThemeAuto
|
|
||||||
},
|
|
||||||
updates: {
|
|
||||||
version: "1.0.0",
|
|
||||||
autoUpdate: true,
|
|
||||||
primarySource: UpdateSourceType.UpdateSourceGithub,
|
|
||||||
backupSource: UpdateSourceType.UpdateSourceGitea,
|
|
||||||
backupBeforeUpdate: true,
|
|
||||||
updateTimeout: 30,
|
|
||||||
github: {
|
|
||||||
owner: "landaiqing",
|
|
||||||
repo: "voidraft",
|
|
||||||
},
|
|
||||||
gitea: {
|
|
||||||
baseURL: "https://git.landaiqing.cn",
|
|
||||||
owner: "landaiqing",
|
|
||||||
repo: "voidraft",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
backup: {
|
|
||||||
enabled: false,
|
|
||||||
repo_url: "",
|
|
||||||
auth_method: AuthMethod.UserPass,
|
|
||||||
username: "",
|
|
||||||
password: "",
|
|
||||||
token: "",
|
|
||||||
ssh_key_path: "",
|
|
||||||
ssh_key_passphrase: "",
|
|
||||||
backup_interval: 60,
|
|
||||||
auto_backup: true,
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
version: '1.0.0',
|
|
||||||
lastUpdated: new Date().toString(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const useConfigStore = defineStore('config', () => {
|
export const useConfigStore = defineStore('config', () => {
|
||||||
const {locale, t} = useI18n();
|
const {locale, t} = useI18n();
|
||||||
|
|
||||||
@@ -242,8 +52,8 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
configLoaded: false
|
configLoaded: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始化FONT_OPTIONS国际化版本
|
// Font options (no longer localized)
|
||||||
const localizedFontOptions = computed(() => createFontOptions(t));
|
const fontOptions = computed(() => FONT_OPTIONS);
|
||||||
|
|
||||||
// 计算属性 - 使用工厂函数简化
|
// 计算属性 - 使用工厂函数简化
|
||||||
const createLimitComputed = (key: NumberConfigKey) => computed(() => CONFIG_LIMITS[key]);
|
const createLimitComputed = (key: NumberConfigKey) => computed(() => CONFIG_LIMITS[key]);
|
||||||
@@ -365,10 +175,6 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 通用布尔值切换器
|
|
||||||
const createGeneralToggler = <T extends keyof GeneralConfig>(key: T) =>
|
|
||||||
async () => await updateGeneralConfig(key, !state.config.general[key] as GeneralConfig[T]);
|
|
||||||
|
|
||||||
const createEditingToggler = <T extends keyof EditingConfig>(key: T) =>
|
const createEditingToggler = <T extends keyof EditingConfig>(key: T) =>
|
||||||
async () => await updateEditingConfig(key, !state.config.editing[key] as EditingConfig[T]);
|
async () => await updateEditingConfig(key, !state.config.editing[key] as EditingConfig[T]);
|
||||||
|
|
||||||
@@ -461,7 +267,7 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
config: computed(() => state.config),
|
config: computed(() => state.config),
|
||||||
configLoaded: computed(() => state.configLoaded),
|
configLoaded: computed(() => state.configLoaded),
|
||||||
isLoading: computed(() => state.isLoading),
|
isLoading: computed(() => state.isLoading),
|
||||||
localizedFontOptions,
|
fontOptions,
|
||||||
|
|
||||||
// 限制常量
|
// 限制常量
|
||||||
...limits,
|
...limits,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import {computed, ref} from 'vue';
|
|||||||
import {DocumentService} from '@/../bindings/voidraft/internal/services';
|
import {DocumentService} from '@/../bindings/voidraft/internal/services';
|
||||||
import {OpenDocumentWindow} from '@/../bindings/voidraft/internal/services/windowservice';
|
import {OpenDocumentWindow} from '@/../bindings/voidraft/internal/services/windowservice';
|
||||||
import {Document} from '@/../bindings/voidraft/internal/models/models';
|
import {Document} from '@/../bindings/voidraft/internal/models/models';
|
||||||
import {useSystemStore} from './systemStore';
|
|
||||||
|
|
||||||
|
|
||||||
export const useDocumentStore = defineStore('document', () => {
|
export const useDocumentStore = defineStore('document', () => {
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ export const fontCompartment = new Compartment();
|
|||||||
|
|
||||||
// 默认字体配置
|
// 默认字体配置
|
||||||
export const DEFAULT_FONT_CONFIG: FontConfig = {
|
export const DEFAULT_FONT_CONFIG: FontConfig = {
|
||||||
fontFamily: '"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif',
|
fontFamily: 'HarmonyOS',
|
||||||
fontSize: 14,
|
fontSize: 13,
|
||||||
lineHeight: 1.5,
|
lineHeight: 1.5,
|
||||||
fontWeight: 'normal'
|
fontWeight: '400'
|
||||||
};
|
};
|
||||||
|
|
||||||
// 从后端配置创建字体配置
|
// 从后端配置创建字体配置
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ onMounted(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 字体选择选项
|
// 字体选择选项
|
||||||
const fontFamilyOptions = computed(() => configStore.localizedFontOptions);
|
const fontFamilyOptions = computed(() => configStore.fontOptions);
|
||||||
const currentFontFamily = computed(() => configStore.config.editing.fontFamily);
|
const currentFontFamily = computed(() => configStore.config.editing.fontFamily);
|
||||||
|
|
||||||
// 字体选择
|
// 字体选择
|
||||||
@@ -32,15 +32,15 @@ const handleFontFamilyChange = async (event: Event) => {
|
|||||||
|
|
||||||
// 字体粗细选项
|
// 字体粗细选项
|
||||||
const fontWeightOptions = [
|
const fontWeightOptions = [
|
||||||
{ value: '100', label: t('settings.fontWeights.100') },
|
{ value: '100', label: '100' },
|
||||||
{ value: '200', label: t('settings.fontWeights.200') },
|
{ value: '200', label: '200' },
|
||||||
{ value: '300', label: t('settings.fontWeights.300') },
|
{ value: '300', label: '300' },
|
||||||
{ value: 'normal', label: t('settings.fontWeights.normal') },
|
{ value: '400', label: '400' },
|
||||||
{ value: '500', label: t('settings.fontWeights.500') },
|
{ value: '500', label: '500' },
|
||||||
{ value: '600', label: t('settings.fontWeights.600') },
|
{ value: '600', label: '600' },
|
||||||
{ value: 'bold', label: t('settings.fontWeights.bold') },
|
{ value: 'bold', label: '700' },
|
||||||
{ value: '800', label: t('settings.fontWeights.800') },
|
{ value: '800', label: '800' },
|
||||||
{ value: '900', label: t('settings.fontWeights.900') }
|
{ value: '900', label: '900' }
|
||||||
];
|
];
|
||||||
|
|
||||||
// 字体粗细选择
|
// 字体粗细选择
|
||||||
@@ -115,7 +115,6 @@ const handleAutoSaveDelayChange = async (event: Event) => {
|
|||||||
<SettingSection :title="t('settings.fontSettings')">
|
<SettingSection :title="t('settings.fontSettings')">
|
||||||
<SettingItem
|
<SettingItem
|
||||||
:title="t('settings.fontFamily')"
|
:title="t('settings.fontFamily')"
|
||||||
:description="t('settings.fontFamilyDescription')"
|
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
class="font-family-select"
|
class="font-family-select"
|
||||||
@@ -134,7 +133,6 @@ const handleAutoSaveDelayChange = async (event: Event) => {
|
|||||||
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
:title="t('settings.fontSize')"
|
:title="t('settings.fontSize')"
|
||||||
:description="t('settings.fontSizeDescription')"
|
|
||||||
>
|
>
|
||||||
<div class="number-control">
|
<div class="number-control">
|
||||||
<button @click="decreaseFontSize" class="control-button">-</button>
|
<button @click="decreaseFontSize" class="control-button">-</button>
|
||||||
@@ -145,7 +143,6 @@ const handleAutoSaveDelayChange = async (event: Event) => {
|
|||||||
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
:title="t('settings.fontWeight')"
|
:title="t('settings.fontWeight')"
|
||||||
:description="t('settings.fontWeightDescription')"
|
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
class="font-weight-select"
|
class="font-weight-select"
|
||||||
@@ -164,7 +161,6 @@ const handleAutoSaveDelayChange = async (event: Event) => {
|
|||||||
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
:title="t('settings.lineHeight')"
|
:title="t('settings.lineHeight')"
|
||||||
:description="t('settings.lineHeightDescription')"
|
|
||||||
>
|
>
|
||||||
<div class="number-control">
|
<div class="number-control">
|
||||||
<button @click="decreaseLineHeight" class="control-button">-</button>
|
<button @click="decreaseLineHeight" class="control-button">-</button>
|
||||||
|
|||||||
8
frontend/src/vite-env.d.ts
vendored
8
frontend/src/vite-env.d.ts
vendored
@@ -1 +1,9 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare interface ImportMetaEnv {
|
||||||
|
readonly VITE_NODE_ENV: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
@@ -166,7 +166,7 @@ func NewDefaultAppConfig() *AppConfig {
|
|||||||
Editing: EditingConfig{
|
Editing: EditingConfig{
|
||||||
// 字体设置
|
// 字体设置
|
||||||
FontSize: 13,
|
FontSize: 13,
|
||||||
FontFamily: `"HarmonyOS Sans SC", "HarmonyOS Sans", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif`,
|
FontFamily: `"HarmonyOS SC", "HarmonyOS", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif`,
|
||||||
FontWeight: "normal",
|
FontWeight: "normal",
|
||||||
LineHeight: 1.5,
|
LineHeight: 1.5,
|
||||||
// Tab设置
|
// Tab设置
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
VERSION=1.4.0
|
VERSION=1.4.1
|
||||||
|
|||||||
Reference in New Issue
Block a user