Skip to content

Commit 85907dd

Browse files
JusterZhuclaude
andauthored
feat: apply UrsaWindow frameless style with emoji nav and text toggles (#89)
- Replace Window with Ursa.Controls.UrsaWindow for frameless title bar - Add UrsaSemiTheme in App.axaml - Add draggable regions via WindowDecorationProperties.ElementRole=TitleBar - Add emoji icons to sidebar navigation items (🩹🧩☁️🔄⚙️🛠) - Replace bottom toggle buttons: emoji → i18n-aware text (明/暗, 中/英) - Add emoji prefixes to each module's page title - Add NavItem.Icon property, ThemeLabel/LocaleLabel computed bindings - Sync all 4 localization sources (zh-CN.json, en-US.json, C# fallbacks) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 87abb9c commit 85907dd

7 files changed

Lines changed: 124 additions & 103 deletions

File tree

src/App.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Application xmlns="https://github.com/avaloniaui"
1+
<Application xmlns="https://github.com/avaloniaui"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
33
x:Class="GeneralUpdate.Tools.App"
44
xmlns:local="using:GeneralUpdate.Tools"
@@ -10,5 +10,6 @@
1010
<Application.Styles>
1111
<FluentTheme />
1212
<semi:SemiTheme Locale="zh-CN" />
13+
<semi:UrsaSemiTheme />
1314
</Application.Styles>
1415
</Application>

src/Resources/Locales/en-US.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"Nav.Simulate": "Simulate",
77
"Nav.Config": "Config",
88
"Nav.Settings": "Settings",
9-
"Patch.Title": "Patch Package",
9+
"Patch.Title": "🩹 Patch Package",
1010
"Patch.CorePaths": "Core Paths",
1111
"Patch.OldDir": "Old Directory",
1212
"Patch.NewDir": "New Directory",
@@ -48,7 +48,7 @@
4848
"Patch.ScanBtnCancel": "Cancel",
4949
"Patch.ScanSkipped": "Skipped {0} suspicious file(s)",
5050
"Patch.ScanCancelled": "Packaging cancelled by user",
51-
"Ext.Title": "Extension Package",
51+
"Ext.Title": "🧩 Extension Package",
5252
"Ext.BasicInfo": "Basic Info",
5353
"Ext.Name": "Name",
5454
"Ext.Version": "Version",
@@ -71,7 +71,7 @@
7171
"Ext.Building": "Generating extension package...",
7272
"Ext.Success": "Success: {0}",
7373
"Ext.Failed": "Failed: {0}",
74-
"OSS.Title": "OSS Config Generator",
74+
"OSS.Title": "☁️ OSS Config Generator",
7575
"OSS.NewEntry": "New Entry",
7676
"OSS.PacketName": "Package Name",
7777
"OSS.Version": "Version",
@@ -90,7 +90,10 @@
9090
"Theme.Light": "Light",
9191
"Theme.Dark": "Dark",
9292
"Theme.Toggle": "Toggle Theme",
93-
"Sim.Title": "Simulate Update",
93+
"Locale.Zh": "",
94+
"Locale.En": "EN",
95+
"Locale.Toggle": "Switch Language",
96+
"Sim.Title": "🔄 Simulate Update",
9497
"Sim.TestTarget": "Test Target",
9598
"Sim.OldAppDir": "Old App Directory",
9699
"Sim.PatchFile": "Patch Package",
@@ -118,7 +121,7 @@
118121
"Sim.Completed": "Simulation completed ({0:F1}s)",
119122
"Sim.Failed": "Simulation failed: {0}",
120123
"Sim.Report": "Report: {0}",
121-
"Config.Title": "Config Generator",
124+
"Config.Title": "⚙️ Config Generator",
122125
"Config.ClientPath": "Client Project (.csproj)",
123126
"Config.UpgradePath": "Upgrade Project (.csproj)",
124127
"Config.Browse": "Browse",

src/Resources/Locales/zh-CN.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"Nav.Simulate": "模拟更新",
77
"Nav.Config": "配置生成",
88
"Nav.Settings": "设置",
9-
"Patch.Title": "补丁包生成",
9+
"Patch.Title": "🩹 补丁包生成",
1010
"Patch.CorePaths": "核心路径",
1111
"Patch.OldDir": "旧版本目录",
1212
"Patch.NewDir": "新版本目录",
@@ -48,7 +48,7 @@
4848
"Patch.ScanBtnCancel": "取消",
4949
"Patch.ScanSkipped": "已跳过 {0} 个可疑文件",
5050
"Patch.ScanCancelled": "用户取消打包",
51-
"Ext.Title": "扩展包生成",
51+
"Ext.Title": "🧩 扩展包生成",
5252
"Ext.BasicInfo": "基本信息",
5353
"Ext.Name": "名称",
5454
"Ext.Version": "版本",
@@ -71,7 +71,7 @@
7171
"Ext.Building": "正在生成扩展包...",
7272
"Ext.Success": "成功: {0}",
7373
"Ext.Failed": "失败: {0}",
74-
"OSS.Title": "OSS 配置生成",
74+
"OSS.Title": "☁️ OSS 配置生成",
7575
"OSS.NewEntry": "新建条目",
7676
"OSS.PacketName": "包名",
7777
"OSS.Version": "版本",
@@ -87,10 +87,13 @@
8787
"OSS.Exported": "导出: {0} 条",
8888
"OSS.HashResult": "SHA256: {0}",
8989
"OSS.InvalidVersion": "版本号 '{0}' 不符合 semver 规范。示例: 1.0.0",
90-
"Theme.Light": "浅色",
91-
"Theme.Dark": "深色",
90+
"Theme.Light": "",
91+
"Theme.Dark": "",
9292
"Theme.Toggle": "切换主题",
93-
"Sim.Title": "模拟更新",
93+
"Locale.Zh": "",
94+
"Locale.En": "",
95+
"Locale.Toggle": "切换语言",
96+
"Sim.Title": "🔄 模拟更新",
9497
"Sim.TestTarget": "测试目标",
9598
"Sim.OldAppDir": "旧版本应用目录",
9699
"Sim.PatchFile": "补丁包文件",
@@ -118,7 +121,7 @@
118121
"Sim.Completed": "模拟完成 ({0:F1}s)",
119122
"Sim.Failed": "模拟失败: {0}",
120123
"Sim.Report": "报告: {0}",
121-
"Config.Title": "配置生成器",
124+
"Config.Title": "⚙️ 配置生成器",
122125
"Config.ClientPath": "Client 项目 (.csproj)",
123126
"Config.UpgradePath": "Upgrade 项目 (.csproj)",
124127
"Config.Browse": "浏览",

src/Services/LocalizationService.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
162162
["App.Title"] = "GeneralUpdate Tools",
163163
["Nav.Patch"] = "补丁包", ["Nav.Extension"] = "扩展包", ["Nav.OSS"] = "OSS配置",
164164
["Nav.Simulate"] = "模拟更新", ["Nav.Config"] = "配置生成", ["Nav.Settings"] = "设置",
165-
["Patch.Title"] = "补丁包生成", ["Patch.CorePaths"] = "核心路径",
165+
["Patch.Title"] = "🩹 补丁包生成", ["Patch.CorePaths"] = "核心路径",
166166
["Patch.OldDir"] = "旧版本目录", ["Patch.NewDir"] = "新版本目录",
167167
["Patch.Select"] = "选择", ["Patch.OldPlaceholder"] = "选择旧版本应用目录...",
168168
["Patch.NewPlaceholder"] = "选择新版本发布目录...", ["Patch.PackageInfo"] = "包信息",
@@ -187,7 +187,7 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
187187
["Patch.ScanBtnSkip"] = "跳过可疑文件,继续打包", ["Patch.ScanBtnInclude"] = "仍然打包全部文件",
188188
["Patch.ScanBtnCancel"] = "取消", ["Patch.ScanSkipped"] = "已跳过 {0} 个可疑文件",
189189
["Patch.ScanCancelled"] = "用户取消打包",
190-
["Ext.Title"] = "扩展包生成", ["Ext.BasicInfo"] = "基本信息",
190+
["Ext.Title"] = "🧩 扩展包生成", ["Ext.BasicInfo"] = "基本信息",
191191
["Ext.Name"] = "名称", ["Ext.Version"] = "版本", ["Ext.Description"] = "描述",
192192
["Ext.DescPlaceholder"] = "扩展功能描述...", ["Ext.Publisher"] = "发布者",
193193
["Ext.License"] = "许可证", ["Ext.LicensePlaceholder"] = "MIT",
@@ -198,15 +198,16 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
198198
["Ext.InvalidVersion"] = "版本号 '{0}' 不符合 semver 规范。示例: 1.0.0",
199199
["Ext.ValidateDir"] = "请选择有效的扩展目录",
200200
["Ext.Building"] = "正在生成扩展包...", ["Ext.Success"] = "成功: {0}", ["Ext.Failed"] = "失败: {0}",
201-
["OSS.Title"] = "OSS 配置生成", ["OSS.NewEntry"] = "新建条目",
201+
["OSS.Title"] = "☁️ OSS 配置生成", ["OSS.NewEntry"] = "新建条目",
202202
["OSS.PacketName"] = "包名", ["OSS.Version"] = "版本", ["OSS.Url"] = "URL",
203203
["OSS.SHA256"] = "SHA256", ["OSS.ComputeHash"] = "计算", ["OSS.AddToList"] = "添加到列表",
204204
["OSS.ConfigList"] = "配置列表", ["OSS.Clear"] = "清空", ["OSS.Export"] = "导出 JSON",
205205
["OSS.Added"] = "已添加", ["OSS.Cleared"] = "已清空", ["OSS.Exported"] = "导出: {0} 条",
206206
["OSS.HashResult"] = "SHA256: {0}",
207207
["OSS.InvalidVersion"] = "版本号 '{0}' 不符合 semver 规范。示例: 1.0.0",
208-
["Theme.Light"] = "浅色", ["Theme.Dark"] = "深色", ["Theme.Toggle"] = "切换主题",
209-
["Sim.Title"] = "模拟更新", ["Sim.TestTarget"] = "测试目标",
208+
["Theme.Light"] = "明", ["Theme.Dark"] = "暗", ["Theme.Toggle"] = "切换主题",
209+
["Locale.Zh"] = "中", ["Locale.En"] = "英", ["Locale.Toggle"] = "切换语言",
210+
["Sim.Title"] = "🔄 模拟更新", ["Sim.TestTarget"] = "测试目标",
210211
["Sim.OldAppDir"] = "旧版本应用目录", ["Sim.PatchFile"] = "补丁包文件",
211212
["Sim.Select"] = "选择", ["Sim.UpdateConfig"] = "更新配置",
212213
["Sim.CurrentVer"] = "当前版本", ["Sim.TargetVer"] = "目标版本",
@@ -222,7 +223,7 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
222223
["Sim.ManualMode"] = "服务器/客户端已生成,可手动运行:\ndotnet script client.csx",
223224
["Sim.Starting"] = "正在启动模拟...", ["Sim.Completed"] = "模拟完成 ({0:F1}s)",
224225
["Sim.Failed"] = "模拟失败: {0}", ["Sim.Report"] = "报告: {0}",
225-
["Config.Title"] = "配置生成器",
226+
["Config.Title"] = "⚙️ 配置生成器",
226227
["Config.ClientPath"] = "Client 项目 (.csproj)", ["Config.UpgradePath"] = "Upgrade 项目 (.csproj)",
227228
["Config.Browse"] = "浏览", ["Config.BrowseClient"] = "选择 Client 项目文件",
228229
["Config.BrowseUpgrade"] = "选择 Upgrade 项目文件",
@@ -267,7 +268,7 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
267268
["App.Title"] = "GeneralUpdate Tools",
268269
["Nav.Patch"] = "Patch", ["Nav.Extension"] = "Extension", ["Nav.OSS"] = "OSS Config",
269270
["Nav.Simulate"] = "Simulate", ["Nav.Config"] = "Config", ["Nav.Settings"] = "Settings",
270-
["Patch.Title"] = "Patch Package", ["Patch.CorePaths"] = "Core Paths",
271+
["Patch.Title"] = "🩹 Patch Package", ["Patch.CorePaths"] = "Core Paths",
271272
["Patch.OldDir"] = "Old Directory", ["Patch.NewDir"] = "New Directory",
272273
["Patch.Select"] = "Select", ["Patch.OldPlaceholder"] = "Select old version directory...",
273274
["Patch.NewPlaceholder"] = "Select new version directory...",
@@ -296,7 +297,7 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
296297
["Patch.ScanBtnInclude"] = "Include all files anyway",
297298
["Patch.ScanBtnCancel"] = "Cancel", ["Patch.ScanSkipped"] = "Skipped {0} suspicious file(s)",
298299
["Patch.ScanCancelled"] = "Packaging cancelled by user",
299-
["Ext.Title"] = "Extension Package", ["Ext.BasicInfo"] = "Basic Info",
300+
["Ext.Title"] = "🧩 Extension Package", ["Ext.BasicInfo"] = "Basic Info",
300301
["Ext.Name"] = "Name", ["Ext.Version"] = "Version", ["Ext.Description"] = "Description",
301302
["Ext.DescPlaceholder"] = "Extension description...", ["Ext.Publisher"] = "Publisher",
302303
["Ext.License"] = "License", ["Ext.LicensePlaceholder"] = "MIT",
@@ -309,7 +310,7 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
309310
["Ext.ValidateDir"] = "Please select a valid extension directory",
310311
["Ext.Building"] = "Generating extension package...",
311312
["Ext.Success"] = "Success: {0}", ["Ext.Failed"] = "Failed: {0}",
312-
["OSS.Title"] = "OSS Config Generator", ["OSS.NewEntry"] = "New Entry",
313+
["OSS.Title"] = "☁️ OSS Config Generator", ["OSS.NewEntry"] = "New Entry",
313314
["OSS.PacketName"] = "Package Name", ["OSS.Version"] = "Version", ["OSS.Url"] = "URL",
314315
["OSS.SHA256"] = "SHA256", ["OSS.ComputeHash"] = "Compute",
315316
["OSS.AddToList"] = "Add to List", ["OSS.ConfigList"] = "Config List",
@@ -318,7 +319,8 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
318319
["OSS.Exported"] = "Exported: {0} entries", ["OSS.HashResult"] = "SHA256: {0}",
319320
["OSS.InvalidVersion"] = "Version '{0}' does not follow semver. Example: 1.0.0",
320321
["Theme.Light"] = "Light", ["Theme.Dark"] = "Dark", ["Theme.Toggle"] = "Toggle Theme",
321-
["Sim.Title"] = "Simulate Update", ["Sim.TestTarget"] = "Test Target",
322+
["Locale.Zh"] = "中", ["Locale.En"] = "EN", ["Locale.Toggle"] = "Switch Language",
323+
["Sim.Title"] = "🔄 Simulate Update", ["Sim.TestTarget"] = "Test Target",
322324
["Sim.OldAppDir"] = "Old App Directory", ["Sim.PatchFile"] = "Patch Package",
323325
["Sim.Select"] = "Select", ["Sim.UpdateConfig"] = "Update Config",
324326
["Sim.CurrentVer"] = "Current Version", ["Sim.TargetVer"] = "Target Version",
@@ -337,7 +339,7 @@ private void OnPropertyChanged([CallerMemberName] string? name = null) =>
337339
["Sim.Starting"] = "Starting simulation...",
338340
["Sim.Completed"] = "Simulation completed ({0:F1}s)",
339341
["Sim.Failed"] = "Simulation failed: {0}", ["Sim.Report"] = "Report: {0}",
340-
["Config.Title"] = "Config Generator",
342+
["Config.Title"] = "⚙️ Config Generator",
341343
["Config.ClientPath"] = "Client Project (.csproj)",
342344
["Config.UpgradePath"] = "Upgrade Project (.csproj)",
343345
["Config.Browse"] = "Browse", ["Config.BrowseClient"] = "Select Client project file",

src/ViewModels/MainWindowViewModel.cs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public partial class MainWindowViewModel : ViewModelBase
1515

1616
[ObservableProperty] private ViewModelBase _currentPage;
1717
[ObservableProperty] private bool _isDarkTheme;
18-
[ObservableProperty] private string _localeText = "EN";
18+
[ObservableProperty] private string _themeLabel = string.Empty;
19+
[ObservableProperty] private string _localeLabel = string.Empty;
1920

2021
public ObservableCollection<NavItem> NavItems { get; } = new();
2122

@@ -28,8 +29,7 @@ public MainWindowViewModel(AppConfig config)
2829
ApplyTheme(IsDarkTheme);
2930

3031
// Apply saved locale
31-
LocaleText = _loc.Locale == "zh-CN" ? "EN" : "中";
32-
32+
SyncLabels();
3333
SyncNavItems();
3434

3535
_loc.PropertyChanged += (_, e) =>
@@ -38,22 +38,42 @@ public MainWindowViewModel(AppConfig config)
3838
return;
3939

4040
SyncNavItems();
41-
LocaleText = _loc.Locale == "zh-CN" ? "EN" : "中";
41+
SyncLabels();
4242
};
4343

