@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,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tutorial.css — Styles for the Space-Gib Interactive Tutorial & Spotlight Tour
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
.tutorial-overlay-container {
|
|
6
|
+
position: fixed;
|
|
7
|
+
inset: 0;
|
|
8
|
+
z-index: 10000;
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
transition: opacity 0.3s ease;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Semi-transparent dimmer backdrop */
|
|
14
|
+
.tutorial-backdrop {
|
|
15
|
+
position: absolute;
|
|
16
|
+
inset: 0;
|
|
17
|
+
background: rgba(8, 10, 15, 0.75);
|
|
18
|
+
backdrop-filter: blur(3px);
|
|
19
|
+
-webkit-backdrop-filter: blur(3px);
|
|
20
|
+
pointer-events: auto;
|
|
21
|
+
transition: clip-path 0.35s cubic-bezier(0.2, 0.9, 0.3, 1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Glowing spotlight ring around the active target */
|
|
25
|
+
.tutorial-spotlight-ring {
|
|
26
|
+
position: absolute;
|
|
27
|
+
border-radius: 8px;
|
|
28
|
+
box-shadow: 0 0 0 4px rgba(255, 204, 0, 0.6),
|
|
29
|
+
0 0 25px 6px rgba(255, 180, 0, 0.4),
|
|
30
|
+
inset 0 0 15px rgba(255, 204, 0, 0.2);
|
|
31
|
+
pointer-events: none;
|
|
32
|
+
transition: top 0.35s cubic-bezier(0.2, 0.9, 0.3, 1),
|
|
33
|
+
left 0.35s cubic-bezier(0.2, 0.9, 0.3, 1),
|
|
34
|
+
width 0.35s cubic-bezier(0.2, 0.9, 0.3, 1),
|
|
35
|
+
height 0.35s cubic-bezier(0.2, 0.9, 0.3, 1);
|
|
36
|
+
z-index: 10001;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Movable Golden Beacon Button */
|
|
40
|
+
.tutorial-beacon {
|
|
41
|
+
position: absolute;
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: 8px;
|
|
45
|
+
padding: 8px 18px;
|
|
46
|
+
background: linear-gradient(135deg, #ffd700 0%, #ff9900 100%);
|
|
47
|
+
color: #121212;
|
|
48
|
+
font-family: inherit;
|
|
49
|
+
font-size: 0.95rem;
|
|
50
|
+
font-weight: 700;
|
|
51
|
+
border: 2px solid rgba(255, 255, 255, 0.8);
|
|
52
|
+
border-radius: 9999px;
|
|
53
|
+
box-shadow: 0 4px 20px rgba(255, 180, 0, 0.65), 0 0 30px rgba(255, 215, 0, 0.4);
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
pointer-events: auto;
|
|
56
|
+
z-index: 10002;
|
|
57
|
+
transition: top 0.35s cubic-bezier(0.2, 0.9, 0.3, 1),
|
|
58
|
+
left 0.35s cubic-bezier(0.2, 0.9, 0.3, 1),
|
|
59
|
+
transform 0.2s ease,
|
|
60
|
+
box-shadow 0.2s ease;
|
|
61
|
+
animation: beacon-pulse 2s infinite ease-in-out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.tutorial-beacon:hover {
|
|
65
|
+
transform: scale(1.06);
|
|
66
|
+
box-shadow: 0 6px 28px rgba(255, 190, 0, 0.85), 0 0 40px rgba(255, 230, 100, 0.6);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.tutorial-beacon:active {
|
|
70
|
+
transform: scale(0.96);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.tutorial-beacon-icon {
|
|
74
|
+
font-size: 1.15rem;
|
|
75
|
+
line-height: 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.tutorial-beacon-text {
|
|
79
|
+
letter-spacing: 0.02em;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@keyframes beacon-pulse {
|
|
83
|
+
0%, 100% {
|
|
84
|
+
box-shadow: 0 4px 20px rgba(255, 180, 0, 0.65), 0 0 15px rgba(255, 215, 0, 0.4);
|
|
85
|
+
}
|
|
86
|
+
50% {
|
|
87
|
+
box-shadow: 0 4px 30px rgba(255, 200, 0, 0.9), 0 0 35px rgba(255, 230, 50, 0.7);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Floating Glassmorphic Narration Card */
|
|
92
|
+
.tutorial-card {
|
|
93
|
+
position: absolute;
|
|
94
|
+
width: 440px;
|
|
95
|
+
max-width: calc(100vw - 32px);
|
|
96
|
+
background: rgba(18, 22, 34, 0.88);
|
|
97
|
+
backdrop-filter: blur(16px);
|
|
98
|
+
-webkit-backdrop-filter: blur(16px);
|
|
99
|
+
border: 1px solid rgba(255, 215, 0, 0.25);
|
|
100
|
+
border-radius: 14px;
|
|
101
|
+
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.6), 0 0 20px rgba(255, 200, 0, 0.15);
|
|
102
|
+
padding: 22px 24px;
|
|
103
|
+
color: #e2e8f0;
|
|
104
|
+
pointer-events: auto;
|
|
105
|
+
z-index: 10002;
|
|
106
|
+
transition: top 0.35s cubic-bezier(0.2, 0.9, 0.3, 1),
|
|
107
|
+
left 0.35s cubic-bezier(0.2, 0.9, 0.3, 1),
|
|
108
|
+
opacity 0.25s ease;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.tutorial-card.placement-center {
|
|
112
|
+
top: 50% !important;
|
|
113
|
+
left: 50% !important;
|
|
114
|
+
transform: translate(-50%, -50%);
|
|
115
|
+
width: 580px;
|
|
116
|
+
border-color: rgba(255, 215, 0, 0.45);
|
|
117
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.8), 0 0 40px rgba(255, 200, 0, 0.25);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.tutorial-card-header {
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: space-between;
|
|
124
|
+
margin-bottom: 12px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.tutorial-step-badge {
|
|
128
|
+
font-size: 0.75rem;
|
|
129
|
+
font-weight: 700;
|
|
130
|
+
text-transform: uppercase;
|
|
131
|
+
letter-spacing: 0.08em;
|
|
132
|
+
color: #ffd700;
|
|
133
|
+
background: rgba(255, 215, 0, 0.12);
|
|
134
|
+
padding: 4px 10px;
|
|
135
|
+
border-radius: 9999px;
|
|
136
|
+
border: 1px solid rgba(255, 215, 0, 0.3);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.tutorial-card-close {
|
|
140
|
+
background: none;
|
|
141
|
+
border: none;
|
|
142
|
+
color: #94a3b8;
|
|
143
|
+
font-size: 1.25rem;
|
|
144
|
+
cursor: pointer;
|
|
145
|
+
padding: 4px 8px;
|
|
146
|
+
border-radius: 6px;
|
|
147
|
+
transition: color 0.15s ease, background 0.15s ease;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.tutorial-card-close:hover {
|
|
151
|
+
color: #ffffff;
|
|
152
|
+
background: rgba(255, 255, 255, 0.1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.tutorial-card-title {
|
|
156
|
+
margin: 0 0 12px 0;
|
|
157
|
+
font-size: 1.2rem;
|
|
158
|
+
font-weight: 700;
|
|
159
|
+
color: #ffffff;
|
|
160
|
+
line-height: 1.35;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.tutorial-card-body {
|
|
164
|
+
font-size: 0.92rem;
|
|
165
|
+
line-height: 1.6;
|
|
166
|
+
color: #cbd5e1;
|
|
167
|
+
margin-bottom: 20px;
|
|
168
|
+
max-height: 55vh;
|
|
169
|
+
overflow-y: auto;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.tutorial-card-body p {
|
|
173
|
+
margin: 0 0 10px 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.tutorial-card-body p:last-child {
|
|
177
|
+
margin-bottom: 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.tutorial-card-body strong {
|
|
181
|
+
color: #f8fafc;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.tutorial-card-body em {
|
|
185
|
+
color: #ffd700;
|
|
186
|
+
font-style: normal;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.tutorial-card-footer {
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: space-between;
|
|
193
|
+
padding-top: 14px;
|
|
194
|
+
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.tutorial-progress-dots {
|
|
198
|
+
display: flex;
|
|
199
|
+
gap: 6px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.tutorial-dot {
|
|
203
|
+
width: 8px;
|
|
204
|
+
height: 8px;
|
|
205
|
+
border-radius: 9999px;
|
|
206
|
+
background: rgba(255, 255, 255, 0.2);
|
|
207
|
+
transition: background 0.25s ease, transform 0.25s ease;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.tutorial-dot.active {
|
|
211
|
+
background: #ffd700;
|
|
212
|
+
transform: scale(1.25);
|
|
213
|
+
box-shadow: 0 0 8px #ffd700;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.tutorial-card-actions {
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
gap: 10px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.tutorial-btn-skip {
|
|
223
|
+
background: none;
|
|
224
|
+
border: none;
|
|
225
|
+
color: #94a3b8;
|
|
226
|
+
font-size: 0.85rem;
|
|
227
|
+
cursor: pointer;
|
|
228
|
+
padding: 6px 12px;
|
|
229
|
+
border-radius: 6px;
|
|
230
|
+
transition: color 0.15s ease;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.tutorial-btn-skip:hover {
|
|
234
|
+
color: #ffffff;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.tutorial-btn-next {
|
|
238
|
+
display: inline-flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
gap: 6px;
|
|
241
|
+
background: linear-gradient(135deg, #ffd700 0%, #ffaa00 100%);
|
|
242
|
+
color: #0f172a;
|
|
243
|
+
font-weight: 700;
|
|
244
|
+
font-size: 0.9rem;
|
|
245
|
+
padding: 8px 18px;
|
|
246
|
+
border: none;
|
|
247
|
+
border-radius: 8px;
|
|
248
|
+
cursor: pointer;
|
|
249
|
+
box-shadow: 0 4px 14px rgba(255, 180, 0, 0.4);
|
|
250
|
+
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.tutorial-btn-next:hover {
|
|
254
|
+
transform: translateY(-1px);
|
|
255
|
+
box-shadow: 0 6px 20px rgba(255, 180, 0, 0.6);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.tutorial-btn-next:active {
|
|
259
|
+
transform: translateY(1px);
|
|
260
|
+
}
|
|
@@ -2,199 +2,50 @@
|
|
|
2
2
|
* @module client/ui/router/space-gib-router-helpers
|
|
3
3
|
*
|
|
4
4
|
* Route parsing and formatting helpers for the Space-Gib Client Router.
|
|
5
|
-
*
|
|
5
|
+
* Delegates universal Cosmos & Galaxy routes to @ibgib/web-gib,
|
|
6
|
+
* while handling space-gib specific routes (/admin/review).
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
|
-
|
|
10
|
+
parseCosmosRoute,
|
|
11
|
+
formatCosmosRoute,
|
|
12
|
+
isSameCosmosRoute,
|
|
13
|
+
safeDecode,
|
|
14
|
+
ParseCosmosRouteOptions,
|
|
15
|
+
CosmosRouteInfo,
|
|
16
|
+
} from '@ibgib/web-gib/dist/ui/router/index.mjs';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
SpaceGibRouteInfo,
|
|
20
|
+
AdminReviewRouteInfo,
|
|
10
21
|
} from './space-gib-router-types.mjs';
|
|
11
22
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*/
|
|
15
|
-
function safeDecode(str: string): string {
|
|
16
|
-
try {
|
|
17
|
-
return decodeURIComponent(str);
|
|
18
|
-
} catch {
|
|
19
|
-
return str;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
23
|
+
export { safeDecode };
|
|
24
|
+
export type ParseSpaceGibRouteOptions = ParseCosmosRouteOptions;
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* Parses a browser pathname into a structured SpaceGibRouteInfo.
|
|
25
|
-
*
|
|
26
|
-
* Supports:
|
|
27
|
-
* - Polycosmos: / or /polycosmos or /@:siteUsername or /keystone/:keystoneTjp
|
|
28
|
-
* - Cosmos: /:cosmos or /@:siteUsername/:cosmos or /keystone/:keystoneTjp/:cosmos
|
|
29
|
-
* - Code Galaxy: /:cosmos/code/:galaxyId[/:branch[/*filePath]]
|
|
30
|
-
* - Notes Galaxy: /:cosmos/notes/:galaxyId[/:topicTjp]
|
|
31
|
-
* - Raw Addr (Snapshot): /:cosmos/:spaceId/addr/:ibGibAddr
|
|
32
|
-
* - Raw Tjp (Living Tip): /:cosmos/:spaceId/tjp/:tjpAddr
|
|
33
|
-
* - Admin Review: /admin/review[/:tjpGib]
|
|
28
|
+
* Handles /admin/review explicitly, and delegates all Cosmos / Galaxy / Raw routes to @ibgib/web-gib.
|
|
34
29
|
*/
|
|
35
|
-
export function parseSpaceGibRoute(pathname: string): SpaceGibRouteInfo {
|
|
30
|
+
export function parseSpaceGibRoute(pathname: string, opts?: ParseSpaceGibRouteOptions): SpaceGibRouteInfo {
|
|
36
31
|
let p = (pathname || '').trim();
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const q: Record<string, string> = {};
|
|
45
|
-
searchParams.forEach((val, key) => {
|
|
46
|
-
q[key] = val;
|
|
47
|
-
});
|
|
48
|
-
if (Object.keys(q).length > 0) {
|
|
49
|
-
queryObj = q;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
const hIdx = p.indexOf('#');
|
|
53
|
-
if (hIdx !== -1) { p = p.substring(0, hIdx); }
|
|
33
|
+
// Check query string/hash for /admin/review prefix
|
|
34
|
+
let cleanPath = p;
|
|
35
|
+
const qIdx = cleanPath.indexOf('?');
|
|
36
|
+
if (qIdx !== -1) { cleanPath = cleanPath.substring(0, qIdx); }
|
|
37
|
+
const hIdx = cleanPath.indexOf('#');
|
|
38
|
+
if (hIdx !== -1) { cleanPath = cleanPath.substring(0, hIdx); }
|
|
54
39
|
|
|
55
|
-
if (
|
|
56
|
-
return { kind: 'polycosmos' };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Special Route: /admin/review
|
|
60
|
-
if (p === '/admin/review') {
|
|
40
|
+
if (cleanPath === '/admin/review') {
|
|
61
41
|
return { kind: 'admin-review' };
|
|
62
42
|
}
|
|
63
|
-
if (
|
|
64
|
-
const tjpGib = safeDecode(
|
|
43
|
+
if (cleanPath.startsWith('/admin/review/')) {
|
|
44
|
+
const tjpGib = safeDecode(cleanPath.slice('/admin/review/'.length)).trim();
|
|
65
45
|
return { kind: 'admin-review', ...(tjpGib ? { tjpGib } : {}) };
|
|
66
46
|
}
|
|
67
47
|
|
|
68
|
-
|
|
69
|
-
if (rawSegments.length === 0) {
|
|
70
|
-
return { kind: 'polycosmos' };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Extract tenant prefix if present (@username or /keystone/tjp)
|
|
74
|
-
let tenant: SpaceGibTenant | undefined;
|
|
75
|
-
let segIdx = 0;
|
|
76
|
-
|
|
77
|
-
if (rawSegments[0].startsWith('@')) {
|
|
78
|
-
const username = safeDecode(rawSegments[0].slice(1)).trim();
|
|
79
|
-
if (username) {
|
|
80
|
-
tenant = { type: 'username', siteUsername: username };
|
|
81
|
-
segIdx = 1;
|
|
82
|
-
}
|
|
83
|
-
} else if (rawSegments[0] === 'keystone' && rawSegments.length > 1) {
|
|
84
|
-
const keystoneTjp = safeDecode(rawSegments[1]).trim();
|
|
85
|
-
if (keystoneTjp) {
|
|
86
|
-
tenant = { type: 'keystone', keystoneTjp };
|
|
87
|
-
segIdx = 2;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const remaining = rawSegments.slice(segIdx);
|
|
92
|
-
|
|
93
|
-
// If only tenant specifier was given (e.g. /@bill or /keystone/tjp123)
|
|
94
|
-
if (remaining.length === 0) {
|
|
95
|
-
return { kind: 'polycosmos', ...(tenant ? { tenant } : {}) };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (remaining.length === 1 && remaining[0] === 'polycosmos') {
|
|
99
|
-
return { kind: 'polycosmos', ...(tenant ? { tenant } : {}) };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const cosmos = safeDecode(remaining[0]).trim();
|
|
103
|
-
|
|
104
|
-
if (remaining.length === 1) {
|
|
105
|
-
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const second = safeDecode(remaining[1]).trim();
|
|
109
|
-
|
|
110
|
-
// Code Galaxy: /:cosmos/code/:galaxyId[/:branch[/*filePath]]
|
|
111
|
-
if (second === 'code') {
|
|
112
|
-
const galaxyId = remaining[2] ? safeDecode(remaining[2]).trim() : '';
|
|
113
|
-
if (!galaxyId) {
|
|
114
|
-
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
115
|
-
}
|
|
116
|
-
const branch = remaining[3] ? safeDecode(remaining[3]).trim() : undefined;
|
|
117
|
-
const filePath = remaining.length > 4 ? remaining.slice(4).map(safeDecode).join('/') : undefined;
|
|
118
|
-
return {
|
|
119
|
-
kind: 'code-galaxy',
|
|
120
|
-
...(tenant ? { tenant } : {}),
|
|
121
|
-
cosmos,
|
|
122
|
-
galaxyId,
|
|
123
|
-
...(branch ? { branch } : {}),
|
|
124
|
-
...(filePath ? { filePath } : {}),
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Notes Galaxy: /:cosmos/notes/:galaxyId[/tjp/:tjp1/:tjp2...] or [/addr/:addr1/:addr2...] or [/:topicTjp]
|
|
129
|
-
if (second === 'notes') {
|
|
130
|
-
const galaxyId = remaining[2] ? safeDecode(remaining[2]).trim() : '';
|
|
131
|
-
if (!galaxyId) {
|
|
132
|
-
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
let trailMode: 'tjp' | 'addr' | undefined;
|
|
136
|
-
let trail: string[] | undefined;
|
|
137
|
-
let topicTjp: string | undefined;
|
|
138
|
-
|
|
139
|
-
if (remaining.length > 3) {
|
|
140
|
-
const modeCandidate = safeDecode(remaining[3]).trim();
|
|
141
|
-
if (modeCandidate === 'tjp' || modeCandidate === 'addr') {
|
|
142
|
-
trailMode = modeCandidate;
|
|
143
|
-
const trailSegments = remaining.slice(4).map(s => safeDecode(s).trim()).filter(s => s.length > 0);
|
|
144
|
-
if (trailSegments.length > 0) {
|
|
145
|
-
trail = trailSegments;
|
|
146
|
-
topicTjp = trailSegments[0];
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
// Backward compatibility / shorthand: /notes/:galaxyId/:topicTjp
|
|
150
|
-
topicTjp = modeCandidate;
|
|
151
|
-
trailMode = 'tjp';
|
|
152
|
-
trail = [modeCandidate];
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
kind: 'notes-galaxy',
|
|
158
|
-
...(tenant ? { tenant } : {}),
|
|
159
|
-
cosmos,
|
|
160
|
-
galaxyId,
|
|
161
|
-
...(trailMode ? { trailMode } : {}),
|
|
162
|
-
...(trail ? { trail } : {}),
|
|
163
|
-
...(topicTjp ? { topicTjp } : {}),
|
|
164
|
-
...(queryObj ? { query: queryObj } : {}),
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Mechanism 1: Space-Qualified Raw Addrs
|
|
169
|
-
// /:cosmos/:spaceId/addr/:ibGibAddr
|
|
170
|
-
// /:cosmos/:spaceId/tjp/:tjpAddr
|
|
171
|
-
if (remaining.length >= 4) {
|
|
172
|
-
const third = safeDecode(remaining[2]).trim();
|
|
173
|
-
const spaceId = second;
|
|
174
|
-
if (third === 'addr') {
|
|
175
|
-
const ibGibAddr = safeDecode(remaining.slice(3).join('/')).trim();
|
|
176
|
-
return {
|
|
177
|
-
kind: 'raw-addr',
|
|
178
|
-
...(tenant ? { tenant } : {}),
|
|
179
|
-
cosmos,
|
|
180
|
-
spaceId,
|
|
181
|
-
ibGibAddr,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
if (third === 'tjp') {
|
|
185
|
-
const tjpAddr = safeDecode(remaining.slice(3).join('/')).trim();
|
|
186
|
-
return {
|
|
187
|
-
kind: 'raw-tjp',
|
|
188
|
-
...(tenant ? { tenant } : {}),
|
|
189
|
-
cosmos,
|
|
190
|
-
spaceId,
|
|
191
|
-
tjpAddr,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Fallback: Cosmos route
|
|
197
|
-
return { kind: 'cosmos', ...(tenant ? { tenant } : {}), cosmos };
|
|
48
|
+
return parseCosmosRoute(pathname, opts) as SpaceGibRouteInfo;
|
|
198
49
|
}
|
|
199
50
|
|
|
200
51
|
/**
|
|
@@ -204,62 +55,7 @@ export function formatSpaceGibRoute(route: SpaceGibRouteInfo): string {
|
|
|
204
55
|
if (route.kind === 'admin-review') {
|
|
205
56
|
return `/admin/review${route.tjpGib ? `/${encodeURIComponent(route.tjpGib)}` : ''}`;
|
|
206
57
|
}
|
|
207
|
-
|
|
208
|
-
let prefix = '';
|
|
209
|
-
if (route.tenant) {
|
|
210
|
-
if (route.tenant.type === 'username') {
|
|
211
|
-
prefix = `/@${encodeURIComponent(route.tenant.siteUsername)}`;
|
|
212
|
-
} else if (route.tenant.type === 'keystone') {
|
|
213
|
-
prefix = `/keystone/${encodeURIComponent(route.tenant.keystoneTjp)}`;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
switch (route.kind) {
|
|
218
|
-
case 'polycosmos':
|
|
219
|
-
return prefix ? `${prefix}/polycosmos` : '/';
|
|
220
|
-
|
|
221
|
-
case 'cosmos':
|
|
222
|
-
return `${prefix}/${encodeURIComponent(route.cosmos)}`;
|
|
223
|
-
|
|
224
|
-
case 'code-galaxy': {
|
|
225
|
-
let res = `${prefix}/${encodeURIComponent(route.cosmos)}/code/${encodeURIComponent(route.galaxyId)}`;
|
|
226
|
-
if (route.branch) {
|
|
227
|
-
res += `/${encodeURIComponent(route.branch)}`;
|
|
228
|
-
if (route.filePath) {
|
|
229
|
-
res += `/${route.filePath.split('/').map(encodeURIComponent).join('/')}`;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return res;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
case 'notes-galaxy': {
|
|
236
|
-
let res = `${prefix}/${encodeURIComponent(route.cosmos)}/notes/${encodeURIComponent(route.galaxyId)}`;
|
|
237
|
-
if (route.trail && route.trail.length > 0) {
|
|
238
|
-
const mode = route.trailMode || 'tjp';
|
|
239
|
-
res += `/${mode}/${route.trail.map(encodeURIComponent).join('/')}`;
|
|
240
|
-
} else if (route.topicTjp) {
|
|
241
|
-
res += `/${encodeURIComponent(route.topicTjp)}`;
|
|
242
|
-
}
|
|
243
|
-
if (route.query && Object.keys(route.query).length > 0) {
|
|
244
|
-
const sp = new URLSearchParams();
|
|
245
|
-
for (const [k, v] of Object.entries(route.query)) {
|
|
246
|
-
if (v !== undefined) { sp.set(k, v); }
|
|
247
|
-
}
|
|
248
|
-
const qs = sp.toString();
|
|
249
|
-
if (qs) { res += `?${qs}`; }
|
|
250
|
-
}
|
|
251
|
-
return res;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
case 'raw-addr':
|
|
255
|
-
return `${prefix}/${encodeURIComponent(route.cosmos)}/${encodeURIComponent(route.spaceId)}/addr/${encodeURIComponent(route.ibGibAddr)}`;
|
|
256
|
-
|
|
257
|
-
case 'raw-tjp':
|
|
258
|
-
return `${prefix}/${encodeURIComponent(route.cosmos)}/${encodeURIComponent(route.spaceId)}/tjp/${encodeURIComponent(route.tjpAddr)}`;
|
|
259
|
-
|
|
260
|
-
default:
|
|
261
|
-
return '/';
|
|
262
|
-
}
|
|
58
|
+
return formatCosmosRoute(route as CosmosRouteInfo);
|
|
263
59
|
}
|
|
264
60
|
|
|
265
61
|
/**
|
|
@@ -268,5 +64,9 @@ export function formatSpaceGibRoute(route: SpaceGibRouteInfo): string {
|
|
|
268
64
|
export function isSameRoute(a?: SpaceGibRouteInfo, b?: SpaceGibRouteInfo): boolean {
|
|
269
65
|
if (!a && !b) { return true; }
|
|
270
66
|
if (!a || !b) { return false; }
|
|
271
|
-
|
|
67
|
+
if (a.kind === 'admin-review' || b.kind === 'admin-review') {
|
|
68
|
+
if (a.kind !== b.kind) { return false; }
|
|
69
|
+
return (a as AdminReviewRouteInfo).tjpGib === (b as AdminReviewRouteInfo).tjpGib;
|
|
70
|
+
}
|
|
71
|
+
return isSameCosmosRoute(a as CosmosRouteInfo, b as CosmosRouteInfo);
|
|
272
72
|
}
|