react-os-shell 0.2.26 → 0.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{Browser-RJZLTAJQ.js → Browser-FZTIGZJH.js} +3 -3
  2. package/dist/{Browser-RJZLTAJQ.js.map → Browser-FZTIGZJH.js.map} +1 -1
  3. package/dist/{Calculator-DMROKOY2.js → Calculator-4J7SP6HW.js} +4 -4
  4. package/dist/{Calculator-DMROKOY2.js.map → Calculator-4J7SP6HW.js.map} +1 -1
  5. package/dist/{Calendar-24TAKCAJ.js → Calendar-QCQJEO2E.js} +3 -3
  6. package/dist/{Calendar-24TAKCAJ.js.map → Calendar-QCQJEO2E.js.map} +1 -1
  7. package/dist/{CurrencyConverter-A6CHXNEQ.js → CurrencyConverter-WP6KZMEU.js} +4 -4
  8. package/dist/{CurrencyConverter-A6CHXNEQ.js.map → CurrencyConverter-WP6KZMEU.js.map} +1 -1
  9. package/dist/{Documents-QMP6QN3C.js → Documents-SWUWWRRB.js} +3 -3
  10. package/dist/{Documents-QMP6QN3C.js.map → Documents-SWUWWRRB.js.map} +1 -1
  11. package/dist/{Email-XTFUEIE5.js → Email-ERTPCJOX.js} +3 -3
  12. package/dist/{Email-XTFUEIE5.js.map → Email-ERTPCJOX.js.map} +1 -1
  13. package/dist/Files-3ZGMJXTR.js +7 -0
  14. package/dist/{Files-YHUOR7RM.js.map → Files-3ZGMJXTR.js.map} +1 -1
  15. package/dist/{Minesweeper-YPAR6SPJ.js → Minesweeper-WVKECHOL.js} +3 -3
  16. package/dist/{Minesweeper-YPAR6SPJ.js.map → Minesweeper-WVKECHOL.js.map} +1 -1
  17. package/dist/{Notepad-VEEUZROP.js → Notepad-I5QTIZDV.js} +3 -3
  18. package/dist/{Notepad-VEEUZROP.js.map → Notepad-I5QTIZDV.js.map} +1 -1
  19. package/dist/{PomodoroTimer-HWHMQZO6.js → PomodoroTimer-DGAITQZR.js} +4 -4
  20. package/dist/{PomodoroTimer-HWHMQZO6.js.map → PomodoroTimer-DGAITQZR.js.map} +1 -1
  21. package/dist/Preview-S7AGTRVP.js +6 -0
  22. package/dist/{Preview-SLX4ZLUQ.js.map → Preview-S7AGTRVP.js.map} +1 -1
  23. package/dist/{Spreadsheet-W76QOD42.js → Spreadsheet-R2VRFGAS.js} +3 -3
  24. package/dist/{Spreadsheet-W76QOD42.js.map → Spreadsheet-R2VRFGAS.js.map} +1 -1
  25. package/dist/{Weather-DIKN7BOT.js → Weather-KZPNE4TY.js} +4 -4
  26. package/dist/{Weather-DIKN7BOT.js.map → Weather-KZPNE4TY.js.map} +1 -1
  27. package/dist/apps/index.js +16 -16
  28. package/dist/{chunk-23RBDC2Z.js → chunk-3DJAOGL7.js} +4 -4
  29. package/dist/{chunk-23RBDC2Z.js.map → chunk-3DJAOGL7.js.map} +1 -1
  30. package/dist/{chunk-6IV6OWF3.js → chunk-6PX6HT6T.js} +3 -3
  31. package/dist/{chunk-6IV6OWF3.js.map → chunk-6PX6HT6T.js.map} +1 -1
  32. package/dist/{chunk-HVZUPS3P.js → chunk-EQ3MNYLX.js} +3 -3
  33. package/dist/{chunk-HVZUPS3P.js.map → chunk-EQ3MNYLX.js.map} +1 -1
  34. package/dist/{chunk-QXY6ZHRX.js → chunk-I7GRSFIL.js} +424 -240
  35. package/dist/chunk-I7GRSFIL.js.map +1 -0
  36. package/dist/index.js +4 -4
  37. package/package.json +1 -1
  38. package/dist/Files-YHUOR7RM.js +0 -7
  39. package/dist/Preview-SLX4ZLUQ.js +0 -6
  40. package/dist/chunk-QXY6ZHRX.js.map +0 -1
@@ -556,9 +556,114 @@ function useIsActiveModal(modalId) {
556
556
  const activeId = useSyncExternalStore(subscribeActive, getActiveModalId);
557
557
  return activationOrder.length <= 1 || activeId === modalId;
558
558
  }
559
+ var _exposeOn = false;
560
+ var _exposeListeners = /* @__PURE__ */ new Set();
561
+ function _notifyExpose() {
562
+ _exposeListeners.forEach((fn) => fn());
563
+ }
564
+ function subscribeExpose(fn) {
565
+ _exposeListeners.add(fn);
566
+ return () => _exposeListeners.delete(fn);
567
+ }
568
+ function getExposeState() {
569
+ return _exposeOn;
570
+ }
571
+ function setExposeState(v) {
572
+ if (_exposeOn === v) return;
573
+ _exposeOn = v;
574
+ _notifyExpose();
575
+ }
559
576
  function triggerSplitView() {
577
+ setExposeState(!_exposeOn);
560
578
  window.dispatchEvent(new CustomEvent("modal-split-view"));
561
579
  }
