mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-30 20:12:21 +02:00
Squash Odysseus development history
This commit is contained in:
+68
-16
@@ -1,5 +1,5 @@
|
||||
// Shared window-drag helper. Replaces the duplicated mousedown / mousemove
|
||||
// / mouseup + snap-to-top fullscreen + left/right edge dock patterns that
|
||||
// / mouseup + legacy snap-to-top fullscreen + edge-dock patterns that
|
||||
// were copy-pasted across calendar.js, tasks.js, gallery.js, emailLibrary.js,
|
||||
// documentLibrary.js, theme.js. Behavior stays identical to the old per-file
|
||||
// copies — each callsite provides its own enter/exit-fullscreen callbacks
|
||||
@@ -31,12 +31,14 @@
|
||||
// true on desktop, irrelevant on mobile (mobileSkip).
|
||||
// mobileSkip: drag is disabled below this viewport width.
|
||||
// Default 768. Set to 0 to never skip.
|
||||
// enableDock: bool — enable left + right edge docks.
|
||||
// Default true.
|
||||
// enableDock: bool — allow an existing programmatic edge dock to be
|
||||
// dragged loose. New drag snaps are owned exclusively
|
||||
// by tileManager so two previews/actions cannot race.
|
||||
// enableFullscreen: bool — enable top-edge fullscreen snap.
|
||||
// Default true when onEnterFullscreen is supplied.
|
||||
|
||||
import { makeEdgeDockController } from './modalSnap.js';
|
||||
import { makeWindowResizable } from './windowResize.js';
|
||||
|
||||
const SNAP_PX = 6; // cursor distance from top edge for fullscreen snap
|
||||
const UNSNAP_PX = 24; // cursor distance from top before fullscreen exits
|
||||
@@ -60,22 +62,60 @@ export function makeWindowDraggable(modal, options = {}) {
|
||||
const fsClass = options.fsClass || null;
|
||||
const onEnterFullscreen = options.onEnterFullscreen || null;
|
||||
const onExitFullscreen = options.onExitFullscreen || null;
|
||||
const enableFullscreen = options.enableFullscreen !== false && !!onEnterFullscreen;
|
||||
const enableFullscreen = false;
|
||||
const onDragEnd = options.onDragEnd || null;
|
||||
const onDragStart = options.onDragStart || null;
|
||||
const skipSelector = options.skipSelector || 'button, input, select';
|
||||
const mobileSkip = (typeof options.mobileSkip === 'number') ? options.mobileSkip : 768;
|
||||
const enableTouch = options.enableTouch !== false;
|
||||
const enableDock = options.enableDock !== false && !!modal;
|
||||
// tileManager is the single source of truth for new edge snaps. Keep these
|
||||
// controllers only so a programmatically docked window can be pulled loose.
|
||||
const enableDockSnap = false;
|
||||
|
||||
header.style.cursor = 'move';
|
||||
header.style.userSelect = 'none';
|
||||
|
||||
// Edge/corner resize. Every draggable window also becomes resizable — the
|
||||
// same gesture a native desktop window uses (grab an edge or corner, drag).
|
||||
// Skipped on mobile (windows are full-screen sheets there) and while the
|
||||
// window is fullscreen-snapped or docked. Wired here so all ~12 callsites
|
||||
// get it without per-file changes.
|
||||
if (options.enableResize !== false) {
|
||||
const _dockClasses = ['modal-right-docked', 'modal-left-docked'];
|
||||
makeWindowResizable(content, {
|
||||
modal,
|
||||
mobileSkip,
|
||||
minWidth: options.minWidth,
|
||||
minHeight: options.minHeight,
|
||||
isLocked: () => (fsClass && modal && modal.classList.contains(fsClass))
|
||||
|| (modal && _dockClasses.some((c) => modal.classList.contains(c))),
|
||||
storageKey: options.resizeStorageKey
|
||||
|| (modal && modal.id ? 'winsize-' + modal.id
|
||||
: (content.id ? 'winsize-' + content.id : null)),
|
||||
});
|
||||
}
|
||||
|
||||
// A native-window-style reset gesture: double-clicking unused header/title
|
||||
// space restores the authored size and lets the modal overlay center it.
|
||||
// Controls keep their own double-click behaviour, and mobile sheets retain
|
||||
// their fixed drawer geometry.
|
||||
header.addEventListener('dblclick', (event) => {
|
||||
if (mobileSkip > 0 && window.innerWidth <= mobileSkip) return;
|
||||
if (skipSelector && event.target.closest(skipSelector)) return;
|
||||
if (event.target.closest('button, input, select, textarea, a, [contenteditable="true"]')) return;
|
||||
if (typeof content._resetWindowGeometry !== 'function') return;
|
||||
if (!content._resetWindowGeometry()) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
const rightDock = enableDock ? makeEdgeDockController(modal, 'right') : null;
|
||||
// Left dock is opt-in (enableLeftDock). For most windows it's off — the
|
||||
// sidebar lives on the left, so a left dock collides with it. The email
|
||||
// window enables it so you can park the message on the left and read it
|
||||
// while replying in the document on the right.
|
||||
const leftDock = (enableDock && options.enableLeftDock) ? makeEdgeDockController(modal, 'left') : null;
|
||||
// Left dock is enabled by default too. modalSnap collapses the wide sidebar
|
||||
// and anchors the panel beside the icon rail, so it no longer collides with
|
||||
// the navigation. Callers can still pass enableLeftDock:false for a special
|
||||
// modal that should only dock right.
|
||||
const leftDock = (enableDock && options.enableLeftDock !== false) ? makeEdgeDockController(modal, 'left') : null;
|
||||
|
||||
// Per-drag state, reset on mousedown.
|
||||
let dragging = false;
|
||||
@@ -126,7 +166,18 @@ export function makeWindowDraggable(modal, options = {}) {
|
||||
|
||||
const _startDrag = (cx, cy) => {
|
||||
dragging = true;
|
||||
if (modal) modal.classList.add('modal-dragging');
|
||||
// Cancel any in-flight open animation so we don't pin a mid-animation
|
||||
// rect and then jump once the animation settles.
|
||||
try {
|
||||
content.getAnimations()
|
||||
.filter(a => a.playState !== 'finished')
|
||||
.forEach(a => a.cancel());
|
||||
} catch (_) {}
|
||||
const rect = content.getBoundingClientRect();
|
||||
if (onDragStart) {
|
||||
try { onDragStart({ rect, cx, cy }); } catch (_) {}
|
||||
}
|
||||
startX = cx; startY = cy;
|
||||
startLeft = rect.left; startTop = rect.top;
|
||||
// Pin position so the drag follows the cursor instead of fighting a
|
||||
@@ -157,20 +208,20 @@ export function makeWindowDraggable(modal, options = {}) {
|
||||
// fullscreen first, which re-CENTERED the window — so it looked like
|
||||
// it "centered instead of docking". Only a downward drag unsnaps to a
|
||||
// windowed (centered) modal.
|
||||
if (nearRight && rightDock) {
|
||||
if (enableDockSnap && nearRight && rightDock) {
|
||||
if (leftDock) leftDock.release();
|
||||
rightDock.onMove(cx, cy);
|
||||
return;
|
||||
}
|
||||
if (nearLeft && leftDock) {
|
||||
if (enableDockSnap && nearLeft && leftDock) {
|
||||
if (rightDock) rightDock.release();
|
||||
leftDock.onMove(cx, cy);
|
||||
return;
|
||||
}
|
||||
if (cy > UNSNAP_PX) {
|
||||
_exitFs(cx, cy);
|
||||
if (rightDock) rightDock.onMove(cx, cy);
|
||||
if (leftDock) leftDock.onMove(cx, cy);
|
||||
if (enableDockSnap && rightDock) rightDock.onMove(cx, cy);
|
||||
if (enableDockSnap && leftDock) leftDock.onMove(cx, cy);
|
||||
} else {
|
||||
if (rightDock) rightDock.release();
|
||||
if (leftDock) leftDock.release();
|
||||
@@ -204,7 +255,7 @@ export function makeWindowDraggable(modal, options = {}) {
|
||||
// top corner only ever snaps to fullscreen — never the corner hybrid.
|
||||
const inTopBand = cy <= SNAP_PX;
|
||||
_showSnapHint(enableFullscreen && inTopBand);
|
||||
if (inTopBand) {
|
||||
if (inTopBand || !enableDockSnap) {
|
||||
if (rightDock) rightDock.release();
|
||||
if (leftDock) leftDock.release();
|
||||
} else {
|
||||
@@ -216,6 +267,7 @@ export function makeWindowDraggable(modal, options = {}) {
|
||||
const _onEnd = (cx, cy) => {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
if (modal) modal.classList.remove('modal-dragging');
|
||||
_showSnapHint(false);
|
||||
// Top edge wins over side edges — fullscreen is the more common gesture.
|
||||
if (enableFullscreen && typeof cy === 'number' && cy <= SNAP_PX) {
|
||||
@@ -224,13 +276,13 @@ export function makeWindowDraggable(modal, options = {}) {
|
||||
_enterFs();
|
||||
return;
|
||||
}
|
||||
if (rightDock && rightDock.hovering()) {
|
||||
if (enableDockSnap && rightDock && rightDock.hovering()) {
|
||||
if (leftDock) leftDock.release();
|
||||
if (fsClass && modal) modal.classList.remove(fsClass); // dock takes over from fullscreen
|
||||
rightDock.commit();
|
||||
return;
|
||||
}
|
||||
if (leftDock && leftDock.hovering()) {
|
||||
if (enableDockSnap && leftDock && leftDock.hovering()) {
|
||||
if (rightDock) rightDock.release();
|
||||
if (fsClass && modal) modal.classList.remove(fsClass);
|
||||
leftDock.commit();
|
||||
|
||||
Reference in New Issue
Block a user