[ui]: some settings ui parts

This commit is contained in:
fanlumaster committed 2025-11-07 01:11:19 +08:00
1 parent 64435eeee8
commit 404f1aa737
4 files changed
+311 -65

No files matched your search

@@ -19,7 +19,7 @@
.container {
margin-top: 0px;
margin-left: 0px;
background-color: #202020;
background: #202020;
/* background: url("https://appassets/background.jpg"); */
padding: 2px;
border-radius: 6px;
@@ -27,7 +27,7 @@
min-width: 7em;
width: fit-content;
user-select: none;
border: 2px solid #9b9b9b2e;
border: 1.5px solid #9b9b9b2e;
}
.row {
+171 -44
View File
@@ -18,24 +18,44 @@
<img src="./assets/MetasequoiaIME.ico" alt="">
<span>水杉输入法</span>
</div>
<div class="item"><span class="icon">⚙️</span> 通用</div>
<div class="item active"><span class="icon">🎨</span> 外观</div>
<div class="item"><span class="icon input-icon">⌨️</span> 输入</div>
<div class="item"><span class="icon">🧩</span> 辅助码</div>
<div class="item"><span class="icon">⌘</span> 快捷键</div>
<div class="item"><span class="icon">📚</span> 词库</div>
<div class="item"><span class="icon">🖼️</span> 皮肤</div>
<div class="item"><span class="icon">🎙️</span> 语音打字</div>
<div class="item"><span class="icon">🤖</span> AI 辅助</div>
<div class="item"><span class="icon">❓</span> 帮助</div>
<div class="item"><span class="icon">ℹ️</span> 关于</div>
<div class="item"><span class="icon">💬</span> 反馈</div>
<div class="item" data-target="general-settings"><span class="icon">⚙️</span> 通用</div>
<div class="item active" data-target="appearence-settings"><span class="icon">🎨</span> 外观</div>
<div class="item" data-target="input-settings"><span class="icon input-icon">⌨️</span> 输入</div>
<div class="item" data-target="helpcode-settings"><span class="icon">🧩</span> 辅助码</div>
<div class="item" data-target="shortcut-settings"><span class="icon">⌘</span> 快捷键</div>
<div class="item" data-target="dict-settings"><span class="icon">📚</span> 词库</div>
<div class="item" data-target="skin-settings"><span class="icon">🖼️</span> 皮肤</div>
<div class="item" data-target="voice-settings"><span class="icon">🎙️</span> 语音打字</div>
<div class="item" data-target="screenkb-settings"><span class="icon">🖥️</span> 屏幕键盘</div>
<div class="item" data-target="tools-settings"><span class="icon">🛠️</span> 实用功能</div>
<div class="item" data-target="ai-settings"><span class="icon">🤖</span> AI 辅助</div>
<div class="item" data-target="help-settings"><span class="icon">❓</span> 帮助</div>
<div class="item" data-target="about-settings"><span class="icon">ℹ️</span> 关于</div>
<div class="item" data-target="feedback-settings"><span class="icon">💬</span> 反馈</div>
</div>
<div class="content">
<!-- 通用 -->
<div class="content" id="general-settings">
<div class="content-header"><span>通用</span></div>
<!-- 悬浮工具栏 toggle -->
<div class="section ftb-toggle">
<div class="section-header">
<div class="section-title">悬浮工具栏</div>
<div class="ftb-toggle-btn" id="ftbToggleBtn">
<div class="ftb-toggle-knob"></div>
</div>
</div>
</div>
</div>
<!-- 外观 -->
<div class="content active" id="appearence-settings">
<div class="content-header"><span>外观</span></div>
<!-- 候选窗口预览 -->
<div class="section candidate-preview">
<h2>候选窗口预览</h2>
<div class="section-title cand-prev-title">候选窗口预览</div>
<div class="candidate-container">
<div class="candidate-row">
<div class="candidate-text">ni'mf</div>
@@ -83,9 +103,10 @@
</div>
</div>
<!-- 主题模式 -->
<div class="section theme">
<div class="section-header">
<h2>主题模式</h2>
<div class="section-title">主题模式(默认)</div>
<div class="dropdown">
<button class="dropdown-toggle" id="themeBtn">
<span>深色</span>
@@ -100,47 +121,153 @@
</div>
</div>
</div>
<div class="divider"></div>
<div class="section-header arrange-item">
<div class="section-title">候选项排列方式</div>
<div class="dropdown">
<button class="dropdown-toggle" id="arrangeBtn">
<span>竖排</span>
<div class="arrow">
<img src="./assets/arrow.svg" alt="arrow">
</div>
</button>
<div class="dropdown-menu" id="arrangeMenu">
<div class="dropdown-item" data-value="horizontal">横排</div>
<div class="dropdown-item" data-value="vertical">竖排</div>
</div>
</div>
</div>
</div>
</div>
<!-- 输入 -->
<div class="content" id="input-settings">
<div class="content-header"><span>输入</span></div>
</div>
<!-- 辅助码 -->
<div class="content" id="helpcode-settings">
<div class="content-header"><span>辅助码</span></div>
</div>
<!-- 快捷键 -->
<div class="content" id="shortcut-settings">
<div class="content-header"><span>快捷键</span></div>
</div>
<!-- 词库 -->
<div class="content" id="dict-settings">
<div class="content-header"><span>词库</span></div>
</div>
<!-- 皮肤 -->
<div class="content" id="skin-settings">
<div class="content-header"><span>皮肤</span></div>
</div>
<!-- 语音打字 -->
<div class="content" id="voice-settings">
<div class="content-header"><span>语音打字</span></div>
</div>
<!-- 屏幕键盘 -->
<div class="content" id="screenkb-settings">
<div class="content-header"><span>屏幕键盘</span></div>
</div>
<!-- 实用功能 -->
<div class="content" id="tools-settings">
<div class="content-header"><span>实用功能</span></div>
</div>
<!-- AI 辅助 -->
<div class="content" id="ai-settings">
<div class="content-header"><span>AI 辅助</span></div>
</div>
<!-- 帮助 -->
<div class="content" id="help-settings">
<div class="content-header"><span>帮助</span></div>
</div>
<!-- 关于 -->
<div class="content" id="about-settings">
<div class="content-header"><span>关于</span></div>
</div>
<!-- 反馈 -->
<div class="content" id="feedback-settings">
<div class="content-header"><span>反馈</span></div>
</div>
</div>
</div>
<script>
const btn = document.getElementById('themeBtn');
const menu = document.getElementById('themeMenu');
const dropdown = document.querySelector('.dropdown');
const textSpan = btn.querySelector('span');
// 打开/关闭下拉菜单
btn.addEventListener('click', (e) => {
e.stopPropagation();
dropdown.classList.toggle('open');
});
const sidebarItems = document.querySelectorAll('.sidebar .item');
// 点击菜单项
menu.querySelectorAll('.dropdown-item').forEach(item => {
item.addEventListener('click', (e) => {
const value = item.dataset.value;
const text = item.textContent;
sidebarItems.forEach(item => {
item.addEventListener('click', () => {
document.querySelector('.sidebar .item.active')?.classList.remove('active');
item.classList.add('active');
// 更新按钮文字
textSpan.textContent = text;
// 可选:发送给 webview 通知主题变化
if (window.chrome?.webview) {
window.chrome.webview.postMessage({ action: "changeTheme", theme: value });
}
// 关闭菜单
dropdown.classList.remove('open');
document.querySelector('.content.active')?.classList.remove('active');
const targetId = item.dataset.target;
document.getElementById(targetId)?.classList.add('active');
});
});
// 点击其他地方关闭菜单
document.addEventListener('click', (e) => {
if (!dropdown.contains(e.target)) {
dropdown.classList.remove('open');
}
//
// 外观 -> 主题模式(默认)
//
document.querySelectorAll('.dropdown').forEach(dropdown => {
const btn = dropdown.querySelector('.dropdown-toggle');
const menu = dropdown.querySelector('.dropdown-menu');
const textSpan = btn.querySelector('span');
// 打开/关闭菜单
btn.addEventListener('click', e => {
e.stopPropagation();
dropdown.classList.toggle('open');
});
// 点击菜单项
menu.querySelectorAll('.dropdown-item').forEach(item => {
item.addEventListener('click', () => {
textSpan.textContent = item.textContent;
// 根据按钮 id 区分动作
if (window.chrome?.webview) {
if (btn.id === 'themeBtn') {
window.chrome.webview.postMessage({ action: "changeTheme", theme: item.dataset.value });
} else if (btn.id === 'arrangeBtn') {
window.chrome.webview.postMessage({ action: "changeCandidateArrange", arrange: item.dataset.value });
}
}
dropdown.classList.remove('open');
});
});
});
// 点击空白处关闭所有下拉
document.addEventListener('click', () => {
document.querySelectorAll('.dropdown').forEach(d => d.classList.remove('open'));
});
//
// 外观 -> 候选项排列方式
//
//
// 通用 -> 悬浮工具栏
//
const toggle = document.getElementById('ftbToggleBtn');
toggle.addEventListener('click', () => {
toggle.classList.toggle('active');
});
</script>
</body>
+126 -7
View File
@@ -44,6 +44,40 @@ body {
flex-direction: column;
padding: 12px 0;
overflow-y: auto;
scrollbar-gutter: stable;
}
/* 整个滚动条宽度 */
.sidebar::-webkit-scrollbar {
width: 8px;
}
/* 滚动条轨道 */
.sidebar::-webkit-scrollbar-track {
background: transparent;
}
/* 滚动条滑块 */
.sidebar::-webkit-scrollbar-thumb {
background-color: rgba(120, 120, 120, 0.4);
border-radius: 2px;
transition: background-color 0.2s;
}
/* 滚动条在鼠标悬浮时更亮一些 */
.sidebar::-webkit-scrollbar-thumb:hover {
background-color: rgba(160, 160, 160, 0.6);
}
/* 深色模式下更暗 */
@media (prefers-color-scheme: dark) {
.sidebar::-webkit-scrollbar-thumb {
background-color: rgba(180, 180, 180, 0.25);
}
.sidebar::-webkit-scrollbar-thumb:hover {
background-color: rgba(220, 220, 220, 0.4);
}
}
.sidebar-header {
@@ -54,6 +88,14 @@ body {
margin-bottom: 8px;
}
.content-header {
display: flex;
align-items: center;
padding: 0 24px 12px 4px;
gap: 10px;
margin-bottom: 8px;
}
.sidebar-header img {
width: 28px;
height: 28px;
@@ -61,6 +103,11 @@ body {
}
.sidebar-header span {
font-weight: 500;
font-size: 19px;
}
.content-header span {
font-weight: 500;
font-size: 18px;
}
@@ -97,6 +144,7 @@ body {
border-radius: 5px;
margin: 2px 8px;
color: #e6e6e6;
/* font-weight: 450; */
}
.sidebar .item:hover {
@@ -112,7 +160,8 @@ body {
color: #fff;
}
.sidebar .item.active::before {
/* item 左侧的 bar */
.sidebar .item::before {
content: "";
position: absolute;
left: -2px;
@@ -120,12 +169,33 @@ body {
height: 50%;
border-radius: 3px;
background: var(--accent-color);
/* 初始收起 */
transform: scaleY(0);
/* 从中间往上下展开 */
transform-origin: center center;
/* 动画过渡 */
transition: transform 0.25s ease;
/* 初始隐藏 */
opacity: 0;
}
.sidebar .item.active::before {
transform: scaleY(1);
/* 展开 */
opacity: 1;
/* 渐显 */
}
.content {
flex: 1;
padding: 12px 12px;
overflow-y: auto;
display: none;
margin-top: 2px;
}
.active {
display: block;
}
.section {
@@ -135,12 +205,13 @@ body {
padding: 20px 24px;
margin-bottom: 18px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
backdrop-filter: blur(10px);
/* backdrop-filter: blur(10px); */
/* z-index: 0; */
}
.section h2 {
.section-title {
font-size: 15px;
font-weight: 600;
font-weight: 550;
color: #ccc;
}
@@ -165,6 +236,10 @@ select:focus {
margin-bottom: 12px;
}
.cand-prev-title {
margin-bottom: 12px;
}
input[type="range"] {
width: 100%;
accent-color: var(--accent-color);
@@ -231,8 +306,19 @@ input[type="range"] {
gap: 10px;
}
.divider {
width: 100%;
height: 1px;
background-color: #908f8f16;
margin: 12px 0;
}
.arrange-item {
margin-top: 12px;
}
/* 主题模式 */
.theme {
.theme .ftb-toggle {
padding-top: 5px;
padding-bottom: 5px;
}
@@ -259,7 +345,6 @@ input[type="range"] {
font-size: 14px;
padding: 4px 12px;
padding-right: 6px;
cursor: pointer;
transition: all 0.2s ease;
text-align: left;
min-width: 100px;
@@ -301,7 +386,6 @@ div.arrow {
.dropdown-item {
margin: 2px;
padding: 4px 8px;
cursor: pointer;
color: #eee;
border-radius: 8px;
font-size: 14px;
@@ -316,4 +400,39 @@ div.arrow {
.dropdown.open .dropdown-menu {
display: block;
}
/* 外观 -> 悬浮工具栏 */
.ftb-toggle-btn {
position: relative;
width: 38px;
height: 19px;
background: #555;
border-radius: 9px;
cursor: pointer;
flex-shrink: 0;
transition: background 0.2s ease, border 0.2s ease;
}
.ftb-toggle-knob {
position: absolute;
top: 50%;
left: 1px;
width: 16px;
height: 16px;
background: #fff;
border-radius: 50%;
transform: translateY(-50%);
transition: all 0.2s ease;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.ftb-toggle-btn.active {
background: #8E8CD8;
border-color: #555;
}
.ftb-toggle-btn.active .ftb-toggle-knob {
/* 38 - 16 - 1 * 2 = 20 */
transform: translate(20px, -50%);
}
+12 -12
View File
@@ -75,7 +75,7 @@ int CreateCandidateWindow(HINSTANCE hInstance)
WS_EX_TOPMOST; //
FLOAT scale = GetForegroundWindowScale();
HWND hwnd = CreateWindowEx( //
HWND hwnd_cand = CreateWindowEx( //
dwExStyle, //
szWindowClass, //
lpWindowNameCand, //
@@ -90,7 +90,7 @@ int CreateCandidateWindow(HINSTANCE hInstance)
nullptr //
); //
if (!hwnd)
if (!hwnd_cand)
{
OutputDebugString(fmt::format(L"Call to CreateWindow for candidate window failed!\n").c_str());
return 1;
@@ -98,15 +98,15 @@ int CreateCandidateWindow(HINSTANCE hInstance)
else
{
// Set the window to be fully not transparent
SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA);
SetLayeredWindowAttributes(hwnd_cand, 0, 255, LWA_ALPHA);
MARGINS mar = {-1};
DwmExtendFrameIntoClientArea(hwnd, &mar);
DwmExtendFrameIntoClientArea(hwnd_cand, &mar);
}
::global_hwnd = hwnd;
::global_hwnd = hwnd_cand;
SetWindowPos( //
hwnd, //
hwnd_cand, //
HWND_TOPMOST, //
-10000, //
-10000, //
@@ -116,7 +116,7 @@ int CreateCandidateWindow(HINSTANCE hInstance)
);
SetWindowPos( //
hwnd, //
hwnd_cand, //
HWND_TOPMOST, //
100, //
100, //
@@ -197,8 +197,8 @@ int CreateCandidateWindow(HINSTANCE hInstance)
/* 设置标题栏和窗口区域为 mica 材质 */
MARGINS margins = {-1};
DwmExtendFrameIntoClientArea(hwnd_settings, &margins);
DWM_SYSTEMBACKDROP_TYPE backdrop = DWMSBT_MAINWINDOW; // Mica 背景类型
DwmSetWindowAttribute(hwnd_settings, DWMWA_SYSTEMBACKDROP_TYPE, &backdrop, sizeof(backdrop));
DWM_SYSTEMBACKDROP_TYPE backdrop_settings = DWMSBT_MAINWINDOW; // Mica 背景类型
DwmSetWindowAttribute(hwnd_settings, DWMWA_SYSTEMBACKDROP_TYPE, &backdrop_settings, sizeof(backdrop_settings));
//
// floating toolbar 窗口
@@ -231,12 +231,12 @@ int CreateCandidateWindow(HINSTANCE hInstance)
//
// 候选窗口、菜单窗口、settings 窗口、floating toolbar 窗口、floating toolbar hover tip 窗口
//
ShowWindow(hwnd, SW_SHOW);
ShowWindow(hwnd_cand, SW_SHOW);
ShowWindow(hwnd_menu, SW_SHOW);
ShowWindow(hwnd_settings, SW_SHOWMINIMIZED);
ShowWindow(hwnd_settings, SW_RESTORE);
ShowWindow(hwnd_ftb, SW_SHOW);
UpdateWindow(hwnd);
UpdateWindow(hwnd_cand);
UpdateWindow(hwnd_menu);
UpdateWindow(hwnd_settings);
UpdateWindow(hwnd_ftb);
@@ -246,7 +246,7 @@ int CreateCandidateWindow(HINSTANCE hInstance)
//
PrepareHtmlForWnds();
/* 候选框窗口 */
InitWebviewCandWnd(hwnd);
InitWebviewCandWnd(hwnd_cand);
/* 托盘语言区右键菜单窗口 */
InitWebviewMenuWnd(hwnd_menu);
/* settings 窗口 */