@ibgib/space-gib 0.0.32 → 0.0.34
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/client/bootstrap.mjs +24 -51
- package/dist/client/chunk-25PXC4HP.mjs +9914 -0
- package/dist/client/chunk-RXWLL2AI.mjs +30 -0
- package/dist/client/css/activity-bar.css +417 -0
- package/dist/client/css/base.css +167 -0
- package/dist/client/css/components.css +218 -0
- package/dist/client/css/cosmic.css +557 -0
- package/dist/client/css/dev-tools.css +163 -0
- package/dist/client/css/landing.css +184 -0
- package/dist/client/css/layout.css +896 -0
- package/dist/client/css/onboarding.css +181 -0
- package/dist/client/css/repos.css +740 -0
- package/dist/client/css/variables.css +64 -0
- package/dist/client/index.html +202 -31
- package/dist/client/index.mjs +31 -31
- package/dist/client/script.mjs +1 -1
- package/dist/client/style.css +11 -1056
- package/dist/respec-gib.node.mjs +5 -0
- package/dist/server/server.mjs +6879 -3109
- package/package.json +6 -6
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/cosmos/seed-cosmos-workspace.mts +69 -0
- package/src/client/css/activity-bar.css +417 -0
- package/src/client/css/base.css +167 -0
- package/src/client/css/components.css +218 -0
- package/src/client/css/cosmic.css +557 -0
- package/src/client/css/dev-tools.css +163 -0
- package/src/client/css/landing.css +184 -0
- package/src/client/css/layout.css +896 -0
- package/src/client/css/onboarding.css +181 -0
- package/src/client/css/repos.css +740 -0
- package/src/client/css/variables.css +64 -0
- package/src/client/dev-tools/vcs-workspace.mts +3 -3
- package/src/client/index.html +202 -31
- package/src/client/style.css +11 -1056
- package/src/client/ui/component/chat-view/IMPLEMENTATION.md +48 -0
- package/src/client/ui/component/chat-view/chat-view.css +381 -0
- package/src/client/ui/component/chat-view/chat-view.html +104 -0
- package/src/client/ui/component/chat-view/chat-view.mts +277 -0
- package/src/client/ui/component/chat-view/index.mts +9 -0
- package/src/client/ui/component/clone/IMPLEMENTATION.md +68 -0
- package/src/client/ui/component/clone/clone-constants.mts +16 -0
- package/src/client/ui/component/clone/clone-types.mts +60 -0
- package/src/client/ui/component/clone/clone.css +383 -0
- package/src/client/ui/component/clone/clone.html +89 -0
- package/src/client/ui/component/clone/clone.mts +620 -0
- package/src/client/ui/component/clone/index.mts +11 -0
- package/src/client/ui/component/code-editor/IMPLEMENTATION.md +89 -0
- package/src/client/ui/component/code-editor/code-editor.css +275 -0
- package/src/client/ui/component/code-editor/code-editor.html +54 -0
- package/src/client/ui/component/code-editor/code-editor.mts +427 -0
- package/src/client/ui/component/code-editor/index.mts +9 -0
- package/src/client/ui/component/cosmos-navigator/IMPLEMENTATION.md +31 -0
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +864 -0
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +97 -0
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +1084 -0
- package/src/client/ui/component/cosmos-navigator/index.mts +18 -0
- package/src/client/ui/component/file-explorer/IMPLEMENTATION.md +42 -0
- package/src/client/ui/component/file-explorer/file-explorer.css +256 -0
- package/src/client/ui/component/file-explorer/file-explorer.html +75 -0
- package/src/client/ui/component/file-explorer/file-explorer.mts +346 -0
- package/src/client/ui/component/file-explorer/index.mts +9 -0
- package/src/client/ui/component/nested-chat/IMPLEMENTATION.md +18 -0
- package/src/client/ui/component/nested-chat/chat/IMPLEMENTATION.md +14 -0
- package/src/client/ui/component/nested-chat/chat/chat-constants.mts +14 -0
- package/src/client/ui/component/nested-chat/chat/chat-helpers.mts +66 -0
- package/src/client/ui/component/nested-chat/chat/chat.css +654 -0
- package/src/client/ui/component/nested-chat/chat/chat.html +90 -0
- package/src/client/ui/component/nested-chat/chat/chat.mts +646 -0
- package/src/client/ui/component/nested-chat/chat/index.mts +7 -0
- package/src/client/ui/component/nested-chat/index.mts +14 -0
- package/src/client/ui/component/nested-chat/nested-chat-constants.mts +12 -0
- package/src/client/ui/component/nested-chat/nested-chat-types.mts +53 -0
- package/src/client/ui/component/nested-chat/nested-chat.css +142 -0
- package/src/client/ui/component/nested-chat/nested-chat.html +11 -0
- package/src/client/ui/component/nested-chat/nested-chat.mts +393 -0
- package/src/client/ui/component/notes-explorer/index.mts +9 -0
- package/src/client/ui/component/notes-explorer/notes-explorer.css +313 -0
- package/src/client/ui/component/notes-explorer/notes-explorer.html +136 -0
- package/src/client/ui/component/notes-explorer/notes-explorer.mts +240 -0
- package/src/client/ui/component/notes-inspector/index.mts +9 -0
- package/src/client/ui/component/notes-inspector/notes-inspector.css +244 -0
- package/src/client/ui/component/notes-inspector/notes-inspector.html +97 -0
- package/src/client/ui/component/notes-inspector/notes-inspector.mts +152 -0
- package/src/client/ui/component/pitch/IMPLEMENTATION.md +48 -0
- package/src/client/ui/component/pitch/index.mts +9 -0
- package/src/client/ui/component/pitch/pitch.css +295 -0
- package/src/client/ui/component/pitch/pitch.html +97 -0
- package/src/client/ui/component/pitch/pitch.mts +135 -0
- package/src/client/ui/component/timeline/IMPLEMENTATION.md +33 -0
- package/src/client/ui/component/timeline/index.mts +9 -0
- package/src/client/ui/component/timeline/timeline.css +264 -0
- package/src/client/ui/component/timeline/timeline.html +23 -0
- package/src/client/ui/component/timeline/timeline.mts +317 -0
- package/src/client/ui/component/timeline-item-details/IMPLEMENTATION.md +28 -0
- package/src/client/ui/component/timeline-item-details/index.mts +9 -0
- package/src/client/ui/component/timeline-item-details/timeline-item-details.css +286 -0
- package/src/client/ui/component/timeline-item-details/timeline-item-details.html +64 -0
- package/src/client/ui/component/timeline-item-details/timeline-item-details.mts +194 -0
- package/src/client/ui/router/index.mts +3 -0
- package/src/client/ui/router/space-gib-router-helpers.mts +272 -0
- package/src/client/ui/router/space-gib-router-helpers.respec.mts +353 -0
- package/src/client/ui/router/space-gib-router-service.mts +186 -0
- package/src/client/ui/router/space-gib-router-types.mts +93 -0
- package/src/client/ui/shell/cosmic-big-bang.mts +844 -0
- package/src/client/ui/shell/space-gib-shell-constants.mts +7 -0
- package/src/client/ui/shell/space-gib-shell-service.mts +1728 -31
- package/src/server/server.mts +20 -1
- package/tsconfig.test.json +5 -1
- package/dist/client/chunk-AX6BROMT.mjs +0 -1
- package/dist/client/chunk-CIQUGV7U.mjs +0 -25
- package/dist/client/chunk-YPCHYDKL.mjs +0 -3102
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ChildInfoBase } from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
|
|
2
|
+
import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
|
|
3
|
+
import { SettingsBase, SettingsWithTabs } from "@ibgib/web-gib/dist/common/settings/settings-types.mjs";
|
|
4
|
+
import { SETTINGS_TYPE_NESTED_CHAT } from "./nested-chat-constants.mjs";
|
|
5
|
+
import type { ChatComponentInstance } from "./chat/chat.mjs";
|
|
6
|
+
|
|
7
|
+
export interface Settings_NestedChat extends SettingsBase, SettingsWithTabs {
|
|
8
|
+
type: typeof SETTINGS_TYPE_NESTED_CHAT;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_SETTINGS_NESTED_CHAT: Settings_NestedChat = {
|
|
12
|
+
type: SETTINGS_TYPE_NESTED_CHAT,
|
|
13
|
+
openChildTjpAddrs: [],
|
|
14
|
+
activeChildTjpAddr: undefined,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Information tracked per breadcrumb tab by the parent space-gib-nested-chat.
|
|
19
|
+
*/
|
|
20
|
+
export interface NestedChatTabInfo extends ChildInfoBase<ChatComponentInstance> {
|
|
21
|
+
shortTitle: string;
|
|
22
|
+
fullText: string;
|
|
23
|
+
depth: number;
|
|
24
|
+
addr: IbGibAddr;
|
|
25
|
+
tjpAddr?: IbGibAddr;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Visual model for a comment/message displayed in space-gib-chat.
|
|
30
|
+
*/
|
|
31
|
+
export interface ChatCommentItem {
|
|
32
|
+
id: string;
|
|
33
|
+
addr: IbGibAddr;
|
|
34
|
+
title?: string;
|
|
35
|
+
author: string;
|
|
36
|
+
avatar?: string;
|
|
37
|
+
role?: 'Keystone' | 'Peer' | 'Agent';
|
|
38
|
+
timestamp: string;
|
|
39
|
+
text: string;
|
|
40
|
+
anchor?: string;
|
|
41
|
+
replyCount?: number;
|
|
42
|
+
isEncrypted?: boolean;
|
|
43
|
+
cipherAlgo?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Detail payload when drilling down into a comment as a child chatroom context.
|
|
48
|
+
*/
|
|
49
|
+
export interface ChatDrillDownEventDetail {
|
|
50
|
+
addr: IbGibAddr;
|
|
51
|
+
text: string;
|
|
52
|
+
author?: string;
|
|
53
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
background: var(--clr-bg-surface, #0d1322);
|
|
7
|
+
color: var(--clr-text-primary, #f0f4fc);
|
|
8
|
+
font-family: var(--font-sans, system-ui, -apple-system, sans-serif);
|
|
9
|
+
font-size: 0.85rem;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.nested-chat-root {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* ── Top Header & Breadcrumb Bar ── */
|
|
22
|
+
.nested-chat-header {
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: space-between;
|
|
26
|
+
gap: 0.5rem;
|
|
27
|
+
padding: 0.4rem 0.75rem;
|
|
28
|
+
background: rgba(5, 8, 15, 0.7);
|
|
29
|
+
border-bottom: 1px solid var(--clr-border, rgba(255, 255, 255, 0.08));
|
|
30
|
+
flex-shrink: 0;
|
|
31
|
+
min-height: 38px;
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.nested-chat-breadcrumbs-container {
|
|
36
|
+
flex: 1;
|
|
37
|
+
overflow-x: auto;
|
|
38
|
+
overflow-y: hidden;
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
scrollbar-width: thin;
|
|
41
|
+
scrollbar-color: rgba(255, 255, 255, 0.15) transparent;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.nested-chat-breadcrumbs-container::-webkit-scrollbar {
|
|
45
|
+
height: 3px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.nested-chat-breadcrumbs-container::-webkit-scrollbar-thumb {
|
|
49
|
+
background: rgba(255, 255, 255, 0.15);
|
|
50
|
+
border-radius: 3px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.nested-chat-breadcrumbs-rail {
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: 0.2rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ── Individual Breadcrumb Item / Tab ── */
|
|
60
|
+
.breadcrumb-btn {
|
|
61
|
+
display: inline-flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
gap: 0.35rem;
|
|
64
|
+
background: transparent;
|
|
65
|
+
border: 1px solid transparent;
|
|
66
|
+
color: var(--clr-text-muted, #7e8c9f);
|
|
67
|
+
padding: 0.2rem 0.5rem;
|
|
68
|
+
border-radius: 4px;
|
|
69
|
+
font-size: 0.75rem;
|
|
70
|
+
font-family: inherit;
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
transition: all 120ms ease;
|
|
73
|
+
max-width: 160px;
|
|
74
|
+
white-space: nowrap;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.breadcrumb-btn:hover {
|
|
78
|
+
background: rgba(255, 255, 255, 0.06);
|
|
79
|
+
color: var(--clr-text-primary, #f0f4fc);
|
|
80
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.breadcrumb-btn.active {
|
|
84
|
+
background: rgba(120, 248, 126, 0.12);
|
|
85
|
+
border-color: rgba(120, 248, 126, 0.3);
|
|
86
|
+
color: var(--clr-accent, #78f87e);
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.bc-icon {
|
|
91
|
+
font-size: 0.8rem;
|
|
92
|
+
line-height: 1;
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.bc-title {
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
text-overflow: ellipsis;
|
|
99
|
+
white-space: nowrap;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.breadcrumb-separator {
|
|
103
|
+
color: rgba(255, 255, 255, 0.25);
|
|
104
|
+
font-size: 0.75rem;
|
|
105
|
+
user-select: none;
|
|
106
|
+
margin: 0 0.15rem;
|
|
107
|
+
flex-shrink: 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ── Close Action ── */
|
|
111
|
+
.nested-chat-header-actions {
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
flex-shrink: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.btn-nested-chat-close {
|
|
118
|
+
background: transparent;
|
|
119
|
+
border: none;
|
|
120
|
+
color: var(--clr-text-muted, #7e8c9f);
|
|
121
|
+
font-size: 0.85rem;
|
|
122
|
+
cursor: pointer;
|
|
123
|
+
padding: 0.2rem 0.4rem;
|
|
124
|
+
border-radius: 4px;
|
|
125
|
+
transition: all 120ms ease;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.btn-nested-chat-close:hover {
|
|
129
|
+
background: rgba(255, 255, 255, 0.08);
|
|
130
|
+
color: var(--clr-text-primary, #f0f4fc);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* ── Active Child Viewport Content ── */
|
|
134
|
+
.nested-chat-content {
|
|
135
|
+
flex: 1;
|
|
136
|
+
width: 100%;
|
|
137
|
+
height: 100%;
|
|
138
|
+
overflow: hidden;
|
|
139
|
+
position: relative;
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-direction: column;
|
|
142
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div id="nested-chat-root" class="nested-chat-root">
|
|
2
|
+
<div id="nested-chat-header" class="nested-chat-header">
|
|
3
|
+
<div id="nested-chat-breadcrumbs-container" class="nested-chat-breadcrumbs-container">
|
|
4
|
+
<div id="nested-chat-breadcrumbs-rail" class="nested-chat-breadcrumbs-rail"></div>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="nested-chat-header-actions">
|
|
7
|
+
<button id="btn-nested-chat-close" class="btn-nested-chat-close" title="Close Chat Panel">✕</button>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
<div id="nested-chat-content" class="nested-chat-content"></div>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import thisCss from "./nested-chat.css";
|
|
2
|
+
import thisHtml from "./nested-chat.html";
|
|
3
|
+
|
|
4
|
+
import { ROOT_ADDR } from "@ibgib/ts-gib/dist/V1/constants.mjs";
|
|
5
|
+
import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
|
|
6
|
+
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
|
|
7
|
+
import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
|
|
8
|
+
import { getIbAndGib, getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
9
|
+
import { getGibInfo } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
|
|
10
|
+
import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
11
|
+
import {
|
|
12
|
+
IbGibDynamicComponentMetaBase, IbGibDynamicComponentInstanceBase_ParentOfTabs,
|
|
13
|
+
} from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
|
|
14
|
+
import {
|
|
15
|
+
ElementsBase, IbGibDynamicComponentInstance,
|
|
16
|
+
} from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
|
|
17
|
+
import { getComponentCtorArg } from "@ibgib/web-gib/dist/app-bootstrap/init-orchestration.mjs";
|
|
18
|
+
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";
|
|
19
|
+
import { SettingsType } from "@ibgib/web-gib/dist/common/settings/settings-constants.mjs";
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
NESTED_CHAT_COMPONENT_NAME, CHAT_COMPONENT_NAME,
|
|
23
|
+
EVENT_SPACE_GIB_CHAT_DRILL_DOWN, EVENT_SPACE_GIB_CHAT_CLOSED,
|
|
24
|
+
SETTINGS_TYPE_NESTED_CHAT, MAX_BREADCRUMB_TEXT_LENGTH,
|
|
25
|
+
} from "./nested-chat-constants.mjs";
|
|
26
|
+
import {
|
|
27
|
+
Settings_NestedChat, NestedChatTabInfo, ChatDrillDownEventDetail,
|
|
28
|
+
} from "./nested-chat-types.mjs";
|
|
29
|
+
import { ChatComponentInstance, ChatComponentMeta } from "./chat/chat.mjs";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Metadata factory for space-gib-nested-chat Web Component.
|
|
33
|
+
*/
|
|
34
|
+
export class NestedChatComponentMeta extends IbGibDynamicComponentMetaBase {
|
|
35
|
+
protected lc: string = `[${NestedChatComponentMeta.name}]`;
|
|
36
|
+
|
|
37
|
+
routeRegExp?: RegExp = new RegExp(`^${NESTED_CHAT_COMPONENT_NAME}$`);
|
|
38
|
+
componentName = NESTED_CHAT_COMPONENT_NAME;
|
|
39
|
+
|
|
40
|
+
constructor() {
|
|
41
|
+
super(getComponentCtorArg());
|
|
42
|
+
if (!customElements.get(this.componentName)) {
|
|
43
|
+
customElements.define(this.componentName, NestedChatComponentInstance);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async createInstance({
|
|
48
|
+
path,
|
|
49
|
+
ibGibAddr
|
|
50
|
+
}: {
|
|
51
|
+
path: string;
|
|
52
|
+
ibGibAddr: IbGibAddr;
|
|
53
|
+
}): Promise<IbGibDynamicComponentInstance> {
|
|
54
|
+
const component = document.createElement(this.componentName) as NestedChatComponentInstance;
|
|
55
|
+
await component.initialize({
|
|
56
|
+
ibGibAddr: ibGibAddr || ROOT_ADDR,
|
|
57
|
+
meta: this,
|
|
58
|
+
html: thisHtml,
|
|
59
|
+
css: [thisCss],
|
|
60
|
+
});
|
|
61
|
+
return component;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* References to DOM elements within the component's Shadow Root.
|
|
67
|
+
*/
|
|
68
|
+
export interface NestedChatElements extends ElementsBase {
|
|
69
|
+
rootEl: HTMLDivElement;
|
|
70
|
+
headerEl: HTMLDivElement;
|
|
71
|
+
breadcrumbsContainerEl: HTMLDivElement;
|
|
72
|
+
breadcrumbsRailEl: HTMLDivElement;
|
|
73
|
+
contentEl: HTMLDivElement;
|
|
74
|
+
btnCloseEl: HTMLButtonElement;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Concrete implementation of the nested, recursive tabbed chat parent component.
|
|
79
|
+
* Hosts child space-gib-chat instances in a breadcrumb trail.
|
|
80
|
+
*/
|
|
81
|
+
export class NestedChatComponentInstance
|
|
82
|
+
extends IbGibDynamicComponentInstanceBase_ParentOfTabs<Settings_NestedChat, IbGib_V1, NestedChatElements, NestedChatTabInfo>
|
|
83
|
+
implements IbGibDynamicComponentInstance<IbGib_V1, NestedChatElements> {
|
|
84
|
+
|
|
85
|
+
protected override lc: string = `[${NestedChatComponentInstance.name}]`;
|
|
86
|
+
|
|
87
|
+
protected get settingsType(): SettingsType {
|
|
88
|
+
return SETTINGS_TYPE_NESTED_CHAT;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get el(): NestedChatElements {
|
|
92
|
+
if (!this.elements) {
|
|
93
|
+
throw new Error(`elements is not defined in ${this.lc}`);
|
|
94
|
+
}
|
|
95
|
+
return this.elements;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private tabLabels: Map<string, { shortTitle: string, fullText: string, icon: string }> = new Map();
|
|
99
|
+
|
|
100
|
+
private ensureValidIbGibAddr(addr: string): IbGibAddr {
|
|
101
|
+
if (!addr || addr === ROOT_ADDR) {
|
|
102
|
+
return 'file src/index.ts^index_tjp';
|
|
103
|
+
}
|
|
104
|
+
if (!addr.includes('^')) {
|
|
105
|
+
return `file ${addr}^${addr.replace(/[^a-zA-Z0-9]/g, '_')}_tjp`;
|
|
106
|
+
}
|
|
107
|
+
return addr;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override async created(): Promise<void> {
|
|
111
|
+
const lc = `${this.lc}[${this.created.name}]`;
|
|
112
|
+
try {
|
|
113
|
+
console.log(`${lc} created starting...`);
|
|
114
|
+
const root = this.shadowRoot!;
|
|
115
|
+
this.elements = {
|
|
116
|
+
rootEl: root.getElementById('nested-chat-root') as HTMLDivElement,
|
|
117
|
+
headerEl: root.getElementById('nested-chat-header') as HTMLDivElement,
|
|
118
|
+
breadcrumbsContainerEl: root.getElementById('nested-chat-breadcrumbs-container') as HTMLDivElement,
|
|
119
|
+
breadcrumbsRailEl: root.getElementById('nested-chat-breadcrumbs-rail') as HTMLDivElement,
|
|
120
|
+
contentEl: root.getElementById('nested-chat-content') as HTMLDivElement,
|
|
121
|
+
btnCloseEl: root.getElementById('btn-nested-chat-close') as HTMLButtonElement,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
this.bindEvents();
|
|
125
|
+
|
|
126
|
+
// Only activate initial thread if an ibGibAddr was explicitly provided to the component
|
|
127
|
+
if (this.ibGibAddr) {
|
|
128
|
+
const rootAddr = this.ensureValidIbGibAddr(this.ibGibAddr);
|
|
129
|
+
setTimeout(async () => {
|
|
130
|
+
console.log(`${lc} activating initial root thread: ${rootAddr}`);
|
|
131
|
+
await this.activateIbGib({ addr: rootAddr });
|
|
132
|
+
}, 0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
override async disconnected(): Promise<void> {
|
|
141
|
+
// Lifecycle cleanup
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private bindEvents(): void {
|
|
145
|
+
this.el.btnCloseEl?.addEventListener('click', () => this.onCloseRequested());
|
|
146
|
+
|
|
147
|
+
// Listen for drill-down events bubbling from child space-gib-chat instances
|
|
148
|
+
this.addEventListener(EVENT_SPACE_GIB_CHAT_DRILL_DOWN, async (e: Event) => {
|
|
149
|
+
const customEv = e as CustomEvent<ChatDrillDownEventDetail>;
|
|
150
|
+
const detail = customEv.detail;
|
|
151
|
+
if (detail?.addr) {
|
|
152
|
+
await this.handleDrillDown(detail);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private onCloseRequested(): void {
|
|
158
|
+
this.dispatchEvent(new CustomEvent(EVENT_SPACE_GIB_CHAT_CLOSED, {
|
|
159
|
+
bubbles: true,
|
|
160
|
+
composed: true,
|
|
161
|
+
}));
|
|
162
|
+
window.dispatchEvent(new CustomEvent('space-gib-chat-close-requested', {
|
|
163
|
+
bubbles: true,
|
|
164
|
+
composed: true,
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Handles drill-down request into a child comment.
|
|
170
|
+
* Preserves ancestor trail, but if drilling down from an earlier ancestor,
|
|
171
|
+
* prunes any diverging descendants beyond the active ancestor.
|
|
172
|
+
*/
|
|
173
|
+
private async handleDrillDown(detail: ChatDrillDownEventDetail): Promise<void> {
|
|
174
|
+
const lc = `${this.lc}[${this.handleDrillDown.name}]`;
|
|
175
|
+
try {
|
|
176
|
+
console.log(`${lc} handleDrillDown requested for:`, detail);
|
|
177
|
+
const activeIndex = this.childInfos.findIndex(x => x.active);
|
|
178
|
+
if (activeIndex >= 0 && activeIndex < this.childInfos.length - 1) {
|
|
179
|
+
// Prune diverging descendants after the active ancestor
|
|
180
|
+
this.childInfos = this.childInfos.slice(0, activeIndex + 1);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const addr = this.ensureValidIbGibAddr(detail.addr);
|
|
184
|
+
// Cache label info for this child comment
|
|
185
|
+
this.tabLabels.set(addr, {
|
|
186
|
+
shortTitle: this.formatShortTitle(detail.text),
|
|
187
|
+
fullText: detail.text,
|
|
188
|
+
icon: '💬',
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await this.activateIbGib({ addr });
|
|
192
|
+
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public override async activateIbGib({ addr, ibGib }: { addr?: IbGibAddr; ibGib?: IbGib_V1; }): Promise<void> {
|
|
199
|
+
const lc = `${this.lc}[${this.activateIbGib.name}]`;
|
|
200
|
+
try {
|
|
201
|
+
if (addr) {
|
|
202
|
+
addr = this.ensureValidIbGibAddr(addr);
|
|
203
|
+
} else if (ibGib) {
|
|
204
|
+
addr = getIbGibAddr({ ibGib });
|
|
205
|
+
}
|
|
206
|
+
console.log(`${lc} activating addr: ${addr}`);
|
|
207
|
+
await super.activateIbGib({ addr, ibGib });
|
|
208
|
+
this.renderBreadcrumbsRail();
|
|
209
|
+
console.log(`${lc} activation complete for addr: ${addr}. Child tabs: ${this.childInfos.length}`);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
protected override async getLoadedChildInfo({
|
|
216
|
+
addr,
|
|
217
|
+
ibGib,
|
|
218
|
+
}: {
|
|
219
|
+
addr: IbGibAddr,
|
|
220
|
+
ibGib?: IbGib_V1,
|
|
221
|
+
}): Promise<NestedChatTabInfo> {
|
|
222
|
+
const lc = `${this.lc}[${this.getLoadedChildInfo.name}]`;
|
|
223
|
+
try {
|
|
224
|
+
if (!addr) { throw new Error(`(UNEXPECTED) addr falsy?`); }
|
|
225
|
+
addr = this.ensureValidIbGibAddr(addr);
|
|
226
|
+
|
|
227
|
+
const gib = getIbAndGib({ ibGibAddr: addr }).gib;
|
|
228
|
+
const gibInfo = getGibInfo({ gib });
|
|
229
|
+
const tjpGib = gibInfo.tjpGib ?? gib;
|
|
230
|
+
|
|
231
|
+
const existing = this.childInfos.find(x => {
|
|
232
|
+
const tabGib = getIbAndGib({ ibGibAddr: x.addr }).gib;
|
|
233
|
+
const tabGibInfo = getGibInfo({ gib: tabGib });
|
|
234
|
+
const tabTjpGib = tabGibInfo.tjpGib ?? tabGib;
|
|
235
|
+
return tabTjpGib === tjpGib || x.addr === addr;
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (existing) {
|
|
239
|
+
if (!existing.component) {
|
|
240
|
+
existing.component = await this.createChildChatComponent(addr);
|
|
241
|
+
}
|
|
242
|
+
return existing;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const childComponent = await this.createChildChatComponent(addr);
|
|
246
|
+
const childIbGib = childComponent.ibGib || Factory_V1.primitive({ ib: `chat ${addr}` });
|
|
247
|
+
const tabBtnEl = await this.addChild({ addr, ibGib: childIbGib });
|
|
248
|
+
|
|
249
|
+
const label = this.getTabLabelForAddr(addr);
|
|
250
|
+
const tabInfo: NestedChatTabInfo = {
|
|
251
|
+
addr,
|
|
252
|
+
childBtnEl: tabBtnEl,
|
|
253
|
+
component: childComponent,
|
|
254
|
+
active: false,
|
|
255
|
+
shortTitle: label.shortTitle,
|
|
256
|
+
fullText: label.fullText,
|
|
257
|
+
depth: this.childInfos.length,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
return tabInfo;
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private async createChildChatComponent(addr: IbGibAddr): Promise<ChatComponentInstance> {
|
|
268
|
+
const lc = `${this.lc}[${this.createChildChatComponent.name}]`;
|
|
269
|
+
console.log(`${lc} creating child chat component for addr: ${addr}`);
|
|
270
|
+
const componentSvc = await getComponentSvc();
|
|
271
|
+
let component = await componentSvc.getComponentInstance({
|
|
272
|
+
path: CHAT_COMPONENT_NAME,
|
|
273
|
+
ibGibAddr: addr,
|
|
274
|
+
useRegExpPrefilter: true,
|
|
275
|
+
}) as ChatComponentInstance;
|
|
276
|
+
if (!component) {
|
|
277
|
+
console.warn(`${lc} componentSvc returned null, falling back to direct meta instantiation`);
|
|
278
|
+
const meta = new ChatComponentMeta();
|
|
279
|
+
component = await meta.createInstance({
|
|
280
|
+
path: CHAT_COMPONENT_NAME,
|
|
281
|
+
ibGibAddr: addr,
|
|
282
|
+
}) as ChatComponentInstance;
|
|
283
|
+
}
|
|
284
|
+
return component;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
protected override async addChild({
|
|
288
|
+
addr,
|
|
289
|
+
ibGib,
|
|
290
|
+
}: {
|
|
291
|
+
ibGib: IbGib_V1,
|
|
292
|
+
addr?: IbGibAddr,
|
|
293
|
+
}): Promise<HTMLElement> {
|
|
294
|
+
addr ??= getIbGibAddr({ ibGib });
|
|
295
|
+
const label = this.getTabLabelForAddr(addr);
|
|
296
|
+
|
|
297
|
+
const btn = document.createElement('button');
|
|
298
|
+
btn.className = 'breadcrumb-btn';
|
|
299
|
+
btn.setAttribute('data-addr', addr);
|
|
300
|
+
btn.title = label.fullText;
|
|
301
|
+
btn.innerHTML = `
|
|
302
|
+
<span class="bc-icon">${label.icon}</span>
|
|
303
|
+
<span class="bc-title">${this.escapeHtml(label.shortTitle)}</span>
|
|
304
|
+
`;
|
|
305
|
+
btn.addEventListener('click', (e) => {
|
|
306
|
+
e.stopPropagation();
|
|
307
|
+
this.activateIbGib({ addr });
|
|
308
|
+
});
|
|
309
|
+
return btn;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
protected override async removeTabBtn({
|
|
313
|
+
tabInfo,
|
|
314
|
+
}: {
|
|
315
|
+
tabInfo: NestedChatTabInfo,
|
|
316
|
+
}): Promise<void> {
|
|
317
|
+
this.renderBreadcrumbsRail();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private renderBreadcrumbsRail(): void {
|
|
321
|
+
if (!this.el?.breadcrumbsRailEl) return;
|
|
322
|
+
|
|
323
|
+
const rail = this.el.breadcrumbsRailEl;
|
|
324
|
+
rail.innerHTML = '';
|
|
325
|
+
|
|
326
|
+
this.childInfos.forEach((info, idx) => {
|
|
327
|
+
// Update active styling
|
|
328
|
+
info.childBtnEl.className = `breadcrumb-btn ${info.active ? 'active' : ''}`;
|
|
329
|
+
rail.appendChild(info.childBtnEl);
|
|
330
|
+
|
|
331
|
+
// Add separator between breadcrumb tabs
|
|
332
|
+
if (idx < this.childInfos.length - 1) {
|
|
333
|
+
const sep = document.createElement('span');
|
|
334
|
+
sep.className = 'breadcrumb-separator';
|
|
335
|
+
sep.textContent = '›';
|
|
336
|
+
rail.appendChild(sep);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Scroll active tab into view
|
|
341
|
+
const activeInfo = this.activeChildInfo;
|
|
342
|
+
if (activeInfo?.childBtnEl) {
|
|
343
|
+
activeInfo.childBtnEl.scrollIntoView({ behavior: 'smooth', inline: 'nearest' });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private getTabLabelForAddr(addr: IbGibAddr): { shortTitle: string, fullText: string, icon: string } {
|
|
348
|
+
const cached = this.tabLabels.get(addr);
|
|
349
|
+
if (cached) { return cached; }
|
|
350
|
+
|
|
351
|
+
const { ib } = getIbAndGib({ ibGibAddr: addr });
|
|
352
|
+
if (addr === ROOT_ADDR || ib === 'root' || ib.includes('file') || !addr.includes('comment')) {
|
|
353
|
+
const fileTitle = ib.startsWith('file ') ? ib.replace('file ', '') : 'src/index.ts';
|
|
354
|
+
return {
|
|
355
|
+
shortTitle: this.formatShortTitle(fileTitle),
|
|
356
|
+
fullText: `Root Thread: ${fileTitle}`,
|
|
357
|
+
icon: '🌿',
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const pieces = ib.split(' ');
|
|
362
|
+
const text = pieces.length > 1 ? pieces.slice(1).join(' ') : 'Comment';
|
|
363
|
+
const shortTitle = this.formatShortTitle(text);
|
|
364
|
+
return {
|
|
365
|
+
shortTitle,
|
|
366
|
+
fullText: text,
|
|
367
|
+
icon: '💬',
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private formatShortTitle(text: string): string {
|
|
372
|
+
const clean = text.replace(/[\n\r]+/g, ' ').trim();
|
|
373
|
+
if (clean.length <= MAX_BREADCRUMB_TEXT_LENGTH) {
|
|
374
|
+
return clean;
|
|
375
|
+
}
|
|
376
|
+
return clean.slice(0, MAX_BREADCRUMB_TEXT_LENGTH) + '…';
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private escapeHtml(text: string): string {
|
|
380
|
+
const div = document.createElement('div');
|
|
381
|
+
div.textContent = text;
|
|
382
|
+
return div.innerHTML;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
public getActiveChatInstance(): ChatComponentInstance | undefined {
|
|
386
|
+
return this.activeChildInfo?.component as ChatComponentInstance | undefined;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
public enterNewTopicMode(initialTitle?: string): void {
|
|
390
|
+
const activeChat = this.getActiveChatInstance();
|
|
391
|
+
activeChat?.enterNewTopicMode(initialTitle);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";
|
|
2
|
+
import { NotesExplorerComponentMeta } from "./notes-explorer.mjs";
|
|
3
|
+
|
|
4
|
+
export * from "./notes-explorer.mjs";
|
|
5
|
+
|
|
6
|
+
export async function registerNotesExplorerComponent(): Promise<void> {
|
|
7
|
+
const componentSvc = await getComponentSvc();
|
|
8
|
+
componentSvc.registerComponentMeta(new NotesExplorerComponentMeta());
|
|
9
|
+
}
|