@ibgib/space-gib 0.0.33 → 0.0.35

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.
Files changed (118) hide show
  1. package/dist/client/bootstrap.mjs +24 -51
  2. package/dist/client/chunk-FIAGRVBY.mjs +10933 -0
  3. package/dist/client/chunk-XLQ3UCQY.mjs +53 -0
  4. package/dist/client/css/activity-bar.css +435 -0
  5. package/dist/client/css/base.css +167 -0
  6. package/dist/client/css/components.css +218 -0
  7. package/dist/client/css/cosmic.css +557 -0
  8. package/dist/client/css/dev-tools.css +163 -0
  9. package/dist/client/css/landing.css +184 -0
  10. package/dist/client/css/layout.css +1017 -0
  11. package/dist/client/css/onboarding.css +181 -0
  12. package/dist/client/css/repos.css +740 -0
  13. package/dist/client/css/variables.css +64 -0
  14. package/dist/client/index.html +208 -31
  15. package/dist/client/index.mjs +22 -45
  16. package/dist/client/privacy.html +22 -22
  17. package/dist/client/script.mjs +1 -1
  18. package/dist/client/style.css +11 -1056
  19. package/dist/respec-gib.node.mjs +5 -0
  20. package/dist/server/server.mjs +6880 -3110
  21. package/package.json +6 -6
  22. package/src/client/AUTO-GENERATED-version.mts +1 -1
  23. package/src/client/cosmos/seed-cosmos-workspace.mts +83 -0
  24. package/src/client/css/activity-bar.css +435 -0
  25. package/src/client/css/base.css +167 -0
  26. package/src/client/css/components.css +218 -0
  27. package/src/client/css/cosmic.css +557 -0
  28. package/src/client/css/dev-tools.css +163 -0
  29. package/src/client/css/landing.css +184 -0
  30. package/src/client/css/layout.css +1017 -0
  31. package/src/client/css/onboarding.css +181 -0
  32. package/src/client/css/repos.css +740 -0
  33. package/src/client/css/variables.css +64 -0
  34. package/src/client/dev-tools/vcs-workspace.mts +7 -7
  35. package/src/client/index.html +208 -31
  36. package/src/client/privacy.html +22 -22
  37. package/src/client/style.css +11 -1056
  38. package/src/client/ui/component/changes/changes.css +413 -0
  39. package/src/client/ui/component/changes/changes.html +37 -0
  40. package/src/client/ui/component/changes/changes.mts +766 -0
  41. package/src/client/ui/component/changes/index.mts +9 -0
  42. package/src/client/ui/component/chat-view/IMPLEMENTATION.md +48 -0
  43. package/src/client/ui/component/chat-view/chat-view.css +381 -0
  44. package/src/client/ui/component/chat-view/chat-view.html +52 -0
  45. package/src/client/ui/component/chat-view/chat-view.mts +264 -0
  46. package/src/client/ui/component/chat-view/index.mts +9 -0
  47. package/src/client/ui/component/clone/IMPLEMENTATION.md +68 -0
  48. package/src/client/ui/component/clone/clone-constants.mts +16 -0
  49. package/src/client/ui/component/clone/clone-types.mts +60 -0
  50. package/src/client/ui/component/clone/clone.css +383 -0
  51. package/src/client/ui/component/clone/clone.html +89 -0
  52. package/src/client/ui/component/clone/clone.mts +648 -0
  53. package/src/client/ui/component/clone/index.mts +11 -0
  54. package/src/client/ui/component/code-editor/IMPLEMENTATION.md +89 -0
  55. package/src/client/ui/component/code-editor/code-editor.css +357 -0
  56. package/src/client/ui/component/code-editor/code-editor.html +67 -0
  57. package/src/client/ui/component/code-editor/code-editor.mts +643 -0
  58. package/src/client/ui/component/code-editor/index.mts +9 -0
  59. package/src/client/ui/component/cosmos-navigator/IMPLEMENTATION.md +31 -0
  60. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +864 -0
  61. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +92 -0
  62. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +1317 -0
  63. package/src/client/ui/component/cosmos-navigator/index.mts +18 -0
  64. package/src/client/ui/component/file-explorer/IMPLEMENTATION.md +42 -0
  65. package/src/client/ui/component/file-explorer/file-explorer.css +720 -0
  66. package/src/client/ui/component/file-explorer/file-explorer.html +55 -0
  67. package/src/client/ui/component/file-explorer/file-explorer.mts +1412 -0
  68. package/src/client/ui/component/file-explorer/index.mts +9 -0
  69. package/src/client/ui/component/nested-chat/IMPLEMENTATION.md +18 -0
  70. package/src/client/ui/component/nested-chat/chat/IMPLEMENTATION.md +14 -0
  71. package/src/client/ui/component/nested-chat/chat/chat-constants.mts +14 -0
  72. package/src/client/ui/component/nested-chat/chat/chat-helpers.mts +66 -0
  73. package/src/client/ui/component/nested-chat/chat/chat.css +654 -0
  74. package/src/client/ui/component/nested-chat/chat/chat.html +90 -0
  75. package/src/client/ui/component/nested-chat/chat/chat.mts +561 -0
  76. package/src/client/ui/component/nested-chat/chat/index.mts +7 -0
  77. package/src/client/ui/component/nested-chat/index.mts +14 -0
  78. package/src/client/ui/component/nested-chat/nested-chat-constants.mts +12 -0
  79. package/src/client/ui/component/nested-chat/nested-chat-types.mts +53 -0
  80. package/src/client/ui/component/nested-chat/nested-chat.css +142 -0
  81. package/src/client/ui/component/nested-chat/nested-chat.html +11 -0
  82. package/src/client/ui/component/nested-chat/nested-chat.mts +395 -0
  83. package/src/client/ui/component/notes-explorer/index.mts +9 -0
  84. package/src/client/ui/component/notes-explorer/notes-explorer.css +313 -0
  85. package/src/client/ui/component/notes-explorer/notes-explorer.html +136 -0
  86. package/src/client/ui/component/notes-explorer/notes-explorer.mts +240 -0
  87. package/src/client/ui/component/notes-inspector/index.mts +9 -0
  88. package/src/client/ui/component/notes-inspector/notes-inspector.css +244 -0
  89. package/src/client/ui/component/notes-inspector/notes-inspector.html +97 -0
  90. package/src/client/ui/component/notes-inspector/notes-inspector.mts +152 -0
  91. package/src/client/ui/component/pitch/IMPLEMENTATION.md +48 -0
  92. package/src/client/ui/component/pitch/index.mts +9 -0
  93. package/src/client/ui/component/pitch/pitch.css +295 -0
  94. package/src/client/ui/component/pitch/pitch.html +97 -0
  95. package/src/client/ui/component/pitch/pitch.mts +135 -0
  96. package/src/client/ui/component/timeline/IMPLEMENTATION.md +33 -0
  97. package/src/client/ui/component/timeline/index.mts +9 -0
  98. package/src/client/ui/component/timeline/timeline.css +279 -0
  99. package/src/client/ui/component/timeline/timeline.html +23 -0
  100. package/src/client/ui/component/timeline/timeline.mts +261 -0
  101. package/src/client/ui/component/timeline-item-details/IMPLEMENTATION.md +28 -0
  102. package/src/client/ui/component/timeline-item-details/index.mts +9 -0
  103. package/src/client/ui/component/timeline-item-details/timeline-item-details.css +286 -0
  104. package/src/client/ui/component/timeline-item-details/timeline-item-details.html +64 -0
  105. package/src/client/ui/component/timeline-item-details/timeline-item-details.mts +194 -0
  106. package/src/client/ui/router/index.mts +3 -0
  107. package/src/client/ui/router/space-gib-router-helpers.mts +72 -0
  108. package/src/client/ui/router/space-gib-router-helpers.respec.mts +529 -0
  109. package/src/client/ui/router/space-gib-router-service.mts +63 -0
  110. package/src/client/ui/router/space-gib-router-types.mts +49 -0
  111. package/src/client/ui/shell/cosmic-big-bang.mts +853 -0
  112. package/src/client/ui/shell/space-gib-shell-constants.mts +7 -0
  113. package/src/client/ui/shell/space-gib-shell-service.mts +2297 -32
  114. package/src/server/server.mts +20 -1
  115. package/tsconfig.test.json +5 -1
  116. package/dist/client/chunk-CRJV762I.mjs +0 -3102
  117. package/dist/client/chunk-LXRCF5OS.mjs +0 -25
  118. package/dist/client/chunk-UBDQUZZV.mjs +0 -1
