mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-05 02:45:28 +00:00
Merge b007a4d8e9 into 20e7fc0164
This commit is contained in:
commit
e3a27344ba
2 changed files with 407 additions and 59 deletions
|
|
@ -23,6 +23,7 @@ const MIN_CHAT_WIDTH = 380;
|
|||
const EMAIL_DOC_SPLIT_WIDTH_KEY = 'odysseus-email-doc-split-width';
|
||||
const EDGE_DOCK_WIDTH_KEY_PREFIX = 'odysseus-edge-dock-width';
|
||||
const MIN_EDGE_DOCK_WIDTH = 320;
|
||||
const EDGE_DOCK_SWITCHER_FLAG = 'odysseus-edge-dock-switcher';
|
||||
|
||||
let _edgeDockHandlePositioner = null;
|
||||
|
||||
|
|
@ -30,10 +31,111 @@ function _positionEdgeDockResizeHandles() {
|
|||
try { _edgeDockHandlePositioner && _edgeDockHandlePositioner(); } catch (_) {}
|
||||
}
|
||||
|
||||
function _notifyEdgeDockChanged(side, owner = null) {
|
||||
try {
|
||||
window.dispatchEvent(new CustomEvent('odysseus:edge-dock-changed', {
|
||||
detail: { side, owner },
|
||||
}));
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
function _dockClassForSide(side) {
|
||||
return side === 'left' ? 'modal-left-docked' : 'modal-right-docked';
|
||||
}
|
||||
|
||||
function _dockOwnerSurface(owner) {
|
||||
return owner?.closest?.('.notes-pane-backdrop') || owner;
|
||||
}
|
||||
|
||||
function _zIndexForElement(el, fallback = 250) {
|
||||
const raw = el ? window.getComputedStyle(el).zIndex : '';
|
||||
const n = parseInt(raw, 10);
|
||||
return Number.isFinite(n) ? n : fallback;
|
||||
}
|
||||
|
||||
function _isUsableDockOwner(owner) {
|
||||
if (!owner || !owner.isConnected) return false;
|
||||
if (owner.classList?.contains('hidden')) return false;
|
||||
if (owner.classList?.contains('modal-minimized')) return false;
|
||||
if (owner.style?.display === 'none') return false;
|
||||
const content = _resolveDockNodes(owner)?.content;
|
||||
if (!content || !content.isConnected) return false;
|
||||
if (content.classList?.contains('hidden')) return false;
|
||||
if (content.style?.display === 'none') return false;
|
||||
const r = content.getBoundingClientRect?.();
|
||||
return !!r && r.width > 0 && r.height > 0;
|
||||
}
|
||||
|
||||
function _dockOwnersForSide(side) {
|
||||
if (side !== 'left' && side !== 'right') return [];
|
||||
return Array.from(document.querySelectorAll(`.${_dockClassForSide(side)}`)).filter(_isUsableDockOwner);
|
||||
}
|
||||
|
||||
function _activeDockOwnerForSide(side) {
|
||||
let best = null;
|
||||
let bestZ = -Infinity;
|
||||
_dockOwnersForSide(side).forEach((owner) => {
|
||||
const z = _zIndexForElement(_dockOwnerSurface(owner), 250);
|
||||
if (z >= bestZ) {
|
||||
best = owner;
|
||||
bestZ = z;
|
||||
}
|
||||
});
|
||||
return best;
|
||||
}
|
||||
|
||||
function _applyDockWidthToOwner(owner, side, width, left = _leftNavRight()) {
|
||||
const content = _resolveDockNodes(owner)?.content;
|
||||
if (!content || !width) return;
|
||||
const w = Math.round(width);
|
||||
content._userDockWidth = w;
|
||||
if (side === 'right') {
|
||||
content.style.left = 'auto';
|
||||
content.style.right = '0';
|
||||
content.style.width = w + 'px';
|
||||
content.style.maxWidth = w + 'px';
|
||||
if (_shouldAutoCollapseSidebar(w)) {
|
||||
_collapseSidebarToRail();
|
||||
if (content._preDockSnapshot) content._preDockSnapshot.collapsedSidebar = true;
|
||||
}
|
||||
} else {
|
||||
content._emailDocSplitUserW = w;
|
||||
content.style.left = left + 'px';
|
||||
content.style.right = 'auto';
|
||||
content.style.width = w + 'px';
|
||||
content.style.maxWidth = w + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
function _syncDockSideWidth(side, requestedWidth, owners = _dockOwnersForSide(side)) {
|
||||
if (side !== 'left' && side !== 'right') return 0;
|
||||
if (!owners.length) return 0;
|
||||
if (side === 'left'
|
||||
&& document.body.classList.contains('email-doc-split-active')
|
||||
&& document.body.classList.contains('doc-view')) {
|
||||
_positionEdgeDockResizeHandles();
|
||||
return requestedWidth || _activeDockWidth(side);
|
||||
}
|
||||
let w = 0;
|
||||
if (side === 'right') {
|
||||
w = _clampRightDockWidth(requestedWidth || _activeDockWidth('right') || _defaultDockWidth());
|
||||
document.body.classList.add('right-dock-active');
|
||||
document.documentElement.style.setProperty('--right-dock-w', w + 'px');
|
||||
owners.forEach((owner) => _applyDockWidthToOwner(owner, side, w));
|
||||
} else {
|
||||
const left = _leftNavRight();
|
||||
w = _clampLeftDockWidth(requestedWidth || _activeDockWidth('left') || _defaultDockWidth(), left);
|
||||
document.body.classList.add('left-dock-active');
|
||||
document.documentElement.style.setProperty(
|
||||
'--left-dock-w',
|
||||
document.body.classList.contains('email-doc-split-active') ? '0px' : w + 'px',
|
||||
);
|
||||
owners.forEach((owner) => _applyDockWidthToOwner(owner, side, w, left));
|
||||
}
|
||||
_positionEdgeDockResizeHandles();
|
||||
return w;
|
||||
}
|
||||
|
||||
function _hasOtherDockedWindow(side, owner) {
|
||||
const cls = _dockClassForSide(side);
|
||||
return Array.from(document.querySelectorAll(`.${cls}`)).some((el) => {
|
||||
|
|
@ -347,6 +449,7 @@ function _applyDockInternal(modal, side, dockClass) {
|
|||
if (!nodes) return 0;
|
||||
const content = nodes.content;
|
||||
if (!content) return 0;
|
||||
const existingSideWidth = _hasOtherDockedWindow(side, modal) ? _activeDockWidth(side) : 0;
|
||||
// If the modal is currently docked on the OTHER side (e.g. the user
|
||||
// manually docked it right, then a reply re-docks it left), clear that
|
||||
// side's class + body push first. Otherwise both sides' state coexist —
|
||||
|
|
@ -509,7 +612,13 @@ function _applyDockInternal(modal, side, dockClass) {
|
|||
}
|
||||
content._dockSide = side;
|
||||
content._dockOwner = modal;
|
||||
_positionEdgeDockResizeHandles();
|
||||
const sideOwners = _dockOwnersForSide(side);
|
||||
if (sideOwners.length > 1) {
|
||||
const syncedWidth = _syncDockSideWidth(side, existingSideWidth || w, sideOwners);
|
||||
if (syncedWidth) w = syncedWidth;
|
||||
} else {
|
||||
_positionEdgeDockResizeHandles();
|
||||
}
|
||||
// Watch for the docked modal disappearing (removed from DOM or hidden
|
||||
// via .hidden class) and clean up the body padding + sidebar in that
|
||||
// case. Without this, closing a docked window leaves a phantom strip
|
||||
|
|
@ -539,6 +648,7 @@ function _applyDockInternal(modal, side, dockClass) {
|
|||
modal._dockCloseWatcher = { obs };
|
||||
}
|
||||
}
|
||||
_notifyEdgeDockChanged(side, modal);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
@ -571,6 +681,8 @@ function _onDockedModalGone(modal, dockClass) {
|
|||
}
|
||||
modal.classList.remove('modal-right-docked');
|
||||
modal.classList.remove('modal-left-docked');
|
||||
if (hadRight) _notifyEdgeDockChanged('right', modal);
|
||||
if (hadLeft) _notifyEdgeDockChanged('left', modal);
|
||||
// Clear the content's docked inline geometry. Singleton modals (plan,
|
||||
// workspace, calendar, …) reuse the same element across open/close, so if we
|
||||
// only drop the body push the element stays positioned (position:fixed;
|
||||
|
|
@ -666,6 +778,7 @@ export function clearRightDock(modal, cx, cy, dockClass) {
|
|||
delete content._preDockSnapshot;
|
||||
delete content._dockSuspended;
|
||||
_positionEdgeDockResizeHandles();
|
||||
_notifyEdgeDockChanged(side, modal);
|
||||
}
|
||||
|
||||
// Temporarily release a docked modal's body push (chat returns to full
|
||||
|
|
@ -711,6 +824,7 @@ export function suspendDock(modal) {
|
|||
}
|
||||
content._dockSuspended = side;
|
||||
_positionEdgeDockResizeHandles();
|
||||
_notifyEdgeDockChanged(side, modal);
|
||||
return side;
|
||||
}
|
||||
|
||||
|
|
@ -785,6 +899,200 @@ export function makeEdgeDockController(modal, side = 'right', dockClass) {
|
|||
};
|
||||
}
|
||||
|
||||
(function _initEdgeDockSwitcher() {
|
||||
if (typeof document === 'undefined' || typeof window === 'undefined') return;
|
||||
|
||||
const bars = { left: null, right: null };
|
||||
let refreshTimer = 0;
|
||||
let refreshInterval = 0;
|
||||
|
||||
const _enabled = () => {
|
||||
try { return localStorage.getItem(EDGE_DOCK_SWITCHER_FLAG) !== '0'; }
|
||||
catch (_) { return true; }
|
||||
};
|
||||
|
||||
const _ownerSurface = _dockOwnerSurface;
|
||||
|
||||
const _topToolZ = (exclude = null) => {
|
||||
const skip = new Set([exclude, _ownerSurface(exclude)].filter(Boolean));
|
||||
let top = 300;
|
||||
document.querySelectorAll('.modal, .research-overlay, .notes-pane-backdrop').forEach((el) => {
|
||||
if (!el || skip.has(el)) return;
|
||||
if (el.classList?.contains('hidden')) return;
|
||||
if (el.style?.display === 'none') return;
|
||||
top = Math.max(top, _zIndexForElement(el, 250));
|
||||
});
|
||||
return top;
|
||||
};
|
||||
|
||||
const _bringOwnerToFront = (owner) => {
|
||||
const surface = _ownerSurface(owner);
|
||||
if (!surface) return;
|
||||
surface.style.setProperty('z-index', String(_topToolZ(owner) + 1), 'important');
|
||||
try {
|
||||
window.dispatchEvent(new CustomEvent('odysseus:modal-opened', {
|
||||
detail: { id: owner?.id || '', modal: owner },
|
||||
}));
|
||||
} catch (_) {}
|
||||
};
|
||||
|
||||
const _simpleTitleForOwner = (owner) => {
|
||||
const id = owner?.id || '';
|
||||
const labels = {
|
||||
'assistant-settings-modal': 'Assistant',
|
||||
'calendar-modal': 'Calendar',
|
||||
'compare-model-overlay': 'Compare',
|
||||
'cookbook-modal': 'Cookbook',
|
||||
'doc-editor-pane': 'Document',
|
||||
'doclib-modal': 'Library',
|
||||
'email-lib-modal': 'Email',
|
||||
'gallery-modal': 'Gallery',
|
||||
'library-modal': 'Library',
|
||||
'notes-pane': 'Notes',
|
||||
'research-overlay': 'Deep Research',
|
||||
'research-pane': 'Deep Research',
|
||||
'settings-modal': 'Settings',
|
||||
'tasks-modal': 'Tasks',
|
||||
};
|
||||
return labels[id] || '';
|
||||
};
|
||||
|
||||
const _cleanTabLabel = (label) => (label || '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/\s+\d+\s+(photos?|research|tasks?|notes?|documents?|docs?|items?|emails?|chats?|sessions?|models?)$/i, '')
|
||||
.trim();
|
||||
|
||||
const _labelForOwner = (owner) => {
|
||||
const simple = _simpleTitleForOwner(owner);
|
||||
if (simple) return simple;
|
||||
const content = _resolveDockNodes(owner)?.content || owner;
|
||||
const titleEl = content?.querySelector?.('.modal-header h4, .notes-pane-title, .modal-title, [data-window-title]');
|
||||
const text = _cleanTabLabel(titleEl?.textContent || owner?.getAttribute?.('aria-label') || owner?.id || 'Window');
|
||||
return text || 'Window';
|
||||
};
|
||||
|
||||
const _activeOwner = (owners) => {
|
||||
let best = null;
|
||||
let bestZ = -Infinity;
|
||||
owners.forEach((owner) => {
|
||||
const z = _zIndexForElement(_ownerSurface(owner), 250);
|
||||
if (z >= bestZ) {
|
||||
best = owner;
|
||||
bestZ = z;
|
||||
}
|
||||
});
|
||||
return best || owners[owners.length - 1] || null;
|
||||
};
|
||||
|
||||
const _hideBar = (side) => {
|
||||
const bar = bars[side];
|
||||
if (!bar) return;
|
||||
bar.replaceChildren();
|
||||
bar.hidden = true;
|
||||
bar.parentElement?.classList?.remove('edge-dock-switcher-host');
|
||||
};
|
||||
|
||||
const _ensureBar = (side) => {
|
||||
if (!bars[side]?.isConnected) {
|
||||
const bar = document.createElement('div');
|
||||
bar.className = `edge-dock-switcher edge-dock-switcher-${side}`;
|
||||
bar.hidden = true;
|
||||
bar.setAttribute('role', 'tablist');
|
||||
bar.setAttribute('aria-label', `${side} docked windows`);
|
||||
bar.addEventListener('pointerdown', (event) => event.stopPropagation());
|
||||
bar.addEventListener('mousedown', (event) => event.stopPropagation());
|
||||
bar.addEventListener('touchstart', (event) => event.stopPropagation(), { passive: true });
|
||||
bars[side] = bar;
|
||||
}
|
||||
const oldParent = bars[side]?.parentElement;
|
||||
if (oldParent && oldParent !== document.body) oldParent.classList.remove('edge-dock-switcher-host');
|
||||
if (bars[side].parentElement !== document.body) document.body.appendChild(bars[side]);
|
||||
return bars[side];
|
||||
};
|
||||
|
||||
const _renderSide = (side) => {
|
||||
const owners = _enabled() && window.innerWidth > 768 ? _dockOwnersForSide(side) : [];
|
||||
if (owners.length < 2) {
|
||||
_hideBar(side);
|
||||
return;
|
||||
}
|
||||
const active = _activeOwner(owners);
|
||||
const bar = _ensureBar(side);
|
||||
bar.replaceChildren();
|
||||
owners.forEach((owner) => {
|
||||
const label = _labelForOwner(owner);
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = `edge-dock-switcher-tab${owner === active ? ' active' : ''}`;
|
||||
btn.title = label;
|
||||
btn.setAttribute('role', 'tab');
|
||||
btn.setAttribute('aria-selected', owner === active ? 'true' : 'false');
|
||||
btn.addEventListener('pointerdown', (event) => event.stopPropagation());
|
||||
btn.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
_bringOwnerToFront(owner);
|
||||
_scheduleRefresh(40);
|
||||
});
|
||||
const labelEl = document.createElement('span');
|
||||
labelEl.className = 'edge-dock-switcher-tab-label';
|
||||
labelEl.textContent = label;
|
||||
btn.appendChild(labelEl);
|
||||
bar.appendChild(btn);
|
||||
});
|
||||
bar.hidden = false;
|
||||
};
|
||||
|
||||
function _refresh() {
|
||||
if (!document.body) return;
|
||||
_renderSide('left');
|
||||
_renderSide('right');
|
||||
}
|
||||
|
||||
function _scheduleRefresh(delay = 180) {
|
||||
if (refreshTimer) clearTimeout(refreshTimer);
|
||||
refreshTimer = setTimeout(() => {
|
||||
refreshTimer = 0;
|
||||
requestAnimationFrame(_refresh);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
const _start = () => {
|
||||
_scheduleRefresh(0);
|
||||
window.addEventListener('resize', () => _scheduleRefresh(120));
|
||||
window.addEventListener('odysseus:modal-opened', () => _scheduleRefresh(120));
|
||||
window.addEventListener('odysseus:edge-dock-changed', () => _scheduleRefresh(320));
|
||||
document.addEventListener('keyup', (event) => {
|
||||
if (event.key === 'Escape') _scheduleRefresh(120);
|
||||
}, true);
|
||||
refreshInterval = window.setInterval(() => {
|
||||
if (document.visibilityState !== 'hidden') _refresh();
|
||||
}, 1500);
|
||||
window.odysseusEdgeDockSwitcher = {
|
||||
refresh: _refresh,
|
||||
disable() {
|
||||
try { localStorage.setItem(EDGE_DOCK_SWITCHER_FLAG, '0'); } catch (_) {}
|
||||
_refresh();
|
||||
},
|
||||
enable() {
|
||||
try { localStorage.removeItem(EDGE_DOCK_SWITCHER_FLAG); } catch (_) {}
|
||||
_refresh();
|
||||
},
|
||||
stop() {
|
||||
if (refreshInterval) window.clearInterval(refreshInterval);
|
||||
refreshInterval = 0;
|
||||
bars.left?.remove();
|
||||
bars.right?.remove();
|
||||
bars.left = null;
|
||||
bars.right = null;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
if (document.body) _start();
|
||||
else document.addEventListener('DOMContentLoaded', _start, { once: true });
|
||||
})();
|
||||
|
||||
(function _initEdgeDockResizeHandles() {
|
||||
if (typeof document === 'undefined') return;
|
||||
if (!document.body) {
|
||||
|
|
@ -820,33 +1128,7 @@ export function makeEdgeDockController(modal, side = 'right', dockClass) {
|
|||
document.body.appendChild(handle);
|
||||
}
|
||||
|
||||
const _isUsableDockOwner = (owner) => {
|
||||
if (!owner || !owner.isConnected) return false;
|
||||
if (owner.classList?.contains('hidden')) return false;
|
||||
if (owner.style?.display === 'none') return false;
|
||||
const nodes = _resolveDockNodes(owner);
|
||||
const content = nodes?.content;
|
||||
if (!content || !content.isConnected) return false;
|
||||
if (content.classList?.contains('hidden')) return false;
|
||||
if (content.style?.display === 'none') return false;
|
||||
const r = content.getBoundingClientRect();
|
||||
return r.width > 0 && r.height > 0;
|
||||
};
|
||||
|
||||
const _activeDockOwner = (side) => {
|
||||
const cls = _dockClassForSide(side);
|
||||
const all = Array.from(document.querySelectorAll(`.${cls}`));
|
||||
for (const owner of all.reverse()) {
|
||||
if (_isUsableDockOwner(owner)) return owner;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const _zIndexFor = (el, fallback = 250) => {
|
||||
const raw = el ? window.getComputedStyle(el).zIndex : '';
|
||||
const n = parseInt(raw, 10);
|
||||
return Number.isFinite(n) ? n : fallback;
|
||||
};
|
||||
const _activeDockOwner = (side) => _activeDockOwnerForSide(side);
|
||||
|
||||
const _hasVisibleFloatingModal = (owner) => {
|
||||
const all = Array.from(document.querySelectorAll('.modal:not(.hidden):not(.modal-minimized)'));
|
||||
|
|
@ -863,40 +1145,18 @@ export function makeEdgeDockController(modal, side = 'right', dockClass) {
|
|||
});
|
||||
};
|
||||
|
||||
const _setWidth = (owner, side, clientX) => {
|
||||
const nodes = _resolveDockNodes(owner);
|
||||
const content = nodes?.content;
|
||||
if (!content) return 0;
|
||||
const _setWidth = (owner, side, clientX, resizeOwners = null) => {
|
||||
const targets = (resizeOwners && resizeOwners.length) ? resizeOwners : [owner].filter(Boolean);
|
||||
if (!targets.length) return 0;
|
||||
let w = 0;
|
||||
if (side === 'right') {
|
||||
w = _clampRightDockWidth(window.innerWidth - clientX);
|
||||
content._userDockWidth = w;
|
||||
content.style.left = 'auto';
|
||||
content.style.right = '0';
|
||||
content.style.width = w + 'px';
|
||||
content.style.maxWidth = w + 'px';
|
||||
document.body.classList.add('right-dock-active');
|
||||
document.documentElement.style.setProperty('--right-dock-w', w + 'px');
|
||||
if (_shouldAutoCollapseSidebar(w)) {
|
||||
_collapseSidebarToRail();
|
||||
if (content._preDockSnapshot) content._preDockSnapshot.collapsedSidebar = true;
|
||||
}
|
||||
_syncDockSideWidth(side, w, targets);
|
||||
} else {
|
||||
const left = _leftNavRight();
|
||||
w = _clampLeftDockWidth(clientX - left, left);
|
||||
content._userDockWidth = w;
|
||||
content._emailDocSplitUserW = w;
|
||||
content.style.left = left + 'px';
|
||||
content.style.right = 'auto';
|
||||
content.style.width = w + 'px';
|
||||
content.style.maxWidth = w + 'px';
|
||||
document.body.classList.add('left-dock-active');
|
||||
document.documentElement.style.setProperty(
|
||||
'--left-dock-w',
|
||||
document.body.classList.contains('email-doc-split-active') ? '0px' : w + 'px',
|
||||
);
|
||||
_syncDockSideWidth(side, w, targets);
|
||||
}
|
||||
_positionEdgeDockResizeHandles();
|
||||
return w;
|
||||
};
|
||||
|
||||
|
|
@ -928,7 +1188,7 @@ export function makeEdgeDockController(modal, side = 'right', dockClass) {
|
|||
}
|
||||
_setStyle(handle, 'display', 'block');
|
||||
_setStyle(handle, 'left', (x - 5) + 'px');
|
||||
_setStyle(handle, 'zIndex', String(_zIndexFor(owner) + 1));
|
||||
_setStyle(handle, 'zIndex', String(_zIndexForElement(_dockOwnerSurface(owner), 250) + 1));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -943,15 +1203,17 @@ export function makeEdgeDockController(modal, side = 'right', dockClass) {
|
|||
handle.setPointerCapture?.(e.pointerId);
|
||||
const nodes = _resolveDockNodes(owner);
|
||||
const content = nodes?.content;
|
||||
const resizeOwners = _dockOwnersForSide(side);
|
||||
if (!resizeOwners.includes(owner)) resizeOwners.push(owner);
|
||||
const prevCursor = document.body.style.cursor;
|
||||
const prevUserSelect = document.body.style.userSelect;
|
||||
document.body.style.cursor = 'col-resize';
|
||||
document.body.style.userSelect = 'none';
|
||||
document.body.classList.add('edge-dock-resizing');
|
||||
_setWidth(owner, side, e.clientX);
|
||||
_setWidth(owner, side, e.clientX, resizeOwners);
|
||||
const onMove = (ev) => {
|
||||
ev.preventDefault();
|
||||
_setWidth(owner, side, ev.clientX);
|
||||
_setWidth(owner, side, ev.clientX, resizeOwners);
|
||||
};
|
||||
const onUp = (ev) => {
|
||||
try { handle.releasePointerCapture?.(e.pointerId); } catch (_) {}
|
||||
|
|
@ -964,7 +1226,12 @@ export function makeEdgeDockController(modal, side = 'right', dockClass) {
|
|||
const finalW = side === 'right'
|
||||
? parseFloat(document.documentElement.style.getPropertyValue('--right-dock-w')) || content?.getBoundingClientRect?.().width || 0
|
||||
: content?.getBoundingClientRect?.().width || 0;
|
||||
if (finalW) _saveDockWidth(owner, content, side, finalW);
|
||||
if (finalW) {
|
||||
resizeOwners.forEach((dockOwner) => {
|
||||
const dockContent = _resolveDockNodes(dockOwner)?.content;
|
||||
if (dockContent) _saveDockWidth(dockOwner, dockContent, side, finalW);
|
||||
});
|
||||
}
|
||||
ev.preventDefault();
|
||||
};
|
||||
document.addEventListener('pointermove', onMove, true);
|
||||
|
|
|
|||
|
|
@ -16366,6 +16366,87 @@ body.right-dock-active .chat-container,
|
|||
body.right-dock-active:not(.email-doc-split-active) .doc-editor-pane {
|
||||
margin-right: var(--right-dock-w, 0px);
|
||||
}
|
||||
.edge-dock-switcher {
|
||||
position: fixed;
|
||||
top: 18px;
|
||||
z-index: 1200;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
max-height: calc(100dvh - 36px);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.edge-dock-switcher[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
.edge-dock-switcher-right {
|
||||
right: calc(var(--right-dock-w, 0px) - 1px);
|
||||
}
|
||||
.edge-dock-switcher-left {
|
||||
left: calc(48px + var(--left-dock-w, 0px) - 1px);
|
||||
}
|
||||
.edge-dock-switcher-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 124px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
background: color-mix(in srgb, var(--panel) 92%, var(--bg));
|
||||
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
||||
color: color-mix(in srgb, var(--fg) 78%, transparent);
|
||||
font: inherit;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.edge-dock-switcher-right .edge-dock-switcher-tab {
|
||||
border-right-color: color-mix(in srgb, var(--panel) 85%, var(--bg));
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
.edge-dock-switcher-left .edge-dock-switcher-tab {
|
||||
border-left-color: color-mix(in srgb, var(--panel) 85%, var(--bg));
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
.edge-dock-switcher-tab-label {
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
width: max-content;
|
||||
max-width: none;
|
||||
overflow: visible;
|
||||
text-overflow: clip;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
}
|
||||
.edge-dock-switcher-right .edge-dock-switcher-tab-label {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.edge-dock-switcher-left .edge-dock-switcher-tab-label {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.edge-dock-switcher-tab:hover {
|
||||
color: var(--fg);
|
||||
border-color: color-mix(in srgb, var(--accent, var(--red)) 48%, var(--border));
|
||||
background: color-mix(in srgb, var(--accent, var(--red)) 9%, var(--panel));
|
||||
}
|
||||
.edge-dock-switcher-tab.active {
|
||||
color: var(--fg);
|
||||
border-color: color-mix(in srgb, var(--accent, var(--red)) 65%, var(--border));
|
||||
background: color-mix(in srgb, var(--accent, var(--red)) 16%, var(--panel));
|
||||
}
|
||||
.edge-dock-switcher-right .edge-dock-switcher-tab.active {
|
||||
border-right-color: color-mix(in srgb, var(--panel) 85%, var(--bg));
|
||||
}
|
||||
.edge-dock-switcher-left .edge-dock-switcher-tab.active {
|
||||
border-left-color: color-mix(in srgb, var(--panel) 85%, var(--bg));
|
||||
}
|
||||
.modal.modal-right-docked {
|
||||
align-items: stretch;
|
||||
justify-content: flex-end;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue