pith-ui 0.0.0-stage → 0.1.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/AI.md +67 -0
- package/API.md +3281 -0
- package/LICENSE +661 -0
- package/README.md +80 -2
- package/dist/composer.d.ts +38 -0
- package/dist/composer.d.ts.map +1 -0
- package/dist/composer.js +114 -0
- package/dist/composer.js.map +1 -0
- package/dist/content/conversation-reader.d.ts +19 -0
- package/dist/content/conversation-reader.d.ts.map +1 -0
- package/dist/content/conversation-reader.js +280 -0
- package/dist/content/conversation-reader.js.map +1 -0
- package/dist/content/conversation-view.d.ts +48 -0
- package/dist/content/conversation-view.d.ts.map +1 -0
- package/dist/content/conversation-view.js +107 -0
- package/dist/content/conversation-view.js.map +1 -0
- package/dist/content/image-viewer.d.ts +23 -0
- package/dist/content/image-viewer.d.ts.map +1 -0
- package/dist/content/image-viewer.js +101 -0
- package/dist/content/image-viewer.js.map +1 -0
- package/dist/content/markdown.d.ts +12 -0
- package/dist/content/markdown.d.ts.map +1 -0
- package/dist/content/markdown.js +68 -0
- package/dist/content/markdown.js.map +1 -0
- package/dist/content/paged-preview.d.ts +15 -0
- package/dist/content/paged-preview.d.ts.map +1 -0
- package/dist/content/paged-preview.js +105 -0
- package/dist/content/paged-preview.js.map +1 -0
- package/dist/content/views.d.ts +9 -0
- package/dist/content/views.d.ts.map +1 -0
- package/dist/content/views.js +53 -0
- package/dist/content/views.js.map +1 -0
- package/dist/content/welcome.d.ts +18 -0
- package/dist/content/welcome.d.ts.map +1 -0
- package/dist/content/welcome.js +45 -0
- package/dist/content/welcome.js.map +1 -0
- package/dist/core.d.ts +36 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +44 -0
- package/dist/core.js.map +1 -0
- package/dist/dom.d.ts +14 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +69 -0
- package/dist/dom.js.map +1 -0
- package/dist/files/panels.d.ts +95 -0
- package/dist/files/panels.d.ts.map +1 -0
- package/dist/files/panels.js +245 -0
- package/dist/files/panels.js.map +1 -0
- package/dist/files/systems.d.ts +91 -0
- package/dist/files/systems.d.ts.map +1 -0
- package/dist/files/systems.js +256 -0
- package/dist/files/systems.js.map +1 -0
- package/dist/forms/actions.d.ts +27 -0
- package/dist/forms/actions.d.ts.map +1 -0
- package/dist/forms/actions.js +19 -0
- package/dist/forms/actions.js.map +1 -0
- package/dist/forms/custom-connection.d.ts +61 -0
- package/dist/forms/custom-connection.d.ts.map +1 -0
- package/dist/forms/custom-connection.js +65 -0
- package/dist/forms/custom-connection.js.map +1 -0
- package/dist/forms/dialog-frame.d.ts +39 -0
- package/dist/forms/dialog-frame.d.ts.map +1 -0
- package/dist/forms/dialog-frame.js +75 -0
- package/dist/forms/dialog-frame.js.map +1 -0
- package/dist/forms/history.d.ts +16 -0
- package/dist/forms/history.d.ts.map +1 -0
- package/dist/forms/history.js +21 -0
- package/dist/forms/history.js.map +1 -0
- package/dist/forms/identity.d.ts +4 -0
- package/dist/forms/identity.d.ts.map +1 -0
- package/dist/forms/identity.js +21 -0
- package/dist/forms/identity.js.map +1 -0
- package/dist/forms/model-editor.d.ts +35 -0
- package/dist/forms/model-editor.d.ts.map +1 -0
- package/dist/forms/model-editor.js +78 -0
- package/dist/forms/model-editor.js.map +1 -0
- package/dist/forms/panels.d.ts +57 -0
- package/dist/forms/panels.d.ts.map +1 -0
- package/dist/forms/panels.js +224 -0
- package/dist/forms/panels.js.map +1 -0
- package/dist/forms/provider-login.d.ts +22 -0
- package/dist/forms/provider-login.d.ts.map +1 -0
- package/dist/forms/provider-login.js +114 -0
- package/dist/forms/provider-login.js.map +1 -0
- package/dist/forms/resource-editor.d.ts +23 -0
- package/dist/forms/resource-editor.d.ts.map +1 -0
- package/dist/forms/resource-editor.js +24 -0
- package/dist/forms/resource-editor.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation/context-menu.d.ts +25 -0
- package/dist/navigation/context-menu.d.ts.map +1 -0
- package/dist/navigation/context-menu.js +67 -0
- package/dist/navigation/context-menu.js.map +1 -0
- package/dist/navigation/navigation.d.ts +57 -0
- package/dist/navigation/navigation.d.ts.map +1 -0
- package/dist/navigation/navigation.js +185 -0
- package/dist/navigation/navigation.js.map +1 -0
- package/dist/primitives.d.ts +307 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +741 -0
- package/dist/primitives.js.map +1 -0
- package/dist/styles.css +849 -0
- package/dist/tasks/approval.d.ts +25 -0
- package/dist/tasks/approval.d.ts.map +1 -0
- package/dist/tasks/approval.js +61 -0
- package/dist/tasks/approval.js.map +1 -0
- package/dist/tasks/permission.d.ts +35 -0
- package/dist/tasks/permission.d.ts.map +1 -0
- package/dist/tasks/permission.js +67 -0
- package/dist/tasks/permission.js.map +1 -0
- package/dist/tasks/runtime.d.ts +31 -0
- package/dist/tasks/runtime.d.ts.map +1 -0
- package/dist/tasks/runtime.js +34 -0
- package/dist/tasks/runtime.js.map +1 -0
- package/dist/theme.d.ts +4 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +6 -0
- package/dist/theme.js.map +1 -0
- package/dist/workspace.d.ts +38 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +183 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +27 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export * from './core.js';
|
|
2
|
+
export * from './dom.js';
|
|
3
|
+
export * from './primitives.js';
|
|
4
|
+
export * from './theme.js';
|
|
5
|
+
export * from './workspace.js';
|
|
6
|
+
export * from './composer.js';
|
|
7
|
+
export * from './content/markdown.js';
|
|
8
|
+
export * from './content/conversation-reader.js';
|
|
9
|
+
export * from './content/conversation-view.js';
|
|
10
|
+
export * from './content/paged-preview.js';
|
|
11
|
+
export * from './content/image-viewer.js';
|
|
12
|
+
export * from './content/welcome.js';
|
|
13
|
+
export * from './forms/panels.js';
|
|
14
|
+
export * from './forms/model-editor.js';
|
|
15
|
+
export * from './forms/custom-connection.js';
|
|
16
|
+
export * from './forms/resource-editor.js';
|
|
17
|
+
export * from './forms/history.js';
|
|
18
|
+
export * from './forms/provider-login.js';
|
|
19
|
+
export * from './forms/dialog-frame.js';
|
|
20
|
+
export * from './forms/actions.js';
|
|
21
|
+
export * from './files/panels.js';
|
|
22
|
+
export * from './files/systems.js';
|
|
23
|
+
export * from './navigation/navigation.js';
|
|
24
|
+
export * from './navigation/context-menu.js';
|
|
25
|
+
export * from './tasks/approval.js';
|
|
26
|
+
export * from './tasks/permission.js';
|
|
27
|
+
export * from './tasks/runtime.js';
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC","sourcesContent":["export * from './core.js';\nexport * from './dom.js';\nexport * from './primitives.js';\nexport * from './theme.js';\nexport * from './workspace.js';\nexport * from './composer.js';\nexport * from './content/markdown.js';\nexport * from './content/conversation-reader.js';\nexport * from './content/conversation-view.js';\nexport * from './content/paged-preview.js';\nexport * from './content/image-viewer.js';\nexport * from './content/welcome.js';\nexport * from './forms/panels.js';\nexport * from './forms/model-editor.js';\nexport * from './forms/custom-connection.js';\nexport * from './forms/resource-editor.js';\nexport * from './forms/history.js';\nexport * from './forms/provider-login.js';\nexport * from './forms/dialog-frame.js';\nexport * from './forms/actions.js';\nexport * from './files/panels.js';\nexport * from './files/systems.js';\nexport * from './navigation/navigation.js';\nexport * from './navigation/context-menu.js';\nexport * from './tasks/approval.js';\nexport * from './tasks/permission.js';\nexport * from './tasks/runtime.js';\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { UIBlock } from '../core.js';
|
|
2
|
+
export interface ContextMenuItem {
|
|
3
|
+
label: string;
|
|
4
|
+
action?: string;
|
|
5
|
+
sdkAction?: string;
|
|
6
|
+
danger?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
idle?: {
|
|
9
|
+
conversationId?: string;
|
|
10
|
+
workspaceId?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface ContextMenuState {
|
|
14
|
+
label: string;
|
|
15
|
+
items: readonly ContextMenuItem[];
|
|
16
|
+
}
|
|
17
|
+
export declare function createContextMenu(options?: {
|
|
18
|
+
element?: HTMLElement;
|
|
19
|
+
onDismiss?: (restoreFocus: boolean) => void;
|
|
20
|
+
onAction?: (item: ContextMenuItem) => void;
|
|
21
|
+
}): UIBlock<ContextMenuState> & {
|
|
22
|
+
open(trigger: HTMLElement, state: ContextMenuState): void;
|
|
23
|
+
close(restoreFocus?: boolean): void;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=context-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.d.ts","sourceRoot":"","sources":["../../src/navigation/context-menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACzF,IAAI,CAAC,EAAE;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;CACxD;AACD,MAAM,WAAW,gBAAgB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAA;CAAC;AACpF,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;CAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,GAAG;IAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAAC,CA4B9R"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export function createContextMenu(options = {}) {
|
|
2
|
+
const element = options.element || document.createElement('div');
|
|
3
|
+
if (!options.element) {
|
|
4
|
+
element.className = 'pui-sidebar-conversation-menu pui-context-menu';
|
|
5
|
+
element.setAttribute('role', 'menu');
|
|
6
|
+
element.hidden = true;
|
|
7
|
+
}
|
|
8
|
+
const abort = new AbortController();
|
|
9
|
+
let trigger = null;
|
|
10
|
+
let destroyed = false;
|
|
11
|
+
const close = (restoreFocus = false) => { element.hidden = true; trigger?.setAttribute('aria-expanded', 'false'); if (restoreFocus)
|
|
12
|
+
trigger?.focus(); trigger = null; };
|
|
13
|
+
const update = (state) => {
|
|
14
|
+
if (destroyed)
|
|
15
|
+
return;
|
|
16
|
+
element.setAttribute('aria-label', state.label);
|
|
17
|
+
element.replaceChildren();
|
|
18
|
+
for (const item of state.items) {
|
|
19
|
+
const button = document.createElement('button');
|
|
20
|
+
button.type = 'button';
|
|
21
|
+
button.setAttribute('role', 'menuitem');
|
|
22
|
+
button.textContent = item.label;
|
|
23
|
+
button.disabled = !!item.disabled;
|
|
24
|
+
if (item.danger)
|
|
25
|
+
button.className = 'pui-destructive-menu-item';
|
|
26
|
+
if (item.action)
|
|
27
|
+
button.dataset.action = item.action;
|
|
28
|
+
if (item.sdkAction)
|
|
29
|
+
button.dataset.sdk = item.sdkAction;
|
|
30
|
+
if (item.idle) {
|
|
31
|
+
button.dataset.idleAction = '';
|
|
32
|
+
if (item.idle.conversationId)
|
|
33
|
+
button.dataset.idleConversation = item.idle.conversationId;
|
|
34
|
+
if (item.idle.workspaceId)
|
|
35
|
+
button.dataset.idleWorkspace = item.idle.workspaceId;
|
|
36
|
+
}
|
|
37
|
+
if (options.onAction)
|
|
38
|
+
button.addEventListener('click', () => options.onAction(item), { signal: abort.signal });
|
|
39
|
+
element.append(button);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
element.addEventListener('keydown', (event) => {
|
|
43
|
+
if (event.key === 'Escape') {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
event.stopPropagation();
|
|
46
|
+
options.onDismiss ? options.onDismiss(true) : close(true);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (event.key === 'Tab') {
|
|
50
|
+
options.onDismiss ? options.onDismiss(false) : close(false);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const buttons = [...element.querySelectorAll('button:not(:disabled)')];
|
|
54
|
+
if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
event.stopPropagation();
|
|
57
|
+
const index = buttons.indexOf(document.activeElement);
|
|
58
|
+
const next = event.key === 'Home' ? 0 : event.key === 'End' ? buttons.length - 1 : (index + (event.key === 'ArrowDown' ? 1 : -1) + buttons.length) % buttons.length;
|
|
59
|
+
buttons[next]?.focus();
|
|
60
|
+
}
|
|
61
|
+
}, { signal: abort.signal });
|
|
62
|
+
return { element, update, close, open(source, state) { if (destroyed)
|
|
63
|
+
return; close(); trigger = source; trigger.setAttribute('aria-expanded', 'true'); update(state); element.hidden = false; const rect = source.getBoundingClientRect(); element.style.left = `${Math.max(8, Math.min(rect.right, window.innerWidth - element.offsetWidth - 8))}px`; element.style.top = `${Math.max(8, Math.min(rect.bottom + 4, window.innerHeight - element.offsetHeight - 8))}px`; element.querySelector('button:not(:disabled)')?.focus(); }, destroy() { if (destroyed)
|
|
64
|
+
return; destroyed = true; close(); abort.abort(); if (!options.element)
|
|
65
|
+
element.remove(); } };
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=context-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.js","sourceRoot":"","sources":["../../src/navigation/context-menu.ts"],"names":[],"mappings":"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","sourcesContent":["import type { UIBlock } from '../core.js';\nexport interface ContextMenuItem {\n label: string; action?: string; sdkAction?: string; danger?: boolean; disabled?: boolean;\n idle?: {conversationId?: string; workspaceId?: string};\n}\nexport interface ContextMenuState {label: string; items: readonly ContextMenuItem[]}\nexport function createContextMenu(options: {element?: HTMLElement; onDismiss?: (restoreFocus: boolean) => void; onAction?: (item: ContextMenuItem) => void} = {}): UIBlock<ContextMenuState> & {open(trigger: HTMLElement, state: ContextMenuState): void; close(restoreFocus?: boolean): void} {\n const element = options.element || document.createElement('div');\n if (!options.element) {element.className = 'pui-sidebar-conversation-menu pui-context-menu'; element.setAttribute('role', 'menu'); element.hidden = true;}\n const abort = new AbortController(); let trigger: HTMLElement | null = null; let destroyed = false;\n const close = (restoreFocus = false) => {element.hidden = true; trigger?.setAttribute('aria-expanded', 'false'); if (restoreFocus) trigger?.focus(); trigger = null;};\n const update = (state: Readonly<ContextMenuState>) => {\n if (destroyed) return; element.setAttribute('aria-label', state.label); element.replaceChildren();\n for (const item of state.items) {\n const button = document.createElement('button'); button.type = 'button'; button.setAttribute('role', 'menuitem'); button.textContent = item.label; button.disabled = !!item.disabled;\n if (item.danger) button.className = 'pui-destructive-menu-item';\n if (item.action) button.dataset.action = item.action;\n if (item.sdkAction) button.dataset.sdk = item.sdkAction;\n if (item.idle) {button.dataset.idleAction = ''; if (item.idle.conversationId) button.dataset.idleConversation = item.idle.conversationId; if (item.idle.workspaceId) button.dataset.idleWorkspace = item.idle.workspaceId;}\n if (options.onAction) button.addEventListener('click', () => options.onAction!(item), {signal:abort.signal});\n element.append(button);\n }\n };\n element.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {event.preventDefault(); event.stopPropagation(); options.onDismiss ? options.onDismiss(true) : close(true); return;}\n if (event.key === 'Tab') {options.onDismiss ? options.onDismiss(false) : close(false); return;}\n const buttons = [...element.querySelectorAll<HTMLButtonElement>('button:not(:disabled)')];\n if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {\n event.preventDefault(); event.stopPropagation(); const index = buttons.indexOf(document.activeElement as HTMLButtonElement);\n const next = event.key === 'Home' ? 0 : event.key === 'End' ? buttons.length - 1 : (index + (event.key === 'ArrowDown' ? 1 : -1) + buttons.length) % buttons.length;\n buttons[next]?.focus();\n }\n }, {signal:abort.signal});\n return {element, update, close, open(source, state) {if (destroyed) return; close(); trigger = source; trigger.setAttribute('aria-expanded', 'true'); update(state); element.hidden = false; const rect = source.getBoundingClientRect(); element.style.left = `${Math.max(8, Math.min(rect.right, window.innerWidth - element.offsetWidth - 8))}px`; element.style.top = `${Math.max(8, Math.min(rect.bottom + 4, window.innerHeight - element.offsetHeight - 8))}px`; element.querySelector<HTMLButtonElement>('button:not(:disabled)')?.focus();}, destroy() {if (destroyed) return; destroyed = true; close(); abort.abort(); if (!options.element) element.remove();}};\n}\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { UIBlock } from '../core.js';
|
|
2
|
+
export interface NavigationConversation {
|
|
3
|
+
id: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
active: boolean;
|
|
6
|
+
menuOpen?: boolean;
|
|
7
|
+
status?: Node | null;
|
|
8
|
+
}
|
|
9
|
+
export interface NavigationWorkspace {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
path: string;
|
|
13
|
+
expanded: boolean;
|
|
14
|
+
selected: boolean;
|
|
15
|
+
menuOpen?: boolean;
|
|
16
|
+
children: readonly NavigationConversation[];
|
|
17
|
+
}
|
|
18
|
+
export interface WorkspaceNavigationState {
|
|
19
|
+
groups: readonly NavigationWorkspace[];
|
|
20
|
+
empty: 'workspaces' | 'search' | null;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function createWorkspaceNavigation(initial: WorkspaceNavigationState, options?: {
|
|
24
|
+
element?: HTMLElement;
|
|
25
|
+
idPrefix?: string;
|
|
26
|
+
onToggle?: (id: string) => void;
|
|
27
|
+
onSelect?: (id: string) => void;
|
|
28
|
+
}): UIBlock<WorkspaceNavigationState>;
|
|
29
|
+
export interface RenameConversationState {
|
|
30
|
+
id: string;
|
|
31
|
+
title: string;
|
|
32
|
+
error?: string;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function createRenameConversation(initial: RenameConversationState, options?: {
|
|
36
|
+
idPrefix?: string;
|
|
37
|
+
}): UIBlock<RenameConversationState> & {
|
|
38
|
+
readonly input: HTMLInputElement;
|
|
39
|
+
readonly form: HTMLFormElement;
|
|
40
|
+
};
|
|
41
|
+
export interface WorkspacePickerState {
|
|
42
|
+
workspaces: readonly {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
path: string;
|
|
46
|
+
}[];
|
|
47
|
+
error?: string;
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare function createWorkspacePicker(initial: WorkspacePickerState, options?: {
|
|
51
|
+
idPrefix?: string;
|
|
52
|
+
}): UIBlock<WorkspacePickerState> & {
|
|
53
|
+
readonly input: HTMLInputElement;
|
|
54
|
+
readonly form: HTMLFormElement;
|
|
55
|
+
readonly pickButton: HTMLButtonElement;
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/navigation/navigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,sBAAsB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CAAC;AAC/H,MAAM,WAAW,mBAAmB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,SAAS,sBAAsB,EAAE,CAAA;CAAC;AACpL,MAAM,WAAW,wBAAwB;IAAE,MAAM,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAAC,KAAK,EAAE,YAAY,GAAG,QAAQ,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAC;AAG7I,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,wBAAwB,EAAE,OAAO,GAAE;IAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAoD1O;AACD,MAAM,WAAW,uBAAuB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAC;AACxG,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,EAAE,OAAO,GAAE;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,GAAG;IAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAC,CAKnN;AACD,MAAM,WAAW,oBAAoB;IAAE,UAAU,EAAE,SAAS;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAC;AAC3I,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,EAAE,OAAO,GAAE;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,GAAG;IAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAA;CAAC,CAKlP"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { scopeIds } from '../forms/identity.js';
|
|
2
|
+
import { dialogHeading, escape, icon, uniqueId } from '../dom.js';
|
|
3
|
+
export function createWorkspaceNavigation(initial, options = {}) {
|
|
4
|
+
const element = options.element || document.createElement('nav');
|
|
5
|
+
if (!options.element) {
|
|
6
|
+
element.className = 'pui-history-list pui-workspace-navigation';
|
|
7
|
+
element.setAttribute('aria-label', 'Workspaces and conversations');
|
|
8
|
+
}
|
|
9
|
+
const prefix = options.idPrefix ?? uniqueId('pui-nav') + '-';
|
|
10
|
+
const abort = new AbortController();
|
|
11
|
+
let destroyed = false;
|
|
12
|
+
const workspaces = new Map();
|
|
13
|
+
const conversations = new Map();
|
|
14
|
+
const emptyWorkspace = document.createElement('button');
|
|
15
|
+
emptyWorkspace.type = 'button';
|
|
16
|
+
emptyWorkspace.className = 'pui-workspace-item pui-empty-workspace';
|
|
17
|
+
emptyWorkspace.dataset.action = 'workspace';
|
|
18
|
+
emptyWorkspace.innerHTML = `${icon('folder')}<span>Add a workspace</span>`;
|
|
19
|
+
const emptySearch = document.createElement('p');
|
|
20
|
+
emptySearch.className = 'pui-history-empty';
|
|
21
|
+
emptySearch.textContent = 'No matching conversations.';
|
|
22
|
+
function createWorkspace() {
|
|
23
|
+
const root = document.createElement('section');
|
|
24
|
+
root.className = 'pui-workspace-group';
|
|
25
|
+
root.innerHTML = `<div class="pui-workspace-heading"><button class="pui-workspace-toggle">${icon('chevron', 'pui-workspace-chevron')}${icon('folder')}<span></span></button><button class="pui-quiet-icon pui-workspace-more" aria-haspopup="menu">${icon('more')}</button><button class="pui-quiet-icon pui-workspace-new" title="New conversation">${icon('compose')}</button></div><div class="pui-workspace-children"></div>`;
|
|
26
|
+
const buttons = root.querySelectorAll('button');
|
|
27
|
+
const empty = document.createElement('p');
|
|
28
|
+
empty.className = 'pui-workspace-empty';
|
|
29
|
+
empty.textContent = 'No conversations yet';
|
|
30
|
+
return { element: root, heading: root.firstElementChild, toggle: buttons[0], title: buttons[0].querySelector('span'), more: buttons[1], create: buttons[2], children: root.lastElementChild, empty };
|
|
31
|
+
}
|
|
32
|
+
function createConversation() {
|
|
33
|
+
const root = document.createElement('div');
|
|
34
|
+
root.className = 'pui-history-row';
|
|
35
|
+
root.innerHTML = `<button class="pui-history-item"><span></span></button><button class="pui-quiet-icon pui-history-more" aria-haspopup="menu">${icon('more')}</button>`;
|
|
36
|
+
const buttons = root.querySelectorAll('button');
|
|
37
|
+
return { element: root, button: buttons[0], title: buttons[0].querySelector('span'), more: buttons[1], status: [], statusSignature: '' };
|
|
38
|
+
}
|
|
39
|
+
function statusSignature(node) {
|
|
40
|
+
if (!node)
|
|
41
|
+
return '';
|
|
42
|
+
const holder = document.createElement('div');
|
|
43
|
+
holder.append(node.cloneNode(true));
|
|
44
|
+
return holder.innerHTML;
|
|
45
|
+
}
|
|
46
|
+
const update = (state) => {
|
|
47
|
+
if (destroyed)
|
|
48
|
+
return;
|
|
49
|
+
const currentWorkspaces = new Set();
|
|
50
|
+
const currentConversations = new Set();
|
|
51
|
+
let groupCursor = element.firstElementChild;
|
|
52
|
+
for (const workspace of state.groups) {
|
|
53
|
+
currentWorkspaces.add(workspace.id);
|
|
54
|
+
let group = workspaces.get(workspace.id);
|
|
55
|
+
if (!group) {
|
|
56
|
+
group = createWorkspace();
|
|
57
|
+
workspaces.set(workspace.id, group);
|
|
58
|
+
}
|
|
59
|
+
group.element.setAttribute('aria-label', workspace.name);
|
|
60
|
+
group.heading.classList.toggle('pui-selected', workspace.selected);
|
|
61
|
+
group.toggle.dataset.toggleWorkspace = workspace.id;
|
|
62
|
+
group.toggle.setAttribute('aria-expanded', String(workspace.expanded));
|
|
63
|
+
group.toggle.setAttribute('aria-controls', prefix + 'workspace-children-' + workspace.id);
|
|
64
|
+
group.toggle.title = workspace.path;
|
|
65
|
+
if (group.title.textContent !== workspace.name)
|
|
66
|
+
group.title.textContent = workspace.name;
|
|
67
|
+
group.more.id = prefix + 'workspace-actions-' + workspace.id;
|
|
68
|
+
group.more.dataset.workspaceMenu = workspace.id;
|
|
69
|
+
group.more.setAttribute('aria-label', 'Actions for workspace ' + workspace.name);
|
|
70
|
+
group.more.setAttribute('aria-expanded', String(!!workspace.menuOpen));
|
|
71
|
+
group.more.disabled = !!state.disabled;
|
|
72
|
+
group.create.dataset.newWorkspace = workspace.id;
|
|
73
|
+
group.create.setAttribute('aria-label', 'New conversation in ' + workspace.name);
|
|
74
|
+
group.create.disabled = !!state.disabled;
|
|
75
|
+
group.children.id = prefix + 'workspace-children-' + workspace.id;
|
|
76
|
+
group.children.hidden = !workspace.expanded;
|
|
77
|
+
let rowCursor = group.children.firstElementChild;
|
|
78
|
+
for (const entry of workspace.children) {
|
|
79
|
+
currentConversations.add(entry.id);
|
|
80
|
+
let row = conversations.get(entry.id);
|
|
81
|
+
if (!row) {
|
|
82
|
+
row = createConversation();
|
|
83
|
+
conversations.set(entry.id, row);
|
|
84
|
+
}
|
|
85
|
+
const title = entry.title || 'Untitled conversation';
|
|
86
|
+
row.element.classList.toggle('pui-active', entry.active);
|
|
87
|
+
row.button.dataset.conversation = entry.id;
|
|
88
|
+
row.button.title = title;
|
|
89
|
+
row.button.disabled = !!state.disabled;
|
|
90
|
+
if (entry.active)
|
|
91
|
+
row.button.setAttribute('aria-current', 'page');
|
|
92
|
+
else
|
|
93
|
+
row.button.removeAttribute('aria-current');
|
|
94
|
+
if (row.title.textContent !== title)
|
|
95
|
+
row.title.textContent = title;
|
|
96
|
+
row.more.id = prefix + 'conversation-actions-' + entry.id;
|
|
97
|
+
row.more.dataset.conversationMenu = entry.id;
|
|
98
|
+
row.more.setAttribute('aria-label', 'Actions for ' + title);
|
|
99
|
+
row.more.setAttribute('aria-expanded', String(!!entry.menuOpen));
|
|
100
|
+
row.more.disabled = !!state.disabled;
|
|
101
|
+
const signature = entry.status === row.statusSource && entry.status instanceof DocumentFragment && entry.status.childNodes.length === 0 ? row.statusSignature : statusSignature(entry.status);
|
|
102
|
+
row.statusSource = entry.status;
|
|
103
|
+
if (signature !== row.statusSignature) {
|
|
104
|
+
for (const node of row.status)
|
|
105
|
+
node.parentNode?.removeChild(node);
|
|
106
|
+
row.status = entry.status ? entry.status instanceof DocumentFragment ? [...entry.status.childNodes] : [entry.status] : [];
|
|
107
|
+
row.button.append(...row.status);
|
|
108
|
+
row.statusSignature = signature;
|
|
109
|
+
}
|
|
110
|
+
if (row.element !== rowCursor)
|
|
111
|
+
group.children.insertBefore(row.element, rowCursor);
|
|
112
|
+
rowCursor = row.element.nextElementSibling;
|
|
113
|
+
}
|
|
114
|
+
if (!workspace.children.length) {
|
|
115
|
+
if (group.empty.parentElement !== group.children)
|
|
116
|
+
group.children.append(group.empty);
|
|
117
|
+
}
|
|
118
|
+
else
|
|
119
|
+
group.empty.remove();
|
|
120
|
+
if (group.element !== groupCursor)
|
|
121
|
+
element.insertBefore(group.element, groupCursor);
|
|
122
|
+
groupCursor = group.element.nextElementSibling;
|
|
123
|
+
}
|
|
124
|
+
for (const [id, row] of conversations)
|
|
125
|
+
if (!currentConversations.has(id)) {
|
|
126
|
+
row.element.remove();
|
|
127
|
+
conversations.delete(id);
|
|
128
|
+
}
|
|
129
|
+
for (const [id, group] of workspaces)
|
|
130
|
+
if (!currentWorkspaces.has(id)) {
|
|
131
|
+
group.element.remove();
|
|
132
|
+
workspaces.delete(id);
|
|
133
|
+
}
|
|
134
|
+
if (state.empty === 'workspaces') {
|
|
135
|
+
if (emptyWorkspace.parentElement !== element)
|
|
136
|
+
element.append(emptyWorkspace);
|
|
137
|
+
}
|
|
138
|
+
else
|
|
139
|
+
emptyWorkspace.remove();
|
|
140
|
+
if (state.empty === 'search') {
|
|
141
|
+
if (emptySearch.parentElement !== element)
|
|
142
|
+
element.append(emptySearch);
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
emptySearch.remove();
|
|
146
|
+
};
|
|
147
|
+
element.addEventListener('click', event => { const target = event.target.closest('button'); if (target?.disabled)
|
|
148
|
+
return; if (target?.dataset.toggleWorkspace)
|
|
149
|
+
options.onToggle?.(target.dataset.toggleWorkspace); if (target?.dataset.conversation)
|
|
150
|
+
options.onSelect?.(target.dataset.conversation); }, { signal: abort.signal });
|
|
151
|
+
update(initial);
|
|
152
|
+
return { element, update, destroy() { if (destroyed)
|
|
153
|
+
return; destroyed = true; abort.abort(); workspaces.clear(); conversations.clear(); if (!options.element)
|
|
154
|
+
element.remove(); } };
|
|
155
|
+
}
|
|
156
|
+
export function createRenameConversation(initial, options = {}) {
|
|
157
|
+
const state = initial;
|
|
158
|
+
const element = document.createElement('div');
|
|
159
|
+
element.className = 'pui-rename-conversation';
|
|
160
|
+
element.innerHTML = `${dialogHeading('Rename conversation', 'rename-title', 'rename-dialog', 'CONVERSATION')}<form id="rename-form"><label class="pui-field-label" for="conversation-title">Title</label><input id="conversation-title" name="title" value="${escape(state.title)}" required autocomplete="off" /><div id="rename-error" class="pui-form-error" role="alert"></div><div class="pui-modal-footer"><button type="button" class="pui-secondary-button" data-close="rename-dialog">Cancel</button><button type="submit" class="pui-primary-button" data-idle-action data-idle-conversation="${escape(state.id)}">Save title</button></div></form>`;
|
|
161
|
+
const input = element.querySelector('#conversation-title');
|
|
162
|
+
const form = element.querySelector('#rename-form');
|
|
163
|
+
const error = element.querySelector('#rename-error');
|
|
164
|
+
const update = (state) => { if (state.error !== undefined)
|
|
165
|
+
error.textContent = state.error; const button = form.querySelector('button[type="submit"]'); button.disabled = !!state.disabled; };
|
|
166
|
+
update(initial);
|
|
167
|
+
scopeIds(element, options.idPrefix ?? uniqueId('pui-rename') + '-');
|
|
168
|
+
return { element, input, form, update, destroy() { element.remove(); } };
|
|
169
|
+
}
|
|
170
|
+
export function createWorkspacePicker(initial, options = {}) {
|
|
171
|
+
const state = initial;
|
|
172
|
+
const element = document.createElement('div');
|
|
173
|
+
element.className = 'pui-workspace-picker';
|
|
174
|
+
element.innerHTML = `${dialogHeading('Workspaces', 'workspace-title', 'workspace-dialog', 'A PLACE TO WORK')}<p class="pui-modal-description">Choose a local folder. Conversations belong to a workspace, so Pith knows where to read and create files.</p><div class="pui-modal-workspaces">${state.workspaces.map((entry) => `<button class="pui-modal-workspace" data-modal-workspace="${escape(entry.id)}">${icon('folder')}<span><strong>${escape(entry.name)}</strong><small>${escape(entry.path)}</small></span>${icon('chevron')}</button>`).join('')}</div><div class="pui-workspace-add"><button class="pui-picker-button" id="pick-folder" type="button">${icon('folder')}Choose a folder…</button><div class="pui-path-divider"><span>or enter a folder path</span></div><form id="workspace-form"><label class="pui-sr-only" for="workspace-path">Absolute folder path</label><input id="workspace-path" name="path" placeholder="/Users/you/Documents/my-work" required autocomplete="off" spellcheck="false" /><p class="pui-field-hint">Use an existing folder on this computer. Pith will work inside it.</p><div id="workspace-error" class="pui-form-error" role="alert"></div><div class="pui-modal-footer"><button class="pui-secondary-button" type="button" data-close="workspace-dialog">Cancel</button><button class="pui-primary-button" id="add-workspace" type="submit">Add workspace</button></div></form></div>`;
|
|
175
|
+
const input = element.querySelector('#workspace-path');
|
|
176
|
+
const form = element.querySelector('#workspace-form');
|
|
177
|
+
const pickButton = element.querySelector('#pick-folder');
|
|
178
|
+
const error = element.querySelector('#workspace-error');
|
|
179
|
+
const update = (state) => { if (state.error !== undefined)
|
|
180
|
+
error.textContent = state.error; const button = form.querySelector('button[type="submit"]'); button.disabled = !!state.disabled; };
|
|
181
|
+
update(initial);
|
|
182
|
+
scopeIds(element, options.idPrefix ?? uniqueId('pui-workspace') + '-');
|
|
183
|
+
return { element, input, form, pickButton, update, destroy() { element.remove(); } };
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/navigation/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import {scopeIds} from '../forms/identity.js';\nimport type { UIBlock } from '../core.js';\nimport {dialogHeading, escape, icon, uniqueId} from '../dom.js';\nexport interface NavigationConversation {id: string; title?: string; active: boolean; menuOpen?: boolean; status?: Node | null}\nexport interface NavigationWorkspace {id: string; name: string; path: string; expanded: boolean; selected: boolean; menuOpen?: boolean; children: readonly NavigationConversation[]}\nexport interface WorkspaceNavigationState {groups: readonly NavigationWorkspace[]; empty: 'workspaces' | 'search' | null; disabled?: boolean}\ntype ConversationDOM = {element: HTMLElement; button: HTMLButtonElement; title: HTMLElement; more: HTMLButtonElement; status: Node[]; statusSignature: string; statusSource?: Node | null};\ntype WorkspaceDOM = {element: HTMLElement; heading: HTMLElement; toggle: HTMLButtonElement; title: HTMLElement; more: HTMLButtonElement; create: HTMLButtonElement; children: HTMLElement; empty: HTMLElement};\nexport function createWorkspaceNavigation(initial: WorkspaceNavigationState, options: {element?: HTMLElement; idPrefix?: string; onToggle?: (id: string) => void; onSelect?: (id: string) => void} = {}): UIBlock<WorkspaceNavigationState> {\n const element = options.element || document.createElement('nav');\n if (!options.element) {element.className = 'pui-history-list pui-workspace-navigation'; element.setAttribute('aria-label', 'Workspaces and conversations');}\n const prefix = options.idPrefix ?? uniqueId('pui-nav') + '-';\n const abort = new AbortController(); let destroyed = false;\n const workspaces = new Map<string, WorkspaceDOM>(); const conversations = new Map<string, ConversationDOM>();\n const emptyWorkspace = document.createElement('button'); emptyWorkspace.type = 'button'; emptyWorkspace.className = 'pui-workspace-item pui-empty-workspace'; emptyWorkspace.dataset.action = 'workspace'; emptyWorkspace.innerHTML = `${icon('folder')}<span>Add a workspace</span>`;\n const emptySearch = document.createElement('p'); emptySearch.className = 'pui-history-empty'; emptySearch.textContent = 'No matching conversations.';\n function createWorkspace(): WorkspaceDOM {\n const root = document.createElement('section'); root.className = 'pui-workspace-group';\n root.innerHTML = `<div class=\"pui-workspace-heading\"><button class=\"pui-workspace-toggle\">${icon('chevron', 'pui-workspace-chevron')}${icon('folder')}<span></span></button><button class=\"pui-quiet-icon pui-workspace-more\" aria-haspopup=\"menu\">${icon('more')}</button><button class=\"pui-quiet-icon pui-workspace-new\" title=\"New conversation\">${icon('compose')}</button></div><div class=\"pui-workspace-children\"></div>`;\n const buttons = root.querySelectorAll<HTMLButtonElement>('button'); const empty = document.createElement('p'); empty.className = 'pui-workspace-empty'; empty.textContent = 'No conversations yet';\n return {element:root,heading:root.firstElementChild as HTMLElement,toggle:buttons[0],title:buttons[0].querySelector('span')!,more:buttons[1],create:buttons[2],children:root.lastElementChild as HTMLElement,empty};\n }\n function createConversation(): ConversationDOM {\n const root = document.createElement('div'); root.className = 'pui-history-row';\n root.innerHTML = `<button class=\"pui-history-item\"><span></span></button><button class=\"pui-quiet-icon pui-history-more\" aria-haspopup=\"menu\">${icon('more')}</button>`;\n const buttons = root.querySelectorAll<HTMLButtonElement>('button'); return {element:root,button:buttons[0],title:buttons[0].querySelector('span')!,more:buttons[1],status:[],statusSignature:''};\n }\n function statusSignature(node?: Node | null): string {\n if (!node) return ''; const holder = document.createElement('div'); holder.append(node.cloneNode(true)); return holder.innerHTML;\n }\n const update = (state: Readonly<WorkspaceNavigationState>) => {\n if (destroyed) return; const currentWorkspaces = new Set<string>(); const currentConversations = new Set<string>(); let groupCursor: Element | null = element.firstElementChild;\n for (const workspace of state.groups) {\n currentWorkspaces.add(workspace.id); let group = workspaces.get(workspace.id); if (!group) {group = createWorkspace(); workspaces.set(workspace.id,group);}\n group.element.setAttribute('aria-label',workspace.name); group.heading.classList.toggle('pui-selected',workspace.selected);\n group.toggle.dataset.toggleWorkspace = workspace.id; group.toggle.setAttribute('aria-expanded',String(workspace.expanded)); group.toggle.setAttribute('aria-controls',prefix+'workspace-children-'+workspace.id); group.toggle.title = workspace.path;\n if (group.title.textContent !== workspace.name) group.title.textContent = workspace.name;\n group.more.id = prefix+'workspace-actions-'+workspace.id; group.more.dataset.workspaceMenu = workspace.id; group.more.setAttribute('aria-label','Actions for workspace '+workspace.name); group.more.setAttribute('aria-expanded',String(!!workspace.menuOpen)); group.more.disabled = !!state.disabled;\n group.create.dataset.newWorkspace = workspace.id; group.create.setAttribute('aria-label','New conversation in '+workspace.name); group.create.disabled = !!state.disabled;\n group.children.id = prefix+'workspace-children-'+workspace.id; group.children.hidden = !workspace.expanded; let rowCursor: Element | null = group.children.firstElementChild;\n for (const entry of workspace.children) {\n currentConversations.add(entry.id); let row = conversations.get(entry.id); if (!row) {row = createConversation(); conversations.set(entry.id,row);}\n const title = entry.title || 'Untitled conversation'; row.element.classList.toggle('pui-active',entry.active); row.button.dataset.conversation = entry.id; row.button.title = title; row.button.disabled = !!state.disabled;\n if (entry.active) row.button.setAttribute('aria-current','page'); else row.button.removeAttribute('aria-current'); if (row.title.textContent !== title) row.title.textContent = title;\n row.more.id = prefix+'conversation-actions-'+entry.id; row.more.dataset.conversationMenu = entry.id; row.more.setAttribute('aria-label','Actions for '+title); row.more.setAttribute('aria-expanded',String(!!entry.menuOpen)); row.more.disabled = !!state.disabled;\n const signature = entry.status === row.statusSource && entry.status instanceof DocumentFragment && entry.status.childNodes.length === 0 ? row.statusSignature : statusSignature(entry.status);\n row.statusSource = entry.status;\n if (signature !== row.statusSignature) {for (const node of row.status) node.parentNode?.removeChild(node); row.status = entry.status ? entry.status instanceof DocumentFragment ? [...entry.status.childNodes] : [entry.status] : []; row.button.append(...row.status); row.statusSignature = signature;}\n if (row.element !== rowCursor) group.children.insertBefore(row.element,rowCursor); rowCursor = row.element.nextElementSibling;\n }\n if (!workspace.children.length) {if (group.empty.parentElement !== group.children) group.children.append(group.empty);} else group.empty.remove();\n if (group.element !== groupCursor) element.insertBefore(group.element,groupCursor); groupCursor = group.element.nextElementSibling;\n }\n for (const [id,row] of conversations) if (!currentConversations.has(id)) {row.element.remove(); conversations.delete(id);}\n for (const [id,group] of workspaces) if (!currentWorkspaces.has(id)) {group.element.remove(); workspaces.delete(id);}\n if (state.empty === 'workspaces') {if (emptyWorkspace.parentElement !== element) element.append(emptyWorkspace);} else emptyWorkspace.remove();\n if (state.empty === 'search') {if (emptySearch.parentElement !== element) element.append(emptySearch);} else emptySearch.remove();\n };\n element.addEventListener('click',event => {const target = (event.target as HTMLElement).closest<HTMLButtonElement>('button'); if (target?.disabled) return; if (target?.dataset.toggleWorkspace) options.onToggle?.(target.dataset.toggleWorkspace); if (target?.dataset.conversation) options.onSelect?.(target.dataset.conversation);},{signal:abort.signal});\n update(initial); return {element,update,destroy() {if (destroyed) return; destroyed = true; abort.abort(); workspaces.clear(); conversations.clear(); if (!options.element) element.remove();}};\n}\nexport interface RenameConversationState {id: string; title: string; error?: string; disabled?: boolean}\nexport function createRenameConversation(initial: RenameConversationState, options: {idPrefix?: string} = {}): UIBlock<RenameConversationState> & {readonly input: HTMLInputElement; readonly form: HTMLFormElement} {\n const state = initial; const element = document.createElement('div'); element.className = 'pui-rename-conversation'; element.innerHTML = `${dialogHeading('Rename conversation', 'rename-title', 'rename-dialog', 'CONVERSATION')}<form id=\"rename-form\"><label class=\"pui-field-label\" for=\"conversation-title\">Title</label><input id=\"conversation-title\" name=\"title\" value=\"${escape(state.title)}\" required autocomplete=\"off\" /><div id=\"rename-error\" class=\"pui-form-error\" role=\"alert\"></div><div class=\"pui-modal-footer\"><button type=\"button\" class=\"pui-secondary-button\" data-close=\"rename-dialog\">Cancel</button><button type=\"submit\" class=\"pui-primary-button\" data-idle-action data-idle-conversation=\"${escape(state.id)}\">Save title</button></div></form>`;\n const input = element.querySelector<HTMLInputElement>('#conversation-title')!; const form = element.querySelector<HTMLFormElement>('#rename-form')!; const error = element.querySelector<HTMLElement>('#rename-error')!;\n const update = (state: Readonly<RenameConversationState>) => {if (state.error !== undefined) error.textContent = state.error; const button = form.querySelector<HTMLButtonElement>('button[type=\"submit\"]')!; button.disabled = !!state.disabled;}; update(initial); scopeIds(element, options.idPrefix ?? uniqueId('pui-rename') + '-');\n return {element, input, form, update, destroy() {element.remove();}};\n}\nexport interface WorkspacePickerState {workspaces: readonly {id: string; name: string; path: string}[]; error?: string; disabled?: boolean}\nexport function createWorkspacePicker(initial: WorkspacePickerState, options: {idPrefix?: string} = {}): UIBlock<WorkspacePickerState> & {readonly input: HTMLInputElement; readonly form: HTMLFormElement; readonly pickButton: HTMLButtonElement} {\n const state = initial; const element = document.createElement('div'); element.className = 'pui-workspace-picker'; element.innerHTML = `${dialogHeading('Workspaces', 'workspace-title', 'workspace-dialog', 'A PLACE TO WORK')}<p class=\"pui-modal-description\">Choose a local folder. Conversations belong to a workspace, so Pith knows where to read and create files.</p><div class=\"pui-modal-workspaces\">${state.workspaces.map((entry) => `<button class=\"pui-modal-workspace\" data-modal-workspace=\"${escape(entry.id)}\">${icon('folder')}<span><strong>${escape(entry.name)}</strong><small>${escape(entry.path)}</small></span>${icon('chevron')}</button>`).join('')}</div><div class=\"pui-workspace-add\"><button class=\"pui-picker-button\" id=\"pick-folder\" type=\"button\">${icon('folder')}Choose a folder…</button><div class=\"pui-path-divider\"><span>or enter a folder path</span></div><form id=\"workspace-form\"><label class=\"pui-sr-only\" for=\"workspace-path\">Absolute folder path</label><input id=\"workspace-path\" name=\"path\" placeholder=\"/Users/you/Documents/my-work\" required autocomplete=\"off\" spellcheck=\"false\" /><p class=\"pui-field-hint\">Use an existing folder on this computer. Pith will work inside it.</p><div id=\"workspace-error\" class=\"pui-form-error\" role=\"alert\"></div><div class=\"pui-modal-footer\"><button class=\"pui-secondary-button\" type=\"button\" data-close=\"workspace-dialog\">Cancel</button><button class=\"pui-primary-button\" id=\"add-workspace\" type=\"submit\">Add workspace</button></div></form></div>`;\n const input = element.querySelector<HTMLInputElement>('#workspace-path')!; const form = element.querySelector<HTMLFormElement>('#workspace-form')!; const pickButton = element.querySelector<HTMLButtonElement>('#pick-folder')!; const error = element.querySelector<HTMLElement>('#workspace-error')!;\n const update = (state: Readonly<WorkspacePickerState>) => {if (state.error !== undefined) error.textContent = state.error; const button = form.querySelector<HTMLButtonElement>('button[type=\"submit\"]')!; button.disabled = !!state.disabled;}; update(initial); scopeIds(element, options.idPrefix ?? uniqueId('pui-workspace') + '-');\n return {element, input, form, pickButton, update, destroy() {element.remove();}};\n}\n"]}
|