diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index 509a4d1..4f9d1db 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -81,21 +81,22 @@ DOM or live LiteGraph state.
primary model-browser surfaces, including the frosted-glass capsule parameter inspection
button with lightweight vector SVG icons and GPU-accelerated micro-interactions;
the sidebar bottom action bar (`#anomalous-sidebar-actions`) features intuitive, highly restrained glyphic vector SVG icons (`SIDEBAR_ICONS`):
- (1) Toolbox Hub (`#anomalous-toolbox-btn`): Precision 18px vector toolbox icon (`TOOLBOX`) anchoring the leftmost action slot, triggering an elevated 310px utility popover (`#anomalous-toolbox-modal`, z-index 999999) with dynamic responsive offset (`left: 266px`, collapsed `72px`), extensible tool registry (`this.registerToolboxItem`), and mutual exclusivity against Settings Hub;
- (2) Scan Wizard (`#anomalous-scan-btn`): Clean circular radar scope with range ring, crosshairs, and sweep beacon (`SCAN_RADAR_ICON_SVG`), animated only during active scanning;
- (3) Model Doctor (`#anomalous-doctor-btn`): Sleek diagnostic medical stethoscope, instantly conveying health check semantics;
- (4) AI Assistant (`#anomalous-assistant-btn`): Radiant AI copilot sparkles (`✦`), representing copilot intelligence;
- (5) Material Library (`#anomalous-materials-btn`): 3D layered preset stack, distinguishing from individual model boxes;
- (6) Settings Hub (`#anomalous-global-settings-btn`): Precision 8-tooth mechanical engineering gear with elevated popover (`#anomalous-settings-hub-modal`) mounted directly to container with `z-index: 999999` and dynamic responsive offset; hosts a clean 3-way Display Mode segmented controller (`#anomalous-view-mode-container` for Standard, Compact, and Aesthetic modes), UI scale controls, dynamic background atmosphere controls, folder manager, language toggles, a restrained inline 13px glyph question icon for Help (decoupling from `.anomalous-btn-icon` 32px box trap), and an intuitive reload arrow (`↺`) for window layout reset replacing esoteric drafting ruler emojis;
- (7) Models & Floating Trigger: Precision 3D Isometric Asset Model Cube SVG (`box`), universally conveying 3D model, mesh, and asset package semantics with zero visual ambiguity;
- adhering to a "low-stimulus idle, subtle-illumination on hover" philosophy where icons use calm `currentColor` in idle state and gently illuminate on interaction;
- critical tool workbenches (`#anomalous-doctor-panel`, `#anomalous-assistant-panel`) strictly enforce 100% opaque, solid backgrounds (`background: var(--amb-bg-page, #131315) !important`) to eliminate background distraction during diagnostics;
- the UI palette strictly adheres to a true neutral dark charcoal / obsidian studio aesthetic (`#131315`, `#1a1a1d`, `#202024`, `#28282d`) with zero cool-blue/navy cast, matching ComfyUI, Blender, and DaVinci Resolve workstation standards;
- the sidebar action bar's circular astrological runic compass watermark (`#anomalous-sidebar-actions::before`) is completely disabled (`display: none !important`), and any backdrop textures are desaturated with `grayscale(100%)` to prevent blue color bleeding;
- all primary action highlights, scan wizard controls, and switches use titanium white (`#e5e7eb` / `#ffffff`) with warm studio amber (`#f59e0b`) accents instead of cold blue/cyan;
- the modal adopts a disciplined "workshop / archive" aesthetic: removing exaggerated `clip-path` chamfers in favor of clean 8px architectural engineering geometry (`border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.1)`);
- the master header (`#anomalous-header`) and sidebar brand bar (`#anomalous-brand-bar`) are tightly calibrated to a 48px slim industrial profile; header navigation tabs (`#anomalous-models-btn`, `#anomalous-gallery-btn`, `#anomalous-notebook-btn`) and window control buttons (`#anomalous-dock-btn`, `#anomalous-close`) are unified to a compact 28px height, 6px border radius, 13px vector icons, active tab tracking, and persistent bilingual text labels (`.anomalous-btn-text` with `display: inline !important`, permanently removing legacy container query text suppression), perfectly harmonizing with adjacent dock and close controls;
- supports 3 unified Display Modes sharing identical DOM structure and UX logic:
+ (1) Toolbox Hub (`#anomalous-toolbox-btn`): Precision 18px vector toolbox icon (`TOOLBOX`) anchoring the leftmost action slot, triggering an elevated 232px micro-utility drawer popover (`#anomalous-toolbox-modal`, z-index 999999) anchored directly above the action bar in the bottom-left corner (`bottom: 50px; left: 10px;`, collapsed `left: 68px`), presenting a high-density 3-column app/utility icon grid palette (`.anomalous-toolbox-grid`, `.anomalous-toolbox-tile`) with instant tooltips, amber status indicator dots, extensible tool registry (`this.registerToolboxItem`), zero obstruction to the central model grid, and mutual exclusivity against Settings Hub;
+ (2) Scan Wizard (`#anomalous-scan-btn`): Clean circular radar scope with range ring, crosshairs, and sweep beacon (`SCAN_RADAR_ICON_SVG`), animated only during active scanning;
+ (3) Model Doctor (`#anomalous-doctor-btn`): Sleek diagnostic medical stethoscope, instantly conveying health check semantics;
+ (4) AI Assistant (`#anomalous-assistant-btn`): Radiant AI copilot sparkles (`✦`), representing copilot intelligence;
+ (5) Material Library (`#anomalous-materials-btn`): 3D layered preset stack, distinguishing from individual model boxes;
+ (6) Settings Hub (`#anomalous-global-settings-btn`): Precision 8-tooth mechanical engineering gear with elevated popover (`#anomalous-settings-hub-modal`) mounted directly to container with `z-index: 999999` and dynamic responsive offset; hosts a clean 3-way Display Mode segmented controller (`#anomalous-view-mode-container` for Standard, Compact, and Aesthetic modes), UI scale controls, dynamic background atmosphere controls, folder manager, language toggles, a restrained inline 13px glyph question icon for Help (decoupling from `.anomalous-btn-icon` 32px box trap), and an intuitive reload arrow (`↺`) for window layout reset replacing esoteric drafting ruler emojis;
+ (7) Models & Floating Trigger: Precision 3D Isometric Asset Model Cube SVG (`box`), universally conveying 3D model, mesh, and asset package semantics with zero visual ambiguity;
+ adhering to a "low-stimulus idle, subtle-illumination on hover" philosophy where icons use calm `currentColor` in idle state and gently illuminate on interaction;
+ critical tool workbenches (`#anomalous-doctor-panel`, `#anomalous-assistant-panel`) strictly enforce 100% opaque, solid backgrounds (`background: var(--amb-bg-page, #131315) !important`) to eliminate background distraction during diagnostics;
+ the UI palette strictly adheres to a true neutral dark charcoal / obsidian studio aesthetic (`#131315`, `#1a1a1d`, `#202024`, `#28282d`) with zero cool-blue/navy cast, matching ComfyUI, Blender, and DaVinci Resolve workstation standards;
+ the sidebar action bar's circular astrological runic compass watermark (`#anomalous-sidebar-actions::before`) is completely disabled (`display: none !important`), and any backdrop textures are desaturated with `grayscale(100%)` to prevent blue color bleeding;
+ all primary action highlights, scan wizard controls, and switches use titanium white (`#e5e7eb` / `#ffffff`) with warm studio amber (`#f59e0b`) accents instead of cold blue/cyan;
+ the modal adopts a disciplined "workshop / archive" aesthetic: removing exaggerated `clip-path` chamfers in favor of clean 8px architectural engineering geometry (`border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.1)`);
+ the master header (`#anomalous-header`) and sidebar brand bar (`#anomalous-brand-bar`) are tightly calibrated to a 48px slim industrial profile; header navigation tabs (`#anomalous-models-btn`, `#anomalous-gallery-btn`, `#anomalous-notebook-btn`) and window control buttons (`#anomalous-dock-btn`, `#anomalous-close`) are unified to a compact 28px height, 6px border radius, 13px vector icons, active tab tracking, and persistent bilingual text labels (`[ 📦 模型 ]`, `[ 🖼️ 图库 ]`, `[ 🔗 工作流 ]` - simplified from "工作流配方" to balance width and match ComfyUI workflow mental model), perfectly harmonizing with adjacent dock and close controls;
+ cards feature restored and refined top-right micro-action buttons (`.anomalous-card-action-btn`: Apply ➕, Edit ✏️, Scan 🎯) with 22px frosted glass styling, smooth hover fade-in, and auto-clipping avoidance against the base model badge (`.anomalous-card-badge`);
+ supports 3 unified Display Modes sharing identical DOM structure and UX logic:
- Compact Mode (紧凑模式, primary default): 140px min-width, 220px card height, tight 10px gaps/14px rows, 5px sidebar folder rows, optimized for high-density scanning and instant visual discovery (Blender Asset Browser inspired);
- Standard Mode (标准模式, comfortable): Balanced 200px cards, 340px height, comfortable whitespace rhythm;
- Aesthetic Mode (沉浸模式): Subtle 8% grayscale ambient archive watermark with frosted glass borders;
diff --git a/web/modules/locales.js b/web/modules/locales.js
index 6c32677..fa7b36c 100644
--- a/web/modules/locales.js
+++ b/web/modules/locales.js
@@ -723,11 +723,23 @@ export const i18n = {
toolboxReady: '就绪',
toolboxHintFooter: '💡 持续扩展中:模型批量重整、孤立缓存清理、哈希重算等运维工具将在此聚合。',
toolOrphanCleanerTitle: '孤立缓存与临时文件清理',
+ toolOrphanCleanerShort: '缓存清理',
toolOrphanCleanerDesc: '扫描并清理已删除模型的未引用缩略图缓存与临时残余文件。',
toolBatchRenameTitle: '批量命名与标签重整',
+ toolBatchRenameShort: '批量重整',
toolBatchRenameDesc: '对指定目录下的模型批量规范命名规则或批量附加分类标签。',
toolCivitaiJumpTitle: 'Civitai 页面一键直达',
+ toolCivitaiJumpShort: 'Civitai',
toolCivitaiJumpDesc: '根据模型 SHA256 哈希或名称直接在浏览器打开对应发布页。',
+ toolHashRecalcTitle: '哈希快查',
+ toolHashRecalcShort: '哈希快查',
+ toolHashRecalcDesc: '快速计算并校验模型文件的 SHA256 哈希值。',
+ toolFormatConvertTitle: '格式转换',
+ toolFormatConvertShort: '格式转换',
+ toolFormatConvertDesc: '模型权重的 FP8/FP16 精度或格式互转辅助工具。',
+ toolCustomScriptsTitle: '扩展脚本',
+ toolCustomScriptsShort: '扩展脚本',
+ toolCustomScriptsDesc: '通过开放接口注册并执行自定义 Python / JS 运维动作。',
sidebarInjectHash: '🟢 注入工作流哈希',
sidebarSkipHash: '⚪ 不注入工作流哈希',
sidebarManageFolders: '文件夹管理',
@@ -775,7 +787,7 @@ export const i18n = {
closeSettings: '✖ 关闭设置面板',
doctorBtn: '节点助手',
importBtn: '导入 / 导出工作流 (分享码)',
- recipeTitle: '工作流配方',
+ recipeTitle: '工作流',
recipeBetaNotice: '工作流配方仍在测试。更新插件以及导入、恢复、删除或应用参数前,请保存当前画布并备份用户 workflows 目录中的 anomalous_recipes 与 anomalous_parameters。',
recipeClose: '关闭工作流配方',
recipeSaveCurrent: '保存当前工作流',
@@ -1801,11 +1813,23 @@ export const i18n = {
toolboxReady: 'Ready',
toolboxHintFooter: '💡 Expanding: Batch organizer, orphan cache cleaner, and hash recalculation tools will be hosted here.',
toolOrphanCleanerTitle: 'Orphan Cache & Temp Cleaner',
+ toolOrphanCleanerShort: 'Cache Clean',
toolOrphanCleanerDesc: 'Scan and remove unreferenced thumbnails and temporary files for deleted models.',
toolBatchRenameTitle: 'Batch Rename & Tagging',
+ toolBatchRenameShort: 'Batch Rename',
toolBatchRenameDesc: 'Standardize model filenames or batch-assign taxonomy tags to folders.',
toolCivitaiJumpTitle: 'Civitai Quick Jump',
+ toolCivitaiJumpShort: 'Civitai',
toolCivitaiJumpDesc: 'Quickly open official model release pages in browser by SHA256 hash or title.',
+ toolHashRecalcTitle: 'Hash Check',
+ toolHashRecalcShort: 'Hash Check',
+ toolHashRecalcDesc: 'Quickly compute and verify model file SHA256 hash.',
+ toolFormatConvertTitle: 'Format Convert',
+ toolFormatConvertShort: 'Convert',
+ toolFormatConvertDesc: 'Helper tools for model FP8/FP16 precision and format conversion.',
+ toolCustomScriptsTitle: 'Custom Scripts',
+ toolCustomScriptsShort: 'Scripts',
+ toolCustomScriptsDesc: 'Register and run custom Python / JS maintenance scripts via API.',
sidebarInjectHash: '🟢 Inject Workflow Hash',
sidebarSkipHash: '⚪ Skip Workflow Hash',
sidebarManageFolders: 'Manage Folders',
@@ -1853,7 +1877,7 @@ export const i18n = {
closeSettings: '✖ Close Settings',
doctorBtn: 'Node Assistant',
importBtn: 'Import / Export Workflow (Share Code)',
- recipeTitle: 'Workflow Recipes',
+ recipeTitle: 'Workflows',
recipeBetaNotice: 'Workflow Recipes are still in beta. Before updating the plugin or importing, restoring, deleting, or applying parameters, save the canvas and back up anomalous_recipes and anomalous_parameters under your user workflows directory.',
recipeClose: 'Close Workflow Recipes',
recipeSaveCurrent: 'Save Current Workflow',
diff --git a/web/modules/ui_grid.js b/web/modules/ui_grid.js
index 4e8da94..081e826 100644
--- a/web/modules/ui_grid.js
+++ b/web/modules/ui_grid.js
@@ -159,7 +159,7 @@ export async function loadModels() {
};
const applyBtn = document.createElement('button');
- applyBtn.innerHTML = ``;
+ applyBtn.innerHTML = ``;
applyBtn.className = 'anomalous-card-action-btn action-apply anomalous-tooltip-target';
applyBtn.removeAttribute('title');
applyBtn.setAttribute('data-tooltip', t('applyToCanvas'));
@@ -170,20 +170,8 @@ export async function loadModels() {
};
card.appendChild(applyBtn);
- const singleScanBtn = document.createElement('button');
- singleScanBtn.innerHTML = ``;
- singleScanBtn.className = 'anomalous-card-action-btn action-scan anomalous-tooltip-target';
- singleScanBtn.removeAttribute('title');
- singleScanBtn.setAttribute('data-tooltip', t('scanModelPrecisely'));
- singleScanBtn.setAttribute('data-tooltip-pos', 'bottom');
- singleScanBtn.onclick = (e) => {
- e.stopPropagation();
- createWizardModal(false, model.filename);
- };
- card.appendChild(singleScanBtn);
-
const editBtn = document.createElement('button');
- editBtn.innerHTML = ``;
+ editBtn.innerHTML = ``;
editBtn.className = 'anomalous-card-action-btn action-edit anomalous-tooltip-target';
editBtn.removeAttribute('title');
editBtn.setAttribute('data-tooltip', t('editModel'));
@@ -194,11 +182,17 @@ export async function loadModels() {
};
card.appendChild(editBtn);
- applyBtn.onclick = (e) => {
+ const singleScanBtn = document.createElement('button');
+ singleScanBtn.innerHTML = ``;
+ singleScanBtn.className = 'anomalous-card-action-btn action-scan anomalous-tooltip-target';
+ singleScanBtn.removeAttribute('title');
+ singleScanBtn.setAttribute('data-tooltip', t('scanModelPrecisely'));
+ singleScanBtn.setAttribute('data-tooltip-pos', 'bottom');
+ singleScanBtn.onclick = (e) => {
e.stopPropagation();
- this.applyModelToCanvas(this.currentType, this.currentSubfolder, model);
+ createWizardModal(false, model.filename);
};
- card.appendChild(applyBtn);
+ card.appendChild(singleScanBtn);
fragment.appendChild(card);
diff --git a/web/modules/ui_sidebar.js b/web/modules/ui_sidebar.js
index 68c3e60..f47d28f 100644
--- a/web/modules/ui_sidebar.js
+++ b/web/modules/ui_sidebar.js
@@ -1898,7 +1898,8 @@ export function createDOM() {
headerRow.style.display = 'flex';
headerRow.style.alignItems = 'center';
headerRow.style.justifyContent = 'space-between';
- headerRow.style.marginBottom = '2px';
+ headerRow.style.padding = '2px 4px 6px';
+ headerRow.style.borderBottom = '1px solid rgba(255, 255, 255, 0.06)';
const titleBox = document.createElement('div');
titleBox.style.display = 'flex';
@@ -1908,14 +1909,14 @@ export function createDOM() {
const titleText = document.createElement('span');
titleText.textContent = t('toolboxTitle');
titleText.style.fontWeight = '600';
- titleText.style.fontSize = '1.05em';
+ titleText.style.fontSize = '12px';
titleText.style.color = '#fff';
const betaBadge = document.createElement('span');
betaBadge.textContent = 'Hub';
- betaBadge.style.fontSize = '10px';
- betaBadge.style.padding = '1px 6px';
- betaBadge.style.borderRadius = '4px';
+ betaBadge.style.fontSize = '9px';
+ betaBadge.style.padding = '1px 5px';
+ betaBadge.style.borderRadius = '3px';
betaBadge.style.background = 'rgba(255, 255, 255, 0.08)';
betaBadge.style.color = '#a1a1aa';
betaBadge.style.fontWeight = '500';
@@ -1927,9 +1928,9 @@ export function createDOM() {
closeModalBtn.innerHTML = '×';
closeModalBtn.style.cursor = 'pointer';
closeModalBtn.style.color = '#888';
- closeModalBtn.style.fontSize = '18px';
+ closeModalBtn.style.fontSize = '16px';
closeModalBtn.style.lineHeight = '1';
- closeModalBtn.style.padding = '2px 6px';
+ closeModalBtn.style.padding = '2px 4px';
closeModalBtn.style.borderRadius = '4px';
closeModalBtn.onmouseover = () => { closeModalBtn.style.color = '#fff'; closeModalBtn.style.background = 'rgba(255,255,255,0.08)'; };
closeModalBtn.onmouseout = () => { closeModalBtn.style.color = '#888'; closeModalBtn.style.background = 'transparent'; };
@@ -1938,25 +1939,16 @@ export function createDOM() {
headerRow.appendChild(titleBox);
headerRow.appendChild(closeModalBtn);
- const subtitle = document.createElement('div');
- subtitle.textContent = t('toolboxSubtitle');
- subtitle.style.fontSize = '11px';
- subtitle.style.color = '#8a8d98';
- subtitle.style.marginBottom = '8px';
-
toolboxModal.appendChild(headerRow);
- toolboxModal.appendChild(subtitle);
- const itemsContainer = document.createElement('div');
- itemsContainer.className = 'anomalous-toolbox-items';
- itemsContainer.style.display = 'flex';
- itemsContainer.style.flexDirection = 'column';
- itemsContainer.style.gap = '8px';
+ const gridContainer = document.createElement('div');
+ gridContainer.className = 'anomalous-toolbox-grid';
const defaultTools = [
{
id: 'orphan-cleaner',
icon: '🧹',
+ shortTitle: t('toolOrphanCleanerShort'),
title: t('toolOrphanCleanerTitle'),
desc: t('toolOrphanCleanerDesc'),
badge: t('toolboxPlanned')
@@ -1964,6 +1956,7 @@ export function createDOM() {
{
id: 'batch-rename',
icon: '🏷️',
+ shortTitle: t('toolBatchRenameShort'),
title: t('toolBatchRenameTitle'),
desc: t('toolBatchRenameDesc'),
badge: t('toolboxPlanned')
@@ -1971,115 +1964,89 @@ export function createDOM() {
{
id: 'civitai-jump',
icon: '🌐',
+ shortTitle: t('toolCivitaiJumpShort'),
title: t('toolCivitaiJumpTitle'),
desc: t('toolCivitaiJumpDesc'),
badge: t('toolboxPlanned')
+ },
+ {
+ id: 'hash-recalc',
+ icon: '⚡',
+ shortTitle: t('toolHashRecalcShort'),
+ title: t('toolHashRecalcTitle'),
+ desc: t('toolHashRecalcDesc'),
+ badge: t('toolboxPlanned')
+ },
+ {
+ id: 'format-convert',
+ icon: '📦',
+ shortTitle: t('toolFormatConvertShort'),
+ title: t('toolFormatConvertTitle'),
+ desc: t('toolFormatConvertDesc'),
+ badge: t('toolboxPlanned')
+ },
+ {
+ id: 'custom-scripts',
+ icon: '🧩',
+ shortTitle: t('toolCustomScriptsShort'),
+ title: t('toolCustomScriptsTitle'),
+ desc: t('toolCustomScriptsDesc'),
+ badge: t('toolboxPlanned')
}
];
const allTools = [...defaultTools, ...(this.customToolboxItems || [])];
allTools.forEach(tool => {
- const card = document.createElement('div');
- card.className = 'anomalous-toolbox-card';
- card.style.display = 'flex';
- card.style.alignItems = 'flex-start';
- card.style.gap = '10px';
- card.style.padding = '9px 11px';
- card.style.background = 'rgba(255, 255, 255, 0.03)';
- card.style.border = '1px solid rgba(255, 255, 255, 0.06)';
- card.style.borderRadius = '8px';
- card.style.cursor = 'pointer';
- card.style.transition = 'all 0.15s ease';
-
- card.onmouseover = () => {
- card.style.background = 'rgba(255, 255, 255, 0.07)';
- card.style.borderColor = 'rgba(255, 255, 255, 0.15)';
- };
- card.onmouseout = () => {
- card.style.background = 'rgba(255, 255, 255, 0.03)';
- card.style.borderColor = 'rgba(255, 255, 255, 0.06)';
- };
- if (tool.action) {
- card.onclick = (e) => {
- e.stopPropagation();
- tool.action();
- };
- }
-
- const iconBox = document.createElement('div');
- iconBox.style.width = '26px';
- iconBox.style.height = '26px';
- iconBox.style.borderRadius = '6px';
- iconBox.style.background = 'rgba(255, 255, 255, 0.05)';
- iconBox.style.display = 'flex';
- iconBox.style.alignItems = 'center';
- iconBox.style.justifyContent = 'center';
- iconBox.style.fontSize = '14px';
- iconBox.style.flexShrink = '0';
- iconBox.innerText = tool.icon;
-
- const textCol = document.createElement('div');
- textCol.style.flex = '1';
- textCol.style.minWidth = '0';
-
- const topRow = document.createElement('div');
- topRow.style.display = 'flex';
- topRow.style.alignItems = 'center';
- topRow.style.justifyContent = 'space-between';
- topRow.style.gap = '6px';
-
- const cTitle = document.createElement('div');
- cTitle.textContent = tool.title;
- cTitle.style.fontWeight = '500';
- cTitle.style.fontSize = '12px';
- cTitle.style.color = '#e4e4e7';
- cTitle.style.whiteSpace = 'nowrap';
- cTitle.style.overflow = 'hidden';
- cTitle.style.textOverflow = 'ellipsis';
-
- topRow.appendChild(cTitle);
+ const tile = document.createElement('div');
+ tile.className = 'anomalous-toolbox-tile anomalous-tooltip-target';
+ tile.setAttribute('data-tooltip', `${tool.title}\n${tool.desc || ''}`);
+ tile.setAttribute('data-tooltip-pos', 'top');
if (tool.badge) {
- const cBadge = document.createElement('span');
- cBadge.textContent = tool.badge;
- cBadge.style.fontSize = '10px';
- cBadge.style.padding = '0 5px';
- cBadge.style.borderRadius = '3px';
- cBadge.style.background = 'rgba(245, 158, 11, 0.12)';
- cBadge.style.color = '#f59e0b';
- cBadge.style.fontWeight = '500';
- cBadge.style.flexShrink = '0';
- topRow.appendChild(cBadge);
+ const dot = document.createElement('span');
+ dot.className = 'anomalous-toolbox-tile-dot';
+ tile.appendChild(dot);
}
- const cDesc = document.createElement('div');
- cDesc.textContent = tool.desc;
- cDesc.style.fontSize = '11px';
- cDesc.style.color = '#8a8d98';
- cDesc.style.lineHeight = '1.35';
- cDesc.style.marginTop = '2px';
+ const iconEl = document.createElement('div');
+ iconEl.className = 'anomalous-toolbox-tile-icon';
+ iconEl.innerText = tool.icon || '🔧';
+ tile.appendChild(iconEl);
- textCol.appendChild(topRow);
- textCol.appendChild(cDesc);
+ const labelEl = document.createElement('div');
+ labelEl.className = 'anomalous-toolbox-tile-label';
+ labelEl.textContent = tool.shortTitle || tool.title;
+ tile.appendChild(labelEl);
- card.appendChild(iconBox);
- card.appendChild(textCol);
- itemsContainer.appendChild(card);
+ tile.onclick = (e) => {
+ e.stopPropagation();
+ if (typeof tool.action === 'function') {
+ tool.action();
+ } else {
+ const alertMsg = window.anomalous_browser_lang === 'zh'
+ ? `【${tool.title}】功能正在规划整合中,敬请期待!`
+ : `[${tool.title}] is currently in development!`;
+ if (typeof window.anomalous_notify === 'function') {
+ window.anomalous_notify(alertMsg, 'info');
+ } else {
+ alert(alertMsg);
+ }
+ }
+ };
+
+ gridContainer.appendChild(tile);
});
- toolboxModal.appendChild(itemsContainer);
+ toolboxModal.appendChild(gridContainer);
const hintFooter = document.createElement('div');
- hintFooter.textContent = t('toolboxHintFooter');
- hintFooter.style.fontSize = '10.5px';
+ hintFooter.textContent = window.anomalous_browser_lang === 'zh' ? '💡 实用运维工具持续扩充中' : '💡 Utility toolset expanding...';
+ hintFooter.style.fontSize = '10px';
hintFooter.style.color = '#71717a';
- hintFooter.style.lineHeight = '1.4';
- hintFooter.style.background = 'rgba(255, 255, 255, 0.02)';
- hintFooter.style.border = '1px dashed rgba(255, 255, 255, 0.08)';
- hintFooter.style.padding = '7px 9px';
- hintFooter.style.borderRadius = '6px';
- hintFooter.style.marginTop = '4px';
+ hintFooter.style.textAlign = 'center';
+ hintFooter.style.padding = '4px 2px 0';
+ hintFooter.style.borderTop = '1px solid rgba(255, 255, 255, 0.05)';
toolboxModal.appendChild(hintFooter);
};
diff --git a/web/styles.css b/web/styles.css
index c329c2a..71baaa9 100644
--- a/web/styles.css
+++ b/web/styles.css
@@ -566,10 +566,13 @@ html:not(.anomalous-floating-entry-enabled) [data-setting-id="Anomalous.ModelBro
#anomalous-container:not(.view-mode-standard):not(.view-mode-aesthetic) .anomalous-card-badge {
top: 6px !important;
left: 6px !important;
- max-width: 65px !important;
+ max-width: 55px !important;
font-size: 0.65em !important;
padding: 1px 4px !important;
border-radius: 3px !important;
+ white-space: nowrap !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
}
#anomalous-container.view-mode-compact .anomalous-card-action-btn,
@@ -586,13 +589,13 @@ html:not(.anomalous-floating-entry-enabled) [data-setting-id="Anomalous.ModelBro
right: 6px !important;
}
-#anomalous-container.view-mode-compact .anomalous-card-action-btn.action-scan,
-#anomalous-container:not(.view-mode-standard):not(.view-mode-aesthetic) .anomalous-card-action-btn.action-scan {
+#anomalous-container.view-mode-compact .anomalous-card-action-btn.action-edit,
+#anomalous-container:not(.view-mode-standard):not(.view-mode-aesthetic) .anomalous-card-action-btn.action-edit {
right: 32px !important;
}
-#anomalous-container.view-mode-compact .anomalous-card-action-btn.action-edit,
-#anomalous-container:not(.view-mode-standard):not(.view-mode-aesthetic) .anomalous-card-action-btn.action-edit {
+#anomalous-container.view-mode-compact .anomalous-card-action-btn.action-scan,
+#anomalous-container:not(.view-mode-standard):not(.view-mode-aesthetic) .anomalous-card-action-btn.action-scan {
right: 58px !important;
}
@@ -773,11 +776,11 @@ html:not(.anomalous-floating-entry-enabled) [data-setting-id="Anomalous.ModelBro
right: 8px;
}
-.anomalous-card-action-btn.action-scan {
+.anomalous-card-action-btn.action-edit {
right: 42px;
}
-.anomalous-card-action-btn.action-edit {
+.anomalous-card-action-btn.action-scan {
right: 76px;
}
@@ -1028,28 +1031,96 @@ html:not(.anomalous-floating-entry-enabled) [data-setting-id="Anomalous.ModelBro
#anomalous-toolbox-modal {
position: absolute;
- bottom: 16px;
- left: 266px;
- width: 310px;
- max-height: calc(100% - 32px);
+ bottom: 50px;
+ left: 10px;
+ width: 232px;
+ max-height: calc(100% - 64px);
overflow-y: auto;
box-sizing: border-box;
- background: rgba(24, 24, 28, 0.98);
+ background: rgba(22, 22, 26, 0.98);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 10px;
- padding: 14px;
- box-shadow: 0 16px 48px rgba(0, 0, 0, 0.85), 0 0 0 1px rgba(255, 255, 255, 0.05);
+ padding: 10px;
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.85), 0 0 0 1px rgba(255, 255, 255, 0.05);
z-index: 999999 !important;
- transition: left 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
+ transition: left 0.25s cubic-bezier(0.2, 0.8, 0.2, 1), bottom 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
display: none;
flex-direction: column;
- gap: 6px;
+ gap: 8px;
}
.anomalous-sidebar-closed #anomalous-toolbox-modal {
- left: 72px !important;
+ left: 68px !important;
+ bottom: 12px !important;
+}
+
+.anomalous-toolbox-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 6px;
+ margin: 2px 0 4px;
+}
+
+.anomalous-toolbox-tile {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ padding: 9px 4px 7px;
+ min-height: 58px;
+ box-sizing: border-box;
+ background: rgba(255, 255, 255, 0.035);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ border-radius: 8px;
+ cursor: pointer;
+ position: relative;
+ user-select: none;
+ transition: all 0.15s cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.anomalous-toolbox-tile:hover {
+ background: rgba(255, 255, 255, 0.08);
+ border-color: rgba(255, 255, 255, 0.18);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
+}
+
+.anomalous-toolbox-tile:active {
+ transform: scale(0.96);
+}
+
+.anomalous-toolbox-tile-icon {
+ font-size: 18px;
+ line-height: 1;
+ margin-bottom: 5px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.anomalous-toolbox-tile-label {
+ font-size: 11px;
+ font-weight: 500;
+ color: #d4d4d8;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100%;
+ line-height: 1.2;
+}
+
+.anomalous-toolbox-tile-dot {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ background: #f59e0b;
+ box-shadow: 0 0 4px rgba(245, 158, 11, 0.6);
}
.anomalous-sidebar-closed #anomalous-sidebar-actions {