pith-ui 0.1.1 → 0.2.0-app.1
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/AI.md +33 -8
- package/API.md +424 -268
- package/APP-API.md +2019 -0
- package/APP.md +137 -0
- package/README.md +37 -4
- package/dist/app/files.d.ts +68 -0
- package/dist/app/files.d.ts.map +1 -0
- package/dist/app/files.js +177 -0
- package/dist/app/files.js.map +1 -0
- package/dist/app/index.d.ts +57 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +300 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/internal.d.ts +31 -0
- package/dist/app/internal.d.ts.map +1 -0
- package/dist/app/internal.js +2 -0
- package/dist/app/internal.js.map +1 -0
- package/dist/app/resources.d.ts +89 -0
- package/dist/app/resources.d.ts.map +1 -0
- package/dist/app/resources.js +190 -0
- package/dist/app/resources.js.map +1 -0
- package/dist/app/session.d.ts +14 -0
- package/dist/app/session.d.ts.map +1 -0
- package/dist/app/session.js +12 -0
- package/dist/app/session.js.map +1 -0
- package/dist/app/settings.d.ts +109 -0
- package/dist/app/settings.d.ts.map +1 -0
- package/dist/app/settings.js +279 -0
- package/dist/app/settings.js.map +1 -0
- package/dist/app/workspace.d.ts +228 -0
- package/dist/app/workspace.d.ts.map +1 -0
- package/dist/app/workspace.js +402 -0
- package/dist/app/workspace.js.map +1 -0
- package/dist/composer.d.ts.map +1 -1
- package/dist/composer.js +37 -27
- package/dist/composer.js.map +1 -1
- package/dist/content/conversation-reader.d.ts.map +1 -1
- package/dist/content/conversation-reader.js +8 -1
- package/dist/content/conversation-reader.js.map +1 -1
- package/dist/content/conversation-view.d.ts.map +1 -1
- package/dist/content/conversation-view.js +34 -8
- package/dist/content/conversation-view.js.map +1 -1
- package/dist/content/image-viewer.d.ts.map +1 -1
- package/dist/content/image-viewer.js +11 -3
- package/dist/content/image-viewer.js.map +1 -1
- package/dist/content/paged-preview.d.ts +1 -1
- package/dist/content/paged-preview.d.ts.map +1 -1
- package/dist/content/paged-preview.js +4 -2
- package/dist/content/paged-preview.js.map +1 -1
- package/dist/content/views.d.ts +3 -0
- package/dist/content/views.d.ts.map +1 -1
- package/dist/content/views.js +110 -41
- package/dist/content/views.js.map +1 -1
- package/dist/content/welcome.d.ts.map +1 -1
- package/dist/content/welcome.js +5 -2
- package/dist/content/welcome.js.map +1 -1
- package/dist/dom.js +1 -1
- package/dist/dom.js.map +1 -1
- package/dist/files/panels.d.ts +2 -0
- package/dist/files/panels.d.ts.map +1 -1
- package/dist/files/panels.js +202 -128
- package/dist/files/panels.js.map +1 -1
- package/dist/files/systems.d.ts.map +1 -1
- package/dist/files/systems.js +37 -64
- package/dist/files/systems.js.map +1 -1
- package/dist/forms/actions.d.ts +24 -2
- package/dist/forms/actions.d.ts.map +1 -1
- package/dist/forms/actions.js +54 -25
- package/dist/forms/actions.js.map +1 -1
- package/dist/forms/custom-connection.d.ts.map +1 -1
- package/dist/forms/custom-connection.js +3 -2
- package/dist/forms/custom-connection.js.map +1 -1
- package/dist/forms/history.d.ts +1 -1
- package/dist/forms/history.d.ts.map +1 -1
- package/dist/forms/history.js +78 -15
- package/dist/forms/history.js.map +1 -1
- package/dist/forms/identity.d.ts.map +1 -1
- package/dist/forms/identity.js +9 -25
- package/dist/forms/identity.js.map +1 -1
- package/dist/forms/model-editor.js +3 -3
- package/dist/forms/model-editor.js.map +1 -1
- package/dist/forms/panels.d.ts +9 -2
- package/dist/forms/panels.d.ts.map +1 -1
- package/dist/forms/panels.js +79 -88
- package/dist/forms/panels.js.map +1 -1
- package/dist/forms/provider-login.d.ts.map +1 -1
- package/dist/forms/provider-login.js +20 -36
- package/dist/forms/provider-login.js.map +1 -1
- package/dist/forms/resource-editor.js +5 -4
- package/dist/forms/resource-editor.js.map +1 -1
- package/dist/foundations.d.ts +1 -1
- package/dist/foundations.d.ts.map +1 -1
- package/dist/foundations.js +22 -38
- package/dist/foundations.js.map +1 -1
- package/dist/navigation/context-menu.d.ts +7 -1
- package/dist/navigation/context-menu.d.ts.map +1 -1
- package/dist/navigation/context-menu.js +60 -57
- package/dist/navigation/context-menu.js.map +1 -1
- package/dist/navigation/navigation.d.ts +13 -0
- package/dist/navigation/navigation.d.ts.map +1 -1
- package/dist/navigation/navigation.js +96 -130
- package/dist/navigation/navigation.js.map +1 -1
- package/dist/operation.d.ts +12 -0
- package/dist/operation.d.ts.map +1 -0
- package/dist/operation.js +49 -0
- package/dist/operation.js.map +1 -0
- package/dist/primitives.d.ts +8 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +114 -143
- package/dist/primitives.js.map +1 -1
- package/dist/reconcile.d.ts +11 -0
- package/dist/reconcile.d.ts.map +1 -0
- package/dist/reconcile.js +36 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/select.d.ts +14 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +304 -0
- package/dist/select.js.map +1 -0
- package/dist/styles.css +439 -370
- package/dist/surface.d.ts +31 -0
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js +193 -3
- package/dist/surface.js.map +1 -1
- package/dist/tasks/approval.d.ts.map +1 -1
- package/dist/tasks/approval.js +83 -45
- package/dist/tasks/approval.js.map +1 -1
- package/dist/tasks/permission-element.d.ts +3 -0
- package/dist/tasks/permission-element.d.ts.map +1 -0
- package/dist/tasks/permission-element.js +10 -0
- package/dist/tasks/permission-element.js.map +1 -0
- package/dist/tasks/permission.d.ts.map +1 -1
- package/dist/tasks/permission.js +37 -18
- package/dist/tasks/permission.js.map +1 -1
- package/dist/tasks/runtime.d.ts.map +1 -1
- package/dist/tasks/runtime.js +32 -15
- package/dist/tasks/runtime.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +93 -40
- package/dist/workspace.js.map +1 -1
- package/package.json +42 -8
package/dist/files/panels.js
CHANGED
|
@@ -2,6 +2,8 @@ import { dialogHeading, escape, icon, uniqueId, setText } from '../dom.js';
|
|
|
2
2
|
import { createPagedPreview } from '../content/paged-preview.js';
|
|
3
3
|
import { adoptProductParts } from '../foundations.js';
|
|
4
4
|
import { createButton } from '../primitives.js';
|
|
5
|
+
import { bindContentClose, installAnchoredSurface } from '../surface.js';
|
|
6
|
+
import { reconcileKeyed } from '../reconcile.js';
|
|
5
7
|
export function fileActionsMarkup(options) {
|
|
6
8
|
const scope = `data-idle-action ${options.kind === 'resource' ? 'data-idle-workspace' : 'data-idle-conversation'}="${escape(options.ownerId)}"`;
|
|
7
9
|
const attributes = `${scope} data-file-kind="${escape(options.kind)}" data-file-owner="${escape(options.ownerId)}" data-file-path="${escape(options.path)}"`;
|
|
@@ -13,14 +15,25 @@ export function createFileActions(options) {
|
|
|
13
15
|
const template = document.createElement('template');
|
|
14
16
|
template.innerHTML = fileActionsMarkup(options);
|
|
15
17
|
const element = template.content.firstElementChild;
|
|
18
|
+
const parts = adoptProductParts(element);
|
|
19
|
+
let destroyed = false;
|
|
16
20
|
const click = (event) => {
|
|
17
21
|
const target = event.target.closest('button');
|
|
18
|
-
if (target && !target.disabled)
|
|
22
|
+
if (target && element.contains(target) && !target.disabled) {
|
|
23
|
+
event.stopPropagation();
|
|
19
24
|
options.onAction?.(target.dataset.fileAction || 'preview');
|
|
25
|
+
}
|
|
20
26
|
};
|
|
21
27
|
if (options.onAction)
|
|
22
28
|
element.addEventListener('click', click);
|
|
23
|
-
return {
|
|
29
|
+
return {
|
|
30
|
+
element,
|
|
31
|
+
setDisabled(disabled) { if (!destroyed)
|
|
32
|
+
for (const button of element.querySelectorAll('button'))
|
|
33
|
+
parts.action(button).update({ disabled }); },
|
|
34
|
+
destroy() { if (destroyed)
|
|
35
|
+
return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); element.remove(); },
|
|
36
|
+
};
|
|
24
37
|
}
|
|
25
38
|
export function createArtifactPanel(options) {
|
|
26
39
|
const { container: element, control, toggle, count } = options;
|
|
@@ -31,37 +44,35 @@ export function createArtifactPanel(options) {
|
|
|
31
44
|
const error = element.querySelector('[role="alert"]');
|
|
32
45
|
const parts = adoptProductParts(element);
|
|
33
46
|
const entries = new Map();
|
|
34
|
-
let open = false;
|
|
35
47
|
let destroyed = false;
|
|
48
|
+
const surface = installAnchoredSurface({
|
|
49
|
+
trigger: toggle,
|
|
50
|
+
panel: element,
|
|
51
|
+
position: false,
|
|
52
|
+
closeOnFocusOut: true,
|
|
53
|
+
exclusions: [control, ...(options.dismissExclusions ?? [])],
|
|
54
|
+
canOpen: () => !control.hidden,
|
|
55
|
+
canEscape: () => !document.querySelector('dialog[open]'),
|
|
56
|
+
onToggle(open) { if (open)
|
|
57
|
+
element.focus(); },
|
|
58
|
+
});
|
|
36
59
|
function setOpen(value, restoreFocus = false) {
|
|
37
60
|
if (destroyed)
|
|
38
61
|
return;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
element.focus();
|
|
44
|
-
else if (restoreFocus && !control.hidden)
|
|
45
|
-
toggle.focus();
|
|
62
|
+
if (value)
|
|
63
|
+
surface.open();
|
|
64
|
+
else
|
|
65
|
+
surface.close(restoreFocus && !control.hidden);
|
|
46
66
|
}
|
|
47
67
|
const abort = new AbortController();
|
|
48
|
-
toggle.addEventListener('click', () => setOpen(!
|
|
68
|
+
toggle.addEventListener('click', () => setOpen(!surface.isOpen()), { signal: abort.signal });
|
|
49
69
|
element.addEventListener('click', event => { if (event.target.closest('[data-artifacts-close]'))
|
|
50
70
|
setOpen(false, true); }, { signal: abort.signal });
|
|
51
|
-
const outside = (event) => { const target = event.target; if (open && !element.contains(target) && !control.contains(target) && !options.dismissExclusions?.some(node => node.contains(target)))
|
|
52
|
-
setOpen(false); };
|
|
53
|
-
document.addEventListener('click', outside, { signal: abort.signal });
|
|
54
|
-
document.addEventListener('focusin', outside, { signal: abort.signal });
|
|
55
|
-
document.addEventListener('keydown', event => { if (event.key === 'Escape' && open && !document.querySelector('dialog[open]')) {
|
|
56
|
-
event.preventDefault();
|
|
57
|
-
setOpen(false, true);
|
|
58
|
-
} }, { signal: abort.signal });
|
|
59
71
|
return {
|
|
60
|
-
element, setOpen, get open() { return
|
|
72
|
+
element, setOpen, get open() { return surface.isOpen(); },
|
|
61
73
|
update(state) {
|
|
62
74
|
if (destroyed)
|
|
63
75
|
return;
|
|
64
|
-
const focused = document.activeElement;
|
|
65
76
|
control.hidden = !state.ownerId || (!state.files.length && !state.error);
|
|
66
77
|
if (control.hidden)
|
|
67
78
|
setOpen(false);
|
|
@@ -74,61 +85,42 @@ export function createArtifactPanel(options) {
|
|
|
74
85
|
loading.hidden = !state.loading;
|
|
75
86
|
error.hidden = !state.error;
|
|
76
87
|
parts.feedback(error).update({ message: state.error, tone: 'error' });
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
entries.delete(key);
|
|
82
|
-
}
|
|
83
|
-
let cursor = rows.firstElementChild;
|
|
84
|
-
for (const file of state.files) {
|
|
85
|
-
const key = `${state.ownerId}/${file.path}`;
|
|
86
|
-
let entry = entries.get(key);
|
|
87
|
-
if (!entry) {
|
|
88
|
+
reconcileKeyed(rows, entries, state.files, {
|
|
89
|
+
key: file => `${state.ownerId}/${file.path}`,
|
|
90
|
+
element: entry => entry.element,
|
|
91
|
+
create(file) {
|
|
88
92
|
const article = document.createElement('article');
|
|
89
93
|
article.className = 'pui-file-card';
|
|
90
94
|
article.innerHTML = `${icon('file')}<div class="pui-file-info"><strong></strong><span class="pui-file-path">${escape(file.path)}</span></div>${fileActionsMarkup({ kind: 'artifact', ownerId: state.ownerId, path: file.path, preview: true, copyMode: state.copyMode })}`;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (focused instanceof HTMLElement && element.contains(focused) && document.activeElement !== focused)
|
|
105
|
-
focused.focus({ preventScroll: true });
|
|
95
|
+
return { element: article, name: article.querySelector('strong'), copy: article.querySelector('[data-file-action="copy"], [data-file-action="copy-path"]') };
|
|
96
|
+
},
|
|
97
|
+
update(entry, file) {
|
|
98
|
+
setText(entry.name, file.name);
|
|
99
|
+
const copyAction = state.copyMode === 'file' ? 'copy' : 'copy-path';
|
|
100
|
+
if (entry.copy.dataset.fileAction !== copyAction)
|
|
101
|
+
entry.copy.dataset.fileAction = copyAction;
|
|
102
|
+
if (entry.copy.dataset.copyPending !== 'true')
|
|
103
|
+
setText(entry.copy, state.copyMode === 'file' ? 'Copy file' : 'Copy path');
|
|
104
|
+
},
|
|
105
|
+
destroy() { },
|
|
106
|
+
});
|
|
107
|
+
parts.update();
|
|
106
108
|
},
|
|
107
|
-
destroy() { destroyed = true; abort.abort(); parts.destroy(); entries.clear(); element.replaceChildren(); },
|
|
109
|
+
destroy() { destroyed = true; surface.destroy(); abort.abort(); parts.destroy(); entries.clear(); element.replaceChildren(); },
|
|
108
110
|
};
|
|
109
111
|
}
|
|
110
112
|
export function createResourcesPanel(options = {}) {
|
|
111
113
|
const element = options.container || document.createElement('div');
|
|
112
114
|
const ids = { titleId: options.titleId || uniqueId('pui-resources-title'), dialogId: options.dialogId || uniqueId('pui-resources-dialog'), listId: options.listId || uniqueId('pui-resources-list'), errorId: options.errorId || uniqueId('pui-resources-error') };
|
|
113
|
-
const close = (
|
|
114
|
-
if (!event.target.closest('[data-close]'))
|
|
115
|
-
return;
|
|
116
|
-
if (options.onClose)
|
|
117
|
-
options.onClose();
|
|
118
|
-
else {
|
|
119
|
-
const dialog = element.closest('dialog');
|
|
120
|
-
if (dialog?.open)
|
|
121
|
-
dialog.close();
|
|
122
|
-
else
|
|
123
|
-
element.hidden = true;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
element.addEventListener('click', close);
|
|
115
|
+
const close = bindContentClose(element, { dialogId: ids.dialogId, onClose: options.onClose });
|
|
127
116
|
let list, error;
|
|
128
117
|
let destroyed = false;
|
|
129
118
|
const parts = adoptProductParts(element);
|
|
130
119
|
const buttons = [];
|
|
131
120
|
const rowButtons = [];
|
|
121
|
+
const sections = new Map();
|
|
122
|
+
let diagnostics;
|
|
123
|
+
let instructionButton;
|
|
132
124
|
const createActions = new Map();
|
|
133
125
|
let createDisabled = false;
|
|
134
126
|
const button = (label, onAction, row = false, create = false) => { const block = createButton({ label, appearance: 'secondary', onAction, disabled: create && createDisabled }); (row ? rowButtons : buttons).push(block); if (create)
|
|
@@ -137,25 +129,53 @@ export function createResourcesPanel(options = {}) {
|
|
|
137
129
|
createActions.delete(block);
|
|
138
130
|
block.destroy();
|
|
139
131
|
} };
|
|
140
|
-
function
|
|
132
|
+
function updateSlot(parent, slot, source) {
|
|
133
|
+
if (slot.source === source)
|
|
134
|
+
return;
|
|
135
|
+
for (const node of slot.nodes)
|
|
136
|
+
if (node.parentNode === parent)
|
|
137
|
+
node.remove();
|
|
138
|
+
slot.source = source;
|
|
139
|
+
slot.nodes = source ? source instanceof DocumentFragment ? [...source.childNodes] : [source] : [];
|
|
140
|
+
}
|
|
141
|
+
function row(type) {
|
|
141
142
|
const outer = document.createElement('article');
|
|
142
143
|
outer.className = type === 'instructions' ? 'pui-resource-card' : 'pui-file-card';
|
|
143
144
|
const body = type === 'instructions' ? document.createElement('div') : outer;
|
|
144
145
|
if (type === 'instructions')
|
|
145
146
|
body.className = 'pui-file-card';
|
|
146
|
-
body.innerHTML = `${type === 'template' ? '' : icon('file')}<div class="pui-file-info"><strong
|
|
147
|
-
|
|
148
|
-
body.append(entry.fileActions);
|
|
149
|
-
if (entry.actions)
|
|
150
|
-
body.append(entry.actions);
|
|
147
|
+
body.innerHTML = `${type === 'template' ? '' : icon('file')}<div class="pui-file-info"><strong></strong>${type !== 'instructions' ? '<p></p>' : ''}<span class="pui-file-path"></span></div>`;
|
|
148
|
+
let content;
|
|
151
149
|
if (type === 'instructions') {
|
|
152
150
|
outer.append(body);
|
|
153
151
|
const details = document.createElement('details');
|
|
154
152
|
details.className = 'pui-resource-preview';
|
|
155
|
-
details.innerHTML =
|
|
153
|
+
details.innerHTML = '<summary>View instructions</summary><pre></pre>';
|
|
156
154
|
outer.append(details);
|
|
155
|
+
content = details.querySelector('pre');
|
|
156
|
+
}
|
|
157
|
+
return { element: outer, body, name: body.querySelector('strong'), description: body.querySelector('p') || undefined, path: body.querySelector('.pui-file-path'), content, slots: [{ nodes: [] }, { nodes: [] }] };
|
|
158
|
+
}
|
|
159
|
+
function updateRow(row, entry) {
|
|
160
|
+
setText(row.name, entry.name);
|
|
161
|
+
setText(row.path, entry.path);
|
|
162
|
+
if (row.description)
|
|
163
|
+
setText(row.description, entry.description || '');
|
|
164
|
+
if (row.content)
|
|
165
|
+
setText(row.content, entry.content || '');
|
|
166
|
+
updateSlot(row.body, row.slots[0], entry.fileActions);
|
|
167
|
+
updateSlot(row.body, row.slots[1], entry.actions);
|
|
168
|
+
let cursor = row.body.querySelector('.pui-file-info').nextSibling;
|
|
169
|
+
for (const node of row.slots.flatMap(slot => slot.nodes)) {
|
|
170
|
+
if (node !== cursor)
|
|
171
|
+
row.body.insertBefore(node, cursor);
|
|
172
|
+
cursor = node.nextSibling;
|
|
157
173
|
}
|
|
158
|
-
|
|
174
|
+
}
|
|
175
|
+
function section() {
|
|
176
|
+
const element = document.createElement('section');
|
|
177
|
+
element.className = 'pui-resource-section';
|
|
178
|
+
return { element, rows: new Map(), create: { nodes: [] } };
|
|
159
179
|
}
|
|
160
180
|
return {
|
|
161
181
|
element,
|
|
@@ -164,6 +184,9 @@ export function createResourcesPanel(options = {}) {
|
|
|
164
184
|
return;
|
|
165
185
|
clearButtons();
|
|
166
186
|
clearButtons(rowButtons);
|
|
187
|
+
instructionButton = undefined;
|
|
188
|
+
sections.clear();
|
|
189
|
+
diagnostics = undefined;
|
|
167
190
|
element.hidden = false;
|
|
168
191
|
element.innerHTML = `${dialogHeading('Workspace resources', ids.titleId, ids.dialogId, workspaceName)}<p class="pui-modal-description">Instructions, skills and prompt templates are loaded by Pith for each task. Edit them here or open their Markdown files.</p><div class="pui-feature-toolbar" data-resources-toolbar></div><div id="${escape(ids.listId)}" data-resources-list><p class="pui-feature-hint">Loading workspace resources…</p></div><div id="${escape(ids.errorId)}" data-resources-error class="pui-form-error" role="alert"></div>`;
|
|
169
192
|
const actions = element.querySelector('[data-resources-toolbar]');
|
|
@@ -183,64 +206,96 @@ export function createResourcesPanel(options = {}) {
|
|
|
183
206
|
update(state) {
|
|
184
207
|
if (destroyed || !list)
|
|
185
208
|
return;
|
|
186
|
-
|
|
187
|
-
|
|
209
|
+
if (!sections.size)
|
|
210
|
+
list.replaceChildren();
|
|
188
211
|
for (const [title, entries, type, empty] of [
|
|
189
212
|
['Instructions', state.instructions, 'instructions', 'No workspace instructions found.'],
|
|
190
213
|
['Skills', state.skills, 'skill', 'No skills found. Add .pi/skills/<skill-name>/SKILL.md in this workspace, then refresh.'],
|
|
191
214
|
['Prompt templates', state.templates, 'template', 'No prompt templates yet.'],
|
|
192
215
|
]) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
216
|
+
let current = sections.get(type);
|
|
217
|
+
if (!current) {
|
|
218
|
+
current = section();
|
|
219
|
+
sections.set(type, current);
|
|
220
|
+
list.append(current.element);
|
|
221
|
+
}
|
|
222
|
+
const items = [{ key: 'heading', kind: 'heading' }, ...entries.map(entry => ({ key: `entry:${entry.path}`, kind: 'entry', entry }))];
|
|
223
|
+
if (!entries.length)
|
|
224
|
+
items.push({ key: 'empty', kind: 'empty' });
|
|
225
|
+
reconcileKeyed(current.element, current.rows, items, {
|
|
226
|
+
key: item => item.key, element: row => row.element,
|
|
227
|
+
create(item) {
|
|
228
|
+
if (item.kind === 'entry')
|
|
229
|
+
return row(type);
|
|
230
|
+
const element = document.createElement(item.kind === 'heading' ? 'h3' : 'p');
|
|
231
|
+
if (item.kind === 'empty')
|
|
232
|
+
element.className = 'pui-feature-hint';
|
|
233
|
+
return { element };
|
|
234
|
+
},
|
|
235
|
+
update(row, item) { if (item.entry)
|
|
236
|
+
updateRow(row, item.entry);
|
|
237
|
+
else
|
|
238
|
+
setText(row.element, item.kind === 'heading' ? title : empty); },
|
|
239
|
+
destroy() { },
|
|
240
|
+
});
|
|
241
|
+
if (type === 'instructions') {
|
|
242
|
+
let create = state.createInstructions;
|
|
243
|
+
if (!create && state.canCreateInstructions) {
|
|
244
|
+
if (!instructionButton) {
|
|
245
|
+
const element = button('Create AGENTS.md in this workspace', () => options.onCreate?.('instructions'), true, true);
|
|
246
|
+
instructionButton = rowButtons.find(block => block.element === element);
|
|
247
|
+
}
|
|
248
|
+
create = instructionButton.element;
|
|
249
|
+
}
|
|
250
|
+
updateSlot(current.element, current.create, create);
|
|
251
|
+
for (const node of current.create.nodes)
|
|
252
|
+
if (node.parentNode !== current.element)
|
|
253
|
+
current.element.append(node);
|
|
205
254
|
}
|
|
206
|
-
if (type === 'instructions' && state.createInstructions)
|
|
207
|
-
section.append(state.createInstructions);
|
|
208
|
-
else if (type === 'instructions' && state.canCreateInstructions)
|
|
209
|
-
section.append(button('Create AGENTS.md in this workspace', () => options.onCreate?.('instructions'), true, true));
|
|
210
|
-
list.append(section);
|
|
211
255
|
}
|
|
212
|
-
parts.update();
|
|
213
256
|
if (state.diagnostics.length) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
257
|
+
if (!diagnostics) {
|
|
258
|
+
diagnostics = section();
|
|
259
|
+
diagnostics.element.classList.add('pui-resource-diagnostics');
|
|
260
|
+
list.append(diagnostics.element);
|
|
261
|
+
}
|
|
262
|
+
reconcileKeyed(diagnostics.element, diagnostics.rows, [{ key: 'heading', text: 'Resource notes' }, ...state.diagnostics.map((text, index) => ({ key: `note:${index}`, text }))], {
|
|
263
|
+
key: value => value.key, element: row => row.element,
|
|
264
|
+
create(value) { return { element: document.createElement(value.key === 'heading' ? 'h3' : 'p') }; },
|
|
265
|
+
update(row, value) { setText(row.element, value.text); }, destroy() { },
|
|
266
|
+
});
|
|
218
267
|
}
|
|
268
|
+
else if (diagnostics) {
|
|
269
|
+
diagnostics.element.remove();
|
|
270
|
+
diagnostics = undefined;
|
|
271
|
+
}
|
|
272
|
+
parts.update();
|
|
219
273
|
},
|
|
220
|
-
destroy() {
|
|
274
|
+
destroy() { if (destroyed)
|
|
275
|
+
return; destroyed = true; clearButtons(); clearButtons(rowButtons); sections.clear(); diagnostics = undefined; parts.destroy(); close.destroy(); element.replaceChildren(); },
|
|
221
276
|
};
|
|
222
277
|
}
|
|
223
278
|
export function createFilePreview(options = {}) {
|
|
224
279
|
const element = options.container || document.createElement('div');
|
|
225
280
|
const ids = { titleId: options.titleId || uniqueId('pui-preview-title'), dialogId: options.dialogId || uniqueId('pui-preview-dialog'), bodyId: options.bodyId || uniqueId('pui-preview-body') };
|
|
226
|
-
const close = (
|
|
227
|
-
if (!event.target.closest('[data-close]'))
|
|
228
|
-
return;
|
|
229
|
-
if (options.onClose)
|
|
230
|
-
options.onClose();
|
|
231
|
-
else {
|
|
232
|
-
const dialog = element.closest('dialog');
|
|
233
|
-
if (dialog?.open)
|
|
234
|
-
dialog.close();
|
|
235
|
-
else
|
|
236
|
-
element.hidden = true;
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
element.addEventListener('click', close);
|
|
281
|
+
const close = bindContentClose(element, { dialogId: ids.dialogId, onClose: options.onClose });
|
|
240
282
|
let body;
|
|
241
283
|
let page;
|
|
284
|
+
let image;
|
|
285
|
+
let note;
|
|
286
|
+
let mode;
|
|
242
287
|
let destroyed = false;
|
|
243
|
-
function clear() {
|
|
288
|
+
function clear() {
|
|
289
|
+
if (destroyed)
|
|
290
|
+
return;
|
|
291
|
+
page?.destroy();
|
|
292
|
+
page = undefined;
|
|
293
|
+
image = undefined;
|
|
294
|
+
note = undefined;
|
|
295
|
+
mode = undefined;
|
|
296
|
+
element.replaceChildren();
|
|
297
|
+
body = undefined;
|
|
298
|
+
}
|
|
244
299
|
return {
|
|
245
300
|
element, clear,
|
|
246
301
|
open(input) {
|
|
@@ -255,32 +310,51 @@ export function createFilePreview(options = {}) {
|
|
|
255
310
|
update(state) {
|
|
256
311
|
if (destroyed || !body)
|
|
257
312
|
return;
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
313
|
+
const nextMode = state.error ? 'error' : state.kind;
|
|
314
|
+
if (mode !== nextMode) {
|
|
315
|
+
page?.destroy();
|
|
316
|
+
page = undefined;
|
|
317
|
+
image = undefined;
|
|
318
|
+
note = undefined;
|
|
319
|
+
body.replaceChildren();
|
|
320
|
+
mode = nextMode;
|
|
321
|
+
}
|
|
261
322
|
if (state.error)
|
|
262
|
-
body
|
|
323
|
+
setText(body, state.error);
|
|
263
324
|
else if (state.kind === 'image') {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
325
|
+
if (!image) {
|
|
326
|
+
image = document.createElement('img');
|
|
327
|
+
image.className = 'pui-file-preview-image';
|
|
328
|
+
image.setAttribute('role', 'button');
|
|
329
|
+
image.tabIndex = 0;
|
|
330
|
+
image.title = 'Click to enlarge';
|
|
331
|
+
body.append(image);
|
|
332
|
+
}
|
|
333
|
+
if (image.getAttribute('src') !== (state.imageSrc || ''))
|
|
334
|
+
image.src = state.imageSrc || '';
|
|
335
|
+
if (image.alt !== (state.imageAlt || ''))
|
|
336
|
+
image.alt = state.imageAlt || '';
|
|
272
337
|
}
|
|
338
|
+
else if (page)
|
|
339
|
+
page.update({ text: state.text || '', kind: state.kind });
|
|
273
340
|
else
|
|
274
|
-
page = createPagedPreview({ container: body, text: state.text || '', kind: state.kind });
|
|
341
|
+
page = createPagedPreview({ container: body, text: state.text || '', kind: state.kind, onCopyCode: options.onCopyCode });
|
|
275
342
|
if (state.truncated) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
343
|
+
if (!note) {
|
|
344
|
+
note = document.createElement('p');
|
|
345
|
+
note.className = 'pui-preview-note';
|
|
346
|
+
note.textContent = 'Showing the first 8 MiB. Use Open for the complete file.';
|
|
347
|
+
}
|
|
348
|
+
if (note.parentElement !== body)
|
|
349
|
+
body.append(note);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
note?.remove();
|
|
353
|
+
note = undefined;
|
|
280
354
|
}
|
|
281
355
|
},
|
|
282
356
|
destroy() { if (destroyed)
|
|
283
|
-
return; clear();
|
|
357
|
+
return; clear(); close.destroy(); destroyed = true; },
|
|
284
358
|
};
|
|
285
359
|
}
|
|
286
360
|
//# sourceMappingURL=panels.js.map
|