@samitouri / QOSami_Agents_Zero / commits / 278a696b
Fork 0

Agent Zero AI framework

Align Time Travel modal with settings shell

Remove Time Travel's floating modal behavior so it uses the standard centered modal shell and shared backdrop like Settings. Keep the modal-only sizing classes on the component document and stop exempting Time Travel from backdrop rendering.

Alessandro committed May 5, 2026 at 17:33 UTC 278a696b8ec6534f5c10e227d0ee011b1a051c2a
4 files changed +5 -115
plugins/_time_travel/webui/main.html
+2 -2
@@ -1,8 +1,8 @@
1 -<html>
1 +<html class="time-travel-modal">
2 <head>
3 <title>Time Travel</title>
4 </head>
5 -<body>
5 +<body class="time-travel-modal-body">
6 <x-component path="/plugins/_time_travel/webui/time-travel-panel.html" mode="modal"></x-component>
7 </body>
8 </html>
plugins/_time_travel/webui/time-travel-panel.html
+2 -13
@@ -242,26 +242,15 @@
242 min-height: min(520px, calc(100vh - 16px));
243 max-width: calc(100vw - 16px);
244 max-height: calc(100vh - 16px);
245 - resize: both;
245 border: 1px solid color-mix(in srgb, var(--color-border) 75%, transparent);
246 border-radius: 7px;
247 box-shadow: 0 18px 48px rgba(0, 0, 0, 0.32);
248 background: color-mix(in srgb, var(--color-background) 94%, #000 6%);
249 }
250
252 - .modal.modal-floating {
253 - pointer-events: none;
254 - }
255 -
256 - .modal.modal-floating .modal-inner {
257 - pointer-events: auto;
258 - }
259 -
251 .modal-inner.time-travel-modal .modal-header {
261 - min-height: 34px;
262 - padding: 0.35rem 0.75rem 0.35rem 1rem;
263 - cursor: move;
264 - user-select: none;
252 + min-height: 42px;
253 + padding: 0.45rem 0.75rem 0.45rem 1rem;
254 background: color-mix(in srgb, var(--color-background) 92%, #000 8%);
255 border-bottom: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
256 }
plugins/_time_travel/webui/time-travel-store.js
+1 -98
@@ -49,7 +49,6 @@ const model = {
49 _mode: "canvas",
50 _refreshTimer: null,
51 _filterTimer: null,
52 - _floatingCleanup: null,
52 _requestSeq: 0,
53 _diffSeq: 0,
54
@@ -60,9 +59,7 @@ const model = {
59 async onMount(element = null, options = {}) {
60 if (element) this._root = element;
61 this._mode = options?.mode === "modal" ? "modal" : "canvas";
63 - if (this._mode === "modal") {
64 - this.setupFloatingModal(element);
65 - } else {
62 + if (this._mode !== "modal") {
63 this.setupCanvasSurface(element);
64 }
65 this.contextId = this.resolveContextId();
@@ -85,103 +82,9 @@ const model = {
82 clearTimeout(this._filterTimer);
83 this._filterTimer = null;
84 }
88 - this._floatingCleanup?.();
89 - this._floatingCleanup = null;
90 - },
91 -
92 - setupFloatingModal(element = null) {
93 - this._floatingCleanup?.();
94 - const root = element || globalThis.document?.querySelector(".time-travel-panel");
95 - const modal = root?.closest?.(".modal");
96 - const inner = modal?.querySelector?.(".modal-inner");
97 - const body = modal?.querySelector?.(".modal-bd");
98 - const header = modal?.querySelector?.(".modal-header");
99 - if (!modal || !inner || !header) return;
100 - modal.classList.add("modal-floating");
101 - inner.classList.add("time-travel-modal", "modal-no-backdrop");
102 - body?.classList?.add("time-travel-modal-body");
103 -
104 - const rect = inner.getBoundingClientRect();
105 - inner.style.left = `${Math.max(8, rect.left)}px`;
106 - inner.style.top = `${Math.max(8, rect.top)}px`;
107 - inner.style.transform = "none";
108 -
109 - let drag = null;
110 - let resizeObserver = null;
111 - const viewportGap = 8;
112 - const clampPosition = (left, top) => {
113 - const bounds = inner.getBoundingClientRect();
114 - const maxLeft = Math.max(viewportGap, globalThis.innerWidth - bounds.width - viewportGap);
115 - const maxTop = Math.max(viewportGap, globalThis.innerHeight - bounds.height - viewportGap);
116 - return {
117 - left: Math.min(Math.max(viewportGap, left), maxLeft),
118 - top: Math.min(Math.max(viewportGap, top), maxTop),
119 - };
120 - };
121 - const clampGeometry = () => {
122 - const bounds = inner.getBoundingClientRect();
123 - const maxWidth = Math.max(360, globalThis.innerWidth - viewportGap * 2);
124 - const maxHeight = Math.max(420, globalThis.innerHeight - viewportGap * 2);
125 - if (bounds.width > maxWidth) inner.style.width = `${maxWidth}px`;
126 - if (bounds.height > maxHeight) inner.style.height = `${maxHeight}px`;
127 - const next = clampPosition(bounds.left, bounds.top);
128 - inner.style.left = `${next.left}px`;
129 - inner.style.top = `${next.top}px`;
130 - inner.style.maxWidth = `${Math.max(360, globalThis.innerWidth - next.left - viewportGap)}px`;
131 - inner.style.maxHeight = `${Math.max(420, globalThis.innerHeight - next.top - viewportGap)}px`;
132 - };
133 - clampGeometry();
134 - globalThis.addEventListener("resize", clampGeometry);
135 - if (globalThis.ResizeObserver) {
136 - resizeObserver = new ResizeObserver(clampGeometry);
137 - resizeObserver.observe(inner);
138 - }
139 -
140 - const onPointerMove = (event) => {
141 - if (!drag) return;
142 - const next = clampPosition(drag.left + event.clientX - drag.x, drag.top + event.clientY - drag.y);
143 - inner.style.left = `${next.left}px`;
144 - inner.style.top = `${next.top}px`;
145 - clampGeometry();
146 - };
147 - const onPointerUp = () => {
148 - drag = null;
149 - globalThis.removeEventListener("pointermove", onPointerMove);
150 - globalThis.removeEventListener("pointerup", onPointerUp);
151 - try {
152 - header.releasePointerCapture?.(header.__timeTravelPanelPointerId || 0);
153 - } catch {}
154 - };
155 - const onPointerDown = (event) => {
156 - if (event.button !== 0) return;
157 - if (event.target?.closest?.("button, input, select, textarea, a")) return;
158 - const current = inner.getBoundingClientRect();
159 - drag = {
160 - x: event.clientX,
161 - y: event.clientY,
162 - left: current.left,
163 - top: current.top,
164 - };
165 - header.__timeTravelPanelPointerId = event.pointerId;
166 - header.setPointerCapture?.(event.pointerId);
167 - globalThis.addEventListener("pointermove", onPointerMove);
168 - globalThis.addEventListener("pointerup", onPointerUp);
169 - event.preventDefault();
170 - };
171 - header.addEventListener("pointerdown", onPointerDown);
172 -
173 - this._floatingCleanup = () => {
174 - header.removeEventListener("pointerdown", onPointerDown);
175 - globalThis.removeEventListener("pointermove", onPointerMove);
176 - globalThis.removeEventListener("pointerup", onPointerUp);
177 - globalThis.removeEventListener("resize", clampGeometry);
178 - resizeObserver?.disconnect?.();
179 - };
85 },
86
87 setupCanvasSurface(element = null) {
183 - this._floatingCleanup?.();
184 - this._floatingCleanup = null;
88 if (element) this._root = element;
89 },
90
webui/js/modals.js
-2
@@ -139,8 +139,6 @@ function modalSuppressesBackdrop(modal) {
139 || path === "plugins/_browser/webui/main.html"
140 || path === "/plugins/_office/webui/main.html"
141 || path === "plugins/_office/webui/main.html"
142 - || path === "/plugins/_time_travel/webui/main.html"
143 - || path === "plugins/_time_travel/webui/main.html"
142 || modal?.element?.classList?.contains("modal-floating")
143 || modal?.element?.classList?.contains("modal-no-backdrop")
144 || modal?.inner?.classList?.contains("modal-no-backdrop");