diff --git a/ui-html/webview2/candwnd/horizontal_candidate_window_graphite.html b/ui-html/webview2/candwnd/horizontal_candidate_window_graphite.html
new file mode 100644
index 00000000..01479b3a
--- /dev/null
+++ b/ui-html/webview2/candwnd/horizontal_candidate_window_graphite.html
@@ -0,0 +1,599 @@
+
+
+
+
+
+
+ (IME)VCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/candwnd/horizontal_candidate_window_graphite_light.html b/ui-html/webview2/candwnd/horizontal_candidate_window_graphite_light.html
new file mode 100644
index 00000000..70e5bf42
--- /dev/null
+++ b/ui-html/webview2/candwnd/horizontal_candidate_window_graphite_light.html
@@ -0,0 +1,599 @@
+
+
+
+
+
+
+ (IME)VCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/candwnd/horizontal_candidate_window_willow_green.html b/ui-html/webview2/candwnd/horizontal_candidate_window_willow_green.html
new file mode 100644
index 00000000..67efecc3
--- /dev/null
+++ b/ui-html/webview2/candwnd/horizontal_candidate_window_willow_green.html
@@ -0,0 +1,635 @@
+
+
+
+
+
+
+ (IME)WechatHCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/candwnd/horizontal_candidate_window_willow_green_light.html b/ui-html/webview2/candwnd/horizontal_candidate_window_willow_green_light.html
new file mode 100644
index 00000000..5da464dd
--- /dev/null
+++ b/ui-html/webview2/candwnd/horizontal_candidate_window_willow_green_light.html
@@ -0,0 +1,634 @@
+
+
+
+
+
+
+ (IME)WechatLightHCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/candwnd/vertical_candidate_window_graphite.html b/ui-html/webview2/candwnd/vertical_candidate_window_graphite.html
new file mode 100644
index 00000000..e6a81cb4
--- /dev/null
+++ b/ui-html/webview2/candwnd/vertical_candidate_window_graphite.html
@@ -0,0 +1,726 @@
+
+
+
+
+
+
+ (IME)VCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/candwnd/vertical_candidate_window_graphite_light.html b/ui-html/webview2/candwnd/vertical_candidate_window_graphite_light.html
new file mode 100644
index 00000000..08186d9a
--- /dev/null
+++ b/ui-html/webview2/candwnd/vertical_candidate_window_graphite_light.html
@@ -0,0 +1,726 @@
+
+
+
+
+
+
+ (IME)VCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/candwnd/vertical_candidate_window_willow_green.html b/ui-html/webview2/candwnd/vertical_candidate_window_willow_green.html
new file mode 100644
index 00000000..139dff81
--- /dev/null
+++ b/ui-html/webview2/candwnd/vertical_candidate_window_willow_green.html
@@ -0,0 +1,752 @@
+
+
+
+
+
+
+ (IME)WechatVCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/candwnd/vertical_candidate_window_willow_green_light.html b/ui-html/webview2/candwnd/vertical_candidate_window_willow_green_light.html
new file mode 100644
index 00000000..31ac38a0
--- /dev/null
+++ b/ui-html/webview2/candwnd/vertical_candidate_window_willow_green_light.html
@@ -0,0 +1,751 @@
+
+
+
+
+
+
+ (IME)WechatLightVCandWnd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/ftb/graphite.html b/ui-html/webview2/ftb/graphite.html
new file mode 100644
index 00000000..fb14865d
--- /dev/null
+++ b/ui-html/webview2/ftb/graphite.html
@@ -0,0 +1,434 @@
+
+
+
+
+
+ IME(FTB)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/ftb/graphite_light.html b/ui-html/webview2/ftb/graphite_light.html
new file mode 100644
index 00000000..d26509e2
--- /dev/null
+++ b/ui-html/webview2/ftb/graphite_light.html
@@ -0,0 +1,433 @@
+
+
+
+
+
+ IME(FTB)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/ftb/willow_green.html b/ui-html/webview2/ftb/willow_green.html
new file mode 100644
index 00000000..fe292821
--- /dev/null
+++ b/ui-html/webview2/ftb/willow_green.html
@@ -0,0 +1,430 @@
+
+
+
+
+
+ IME(WeChat FTB)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/ftb/willow_green_light.html b/ui-html/webview2/ftb/willow_green_light.html
new file mode 100644
index 00000000..75ac3b91
--- /dev/null
+++ b/ui-html/webview2/ftb/willow_green_light.html
@@ -0,0 +1,429 @@
+
+
+
+
+
+ IME(WeChat Light FTB)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-html/webview2/settings/ime-settings/src/modules/skin.ts b/ui-html/webview2/settings/ime-settings/src/modules/skin.ts
index bf31f27c..85017ca4 100644
--- a/ui-html/webview2/settings/ime-settings/src/modules/skin.ts
+++ b/ui-html/webview2/settings/ime-settings/src/modules/skin.ts
@@ -2,19 +2,21 @@ import { loadHTML } from '../utils/common-utils';
import ftbHTML from '../../../../ftb/default.html?raw';
export type SkinPreviewTheme = 'dark' | 'light';
-export type CandidateSkin = 'fluent' | 'wechat';
+export type CandidateSkin = 'fluent' | 'wechat' | 'graphite' | 'willow_green';
-const SKINS: CandidateSkin[] = ['fluent', 'wechat'];
+const SKINS: CandidateSkin[] = ['fluent', 'wechat', 'graphite', 'willow_green'];
const previewOverrides: Record = {
fluent: null,
- wechat: null
+ wechat: null,
+ graphite: null,
+ willow_green: null
};
let activeTheme: SkinPreviewTheme = 'dark';
let activeSkin: CandidateSkin = 'fluent';
const SKIN_PREVIEW_PAGE_SIZE = 6;
function normalizeCandidateSkin(value: unknown): CandidateSkin {
- return value === 'wechat' ? 'wechat' : 'fluent';
+ return value === 'wechat' || value === 'graphite' || value === 'willow_green' ? value : 'fluent';
}
function limitCandidatePreview(host: HTMLElement): void {
@@ -44,7 +46,13 @@ function applySkinPreviewTheme(skin: CandidateSkin, theme: SkinPreviewTheme): vo
const title = card.querySelector('.section-title');
if (title) {
- const name = skin === 'wechat' ? '微信绿主题' : 'Fluent 主题';
+ const name = skin === 'wechat'
+ ? '微信绿主题'
+ : skin === 'graphite'
+ ? '石墨 Graphite'
+ : skin === 'willow_green'
+ ? '杨柳青 Willow green'
+ : 'Fluent 主题';
title.textContent = `${name}(${theme === 'light' ? 'Light' : 'Dark'})`;
}
card.querySelectorAll('[data-skin-preview-switch]').forEach((button) => {
@@ -66,11 +74,17 @@ function syncSkinSwitches(): void {
function syncAppearancePreviews(): void {
const useWechat = activeSkin === 'wechat';
+ const useGraphite = activeSkin === 'graphite';
+ const useWillowGreen = activeSkin === 'willow_green';
document.querySelectorAll('.cand-preview .candidate').forEach((element) => {
element.classList.toggle('skin-wechat', useWechat);
+ element.classList.toggle('skin-graphite', useGraphite);
+ element.classList.toggle('skin-willow-green', useWillowGreen);
});
document.querySelectorAll('.ftb-preview-host:not([data-skin-toolbar])').forEach((element) => {
element.classList.toggle('skin-wechat', useWechat);
+ element.classList.toggle('skin-graphite', useGraphite);
+ element.classList.toggle('skin-willow-green', useWillowGreen);
});
}
diff --git a/ui-html/webview2/settings/ime-settings/src/partials/skin.html b/ui-html/webview2/settings/ime-settings/src/partials/skin.html
index 80509c89..5dfe8bd7 100644
--- a/ui-html/webview2/settings/ime-settings/src/partials/skin.html
+++ b/ui-html/webview2/settings/ime-settings/src/partials/skin.html
@@ -54,4 +54,58 @@
+
+
+
+
diff --git a/ui-html/webview2/settings/ime-settings/src/styles/modules/skin.css b/ui-html/webview2/settings/ime-settings/src/styles/modules/skin.css
index 403f40c4..319580de 100644
--- a/ui-html/webview2/settings/ime-settings/src/styles/modules/skin.css
+++ b/ui-html/webview2/settings/ime-settings/src/styles/modules/skin.css
@@ -77,3 +77,152 @@
box-shadow: 0 5px 14px rgba(0, 0, 0, .12);
}
.ftb-preview-host.skin-wechat .drag-handle { background: #07c160; }
+
+/* Preview equivalents of the standalone Graphite skin HTML files. */
+.candidate.skin-graphite.theme-dark {
+ --cand-bg: #1c1f23;
+ --cand-border: #30353b;
+ --cand-shadow: 0 2px 8px rgba(0, 0, 0, .28);
+ --cand-text: #aeb6c2;
+ --cand-num: #707987;
+ --cand-hover: rgba(255, 255, 255, .055);
+ --cand-selected: transparent;
+ --accent-strong: #8993a0;
+}
+.candidate.skin-graphite.theme-light {
+ --cand-bg: #fbfbfc;
+ --cand-border: #e2e5e9;
+ --cand-shadow: 0 2px 8px rgba(17, 24, 39, .10);
+ --cand-text: #586476;
+ --cand-num: #8993a1;
+ --cand-hover: rgba(31, 41, 55, .055);
+ --cand-selected: transparent;
+ --accent-strong: #5f6b7a;
+}
+.candidate.skin-graphite .container { padding: 3px 5px; border-radius: 3px; }
+.candidate.skin-graphite .cand,
+.candidate.skin-graphite .first { border-radius: 2px; }
+.candidate.skin-graphite .first::before { display: none; }
+.candidate.skin-graphite.theme-dark .first .text,
+.candidate.skin-graphite.theme-dark .first .num,
+.candidate.skin-graphite.theme-dark .first .cand-no { color: #f1f3f5; }
+.candidate.skin-graphite.theme-light .first .text,
+.candidate.skin-graphite.theme-light .first .num,
+.candidate.skin-graphite.theme-light .first .cand-no { color: #111827; }
+
+.ftb-preview-host.skin-graphite.theme-dark .status-bar {
+ background-color: #1c1f23;
+ border-color: #30353b;
+ border-radius: calc(4px * var(--ftb-scale));
+ box-shadow: 0 2px 8px rgba(0, 0, 0, .28);
+}
+.ftb-preview-host.skin-graphite.theme-light .status-bar {
+ background-color: #fbfbfc;
+ border-color: #e2e5e9;
+ border-radius: calc(4px * var(--ftb-scale));
+ box-shadow: 0 2px 8px rgba(17, 24, 39, .10);
+}
+.ftb-preview-host.skin-graphite.theme-dark .drag-handle { background: #8993a0; }
+.ftb-preview-host.skin-graphite.theme-light .drag-handle { background: #5f6b7a; }
+.ftb-preview-host.skin-graphite .icon { border-radius: calc(3px * var(--ftb-scale)); }
+
+/* Preview equivalents of the standalone Willow green skin HTML files. */
+.candidate.skin-willow-green.theme-dark {
+ --accent-strong: #65c98d;
+ --cand-bg: #2d2f2e;
+ --cand-border: #3b3e3c;
+ --cand-shadow: 0 7px 18px rgba(0, 0, 0, .34);
+ --cand-text: #d8dbd8;
+ --cand-num: #a6aba7;
+ --cand-hover: rgba(101, 201, 141, .22);
+ --cand-selected: #65c98d;
+}
+.candidate.skin-willow-green.theme-light {
+ --accent-strong: #58b980;
+ --cand-bg: #f4f5f3;
+ --cand-border: #dfe3df;
+ --cand-shadow: 0 7px 18px rgba(42, 55, 47, .16);
+ --cand-text: #343936;
+ --cand-num: #686f6a;
+ --cand-hover: rgba(88, 185, 128, .16);
+ --cand-selected: #58b980;
+}
+.candidate.skin-willow-green .container { padding: 0; border-radius: 9px; }
+.candidate.skin-willow-green .cand,
+.candidate.skin-willow-green .first { border-radius: 0; }
+.candidate.skin-willow-green .first::before { display: none; }
+.candidate.skin-willow-green .first .text,
+.candidate.skin-willow-green .first .num,
+.candidate.skin-willow-green .first .cand-no { color: #fff; }
+.candidate.skin-willow-green.wnd-v .row.pinyin {
+ margin-top: 0;
+ padding: 6px 12px 4px 8px;
+}
+.candidate.skin-willow-green.wnd-v .row.cand {
+ margin-top: 0;
+ padding: 4px 14px 4px 8px;
+}
+.candidate.skin-willow-green.wnd-v .container.preedit-hidden > .pinyin + .row-wrapper > .first {
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
+}
+.candidate.skin-willow-green.wnd-v .container > .row-wrapper:last-child > .first {
+ border-bottom-left-radius: 8px;
+ border-bottom-right-radius: 8px;
+}
+.candidate.skin-willow-green.wnd-h {
+ width: fit-content;
+ max-width: 100%;
+}
+.candidate.skin-willow-green.wnd-h .container {
+ width: max-content;
+ max-width: 100%;
+ letter-spacing: -0.31em;
+}
+.candidate.skin-willow-green.wnd-h .row.pinyin {
+ letter-spacing: normal;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding: 6px 10px 3px 8px;
+}
+.candidate.skin-willow-green.wnd-h .row.cand {
+ margin-top: 0;
+ margin-bottom: 0;
+ padding: 6px 8px;
+}
+.candidate.skin-willow-green.wnd-h .row-wrapper {
+ display: inline-block;
+ letter-spacing: normal;
+ margin: 0;
+ vertical-align: top;
+}
+.candidate.skin-willow-green.wnd-h .first-row-wrapper { margin-left: 0; }
+.candidate.skin-willow-green.wnd-h .container.preedit-hidden > .pinyin + .row-wrapper > .first {
+ border-top-left-radius: 8px;
+ border-bottom-left-radius: 8px;
+}
+.candidate.skin-willow-green.wnd-h .container:not(.preedit-hidden) > .pinyin + .row-wrapper > .first {
+ border-bottom-left-radius: 8px;
+}
+.candidate.skin-willow-green.wnd-h .container.preedit-hidden > .row-wrapper:last-child > .first {
+ border-top-right-radius: 8px;
+ border-bottom-right-radius: 8px;
+}
+.candidate.skin-willow-green.wnd-h .container:not(.preedit-hidden) > .row-wrapper:last-child > .first {
+ border-bottom-right-radius: 8px;
+}
+
+.ftb-preview-host.skin-willow-green.theme-dark .status-bar {
+ background-color: #2d2f2e;
+ border-color: #3b3e3c;
+ border-radius: calc(9px * var(--ftb-scale));
+ box-shadow: 0 7px 18px rgba(0, 0, 0, .34);
+}
+.ftb-preview-host.skin-willow-green.theme-light .status-bar {
+ background-color: #f4f5f3;
+ border-color: #dfe3df;
+ border-radius: calc(9px * var(--ftb-scale));
+ box-shadow: 0 7px 18px rgba(42, 55, 47, .16);
+}
+.ftb-preview-host.skin-willow-green.theme-dark .drag-handle { background: #65c98d; }
+.ftb-preview-host.skin-willow-green.theme-light .drag-handle { background: #58b980; }