@@ -0,0 +1,12 @@
1
+
2
+ export const NESTED_CHAT_COMPONENT_NAME = 'space-gib-nested-chat';
3
+ export const CHAT_COMPONENT_NAME = 'space-gib-chat';
4
+
5
+ export const EVENT_SPACE_GIB_CHAT_DRILL_DOWN = 'space-gib-chat-drill-down';
6
+ export const EVENT_SPACE_GIB_CHAT_BREADCRUMB_SELECTED = 'space-gib-chat-breadcrumb-selected';
7
+ export const EVENT_SPACE_GIB_CHAT_CLOSED = 'space-gib-chat-closed';
8
+
9
+ export const MAX_BREADCRUMB_TEXT_LENGTH = 16;
10
+
11
+ export const SETTINGS_TYPE_NESTED_CHAT = 'nested-chat';
12
+ export const NESTED_CHAT_SETTINGS_TYPE = SETTINGS_TYPE_NESTED_CHAT;
@@ -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,395 @@
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 ROOT_ADDR;
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 (not ROOT_ADDR)
127
+ if (this.ibGibAddr && this.ibGibAddr !== ROOT_ADDR) {
128
+ const rootAddr = this.ensureValidIbGibAddr(this.ibGibAddr);
129
+ if (rootAddr && rootAddr !== ROOT_ADDR) {
130
+ setTimeout(async () => {
131
+ console.log(`${lc} activating initial root thread: ${rootAddr}`);
132
+ await this.activateIbGib({ addr: rootAddr });
133
+ }, 0);
134
+ }
135
+ }
136
+
137
+ } catch (error) {
138
+ console.error(`${lc} ${extractErrorMsg(error)}`);
139
+ }
140
+ }
141
+
142
+ override async disconnected(): Promise<void> {
143
+ // Lifecycle cleanup
144
+ }
145
+
146
+ private bindEvents(): void {
147
+ this.el.btnCloseEl?.addEventListener('click', () => this.onCloseRequested());
148
+
149
+ // Listen for drill-down events bubbling from child space-gib-chat instances
150
+ this.addEventListener(EVENT_SPACE_GIB_CHAT_DRILL_DOWN, async (e: Event) => {
151
+ const customEv = e as CustomEvent<ChatDrillDownEventDetail>;
152
+ const detail = customEv.detail;
153
+ if (detail?.addr) {
154
+ await this.handleDrillDown(detail);
155
+ }
156
+ });
157
+ }
158
+
159
+ private onCloseRequested(): void {
160
+ this.dispatchEvent(new CustomEvent(EVENT_SPACE_GIB_CHAT_CLOSED, {
161
+ bubbles: true,
162
+ composed: true,
163
+ }));
164
+ window.dispatchEvent(new CustomEvent('space-gib-chat-close-requested', {
165
+ bubbles: true,
166
+ composed: true,
167
+ }));
168
+ }
169
+
170
+ /**
171
+ * Handles drill-down request into a child comment.
172
+ * Preserves ancestor trail, but if drilling down from an earlier ancestor,
173
+ * prunes any diverging descendants beyond the active ancestor.
174
+ */
175
+ private async handleDrillDown(detail: ChatDrillDownEventDetail): Promise<void> {
176
+ const lc = `${this.lc}[${this.handleDrillDown.name}]`;
177
+ try {
178
+ console.log(`${lc} handleDrillDown requested for:`, detail);
179
+ const activeIndex = this.childInfos.findIndex(x => x.active);
180
+ if (activeIndex >= 0 && activeIndex < this.childInfos.length - 1) {
181
+ // Prune diverging descendants after the active ancestor
182
+ this.childInfos = this.childInfos.slice(0, activeIndex + 1);
183
+ }
184
+
185
+ const addr = this.ensureValidIbGibAddr(detail.addr);
186
+ // Cache label info for this child comment
187
+ this.tabLabels.set(addr, {
188
+ shortTitle: this.formatShortTitle(detail.text),
189
+ fullText: detail.text,
190
+ icon: '💬',
191
+ });
192
+
193
+ await this.activateIbGib({ addr });
194
+
195
+ } catch (error) {
196
+ console.error(`${lc} ${extractErrorMsg(error)}`);
197
+ }
198
+ }
199
+
200
+ public override async activateIbGib({ addr, ibGib }: { addr?: IbGibAddr; ibGib?: IbGib_V1; }): Promise<void> {
201
+ const lc = `${this.lc}[${this.activateIbGib.name}]`;
202
+ try {
203
+ if (addr) {
204
+ addr = this.ensureValidIbGibAddr(addr);
205
+ } else if (ibGib) {
206
+ addr = getIbGibAddr({ ibGib });
207
+ }
208
+ console.log(`${lc} activating addr: ${addr}`);
209
+ await super.activateIbGib({ addr, ibGib });
210
+ this.renderBreadcrumbsRail();
211
+ console.log(`${lc} activation complete for addr: ${addr}. Child tabs: ${this.childInfos.length}`);
212
+ } catch (error) {
213
+ console.error(`${lc} ${extractErrorMsg(error)}`);
214
+ }
215
+ }
216
+
217
+ protected override async getLoadedChildInfo({
218
+ addr,
219
+ ibGib,
220
+ }: {
221
+ addr: IbGibAddr,
222
+ ibGib?: IbGib_V1,
223
+ }): Promise<NestedChatTabInfo> {
224
+ const lc = `${this.lc}[${this.getLoadedChildInfo.name}]`;
225
+ try {
226
+ if (!addr) { throw new Error(`(UNEXPECTED) addr falsy?`); }
227
+ addr = this.ensureValidIbGibAddr(addr);
228
+
229
+ const gib = getIbAndGib({ ibGibAddr: addr }).gib;
230
+ const gibInfo = getGibInfo({ gib });
231
+ const tjpGib = gibInfo.tjpGib ?? gib;
232
+
233
+ const existing = this.childInfos.find(x => {
234
+ const tabGib = getIbAndGib({ ibGibAddr: x.addr }).gib;
235
+ const tabGibInfo = getGibInfo({ gib: tabGib });
236
+ const tabTjpGib = tabGibInfo.tjpGib ?? tabGib;
237
+ return tabTjpGib === tjpGib || x.addr === addr;
238
+ });
239
+
240
+ if (existing) {
241
+ if (!existing.component) {
242
+ existing.component = await this.createChildChatComponent(addr);
243
+ }
244
+ return existing;
245
+ }
246
+
247
+ const childComponent = await this.createChildChatComponent(addr);
248
+ const childIbGib = childComponent.ibGib || Factory_V1.primitive({ ib: `chat ${addr}` });
249
+ const tabBtnEl = await this.addChild({ addr, ibGib: childIbGib });
250
+
251
+ const label = this.getTabLabelForAddr(addr);
252
+ const tabInfo: NestedChatTabInfo = {
253
+ addr,
254
+ childBtnEl: tabBtnEl,
255
+ component: childComponent,
256
+ active: false,
257
+ shortTitle: label.shortTitle,
258
+ fullText: label.fullText,
259
+ depth: this.childInfos.length,
260
+ };
261
+
262
+ return tabInfo;
263
+ } catch (error) {
264
+ console.error(`${lc} ${extractErrorMsg(error)}`);
265
+ throw error;
266
+ }
267
+ }
268
+
269
+ private async createChildChatComponent(addr: IbGibAddr): Promise<ChatComponentInstance> {
270
+ const lc = `${this.lc}[${this.createChildChatComponent.name}]`;
271
+ console.log(`${lc} creating child chat component for addr: ${addr}`);
272
+ const componentSvc = await getComponentSvc();
273
+ let component = await componentSvc.getComponentInstance({
274
+ path: CHAT_COMPONENT_NAME,
275
+ ibGibAddr: addr,
276
+ useRegExpPrefilter: true,
277
+ }) as ChatComponentInstance;
278
+ if (!component) {
279
+ console.warn(`${lc} componentSvc returned null, falling back to direct meta instantiation`);
280
+ const meta = new ChatComponentMeta();
281
+ component = await meta.createInstance({
282
+ path: CHAT_COMPONENT_NAME,
283
+ ibGibAddr: addr,
284
+ }) as ChatComponentInstance;
285
+ }
286
+ return component;
287
+ }
288
+
289
+ protected override async addChild({
290
+ addr,
291
+ ibGib,
292
+ }: {
293
+ ibGib: IbGib_V1,
294
+ addr?: IbGibAddr,
295
+ }): Promise<HTMLElement> {
296
+ addr ??= getIbGibAddr({ ibGib });
297
+ const label = this.getTabLabelForAddr(addr);
298
+
299
+ const btn = document.createElement('button');
300
+ btn.className = 'breadcrumb-btn';
301
+ btn.setAttribute('data-addr', addr);
302
+ btn.title = label.fullText;
303
+ btn.innerHTML = `
304
+ <span class="bc-icon">${label.icon}</span>
305
+ <span class="bc-title">${this.escapeHtml(label.shortTitle)}</span>
306
+ `;
307
+ btn.addEventListener('click', (e) => {
308
+ e.stopPropagation();
309
+ this.activateIbGib({ addr });
310
+ });
311
+ return btn;
312
+ }
313
+
314
+ protected override async removeTabBtn({
315
+ tabInfo,
316
+ }: {
317
+ tabInfo: NestedChatTabInfo,
318
+ }): Promise<void> {
319
+ this.renderBreadcrumbsRail();
320
+ }
321
+
322
+ private renderBreadcrumbsRail(): void {
323
+ if (!this.el?.breadcrumbsRailEl) return;
324
+
325
+ const rail = this.el.breadcrumbsRailEl;
326
+ rail.innerHTML = '';
327
+
328
+ this.childInfos.forEach((info, idx) => {
329
+ // Update active styling
330
+ info.childBtnEl.className = `breadcrumb-btn ${info.active ? 'active' : ''}`;
331
+ rail.appendChild(info.childBtnEl);
332
+
333
+ // Add separator between breadcrumb tabs
334
+ if (idx < this.childInfos.length - 1) {
335
+ const sep = document.createElement('span');
336
+ sep.className = 'breadcrumb-separator';
337
+ sep.textContent = '›';
338
+ rail.appendChild(sep);
339
+ }
340
+ });
341
+
342
+ // Scroll active tab into view
343
+ const activeInfo = this.activeChildInfo;
344
+ if (activeInfo?.childBtnEl) {
345
+ activeInfo.childBtnEl.scrollIntoView({ behavior: 'smooth', inline: 'nearest' });
346
+ }
347
+ }
348
+
349
+ private getTabLabelForAddr(addr: IbGibAddr): { shortTitle: string, fullText: string, icon: string } {
350
+ const cached = this.tabLabels.get(addr);
351
+ if (cached) { return cached; }
352
+
353
+ const { ib } = getIbAndGib({ ibGibAddr: addr });
354
+ if (addr === ROOT_ADDR || ib === 'root' || ib.includes('file') || !addr.includes('comment')) {
355
+ const fileTitle = ib.startsWith('file ') ? ib.replace('file ', '') : (ib === 'root' || addr === ROOT_ADDR ? 'Workspace' : ib);
356
+ return {
357
+ shortTitle: this.formatShortTitle(fileTitle),
358
+ fullText: `Root Thread: ${fileTitle}`,
359
+ icon: '🌿',
360
+ };
361
+ }
362
+
363
+ const pieces = ib.split(' ');
364
+ const text = pieces.length > 1 ? pieces.slice(1).join(' ') : 'Comment';
365
+ const shortTitle = this.formatShortTitle(text);
366
+ return {
367
+ shortTitle,
368
+ fullText: text,
369
+ icon: '💬',
370
+ };
371
+ }
372
+
373
+ private formatShortTitle(text: string): string {
374
+ const clean = text.replace(/[\n\r]+/g, ' ').trim();
375
+ if (clean.length <= MAX_BREADCRUMB_TEXT_LENGTH) {
376
+ return clean;
377
+ }
378
+ return clean.slice(0, MAX_BREADCRUMB_TEXT_LENGTH) + '…';
379
+ }
380
+
381
+ private escapeHtml(text: string): string {
382
+ const div = document.createElement('div');
383
+ div.textContent = text;
384
+ return div.innerHTML;
385
+ }
386
+
387
+ public getActiveChatInstance(): ChatComponentInstance | undefined {
388
+ return this.activeChildInfo?.component as ChatComponentInstance | undefined;
389
+ }
390
+
391
+ public enterNewTopicMode(initialTitle?: string): void {
392
+ const activeChat = this.getActiveChatInstance();
393
+ activeChat?.enterNewTopicMode(initialTitle);
394
+ }
395
+ }
@@ -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
+ }