@daydreamui/pages 0.0.0-stage → 0.3.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/dist/index.js +1421 -0
- package/icon.svg +5 -0
- package/manifest.json +17 -0
- package/package.json +15 -4
- package/README.md +0 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,1421 @@
|
|
|
1
|
+
import { className, createComponent, delegateEvents, effect, insert, memo, ref, setAttribute, setStyleProperty, template } from "@solidjs/web";
|
|
2
|
+
import { For, Show, createEffect, createMemo, createSignal, untrack } from "solid-js";
|
|
3
|
+
var DEFAULT_FRAME = { width: 960 };
|
|
4
|
+
function pageRows(doc, viewports) {
|
|
5
|
+
const byPage = new Map();
|
|
6
|
+
for (const viewport of viewports) {
|
|
7
|
+
const ids = byPage.get(viewport.payload.page) ?? [];
|
|
8
|
+
ids.push(viewport.id);
|
|
9
|
+
byPage.set(viewport.payload.page, ids);
|
|
10
|
+
}
|
|
11
|
+
return doc.pages.map(({ path, meta }) => {
|
|
12
|
+
const slash = path.lastIndexOf("/");
|
|
13
|
+
return {
|
|
14
|
+
path,
|
|
15
|
+
variantOf: meta?.variantOf,
|
|
16
|
+
folder: path.slice(0, slash + 1),
|
|
17
|
+
name: path.slice(slash + 1),
|
|
18
|
+
viewports: byPage.get(path) ?? []
|
|
19
|
+
};
|
|
20
|
+
}).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
21
|
+
}
|
|
22
|
+
function listPages(rows, view, query, titles) {
|
|
23
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
24
|
+
const visible = new Set(rows.filter((row) => `${row.path} ${titles.get(row.path) ?? ""}`.toLocaleLowerCase().includes(needle)).map((row) => row.path));
|
|
25
|
+
if (view === "list") return rows.filter((row) => visible.has(row.path)).map((row) => ({
|
|
26
|
+
...row,
|
|
27
|
+
depth: 0,
|
|
28
|
+
last: true
|
|
29
|
+
}));
|
|
30
|
+
const byPath = new Map(rows.map((row) => [row.path, row]));
|
|
31
|
+
const children = new Map();
|
|
32
|
+
for (const row of rows) if (row.variantOf && byPath.has(row.variantOf) && row.variantOf !== row.path) {
|
|
33
|
+
const siblings = children.get(row.variantOf) ?? [];
|
|
34
|
+
siblings.push(row);
|
|
35
|
+
children.set(row.variantOf, siblings);
|
|
36
|
+
}
|
|
37
|
+
for (const path of [...visible]) {
|
|
38
|
+
const visited = new Set([path]);
|
|
39
|
+
let parent = byPath.get(path)?.variantOf;
|
|
40
|
+
while (parent && byPath.has(parent) && !visited.has(parent)) {
|
|
41
|
+
visible.add(parent);
|
|
42
|
+
visited.add(parent);
|
|
43
|
+
parent = byPath.get(parent)?.variantOf;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const result = [];
|
|
47
|
+
const visited = new Set();
|
|
48
|
+
const append = (row, depth, last) => {
|
|
49
|
+
if (visited.has(row.path) || !visible.has(row.path)) return;
|
|
50
|
+
visited.add(row.path);
|
|
51
|
+
result.push({
|
|
52
|
+
...row,
|
|
53
|
+
depth,
|
|
54
|
+
last
|
|
55
|
+
});
|
|
56
|
+
const family = (children.get(row.path) ?? []).filter((child) => visible.has(child.path) && !visited.has(child.path));
|
|
57
|
+
family.forEach((child, index) => append(child, depth + 1, index === family.length - 1));
|
|
58
|
+
};
|
|
59
|
+
rows.filter((row) => !row.variantOf || !byPath.has(row.variantOf) || row.variantOf === row.path).forEach((row) => append(row, 0, true));
|
|
60
|
+
rows.forEach((row) => append(row, 0, true));
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
function frameFor(page, viewports) {
|
|
64
|
+
for (let index = viewports.length - 1; index >= 0; index--) {
|
|
65
|
+
const viewport = viewports[index];
|
|
66
|
+
if (viewport.payload.page !== page) continue;
|
|
67
|
+
if (viewport.frame === void 0) break;
|
|
68
|
+
const { width, height } = viewport.frame;
|
|
69
|
+
return height === void 0 ? { width } : {
|
|
70
|
+
width,
|
|
71
|
+
height
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { ...DEFAULT_FRAME };
|
|
75
|
+
}
|
|
76
|
+
function centeredAt(center, frame) {
|
|
77
|
+
return {
|
|
78
|
+
x: Math.round(center.x - frame.width / 2),
|
|
79
|
+
y: Math.round(center.y - frame.width / 4)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function ghostSize(frame, zoom, rendered) {
|
|
83
|
+
if (rendered !== null && rendered.width > 0 && rendered.height > 0) return {
|
|
84
|
+
width: Math.round(rendered.width),
|
|
85
|
+
height: Math.round(rendered.height)
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
width: Math.round(frame.width * zoom),
|
|
89
|
+
height: Math.round((frame.height ?? frame.width * .625) * zoom)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function clearOf(position, taken) {
|
|
93
|
+
let { x, y } = position;
|
|
94
|
+
while (taken.some((at) => at.x === x && at.y === y)) {
|
|
95
|
+
x += 16;
|
|
96
|
+
y += 16;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
x,
|
|
100
|
+
y
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function emptyPage(title) {
|
|
104
|
+
return `<!doctype html>
|
|
105
|
+
<html lang="en">
|
|
106
|
+
<head>
|
|
107
|
+
<meta charset="utf-8">
|
|
108
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
109
|
+
<title>${title.trim().replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">")}</title>
|
|
110
|
+
<style>
|
|
111
|
+
html { background: #fff; }
|
|
112
|
+
</style>
|
|
113
|
+
</head>
|
|
114
|
+
<body>
|
|
115
|
+
</body>
|
|
116
|
+
</html>
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
function typedPagePath(from, typed) {
|
|
120
|
+
let path = typed.trim().replace(/^\/+/, "");
|
|
121
|
+
if (path === "") return path;
|
|
122
|
+
if (path.endsWith("/")) path += from.slice(from.lastIndexOf("/") + 1);
|
|
123
|
+
const extension = /\.html?$/i.exec(from)?.[0] ?? ".html";
|
|
124
|
+
const typedExtension = /\.html?$/i.exec(path)?.[0];
|
|
125
|
+
if (typedExtension === void 0) return `${path}${extension}`;
|
|
126
|
+
if (typedExtension.toLowerCase() !== extension.toLowerCase()) return path;
|
|
127
|
+
return `${path.slice(0, -typedExtension.length)}${extension}`;
|
|
128
|
+
}
|
|
129
|
+
function stemSpan(path) {
|
|
130
|
+
const start = path.lastIndexOf("/") + 1;
|
|
131
|
+
const extension = /\.html?$/i.exec(path)?.[0].length ?? 0;
|
|
132
|
+
return {
|
|
133
|
+
start,
|
|
134
|
+
end: path.length - extension
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
var dragType = (pluginId) => `application/x-${pluginId}-page`;
|
|
138
|
+
var taken = (dd) => dd.items().map((item) => item.position);
|
|
139
|
+
function placeViewport(dd, path, at) {
|
|
140
|
+
if (dd.page(path) === void 0) return null;
|
|
141
|
+
const frame = frameFor(path, dd.core.viewportItems(dd.document()));
|
|
142
|
+
const position = {
|
|
143
|
+
x: Math.round(at.x),
|
|
144
|
+
y: Math.round(at.y)
|
|
145
|
+
};
|
|
146
|
+
const id = dd.core.generateId();
|
|
147
|
+
try {
|
|
148
|
+
dd.mutateItems((items) => {
|
|
149
|
+
items.push({
|
|
150
|
+
id,
|
|
151
|
+
kind: dd.core.viewportKind,
|
|
152
|
+
position,
|
|
153
|
+
frame,
|
|
154
|
+
payload: { page: path }
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error(`[${dd.plugin.id}] could not place ${path}:`, error);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
dd.select(id);
|
|
162
|
+
return id;
|
|
163
|
+
}
|
|
164
|
+
function viewCenter(dd) {
|
|
165
|
+
const view = dd.canvas.visibleRect();
|
|
166
|
+
if (view.width === 0 || view.height === 0) return dd.canvas.center();
|
|
167
|
+
return {
|
|
168
|
+
x: view.x + view.width / 2,
|
|
169
|
+
y: view.y + view.height / 2
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function placeInView(dd, path) {
|
|
173
|
+
const frame = frameFor(path, dd.core.viewportItems(dd.document()));
|
|
174
|
+
return placeViewport(dd, path, clearOf(centeredAt(viewCenter(dd), frame), taken(dd)));
|
|
175
|
+
}
|
|
176
|
+
async function createEmptyPage(dd, title) {
|
|
177
|
+
const made = await dd.createPage(emptyPage(title), {
|
|
178
|
+
position: clearOf(centeredAt(viewCenter(dd), DEFAULT_FRAME), taken(dd)),
|
|
179
|
+
frame: { ...DEFAULT_FRAME }
|
|
180
|
+
});
|
|
181
|
+
dd.select(made.viewportId);
|
|
182
|
+
return made.path;
|
|
183
|
+
}
|
|
184
|
+
function startPageDrag(dd, path, event) {
|
|
185
|
+
const transfer = event.dataTransfer;
|
|
186
|
+
if (transfer === null || dd.page(path) === void 0) return;
|
|
187
|
+
transfer.setData(dragType(dd.plugin.id), path);
|
|
188
|
+
transfer.effectAllowed = "copy";
|
|
189
|
+
const viewports = dd.core.viewportItems(dd.document());
|
|
190
|
+
const last = viewports.filter((viewport) => viewport.payload.page === path).at(-1);
|
|
191
|
+
const size = ghostSize(frameFor(path, viewports), dd.geometry.camera().zoom, last === void 0 ? null : dd.geometry.itemRect(last.id));
|
|
192
|
+
const ghost = document.createElement("div");
|
|
193
|
+
ghost.textContent = path;
|
|
194
|
+
Object.assign(ghost.style, {
|
|
195
|
+
position: "fixed",
|
|
196
|
+
top: "-10000px",
|
|
197
|
+
left: "-10000px",
|
|
198
|
+
boxSizing: "border-box",
|
|
199
|
+
width: `${size.width}px`,
|
|
200
|
+
height: `${size.height}px`,
|
|
201
|
+
padding: "4px 6px",
|
|
202
|
+
fontSize: "11px",
|
|
203
|
+
lineHeight: "1.4",
|
|
204
|
+
color: "var(--dream-app-accent, #4c9aff)",
|
|
205
|
+
background: "color-mix(in srgb, var(--dream-app-accent, #4c9aff) 8%, transparent)",
|
|
206
|
+
border: "1px solid var(--dream-app-accent, #4c9aff)",
|
|
207
|
+
overflow: "hidden",
|
|
208
|
+
whiteSpace: "nowrap",
|
|
209
|
+
pointerEvents: "none"
|
|
210
|
+
});
|
|
211
|
+
if (event.currentTarget instanceof Element) ghost.style.setProperty("--dream-app-accent", getComputedStyle(event.currentTarget).getPropertyValue("--dream-app-accent"));
|
|
212
|
+
document.body.append(ghost);
|
|
213
|
+
transfer.setDragImage(ghost, 0, 0);
|
|
214
|
+
requestAnimationFrame(() => ghost.remove());
|
|
215
|
+
}
|
|
216
|
+
function registerDrop(dd) {
|
|
217
|
+
const type = dragType(dd.plugin.id);
|
|
218
|
+
dd.canvas.onDragOver((event) => {
|
|
219
|
+
if (!event.dataTransfer?.types.includes(type)) return;
|
|
220
|
+
event.preventDefault();
|
|
221
|
+
event.dataTransfer.dropEffect = "copy";
|
|
222
|
+
});
|
|
223
|
+
dd.canvas.onDrop((event) => {
|
|
224
|
+
const path = event.dataTransfer?.getData(type) ?? "";
|
|
225
|
+
if (path === "") return;
|
|
226
|
+
event.preventDefault();
|
|
227
|
+
placeViewport(dd, path, dd.canvas.screenToWorld(event.clientX, event.clientY));
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
var classPrefix = (pluginId) => pluginId.replace(/[^A-Za-z0-9_-]/g, "-");
|
|
231
|
+
var css = (p) => `
|
|
232
|
+
.${p}-panel {
|
|
233
|
+
--panel-text: var(--dream-app-text, #b8b8be);
|
|
234
|
+
--panel-bright: var(--dream-app-bright, #c8c8ce);
|
|
235
|
+
--panel-dim: var(--dream-app-dim, #9a9aa0);
|
|
236
|
+
--panel-muted: var(--dream-app-muted, #85858c);
|
|
237
|
+
--panel-line: var(--dream-app-line, #232326);
|
|
238
|
+
--panel-strong: var(--dream-app-line-strong, #3a3a40);
|
|
239
|
+
--panel-field: var(--dream-app-field, #1c1c20);
|
|
240
|
+
--panel-raised: var(--dream-app-raised, #1c1c20);
|
|
241
|
+
--panel-hover: var(--dream-app-hover, #232326);
|
|
242
|
+
--panel-selected: var(--dream-app-selection, #2d3a49);
|
|
243
|
+
--panel-accent: var(--dream-app-accent, #4c9aff);
|
|
244
|
+
--panel-danger: var(--dream-app-danger, #ba3541);
|
|
245
|
+
flex: 1 1 auto;
|
|
246
|
+
display: flex;
|
|
247
|
+
flex-direction: column;
|
|
248
|
+
min-height: 0;
|
|
249
|
+
min-width: 0;
|
|
250
|
+
container: ${p} / inline-size;
|
|
251
|
+
font-size: 12px;
|
|
252
|
+
line-height: 1.4;
|
|
253
|
+
color: var(--panel-text);
|
|
254
|
+
}
|
|
255
|
+
.${p}-panel *, .${p}-panel *::before, .${p}-panel *::after { box-sizing: border-box; }
|
|
256
|
+
.${p}-panel button, .${p}-panel input { font: inherit; }
|
|
257
|
+
.${p}-panel button { color: inherit; border: 0; background: none; cursor: pointer; }
|
|
258
|
+
.${p}-panel button:focus-visible, .${p}-panel input:focus-visible {
|
|
259
|
+
outline: 1px solid var(--panel-accent);
|
|
260
|
+
outline-offset: -1px;
|
|
261
|
+
}
|
|
262
|
+
.${p}-panel svg {
|
|
263
|
+
flex: none;
|
|
264
|
+
width: 12px;
|
|
265
|
+
height: 12px;
|
|
266
|
+
fill: none;
|
|
267
|
+
stroke: currentColor;
|
|
268
|
+
stroke-width: 1.25;
|
|
269
|
+
stroke-linecap: round;
|
|
270
|
+
stroke-linejoin: round;
|
|
271
|
+
}
|
|
272
|
+
.${p}-toolbar {
|
|
273
|
+
flex: none;
|
|
274
|
+
display: flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
gap: 6px;
|
|
277
|
+
padding: 4px 14px 8px;
|
|
278
|
+
}
|
|
279
|
+
.${p}-search-field {
|
|
280
|
+
flex: 1;
|
|
281
|
+
min-width: 0;
|
|
282
|
+
display: flex;
|
|
283
|
+
align-items: center;
|
|
284
|
+
gap: 6px;
|
|
285
|
+
min-height: 28px;
|
|
286
|
+
padding: 0 7px;
|
|
287
|
+
color: var(--panel-muted);
|
|
288
|
+
background: var(--panel-field);
|
|
289
|
+
border: 1px solid var(--panel-line);
|
|
290
|
+
border-radius: 3px;
|
|
291
|
+
}
|
|
292
|
+
/* Match the agent composer's quiet, warm focus edge. */
|
|
293
|
+
.${p}-search-field:focus-within {
|
|
294
|
+
border-color: color-mix(
|
|
295
|
+
in srgb,
|
|
296
|
+
var(--dream-app-accent-fill, #f66a2c) 40%,
|
|
297
|
+
var(--panel-strong)
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
.${p}-panel .${p}-search {
|
|
301
|
+
flex: 1;
|
|
302
|
+
min-width: 0;
|
|
303
|
+
width: 100%;
|
|
304
|
+
padding: 5px 0;
|
|
305
|
+
border: 0;
|
|
306
|
+
outline: none;
|
|
307
|
+
color: var(--panel-bright);
|
|
308
|
+
background: transparent;
|
|
309
|
+
font-size: 11px;
|
|
310
|
+
line-height: 16px;
|
|
311
|
+
}
|
|
312
|
+
/* The enclosing search field carries the focus ring. */
|
|
313
|
+
.${p}-panel .${p}-search:focus-visible { outline: none; }
|
|
314
|
+
.${p}-search::placeholder { color: var(--panel-muted); }
|
|
315
|
+
.${p}-search::-webkit-search-cancel-button { display: none; }
|
|
316
|
+
.${p}-views { flex: none; display: flex; gap: 2px; }
|
|
317
|
+
.${p}-views .${p}-icon { width: 24px; height: 26px; }
|
|
318
|
+
.${p}-views [aria-pressed="true"] { color: var(--panel-bright); background: var(--panel-hover); }
|
|
319
|
+
.${p}-list {
|
|
320
|
+
flex: 1 1 auto;
|
|
321
|
+
min-height: 0;
|
|
322
|
+
overflow: auto;
|
|
323
|
+
scrollbar-width: thin;
|
|
324
|
+
scrollbar-color: var(--panel-strong) transparent;
|
|
325
|
+
margin: 0;
|
|
326
|
+
padding: 4px 0 6px;
|
|
327
|
+
list-style: none;
|
|
328
|
+
}
|
|
329
|
+
.${p}-empty { padding: 12px 15px; color: var(--panel-dim); font-size: 11px; }
|
|
330
|
+
.${p}-row {
|
|
331
|
+
position: relative;
|
|
332
|
+
display: flex;
|
|
333
|
+
flex-wrap: wrap;
|
|
334
|
+
align-items: center;
|
|
335
|
+
gap: 0 6px;
|
|
336
|
+
min-height: 48px;
|
|
337
|
+
padding: 0 12px 0 6px;
|
|
338
|
+
}
|
|
339
|
+
.${p}-row:hover { background: var(--panel-hover); }
|
|
340
|
+
.${p}-row[data-selected] { background: var(--panel-selected); }
|
|
341
|
+
.${p}-row[data-selected]::before {
|
|
342
|
+
content: "";
|
|
343
|
+
position: absolute;
|
|
344
|
+
left: 0;
|
|
345
|
+
top: 12px;
|
|
346
|
+
bottom: 12px;
|
|
347
|
+
width: 1px;
|
|
348
|
+
background: var(--panel-bright);
|
|
349
|
+
}
|
|
350
|
+
.${p}-row[data-threaded] { padding-left: calc(6px + var(--page-depth) * 18px); }
|
|
351
|
+
.${p}-row[data-threaded]::after {
|
|
352
|
+
content: "";
|
|
353
|
+
position: absolute;
|
|
354
|
+
pointer-events: none;
|
|
355
|
+
left: calc(var(--page-depth) * 18px - 3px);
|
|
356
|
+
top: 0;
|
|
357
|
+
bottom: 0;
|
|
358
|
+
width: 10px;
|
|
359
|
+
border-left: 1px solid var(--panel-strong);
|
|
360
|
+
background: linear-gradient(var(--panel-strong), var(--panel-strong)) left 23px / 10px 1px no-repeat;
|
|
361
|
+
}
|
|
362
|
+
.${p}-row[data-threaded][data-last]::after { bottom: auto; height: 24px; }
|
|
363
|
+
.${p}-panel .${p}-name {
|
|
364
|
+
display: flex;
|
|
365
|
+
flex: 1 1 0;
|
|
366
|
+
min-width: 0;
|
|
367
|
+
flex-direction: column;
|
|
368
|
+
align-items: stretch;
|
|
369
|
+
gap: 2px;
|
|
370
|
+
padding: 7px 9px;
|
|
371
|
+
text-align: left;
|
|
372
|
+
line-height: 16px;
|
|
373
|
+
cursor: grab;
|
|
374
|
+
user-select: none;
|
|
375
|
+
}
|
|
376
|
+
.${p}-filename-line { display: flex; align-items: center; gap: 8px; max-width: 100%; min-width: 0; }
|
|
377
|
+
.${p}-path, .${p}-title { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
378
|
+
.${p}-path { min-width: 0; color: var(--panel-bright); }
|
|
379
|
+
.${p}-folder { color: var(--panel-dim); }
|
|
380
|
+
.${p}-title { font-size: 11px; color: var(--panel-dim); }
|
|
381
|
+
.${p}-row[data-off] .${p}-path { color: var(--panel-dim); }
|
|
382
|
+
.${p}-row[data-missing] .${p}-path { color: var(--panel-muted); text-decoration: line-through; }
|
|
383
|
+
.${p}-row[data-missing] .${p}-name { cursor: default; }
|
|
384
|
+
.${p}-metadata { flex: none; display: flex; align-items: center; gap: 4px; color: var(--panel-dim); font-size: 11px; font-variant-numeric: tabular-nums; }
|
|
385
|
+
.${p}-note { flex: none; font-size: 11px; color: var(--panel-muted); }
|
|
386
|
+
.${p}-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
|
387
|
+
.${p}-actions { flex: none; opacity: 0; }
|
|
388
|
+
.${p}-row:hover .${p}-actions,
|
|
389
|
+
.${p}-row:focus-within .${p}-actions,
|
|
390
|
+
.${p}-row[data-selected] .${p}-actions,
|
|
391
|
+
.${p}-actions[data-open], .${p}-actions[data-confirming] { opacity: 1; }
|
|
392
|
+
.${p}-direct, .${p}-confirm { display: flex; gap: 2px; }
|
|
393
|
+
.${p}-panel .${p}-icon {
|
|
394
|
+
display: grid;
|
|
395
|
+
place-items: center;
|
|
396
|
+
width: 22px;
|
|
397
|
+
height: 22px;
|
|
398
|
+
padding: 0;
|
|
399
|
+
border-radius: 4px;
|
|
400
|
+
color: var(--panel-dim);
|
|
401
|
+
}
|
|
402
|
+
.${p}-panel .${p}-icon:hover { color: var(--panel-bright); background: var(--panel-hover); }
|
|
403
|
+
.${p}-panel .${p}-more { display: none; }
|
|
404
|
+
.${p}-panel .${p}-views .${p}-icon { width: 24px; height: 26px; }
|
|
405
|
+
.${p}-panel .${p}-views [aria-pressed="true"] { color: var(--panel-bright); background: var(--panel-hover); }
|
|
406
|
+
.${p}-menu {
|
|
407
|
+
position: fixed;
|
|
408
|
+
inset: auto;
|
|
409
|
+
width: 126px;
|
|
410
|
+
margin: 0;
|
|
411
|
+
padding: 4px;
|
|
412
|
+
color: var(--panel-text);
|
|
413
|
+
background: var(--panel-raised);
|
|
414
|
+
border: 1px solid var(--panel-strong);
|
|
415
|
+
border-radius: 6px;
|
|
416
|
+
font: inherit;
|
|
417
|
+
}
|
|
418
|
+
.${p}-menu button, .${p}-menu .${p}-icon {
|
|
419
|
+
display: flex;
|
|
420
|
+
align-items: center;
|
|
421
|
+
justify-content: flex-start;
|
|
422
|
+
gap: 8px;
|
|
423
|
+
width: 100%;
|
|
424
|
+
height: auto;
|
|
425
|
+
padding: 7px 8px;
|
|
426
|
+
border-radius: 3px;
|
|
427
|
+
text-align: left;
|
|
428
|
+
}
|
|
429
|
+
.${p}-menu button:hover { background: var(--panel-hover); color: var(--panel-bright); }
|
|
430
|
+
.${p}-menu .${p}-confirm { flex-direction: column; gap: 3px; }
|
|
431
|
+
.${p}-panel .${p}-confirm [data-danger] { color: #fff; background: #ba3541; }
|
|
432
|
+
.${p}-panel .${p}-confirm [data-danger]:hover { color: #fff; background: #d34250; }
|
|
433
|
+
.${p}-panel [aria-disabled="true"] { cursor: default; }
|
|
434
|
+
@container ${p} (width < 340px) {
|
|
435
|
+
.${p}-direct { display: none; }
|
|
436
|
+
.${p}-panel .${p}-more { display: grid; }
|
|
437
|
+
}
|
|
438
|
+
@media (hover: none) { .${p}-actions { opacity: 1; } }
|
|
439
|
+
.${p}-new { flex: none; margin-top: auto; }
|
|
440
|
+
.${p}-panel .${p}-new-button {
|
|
441
|
+
display: flex;
|
|
442
|
+
align-items: center;
|
|
443
|
+
gap: 7px;
|
|
444
|
+
width: 100%;
|
|
445
|
+
padding: 14px 15px;
|
|
446
|
+
line-height: 16px;
|
|
447
|
+
text-align: left;
|
|
448
|
+
font-size: 11px;
|
|
449
|
+
color: var(--panel-dim);
|
|
450
|
+
}
|
|
451
|
+
.${p}-panel .${p}-new-button:hover { background: var(--panel-hover); color: var(--panel-bright); }
|
|
452
|
+
.${p}-rename, .${p}-new-input {
|
|
453
|
+
min-width: 0;
|
|
454
|
+
padding: 6px;
|
|
455
|
+
color: var(--panel-bright);
|
|
456
|
+
background: var(--panel-field);
|
|
457
|
+
border: 1px solid var(--panel-strong);
|
|
458
|
+
border-radius: 3px;
|
|
459
|
+
}
|
|
460
|
+
.${p}-rename { flex: 1; width: 100%; margin: 6px; }
|
|
461
|
+
.${p}-new-input { width: calc(100% - 28px); margin: 10px 14px; }
|
|
462
|
+
.${p}-rename:focus, .${p}-new-input:focus { border-color: var(--panel-accent); }
|
|
463
|
+
.${p}-row-problem, .${p}-problem {
|
|
464
|
+
flex: 0 0 100%;
|
|
465
|
+
margin: 0;
|
|
466
|
+
padding: 4px 9px 8px;
|
|
467
|
+
color: var(--panel-danger);
|
|
468
|
+
font-size: 11px;
|
|
469
|
+
overflow-wrap: anywhere;
|
|
470
|
+
}
|
|
471
|
+
`;
|
|
472
|
+
var _tmpl$$2 = template(`<svg><circle cx=6.5 cy=6.5 r=4.5></svg>`, 2);
|
|
473
|
+
var _tmpl$2$2 = template(`<svg><path d="m10 10 4 4"></svg>`, 2);
|
|
474
|
+
var _tmpl$3$2 = template(`<svg><path d="M5 3h9M5 8h9M5 13h9M2 3h.01M2 8h.01M2 13h.01"></svg>`, 2);
|
|
475
|
+
var _tmpl$4$2 = template(`<svg><path d="M2 3h12M3 6v7h3M3 8h3M9 8h5M9 13h5"></svg>`, 2);
|
|
476
|
+
var _tmpl$5$2 = template(`<svg><path d="m4 4 8 8M12 4l-8 8"></svg>`, 2);
|
|
477
|
+
var _tmpl$6$1 = template(`<svg><path d="m10 2 3 3-8 8H2v-3z"></svg>`, 2);
|
|
478
|
+
var _tmpl$7$1 = template(`<svg><path d="M3 4h10M6 4V2h4v2M4 4l.7 10h6.6L12 4"></svg>`, 2);
|
|
479
|
+
var _tmpl$8$1 = template(`<svg><circle cx=3 cy=8 r=.6></svg>`, 2);
|
|
480
|
+
var _tmpl$9$1 = template(`<svg><circle cx=8 cy=8 r=.6></svg>`, 2);
|
|
481
|
+
var _tmpl$10$1 = template(`<svg><circle cx=13 cy=8 r=.6></svg>`, 2);
|
|
482
|
+
var _tmpl$11$1 = template(`<svg><circle cx=4 cy=3 r=2></svg>`, 2);
|
|
483
|
+
var _tmpl$12$1 = template(`<svg><circle cx=4 cy=13 r=2></svg>`, 2);
|
|
484
|
+
var _tmpl$13$1 = template(`<svg><circle cx=12 cy=3 r=2></svg>`, 2);
|
|
485
|
+
var _tmpl$14$1 = template(`<svg><path d="M4 5v6m0-3h4a4 4 0 0 0 4-4"></svg>`, 2);
|
|
486
|
+
var _tmpl$15$1 = template(`<svg><rect x=5 y=5 width=9 height=9 rx=1></svg>`, 2);
|
|
487
|
+
var _tmpl$16 = template(`<svg><path d="M3 11H2V2h9v1"></svg>`, 2);
|
|
488
|
+
var _tmpl$17 = template(`<svg><path d="M8 3v10M3 8h10"></svg>`, 2);
|
|
489
|
+
var _tmpl$18 = template(`<svg viewBox="0 0 16 16"aria-hidden=true>`);
|
|
490
|
+
var paths = {
|
|
491
|
+
search: () => [_tmpl$$2(), _tmpl$2$2()],
|
|
492
|
+
list: () => _tmpl$3$2(),
|
|
493
|
+
threaded: () => _tmpl$4$2(),
|
|
494
|
+
close: () => _tmpl$5$2(),
|
|
495
|
+
rename: () => _tmpl$6$1(),
|
|
496
|
+
delete: () => _tmpl$7$1(),
|
|
497
|
+
more: () => [
|
|
498
|
+
_tmpl$8$1(),
|
|
499
|
+
_tmpl$9$1(),
|
|
500
|
+
_tmpl$10$1()
|
|
501
|
+
],
|
|
502
|
+
variant: () => [
|
|
503
|
+
_tmpl$11$1(),
|
|
504
|
+
_tmpl$12$1(),
|
|
505
|
+
_tmpl$13$1(),
|
|
506
|
+
_tmpl$14$1()
|
|
507
|
+
],
|
|
508
|
+
viewports: () => [_tmpl$15$1(), _tmpl$16()],
|
|
509
|
+
plus: () => _tmpl$17()
|
|
510
|
+
};
|
|
511
|
+
function Icon(props) {
|
|
512
|
+
var _el$18 = _tmpl$18();
|
|
513
|
+
insert(_el$18, () => {
|
|
514
|
+
return paths[props.name]();
|
|
515
|
+
});
|
|
516
|
+
return _el$18;
|
|
517
|
+
}
|
|
518
|
+
var _tmpl$$1 = template(`<span role=group aria-label="Confirm page deletion"><button type=button data-danger title="Delete page"></button><button type=button data-cancel aria-label="Cancel deletion"title="Cancel deletion">`);
|
|
519
|
+
var _tmpl$2$1 = template(`<span><span><button type=button></button></span><button type=button title="Page actions"aria-haspopup=dialog></button><div popover=auto role=dialog>`);
|
|
520
|
+
var _tmpl$3$1 = template(`<button type=button>`);
|
|
521
|
+
var _tmpl$4$1 = template(`<button type=button>Rename`);
|
|
522
|
+
var _tmpl$5$1 = template(`<button type=button data-delete>Delete`);
|
|
523
|
+
function PageActions(props) {
|
|
524
|
+
const [confirm, setConfirm] = createSignal(null);
|
|
525
|
+
const busy = () => props.busy;
|
|
526
|
+
const [menuOpen, setMenuOpen] = createSignal(false);
|
|
527
|
+
let root;
|
|
528
|
+
let menu;
|
|
529
|
+
let trigger;
|
|
530
|
+
const focusName = () => root.closest("li")?.querySelector(`.${props.p}-name`)?.focus();
|
|
531
|
+
const dismiss = () => {
|
|
532
|
+
if (menu.matches(":popover-open")) menu.hidePopover();
|
|
533
|
+
setConfirm(null);
|
|
534
|
+
};
|
|
535
|
+
createEffect(() => menuOpen() || confirm() !== null, (active) => {
|
|
536
|
+
if (!active) return;
|
|
537
|
+
const outside = (event) => {
|
|
538
|
+
if (event.target instanceof Node && !root.contains(event.target)) setConfirm(null);
|
|
539
|
+
};
|
|
540
|
+
const scroll = (event) => {
|
|
541
|
+
if (event.target instanceof Node && !menu.contains(event.target) && menu.matches(":popover-open")) menu.hidePopover();
|
|
542
|
+
};
|
|
543
|
+
const list = root.closest("ul");
|
|
544
|
+
let width = list.getBoundingClientRect().width;
|
|
545
|
+
const observer = new ResizeObserver(() => {
|
|
546
|
+
const next = list.getBoundingClientRect().width;
|
|
547
|
+
if (next !== width) dismiss();
|
|
548
|
+
width = next;
|
|
549
|
+
});
|
|
550
|
+
observer.observe(list);
|
|
551
|
+
document.addEventListener("pointerdown", outside);
|
|
552
|
+
list.addEventListener("scroll", scroll);
|
|
553
|
+
window.addEventListener("resize", dismiss);
|
|
554
|
+
return () => {
|
|
555
|
+
observer.disconnect();
|
|
556
|
+
document.removeEventListener("pointerdown", outside);
|
|
557
|
+
list.removeEventListener("scroll", scroll);
|
|
558
|
+
window.removeEventListener("resize", dismiss);
|
|
559
|
+
};
|
|
560
|
+
});
|
|
561
|
+
const showMenu = () => {
|
|
562
|
+
if (busy()) return;
|
|
563
|
+
if (menu.matches(":popover-open")) {
|
|
564
|
+
dismiss();
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
menu.showPopover();
|
|
568
|
+
const rect = trigger.getBoundingClientRect();
|
|
569
|
+
const bounds = menu.getBoundingClientRect();
|
|
570
|
+
menu.style.left = `${Math.max(8, Math.min(rect.right - bounds.width, window.innerWidth - bounds.width - 8))}px`;
|
|
571
|
+
menu.style.top = `${Math.max(8, Math.min(rect.bottom + 4, window.innerHeight - bounds.height - 8))}px`;
|
|
572
|
+
menu.querySelector("button")?.focus();
|
|
573
|
+
};
|
|
574
|
+
const ask = (where) => {
|
|
575
|
+
if (busy()) return;
|
|
576
|
+
props.onProblem(null);
|
|
577
|
+
setConfirm(where);
|
|
578
|
+
};
|
|
579
|
+
const cancel = () => {
|
|
580
|
+
if (busy()) return;
|
|
581
|
+
setConfirm(null);
|
|
582
|
+
setTimeout(() => {
|
|
583
|
+
if (menu.matches(":popover-open")) menu.querySelector("[data-delete]")?.focus();
|
|
584
|
+
else focusName();
|
|
585
|
+
});
|
|
586
|
+
};
|
|
587
|
+
const remove = async () => {
|
|
588
|
+
if (busy()) return;
|
|
589
|
+
const item = root.closest("li");
|
|
590
|
+
const near = item.nextElementSibling ?? item.previousElementSibling;
|
|
591
|
+
const panel = root.closest(`.${props.p}-panel`);
|
|
592
|
+
const where = near?.getAttribute("data-path");
|
|
593
|
+
props.onBusy(true);
|
|
594
|
+
try {
|
|
595
|
+
await props.dd.deletePage(props.path);
|
|
596
|
+
dismiss();
|
|
597
|
+
setTimeout(() => {
|
|
598
|
+
if (document.activeElement !== document.body && !root.contains(document.activeElement)) return;
|
|
599
|
+
((where ? panel?.querySelector(`li[data-path="${CSS.escape(where)}"] .${props.p}-name`) : null) ?? panel?.querySelector(`.${props.p}-new-button`))?.focus();
|
|
600
|
+
});
|
|
601
|
+
} catch (error) {
|
|
602
|
+
props.onProblem(error instanceof Error ? error.message : String(error));
|
|
603
|
+
const restoreFocus = root.contains(document.activeElement);
|
|
604
|
+
dismiss();
|
|
605
|
+
if (restoreFocus) focusName();
|
|
606
|
+
} finally {
|
|
607
|
+
props.onBusy(false);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
const confirmation = (words) => (() => {
|
|
611
|
+
var _el$ = _tmpl$$1();
|
|
612
|
+
var _el$2 = _el$.firstChild;
|
|
613
|
+
var _el$3 = _el$2.nextSibling;
|
|
614
|
+
_el$2._$$click = () => void remove();
|
|
615
|
+
insert(_el$2, words ? "Delete page" : createComponent(Icon, { name: "delete" }));
|
|
616
|
+
_el$3._$$click = cancel;
|
|
617
|
+
ref(() => {
|
|
618
|
+
return (node) => queueMicrotask(() => {
|
|
619
|
+
if (node.isConnected) node.focus();
|
|
620
|
+
});
|
|
621
|
+
}, _el$3);
|
|
622
|
+
insert(_el$3, words ? "Cancel" : createComponent(Icon, { name: "close" }));
|
|
623
|
+
effect(() => {
|
|
624
|
+
return {
|
|
625
|
+
e: `${props.p}-confirm`,
|
|
626
|
+
t: `${props.p}-icon`,
|
|
627
|
+
a: `Delete ${props.path} permanently`,
|
|
628
|
+
o: busy() ? "true" : void 0,
|
|
629
|
+
i: `${props.p}-icon`,
|
|
630
|
+
n: busy() ? "true" : void 0
|
|
631
|
+
};
|
|
632
|
+
}, ({ e, t, a, o, i, n }, _p$) => {
|
|
633
|
+
className(_el$, e, _p$?.e);
|
|
634
|
+
className(_el$2, t, _p$?.t);
|
|
635
|
+
a !== _p$?.a && setAttribute(_el$2, "aria-label", a);
|
|
636
|
+
o !== _p$?.o && setAttribute(_el$2, "aria-disabled", o);
|
|
637
|
+
className(_el$3, i, _p$?.i);
|
|
638
|
+
n !== _p$?.n && setAttribute(_el$3, "aria-disabled", n);
|
|
639
|
+
});
|
|
640
|
+
return _el$;
|
|
641
|
+
})();
|
|
642
|
+
var _el$4 = _tmpl$2$1();
|
|
643
|
+
var _el$5 = _el$4.firstChild;
|
|
644
|
+
var _el$6 = _el$5.firstChild;
|
|
645
|
+
var _el$7 = _el$5.nextSibling;
|
|
646
|
+
var _el$8 = _el$7.nextSibling;
|
|
647
|
+
var _ref$ = root;
|
|
648
|
+
typeof _ref$ === "function" || Array.isArray(_ref$) ? ref(() => {
|
|
649
|
+
return _ref$;
|
|
650
|
+
}, _el$4) : root = _el$4;
|
|
651
|
+
_el$6._$$click = () => {
|
|
652
|
+
if (!busy()) props.onRename();
|
|
653
|
+
};
|
|
654
|
+
insert(_el$6, createComponent(Icon, { name: "rename" }));
|
|
655
|
+
insert(_el$5, createComponent(Show, {
|
|
656
|
+
get when() {
|
|
657
|
+
return confirm() === "inline";
|
|
658
|
+
},
|
|
659
|
+
get fallback() {
|
|
660
|
+
var _el$9 = _tmpl$3$1();
|
|
661
|
+
_el$9._$$click = () => ask("inline");
|
|
662
|
+
insert(_el$9, createComponent(Icon, { name: "delete" }));
|
|
663
|
+
effect(() => {
|
|
664
|
+
return {
|
|
665
|
+
e: `${props.p}-icon`,
|
|
666
|
+
t: `Delete ${props.path}`,
|
|
667
|
+
a: `Delete ${props.path}`
|
|
668
|
+
};
|
|
669
|
+
}, ({ e, t, a }, _p$) => {
|
|
670
|
+
className(_el$9, e, _p$?.e);
|
|
671
|
+
t !== _p$?.t && setAttribute(_el$9, "title", t);
|
|
672
|
+
a !== _p$?.a && setAttribute(_el$9, "aria-label", a);
|
|
673
|
+
});
|
|
674
|
+
return _el$9;
|
|
675
|
+
},
|
|
676
|
+
get children() {
|
|
677
|
+
return confirmation(false);
|
|
678
|
+
}
|
|
679
|
+
}), null);
|
|
680
|
+
_el$7._$$click = showMenu;
|
|
681
|
+
var _ref$2 = trigger;
|
|
682
|
+
typeof _ref$2 === "function" || Array.isArray(_ref$2) ? ref(() => {
|
|
683
|
+
return _ref$2;
|
|
684
|
+
}, _el$7) : trigger = _el$7;
|
|
685
|
+
insert(_el$7, createComponent(Icon, { name: "more" }));
|
|
686
|
+
_el$8.addEventListener("toggle", () => {
|
|
687
|
+
const open = menu.matches(":popover-open");
|
|
688
|
+
setMenuOpen(open);
|
|
689
|
+
if (!open) setConfirm(null);
|
|
690
|
+
});
|
|
691
|
+
var _ref$3 = menu;
|
|
692
|
+
typeof _ref$3 === "function" || Array.isArray(_ref$3) ? ref(() => {
|
|
693
|
+
return _ref$3;
|
|
694
|
+
}, _el$8) : menu = _el$8;
|
|
695
|
+
insert(_el$8, createComponent(Show, {
|
|
696
|
+
get when() {
|
|
697
|
+
return confirm() === "menu";
|
|
698
|
+
},
|
|
699
|
+
get fallback() {
|
|
700
|
+
return [(() => {
|
|
701
|
+
var _el$10 = _tmpl$4$1();
|
|
702
|
+
var _el$11 = _el$10.firstChild;
|
|
703
|
+
_el$10._$$click = () => {
|
|
704
|
+
if (busy()) return;
|
|
705
|
+
dismiss();
|
|
706
|
+
props.onRename();
|
|
707
|
+
};
|
|
708
|
+
insert(_el$10, createComponent(Icon, { name: "rename" }), _el$11);
|
|
709
|
+
effect(() => `Rename ${props.path}`, (_v$) => {
|
|
710
|
+
setAttribute(_el$10, "aria-label", _v$);
|
|
711
|
+
});
|
|
712
|
+
return _el$10;
|
|
713
|
+
})(), (() => {
|
|
714
|
+
var _el$12 = _tmpl$5$1();
|
|
715
|
+
var _el$13 = _el$12.firstChild;
|
|
716
|
+
_el$12._$$click = () => ask("menu");
|
|
717
|
+
insert(_el$12, createComponent(Icon, { name: "delete" }), _el$13);
|
|
718
|
+
effect(() => `Delete ${props.path}`, (_v$) => {
|
|
719
|
+
setAttribute(_el$12, "aria-label", _v$);
|
|
720
|
+
});
|
|
721
|
+
return _el$12;
|
|
722
|
+
})()];
|
|
723
|
+
},
|
|
724
|
+
get children() {
|
|
725
|
+
return confirmation(true);
|
|
726
|
+
}
|
|
727
|
+
}));
|
|
728
|
+
effect(() => {
|
|
729
|
+
return {
|
|
730
|
+
e: `${props.p}-actions`,
|
|
731
|
+
t: confirm() ? "" : void 0,
|
|
732
|
+
a: menuOpen() ? "" : void 0,
|
|
733
|
+
o: `${props.p}-direct`,
|
|
734
|
+
i: `${props.p}-icon`,
|
|
735
|
+
n: `Rename ${props.path}`,
|
|
736
|
+
s: `Rename ${props.path}`,
|
|
737
|
+
h: busy() ? "true" : void 0,
|
|
738
|
+
r: `${props.p}-icon ${props.p}-more`,
|
|
739
|
+
d: `Actions for ${props.path}`,
|
|
740
|
+
l: menuOpen() ? "true" : "false",
|
|
741
|
+
u: busy() ? "true" : void 0,
|
|
742
|
+
c: `Actions for ${props.path}`,
|
|
743
|
+
w: `${props.p}-menu`
|
|
744
|
+
};
|
|
745
|
+
}, ({ e, t, a, o, i, n, s, h, r, d, l, u, c, w }, _p$) => {
|
|
746
|
+
className(_el$4, e, _p$?.e);
|
|
747
|
+
t !== _p$?.t && setAttribute(_el$4, "data-confirming", t);
|
|
748
|
+
a !== _p$?.a && setAttribute(_el$4, "data-open", a);
|
|
749
|
+
className(_el$5, o, _p$?.o);
|
|
750
|
+
className(_el$6, i, _p$?.i);
|
|
751
|
+
n !== _p$?.n && setAttribute(_el$6, "title", n);
|
|
752
|
+
s !== _p$?.s && setAttribute(_el$6, "aria-label", s);
|
|
753
|
+
h !== _p$?.h && setAttribute(_el$6, "aria-disabled", h);
|
|
754
|
+
className(_el$7, r, _p$?.r);
|
|
755
|
+
d !== _p$?.d && setAttribute(_el$7, "aria-label", d);
|
|
756
|
+
l !== _p$?.l && setAttribute(_el$7, "aria-expanded", l);
|
|
757
|
+
u !== _p$?.u && setAttribute(_el$7, "aria-disabled", u);
|
|
758
|
+
c !== _p$?.c && setAttribute(_el$8, "aria-label", c);
|
|
759
|
+
className(_el$8, w, _p$?.w);
|
|
760
|
+
});
|
|
761
|
+
return _el$4;
|
|
762
|
+
}
|
|
763
|
+
delegateEvents(["click"]);
|
|
764
|
+
var _tmpl$ = template(`<button type=button aria-label="Clear search"title="Clear search">`);
|
|
765
|
+
var _tmpl$2 = template(`<li role=status>`);
|
|
766
|
+
var _tmpl$3 = template(`<div><div><div><input type=search aria-label="Search pages"placeholder=Search… autocomplete=off><!></div><div role=group aria-label="Pages view"><button type=button aria-label="List view"title="List view"></button><button type=button aria-label="Threaded view"title="Threaded view"></button></div></div><ul aria-label=Pages><!><!>`);
|
|
767
|
+
var _tmpl$4 = template(`<li><!><!><!>`);
|
|
768
|
+
var _tmpl$5 = template(`<span>`);
|
|
769
|
+
var _tmpl$6 = template(`<span role=img>`);
|
|
770
|
+
var _tmpl$7 = template(`<span><!><!>`);
|
|
771
|
+
var _tmpl$8 = template(`<span>, off the canvas`);
|
|
772
|
+
var _tmpl$9 = template(`<button type=button><span><span><!><!></span><!><!></span><!><!>`);
|
|
773
|
+
var _tmpl$10 = template(`<span>missing`);
|
|
774
|
+
var _tmpl$11 = template(`<p role=alert>`);
|
|
775
|
+
var _tmpl$12 = template(`<input type=text>`);
|
|
776
|
+
var _tmpl$13 = template(`<input type=text placeholder="Title, then Enter"aria-label="New page title">`);
|
|
777
|
+
var _tmpl$14 = template(`<div>`);
|
|
778
|
+
var _tmpl$15 = template(`<button type=button>New page`);
|
|
779
|
+
var reason = (error) => error instanceof Error ? error.message : String(error);
|
|
780
|
+
var isEnter = (event) => event.key === "Enter" && !event.isComposing;
|
|
781
|
+
function focusLater(within, ...selectors) {
|
|
782
|
+
setTimeout(() => {
|
|
783
|
+
for (const selector of selectors) {
|
|
784
|
+
const found = within?.querySelector(selector);
|
|
785
|
+
if (found !== null && found !== void 0) return found.focus();
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
var focusName = (list, p, path) => focusLater(list?.closest(`.${p}-panel`) ?? list, `li[data-path="${CSS.escape(path)}"] .${p}-name`, `.${p}-search`);
|
|
790
|
+
function createPagesPanel(dd, context) {
|
|
791
|
+
const p = classPrefix(dd.plugin.id);
|
|
792
|
+
const rows = createMemo(() => pageRows(dd.document(), dd.core.viewportItems(dd.document())));
|
|
793
|
+
const [deleting, setDeleting] = createSignal(new Set());
|
|
794
|
+
const markDeleting = (path, busy) => setDeleting((previous) => {
|
|
795
|
+
const next = new Set(previous);
|
|
796
|
+
if (busy) next.add(path);
|
|
797
|
+
else next.delete(path);
|
|
798
|
+
return next;
|
|
799
|
+
});
|
|
800
|
+
const [problems, setProblems] = createSignal(new Map());
|
|
801
|
+
const reportProblem = (path, message) => setProblems((previous) => {
|
|
802
|
+
const next = new Map(previous);
|
|
803
|
+
if (message === null) next.delete(path);
|
|
804
|
+
else next.set(path, message);
|
|
805
|
+
return next;
|
|
806
|
+
});
|
|
807
|
+
const [query, setQuery] = createSignal("");
|
|
808
|
+
const [view, setView] = createSignal("list");
|
|
809
|
+
const titleCache = new Map();
|
|
810
|
+
const titles = createMemo(() => {
|
|
811
|
+
const result = new Map();
|
|
812
|
+
for (const row of rows()) {
|
|
813
|
+
const html = dd.page(row.path)?.html ?? "";
|
|
814
|
+
let cached = titleCache.get(row.path);
|
|
815
|
+
if (cached?.html !== html) {
|
|
816
|
+
cached = {
|
|
817
|
+
html,
|
|
818
|
+
title: html ? dd.core.parsePage(html).title.trim() : ""
|
|
819
|
+
};
|
|
820
|
+
titleCache.set(row.path, cached);
|
|
821
|
+
}
|
|
822
|
+
result.set(row.path, cached.title);
|
|
823
|
+
}
|
|
824
|
+
for (const path of titleCache.keys()) if (!result.has(path)) titleCache.delete(path);
|
|
825
|
+
return result;
|
|
826
|
+
});
|
|
827
|
+
const listed = createMemo(() => listPages(rows(), view(), query(), titles()));
|
|
828
|
+
let search;
|
|
829
|
+
const [selectedViewport, setSelectedViewport] = createSignal(null);
|
|
830
|
+
createEffect(() => {
|
|
831
|
+
dd.documentVersion();
|
|
832
|
+
return {
|
|
833
|
+
element: context.selection(),
|
|
834
|
+
items: context.itemSelection()
|
|
835
|
+
};
|
|
836
|
+
}, ({ element, items }) => {
|
|
837
|
+
setSelectedViewport(items.length > 0 ? items.at(-1) : element === null ? null : untrack(() => dd.pageElement(element))?.viewportId ?? null);
|
|
838
|
+
});
|
|
839
|
+
const select = (row) => {
|
|
840
|
+
if (row.viewports.length === 0) return;
|
|
841
|
+
dd.selectItems(row.viewports);
|
|
842
|
+
dd.canvas.reveal(row.viewports);
|
|
843
|
+
};
|
|
844
|
+
var _el$ = _tmpl$3();
|
|
845
|
+
var _el$2 = _el$.firstChild;
|
|
846
|
+
var _el$3 = _el$2.firstChild;
|
|
847
|
+
var _el$4 = _el$3.firstChild;
|
|
848
|
+
var _el$6 = _el$4.nextSibling;
|
|
849
|
+
var _el$7 = _el$3.nextSibling;
|
|
850
|
+
var _el$8 = _el$7.firstChild;
|
|
851
|
+
var _el$9 = _el$8.nextSibling;
|
|
852
|
+
var _el$10 = _el$2.nextSibling;
|
|
853
|
+
var _el$11 = _el$10.firstChild;
|
|
854
|
+
var _el$13 = _el$11.nextSibling;
|
|
855
|
+
insert(_el$3, createComponent(Icon, { name: "search" }), _el$4);
|
|
856
|
+
_el$4._$$input = (event) => setQuery(event.currentTarget.value);
|
|
857
|
+
var _ref$ = search;
|
|
858
|
+
typeof _ref$ === "function" || Array.isArray(_ref$) ? ref(() => {
|
|
859
|
+
return _ref$;
|
|
860
|
+
}, _el$4) : search = _el$4;
|
|
861
|
+
insert(_el$3, createComponent(Show, {
|
|
862
|
+
get when() {
|
|
863
|
+
return query() !== "";
|
|
864
|
+
},
|
|
865
|
+
get children() {
|
|
866
|
+
var _el$5 = _tmpl$();
|
|
867
|
+
_el$5._$$click = () => {
|
|
868
|
+
setQuery("");
|
|
869
|
+
search?.focus();
|
|
870
|
+
};
|
|
871
|
+
insert(_el$5, createComponent(Icon, { name: "close" }));
|
|
872
|
+
effect(() => `${p}-icon`, (_v$, _$p) => {
|
|
873
|
+
className(_el$5, _v$, _$p);
|
|
874
|
+
});
|
|
875
|
+
return _el$5;
|
|
876
|
+
}
|
|
877
|
+
}), _el$6);
|
|
878
|
+
_el$8._$$click = () => setView("list");
|
|
879
|
+
insert(_el$8, createComponent(Icon, { name: "list" }));
|
|
880
|
+
_el$9._$$click = () => setView("threaded");
|
|
881
|
+
insert(_el$9, createComponent(Icon, { name: "threaded" }));
|
|
882
|
+
insert(_el$10, createComponent(For, {
|
|
883
|
+
get each() {
|
|
884
|
+
return listed();
|
|
885
|
+
},
|
|
886
|
+
keyed: (row) => row.path,
|
|
887
|
+
children: (row) => createComponent(PageRowView, {
|
|
888
|
+
dd,
|
|
889
|
+
p,
|
|
890
|
+
get row() {
|
|
891
|
+
return row();
|
|
892
|
+
},
|
|
893
|
+
get title() {
|
|
894
|
+
return titles().get(row().path) ?? "";
|
|
895
|
+
},
|
|
896
|
+
get selected() {
|
|
897
|
+
return row().viewports.includes(selectedViewport() ?? "");
|
|
898
|
+
},
|
|
899
|
+
onSelect: () => select(row()),
|
|
900
|
+
get deleting() {
|
|
901
|
+
return deleting().has(row().path);
|
|
902
|
+
},
|
|
903
|
+
get problem() {
|
|
904
|
+
return problems().get(row().path) ?? null;
|
|
905
|
+
},
|
|
906
|
+
onProblem: (message) => reportProblem(row().path, message),
|
|
907
|
+
onDeleting: (busy) => markDeleting(row().path, busy)
|
|
908
|
+
})
|
|
909
|
+
}), _el$11);
|
|
910
|
+
insert(_el$10, createComponent(Show, {
|
|
911
|
+
get when() {
|
|
912
|
+
return listed().length === 0;
|
|
913
|
+
},
|
|
914
|
+
get children() {
|
|
915
|
+
var _el$12 = _tmpl$2();
|
|
916
|
+
insert(_el$12, () => {
|
|
917
|
+
return rows().length ? "No matching pages." : "No pages in this project yet.";
|
|
918
|
+
});
|
|
919
|
+
effect(() => `${p}-empty`, (_v$, _$p) => {
|
|
920
|
+
className(_el$12, _v$, _$p);
|
|
921
|
+
});
|
|
922
|
+
return _el$12;
|
|
923
|
+
}
|
|
924
|
+
}), _el$13);
|
|
925
|
+
insert(_el$, createComponent(NewPage, {
|
|
926
|
+
dd,
|
|
927
|
+
p,
|
|
928
|
+
onCreated: () => setQuery("")
|
|
929
|
+
}), null);
|
|
930
|
+
effect(() => {
|
|
931
|
+
return {
|
|
932
|
+
e: `${p}-panel`,
|
|
933
|
+
t: `${p}-toolbar`,
|
|
934
|
+
a: `${p}-search-field`,
|
|
935
|
+
o: `${p}-search`,
|
|
936
|
+
i: query(),
|
|
937
|
+
n: `${p}-views`,
|
|
938
|
+
s: `${p}-icon`,
|
|
939
|
+
h: view() === "list" ? "true" : "false",
|
|
940
|
+
r: `${p}-icon`,
|
|
941
|
+
d: view() === "threaded" ? "true" : "false",
|
|
942
|
+
l: `${p}-list`
|
|
943
|
+
};
|
|
944
|
+
}, ({ e, t, a, o, i, n, s, h, r, d, l }, _p$) => {
|
|
945
|
+
className(_el$, e, _p$?.e);
|
|
946
|
+
className(_el$2, t, _p$?.t);
|
|
947
|
+
className(_el$3, a, _p$?.a);
|
|
948
|
+
className(_el$4, o, _p$?.o);
|
|
949
|
+
_el$4.value = i ?? "";
|
|
950
|
+
className(_el$7, n, _p$?.n);
|
|
951
|
+
className(_el$8, s, _p$?.s);
|
|
952
|
+
h !== _p$?.h && setAttribute(_el$8, "aria-pressed", h);
|
|
953
|
+
className(_el$9, r, _p$?.r);
|
|
954
|
+
d !== _p$?.d && setAttribute(_el$9, "aria-pressed", d);
|
|
955
|
+
className(_el$10, l, _p$?.l);
|
|
956
|
+
});
|
|
957
|
+
return _el$;
|
|
958
|
+
}
|
|
959
|
+
function PageRowView(props) {
|
|
960
|
+
const page = () => props.dd.page(props.row.path);
|
|
961
|
+
const missing = () => page() === void 0;
|
|
962
|
+
const count = () => props.row.viewports.length;
|
|
963
|
+
const onCanvas = () => count() > 0;
|
|
964
|
+
const [mode, setMode] = createSignal("name");
|
|
965
|
+
let item;
|
|
966
|
+
const open = (next) => {
|
|
967
|
+
if (missing() || props.deleting) return;
|
|
968
|
+
props.onProblem(null);
|
|
969
|
+
setMode(next);
|
|
970
|
+
};
|
|
971
|
+
const close = (refocus) => {
|
|
972
|
+
setMode("name");
|
|
973
|
+
if (refocus) focusName(item?.parentElement ?? null, props.p, props.row.path);
|
|
974
|
+
};
|
|
975
|
+
const press = (event) => {
|
|
976
|
+
if (missing() || props.deleting) return;
|
|
977
|
+
if (onCanvas()) props.onSelect();
|
|
978
|
+
else if (event.detail === 0) placeInView(props.dd, props.row.path);
|
|
979
|
+
};
|
|
980
|
+
var _el$14 = _tmpl$4();
|
|
981
|
+
var _el$15 = _el$14.firstChild;
|
|
982
|
+
var _el$16 = _el$15.nextSibling;
|
|
983
|
+
var _el$17 = _el$16.nextSibling;
|
|
984
|
+
var _ref$2 = item;
|
|
985
|
+
typeof _ref$2 === "function" || Array.isArray(_ref$2) ? ref(() => {
|
|
986
|
+
return _ref$2;
|
|
987
|
+
}, _el$14) : item = _el$14;
|
|
988
|
+
insert(_el$14, createComponent(Show, {
|
|
989
|
+
get when() {
|
|
990
|
+
return mode() === "edit";
|
|
991
|
+
},
|
|
992
|
+
get fallback() {
|
|
993
|
+
var _el$18 = _tmpl$9();
|
|
994
|
+
var _el$19 = _el$18.firstChild;
|
|
995
|
+
var _el$20 = _el$19.firstChild;
|
|
996
|
+
var _el$22 = _el$20.firstChild;
|
|
997
|
+
var _el$23 = _el$22.nextSibling;
|
|
998
|
+
var _el$25 = _el$20.nextSibling;
|
|
999
|
+
var _el$29 = _el$25.nextSibling;
|
|
1000
|
+
var _el$31 = _el$19.nextSibling;
|
|
1001
|
+
var _el$33 = _el$31.nextSibling;
|
|
1002
|
+
_el$18._$$dblclick = () => open("edit");
|
|
1003
|
+
_el$18._$$click = press;
|
|
1004
|
+
_el$18.addEventListener("dragstart", (event) => startPageDrag(props.dd, props.row.path, event));
|
|
1005
|
+
insert(_el$20, createComponent(Show, {
|
|
1006
|
+
get when() {
|
|
1007
|
+
return props.row.folder !== "";
|
|
1008
|
+
},
|
|
1009
|
+
get children() {
|
|
1010
|
+
var _el$21 = _tmpl$5();
|
|
1011
|
+
insert(_el$21, () => {
|
|
1012
|
+
return props.row.folder;
|
|
1013
|
+
});
|
|
1014
|
+
effect(() => `${props.p}-folder`, (_v$, _$p) => {
|
|
1015
|
+
className(_el$21, _v$, _$p);
|
|
1016
|
+
});
|
|
1017
|
+
return _el$21;
|
|
1018
|
+
}
|
|
1019
|
+
}), _el$22);
|
|
1020
|
+
insert(_el$20, () => {
|
|
1021
|
+
return props.row.name;
|
|
1022
|
+
}, _el$23);
|
|
1023
|
+
insert(_el$19, createComponent(Show, {
|
|
1024
|
+
get when() {
|
|
1025
|
+
return props.row.variantOf;
|
|
1026
|
+
},
|
|
1027
|
+
get children() {
|
|
1028
|
+
var _el$24 = _tmpl$6();
|
|
1029
|
+
insert(_el$24, createComponent(Icon, { name: "variant" }));
|
|
1030
|
+
effect(() => {
|
|
1031
|
+
return {
|
|
1032
|
+
e: `${props.p}-metadata`,
|
|
1033
|
+
t: `Variant of ${props.row.variantOf}`,
|
|
1034
|
+
a: `Variant of ${props.row.variantOf}`
|
|
1035
|
+
};
|
|
1036
|
+
}, ({ e, t, a }, _p$) => {
|
|
1037
|
+
className(_el$24, e, _p$?.e);
|
|
1038
|
+
t !== _p$?.t && setAttribute(_el$24, "title", t);
|
|
1039
|
+
a !== _p$?.a && setAttribute(_el$24, "aria-label", a);
|
|
1040
|
+
});
|
|
1041
|
+
return _el$24;
|
|
1042
|
+
}
|
|
1043
|
+
}), _el$25);
|
|
1044
|
+
insert(_el$19, createComponent(Show, {
|
|
1045
|
+
get when() {
|
|
1046
|
+
return memo(() => {
|
|
1047
|
+
return !missing();
|
|
1048
|
+
})() && count() > 1;
|
|
1049
|
+
},
|
|
1050
|
+
get children() {
|
|
1051
|
+
var _el$26 = _tmpl$7();
|
|
1052
|
+
var _el$27 = _el$26.firstChild;
|
|
1053
|
+
var _el$28 = _el$27.nextSibling;
|
|
1054
|
+
insert(_el$26, createComponent(Icon, { name: "viewports" }), _el$27);
|
|
1055
|
+
insert(_el$26, count, _el$28);
|
|
1056
|
+
effect(() => {
|
|
1057
|
+
return {
|
|
1058
|
+
e: `${props.p}-metadata`,
|
|
1059
|
+
t: `${count()} viewports on the canvas`,
|
|
1060
|
+
a: `${count()} viewports on the canvas`
|
|
1061
|
+
};
|
|
1062
|
+
}, ({ e, t, a }, _p$) => {
|
|
1063
|
+
className(_el$26, e, _p$?.e);
|
|
1064
|
+
t !== _p$?.t && setAttribute(_el$26, "title", t);
|
|
1065
|
+
a !== _p$?.a && setAttribute(_el$26, "aria-label", a);
|
|
1066
|
+
});
|
|
1067
|
+
return _el$26;
|
|
1068
|
+
}
|
|
1069
|
+
}), _el$29);
|
|
1070
|
+
insert(_el$18, createComponent(Show, {
|
|
1071
|
+
get when() {
|
|
1072
|
+
return props.title !== "";
|
|
1073
|
+
},
|
|
1074
|
+
get children() {
|
|
1075
|
+
var _el$30 = _tmpl$5();
|
|
1076
|
+
insert(_el$30, () => {
|
|
1077
|
+
return props.title;
|
|
1078
|
+
});
|
|
1079
|
+
effect(() => `${props.p}-title`, (_v$, _$p) => {
|
|
1080
|
+
className(_el$30, _v$, _$p);
|
|
1081
|
+
});
|
|
1082
|
+
return _el$30;
|
|
1083
|
+
}
|
|
1084
|
+
}), _el$31);
|
|
1085
|
+
insert(_el$18, createComponent(Show, {
|
|
1086
|
+
get when() {
|
|
1087
|
+
return memo(() => {
|
|
1088
|
+
return !missing();
|
|
1089
|
+
})() && !onCanvas();
|
|
1090
|
+
},
|
|
1091
|
+
get children() {
|
|
1092
|
+
var _el$32 = _tmpl$8();
|
|
1093
|
+
effect(() => `${props.p}-hidden`, (_v$, _$p) => {
|
|
1094
|
+
className(_el$32, _v$, _$p);
|
|
1095
|
+
});
|
|
1096
|
+
return _el$32;
|
|
1097
|
+
}
|
|
1098
|
+
}), _el$33);
|
|
1099
|
+
effect(() => {
|
|
1100
|
+
return {
|
|
1101
|
+
e: `${props.p}-name`,
|
|
1102
|
+
t: props.selected ? "true" : void 0,
|
|
1103
|
+
a: missing() || props.deleting ? "true" : void 0,
|
|
1104
|
+
o: missing() ? `${props.row.path} is missing from the project` : onCanvas() ? `Select ${props.row.path}, or drag it onto the canvas` : `Drag ${props.row.path} onto the canvas, or press Enter to place it`,
|
|
1105
|
+
i: missing() || props.deleting ? "false" : "true",
|
|
1106
|
+
n: `${props.p}-filename-line`,
|
|
1107
|
+
s: `${props.p}-path`
|
|
1108
|
+
};
|
|
1109
|
+
}, ({ e, t, a, o, i, n, s }, _p$) => {
|
|
1110
|
+
className(_el$18, e, _p$?.e);
|
|
1111
|
+
t !== _p$?.t && setAttribute(_el$18, "aria-current", t);
|
|
1112
|
+
a !== _p$?.a && setAttribute(_el$18, "aria-disabled", a);
|
|
1113
|
+
o !== _p$?.o && setAttribute(_el$18, "title", o);
|
|
1114
|
+
i !== _p$?.i && setAttribute(_el$18, "draggable", i);
|
|
1115
|
+
className(_el$19, n, _p$?.n);
|
|
1116
|
+
className(_el$20, s, _p$?.s);
|
|
1117
|
+
});
|
|
1118
|
+
return _el$18;
|
|
1119
|
+
},
|
|
1120
|
+
get children() {
|
|
1121
|
+
return createComponent(RenameField, {
|
|
1122
|
+
get dd() {
|
|
1123
|
+
return props.dd;
|
|
1124
|
+
},
|
|
1125
|
+
get p() {
|
|
1126
|
+
return props.p;
|
|
1127
|
+
},
|
|
1128
|
+
get path() {
|
|
1129
|
+
return props.row.path;
|
|
1130
|
+
},
|
|
1131
|
+
list: () => item?.parentElement ?? null,
|
|
1132
|
+
onClose: close,
|
|
1133
|
+
get onProblem() {
|
|
1134
|
+
return props.onProblem;
|
|
1135
|
+
}
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
}), _el$15);
|
|
1139
|
+
insert(_el$14, createComponent(Show, {
|
|
1140
|
+
get when() {
|
|
1141
|
+
return !missing();
|
|
1142
|
+
},
|
|
1143
|
+
get fallback() {
|
|
1144
|
+
var _el$34 = _tmpl$10();
|
|
1145
|
+
effect(() => `${props.p}-note`, (_v$, _$p) => {
|
|
1146
|
+
className(_el$34, _v$, _$p);
|
|
1147
|
+
});
|
|
1148
|
+
return _el$34;
|
|
1149
|
+
},
|
|
1150
|
+
get children() {
|
|
1151
|
+
return createComponent(Show, {
|
|
1152
|
+
get when() {
|
|
1153
|
+
return mode() === "name";
|
|
1154
|
+
},
|
|
1155
|
+
get children() {
|
|
1156
|
+
return createComponent(PageActions, {
|
|
1157
|
+
get dd() {
|
|
1158
|
+
return props.dd;
|
|
1159
|
+
},
|
|
1160
|
+
get p() {
|
|
1161
|
+
return props.p;
|
|
1162
|
+
},
|
|
1163
|
+
get path() {
|
|
1164
|
+
return props.row.path;
|
|
1165
|
+
},
|
|
1166
|
+
onRename: () => open("edit"),
|
|
1167
|
+
get onProblem() {
|
|
1168
|
+
return props.onProblem;
|
|
1169
|
+
},
|
|
1170
|
+
get busy() {
|
|
1171
|
+
return props.deleting;
|
|
1172
|
+
},
|
|
1173
|
+
get onBusy() {
|
|
1174
|
+
return props.onDeleting;
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
}), _el$16);
|
|
1181
|
+
insert(_el$14, createComponent(Show, {
|
|
1182
|
+
get when() {
|
|
1183
|
+
return props.problem;
|
|
1184
|
+
},
|
|
1185
|
+
children: (text) => (() => {
|
|
1186
|
+
var _el$35 = _tmpl$11();
|
|
1187
|
+
insert(_el$35, text);
|
|
1188
|
+
effect(() => `${props.p}-row-problem`, (_v$, _$p) => {
|
|
1189
|
+
className(_el$35, _v$, _$p);
|
|
1190
|
+
});
|
|
1191
|
+
return _el$35;
|
|
1192
|
+
})()
|
|
1193
|
+
}), _el$17);
|
|
1194
|
+
effect(() => {
|
|
1195
|
+
return {
|
|
1196
|
+
e: `${props.p}-row`,
|
|
1197
|
+
t: props.row.path,
|
|
1198
|
+
a: props.row.depth > 0 ? "" : void 0,
|
|
1199
|
+
o: props.row.last ? "" : void 0,
|
|
1200
|
+
i: props.row.depth,
|
|
1201
|
+
n: props.selected ? "" : void 0,
|
|
1202
|
+
s: onCanvas() ? void 0 : "",
|
|
1203
|
+
h: missing() ? "" : void 0,
|
|
1204
|
+
r: mode(),
|
|
1205
|
+
d: props.deleting ? "true" : void 0
|
|
1206
|
+
};
|
|
1207
|
+
}, ({ e, t, a, o, i, n, s, h, r, d }, _p$) => {
|
|
1208
|
+
className(_el$14, e, _p$?.e);
|
|
1209
|
+
t !== _p$?.t && setAttribute(_el$14, "data-path", t);
|
|
1210
|
+
a !== _p$?.a && setAttribute(_el$14, "data-threaded", a);
|
|
1211
|
+
o !== _p$?.o && setAttribute(_el$14, "data-last", o);
|
|
1212
|
+
i !== _p$?.i && setStyleProperty(_el$14, "--page-depth", i);
|
|
1213
|
+
n !== _p$?.n && setAttribute(_el$14, "data-selected", n);
|
|
1214
|
+
s !== _p$?.s && setAttribute(_el$14, "data-off", s);
|
|
1215
|
+
h !== _p$?.h && setAttribute(_el$14, "data-missing", h);
|
|
1216
|
+
r !== _p$?.r && setAttribute(_el$14, "data-mode", r);
|
|
1217
|
+
d !== _p$?.d && setAttribute(_el$14, "aria-busy", d);
|
|
1218
|
+
});
|
|
1219
|
+
return _el$14;
|
|
1220
|
+
}
|
|
1221
|
+
function RenameField(props) {
|
|
1222
|
+
const [busy, setBusy] = createSignal(false);
|
|
1223
|
+
let settled = false;
|
|
1224
|
+
const path = untrack(() => props.path);
|
|
1225
|
+
const commit = async (input, left) => {
|
|
1226
|
+
if (settled || busy()) return;
|
|
1227
|
+
const to = typedPagePath(path, input.value);
|
|
1228
|
+
if (to === "" || to === path) {
|
|
1229
|
+
settled = true;
|
|
1230
|
+
props.onClose(!left);
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
const list = props.list();
|
|
1234
|
+
setBusy(true);
|
|
1235
|
+
try {
|
|
1236
|
+
await props.dd.renamePage(path, to);
|
|
1237
|
+
settled = true;
|
|
1238
|
+
props.onClose(false);
|
|
1239
|
+
if (!left) focusName(list, props.p, to);
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
props.onProblem(reason(error));
|
|
1242
|
+
if (left) {
|
|
1243
|
+
settled = true;
|
|
1244
|
+
props.onClose(false);
|
|
1245
|
+
} else input.focus();
|
|
1246
|
+
} finally {
|
|
1247
|
+
setBusy(false);
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
var _el$36 = _tmpl$12();
|
|
1251
|
+
_el$36.addEventListener("blur", (event) => {
|
|
1252
|
+
if (!document.hasFocus()) return;
|
|
1253
|
+
const input = event.currentTarget;
|
|
1254
|
+
untrack(() => void commit(input, true));
|
|
1255
|
+
});
|
|
1256
|
+
_el$36._$$keydown = (event) => {
|
|
1257
|
+
if (isEnter(event)) {
|
|
1258
|
+
event.preventDefault();
|
|
1259
|
+
commit(event.currentTarget, false);
|
|
1260
|
+
} else if (event.key === "Escape") {
|
|
1261
|
+
event.preventDefault();
|
|
1262
|
+
event.stopPropagation();
|
|
1263
|
+
settled = true;
|
|
1264
|
+
props.onProblem(null);
|
|
1265
|
+
props.onClose(true);
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
ref(() => {
|
|
1269
|
+
return (node) => {
|
|
1270
|
+
node.value = path;
|
|
1271
|
+
queueMicrotask(() => {
|
|
1272
|
+
node.focus();
|
|
1273
|
+
const { start, end } = stemSpan(node.value);
|
|
1274
|
+
node.setSelectionRange(start, end);
|
|
1275
|
+
});
|
|
1276
|
+
};
|
|
1277
|
+
}, _el$36);
|
|
1278
|
+
setAttribute(_el$36, "aria-label", `New path for ${path}`);
|
|
1279
|
+
effect(() => {
|
|
1280
|
+
return {
|
|
1281
|
+
e: `${props.p}-rename`,
|
|
1282
|
+
t: busy()
|
|
1283
|
+
};
|
|
1284
|
+
}, ({ e, t }, _p$) => {
|
|
1285
|
+
className(_el$36, e, _p$?.e);
|
|
1286
|
+
t !== _p$?.t && setAttribute(_el$36, "readonly", t);
|
|
1287
|
+
});
|
|
1288
|
+
return _el$36;
|
|
1289
|
+
}
|
|
1290
|
+
function NewPage(props) {
|
|
1291
|
+
const [open, setOpen] = createSignal(false);
|
|
1292
|
+
const [busy, setBusy] = createSignal(false);
|
|
1293
|
+
const [problem, setProblem] = createSignal(null);
|
|
1294
|
+
let root;
|
|
1295
|
+
const close = (refocus) => {
|
|
1296
|
+
setOpen(false);
|
|
1297
|
+
setProblem(null);
|
|
1298
|
+
if (refocus) focusLater(root ?? null, `.${props.p}-new-button`);
|
|
1299
|
+
};
|
|
1300
|
+
const submit = async (input) => {
|
|
1301
|
+
const title = input.value.trim();
|
|
1302
|
+
if (title === "" || busy()) return;
|
|
1303
|
+
setBusy(true);
|
|
1304
|
+
setProblem(null);
|
|
1305
|
+
try {
|
|
1306
|
+
await createEmptyPage(props.dd, title);
|
|
1307
|
+
props.onCreated();
|
|
1308
|
+
close(true);
|
|
1309
|
+
} catch (error) {
|
|
1310
|
+
setProblem(reason(error));
|
|
1311
|
+
input.focus();
|
|
1312
|
+
} finally {
|
|
1313
|
+
setBusy(false);
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
var _el$37 = _tmpl$14();
|
|
1317
|
+
var _ref$3 = root;
|
|
1318
|
+
typeof _ref$3 === "function" || Array.isArray(_ref$3) ? ref(() => {
|
|
1319
|
+
return _ref$3;
|
|
1320
|
+
}, _el$37) : root = _el$37;
|
|
1321
|
+
insert(_el$37, createComponent(Show, {
|
|
1322
|
+
get when() {
|
|
1323
|
+
return open();
|
|
1324
|
+
},
|
|
1325
|
+
get fallback() {
|
|
1326
|
+
var _el$39 = _tmpl$15();
|
|
1327
|
+
var _el$40 = _el$39.firstChild;
|
|
1328
|
+
_el$39._$$click = () => setOpen(true);
|
|
1329
|
+
insert(_el$39, createComponent(Icon, { name: "plus" }), _el$40);
|
|
1330
|
+
effect(() => `${props.p}-new-button`, (_v$, _$p) => {
|
|
1331
|
+
className(_el$39, _v$, _$p);
|
|
1332
|
+
});
|
|
1333
|
+
return _el$39;
|
|
1334
|
+
},
|
|
1335
|
+
get children() {
|
|
1336
|
+
return [(() => {
|
|
1337
|
+
var _el$38 = _tmpl$13();
|
|
1338
|
+
_el$38.addEventListener("blur", (event) => {
|
|
1339
|
+
const empty = event.currentTarget.value.trim() === "";
|
|
1340
|
+
untrack(() => {
|
|
1341
|
+
if (empty && !busy()) close(false);
|
|
1342
|
+
});
|
|
1343
|
+
});
|
|
1344
|
+
_el$38._$$keydown = (event) => {
|
|
1345
|
+
if (isEnter(event)) {
|
|
1346
|
+
event.preventDefault();
|
|
1347
|
+
submit(event.currentTarget);
|
|
1348
|
+
} else if (event.key === "Escape") {
|
|
1349
|
+
event.preventDefault();
|
|
1350
|
+
event.stopPropagation();
|
|
1351
|
+
close(true);
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
ref(() => {
|
|
1355
|
+
return (node) => queueMicrotask(() => node.focus());
|
|
1356
|
+
}, _el$38);
|
|
1357
|
+
effect(() => {
|
|
1358
|
+
return {
|
|
1359
|
+
e: `${props.p}-new-input`,
|
|
1360
|
+
t: busy()
|
|
1361
|
+
};
|
|
1362
|
+
}, ({ e, t }, _p$) => {
|
|
1363
|
+
className(_el$38, e, _p$?.e);
|
|
1364
|
+
t !== _p$?.t && setAttribute(_el$38, "readonly", t);
|
|
1365
|
+
});
|
|
1366
|
+
return _el$38;
|
|
1367
|
+
})(), createComponent(Show, {
|
|
1368
|
+
get when() {
|
|
1369
|
+
return problem();
|
|
1370
|
+
},
|
|
1371
|
+
children: (text) => (() => {
|
|
1372
|
+
var _el$41 = _tmpl$11();
|
|
1373
|
+
insert(_el$41, text);
|
|
1374
|
+
effect(() => `${props.p}-problem`, (_v$, _$p) => {
|
|
1375
|
+
className(_el$41, _v$, _$p);
|
|
1376
|
+
});
|
|
1377
|
+
return _el$41;
|
|
1378
|
+
})()
|
|
1379
|
+
})];
|
|
1380
|
+
}
|
|
1381
|
+
}));
|
|
1382
|
+
effect(() => `${props.p}-new`, (_v$, _$p) => {
|
|
1383
|
+
className(_el$37, _v$, _$p);
|
|
1384
|
+
});
|
|
1385
|
+
return _el$37;
|
|
1386
|
+
}
|
|
1387
|
+
delegateEvents([
|
|
1388
|
+
"input",
|
|
1389
|
+
"click",
|
|
1390
|
+
"dblclick",
|
|
1391
|
+
"keydown"
|
|
1392
|
+
]);
|
|
1393
|
+
function activate(dd) {
|
|
1394
|
+
const p = classPrefix(dd.plugin.id);
|
|
1395
|
+
registerDrop(dd);
|
|
1396
|
+
dd.registerPanel({
|
|
1397
|
+
id: "pages",
|
|
1398
|
+
title: "Pages",
|
|
1399
|
+
grow: 1,
|
|
1400
|
+
styles: css(p),
|
|
1401
|
+
render: (context) => createPagesPanel(dd, context)
|
|
1402
|
+
});
|
|
1403
|
+
const actionsOf = (target) => target instanceof Element ? target.closest(`.${p}-confirm, .${p}-menu:popover-open`) : null;
|
|
1404
|
+
dd.registerCommand({
|
|
1405
|
+
id: `${dd.plugin.id}.cancel-delete`,
|
|
1406
|
+
title: "Pages: keep the page",
|
|
1407
|
+
scope: "canvas",
|
|
1408
|
+
when: (ctx) => actionsOf(ctx.event?.target) !== null,
|
|
1409
|
+
run: (ctx) => {
|
|
1410
|
+
const actions = actionsOf(ctx.event?.target);
|
|
1411
|
+
const cancel = actions?.querySelector("[data-cancel]");
|
|
1412
|
+
if (cancel) cancel.click();
|
|
1413
|
+
else if (actions instanceof HTMLElement) {
|
|
1414
|
+
actions.hidePopover();
|
|
1415
|
+
actions.parentElement?.querySelector(`.${p}-more`)?.focus();
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
dd.bindShortcut(`${dd.plugin.id}.cancel-delete`, "Escape");
|
|
1420
|
+
}
|
|
1421
|
+
export { activate as default };
|