Compare changes

Choose any two refs to compare.

Changed files
+444 -122
+19
app.js
··· 2 2 document.addEventListener("alpine:init", () => { 3 3 Alpine.data("app", () => ({ 4 4 // State 5 + darkTheme: localStorage.getItem("darkTheme") !== "false", 5 6 serverUrl: "https://knot.srv.rbrt.fr", 6 7 isConnected: false, 7 8 status: { ··· 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
··· 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>
+2
readme.md
··· 9 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 10 In the meantime, you need to know the did and the repo name of the repository you want to browse. 11 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 + 12 14 ## License 13 15 14 16 [MIT](license)
+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 }