580
+ window.addEventListener("keydown", (e) => {
581
+ if (_exposeOn && e.key === "Escape") {
582
+ setExposeState(false);
583
+ }
584
+ });
585
+ function computeExposeTile(modalId) {
586
+ if (typeof document === "undefined") return null;
587
+ const allPanels = Array.from(document.querySelectorAll("[data-modal-panel]"));
588
+ const tileable = allPanels.filter((p) => {
589
+ const el = p;
590
+ if (el.hasAttribute("data-utility") || el.hasAttribute("data-widget")) return false;
591
+ if (el.style.display === "none") return false;
592
+ return true;
593
+ });
594
+ tileable.sort((a2, b) => (a2.getAttribute("data-modal-id") || "").localeCompare(b.getAttribute("data-modal-id") || ""));
595
+ const myIdx = tileable.findIndex((p) => p.getAttribute("data-modal-id") === modalId);
596
+ const count = tileable.length;
597
+ if (myIdx < 0 || count < 1) return null;
598
+ const cols = Math.ceil(Math.sqrt(count));
599
+ const rows = Math.ceil(count / cols);
600
+ const myRow = Math.floor(myIdx / cols);
601
+ const myCol = myIdx % cols;
602
+ const lastRowCount = count - cols * (rows - 1);
603
+ const isLastRow = myRow === rows - 1 && lastRowCount < cols;
604
+ const taskbarH = parseInt(getComputedStyle(document.documentElement).getPropertyValue("--taskbar-height")) || 0;
605
+ const taskbarW = parseInt(getComputedStyle(document.documentElement).getPropertyValue("--taskbar-width")) || 0;
606
+ const tbPos = (getComputedStyle(document.documentElement).getPropertyValue("--taskbar-position") || "bottom").trim();
607
+ const xOffset = tbPos === "left" ? taskbarW : 0;
608
+ const xRight = tbPos === "right" ? taskbarW : 0;
609
+ const yOffset = tbPos === "top" ? taskbarH : 0;
610
+ const yBottom = tbPos === "top" || tbPos === "left" || tbPos === "right" ? 0 : taskbarH;
611
+ const a = {
612
+ x: xOffset,
613
+ y: yOffset,
614
+ w: window.innerWidth - xOffset - xRight,
615
+ h: window.innerHeight - yOffset - yBottom
616
+ };
617
+ const gapX = 20;
618
+ const gapY = 14;
619
+ const labelH = 22;
620
+ const cellW = (a.w - gapX * (cols + 1)) / cols;
621
+ const cellH = (a.h - gapY * (rows + 1) - labelH * rows) / rows;
622
+ const lastRowOffsetX = isLastRow ? (cols - lastRowCount) * (cellW + gapX) / 2 : 0;
623
+ const tileX = a.x + gapX + myCol * (cellW + gapX) + lastRowOffsetX;
624
+ const tileY = a.y + gapY + myRow * (cellH + gapY + labelH);
625
+ return { x: tileX, y: tileY, w: cellW, h: cellH };
626
+ }
627
+ function ExposeBackdrop() {
628
+ const on = useSyncExternalStore(subscribeExpose, getExposeState);
629
+ const [mounted, setMounted] = useState(on);
630
+ const [visible, setVisible] = useState(on);
631
+ useEffect(() => {
632
+ if (on) {
633
+ setMounted(true);
634
+ const id = requestAnimationFrame(() => setVisible(true));
635
+ return () => cancelAnimationFrame(id);
636
+ }
637
+ setVisible(false);
638
+ const t = setTimeout(() => setMounted(false), 280);
639
+ return () => clearTimeout(t);
640
+ }, [on]);
641
+ if (!mounted || typeof document === "undefined") return null;
642
+ return createPortal(
643
+ /* @__PURE__ */ jsx(
644
+ "div",
645
+ {
646
+ onMouseDown: (e) => {
647
+ e.stopPropagation();
648
+ setExposeState(false);
649
+ },
650
+ style: {
651
+ position: "fixed",
652
+ inset: 0,
653
+ background: "rgba(0,0,0,0.55)",
654
+ backdropFilter: "blur(2px)",
655
+ WebkitBackdropFilter: "blur(2px)",
656
+ zIndex: 2e3,
657
+ cursor: "pointer",
658
+ opacity: visible ? 1 : 0,
659
+ transition: "opacity 260ms cubic-bezier(0.2, 0.8, 0.2, 1)",
660
+ pointerEvents: visible ? "auto" : "none"
661
+ }
662
+ }
663
+ ),
664
+ document.body
665
+ );
666
+ }
562
667
  function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = false, onNext, onPrev, footer, bodyScroll, onMinimize, initialBox, actions, actionsLeft, allowPinOnTop, initialPosition, widget, compact, appStyle, autoHeight, autoMinHeight, widgetMenu, dimensions, windowKey, openedFromKey, children }) {
563
668
  const isMobile = useIsMobile();
564
669
  const [swipeX, setSwipeX] = useState(0);
@@ -670,6 +775,24 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
670
775
  }, [modalId]);
671
776
  const [zIndex, setZIndex] = useState(50);
672
777
  const isActive = useIsActiveModal(modalId);
778
+ const exposeOn = useSyncExternalStore(subscribeExpose, getExposeState);
779
+ const isExposeTileable = !allowPinOnTop && !widget;
780
+ const exposeActive = exposeOn && isExposeTileable;
781
+ const [exposeHovered, setExposeHovered] = useState(false);
782
+ const [exposeExiting, setExposeExiting] = useState(false);
783
+ const prevExposeActiveRef = useRef(exposeActive);
784
+ useEffect(() => {
785
+ if (prevExposeActiveRef.current && !exposeActive) {
786
+ setExposeExiting(true);
787
+ const t = setTimeout(() => setExposeExiting(false), 320);
788
+ prevExposeActiveRef.current = exposeActive;
789
+ return () => clearTimeout(t);
790
+ }
791
+ prevExposeActiveRef.current = exposeActive;
792
+ }, [exposeActive]);
793
+ useEffect(() => {
794
+ if (!exposeActive) setExposeHovered(false);
795
+ }, [exposeActive]);
673
796
  useEffect(() => {
674
797
  const r = actionsRef.current;
675
798
  const l = actionsLeftRef.current;
@@ -756,28 +879,6 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
756
879
  setZIndex(getZForModal(modalId));
757
880
  };
758
881
  const onSplitView = () => {
759
- if (allowPinOnTop || widget) return;
760
- const allPanels = document.querySelectorAll("[data-modal-panel]");
761
- let nonUtilityCount = 0;
762
- let myNonUtilIdx = -1;
763
- activationOrder.forEach((id, _i) => {
764
- const panel = Array.from(allPanels).find((p) => p.getAttribute("data-modal-id") === id);
765
- if (panel && !panel.hasAttribute("data-utility") && !panel.hasAttribute("data-widget")) {
766
- if (id === modalId) myNonUtilIdx = nonUtilityCount;
767
- nonUtilityCount++;
768
- }
769
- });
770
- const count = nonUtilityCount;
771
- if (count < 2) return;
772
- const myIdx = myNonUtilIdx;
773
- if (myIdx < 0) return;
774
- const a = workArea();
775
- const baseW = Math.floor(a.w / count);
776
- const remainder = a.w - baseW * count;
777
- const colW = baseW + (myIdx < remainder ? 1 : 0);
778
- const xOffset = myIdx * baseW + Math.min(myIdx, remainder);
779
- setBox({ x: a.x + xOffset, y: a.y, w: colW, h: a.h });
780
- setMaximized(false);
781
882
  };
782
883
  const onCenter = (e) => {
783
884
  const label = e.detail?.label;
@@ -1129,121 +1230,206 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1129
1230
  return () => window.removeEventListener("keydown", handler);
1130
1231
  }, [open, onNext, onPrev, hasNav, showBoundaryToast, modalId]);