4444
// Default to Patch page
4545
CurrentPage = new PatchViewModel(config);
4646
}
4747

48+
partial void OnIsDarkThemeChanged(bool value) => SyncThemeLabel();
49+
50+
private void SyncLabels()
51+
{
52+
SyncThemeLabel();
53+
SyncLocaleLabel();
54+
}
55+
56+
private void SyncThemeLabel()
57+
{
58+
// Show what you'll switch TO: light → "暗", dark → "明"
59+
ThemeLabel = IsDarkTheme ? _loc["Theme.Light"] : _loc["Theme.Dark"];
60+
}
61+
62+
private void SyncLocaleLabel()
63+
{
64+
// Show what you'll switch TO: zh-CN → "英", en-US → "中"
65+
LocaleLabel = _loc.Locale == "zh-CN" ? _loc["Locale.En"] : _loc["Locale.Zh"];
66+
}
67+
4868
private void SyncNavItems()
4969
{
5070
NavItems.Clear();
51-
NavItems.Add(new("Patch", _loc["Nav.Patch"], typeof(PatchViewModel), true));
52-
NavItems.Add(new("Extension", _loc["Nav.Extension"], typeof(ExtensionViewModel), false));
53-
NavItems.Add(new("OSS", _loc["Nav.OSS"], typeof(OSSViewModel), false));
54-
NavItems.Add(new("Simulate", _loc["Nav.Simulate"], typeof(SimulateViewModel), false));
55-
NavItems.Add(new("Config", _loc["Nav.Config"], typeof(ConfigViewModel), false));
56-
NavItems.Add(new("Settings", _loc["Nav.Settings"], typeof(SettingsViewModel), false));
71+
NavItems.Add(new("Patch", _loc["Nav.Patch"], "\U0001FA79", typeof(PatchViewModel), true));
72+
NavItems.Add(new("Extension", _loc["Nav.Extension"], "\U0001F9E9", typeof(ExtensionViewModel), false));
73+
NavItems.Add(new("OSS", _loc["Nav.OSS"], "☁️", typeof(OSSViewModel), false));
74+
NavItems.Add(new("Simulate", _loc["Nav.Simulate"], "\U0001F504", typeof(SimulateViewModel), false));
75+
NavItems.Add(new("Config", _loc["Nav.Config"], "⚙️", typeof(ConfigViewModel), false));
76+
NavItems.Add(new("Settings", _loc["Nav.Settings"], "\U0001F6E0", typeof(SettingsViewModel), false));
5777
}
5878

5979
[RelayCommand]
@@ -114,13 +134,15 @@ public partial class NavItem : ObservableObject
114134
{
115135
public string Key { get; }
116136
public string Title { get; }
137+
public string Icon { get; }
117138
public System.Type PageType { get; }
118139
[ObservableProperty] private bool _isSelected;
119140

120-
public NavItem(string key, string title, System.Type pageType, bool selected)
141+
public NavItem(string key, string title, string icon, System.Type pageType, bool selected)
121142
{
122143
Key = key;
123144
Title = title;
145+
Icon = icon;
124146
PageType = pageType;
125147
_isSelected = selected;
126148
}

0 commit comments

Comments
 (0)