Improve space toggles and email warmup

This commit is contained in:
pewdiepie-archdaemon
2026-06-01 14:35:38 +09:00
parent cb8a0b268d
commit e846269d61
3 changed files with 110 additions and 9 deletions

View File

@@ -456,7 +456,8 @@ def setup_email_routes():
_IMAP_POOL = {} # account_id → (conn, last_used_at)
_IMAP_IDLE_MAX = 60.0
_WARMING_READS = set()
_WARM_READ_LIMIT = 24
_WARM_READ_LIMIT = 3
_WARM_MAX_BYTES = 128 * 1024
_WARM_RECENT_SECONDS = 7 * 24 * 60 * 60
_pool_lock = _threading.Lock()
@@ -1322,9 +1323,16 @@ def setup_email_routes():
epoch = 0
if epoch and now - epoch > _WARM_RECENT_SECONDS:
continue
try:
size = int((em or {}).get("size") or 0)
except Exception:
size = 0
if size > _WARM_MAX_BYTES:
continue
ck = _read_cache_key(account_id, folder, uid, owner=owner)
if _read_cache_get(ck) is not None or ck in _WARMING_READS:
continue
_WARMING_READS.add(ck)
selected.append((uid, ck))
if len(selected) >= _WARM_READ_LIMIT:
break
@@ -1334,8 +1342,8 @@ def setup_email_routes():
async def _warm():
for uid, ck in selected:
if _read_cache_get(ck) is not None:
_WARMING_READS.discard(ck)
continue
_WARMING_READS.add(ck)
try:
result = await _asyncio.to_thread(_read_email_sync, uid, folder, account_id, owner, False)
if result and not result.get("error"):

View File