1131
1232
  if (!open || interceptedRef.current) return null;
1132
- const content = /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
1133
- "div",
1134
- {
1135
- ref: panelRef,
1136
- "data-modal-panel": true,
1137
- "data-modal-id": modalId,
1138
- "data-window-key": windowKey || void 0,
1139
- ...allowPinOnTop ? { "data-utility": "" } : {},
1140
- ...widget ? { "data-widget": "" } : {},
1141
- className: `fixed rounded-lg flex flex-col overflow-hidden group ${widget ? isActive ? "shadow-2xl" : "shadow-lg" : `border ${isActive ? "shadow-2xl border-gray-200" : "shadow-lg border-gray-300"}`}`,
1142
- onMouseDown: (e) => {
1143
- setWindowMenu(null);
1144
- const targetPanel = e.target.closest("[data-modal-panel]");
1145
- if (targetPanel && targetPanel !== panelRef.current) return;
1146
- if (!e.target.closest("button, input, a, select, textarea")) {
1147
- activateModal(modalId);
1148
- }
1149
- },
1150
- style: isMobile ? {
1151
- // Mobile fullscreen: ignore stored box, fill viewport down to bottom
1152
- // nav. Widgets stay hidden on mobile. Only the active window is
1153
- // visible — all others hidden so swipe-right reveals the home
1154
- // wallpaper backdrop. Exception: when a sibling Modal is being
1155
- // swiped to-back and we're its `openedFrom` parent, un-hide so the
1156
- // user sees their parent list during the slide instead of just the
1157
- // wallpaper.
1158
- zIndex: zIndex + 1,
1159
- top: 0,
1160
- left: 0,
1161
- right: 0,
1162
- bottom: "var(--mobile-bottom-nav, 56px)",
1163
- width: "auto",
1164
- height: "auto",
1165
- transform: `translateX(${swipeX}px)`,
1166
- transition: swipeDragging ? "none" : "transform 180ms ease-out",
1167
- ...widget ? { display: "none" } : {},
1168
- ...zIndex < 0 ? { display: "none" } : {},
1169
- ...!isActive && !pinnedOnTop && !(swipingParentKey && windowKey === swipingParentKey) ? { display: "none" } : {}
1170
- } : {
1171
- zIndex: pinnedOnTop ? 999 : zIndex + 1,
1172
- width: box.w,
1173
- height: autoHeight ? "auto" : box.h,
1174
- top: box.y,
1175
- ...autoHeight ? {
1176
- // Widgets must fit content exactly (Weather, Currency, etc.) —
1177
- // the 240 px floor only applies to non-widget app windows where
1178
- // a near-empty body would look broken.
1179
- minHeight: `${autoMinHeight ?? (widget ? 0 : 240)}px`,
1180
- maxHeight: `calc(100vh - var(--taskbar-height, 0px) - 24px)`
1181
- } : {},
1182
- ...widget && widgetAnchor === "right" ? { right: window.innerWidth - box.x - box.w } : { left: box.x },
1183
- ...zIndex < 0 && !pinnedOnTop ? { display: "none" } : {}
1184
- },
1185
- children: [
1186
- isMobile && !widget && /* @__PURE__ */ jsx(
1187
- "div",
1188
- {
1189
- onPointerDown: handleEdgePointerDown,
1190
- className: "absolute top-0 bottom-0 left-0 w-[22px] z-[5]",
1191
- style: { touchAction: "pan-y" },
1192
- "aria-hidden": "true"
1233
+ const exposeTile = exposeActive ? computeExposeTile(modalId) : null;
1234
+ const exposeStyle = (() => {
1235
+ if (exposeActive && exposeTile) {
1236
+ const scale = Math.min(exposeTile.w / box.w, exposeTile.h / box.h);
1237
+ const scaledW = box.w * scale;
1238
+ const scaledH = box.h * scale;
1239
+ const tx = exposeTile.x + (exposeTile.w - scaledW) / 2 - box.x;
1240
+ const ty = exposeTile.y + (exposeTile.h - scaledH) / 2 - box.y;
1241
+ return {
1242
+ transform: `translate(${tx}px, ${ty}px) scale(${scale})`,
1243
+ transformOrigin: "top left",
1244
+ transition: "transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 280ms",
1245
+ cursor: "pointer",
1246
+ // Hovered tile lifts above its neighbours so the hover ring isn't
1247
+ // clipped by adjacent panels.
1248
+ zIndex: exposeHovered ? 2020 : 2010,
1249
+ boxShadow: exposeHovered ? "0 24px 72px rgba(0,0,0,0.6), 0 0 0 2px rgba(255,255,255,0.55), 0 0 36px 12px rgba(96,165,250,0.85), 0 0 96px 28px rgba(96,165,250,0.55)" : "0 16px 48px rgba(0,0,0,0.55)",
1250
+ pointerEvents: "auto"
1251
+ };
1252
+ }
1253
+ if (exposeExiting && isExposeTileable) {
1254
+ return {
1255
+ transition: "transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 280ms"
1256
+ };
1257
+ }
1258
+ return null;
1259
+ })();
1260
+ const content = /* @__PURE__ */ jsxs("div", { children: [
1261
+ /* @__PURE__ */ jsxs(
1262
+ "div",
1263
+ {
1264
+ ref: panelRef,
1265
+ "data-modal-panel": true,
1266
+ "data-modal-id": modalId,
1267
+ "data-window-key": windowKey || void 0,
1268
+ ...allowPinOnTop ? { "data-utility": "" } : {},
1269
+ ...widget ? { "data-widget": "" } : {},
1270
+ className: `fixed rounded-lg flex flex-col overflow-hidden group ${widget ? isActive ? "shadow-2xl" : "shadow-lg" : `border ${isActive ? "shadow-2xl border-gray-200" : "shadow-lg border-gray-300"}`}`,
1271
+ onMouseDownCapture: (e) => {
1272
+ if (exposeActive) {
1273
+ e.preventDefault();
1274
+ e.stopPropagation();
1275
+ setExposeState(false);
1276
+ activateModal(modalId);
1277
+ return;
1193
1278
  }
1194
- ),
1195
- widget ? (
1196
- /* Widget: no title bar — drag via body, close via right-click context menu */
1197
- null
1198
- ) : isMobile ? null : compact ? (
1199
- /* Compact: smaller title bar with title + close only */
1200
- /* @__PURE__ */ jsxs(
1279
+ },
1280
+ onMouseDown: (e) => {
1281
+ if (exposeActive) return;
1282
+ setWindowMenu(null);
1283
+ const targetPanel = e.target.closest("[data-modal-panel]");
1284
+ if (targetPanel && targetPanel !== panelRef.current) return;
1285
+ if (!e.target.closest("button, input, a, select, textarea")) {
1286
+ activateModal(modalId);
1287
+ }
1288
+ },
1289
+ style: isMobile ? {
1290
+ // Mobile fullscreen: ignore stored box, fill viewport down to bottom
1291
+ // nav. Widgets stay hidden on mobile. Only the active window is
1292
+ // visible — all others hidden so swipe-right reveals the home
1293
+ // wallpaper backdrop. Exception: when a sibling Modal is being
1294
+ // swiped to-back and we're its `openedFrom` parent, un-hide so the
1295
+ // user sees their parent list during the slide instead of just the
1296
+ // wallpaper.
1297
+ zIndex: zIndex + 1,
1298
+ top: 0,
1299
+ left: 0,
1300
+ right: 0,
1301
+ bottom: "var(--mobile-bottom-nav, 56px)",
1302
+ width: "auto",
1303
+ height: "auto",
1304
+ transform: `translateX(${swipeX}px)`,
1305
+ transition: swipeDragging ? "none" : "transform 180ms ease-out",
1306
+ ...widget ? { display: "none" } : {},
1307
+ ...zIndex < 0 ? { display: "none" } : {},
1308
+ ...!isActive && !pinnedOnTop && !(swipingParentKey && windowKey === swipingParentKey) ? { display: "none" } : {}
1309
+ } : {
1310
+ zIndex: pinnedOnTop ? 999 : zIndex + 1,
1311
+ width: box.w,
1312
+ height: autoHeight ? "auto" : box.h,
1313
+ top: box.y,
1314
+ ...autoHeight ? {
1315
+ // Widgets must fit content exactly (Weather, Currency, etc.) —
1316
+ // the 240 px floor only applies to non-widget app windows where
1317
+ // a near-empty body would look broken.
1318
+ minHeight: `${autoMinHeight ?? (widget ? 0 : 240)}px`,
1319
+ maxHeight: `calc(100vh - var(--taskbar-height, 0px) - 24px)`
1320
+ } : {},
1321
+ ...widget && widgetAnchor === "right" ? { right: window.innerWidth - box.x - box.w } : { left: box.x },
1322
+ ...zIndex < 0 && !pinnedOnTop ? { display: "none" } : {},
1323
+ ...exposeStyle ?? {}
1324
+ },
1325
+ children: [
1326
+ isMobile && !widget && /* @__PURE__ */ jsx(
1201
1327
  "div",
1202
1328
  {
1203
- onPointerDown: startDrag,
1204
- className: `flex items-center justify-between px-3 py-1.5 border-b border-gray-200 shrink-0 cursor-move select-none rounded-t-lg ${isActive ? "backdrop-blur-sm" : ""}`,
1205
- style: { touchAction: "none", backgroundColor: isActive ? `rgb(var(--window-header-rgb) / var(--active-header-opacity, 0.8))` : `rgb(var(--window-header-rgb) / var(--inactive-header-opacity, 0.7))` },
1206
- children: [
1207
- /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium min-w-0 flex-1 truncate flex items-center gap-1.5", style: { color: isActive ? "rgb(17 24 39)" : "rgb(156 163 175)" }, children: [
1208
- renderIconButton(),
1209
- /* @__PURE__ */ jsx("span", { className: "truncate", children: displayTitle })
1210
- ] }),
1211
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0 ml-2", children: [
1212
- allowPinOnTop && /* @__PURE__ */ jsx(
1213
- "button",
1214
- {
1215
- onClick: () => setPinnedOnTop((p) => !p),
1216
- title: pinnedOnTop ? "Unpin from top" : "Pin on top",
1217
- className: `p-0.5 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
1218
- children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
1219
- }
1220
- ),
1221
- /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded p-0.5 text-gray-400 hover:text-gray-600 hover:bg-gray-200", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-4 w-4" }) })
1222
- ] })
1223
- ]
1329
+ onPointerDown: handleEdgePointerDown,
1330
+ className: "absolute top-0 bottom-0 left-0 w-[22px] z-[5]",
1331
+ style: { touchAction: "pan-y" },
1332
+ "aria-hidden": "true"
1224
1333
  }
1225
- )
1226
- ) : appStyle ? (
1227
- /* App style: small title bar like compact, but keeps minimize/maximize for full window control. */
1228
- /* @__PURE__ */ jsxs(
1334
+ ),
1335
+ widget ? (
1336
+ /* Widget: no title bar drag via body, close via right-click context menu */
1337
+ null
1338
+ ) : isMobile ? null : compact ? (
1339
+ /* Compact: smaller title bar with title + close only */
1340
+ /* @__PURE__ */ jsxs(
1341
+ "div",
1342
+ {
1343
+ onPointerDown: startDrag,
1344
+ className: `flex items-center justify-between px-3 py-1.5 border-b border-gray-200 shrink-0 cursor-move select-none rounded-t-lg ${isActive ? "backdrop-blur-sm" : ""}`,
1345
+ style: { touchAction: "none", backgroundColor: isActive ? `rgb(var(--window-header-rgb) / var(--active-header-opacity, 0.8))` : `rgb(var(--window-header-rgb) / var(--inactive-header-opacity, 0.7))` },
1346
+ children: [
1347
+ /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium min-w-0 flex-1 truncate flex items-center gap-1.5", style: { color: isActive ? "rgb(17 24 39)" : "rgb(156 163 175)" }, children: [
1348
+ renderIconButton(),
1349
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: displayTitle })
1350
+ ] }),
1351
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0 ml-2", children: [
1352
+ allowPinOnTop && /* @__PURE__ */ jsx(
1353
+ "button",
1354
+ {
1355
+ onClick: () => setPinnedOnTop((p) => !p),
1356
+ title: pinnedOnTop ? "Unpin from top" : "Pin on top",
1357
+ className: `p-0.5 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
1358
+ children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
1359
+ }
1360
+ ),
1361
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded p-0.5 text-gray-400 hover:text-gray-600 hover:bg-gray-200", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-4 w-4" }) })
1362
+ ] })
1363
+ ]
1364
+ }
1365
+ )
1366
+ ) : appStyle ? (
1367
+ /* App style: small title bar like compact, but keeps minimize/maximize for full window control. */
1368
+ /* @__PURE__ */ jsxs(
1369
+ "div",
1370
+ {
1371
+ onPointerDown: startDrag,
1372
+ className: `flex items-center justify-between px-3 py-1.5 border-b border-gray-200 shrink-0 cursor-move select-none rounded-t-lg ${isActive ? "backdrop-blur-sm" : ""}`,
1373
+ style: { touchAction: "none", backgroundColor: isActive ? `rgb(var(--window-header-rgb) / var(--active-header-opacity, 0.8))` : `rgb(var(--window-header-rgb) / var(--inactive-header-opacity, 0.7))` },
1374
+ children: [
1375
+ /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium min-w-0 flex-1 truncate flex items-center gap-1.5", style: { color: isActive ? "rgb(17 24 39)" : "rgb(156 163 175)" }, children: [
1376
+ renderIconButton(),
1377
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: displayTitle })
1378
+ ] }),
1379
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 shrink-0 ml-2", children: [
1380
+ allowPinOnTop && /* @__PURE__ */ jsx(
1381
+ "button",
1382
+ {
1383
+ onClick: () => setPinnedOnTop((p) => !p),
1384
+ title: pinnedOnTop ? "Unpin from top" : "Pin on top",
1385
+ className: `p-0.5 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
1386
+ children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
1387
+ }
1388
+ ),
1389
+ /* @__PURE__ */ jsx("button", { onClick: () => {
1390
+ const idx = activationOrder.indexOf(modalId);
1391
+ if (idx !== -1) activationOrder.splice(idx, 1);
1392
+ activeListeners.forEach((fn) => fn());
1393
+ window.dispatchEvent(new CustomEvent("modal-reorder"));
1394
+ }, title: "Minimize", className: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none", children: "\u2500" }),
1395
+ /* @__PURE__ */ jsx("button", { onClick: () => {
1396
+ if (maximized) {
1397
+ setMaximized(false);
1398
+ setBox(calcWindowed());
1399
+ } else {
1400
+ reset();
1401
+ }
1402
+ }, title: maximized ? "Windowed" : "Maximize", className: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none", children: maximized ? "\u2750" : "\u2922" }),
1403
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded p-0.5 text-gray-400 hover:text-gray-600 hover:bg-gray-200", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-4 w-4" }) })
1404
+ ] })
1405
+ ]
1406
+ }
1407
+ )
1408
+ ) : /* @__PURE__ */ jsxs(
1229
1409
  "div",
1230
1410
  {
1231
1411
  onPointerDown: startDrag,
1232
- className: `flex items-center justify-between px-3 py-1.5 border-b border-gray-200 shrink-0 cursor-move select-none rounded-t-lg ${isActive ? "backdrop-blur-sm" : ""}`,
1412
+ className: `flex items-center justify-between px-4 py-2.5 border-b border-gray-200 shrink-0 cursor-move select-none rounded-t-lg ${isActive ? "backdrop-blur-sm" : ""}`,
1233
1413
  style: { touchAction: "none", backgroundColor: isActive ? `rgb(var(--window-header-rgb) / var(--active-header-opacity, 0.8))` : `rgb(var(--window-header-rgb) / var(--inactive-header-opacity, 0.7))` },
1234
1414
  children: [
1235
- /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium min-w-0 flex-1 truncate flex items-center gap-1.5", style: { color: isActive ? "rgb(17 24 39)" : "rgb(156 163 175)" }, children: [
1415
+ /* @__PURE__ */ jsxs("div", { className: "text-lg font-semibold min-w-0 flex-1 truncate flex items-center gap-2", style: { color: isActive ? "var(--window-title-active, rgb(17 24 39))" : "var(--window-title-inactive, rgb(156 163 175))" }, children: [
1236
1416
  renderIconButton(),
1237
1417
  /* @__PURE__ */ jsx("span", { className: "truncate", children: displayTitle })
1238
1418
  ] }),
1239
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 shrink-0 ml-2", children: [
1419
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0 ml-4", children: [
1420
+ hasNav && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 mr-1 text-[10px] text-gray-400", children: [
1421
+ /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 font-medium text-gray-500", children: "K" }),
1422
+ /* @__PURE__ */ jsx("span", { children: "Prev" }),
1423
+ /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 font-medium ml-1 text-gray-500", children: "J" }),
1424
+ /* @__PURE__ */ jsx("span", { children: "Next" })
1425
+ ] }),
1240
1426
  allowPinOnTop && /* @__PURE__ */ jsx(
1241
1427
  "button",
1242
1428
  {
1243
1429
  onClick: () => setPinnedOnTop((p) => !p),
1244
1430
  title: pinnedOnTop ? "Unpin from top" : "Pin on top",
1245
- className: `p-0.5 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
1246
- children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
1431
+ className: `text-xs px-2 py-1 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
1432
+ children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
1247
1433
  }
1248
1434
  ),
1249
1435
  /* @__PURE__ */ jsx("button", { onClick: () => {
@@ -1251,7 +1437,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1251
1437
  if (idx !== -1) activationOrder.splice(idx, 1);
1252
1438
  activeListeners.forEach((fn) => fn());
1253
1439
  window.dispatchEvent(new CustomEvent("modal-reorder"));
1254
- }, title: "Minimize", className: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none", children: "\u2500" }),
1440
+ }, title: "Minimize", className: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200", children: "\u2500" }),
1255
1441
  /* @__PURE__ */ jsx("button", { onClick: () => {
1256
1442
  if (maximized) {
1257
1443
  setMaximized(false);
@@ -1259,126 +1445,117 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1259
1445
  } else {
1260
1446
  reset();
1261
1447
  }
1262
- }, title: maximized ? "Windowed" : "Maximize", className: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none", children: maximized ? "\u2750" : "\u2922" }),
1263
- /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded p-0.5 text-gray-400 hover:text-gray-600 hover:bg-gray-200", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-4 w-4" }) })
1448
+ }, title: maximized ? "Windowed" : "Maximize", className: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200", children: maximized ? "\u2750" : "\u2922" }),
1449
+ /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 text-[10px] font-medium text-gray-400", children: "ESC" }),
1450
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded-md text-gray-400 hover:text-gray-600", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-5 w-5" }) })
1264
1451
  ] })
1265
1452
  ]
1266
1453
  }
1267
- )
1268
- ) : /* @__PURE__ */ jsxs(
1269
- "div",
1270
- {
1271
- onPointerDown: startDrag,
1272
- className: `flex items-center justify-between px-4 py-2.5 border-b border-gray-200 shrink-0 cursor-move select-none rounded-t-lg ${isActive ? "backdrop-blur-sm" : ""}`,
1273
- style: { touchAction: "none", backgroundColor: isActive ? `rgb(var(--window-header-rgb) / var(--active-header-opacity, 0.8))` : `rgb(var(--window-header-rgb) / var(--inactive-header-opacity, 0.7))` },
1274
- children: [
1275
- /* @__PURE__ */ jsxs("div", { className: "text-lg font-semibold min-w-0 flex-1 truncate flex items-center gap-2", style: { color: isActive ? "var(--window-title-active, rgb(17 24 39))" : "var(--window-title-inactive, rgb(156 163 175))" }, children: [
1276
- renderIconButton(),
1277
- /* @__PURE__ */ jsx("span", { className: "truncate", children: displayTitle })
1278
- ] }),
1279
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0 ml-4", children: [
1280
- hasNav && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 mr-1 text-[10px] text-gray-400", children: [
1281
- /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 font-medium text-gray-500", children: "K" }),
1282
- /* @__PURE__ */ jsx("span", { children: "Prev" }),
1283
- /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 font-medium ml-1 text-gray-500", children: "J" }),
1284
- /* @__PURE__ */ jsx("span", { children: "Next" })
1285
- ] }),
1286
- allowPinOnTop && /* @__PURE__ */ jsx(
1287
- "button",
1288
- {
1289
- onClick: () => setPinnedOnTop((p) => !p),
1290
- title: pinnedOnTop ? "Unpin from top" : "Pin on top",
1291
- className: `text-xs px-2 py-1 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
1292
- children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
1293
- }
1294
- ),
1295
- /* @__PURE__ */ jsx("button", { onClick: () => {
1296
- const idx = activationOrder.indexOf(modalId);
1297
- if (idx !== -1) activationOrder.splice(idx, 1);
1298
- activeListeners.forEach((fn) => fn());
1299
- window.dispatchEvent(new CustomEvent("modal-reorder"));
1300
- }, title: "Minimize", className: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200", children: "\u2500" }),
1301
- /* @__PURE__ */ jsx("button", { onClick: () => {
1302
- if (maximized) {
1303
- setMaximized(false);
1304
- setBox(calcWindowed());
1305
- } else {
1306
- reset();
1307
- }
1308
- }, title: maximized ? "Windowed" : "Maximize", className: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200", children: maximized ? "\u2750" : "\u2922" }),
1309
- /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 text-[10px] font-medium text-gray-400", children: "ESC" }),
1310
- /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded-md text-gray-400 hover:text-gray-600", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-5 w-5" }) })
1311
- ] })
1312
- ]
1313
- }
1314
- ),
1315
- /* @__PURE__ */ jsx(ModalIdContext.Provider, { value: modalId, children: /* @__PURE__ */ jsx(ModalActionsContext.Provider, { value: { rightRef: actionsRef, leftRef: actionsLeftRef, notify: () => setHasActions(true), active: isActive, isDirty }, children: /* @__PURE__ */ jsx(
1316
- "div",
1317
- {
1318
- ...widget ? { onPointerDown: startDrag, onContextMenu: (e) => {
1319
- e.preventDefault();
1320
- setCtxMenu({ x: e.clientX, y: e.clientY });
1321
- } } : {},
1322
- className: `flex-1 min-h-0 flex flex-col ${widget ? "p-0 cursor-move" : appStyle ? "p-0" : compact ? "p-2" : "p-4"} ${widget ? "" : "backdrop-blur-sm"} ${bodyScroll === false || appStyle ? "overflow-hidden" : "overflow-y-auto"} ${widget ? "rounded-lg select-none" : ""}`,
1323
- style: { ...widget ? { touchAction: "none" } : {}, backgroundColor: widget ? "transparent" : isActive ? `rgb(var(--window-content-rgb) / var(--active-content-opacity, 0.9))` : `rgb(var(--window-content-rgb) / var(--inactive-content-opacity, 0.8))` },
1324
- children
1325
- }
1326
- ) }) }),
1327
- widget && ctxMenu && /* @__PURE__ */ jsxs(PopupMenu, { minWidth: 160, style: { left: ctxMenu.x, top: ctxMenu.y }, onClose: () => setCtxMenu(null), children: [
1328
- /* @__PURE__ */ jsx(PopupMenuItem, { onClick: () => {
1329
- setCtxMenu(null);
1330
- window.dispatchEvent(new CustomEvent("widget-open-settings", { detail: modalId }));
1331
- }, children: "Settings" }),
1332
- /* @__PURE__ */ jsx(PopupMenuDivider, {}),
1333
- widgetMenu && /* @__PURE__ */ jsxs(Fragment, { children: [
1334
- widgetMenu,
1335
- /* @__PURE__ */ jsx(PopupMenuDivider, {})
1454
+ ),
1455
+ /* @__PURE__ */ jsx(ModalIdContext.Provider, { value: modalId, children: /* @__PURE__ */ jsx(ModalActionsContext.Provider, { value: { rightRef: actionsRef, leftRef: actionsLeftRef, notify: () => setHasActions(true), active: isActive, isDirty }, children: /* @__PURE__ */ jsx(
1456
+ "div",
1457
+ {
1458
+ ...widget ? { onPointerDown: startDrag, onContextMenu: (e) => {
1459
+ e.preventDefault();
1460
+ setCtxMenu({ x: e.clientX, y: e.clientY });
1461
+ } } : {},
1462
+ className: `flex-1 min-h-0 flex flex-col ${widget ? "p-0 cursor-move" : appStyle ? "p-0" : compact ? "p-2" : "p-4"} ${widget ? "" : "backdrop-blur-sm"} ${bodyScroll === false || appStyle ? "overflow-hidden" : "overflow-y-auto"} ${widget ? "rounded-lg select-none" : ""}`,
1463
+ style: { ...widget ? { touchAction: "none" } : {}, backgroundColor: widget ? "transparent" : isActive ? `rgb(var(--window-content-rgb) / var(--active-content-opacity, 0.9))` : `rgb(var(--window-content-rgb) / var(--inactive-content-opacity, 0.8))` },
1464
+ children
1465
+ }
1466
+ ) }) }),
1467
+ widget && ctxMenu && /* @__PURE__ */ jsxs(PopupMenu, { minWidth: 160, style: { left: ctxMenu.x, top: ctxMenu.y }, onClose: () => setCtxMenu(null), children: [
1468
+ /* @__PURE__ */ jsx(PopupMenuItem, { onClick: () => {
1469
+ setCtxMenu(null);
1470
+ window.dispatchEvent(new CustomEvent("widget-open-settings", { detail: modalId }));
1471
+ }, children: "Settings" }),
1472
+ /* @__PURE__ */ jsx(PopupMenuDivider, {}),
1473
+ widgetMenu && /* @__PURE__ */ jsxs(Fragment, { children: [
1474
+ widgetMenu,
1475
+ /* @__PURE__ */ jsx(PopupMenuDivider, {})
1476
+ ] }),
1477
+ /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
1478
+ setCtxMenu(null);
1479
+ setPinnedOnTop((p) => !p);
1480
+ }, children: [
1481
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "Always on Top" }),
1482
+ pinnedOnTop && /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-blue-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) })
1483
+ ] }),
1484
+ /* @__PURE__ */ jsx(PopupMenuDivider, {}),
1485
+ /* @__PURE__ */ jsx(PopupMenuItem, { onClick: () => {
1486
+ setCtxMenu(null);
1487
+ guardedClose();
1488
+ }, children: "Close" })
1336
1489
  ] }),
