@ibgib/space-gib 0.0.34 โ 0.0.36
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 +1 -1
- package/dist/client/{chunk-25PXC4HP.mjs โ chunk-5DTAUY3E.mjs} +1586 -464
- package/dist/client/chunk-J7X3XTAI.mjs +53 -0
- package/dist/client/css/activity-bar.css +21 -3
- package/dist/client/css/layout.css +126 -5
- package/dist/client/css/tutorial.css +327 -0
- package/dist/client/index.html +6 -0
- package/dist/client/index.mjs +22 -45
- package/dist/client/privacy.html +22 -22
- package/dist/client/script.mjs +1 -1
- package/dist/client/style.css +1 -0
- package/dist/server/server.mjs +3 -3
- package/package.json +6 -6
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/cosmos/seed-cosmos-workspace.mts +20 -6
- package/src/client/css/activity-bar.css +21 -3
- package/src/client/css/layout.css +126 -5
- package/src/client/css/tutorial.css +327 -0
- package/src/client/dev-tools/vcs-workspace.mts +4 -4
- package/src/client/index.html +6 -0
- package/src/client/privacy.html +22 -22
- package/src/client/style.css +1 -0
- package/src/client/ui/component/changes/changes.css +413 -0
- package/src/client/ui/component/changes/changes.html +37 -0
- package/src/client/ui/component/changes/changes.mts +766 -0
- package/src/client/ui/component/changes/index.mts +9 -0
- package/src/client/ui/component/chat-view/chat-view.html +6 -58
- package/src/client/ui/component/chat-view/chat-view.mts +13 -26
- package/src/client/ui/component/clone/clone.mts +67 -39
- package/src/client/ui/component/code-editor/code-editor.css +91 -9
- package/src/client/ui/component/code-editor/code-editor.html +58 -45
- package/src/client/ui/component/code-editor/code-editor.mts +265 -49
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +1 -1
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +5 -10
- package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +328 -64
- package/src/client/ui/component/file-explorer/file-explorer.css +475 -11
- package/src/client/ui/component/file-explorer/file-explorer.html +45 -65
- package/src/client/ui/component/file-explorer/file-explorer.mts +1164 -98
- package/src/client/ui/component/nested-chat/chat/chat.mts +5 -90
- package/src/client/ui/component/nested-chat/nested-chat.mts +10 -8
- package/src/client/ui/component/timeline/timeline.css +16 -1
- package/src/client/ui/component/timeline/timeline.mts +37 -93
- package/src/client/ui/component/tutorial/index.mts +9 -0
- package/src/client/ui/component/tutorial/scripts/pitch-tour-script.mts +265 -0
- package/src/client/ui/component/tutorial/tutorial-controller.mts +622 -0
- package/src/client/ui/component/tutorial/tutorial-types.mts +45 -0
- package/src/client/ui/component/tutorial/tutorial.css +260 -0
- package/src/client/ui/router/space-gib-router-helpers.mts +33 -233
- package/src/client/ui/router/space-gib-router-helpers.respec.mts +298 -122
- package/src/client/ui/router/space-gib-router-service.mts +28 -151
- package/src/client/ui/router/space-gib-router-types.mts +32 -76
- package/src/client/ui/shell/cosmic-big-bang.mts +12 -3
- package/src/client/ui/shell/space-gib-shell-service.mts +715 -143
- package/dist/client/chunk-RXWLL2AI.mjs +0 -30
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";
|
|
2
|
+
import { ChangesComponentMeta, CHANGES_COMPONENT_NAME } from "./changes.mjs";
|
|
3
|
+
|
|
4
|
+
export * from "./changes.mjs";
|
|
5
|
+
|
|
6
|
+
export async function registerChangesComponent(): Promise<void> {
|
|
7
|
+
const componentSvc = await getComponentSvc();
|
|
8
|
+
componentSvc.registerComponentMeta(new ChangesComponentMeta());
|
|
9
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<span class="chat-header-icon">๐ฌ</span>
|
|
6
6
|
<div class="chat-title-group">
|
|
7
7
|
<h3 class="chat-title">Discussions</h3>
|
|
8
|
-
<span class="chat-target-badge" id="chat-target-file">
|
|
8
|
+
<span class="chat-target-badge" id="chat-target-file">No file selected</span>
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
11
|
<div class="chat-header-actions">
|
|
@@ -17,69 +17,17 @@
|
|
|
17
17
|
<div class="chat-sub-bar">
|
|
18
18
|
<div class="chat-context-item">
|
|
19
19
|
<span class="context-icon">๐ฟ</span>
|
|
20
|
-
<span class="context-text" id="chat-branch-tip"
|
|
20
|
+
<span class="context-text" id="chat-branch-tip"></span>
|
|
21
21
|
</div>
|
|
22
22
|
<div class="chat-filter-item">
|
|
23
|
-
<span class="filter-text">
|
|
23
|
+
<span class="filter-text" id="chat-notes-count">0 Notes</span>
|
|
24
24
|
</div>
|
|
25
25
|
</div>
|
|
26
26
|
|
|
27
27
|
<!-- Messages Stream -->
|
|
28
28
|
<div class="chat-messages" id="chat-messages">
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<div class="msg-header">
|
|
32
|
-
<div class="msg-author-group">
|
|
33
|
-
<span class="msg-avatar">๐ฉโ๐ป</span>
|
|
34
|
-
<span class="msg-author">Alice</span>
|
|
35
|
-
<span class="msg-badge">Keystone</span>
|
|
36
|
-
</div>
|
|
37
|
-
<span class="msg-time">2m ago</span>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="msg-anchor">
|
|
40
|
-
<span class="anchor-icon">๐</span>
|
|
41
|
-
<span class="anchor-label">src/index.ts#L1-18</span>
|
|
42
|
-
<span class="anchor-tag">Inverted Rel8n</span>
|
|
43
|
-
</div>
|
|
44
|
-
<div class="msg-body">
|
|
45
|
-
<p class="msg-lead"><strong>Architectural Rationale</strong></p>
|
|
46
|
-
<p>This entrypoint initializes the virtual repository workspace within the browserโs local IndexedDB metaspace.
|
|
47
|
-
</p>
|
|
48
|
-
<div class="msg-callout">
|
|
49
|
-
<span class="callout-emoji">๐ก</span>
|
|
50
|
-
<div class="callout-text">
|
|
51
|
-
<strong>Why Living Comments?</strong> Unlike centralized SaaS review comments, this discussion node is an
|
|
52
|
-
in-band Merkle ibgib traveling directly with the branch DAG.
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
<div class="msg-footer">
|
|
57
|
-
<button class="msg-action-btn" type="button">Reply</button>
|
|
58
|
-
<button class="msg-action-btn" type="button">๐ 1</button>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<!-- Message 2: Code Review Discussion -->
|
|
63
|
-
<div class="chat-message peer-comment">
|
|
64
|
-
<div class="msg-header">
|
|
65
|
-
<div class="msg-author-group">
|
|
66
|
-
<span class="msg-avatar">๐จโ๐</span>
|
|
67
|
-
<span class="msg-author">Bob</span>
|
|
68
|
-
<span class="msg-badge">Peer</span>
|
|
69
|
-
</div>
|
|
70
|
-
<span class="msg-time">1m ago</span>
|
|
71
|
-
</div>
|
|
72
|
-
<div class="msg-anchor">
|
|
73
|
-
<span class="anchor-icon">๐</span>
|
|
74
|
-
<span class="anchor-label">src/index.ts#L36-42</span>
|
|
75
|
-
</div>
|
|
76
|
-
<div class="msg-body">
|
|
77
|
-
<p>Looks super clean! Should we add an async try/catch boundary around <code>boot()</code> as well?</p>
|
|
78
|
-
</div>
|
|
79
|
-
<div class="msg-footer">
|
|
80
|
-
<button class="msg-action-btn" type="button">Reply</button>
|
|
81
|
-
<button class="msg-action-btn" type="button">๐</button>
|
|
82
|
-
</div>
|
|
29
|
+
<div class="empty-chat-msg" style="padding: 24px 16px; font-size: 12px; color: #8a99a8; text-align: center; font-style: italic;">
|
|
30
|
+
No discussions yet for this context.
|
|
83
31
|
</div>
|
|
84
32
|
</div>
|
|
85
33
|
|
|
@@ -91,7 +39,7 @@
|
|
|
91
39
|
<div class="compose-tools-left">
|
|
92
40
|
<button id="btn-chat-pin" class="compose-tool-btn active" type="button" title="Pin to current line selection">
|
|
93
41
|
<span class="tool-icon">๐</span>
|
|
94
|
-
<span class="tool-label">
|
|
42
|
+
<span class="tool-label" id="chat-pin-label">No target</span>
|
|
95
43
|
</button>
|
|
96
44
|
</div>
|
|
97
45
|
<button id="btn-chat-send" class="compose-send-btn" type="button">
|
|
@@ -85,8 +85,8 @@ export class ChatViewComponentInstance
|
|
|
85
85
|
|
|
86
86
|
protected lc: string = `[${ChatViewComponentInstance.name}]`;
|
|
87
87
|
|
|
88
|
-
private targetFile: string = '
|
|
89
|
-
private branchTip: string = '
|
|
88
|
+
private targetFile: string = '';
|
|
89
|
+
private branchTip: string = '';
|
|
90
90
|
|
|
91
91
|
get el(): ChatViewElements {
|
|
92
92
|
if (!this.elements) {
|
|
@@ -95,29 +95,7 @@ export class ChatViewComponentInstance
|
|
|
95
95
|
return this.elements;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
private messages: ChatMessageItem[] = [
|
|
99
|
-
{
|
|
100
|
-
id: 'msg-1',
|
|
101
|
-
author: 'Alice',
|
|
102
|
-
avatar: '๐ฉโ๐ป',
|
|
103
|
-
role: 'Keystone',
|
|
104
|
-
timeAgo: '2m ago',
|
|
105
|
-
anchor: 'src/index.ts#L1-18',
|
|
106
|
-
text: 'Architectural Rationale: This entrypoint initializes the virtual repository workspace within the browserโs local IndexedDB metaspace.',
|
|
107
|
-
callout: 'Why Living Comments? Unlike centralized SaaS review comments, this discussion node is an in-band Merkle ibgib traveling directly with the branch DAG.',
|
|
108
|
-
isInBandNote: true,
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
id: 'msg-2',
|
|
112
|
-
author: 'Bob',
|
|
113
|
-
avatar: '๐จโ๐',
|
|
114
|
-
role: 'Peer',
|
|
115
|
-
timeAgo: '1m ago',
|
|
116
|
-
anchor: 'src/index.ts#L36-42',
|
|
117
|
-
text: 'Looks super clean! Should we add an async try/catch boundary around boot() as well?',
|
|
118
|
-
isInBandNote: false,
|
|
119
|
-
}
|
|
120
|
-
];
|
|
98
|
+
private messages: ChatMessageItem[] = [];
|
|
121
99
|
|
|
122
100
|
override async created(): Promise<void> {
|
|
123
101
|
const lc = `${this.lc}[${this.created.name}]`;
|
|
@@ -165,7 +143,7 @@ export class ChatViewComponentInstance
|
|
|
165
143
|
|
|
166
144
|
this.el.btnPinEl?.addEventListener('click', () => {
|
|
167
145
|
const currentPin = this.el?.btnPinEl?.querySelector('.tool-label')?.textContent || '';
|
|
168
|
-
const newPin = prompt('Pin comment to code reference (e.g.
|
|
146
|
+
const newPin = prompt('Pin comment to code reference (e.g. file.ts#L10-25):', currentPin);
|
|
169
147
|
if (newPin && this.el?.btnPinEl) {
|
|
170
148
|
const label = this.el.btnPinEl.querySelector('.tool-label');
|
|
171
149
|
if (label) { label.textContent = newPin; }
|
|
@@ -216,6 +194,15 @@ export class ChatViewComponentInstance
|
|
|
216
194
|
private renderMessages(): void {
|
|
217
195
|
if (!this.el?.messagesContainerEl) return;
|
|
218
196
|
|
|
197
|
+
if (this.messages.length === 0) {
|
|
198
|
+
this.el.messagesContainerEl.innerHTML = `
|
|
199
|
+
<div class="empty-chat-msg" style="padding: 24px 16px; font-size: 12px; color: #8a99a8; text-align: center; font-style: italic;">
|
|
200
|
+
No discussions yet for this context.
|
|
201
|
+
</div>
|
|
202
|
+
`;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
219
206
|
this.el.messagesContainerEl.innerHTML = this.messages.map(msg => `
|
|
220
207
|
<div class="chat-message ${msg.isInBandNote ? 'in-band-note' : 'peer-comment'}">
|
|
221
208
|
<div class="msg-header">
|
|
@@ -6,6 +6,7 @@ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
|
|
|
6
6
|
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
|
|
7
7
|
import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
8
8
|
import { promptForText } from "@ibgib/web-gib/dist/helpers.web.mjs";
|
|
9
|
+
import { validateBranchName } from "@ibgib/core-gib/dist/cosmology/branching/branch/branch-helpers.mjs";
|
|
9
10
|
import {
|
|
10
11
|
IbGibDynamicComponentMetaBase, IbGibDynamicComponentInstanceBase,
|
|
11
12
|
} from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
|
|
@@ -417,28 +418,41 @@ export class CloneComponentInstance
|
|
|
417
418
|
const btnBranchItem = this.el.singleItemContainerEl.querySelector('#btn-clone-modal-branch-item');
|
|
418
419
|
btnBranchItem?.addEventListener('click', async () => {
|
|
419
420
|
const filename = item.path.split('/').pop() || item.path;
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}));
|
|
421
|
+
let candidateName = `feature-branch-${filename.replace(/[^a-zA-Z0-9_.-]/g, '-')}`;
|
|
422
|
+
let promptMsg = `Enter branch name isolating and diverging from item [${item.path}]:`;
|
|
423
|
+
let cleanBranchName = '';
|
|
424
|
+
|
|
425
|
+
while (true) {
|
|
426
|
+
const newBranchName = await promptForText({
|
|
427
|
+
title: `Create Branch from Item`,
|
|
428
|
+
msg: promptMsg,
|
|
429
|
+
defaultValue: candidateName,
|
|
430
|
+
cancelable: true,
|
|
431
|
+
});
|
|
432
|
+
if (!newBranchName || !newBranchName.trim()) return;
|
|
433
|
+
cleanBranchName = newBranchName.trim();
|
|
434
|
+
const validation = validateBranchName(cleanBranchName);
|
|
435
|
+
if (!validation.isValid) {
|
|
436
|
+
candidateName = cleanBranchName;
|
|
437
|
+
promptMsg = `Invalid branch name: ${validation.error}\n\nPlease enter a valid branch name:`;
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
break;
|
|
441
441
|
}
|
|
442
|
+
|
|
443
|
+
this.showStatus(`Branch created: ${cleanBranchName}`);
|
|
444
|
+
window.dispatchEvent(new CustomEvent('space-gib-branch-requested', {
|
|
445
|
+
detail: {
|
|
446
|
+
galaxyName: item.galaxyName || 'Code Galaxy',
|
|
447
|
+
sourceBranch: item.branchName || 'main',
|
|
448
|
+
itemPath: item.path,
|
|
449
|
+
isDir: item.isDir,
|
|
450
|
+
newBranchName: cleanBranchName,
|
|
451
|
+
scope: 'item',
|
|
452
|
+
},
|
|
453
|
+
bubbles: true,
|
|
454
|
+
composed: true,
|
|
455
|
+
}));
|
|
442
456
|
});
|
|
443
457
|
}
|
|
444
458
|
|
|
@@ -484,25 +498,39 @@ export class CloneComponentInstance
|
|
|
484
498
|
e.stopPropagation();
|
|
485
499
|
const branchName = btn.getAttribute('data-branch') || 'main';
|
|
486
500
|
const galaxyName = btn.getAttribute('data-galaxy') || 'Code Galaxy';
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
501
|
+
let candidateName = `feature-branch-from-${branchName}`;
|
|
502
|
+
let promptMsg = `Enter branch name diverging from [${branchName}]:`;
|
|
503
|
+
let cleanBranchName = '';
|
|
504
|
+
|
|
505
|
+
while (true) {
|
|
506
|
+
const newBranchName = await promptForText({
|
|
507
|
+
title: 'Create Branch from Branch',
|
|
508
|
+
msg: promptMsg,
|
|
509
|
+
defaultValue: candidateName,
|
|
510
|
+
cancelable: true,
|
|
511
|
+
});
|
|
512
|
+
if (!newBranchName || !newBranchName.trim()) return;
|
|
513
|
+
cleanBranchName = newBranchName.trim();
|
|
514
|
+
const validation = validateBranchName(cleanBranchName);
|
|
515
|
+
if (!validation.isValid) {
|
|
516
|
+
candidateName = cleanBranchName;
|
|
517
|
+
promptMsg = `Invalid branch name: ${validation.error}\n\nPlease enter a valid branch name:`;
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
break;
|
|
505
521
|
}
|
|
522
|
+
|
|
523
|
+
this.showStatus(`Branch created: ${cleanBranchName}`);
|
|
524
|
+
window.dispatchEvent(new CustomEvent('space-gib-branch-requested', {
|
|
525
|
+
detail: {
|
|
526
|
+
galaxyName,
|
|
527
|
+
sourceBranch: branchName,
|
|
528
|
+
newBranchName: cleanBranchName,
|
|
529
|
+
scope: 'branch',
|
|
530
|
+
},
|
|
531
|
+
bubbles: true,
|
|
532
|
+
composed: true,
|
|
533
|
+
}));
|
|
506
534
|
});
|
|
507
535
|
});
|
|
508
536
|
}
|
|
@@ -18,6 +18,65 @@
|
|
|
18
18
|
height: 100%;
|
|
19
19
|
min-height: 0;
|
|
20
20
|
overflow: hidden;
|
|
21
|
+
position: relative;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
border: 2px solid var(--branch-accent-color, rgba(255, 255, 255, 0.08));
|
|
24
|
+
box-shadow: inset 0 0 16px var(--branch-accent-translucent, rgba(0, 0, 0, 0.2));
|
|
25
|
+
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* โโ Empty Placeholder View โโ */
|
|
29
|
+
.editor-empty-placeholder {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 100%;
|
|
36
|
+
color: var(--clr-text-muted, #7e8c9f);
|
|
37
|
+
text-align: center;
|
|
38
|
+
padding: 2.5rem;
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.editor-empty-placeholder .empty-icon {
|
|
43
|
+
font-size: 3.5rem;
|
|
44
|
+
margin-bottom: 1.25rem;
|
|
45
|
+
opacity: 0.4;
|
|
46
|
+
filter: drop-shadow(0 0 12px rgba(124, 92, 252, 0.2));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.editor-empty-placeholder .empty-title {
|
|
50
|
+
font-size: 1.35rem;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
color: var(--clr-text-primary, #f0f4fc);
|
|
53
|
+
margin-bottom: 0.6rem;
|
|
54
|
+
letter-spacing: -0.01em;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.editor-empty-placeholder .empty-desc {
|
|
58
|
+
font-size: 0.95rem;
|
|
59
|
+
max-width: 420px;
|
|
60
|
+
line-height: 1.6;
|
|
61
|
+
color: var(--clr-text-muted, #8b949e);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.editor-empty-placeholder .highlight {
|
|
65
|
+
color: var(--clr-accent, #78f87e);
|
|
66
|
+
font-weight: 600;
|
|
67
|
+
padding: 0.15rem 0.4rem;
|
|
68
|
+
background: rgba(120, 248, 126, 0.12);
|
|
69
|
+
border: 1px solid rgba(120, 248, 126, 0.25);
|
|
70
|
+
border-radius: 4px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.editor-main-container {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
width: 100%;
|
|
77
|
+
height: 100%;
|
|
78
|
+
min-height: 0;
|
|
79
|
+
overflow: hidden;
|
|
21
80
|
}
|
|
22
81
|
|
|
23
82
|
/* โโ Integrated Header (File Breadcrumb + Virtual Tip + Actions) โโ */
|
|
@@ -74,38 +133,40 @@
|
|
|
74
133
|
display: inline-flex;
|
|
75
134
|
align-items: center;
|
|
76
135
|
gap: 0.35rem;
|
|
77
|
-
background: rgba(124, 92, 252, 0.12);
|
|
78
|
-
border: 1px solid rgba(124, 92, 252, 0.35);
|
|
136
|
+
background: var(--branch-accent-translucent, rgba(124, 92, 252, 0.12));
|
|
137
|
+
border: 1px solid var(--branch-accent-color, rgba(124, 92, 252, 0.35));
|
|
79
138
|
border-radius: var(--radius-sm, 6px);
|
|
80
139
|
padding: 0.2rem 0.55rem;
|
|
81
140
|
font-size: 0.775rem;
|
|
82
141
|
font-family: var(--font-mono, monospace);
|
|
83
|
-
color: #c4b5fd;
|
|
142
|
+
color: var(--branch-accent-color, #c4b5fd);
|
|
84
143
|
user-select: none;
|
|
85
144
|
transition: all 150ms ease;
|
|
86
145
|
}
|
|
87
146
|
|
|
88
147
|
.tip-virtual-breadcrumb:hover {
|
|
89
|
-
background: rgba(124, 92, 252, 0.2);
|
|
90
|
-
border-color: rgba(124, 92, 252, 0.6);
|
|
91
|
-
box-shadow: 0 0 10px rgba(124, 92, 252, 0.25);
|
|
148
|
+
background: var(--branch-accent-translucent, rgba(124, 92, 252, 0.2));
|
|
149
|
+
border-color: var(--branch-accent-color, rgba(124, 92, 252, 0.6));
|
|
150
|
+
box-shadow: 0 0 10px var(--branch-accent-translucent, rgba(124, 92, 252, 0.25));
|
|
92
151
|
}
|
|
93
152
|
|
|
94
153
|
.tip-sep {
|
|
95
|
-
color: rgba(196, 181, 253, 0.5);
|
|
154
|
+
color: var(--branch-accent-color, rgba(196, 181, 253, 0.5));
|
|
155
|
+
opacity: 0.7;
|
|
96
156
|
}
|
|
97
157
|
|
|
98
158
|
.tip-icon {
|
|
99
159
|
font-size: 0.8rem;
|
|
160
|
+
color: var(--branch-accent-color, #a78bfa);
|
|
100
161
|
}
|
|
101
162
|
|
|
102
163
|
.tip-branch {
|
|
103
|
-
color: #
|
|
164
|
+
color: #ffffff;
|
|
104
165
|
font-weight: 600;
|
|
105
166
|
}
|
|
106
167
|
|
|
107
168
|
.tip-hash {
|
|
108
|
-
color: #a78bfa;
|
|
169
|
+
color: var(--branch-accent-color, #a78bfa);
|
|
109
170
|
font-weight: 700;
|
|
110
171
|
letter-spacing: 0.02em;
|
|
111
172
|
}
|
|
@@ -181,6 +242,27 @@
|
|
|
181
242
|
border-color: rgba(120, 248, 126, 0.7);
|
|
182
243
|
}
|
|
183
244
|
|
|
245
|
+
.mode-toggle-btn.saving {
|
|
246
|
+
border-color: rgba(120, 248, 126, 0.6);
|
|
247
|
+
color: #78f87e;
|
|
248
|
+
background: rgba(120, 248, 126, 0.12);
|
|
249
|
+
box-shadow: 0 0 8px rgba(120, 248, 126, 0.2);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.mode-toggle-btn .save-spinner {
|
|
253
|
+
width: 10px;
|
|
254
|
+
height: 10px;
|
|
255
|
+
border: 1.5px solid rgba(120, 248, 126, 0.3);
|
|
256
|
+
border-top-color: var(--clr-accent, #78f87e);
|
|
257
|
+
border-radius: 50%;
|
|
258
|
+
animation: save-spin 0.6s linear infinite;
|
|
259
|
+
flex-shrink: 0;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@keyframes save-spin {
|
|
263
|
+
to { transform: rotate(360deg); }
|
|
264
|
+
}
|
|
265
|
+
|
|
184
266
|
.action-btn {
|
|
185
267
|
display: inline-flex;
|
|
186
268
|
align-items: center;
|
|
@@ -1,54 +1,67 @@
|
|
|
1
1
|
<div class="editor-root" id="editor-root">
|
|
2
|
-
<!--
|
|
3
|
-
<
|
|
4
|
-
<div class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<span class="crumb-sep">/</span>
|
|
9
|
-
<span class="crumb-path" id="crumb-path">src/index.ts</span>
|
|
10
|
-
</div>
|
|
11
|
-
|
|
12
|
-
<!-- Secondary Virtual Breadcrumb: Active Branch & Tip Merkle Hash -->
|
|
13
|
-
<div class="tip-virtual-breadcrumb" id="crumb-tip-container" title="Active Branch Tip Merkle Address">
|
|
14
|
-
<span class="tip-sep">@</span>
|
|
15
|
-
<span class="tip-icon">๐ฟ</span>
|
|
16
|
-
<span class="tip-branch" id="crumb-branch">main</span>
|
|
17
|
-
<span class="tip-hash" id="crumb-tip">7f8a1b2</span>
|
|
18
|
-
</div>
|
|
2
|
+
<!-- Empty placeholder when no file is loaded -->
|
|
3
|
+
<div class="editor-empty-placeholder" id="editor-empty-placeholder" style="display: none;">
|
|
4
|
+
<div class="empty-icon">๐</div>
|
|
5
|
+
<div class="empty-title">No file open</div>
|
|
6
|
+
<div class="empty-desc">
|
|
7
|
+
Select a file from the explorer on the left, or click <span class="highlight">๐+</span> to create a file.
|
|
19
8
|
</div>
|
|
9
|
+
</div>
|
|
20
10
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
11
|
+
<!-- Main editor container -->
|
|
12
|
+
<div class="editor-main-container" id="editor-main-container">
|
|
13
|
+
<!-- Combined File View Header & Virtual Breadcrumb -->
|
|
14
|
+
<header class="editor-header" id="editor-header">
|
|
15
|
+
<div class="header-left">
|
|
16
|
+
<div class="file-breadcrumb">
|
|
17
|
+
<span class="crumb-icon">๐</span>
|
|
18
|
+
<span class="crumb-repo" id="crumb-repo"></span>
|
|
19
|
+
<span class="crumb-sep">/</span>
|
|
20
|
+
<span class="crumb-path" id="crumb-path"></span>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<!-- Secondary Virtual Breadcrumb: Active Branch & Tip Merkle Hash -->
|
|
24
|
+
<div class="tip-virtual-breadcrumb" id="crumb-tip-container" title="Active Branch Tip Merkle Address">
|
|
25
|
+
<span class="tip-sep">@</span>
|
|
26
|
+
<span class="tip-icon">๐ฟ</span>
|
|
27
|
+
<span class="tip-branch" id="crumb-branch">main</span>
|
|
28
|
+
<span class="tip-hash" id="crumb-tip"></span>
|
|
29
|
+
</div>
|
|
28
30
|
</div>
|
|
29
31
|
|
|
30
|
-
<div class="header-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<span class="
|
|
34
|
-
<span class="
|
|
35
|
-
|
|
32
|
+
<div class="header-right">
|
|
33
|
+
<div class="editor-stats">
|
|
34
|
+
<span class="stat-badge" id="stat-lang"></span>
|
|
35
|
+
<span class="stat-sep">ยท</span>
|
|
36
|
+
<span class="stat-badge" id="stat-lines">0 lines</span>
|
|
37
|
+
<span class="stat-sep">ยท</span>
|
|
38
|
+
<span class="stat-badge" id="stat-size">0 B</span>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="header-actions">
|
|
42
|
+
<!-- Read-Only / Editable Mode Toggle & Save Status -->
|
|
43
|
+
<button id="btn-toggle-readonly" class="mode-toggle-btn" type="button" title="Toggle Read-Only / Editable Mode">
|
|
44
|
+
<span class="save-spinner" id="btn-save-spinner" style="display: none;"></span>
|
|
45
|
+
<span class="mode-icon" id="mode-icon">๐</span>
|
|
46
|
+
<span class="mode-text" id="mode-text">Read-Only</span>
|
|
47
|
+
</button>
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
<!-- Copy Code Action -->
|
|
50
|
+
<button id="btn-copy-code" class="action-btn" type="button" title="Copy code to clipboard">
|
|
51
|
+
<span class="btn-icon">๐</span>
|
|
52
|
+
</button>
|
|
53
|
+
</div>
|
|
41
54
|
</div>
|
|
42
|
-
</
|
|
43
|
-
</header>
|
|
55
|
+
</header>
|
|
44
56
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
<!-- Single Editor Body (Gutter + Code Textarea) -->
|
|
58
|
+
<main class="editor-body" id="editor-body">
|
|
59
|
+
<div class="editor-gutter" id="editor-gutter" aria-hidden="true">
|
|
60
|
+
<span class="line-num">1</span>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="editor-content-wrapper">
|
|
63
|
+
<textarea id="editor-textarea" class="editor-textarea" spellcheck="false" autocomplete="off" autocapitalize="off" wrap="off" placeholder="Write code here..."></textarea>
|
|
64
|
+
</div>
|
|
65
|
+
</main>
|
|
66
|
+
</div>
|
|
54
67
|
</div>
|