flexdesk 0.13.0 → 0.14.0
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.
- package/README.md +53 -0
- package/css/flexdesk.css +99 -0
- package/dist/flexdesk.css +99 -0
- package/dist/flow.js +3 -0
- package/dist/flow.js.map +2 -2
- package/dist/host.js +138 -0
- package/dist/host.js.map +3 -3
- package/dist/widgets.js +563 -5
- package/dist/widgets.js.map +3 -3
- package/dist/wm.js +146 -0
- package/dist/wm.js.map +3 -3
- package/package.json +1 -1
- package/src/flow/kit/dom.js +6 -0
- package/src/host/photino_host.js +176 -0
- package/src/host/photino_host.md +98 -0
- package/src/tiling/bottom_panel_tabs.js +201 -0
- package/src/ui/components/alert_log.js +274 -0
- package/src/ui/components/alerts_pane.js +294 -0
- package/src/ui/components/notification_history.js +54 -4
- package/src/ui/utils/auto_scrollbars.js +30 -0
package/dist/wm.js
CHANGED
|
@@ -16,6 +16,150 @@ import {
|
|
|
16
16
|
import "./chunk-WVFGV5FT.js";
|
|
17
17
|
import "./chunk-JYWURG5T.js";
|
|
18
18
|
|
|
19
|
+
// src/tiling/bottom_panel_tabs.js
|
|
20
|
+
var BADGE_LEVELS = Object.freeze(["info", "warning", "alert"]);
|
|
21
|
+
function createBottomPanelTabs(container, {
|
|
22
|
+
panes = [],
|
|
23
|
+
remember = null,
|
|
24
|
+
store = null,
|
|
25
|
+
eventBus = null,
|
|
26
|
+
onSelect = null,
|
|
27
|
+
initial = null
|
|
28
|
+
} = {}) {
|
|
29
|
+
const doc = container.ownerDocument;
|
|
30
|
+
const root = doc.createElement("div");
|
|
31
|
+
root.className = "twm-bp";
|
|
32
|
+
const strip = doc.createElement("div");
|
|
33
|
+
strip.className = "twm-bp__tabs";
|
|
34
|
+
strip.setAttribute("role", "tablist");
|
|
35
|
+
const body = doc.createElement("div");
|
|
36
|
+
body.className = "twm-bp__body";
|
|
37
|
+
root.append(strip, body);
|
|
38
|
+
container.appendChild(root);
|
|
39
|
+
const byId = new Map(panes.map((pane) => [pane.id, pane]));
|
|
40
|
+
const tabs = /* @__PURE__ */ new Map();
|
|
41
|
+
const mounted = /* @__PURE__ */ new Map();
|
|
42
|
+
let active = null;
|
|
43
|
+
let chosen = false;
|
|
44
|
+
let destroyed = false;
|
|
45
|
+
for (const pane of panes) {
|
|
46
|
+
const tab = doc.createElement("button");
|
|
47
|
+
tab.type = "button";
|
|
48
|
+
tab.className = "twm-bp__tab";
|
|
49
|
+
tab.dataset.pane = pane.id;
|
|
50
|
+
tab.setAttribute("role", "tab");
|
|
51
|
+
tab.setAttribute("aria-selected", "false");
|
|
52
|
+
const label = doc.createElement("span");
|
|
53
|
+
label.className = "twm-bp__label";
|
|
54
|
+
label.textContent = pane.label;
|
|
55
|
+
const badge = doc.createElement("span");
|
|
56
|
+
badge.className = "twm-bp__badge";
|
|
57
|
+
badge.hidden = true;
|
|
58
|
+
tab.append(label, badge);
|
|
59
|
+
tab.addEventListener("click", () => api.select(pane.id));
|
|
60
|
+
strip.appendChild(tab);
|
|
61
|
+
tabs.set(pane.id, tab);
|
|
62
|
+
}
|
|
63
|
+
function mount(id) {
|
|
64
|
+
if (mounted.has(id)) return mounted.get(id);
|
|
65
|
+
const pane = byId.get(id);
|
|
66
|
+
const el = doc.createElement("div");
|
|
67
|
+
el.className = "twm-bp-pane";
|
|
68
|
+
el.dataset.pane = id;
|
|
69
|
+
el.setAttribute("role", "tabpanel");
|
|
70
|
+
el.hidden = id !== active;
|
|
71
|
+
body.appendChild(el);
|
|
72
|
+
const entry = { el, instance: null };
|
|
73
|
+
mounted.set(id, entry);
|
|
74
|
+
try {
|
|
75
|
+
entry.instance = pane.mount?.(el, store ? store(pane) : null, api) ?? null;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
console.error(`[bottom-panel] pane "${id}" failed to mount`, err);
|
|
78
|
+
}
|
|
79
|
+
return entry;
|
|
80
|
+
}
|
|
81
|
+
function show(id) {
|
|
82
|
+
if (destroyed || !byId.has(id)) return false;
|
|
83
|
+
active = id;
|
|
84
|
+
for (const [key, tab] of tabs) {
|
|
85
|
+
const on = key === id;
|
|
86
|
+
tab.classList.toggle("twm-bp__tab--on", on);
|
|
87
|
+
tab.setAttribute("aria-selected", String(on));
|
|
88
|
+
}
|
|
89
|
+
for (const [key, entry] of mounted) entry.el.hidden = key !== id;
|
|
90
|
+
mount(id).instance?.onShow?.();
|
|
91
|
+
onSelect?.(id, byId.get(id));
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
const api = {
|
|
95
|
+
root,
|
|
96
|
+
/** Bring a tab to the front, and remember it. */
|
|
97
|
+
select(id) {
|
|
98
|
+
if (!show(id)) return;
|
|
99
|
+
chosen = true;
|
|
100
|
+
try {
|
|
101
|
+
remember?.write?.(id);
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
/** The tab in front, or null. */
|
|
106
|
+
active: () => active,
|
|
107
|
+
/** `count` on a tab, coloured by `level`; nothing at zero. */
|
|
108
|
+
setBadge(id, count, level = null) {
|
|
109
|
+
const badge = tabs.get(id)?.querySelector(".twm-bp__badge");
|
|
110
|
+
if (!badge) return;
|
|
111
|
+
const n = Number(count) || 0;
|
|
112
|
+
badge.hidden = n <= 0;
|
|
113
|
+
badge.textContent = n > 99 ? "99+" : String(Math.max(n, 0));
|
|
114
|
+
badge.className = "twm-bp__badge" + (BADGE_LEVELS.includes(level) ? ` twm-bp__badge--${level}` : "");
|
|
115
|
+
},
|
|
116
|
+
/** A mounted pane's live instance, or null — how one tab hands work to
|
|
117
|
+
* another. `select` it first, which mounts it. */
|
|
118
|
+
instance: (id) => mounted.get(id)?.instance ?? null,
|
|
119
|
+
/** The panel is on screen again (its tile re-mounted): tell the pane in front. */
|
|
120
|
+
reshow() {
|
|
121
|
+
if (active) mounted.get(active)?.instance?.onShow?.();
|
|
122
|
+
},
|
|
123
|
+
/** Before the panel is torn down: every mounted pane saves. */
|
|
124
|
+
async persist() {
|
|
125
|
+
for (const entry of mounted.values()) await entry.instance?.persist?.();
|
|
126
|
+
},
|
|
127
|
+
/** Gone for good: panes save, then are destroyed; the bus is let go. */
|
|
128
|
+
async destroy() {
|
|
129
|
+
if (destroyed) return;
|
|
130
|
+
await api.persist();
|
|
131
|
+
destroyed = true;
|
|
132
|
+
try {
|
|
133
|
+
subscription?.dispose?.();
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
for (const entry of mounted.values()) {
|
|
137
|
+
try {
|
|
138
|
+
entry.instance?.destroy?.();
|
|
139
|
+
} catch (err) {
|
|
140
|
+
console.warn("[bottom-panel] pane destroy failed", err);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
mounted.clear();
|
|
144
|
+
root.remove();
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
for (const pane of panes) if (pane.eager) mount(pane.id);
|
|
148
|
+
const subscription = eventBus?.on?.(
|
|
149
|
+
"bottompanel:show",
|
|
150
|
+
(payload) => api.select(payload?.tab ?? panes[0]?.id)
|
|
151
|
+
) ?? null;
|
|
152
|
+
show(byId.has(initial) ? initial : panes[0]?.id);
|
|
153
|
+
if (remember?.read) {
|
|
154
|
+
Promise.resolve().then(() => remember.read()).then((saved) => {
|
|
155
|
+
if (chosen || destroyed) return;
|
|
156
|
+
if (byId.has(saved)) show(saved);
|
|
157
|
+
}).catch(() => {
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return api;
|
|
161
|
+
}
|
|
162
|
+
|
|
19
163
|
// src/tiling/command_palette.js
|
|
20
164
|
var ROOT_ID = "twm-cmdpal";
|
|
21
165
|
var STATIC_COMMANDS = [
|
|
@@ -8732,6 +8876,7 @@ function _tileContextMenu(wm, leafId, x, y) {
|
|
|
8732
8876
|
});
|
|
8733
8877
|
}
|
|
8734
8878
|
export {
|
|
8879
|
+
BADGE_LEVELS,
|
|
8735
8880
|
DesktopManager,
|
|
8736
8881
|
PLACEHOLDER_KIND,
|
|
8737
8882
|
PanelKeyRouter,
|
|
@@ -8751,6 +8896,7 @@ export {
|
|
|
8751
8896
|
attachLandingShell,
|
|
8752
8897
|
attachLandingTableBehavior,
|
|
8753
8898
|
clampZoom,
|
|
8899
|
+
createBottomPanelTabs,
|
|
8754
8900
|
createCommandPalette,
|
|
8755
8901
|
createContentRegistry,
|
|
8756
8902
|
createEntityCatalog,
|