@@ -28,7 +28,7 @@
import { previewZoneAt, clearPreview, snapModalToZone } from './tileManager.js';
import { suspendDock, resumeDock, clearRightDock, applyEdgeDock } from './modalSnap.js';
const _state = new Map(); // id -> { restoreFn, closeFn, railBtnId, isMinimized }
const _state = new Map(); // id -> { restoreFn, closeFn, railBtnId, isMinimized, restoreMinHeight }
const _rememberedDockKey = (id) => `odysseus-modal-remembered-dock-${id}`;
function _rememberDock(id, side) {
@@ -73,6 +73,26 @@ function _emitModalOpened(id, modal) {
} catch (_) {}
}
function _captureRestoreHeight(modal, state) {
if (!modal || !state) return;
const content = modal.querySelector('.modal-content');
if (!content) return;
const rect = content.getBoundingClientRect();
if (!rect || rect.height < 120) return;
const maxHeight = Math.max(180, window.innerHeight - 24);
state.restoreMinHeight = `${Math.round(Math.min(rect.height, maxHeight))}px`;
}
function _applyRestoreHeight(modal, state) {
if (!modal || !state?.restoreMinHeight) return;
const content = modal.querySelector('.modal-content');
if (!content) return;
const maxHeight = Math.max(180, window.innerHeight - 24);
const requested = parseInt(state.restoreMinHeight, 10);
const height = Number.isFinite(requested) ? Math.min(requested, maxHeight) : null;
if (height) content.style.minHeight = `${height}px`;
}
function _setBadge(btnIds, on) {
if (!btnIds) return;
const ids = Array.isArray(btnIds) ? btnIds : [btnIds];
@@ -1109,6 +1129,7 @@ export function register(id, { restoreFn, closeFn, railBtnId, sidebarBtnId, labe
closeFn: closeFn || (() => {}),
btnIds,
isMinimized: false,
restoreMinHeight: '',
});
// Auto-stack: whichever modal becomes visible last sits on top of any
// already-open modals. The various tool open() functions (gallery,
@@ -1188,6 +1209,7 @@ export function minimize(id) {
// and let the chip drive restore/close via the registered functions.
const modal = document.getElementById(id);
if (modal) {
_captureRestoreHeight(modal, s);
// If this window is edge-docked (right/left), SUSPEND the dock: release
// the body push so the chat returns to full width while the window is
// minimized, but keep the dock so restoring the chip snaps it back in.
@@ -1218,6 +1240,7 @@ export function restore(id) {
if (modal) {
modal.classList.remove('hidden', 'modal-minimized');
modal.style.display = '';
_applyRestoreHeight(modal, s);
// Surface above any already-open tool window — restoring from the dock
// should bring this tool to the front, not leave it stuck behind one with
// a higher static z-index.

View File

@@ -5,10 +5,13 @@
*/
import themeModule from './theme.js';
import * as Modals from './modalManager.js';
let toastEl = null;
let autoScrollEnabled = true;
let hoveredToggleCard = null;
let hoveredToggleWindow = null;
let hoveredDockChip = null;
// Smooth scroll state
let _scrollRafId = null;
@@ -19,25 +22,92 @@ function _isTextEditingTarget(target) {
return !!(el && el.closest('input, textarea, select, [contenteditable="true"], [contenteditable=""]'));
}
const SPACE_CARD_SELECTOR = [
'#email-lib-modal .doclib-card',
'#doclib-modal .doclib-card',
'#memory-modal .doclib-card',
'#tasks-modal .task-card',
'#tasks-modal .task-log-row',
'#research-overlay [data-job-id]',
'#cookbook-modal .doclib-card',
'.email-reader-tab-modal .doclib-card',
'.email-window-modal .doclib-card',
].join(', ');
const SPACE_BLOCKED_SELECTOR = [
'button',
'a',
'input',
'textarea',
'select',
'[contenteditable="true"]',
'[contenteditable=""]',
'.recipient-chip',
'.doclib-card-dropdown',
'.email-card-dropdown',
'.task-log-row-actions',
'.modal-header',
].join(', ');
function _visibleModalForSpace(win) {
const modal = win?.closest?.('.modal[id]');
if (!modal || modal.classList.contains('hidden') || modal.classList.contains('modal-minimized')) return null;
return modal;
}
function _isSpaceVisible(el) {
if (!el || !document.contains(el)) return false;
if (el.closest?.('.modal.hidden, .modal.modal-minimized, [hidden]')) return false;
return true;
}
function _spaceWindowId(win) {
if (!win || !document.contains(win)) return null;
const modal = _visibleModalForSpace(win);
if (modal && Modals.isRegistered(modal.id)) return modal.id;
if (win.closest?.('.doc-editor-pane') && Modals.isRegistered('doc-panel') && !Modals.isMinimized('doc-panel')) return 'doc-panel';
return null;
}
function _initHoverCardSpaceToggle() {
if (document._odysseusHoverCardSpaceToggle) return;
document._odysseusHoverCardSpaceToggle = true;
document.addEventListener('pointerover', (e) => {
const card = e.target?.closest?.('#email-lib-modal .doclib-card, #doclib-modal .doclib-card, .email-reader-tab-modal .doclib-card, .email-window-modal .doclib-card');
const chip = e.target?.closest?.('.minimized-dock-chip[data-modal-id]');
if (chip) hoveredDockChip = chip;
const card = e.target?.closest?.(SPACE_CARD_SELECTOR);
if (card) hoveredToggleCard = card;
const win = e.target?.closest?.('.modal:not(.hidden):not(.modal-minimized) .modal-content, .doc-editor-pane');
if (win) hoveredToggleWindow = win;
}, true);
document.addEventListener('pointerout', (e) => {
if (!hoveredToggleCard) return;
const next = e.relatedTarget;
if (!next || !hoveredToggleCard.contains(next)) hoveredToggleCard = null;
if (hoveredDockChip && (!next || !hoveredDockChip.contains(next))) hoveredDockChip = null;
if (hoveredToggleCard && (!next || !hoveredToggleCard.contains(next))) hoveredToggleCard = null;
if (hoveredToggleWindow && (!next || !hoveredToggleWindow.contains(next))) hoveredToggleWindow = null;
}, true);
document.addEventListener('keydown', (e) => {
if (e.code !== 'Space' || e.repeat || !hoveredToggleCard || !document.contains(hoveredToggleCard)) return;
if (e.code !== 'Space' || e.repeat) return;
if (_isTextEditingTarget(e.target)) return;
const blocked = e.target?.closest?.('button, a, input, textarea, select, [contenteditable="true"], [contenteditable=""], .recipient-chip, .doclib-card-dropdown, .email-card-dropdown');
const blocked = e.target?.closest?.(SPACE_BLOCKED_SELECTOR);
if (blocked) return;
if (hoveredToggleCard && _isSpaceVisible(hoveredToggleCard)) {
e.preventDefault();
hoveredToggleCard.click();
return;
}
if (hoveredDockChip && document.contains(hoveredDockChip)) {
const id = hoveredDockChip.dataset.modalId;
if (id && Modals.isRegistered(id)) {
e.preventDefault();
Modals.restore(id);
}
return;
}
const id = _spaceWindowId(hoveredToggleWindow);
if (!id) return;
e.preventDefault();
hoveredToggleCard.click();
Modals.minimize(id);
}, true);
}