-9
README.md
-9
README.md
+20
-1
app.js
+20
-1
app.js
···
2
2
document.addEventListener("alpine:init", () => {
3
3
Alpine.data("app", () => ({
4
4
// State
5
-
serverUrl: window.location.origin,
5
+
darkTheme: localStorage.getItem("darkTheme") !== "false",
6
+
serverUrl: "https://knot.srv.rbrt.fr",
6
7
isConnected: false,
7
8
status: {
8
9
message: "",
···
34
35
35
36
// Initialization
36
37
init() {
38
+
// Apply saved theme
39
+
this.applyTheme();
40
+
37
41
// Make this component globally accessible for onclick handlers
38
42
window.appInstance = this;
39
43
···
65
69
66
70
// Restore from URL on load
67
71
this.restoreFromURL();
72
+
},
73
+
74
+
// Theme
75
+
toggleTheme() {
76
+
this.darkTheme = !this.darkTheme;
77
+
localStorage.setItem("darkTheme", this.darkTheme);
78
+
this.applyTheme();
79
+
},
80
+
81
+
applyTheme() {
82
+
if (this.darkTheme) {
83
+
document.body.classList.add("dark-theme");
84
+
} else {
85
+
document.body.classList.remove("dark-theme");
86
+
}
68
87
},
69
88
70
89
// Connection
+70
-6
index.html
+70
-6
index.html
···
22
22
<body>
23
23
<div class="container" x-data="app" x-init="init()">
24
24
<header>
25
-
<h1>KnotView</h1>
25
+
<div class="header-top">
26
+
<h1>KnotView</h1>
27
+
<button class="theme-toggle" @click="toggleTheme">
28
+
<span x-show="!darkTheme">๐</span>
29
+
<span x-show="darkTheme">โ๏ธ</span>
30
+
<span x-text="darkTheme ? 'Light' : 'Dark'"></span>
31
+
</button>
32
+
</div>
26
33
<div class="connection-panel">
27
34
<input
28
35
type="text"
···
129
136
<!-- Empty State -->
130
137
<div
131
138
x-show="!loading && !error && !state.currentRepo && view === 'empty'"
132
-
class="empty-state"
139
+
class="welcome-hero"
133
140
>
134
141
<svg
135
142
xmlns="http://www.w3.org/2000/svg"
···
144
151
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
145
152
/>
146
153
</svg>
147
-
<h3>No Repository Selected</h3>
148
-
<p>
149
-
Connect to a server and select a repository to
150
-
browse its contents.
154
+
<h2>Welcome to KnotView</h2>
155
+
<p class="subtitle">
156
+
A web-based repository browser for Tangled Knots.
157
+
Browse, explore, and download content from Knot
158
+
servers.
151
159
</p>
160
+
161
+
<div class="feature-list">
162
+
<div class="feature-item">
163
+
<h4>๐๏ธ Browse Repositories</h4>
164
+
<p>
165
+
Navigate through files and folders with an
166
+
intuitive interface
167
+
</p>
168
+
</div>
169
+
<div class="feature-item">
170
+
<h4>๐ฟ Branch Support</h4>
171
+
<p>
172
+
Switch between different branches seamlessly
173
+
</p>
174
+
</div>
175
+
<div class="feature-item">
176
+
<h4>๐ File Viewer</h4>
177
+
<p>
178
+
View files with syntax highlighting and
179
+
markdown rendering
180
+
</p>
181
+
</div>
182
+
<div class="feature-item">
183
+
<h4>๐ฆ Download Archives</h4>
184
+
<p>Download entire repositories as archives</p>
185
+
</div>
186
+
</div>
187
+
188
+
<div class="getting-started">
189
+
<h3>Getting Started</h3>
190
+
<ol>
191
+
<li>
192
+
Enter your Knot server URL in the input
193
+
above
194
+
</li>
195
+
<li>
196
+
Click "Connect" to connect to the server
197
+
</li>
198
+
<li>Select a repository from the list</li>
199
+
<li>
200
+
Browse files, switch branches, and explore
201
+
even if Tangled AppView is down!
202
+
</li>
203
+
</ol>
204
+
</div>
152
205
</div>
153
206
154
207
<!-- Users/Repos List -->
···
302
355
</div>
303
356
</main>
304
357
</div>
358
+
<footer>
359
+
<p>
360
+
<a
361
+
href="https://tangled.org/julien.rbrt.fr/knotview"
362
+
target="_blank"
363
+
rel="noopener noreferrer"
364
+
>
365
+
Fork me on Tangled.
366
+
</a>
367
+
</p>
368
+
</footer>
305
369
</div>
306
370
</body>
307
371
</html>
+16
readme.md
+16
readme.md
···
1
+
# KnotView
2
+
3
+
A lightweight web-based browser for exploring Git repositories hosted on KnotServer instances.
4
+
5
+
Selfhost it, or use the hosted version at [`knotview.srv.rbrt.fr`](https://knotview.srv.rbrt.fr)
6
+
7
+
## Note
8
+
9
+
Once PR [#903](https://tangled.org/tangled.org/core/pulls/903) is merged in tangled/core, the UX of browsing a knot will be better.
10
+
In the meantime, you need to know the did and the repo name of the repository you want to browse.
11
+
12
+
In case of CORS issues, configure the Knot server to allow CORS requests from the domain hosting KnotView. Or simply use a browser extension to disable CORS check on the domain.
13
+
14
+
## License
15
+
16
+
[MIT](license)
+353
-116
styles.css
+353
-116
styles.css
···
4
4
box-sizing: border-box;
5
5
}
6
6
7
+
:root {
8
+
/* Light theme colors */
9
+
--bg-primary: #f9fafb;
10
+
--bg-secondary: #ffffff;
11
+
--bg-tertiary: #f3f4f6;
12
+
--bg-hover: #f3f4f6;
13
+
--bg-active: #dbeafe;
14
+
15
+
--text-primary: #111827;
16
+
--text-secondary: #4b5563;
17
+
--text-tertiary: #6b7280;
18
+
--text-heading: #111827;
19
+
20
+
--border-primary: #e5e7eb;
21
+
--border-secondary: #d1d5db;
22
+
--border-light: #f3f4f6;
23
+
24
+
--accent-primary: #3b82f6;
25
+
--accent-hover: #2563eb;
26
+
--accent-light: #dbeafe;
27
+
28
+
--success-bg: #dcfce7;
29
+
--success-text: #166534;
30
+
--success-border: #bbf7d0;
31
+
32
+
--error-bg: #fee2e2;
33
+
--error-text: #991b1b;
34
+
--error-border: #fecaca;
35
+
36
+
--code-bg: #f3f4f6;
37
+
--code-text: #111827;
38
+
--code-block-bg: #1f2937;
39
+
--code-block-text: #e5e7eb;
40
+
--code-block-border: #374151;
41
+
--code-block-line-numbers: #9ca3af;
42
+
43
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
44
+
--shadow-md:
45
+
0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
46
+
}
47
+
48
+
body.dark-theme {
49
+
/* Dark theme colors */
50
+
--bg-primary: #111827;
51
+
--bg-secondary: #1f2937;
52
+
--bg-tertiary: #374151;
53
+
--bg-hover: #374151;
54
+
--bg-active: #1e3a8a;
55
+
56
+
--text-primary: #f3f4f6;
57
+
--text-secondary: #d1d5db;
58
+
--text-tertiary: #9ca3af;
59
+
--text-heading: #ffffff;
60
+
61
+
--border-primary: #374151;
62
+
--border-secondary: #4b5563;
63
+
--border-light: #374151;
64
+
65
+
--accent-primary: #3b82f6;
66
+
--accent-hover: #60a5fa;
67
+
--accent-light: #1e3a8a;
68
+
69
+
--success-bg: #14532d;
70
+
--success-text: #86efac;
71
+
--success-border: #166534;
72
+
73
+
--error-bg: #7f1d1d;
74
+
--error-text: #fecaca;
75
+
--error-border: #991b1b;
76
+
77
+
--code-bg: #374151;
78
+
--code-text: #d1d5db;
79
+
--code-block-bg: #1f2937;
80
+
--code-block-text: #e5e7eb;
81
+
--code-block-border: #4b5563;
82
+
--code-block-line-numbers: #9ca3af;
83
+
84
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
85
+
--shadow-md:
86
+
0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.4);
87
+
}
88
+
7
89
body {
8
-
font-family:
9
-
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
10
-
Cantarell, sans-serif;
11
-
background: #f1f5f9;
12
-
color: #1e293b;
90
+
font-family: InterVariable, system-ui, sans-serif, ui-sans-serif;
91
+
background: var(--bg-primary);
92
+
color: var(--text-primary);
13
93
font-size: 14px;
14
94
line-height: 1.5;
95
+
transition:
96
+
background-color 0.3s ease,
97
+
color 0.3s ease;
15
98
}
16
99
17
100
.container {
···
21
104
}
22
105
23
106
header {
24
-
background: white;
107
+
background: var(--bg-secondary);
25
108
padding: 24px;
26
109
border-radius: 8px;
27
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
110
+
box-shadow: var(--shadow-md);
111
+
margin-bottom: 20px;
112
+
border: 1px solid var(--border-primary);
113
+
}
114
+
115
+
.header-top {
116
+
display: flex;
117
+
justify-content: space-between;
118
+
align-items: center;
28
119
margin-bottom: 20px;
29
-
border: 1px solid #e2e8f0;
30
120
}
31
121
32
122
h1 {
33
123
font-size: 24px;
34
-
margin-bottom: 20px;
35
-
color: #0f172a;
124
+
margin: 0;
125
+
color: var(--text-heading);
36
126
font-weight: 600;
37
127
}
38
128
129
+
.theme-toggle {
130
+
background: var(--bg-tertiary);
131
+
border: 1px solid var(--border-primary);
132
+
color: var(--text-primary);
133
+
padding: 8px 16px;
134
+
border-radius: 6px;
135
+
cursor: pointer;
136
+
font-size: 14px;
137
+
display: flex;
138
+
align-items: center;
139
+
gap: 8px;
140
+
transition: all 0.15s;
141
+
}
142
+
143
+
.theme-toggle:hover {
144
+
background: var(--bg-hover);
145
+
border-color: var(--border-secondary);
146
+
}
147
+
39
148
.connection-panel {
40
149
display: flex;
41
150
gap: 12px;
···
47
156
flex: 1;
48
157
min-width: 300px;
49
158
padding: 10px 14px;
50
-
border: 1px solid #cbd5e1;
159
+
border: 1px solid var(--border-secondary);
51
160
border-radius: 6px;
52
161
font-size: 14px;
53
-
background: white;
162
+
background: var(--bg-secondary);
163
+
color: var(--text-primary);
54
164
transition: all 0.15s;
55
165
}
56
166
57
167
.connection-panel input:focus {
58
168
outline: none;
59
-
border-color: #3b82f6;
169
+
border-color: var(--accent-primary);
60
170
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
61
171
}
62
172
63
173
button {
64
174
padding: 10px 20px;
65
-
background: #3b82f6;
175
+
background: var(--accent-primary);
66
176
color: white;
67
177
border: none;
68
178
border-radius: 6px;
···
70
180
font-size: 14px;
71
181
font-weight: 500;
72
182
transition: all 0.15s;
73
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
183
+
box-shadow: var(--shadow-sm);
74
184
}
75
185
76
186
button:hover {
77
-
background: #2563eb;
187
+
background: var(--accent-hover);
78
188
}
79
189
80
190
button:active {
···
82
192
}
83
193
84
194
button:disabled {
85
-
background: #94a3b8;
195
+
background: var(--text-tertiary);
86
196
cursor: not-allowed;
87
197
transform: none;
88
198
}
89
199
90
200
button.secondary {
91
-
background: white;
92
-
color: #475569;
93
-
border: 1px solid #cbd5e1;
201
+
background: var(--bg-secondary);
202
+
color: var(--text-secondary);
203
+
border: 1px solid var(--border-secondary);
94
204
}
95
205
96
206
button.secondary:hover {
97
-
background: #f8fafc;
207
+
background: var(--bg-hover);
98
208
}
99
209
100
210
.status {
101
-
padding: 10px 14px;
211
+
padding: 12px 16px;
102
212
border-radius: 6px;
103
213
font-size: 13px;
214
+
border: 1px solid transparent;
215
+
margin-top: 12px;
216
+
font-weight: 500;
217
+
line-height: 1.5;
218
+
}
219
+
220
+
.status:empty {
104
221
display: none;
105
-
border: 1px solid transparent;
106
222
}
107
223
108
224
.status.success {
109
-
background: #dcfce7;
110
-
color: #166534;
111
-
border-color: #bbf7d0;
225
+
background: var(--success-bg);
226
+
color: var(--success-text);
227
+
border-color: var(--success-border);
112
228
}
113
229
114
230
.status.error {
115
-
background: #fee2e2;
116
-
color: #991b1b;
117
-
border-color: #fecaca;
231
+
background: var(--error-bg);
232
+
color: var(--error-text);
233
+
border-color: var(--error-border);
234
+
font-weight: 600;
235
+
}
236
+
237
+
.status.error::before {
238
+
content: "โ ๏ธ ";
239
+
margin-right: 4px;
240
+
}
241
+
242
+
.status.success::before {
243
+
content: "โ ";
244
+
margin-right: 4px;
118
245
}
119
246
120
247
.main-content {
···
125
252
126
253
.sidebar {
127
254
width: 300px;
128
-
background: white;
255
+
background: var(--bg-secondary);
129
256
border-radius: 8px;
130
-
border: 1px solid #e2e8f0;
131
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
257
+
border: 1px solid var(--border-primary);
258
+
box-shadow: var(--shadow-md);
132
259
flex-shrink: 0;
133
260
}
134
261
···
136
263
font-size: 16px;
137
264
font-weight: 600;
138
265
padding: 16px 20px;
139
-
border-bottom: 1px solid #e2e8f0;
140
-
color: #0f172a;
266
+
border-bottom: 1px solid var(--border-primary);
267
+
color: var(--text-heading);
141
268
display: flex;
142
269
align-items: center;
143
270
justify-content: space-between;
···
145
272
146
273
.repo-info {
147
274
padding: 20px;
148
-
background: white;
149
-
border-radius: 8px;
150
-
border: 1px solid #e2e8f0;
151
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
152
-
margin-bottom: 20px;
153
275
}
154
276
155
277
.repo-info h3 {
156
278
font-size: 14px;
157
279
font-weight: 600;
158
280
margin-bottom: 12px;
159
-
color: #64748b;
281
+
color: var(--text-tertiary);
160
282
}
161
283
162
284
.repo-info .label {
163
285
font-size: 12px;
164
-
color: #64748b;
286
+
color: var(--text-tertiary);
165
287
margin-bottom: 4px;
166
288
font-weight: 500;
167
289
text-transform: uppercase;
···
170
292
171
293
.repo-info .value {
172
294
font-size: 13px;
173
-
color: #1e293b;
295
+
color: var(--text-primary);
174
296
margin-bottom: 12px;
175
-
font-family: monospace;
297
+
font-family: IBMPlexMono, ui-monospace, monospace;
176
298
}
177
299
178
300
.clone-url {
179
301
display: flex;
180
302
align-items: center;
181
303
gap: 8px;
182
-
background: #f8fafc;
304
+
background: var(--bg-tertiary);
183
305
padding: 8px 12px;
184
306
border-radius: 6px;
185
-
border: 1px solid #e2e8f0;
307
+
border: 1px solid var(--border-primary);
186
308
margin-bottom: 12px;
187
309
}
188
310
189
311
.clone-url code {
190
312
flex: 1;
191
313
font-size: 12px;
192
-
color: #475569;
314
+
color: var(--text-secondary);
193
315
overflow: hidden;
194
316
text-overflow: ellipsis;
195
317
}
···
201
323
}
202
324
203
325
.copy-btn:hover {
204
-
background: #2563eb;
326
+
background: var(--accent-hover);
205
327
}
206
328
207
329
.branches-section {
208
-
border-top: 1px solid #e2e8f0;
330
+
border-top: 1px solid var(--border-primary);
209
331
}
210
332
211
333
.branch-list {
···
217
339
padding: 10px 20px;
218
340
cursor: pointer;
219
341
transition: background 0.15s;
220
-
border-bottom: 1px solid #f1f5f9;
342
+
border-bottom: 1px solid var(--border-light);
221
343
font-size: 13px;
222
-
color: #475569;
344
+
color: var(--text-secondary);
223
345
display: flex;
224
346
align-items: center;
225
347
gap: 8px;
226
348
}
227
349
228
350
.branch-item:hover {
229
-
background: #f8fafc;
351
+
background: var(--bg-hover);
230
352
}
231
353
232
354
.branch-item.active {
233
-
background: #eff6ff;
234
-
color: #1e40af;
355
+
background: var(--accent-light);
356
+
color: var(--accent-primary);
235
357
font-weight: 500;
236
358
}
237
359
238
360
.viewer {
239
361
flex: 1;
240
-
background: white;
362
+
background: var(--bg-secondary);
241
363
border-radius: 8px;
242
-
border: 1px solid #e2e8f0;
243
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
364
+
border: 1px solid var(--border-primary);
365
+
box-shadow: var(--shadow-md);
244
366
overflow: hidden;
245
367
}
246
368
247
369
.breadcrumb {
248
370
padding: 16px 20px;
249
-
border-bottom: 1px solid #e2e8f0;
371
+
border-bottom: 1px solid var(--border-primary);
250
372
font-size: 13px;
251
-
color: #64748b;
252
-
background: #f8fafc;
373
+
color: var(--text-tertiary);
374
+
background: var(--bg-tertiary);
253
375
display: flex;
254
376
align-items: center;
255
377
flex-wrap: wrap;
256
378
}
257
379
258
380
.breadcrumb a {
259
-
color: #3b82f6;
381
+
color: var(--accent-primary);
260
382
text-decoration: none;
261
383
transition: color 0.15s;
262
384
cursor: pointer;
263
385
}
264
386
265
387
.breadcrumb a:hover {
266
-
color: #2563eb;
388
+
color: var(--accent-hover);
267
389
text-decoration: underline;
268
390
}
269
391
···
272
394
}
273
395
274
396
.breadcrumb .current {
275
-
color: #1e293b;
397
+
color: var(--text-primary);
276
398
font-weight: 500;
277
399
}
278
400
···
287
409
display: flex;
288
410
align-items: center;
289
411
gap: 12px;
290
-
border-bottom: 1px solid #f1f5f9;
412
+
border-bottom: 1px solid var(--border-light);
291
413
cursor: pointer !important;
292
414
}
293
415
···
296
418
}
297
419
298
420
.file-item:hover {
299
-
background: #f8fafc;
421
+
background: var(--bg-hover);
300
422
}
301
423
302
424
.file-icon {
303
425
width: 20px;
304
426
height: 20px;
305
427
flex-shrink: 0;
306
-
color: #64748b;
428
+
color: var(--text-tertiary);
307
429
cursor: pointer;
308
430
}
309
431
310
432
.file-name {
311
433
flex: 1;
312
-
color: #1e293b;
434
+
color: var(--text-primary);
313
435
font-size: 14px;
314
436
cursor: pointer;
315
437
}
316
438
317
439
.file-size {
318
-
color: #64748b;
440
+
color: var(--text-tertiary);
319
441
font-size: 12px;
320
442
cursor: pointer;
321
443
}
···
323
445
.file-content {
324
446
padding: 0;
325
447
overflow-x: auto;
326
-
background: #0d1117;
327
-
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
448
+
background: var(--code-block-bg);
449
+
font-family: IBMPlexMono, Monaco, Menlo, monospace;
328
450
font-size: 13px;
329
451
}
330
452
···
347
469
.line-numbers {
348
470
display: flex;
349
471
gap: 0;
350
-
background: #0d1117;
472
+
background: var(--code-block-bg);
351
473
}
352
474
353
475
.line-numbers .numbers {
354
-
color: #6e7681;
476
+
color: var(--code-block-line-numbers);
355
477
text-align: right;
356
478
user-select: none;
357
479
min-width: 50px;
358
480
padding: 20px 16px 20px 20px;
359
-
border-right: 1px solid #30363d;
360
-
background: #0d1117;
481
+
border-right: 1px solid var(--code-block-border);
482
+
background: var(--code-block-bg);
361
483
line-height: 1.5;
362
484
}
363
485
···
369
491
.loading {
370
492
padding: 40px;
371
493
text-align: center;
372
-
color: #64748b;
494
+
color: var(--text-tertiary);
373
495
}
374
496
375
497
.spinner {
376
498
width: 40px;
377
499
height: 40px;
378
500
margin: 0 auto 16px;
379
-
border: 3px solid #e2e8f0;
380
-
border-top-color: #3b82f6;
501
+
border: 3px solid var(--border-primary);
502
+
border-top-color: var(--accent-primary);
381
503
border-radius: 50%;
382
504
animation: spin 0.8s linear infinite;
383
505
}
···
397
519
width: 64px;
398
520
height: 64px;
399
521
margin: 0 auto 20px;
400
-
color: #cbd5e1;
522
+
color: var(--text-tertiary);
401
523
display: block;
402
524
}
403
525
404
526
.empty-state h3 {
405
527
font-size: 18px;
406
-
color: #475569;
528
+
color: var(--text-secondary);
407
529
margin-bottom: 8px;
408
530
}
409
531
410
532
.empty-state p {
411
-
color: #64748b;
533
+
color: var(--text-tertiary);
534
+
font-size: 14px;
535
+
}
536
+
537
+
.welcome-hero {
538
+
padding: 80px 40px;
539
+
text-align: center;
540
+
max-width: 700px;
541
+
margin: 0 auto;
542
+
}
543
+
544
+
.welcome-hero svg {
545
+
width: 96px;
546
+
height: 96px;
547
+
margin: 0 auto 32px;
548
+
color: var(--accent-primary);
549
+
display: block;
550
+
}
551
+
552
+
.welcome-hero h2 {
553
+
font-size: 32px;
554
+
color: var(--text-heading);
555
+
margin-bottom: 16px;
556
+
font-weight: 700;
557
+
}
558
+
559
+
.welcome-hero .subtitle {
560
+
font-size: 18px;
561
+
color: var(--text-secondary);
562
+
margin-bottom: 48px;
563
+
line-height: 1.6;
564
+
}
565
+
566
+
.feature-list {
567
+
display: grid;
568
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
569
+
gap: 24px;
570
+
margin-top: 48px;
571
+
text-align: left;
572
+
}
573
+
574
+
.feature-item {
575
+
padding: 20px;
576
+
background: var(--bg-tertiary);
577
+
border-radius: 8px;
578
+
border: 1px solid var(--border-primary);
579
+
}
580
+
581
+
.feature-item h4 {
582
+
font-size: 16px;
583
+
color: var(--text-heading);
584
+
margin-bottom: 8px;
585
+
display: flex;
586
+
align-items: center;
587
+
gap: 8px;
588
+
}
589
+
590
+
.feature-item p {
412
591
font-size: 14px;
592
+
color: var(--text-tertiary);
593
+
line-height: 1.5;
594
+
margin: 0;
595
+
}
596
+
597
+
.getting-started {
598
+
margin-top: 48px;
599
+
padding: 24px;
600
+
background: var(--bg-tertiary);
601
+
border-radius: 8px;
602
+
border: 1px solid var(--border-primary);
603
+
text-align: left;
604
+
}
605
+
606
+
.getting-started h3 {
607
+
font-size: 18px;
608
+
color: var(--text-heading);
609
+
margin-bottom: 16px;
610
+
}
611
+
612
+
.getting-started ol {
613
+
margin-left: 20px;
614
+
color: var(--text-secondary);
615
+
}
616
+
617
+
.getting-started li {
618
+
margin-bottom: 8px;
619
+
line-height: 1.6;
413
620
}
414
621
415
622
.error-message {
416
623
padding: 40px;
417
624
text-align: center;
418
-
color: #991b1b;
419
-
background: #fee2e2;
625
+
color: var(--error-text);
626
+
background: var(--error-bg);
420
627
margin: 20px;
421
628
border-radius: 8px;
422
-
border: 1px solid #fecaca;
629
+
border: 1px solid var(--error-border);
423
630
}
424
631
425
632
.file-header {
426
633
padding: 16px 20px;
427
-
border-bottom: 1px solid #e2e8f0;
428
-
background: #f8fafc;
634
+
border-bottom: 1px solid var(--border-primary);
635
+
background: var(--bg-tertiary);
429
636
display: flex;
430
637
justify-content: space-between;
431
638
align-items: center;
···
433
640
434
641
.file-header h3 {
435
642
font-size: 15px;
436
-
color: #1e293b;
643
+
color: var(--text-primary);
437
644
font-weight: 600;
438
645
}
439
646
···
454
661
.user-header {
455
662
font-size: 16px;
456
663
font-weight: 600;
457
-
color: #0f172a;
664
+
color: var(--text-heading);
458
665
margin-bottom: 12px;
459
666
padding: 12px;
460
-
background: #f8fafc;
667
+
background: var(--bg-tertiary);
461
668
border-radius: 6px;
462
669
}
463
670
464
671
.repo-item {
465
672
padding: 12px;
466
673
margin-bottom: 8px;
467
-
background: white;
468
-
border: 1px solid #e2e8f0;
674
+
background: var(--bg-secondary);
675
+
border: 1px solid var(--border-primary);
469
676
border-radius: 6px;
470
677
cursor: pointer;
471
678
transition: all 0.15s;
472
679
}
473
680
474
681
.repo-item:hover {
475
-
border-color: #3b82f6;
682
+
border-color: var(--accent-primary);
476
683
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.1);
477
684
}
478
685
479
686
.repo-item strong {
480
687
display: block;
481
688
font-size: 14px;
482
-
color: #1e293b;
689
+
color: var(--text-primary);
483
690
margin-bottom: 4px;
484
691
}
485
692
486
693
.repo-item small {
487
694
font-size: 12px;
488
-
color: #64748b;
489
-
font-family: monospace;
695
+
color: var(--text-tertiary);
696
+
font-family: IBMPlexMono, monospace;
490
697
}
491
698
492
699
.markdown-content {
493
700
padding: 20px 40px;
494
-
background: white;
495
-
font-family:
496
-
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
497
-
Cantarell, sans-serif;
701
+
background: var(--bg-secondary);
702
+
font-family: InterVariable, system-ui, sans-serif;
498
703
font-size: 15px;
499
704
line-height: 1.6;
500
-
color: #1e293b;
705
+
color: var(--text-primary);
501
706
}
502
707
503
708
.markdown-content h1,
···
510
715
margin-bottom: 16px;
511
716
font-weight: 600;
512
717
line-height: 1.25;
513
-
color: #0f172a;
718
+
color: var(--text-heading);
514
719
}
515
720
516
721
.markdown-content h1 {
517
722
font-size: 2em;
518
723
padding-bottom: 0.3em;
519
-
border-bottom: 1px solid #e2e8f0;
724
+
border-bottom: 1px solid var(--border-primary);
520
725
}
521
726
522
727
.markdown-content h2 {
523
728
font-size: 1.5em;
524
729
padding-bottom: 0.3em;
525
-
border-bottom: 1px solid #e2e8f0;
730
+
border-bottom: 1px solid var(--border-primary);
526
731
}
527
732
528
733
.markdown-content h3 {
···
539
744
540
745
.markdown-content h6 {
541
746
font-size: 0.85em;
542
-
color: #64748b;
747
+
color: var(--text-tertiary);
543
748
}
544
749
545
750
.markdown-content p {
···
562
767
padding: 0.2em 0.4em;
563
768
margin: 0;
564
769
font-size: 85%;
565
-
background: #f1f5f9;
770
+
background: var(--code-bg);
566
771
border-radius: 6px;
567
-
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
568
-
color: #e11d48;
772
+
font-family: IBMPlexMono, Monaco, Menlo, monospace;
773
+
color: var(--code-text);
569
774
}
570
775
571
776
.markdown-content pre {
···
573
778
overflow: auto;
574
779
font-size: 85%;
575
780
line-height: 1.45;
576
-
background: #0d1117;
781
+
background: var(--code-block-bg);
577
782
border-radius: 6px;
578
783
margin-bottom: 16px;
579
784
}
···
587
792
word-wrap: normal;
588
793
background: transparent;
589
794
border: 0;
590
-
color: #c9d1d9;
795
+
color: var(--code-block-text);
591
796
}
592
797
593
798
.markdown-content pre code.hljs {
···
596
801
597
802
.markdown-content blockquote {
598
803
padding: 0 1em;
599
-
color: #64748b;
600
-
border-left: 0.25em solid #cbd5e1;
804
+
color: var(--text-tertiary);
805
+
border-left: 0.25em solid var(--border-secondary);
601
806
margin: 0 0 16px 0;
602
807
}
603
808
···
620
825
.markdown-content table th,
621
826
.markdown-content table td {
622
827
padding: 6px 13px;
623
-
border: 1px solid #e2e8f0;
828
+
border: 1px solid var(--border-primary);
624
829
}
625
830
626
831
.markdown-content table th {
627
832
font-weight: 600;
628
-
background: #f8fafc;
833
+
background: var(--bg-tertiary);
629
834
}
630
835
631
836
.markdown-content table tr {
632
-
background: white;
633
-
border-top: 1px solid #e2e8f0;
837
+
background: var(--bg-secondary);
838
+
border-top: 1px solid var(--border-primary);
634
839
}
635
840
636
841
.markdown-content table tr:nth-child(2n) {
637
-
background: #f8fafc;
842
+
background: var(--bg-tertiary);
638
843
}
639
844
640
845
.markdown-content img {
···
644
849
}
645
850
646
851
.markdown-content a {
647
-
color: #3b82f6;
852
+
color: var(--accent-primary);
648
853
text-decoration: none;
649
854
}
650
855
···
656
861
height: 0.25em;
657
862
padding: 0;
658
863
margin: 24px 0;
659
-
background-color: #e2e8f0;
864
+
background-color: var(--border-primary);
660
865
border: 0;
661
866
}
662
867
868
+
footer {
869
+
padding: 20px;
870
+
text-align: center;
871
+
border-top: 1px solid var(--border-primary);
872
+
margin-top: 40px;
873
+
}
874
+
875
+
footer p {
876
+
margin: 0;
877
+
color: var(--text-secondary);
878
+
font-size: 0.9rem;
879
+
}
880
+
881
+
footer a {
882
+
color: var(--accent-primary);
883
+
text-decoration: none;
884
+
font-weight: 500;
885
+
}
886
+
887
+
footer a:hover {
888
+
text-decoration: underline;
889
+
color: var(--accent-hover);
890
+
}
891
+
663
892
@media (max-width: 768px) {
664
893
.main-content {
665
894
flex-direction: column;
666
895
}
667
896
897
+
.sidebar {
898
+
width: 100%;
899
+
}
900
+
668
901
.connection-panel {
669
902
flex-direction: column;
670
903
}
···
675
908
676
909
.markdown-content {
677
910
padding: 20px;
911
+
}
912
+
913
+
.welcome-hero {
914
+
padding: 40px 20px;
678
915
}
679
916
}