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 {