fix(entry): relocate floating trigger to top-left safe canvas area and auto-heal sidebar occlusion
This commit is contained in:
+2
-2
@@ -92,8 +92,8 @@ DOM or live LiteGraph state.
|
||||
browser class and extracted-method wiring; `browser_entry.js` owns the single
|
||||
browser instance plus floating/topbar/menu entry behavior; `entry_controls.js`
|
||||
owns entry mode, trigger sizing/styling normalization, viewport-safe boundary
|
||||
clamping (`clampFloatingTriggerPosition`), and legacy top-left auto-healing
|
||||
(`isValidSavedTriggerPosition`); and `interface_settings.js` owns language and theme preferences.
|
||||
clamping (`clampFloatingTriggerPosition`), and toolbar occlusion auto-healing
|
||||
(`isValidSavedTriggerPosition`, `normalizeSavedTriggerPosition`); and `interface_settings.js` owns language and theme preferences.
|
||||
- `ui_domain_switcher.js` owns the dual-domain mode toggle (Visual Studio 🎨 vs Audio & Voice Studio 🎙️) embedded in the brand header.
|
||||
- `ui_audio_studio.js` owns the Audio & Voice Studio workspace, presenting character voice cards, emotion slice playback, prompt syntax copying, real-time search, animated equalizers, and canvas drag-and-drop.
|
||||
- `ui_audio_sidebar.js` owns the Audio Sidebar navigation, rendering trees for All Voices, Character Presets (e.g. Arona) with count badges, and Output History Vault.
|
||||
|
||||
@@ -23,12 +23,14 @@ the real ComfyUI runtime creates the configured entry. Floating trigger styling
|
||||
the ordered stylesheet bundle rooted at `web/styles.css` uses dynamic `1em` SVG
|
||||
scaling and flex centering to guarantee
|
||||
consistent visual presentation across all configured trigger sizes. By default, the
|
||||
floating trigger button is positioned via pure responsive CSS (`bottom: 30px; right: 30px;`)
|
||||
floating trigger button is positioned via pure responsive CSS (`top: 60px; left: 60px;`),
|
||||
leaving comfortable 12px margins from both the ComfyUI left sidebar (~48px) and topbar (~48px)
|
||||
without inline left/top overrides. `browser_entry.js` strictly distinguishes clicks from
|
||||
drags (threshold: 5px) to prevent accidental persistence, while `entry_controls.js`
|
||||
provides robust boundary clamping (`clampFloatingTriggerPosition`) with safe viewport
|
||||
fallbacks (1024x768) and automatic healing of legacy collapsed top-left coordinates
|
||||
(`isValidSavedTriggerPosition`). Resetting trigger position cleanly restores default CSS positioning.
|
||||
fallbacks (1024x768) and automatic healing of legacy or accidental toolbar/sidebar
|
||||
occlusion coordinates (`isValidSavedTriggerPosition`, `normalizeSavedTriggerPosition`).
|
||||
Resetting trigger position cleanly restores default CSS positioning.
|
||||
|
||||
Major UI panels live in `web/modules/ui_*.js`. Shared browser state remains on
|
||||
the `AnomalousBrowser` instance. Pure parsing, normalization, comparison, and
|
||||
|
||||
@@ -2,10 +2,12 @@ import { app } from '../../../scripts/app.js';
|
||||
import { AnomalousBrowser } from './browser.js';
|
||||
import {
|
||||
clampFloatingTriggerPosition,
|
||||
DEFAULT_TRIGGER_POSITION,
|
||||
isValidSavedTriggerPosition,
|
||||
normalizeEntryMode,
|
||||
normalizeFloatingTriggerSize,
|
||||
normalizeFloatingTriggerStyle
|
||||
normalizeFloatingTriggerStyle,
|
||||
normalizeSavedTriggerPosition
|
||||
} from './entry_controls.js';
|
||||
import {
|
||||
createShortcutSettingControl,
|
||||
@@ -304,8 +306,13 @@ export function createBrowserEntry({ translate, getCurrentLanguage }) {
|
||||
isDragging = false;
|
||||
btn.style.transition = 'transform 0.15s, box-shadow 0.15s';
|
||||
if (hasMoved) {
|
||||
localStorage.setItem('anomalous_btn_x', btn.style.left);
|
||||
localStorage.setItem('anomalous_btn_y', btn.style.top);
|
||||
const norm = normalizeSavedTriggerPosition(btn.style.left, btn.style.top);
|
||||
if (norm) {
|
||||
btn.style.left = norm.x + 'px';
|
||||
btn.style.top = norm.y + 'px';
|
||||
localStorage.setItem('anomalous_btn_x', btn.style.left);
|
||||
localStorage.setItem('anomalous_btn_y', btn.style.top);
|
||||
}
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
@@ -314,7 +321,8 @@ export function createBrowserEntry({ translate, getCurrentLanguage }) {
|
||||
const updateBtnBounds = () => {
|
||||
const savedX = localStorage.getItem('anomalous_btn_x');
|
||||
const savedY = localStorage.getItem('anomalous_btn_y');
|
||||
if (!isValidSavedTriggerPosition(savedX, savedY)) {
|
||||
const norm = normalizeSavedTriggerPosition(savedX, savedY);
|
||||
if (!norm) {
|
||||
btn.style.left = '';
|
||||
btn.style.top = '';
|
||||
btn.style.right = '';
|
||||
@@ -322,8 +330,8 @@ export function createBrowserEntry({ translate, getCurrentLanguage }) {
|
||||
return;
|
||||
}
|
||||
const position = clampFloatingTriggerPosition({
|
||||
x: btn.style.left || savedX,
|
||||
y: btn.style.top || savedY,
|
||||
x: btn.style.left || (norm.x + 'px'),
|
||||
y: btn.style.top || (norm.y + 'px'),
|
||||
width: btn.offsetWidth,
|
||||
height: btn.offsetHeight,
|
||||
viewportWidth: window.innerWidth,
|
||||
@@ -338,11 +346,14 @@ export function createBrowserEntry({ translate, getCurrentLanguage }) {
|
||||
|
||||
const initialSavedX = localStorage.getItem('anomalous_btn_x');
|
||||
const initialSavedY = localStorage.getItem('anomalous_btn_y');
|
||||
if (isValidSavedTriggerPosition(initialSavedX, initialSavedY)) {
|
||||
const initialNorm = normalizeSavedTriggerPosition(initialSavedX, initialSavedY);
|
||||
if (initialNorm) {
|
||||
btn.style.right = 'auto';
|
||||
btn.style.bottom = 'auto';
|
||||
btn.style.left = initialSavedX;
|
||||
btn.style.top = initialSavedY;
|
||||
btn.style.left = initialNorm.x + 'px';
|
||||
btn.style.top = initialNorm.y + 'px';
|
||||
localStorage.setItem('anomalous_btn_x', btn.style.left);
|
||||
localStorage.setItem('anomalous_btn_y', btn.style.top);
|
||||
setTimeout(updateBtnBounds, 200);
|
||||
} else {
|
||||
localStorage.removeItem('anomalous_btn_x');
|
||||
@@ -355,7 +366,7 @@ export function createBrowserEntry({ translate, getCurrentLanguage }) {
|
||||
window.addEventListener('resize', () => {
|
||||
const curX = localStorage.getItem('anomalous_btn_x');
|
||||
const curY = localStorage.getItem('anomalous_btn_y');
|
||||
if (isValidSavedTriggerPosition(curX, curY)) {
|
||||
if (normalizeSavedTriggerPosition(curX, curY)) {
|
||||
updateBtnBounds();
|
||||
}
|
||||
syncVisibility();
|
||||
|
||||
@@ -14,6 +14,8 @@ export function normalizeEntryMode(value) {
|
||||
return ENTRY_MODES.has(value) ? value : 'floating';
|
||||
}
|
||||
|
||||
export const DEFAULT_TRIGGER_POSITION = Object.freeze({ x: 60, y: 60 });
|
||||
|
||||
export function isValidSavedTriggerPosition(x, y) {
|
||||
if (x == null || y == null) return false;
|
||||
const px = Number.parseFloat(x);
|
||||
@@ -24,6 +26,23 @@ export function isValidSavedTriggerPosition(x, y) {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeSavedTriggerPosition(x, y) {
|
||||
if (x == null || y == null) return null;
|
||||
let px = Number.parseFloat(x);
|
||||
let py = Number.parseFloat(y);
|
||||
if (!Number.isFinite(px) || !Number.isFinite(py)) return null;
|
||||
if (px < 10 && py < 10) return null;
|
||||
// Auto-adjust away from left sidebar occlusion zone (sidebar width is ~48px)
|
||||
if (px < 56 && py < 300) {
|
||||
px = DEFAULT_TRIGGER_POSITION.x;
|
||||
}
|
||||
// Auto-adjust away from topbar occlusion zone (topbar height is ~48px)
|
||||
if (py < 52 && px < 400) {
|
||||
py = DEFAULT_TRIGGER_POSITION.y;
|
||||
}
|
||||
return { x: px, y: py };
|
||||
}
|
||||
|
||||
export function clampFloatingTriggerPosition({
|
||||
x,
|
||||
y,
|
||||
@@ -39,8 +58,8 @@ export function clampFloatingTriggerPosition({
|
||||
const safeVh = Math.max(safeHeight + margin, Number(viewportHeight) || (typeof window !== 'undefined' ? window.innerHeight : 768) || 768);
|
||||
const maxX = Math.max(0, safeVw - safeWidth);
|
||||
const maxY = Math.max(0, safeVh - safeHeight);
|
||||
const fallbackX = Math.max(0, maxX - margin);
|
||||
const fallbackY = Math.max(0, maxY - margin);
|
||||
const fallbackX = DEFAULT_TRIGGER_POSITION.x;
|
||||
const fallbackY = DEFAULT_TRIGGER_POSITION.y;
|
||||
const parsedX = Number.parseFloat(x);
|
||||
const parsedY = Number.parseFloat(y);
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ html.theme-abyssal-scarlet,
|
||||
--anomalous-trigger-font-size: 28px;
|
||||
--anomalous-trigger-pill-padding: 18px;
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
top: 60px;
|
||||
left: 60px;
|
||||
width: var(--anomalous-trigger-size);
|
||||
height: var(--anomalous-trigger-size);
|
||||
border-radius: 50%;
|
||||
|
||||
Reference in New Issue
Block a user