chore: UI样式调整

- 过时语法修复
- 样式细节调整
- 添加前端语法格式化
This commit is contained in:
ASLant committed 2026-01-31 13:40:38 +08:00
1 parent 127c6c1442
commit bd10195fdb
12 files changed
+196 -104

No files matched your search

-9
View File
@@ -1,9 +0,0 @@
node_modules/
src-tauri/
upx/
icons/
img/
*.min.js
*.min.css
dist/
target/
-27
View File
@@ -1,27 +0,0 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["html"],
"rules": {
"indent": ["error", 4],
"quotes": ["error", "single", { "avoidEscape": true }],
"semi": ["error", "never"],
"no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
"no-constant-condition": ["warn", { "checkLoops": false }],
"no-console": "off"
},
"globals": {
"invoke": "readonly",
"open": "readonly",
"save": "readonly",
"getCurrentWindow": "readonly",
"listen": "readonly"
}
}
+68 -18
View File
@@ -1,6 +1,6 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This file provides guidance to Claude Code (claude.ai/code) when working in this codebase.
## 项目概述
@@ -16,6 +16,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
- **拖放支持**:支持文件/文件夹拖放到窗口,自动判断操作区域
- **多线程批处理**:根据 CPU 核心数动态调整并发数
- **配置持久化**:配置保存在程序目录的 `upx_gui_config.json`
- **便携版支持**:使用 `include_bytes!` 嵌入 UPX,运行时释放到临时目录
## 常用命令
@@ -28,41 +29,60 @@ cargo tauri build
# 编译产物位置
# src-tauri/target/release/bundle/
# 生成 MSI 和 NSIS 两种安装包
# 生成 MSI、NSIS 和 Portable 三种格式
# 前端代码检查
npm run lint # 检查代码问题
npm run lint:fix # 自动修复
npm run format # 格式化代码
npm run check # 完整检查
# Tailwind CSS 构建
npm run build:css # 编译并压缩 Tailwind CSS
npm run watch:css # 监听模式编译 Tailwind CSS
# 完整构建(包含便携版复制)
npm run build # 编译 Tauri 并复制便携版到 bundle 目录
```
## 代码结构
### 前端 (ui/)
- `index.html` - 主界面,包含双操作按钮布局
- `js/main.js` - 前端逻辑,约 740 行,包含:
- 拖放检测与区域判断
- `index.html` - 主界面,包含双操作按钮布局、设置弹窗、更新弹窗
- `js/main.js` - 前端逻辑(约 900 行),包含:
- 拖放检测与区域判断(通过按钮位置缓存 `cachedButtonRects`)
- 动态批处理(基于 CPU 核心数)
- 配置的保存/加载
- 日志系统(带数量限制和自动清理)
- `css/style.css` - 主样式
- `css/tailwind-custom.css` - Tailwind 自定义
- 日志系统(带数量限制和自动清理,最大 1000 条)
- 更新检查与下载
- `css/style.css` - 主样式,包含 shadcn/ui CSS 变量、自定义按钮、弹窗动画
- `css/main.css` - Tailwind 入口文件(需编译)
### 后端 (src-tauri/src/)
- `main.rs` - 唯一的 Rust 源文件,包含所有 Tauri commands:
- `process_upx` - 执行压缩/解压
- `scan_folder` - 递归扫描 exe/dll 文件
- `get_upx_version` - 获取 UPX 版本
- `refresh_icon_cache` - 刷新 Windows 图标缓存
- `check_update` - 检查 GitHub 最新版本
- `save_config` / `load_config` - 配置持久化
- `main.rs` - 唯一的 Rust 源文件(约 500 行),采用模块化结构:
- **数据结构定义**:`UpxOptions`、`ScanFolderOptions`、`AppConfig`、`UpdateInfo`
- **路径解析**:`get_upx_path()` 多级查找(安装版 → 开发版 → 便携版嵌入资源)
- **命令构建辅助**:`build_compress_args()`、`build_decompress_args()`
- **输出处理**:`filter_output_lines()`、`parse_upx_error()` 智能过滤和错误解析
- **Tauri Commands**:
- `process_upx` - 执行压缩/解压(支持 tokio 阻塞任务)
- `scan_folder` - 递归扫描 exe/dll 文件
- `get_upx_version` - 获取 UPX 版本
- `refresh_icon_cache` - 刷新 Windows 图标缓存
- `check_update` / `download_and_install` - 检查和下载 GitHub 更新
- `save_config` / `load_config` - 配置持久化
### 构建配置
- `src-tauri/tauri.conf.json` - Tauri 配置,定义窗口属性、权限、打包设置
- `src-tauri/Cargo.toml` - Rust 依赖,release profile 优化(strip、lto、opt-level=z)
- `.github/workflows/release.yml` - GitHub Actions 自动发布,生成 MSI、NSIS、Portable 三种安装包
## 重要细节
### UPX 路径解析
开发环境:`../upx/upx.exe`
打包后:`_up_/upx/upx.exe`(相对于程序目录)
### UPX 路径解析(三级查找)
1. **安装版**:`程序目录/_up_/upx/upx.exe`
2. **开发版**:`../upx/upx.exe`(相对于项目根目录)
3. **便携版**:从嵌入的 `EMBEDDED_UPX` 释放到 `%TEMP%/upx-gui-portable/upx.exe`
### 编码处理
UPX 在 Windows 上输出 GBK 编码,使用 `encoding_rs::GBK` 转换为 UTF-8
@@ -73,10 +93,24 @@ batchSize = Math.max(2, Math.min(cpuCores * 2, 16))
```
最小 2,最大 16,默认为 CPU 核心数的 2 倍
### 日志系统
- 最大日志条数:1000 条
- 超出时一次删除 200 条(批量删除优化性能)
- 支持不同日志类型:`info`、`error`、`warning`、`success`、`hint`
- 使用 `requestAnimationFrame` 优化滚动性能
### Tauri 2.0 特性
- 使用 `window.__TAURI__` 全局对象(需启用 `withGlobalTauri: true`)
- 命令调用:`invoke('command_name', { options })`
- 拖放事件:`listen('tauri://drag-drop', handler)`
- 权限通过 `capabilities` 定义(`main-capability`)
### 错误处理模式
后端使用模式匹配解析 UPX 输出,提供中文错误提示和解决方案:
- `AlreadyPackedException` - 文件已加壳
- `NotPackedException` - 文件未加壳
- `CantPackException` - 无法压缩
- `OverlayException` - 附加数据冲突
## 代码规范
@@ -93,3 +127,19 @@ batchSize = Math.max(2, Math.min(cpuCores * 2, 16))
### 后端 (Rust)
- 使用 `cargo fmt` 格式化
- 使用 `cargo clippy` 检查代码质量
- Release profile 已优化:`strip = true`、`lto = true`、`opt-level = "z"`
### 界面风格
- 基于 shadcn/ui New York 风格,使用 neutral 基色
- 自定义字体:`YASLant`(回退到系统字体)
- 禁用右键菜单、F5 刷新、Ctrl+W 等浏览器默认行为
## 版本发布
1. 修改 `src-tauri/Cargo.toml` 和 `package.json` 中的版本号
2. 推送 tag:`git tag v1.x.x && git push origin v1.x.x`
3. GitHub Actions 自动构建并发布 Release
4. 生成三种安装包:
- `UPX-Tools-{version}-x64.msi` - MSI 安装包
- `UPX-Tools-{version}-x64-setup.exe` - NSIS 安装包
- `UPX-Tools-{version}-x64-portable.exe` - 便携版(单文件,内嵌 UPX)
+2 -1
View File
@@ -148,10 +148,11 @@ UPX-Tools/
│ └── js/ # JavaScript 代码
├── src-tauri/ # Rust 后端
│ ├── src/ # Rust 源码
│ ├── Cargo.toml # Rust 依赖配置
│ └── tauri.conf.json # Tauri 配置
├── upx/ # UPX 工具
│ └── upx.exe # UPX 可执行文件
├── .eslintrc.json # ESLint 配置
├── eslint.config.js # ESLint v9 配置
├── .prettierrc.json # Prettier 配置
└── package.json # npm 依赖配置
```
+46
View File
@@ -0,0 +1,46 @@
import js from '@eslint/js'
import html from 'eslint-plugin-html'
import globals from 'globals'
export default [
js.configs.recommended,
{
files: ['ui/**/*.{js,html}'],
plugins: {
html,
},
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
invoke: 'readonly',
open: 'readonly',
save: 'readonly',
getCurrentWindow: 'readonly',
listen: 'readonly',
},
},
rules: {
indent: ['error', 4],
quotes: ['error', 'single', { avoidEscape: true }],
semi: ['error', 'never'],
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'no-constant-condition': ['warn', { checkLoops: false }],
'no-console': 'off',
},
},
{
ignores: [
'node_modules/**',
'src-tauri/**',
'upx/**',
'icons/**',
'img/**',
'*.min.js',
'*.min.css',
'dist/**',
'target/**',
],
},
]
+3 -1
View File
@@ -15,9 +15,11 @@
"post-build": "powershell -Command \"New-Item -Path 'src-tauri/target/release/bundle/Portable' -ItemType Directory -Force; Copy-Item 'src-tauri/target/release/UPX-Tools.exe' 'src-tauri/target/release/bundle/Portable/'\""
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"autoprefixer": "^10.4.23",
"eslint": "^8.57.1",
"eslint": "^9.39.2",
"eslint-plugin-html": "^8.1.1",
"globals": "^17.2.0",
"postcss": "^8.5.6",
"postcss-cli": "^11.0.1",
"prettier": "^3.3.3",
+14 -14
View File
@@ -171,9 +171,9 @@ checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "bytemuck"
version = "1.24.0"
version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
[[package]]
name = "byteorder"
@@ -259,9 +259,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.54"
version = "1.2.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -728,9 +728,9 @@ dependencies = [
[[package]]
name = "find-msvc-tools"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "flate2"
@@ -2861,7 +2861,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -3842,7 +3842,7 @@ dependencies = [
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -5122,18 +5122,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.35"
version = "0.8.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572"
checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.35"
version = "0.8.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22"
checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0"
dependencies = [
"proc-macro2",
"quote",
@@ -5202,6 +5202,6 @@ dependencies = [
[[package]]
name = "zmij"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439"
checksum = "1966f8ac2c1f76987d69a74d0e0f929241c10e78136434e3be70ff7f58f64214"
-1
View File
@@ -501,7 +501,6 @@ fn refresh_icon_cache_internal() {
}
#[tauri::command]
#[allow(dead_code)]
async fn refresh_icon_cache() -> Result<(), String> {
tokio::task::spawn_blocking(move || {
#[cfg(target_os = "windows")]
+4 -4
View File
@@ -14,10 +14,10 @@
{
"label": "main",
"title": "UPX-Tools",
"width": 1000,
"height": 800,
"minWidth": 900,
"minHeight": 700,
"width": 640,
"height": 600,
"minWidth": 640,
"minHeight": 600,
"resizable": true,
"fullscreen": false,
"center": true,
+22 -23
View File
@@ -99,52 +99,45 @@ body {
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
width: 4px;
height: 4px;
}
::-webkit-scrollbar-track {
background: hsl(var(--muted));
background: transparent;
}
::-webkit-scrollbar-thumb {
background: hsl(var(--muted-foreground) / 0.3);
border-radius: var(--radius);
background: hsl(var(--border));
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: hsl(var(--muted-foreground) / 0.5);
background: hsl(var(--muted-foreground) / 0.3);
}
/* 日志输出区域 */
#log-output {
font-family: 'YASLant', 'Consolas', 'Monaco', 'Courier New', monospace;
overflow: overlay;
overflow: auto;
}
/* 日志输出区域滚动条 */
#log-output::-webkit-scrollbar {
width: 6px;
width: 4px;
}
#log-output::-webkit-scrollbar-track {
background: transparent;
border-radius: var(--radius);
}
#log-output::-webkit-scrollbar-thumb {
background: hsl(0 0% 40% / 0.4);
border-radius: var(--radius);
background: hsl(var(--muted-foreground) / 0.2);
border-radius: 2px;
}
#log-output::-webkit-scrollbar-thumb:hover {
background: hsl(0 0% 50% / 0.6);
}
/* 日志高亮样式 */
#log-output .log-highlight {
color: #ffffff;
font-weight: 500;
background: hsl(var(--muted-foreground) / 0.4);
}
/* 日志行样式 */
@@ -158,24 +151,24 @@ body {
}
.log-info {
color: #a1a1aa;
color: hsl(var(--muted-foreground));
}
.log-error {
color: #f87171;
color: hsl(var(--destructive));
}
.log-warning {
color: #fbbf24;
color: #f59e0b;
}
.log-success {
color: #4ade80;
color: hsl(var(--primary));
font-weight: 500;
}
.log-hint {
color: #71717a;
color: hsl(var(--muted-foreground));
padding-left: 16px;
}
@@ -246,6 +239,12 @@ body {
color: hsl(var(--accent-foreground));
}
/* 清空按钮 hover 特效 */
#clear-log-btn:hover {
color: hsl(var(--destructive));
background-color: hsl(var(--destructive) / 0.1);
}
/* 卡片样式 */
.card {
background-color: hsl(var(--card));
+29 -6
View File
@@ -135,9 +135,9 @@
</div>
<!-- 主内容区 -->
<div class="h-[calc(100vh-2.5rem)] flex flex-col p-5 gap-4">
<div class="h-[calc(100vh-2.5rem)] flex flex-col p-3 gap-3">
<!-- 操作选择 -->
<div class="grid grid-cols-2 gap-4">
<div class="grid grid-cols-2 gap-3">
<button
id="compress-btn"
class="drop-zone group relative py-6 px-5 bg-secondary/50 border border-border rounded-lg hover:border-primary hover:bg-accent transition-all cursor-pointer outline-none focus:outline-none"
@@ -189,13 +189,36 @@
</div>
<!-- 日志输出 -->
<div class="card p-5 flex-1 flex flex-col min-h-0">
<h2 class="text-sm font-semibold text-foreground mb-3">执行日志</h2>
<div class="flex-1 flex flex-col min-h-0">
<div class="card p-3 mb-3">
<div class="flex items-center justify-between">
<h2 class="text-sm font-medium text-foreground">执行日志:</h2>
<button
id="clear-log-btn"
class="btn btn-ghost w-8 h-8 p-0 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
title="清空日志"
>
<svg
class="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</div>
</div>
<div
id="log-output"
class="flex-1 bg-primary text-primary-foreground font-mono text-sm p-4 overflow-y-auto overflow-x-hidden rounded-md"
class="flex-1 bg-muted text-muted-foreground font-mono text-sm p-3 overflow-y-auto overflow-x-hidden rounded-md"
>
<div class="text-primary-foreground/50">等待操作...</div>
<div class="text-muted-foreground/50">等待操作...</div>
</div>
</div>
</div>
+8
View File
@@ -25,6 +25,7 @@ let compressBtn,
includeSubfoldersCheckbox,
forceCompressCheckbox,
logOutput,
clearLogBtn,
settingsModal,
settingsBtn,
closeSettingsBtn,
@@ -48,6 +49,7 @@ function initDOMElements() {
includeSubfoldersCheckbox = $('include-subfolders')
forceCompressCheckbox = $('force-compress')
logOutput = $('log-output')
clearLogBtn = $('clear-log-btn')
settingsModal = $('settings-modal')
settingsBtn = $('settings-btn')
closeSettingsBtn = $('close-settings')
@@ -152,6 +154,7 @@ function initOperationButtons() {
settingsBtn.addEventListener('click', showSettingsModal)
closeSettingsBtn.addEventListener('click', handleCloseSettings)
settingsModal.addEventListener('click', handleModalBackdropClick)
clearLogBtn.addEventListener('click', handleClearLog)
compressBtn.addEventListener('click', () => handleOperationClick('compress'))
decompressBtn.addEventListener('click', () => handleOperationClick('decompress'))
@@ -576,6 +579,11 @@ async function handleRefreshIcon() {
}
}
// 清空日志
function handleClearLog() {
logOutput.innerHTML = '<div class="text-muted-foreground/50">日志已清空</div>'
}
// 更新弹窗相关元素(延迟初始化)
let updateModal,
updateVersion,