1337
- /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
1338
- setCtxMenu(null);
1339
- setPinnedOnTop((p) => !p);
1340
- }, children: [
1341
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: "Always on Top" }),
1342
- pinnedOnTop && /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-blue-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) })
1490
+ /* @__PURE__ */ jsxs(
1491
+ "div",
1492
+ {
1493
+ onPointerDown: startDrag,
1494
+ className: `px-4 py-2 border-t border-gray-200 shrink-0 flex items-center justify-between text-xs select-none cursor-move${isActive ? " backdrop-blur-sm" : ""}${widget || compact || appStyle || isMobile || !footer && !hasActions && !actions && !actionsLeft ? " hidden" : ""}`,
1495
+ style: { touchAction: "none", backgroundColor: isActive ? `rgb(var(--window-footer-rgb) / var(--active-header-opacity, 0.8))` : `rgb(var(--window-footer-rgb) / var(--inactive-header-opacity, 0.7))` },
1496
+ children: [
1497
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
1498
+ actionsLeft,
1499
+ /* @__PURE__ */ jsx("div", { ref: actionsLeftRef, "data-modal-actions-left": true, className: "flex items-center gap-2" }),
1500
+ footer
1501
+ ] }),
1502
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 ml-auto", children: [
1503
+ /* @__PURE__ */ jsx("div", { ref: actionsRef, "data-modal-actions": true, className: "flex items-center gap-2" }),
1504
+ actions
1505
+ ] })
1506
+ ]
1507
+ }
1508
+ ),
1509
+ !widget && !isMobile && !exposeActive && isActive && /* @__PURE__ */ jsxs(Fragment, { children: [
1510
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "se"), className: "absolute bottom-0 right-0 w-3 h-3 cursor-nwse-resize z-10" }),
1511
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "sw"), className: "absolute bottom-0 left-0 w-3 h-3 cursor-nesw-resize z-10" }),
1512
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "ne"), className: "absolute top-0 right-0 w-3 h-3 cursor-nesw-resize z-10" }),
1513
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "nw"), className: "absolute top-0 left-0 w-3 h-3 cursor-nwse-resize z-10" }),
1514
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "n"), className: "absolute top-0 left-3 right-3 h-1 cursor-ns-resize" }),
1515
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "s"), className: "absolute bottom-0 left-3 right-3 h-1 cursor-ns-resize" }),
1516
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "e"), className: "absolute top-3 bottom-3 right-0 w-1 cursor-ew-resize" }),
1517
+ /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "w"), className: "absolute top-3 bottom-3 left-0 w-1 cursor-ew-resize" })
1343
1518
  ] }),
1344
- /* @__PURE__ */ jsx(PopupMenuDivider, {}),
1345
- /* @__PURE__ */ jsx(PopupMenuItem, { onClick: () => {
1346
- setCtxMenu(null);
1347
- guardedClose();
1348
- }, children: "Close" })
1349
- ] }),
1350
- /* @__PURE__ */ jsxs(
1351
- "div",
1352
- {
1353
- onPointerDown: startDrag,
1354
- className: `px-4 py-2 border-t border-gray-200 shrink-0 flex items-center justify-between text-xs select-none cursor-move${isActive ? " backdrop-blur-sm" : ""}${widget || compact || appStyle || isMobile || !footer && !hasActions && !actions && !actionsLeft ? " hidden" : ""}`,
1355
- style: { touchAction: "none", backgroundColor: isActive ? `rgb(var(--window-footer-rgb) / var(--active-header-opacity, 0.8))` : `rgb(var(--window-footer-rgb) / var(--inactive-header-opacity, 0.7))` },
1356
- children: [
1357
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
1358
- actionsLeft,
1359
- /* @__PURE__ */ jsx("div", { ref: actionsLeftRef, "data-modal-actions-left": true, className: "flex items-center gap-2" }),
1360
- footer
1361
- ] }),
1362
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 ml-auto", children: [
1363
- /* @__PURE__ */ jsx("div", { ref: actionsRef, "data-modal-actions": true, className: "flex items-center gap-2" }),
1364
- actions
1365
- ] })
1366
- ]
1367
- }
1368
- ),
1369
- !widget && !isMobile && isActive && /* @__PURE__ */ jsxs(Fragment, { children: [
1370
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "se"), className: "absolute bottom-0 right-0 w-3 h-3 cursor-nwse-resize z-10" }),
1371
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "sw"), className: "absolute bottom-0 left-0 w-3 h-3 cursor-nesw-resize z-10" }),
1372
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "ne"), className: "absolute top-0 right-0 w-3 h-3 cursor-nesw-resize z-10" }),
1373
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "nw"), className: "absolute top-0 left-0 w-3 h-3 cursor-nwse-resize z-10" }),
1374
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "n"), className: "absolute top-0 left-3 right-3 h-1 cursor-ns-resize" }),
1375
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "s"), className: "absolute bottom-0 left-3 right-3 h-1 cursor-ns-resize" }),
1376
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "e"), className: "absolute top-3 bottom-3 right-0 w-1 cursor-ew-resize" }),
1377
- /* @__PURE__ */ jsx("div", { onPointerDown: (e) => startResizeCorner(e, "w"), className: "absolute top-3 bottom-3 left-0 w-1 cursor-ew-resize" })
1378
- ] })
1379
- ]
1380
- }
1381
- ) });
1519
+ exposeActive && /* @__PURE__ */ jsx(
1520
+ "div",
1521
+ {
1522
+ className: "absolute inset-0",
1523
+ style: { zIndex: 9999, cursor: "pointer", background: "transparent" },
1524
+ onMouseEnter: () => setExposeHovered(true),
1525
+ onMouseLeave: () => setExposeHovered(false),
1526
+ onMouseDown: (e) => {
1527
+ e.stopPropagation();
1528
+ e.preventDefault();
1529
+ activateModal(modalId);
1530
+ setExposeState(false);
1531
+ },
1532
+ onClick: (e) => {
1533
+ e.stopPropagation();
1534
+ e.preventDefault();
1535
+ }
1536
+ }
1537
+ )
1538
+ ]
1539
+ }
1540
+ ),
1541
+ exposeActive && exposeTile && /* @__PURE__ */ jsx(
1542
+ "div",
1543
+ {
1544
+ className: "fixed pointer-events-none select-none truncate text-center",
1545
+ style: {
1546
+ left: exposeTile.x,
1547
+ top: exposeTile.y + exposeTile.h + 4,
1548
+ width: exposeTile.w,
1549
+ zIndex: exposeHovered ? 2021 : 2011,
1550
+ color: "white",
1551
+ fontSize: 12,
1552
+ fontWeight: 500,
1553
+ textShadow: "0 1px 2px rgba(0,0,0,0.6)"
1554
+ },
1555
+ children: displayTitle
1556
+ }
1557
+ )
1558
+ ] });
1382
1559
  const windowMenuEl = windowMenu && /* @__PURE__ */ jsxs(PopupMenu, { style: { left: windowMenu.x, top: windowMenu.y }, onClose: () => setWindowMenu(null), minWidth: 160, children: [
1383
1560
  !widget && !compact && /* @__PURE__ */ jsxs(Fragment, { children: [
1384
1561
  /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
@@ -1863,10 +2040,16 @@ function TaskbarWindows({ openWindows, onRemove, onCloseAll, onSplitView, onActi
1863
2040
  "button",
1864
2041
  {
1865
2042
  onClick: onSplitView,
2043
+ title: "Expos\xE9 \u2014 show all open windows as thumbnails",
1866
2044
  className: "flex items-center gap-1 rounded px-2 py-1 text-[11px] font-medium text-blue-600 border border-blue-300 hover:bg-blue-50 transition-colors shrink-0",
1867
2045
  children: [
1868
- /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 4H5a1 1 0 00-1 1v14a1 1 0 001 1h4m6-16h4a1 1 0 011 1v14a1 1 0 01-1 1h-4m-6 0V4" }) }),
1869
- "Split"
2046
+ /* @__PURE__ */ jsxs("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [
2047
+ /* @__PURE__ */ jsx("rect", { x: "3.5", y: "3.5", width: "7", height: "7", rx: "1" }),
2048
+ /* @__PURE__ */ jsx("rect", { x: "13.5", y: "3.5", width: "7", height: "7", rx: "1" }),
2049
+ /* @__PURE__ */ jsx("rect", { x: "3.5", y: "13.5", width: "7", height: "7", rx: "1" }),
2050
+ /* @__PURE__ */ jsx("rect", { x: "13.5", y: "13.5", width: "7", height: "7", rx: "1" })
2051
+ ] }),
2052
+ "Expos\xE9"
1870
2053
  ]
1871
2054
  }
1872
2055
  ),
@@ -2034,6 +2217,7 @@ function WindowManagerProvider({ children }) {
2034
2217
  }
2035
2218
  }
2036
2219
  ),
2220
+ /* @__PURE__ */ jsx(ExposeBackdrop, {}),
2037
2221
  !isAuthPage && openWindows.map((item) => item.type === "page" ? /* @__PURE__ */ jsx(PageWindow, { item, onClose: () => closeEntity(item.id) }, item.id) : /* @__PURE__ */ jsx(
2038
2222
  RestoredRegistryModal,
2039
2223
  {
@@ -2048,5 +2232,5 @@ function WindowManagerProvider({ children }) {
2048
2232
  }
2049
2233
 
2050
2234
  export { CancelButton, CopyButton, DocFavStar, GLASS_DIVIDER, GLASS_INPUT_BG, LoadingSpinner, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ThumbCard, WINDOW_REGISTRY, WindowManagerProvider, WindowTitle, activateModal, client_default, getActiveModalId, glassStyle, isEntityEntry, isPageEntry, isSection, navIcons, navSections, sectionIcons, setShellApiClient, setShellNavIcons, setShellWindowRegistry, startMenuCategories, useIsMobile, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle };
2051
- //# sourceMappingURL=chunk-QXY6ZHRX.js.map
2052
- //# sourceMappingURL=chunk-QXY6ZHRX.js.map
2235
+ //# sourceMappingURL=chunk-I7GRSFIL.js.map
2236
+ //# sourceMappingURL=chunk-I7GRSFIL.js.map