feat: dark theme + landing page

Changed files
+389 -120
+19
app.js
··· 2 document.addEventListener("alpine:init", () => { 3 Alpine.data("app", () => ({ 4 // State 5 serverUrl: "https://knot.srv.rbrt.fr", 6 isConnected: false, 7 status: { ··· 34 35 // Initialization 36 init() { 37 // Make this component globally accessible for onclick handlers 38 window.appInstance = this; 39 ··· 65 66 // Restore from URL on load 67 this.restoreFromURL(); 68 }, 69 70 // Connection
··· 2 document.addEventListener("alpine:init", () => { 3 Alpine.data("app", () => ({ 4 // State 5 + darkTheme: localStorage.getItem("darkTheme") !== "false", 6 serverUrl: "https://knot.srv.rbrt.fr", 7 isConnected: false, 8 status: { ··· 35 36 // Initialization 37 init() { 38 + // Apply saved theme 39 + this.applyTheme(); 40 + 41 // Make this component globally accessible for onclick handlers 42 window.appInstance = this; 43 ··· 69 70 // Restore from URL on load 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 + } 87 }, 88 89 // Connection
+58 -6
index.html
··· 22 <body> 23 <div class="container" x-data="app" x-init="init()"> 24 <header> 25 - <h1>KnotView</h1> 26 <div class="connection-panel"> 27 <input 28 type="text" ··· 129 <!-- Empty State --> 130 <div 131 x-show="!loading && !error && !state.currentRepo && view === 'empty'" 132 - class="empty-state" 133 > 134 <svg 135 xmlns="http://www.w3.org/2000/svg" ··· 144 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 /> 146 </svg> 147 - <h3>No Repository Selected</h3> 148 - <p> 149 - Connect to a server and select a repository to 150 - browse its contents. 151 </p> 152 </div> 153 154 <!-- Users/Repos List -->
··· 22 <body> 23 <div class="container" x-data="app" x-init="init()"> 24 <header> 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> 33 <div class="connection-panel"> 34 <input 35 type="text" ··· 136 <!-- Empty State --> 137 <div 138 x-show="!loading && !error && !state.currentRepo && view === 'empty'" 139 + class="welcome-hero" 140 > 141 <svg 142 xmlns="http://www.w3.org/2000/svg" ··· 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" 152 /> 153 </svg> 154 + <h2>Welcome to KnotView</h2> 155 + <p class="subtitle"> 156 + A web-based repository browser for AT Protocol 157 + repositories. Browse, explore, and download content 158 + from Knot servers. 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 + </li> 202 + </ol> 203 + </div> 204 </div> 205 206 <!-- Users/Repos List -->
+2
readme.md
··· 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 ## License 13 14 [MIT](license)
··· 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)
+310 -114
styles.css
··· 4 box-sizing: border-box; 5 } 6 7 body { 8 - font-family: 9 - -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, 10 - Cantarell, sans-serif; 11 - background: #f1f5f9; 12 - color: #1e293b; 13 font-size: 14px; 14 line-height: 1.5; 15 } 16 17 .container { ··· 21 } 22 23 header { 24 - background: white; 25 padding: 24px; 26 border-radius: 8px; 27 - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 28 margin-bottom: 20px; 29 - border: 1px solid #e2e8f0; 30 } 31 32 h1 { 33 font-size: 24px; 34 - margin-bottom: 20px; 35 - color: #0f172a; 36 font-weight: 600; 37 } 38 39 .connection-panel { 40 display: flex; 41 gap: 12px; ··· 47 flex: 1; 48 min-width: 300px; 49 padding: 10px 14px; 50 - border: 1px solid #cbd5e1; 51 border-radius: 6px; 52 font-size: 14px; 53 - background: white; 54 transition: all 0.15s; 55 } 56 57 .connection-panel input:focus { 58 outline: none; 59 - border-color: #3b82f6; 60 box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); 61 } 62 63 button { 64 padding: 10px 20px; 65 - background: #3b82f6; 66 color: white; 67 border: none; 68 border-radius: 6px; ··· 70 font-size: 14px; 71 font-weight: 500; 72 transition: all 0.15s; 73 - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 74 } 75 76 button:hover { 77 - background: #2563eb; 78 } 79 80 button:active { ··· 82 } 83 84 button:disabled { 85 - background: #94a3b8; 86 cursor: not-allowed; 87 transform: none; 88 } 89 90 button.secondary { 91 - background: white; 92 - color: #475569; 93 - border: 1px solid #cbd5e1; 94 } 95 96 button.secondary:hover { 97 - background: #f8fafc; 98 } 99 100 .status { ··· 106 } 107 108 .status.success { 109 - background: #dcfce7; 110 - color: #166534; 111 - border-color: #bbf7d0; 112 } 113 114 .status.error { 115 - background: #fee2e2; 116 - color: #991b1b; 117 - border-color: #fecaca; 118 } 119 120 .main-content { ··· 125 126 .sidebar { 127 width: 300px; 128 - background: white; 129 border-radius: 8px; 130 - border: 1px solid #e2e8f0; 131 - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 132 flex-shrink: 0; 133 } 134 ··· 136 font-size: 16px; 137 font-weight: 600; 138 padding: 16px 20px; 139 - border-bottom: 1px solid #e2e8f0; 140 - color: #0f172a; 141 display: flex; 142 align-items: center; 143 justify-content: space-between; ··· 145 146 .repo-info { 147 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 } 154 155 .repo-info h3 { 156 font-size: 14px; 157 font-weight: 600; 158 margin-bottom: 12px; 159 - color: #64748b; 160 } 161 162 .repo-info .label { 163 font-size: 12px; 164 - color: #64748b; 165 margin-bottom: 4px; 166 font-weight: 500; 167 text-transform: uppercase; ··· 170 171 .repo-info .value { 172 font-size: 13px; 173 - color: #1e293b; 174 margin-bottom: 12px; 175 - font-family: monospace; 176 } 177 178 .clone-url { 179 display: flex; 180 align-items: center; 181 gap: 8px; 182 - background: #f8fafc; 183 padding: 8px 12px; 184 border-radius: 6px; 185 - border: 1px solid #e2e8f0; 186 margin-bottom: 12px; 187 } 188 189 .clone-url code { 190 flex: 1; 191 font-size: 12px; 192 - color: #475569; 193 overflow: hidden; 194 text-overflow: ellipsis; 195 } ··· 201 } 202 203 .copy-btn:hover { 204 - background: #2563eb; 205 } 206 207 .branches-section { 208 - border-top: 1px solid #e2e8f0; 209 } 210 211 .branch-list { ··· 217 padding: 10px 20px; 218 cursor: pointer; 219 transition: background 0.15s; 220 - border-bottom: 1px solid #f1f5f9; 221 font-size: 13px; 222 - color: #475569; 223 display: flex; 224 align-items: center; 225 gap: 8px; 226 } 227 228 .branch-item:hover { 229 - background: #f8fafc; 230 } 231 232 .branch-item.active { 233 - background: #eff6ff; 234 - color: #1e40af; 235 font-weight: 500; 236 } 237 238 .viewer { 239 flex: 1; 240 - background: white; 241 border-radius: 8px; 242 - border: 1px solid #e2e8f0; 243 - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 244 overflow: hidden; 245 } 246 247 .breadcrumb { 248 padding: 16px 20px; 249 - border-bottom: 1px solid #e2e8f0; 250 font-size: 13px; 251 - color: #64748b; 252 - background: #f8fafc; 253 display: flex; 254 align-items: center; 255 flex-wrap: wrap; 256 } 257 258 .breadcrumb a { 259 - color: #3b82f6; 260 text-decoration: none; 261 transition: color 0.15s; 262 cursor: pointer; 263 } 264 265 .breadcrumb a:hover { 266 - color: #2563eb; 267 text-decoration: underline; 268 } 269 ··· 272 } 273 274 .breadcrumb .current { 275 - color: #1e293b; 276 font-weight: 500; 277 } 278 ··· 287 display: flex; 288 align-items: center; 289 gap: 12px; 290 - border-bottom: 1px solid #f1f5f9; 291 cursor: pointer !important; 292 } 293 ··· 296 } 297 298 .file-item:hover { 299 - background: #f8fafc; 300 } 301 302 .file-icon { 303 width: 20px; 304 height: 20px; 305 flex-shrink: 0; 306 - color: #64748b; 307 cursor: pointer; 308 } 309 310 .file-name { 311 flex: 1; 312 - color: #1e293b; 313 font-size: 14px; 314 cursor: pointer; 315 } 316 317 .file-size { 318 - color: #64748b; 319 font-size: 12px; 320 cursor: pointer; 321 } ··· 323 .file-content { 324 padding: 0; 325 overflow-x: auto; 326 - background: #0d1117; 327 - font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace; 328 font-size: 13px; 329 } 330 ··· 347 .line-numbers { 348 display: flex; 349 gap: 0; 350 - background: #0d1117; 351 } 352 353 .line-numbers .numbers { 354 - color: #6e7681; 355 text-align: right; 356 user-select: none; 357 min-width: 50px; 358 padding: 20px 16px 20px 20px; 359 - border-right: 1px solid #30363d; 360 - background: #0d1117; 361 line-height: 1.5; 362 } 363 ··· 369 .loading { 370 padding: 40px; 371 text-align: center; 372 - color: #64748b; 373 } 374 375 .spinner { 376 width: 40px; 377 height: 40px; 378 margin: 0 auto 16px; 379 - border: 3px solid #e2e8f0; 380 - border-top-color: #3b82f6; 381 border-radius: 50%; 382 animation: spin 0.8s linear infinite; 383 } ··· 397 width: 64px; 398 height: 64px; 399 margin: 0 auto 20px; 400 - color: #cbd5e1; 401 display: block; 402 } 403 404 .empty-state h3 { 405 font-size: 18px; 406 - color: #475569; 407 margin-bottom: 8px; 408 } 409 410 .empty-state p { 411 - color: #64748b; 412 font-size: 14px; 413 } 414 415 .error-message { 416 padding: 40px; 417 text-align: center; 418 - color: #991b1b; 419 - background: #fee2e2; 420 margin: 20px; 421 border-radius: 8px; 422 - border: 1px solid #fecaca; 423 } 424 425 .file-header { 426 padding: 16px 20px; 427 - border-bottom: 1px solid #e2e8f0; 428 - background: #f8fafc; 429 display: flex; 430 justify-content: space-between; 431 align-items: center; ··· 433 434 .file-header h3 { 435 font-size: 15px; 436 - color: #1e293b; 437 font-weight: 600; 438 } 439 ··· 454 .user-header { 455 font-size: 16px; 456 font-weight: 600; 457 - color: #0f172a; 458 margin-bottom: 12px; 459 padding: 12px; 460 - background: #f8fafc; 461 border-radius: 6px; 462 } 463 464 .repo-item { 465 padding: 12px; 466 margin-bottom: 8px; 467 - background: white; 468 - border: 1px solid #e2e8f0; 469 border-radius: 6px; 470 cursor: pointer; 471 transition: all 0.15s; 472 } 473 474 .repo-item:hover { 475 - border-color: #3b82f6; 476 box-shadow: 0 2px 4px rgba(59, 130, 246, 0.1); 477 } 478 479 .repo-item strong { 480 display: block; 481 font-size: 14px; 482 - color: #1e293b; 483 margin-bottom: 4px; 484 } 485 486 .repo-item small { 487 font-size: 12px; 488 - color: #64748b; 489 - font-family: monospace; 490 } 491 492 .markdown-content { 493 padding: 20px 40px; 494 - background: white; 495 - font-family: 496 - -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, 497 - Cantarell, sans-serif; 498 font-size: 15px; 499 line-height: 1.6; 500 - color: #1e293b; 501 } 502 503 .markdown-content h1, ··· 510 margin-bottom: 16px; 511 font-weight: 600; 512 line-height: 1.25; 513 - color: #0f172a; 514 } 515 516 .markdown-content h1 { 517 font-size: 2em; 518 padding-bottom: 0.3em; 519 - border-bottom: 1px solid #e2e8f0; 520 } 521 522 .markdown-content h2 { 523 font-size: 1.5em; 524 padding-bottom: 0.3em; 525 - border-bottom: 1px solid #e2e8f0; 526 } 527 528 .markdown-content h3 { ··· 539 540 .markdown-content h6 { 541 font-size: 0.85em; 542 - color: #64748b; 543 } 544 545 .markdown-content p { ··· 562 padding: 0.2em 0.4em; 563 margin: 0; 564 font-size: 85%; 565 - background: #f1f5f9; 566 border-radius: 6px; 567 - font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace; 568 - color: #e11d48; 569 } 570 571 .markdown-content pre { ··· 573 overflow: auto; 574 font-size: 85%; 575 line-height: 1.45; 576 - background: #0d1117; 577 border-radius: 6px; 578 margin-bottom: 16px; 579 } ··· 587 word-wrap: normal; 588 background: transparent; 589 border: 0; 590 - color: #c9d1d9; 591 } 592 593 .markdown-content pre code.hljs { ··· 596 597 .markdown-content blockquote { 598 padding: 0 1em; 599 - color: #64748b; 600 - border-left: 0.25em solid #cbd5e1; 601 margin: 0 0 16px 0; 602 } 603 ··· 620 .markdown-content table th, 621 .markdown-content table td { 622 padding: 6px 13px; 623 - border: 1px solid #e2e8f0; 624 } 625 626 .markdown-content table th { 627 font-weight: 600; 628 - background: #f8fafc; 629 } 630 631 .markdown-content table tr { 632 - background: white; 633 - border-top: 1px solid #e2e8f0; 634 } 635 636 .markdown-content table tr:nth-child(2n) { 637 - background: #f8fafc; 638 } 639 640 .markdown-content img { ··· 644 } 645 646 .markdown-content a { 647 - color: #3b82f6; 648 text-decoration: none; 649 } 650 ··· 656 height: 0.25em; 657 padding: 0; 658 margin: 24px 0; 659 - background-color: #e2e8f0; 660 border: 0; 661 } 662 ··· 665 flex-direction: column; 666 } 667 668 .connection-panel { 669 flex-direction: column; 670 } ··· 675 676 .markdown-content { 677 padding: 20px; 678 } 679 }
··· 4 box-sizing: border-box; 5 } 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 + 89 body { 90 + font-family: InterVariable, system-ui, sans-serif, ui-sans-serif; 91 + background: var(--bg-primary); 92 + color: var(--text-primary); 93 font-size: 14px; 94 line-height: 1.5; 95 + transition: 96 + background-color 0.3s ease, 97 + color 0.3s ease; 98 } 99 100 .container { ··· 104 } 105 106 header { 107 + background: var(--bg-secondary); 108 padding: 24px; 109 border-radius: 8px; 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; 119 margin-bottom: 20px; 120 } 121 122 h1 { 123 font-size: 24px; 124 + margin: 0; 125 + color: var(--text-heading); 126 font-weight: 600; 127 } 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 + 148 .connection-panel { 149 display: flex; 150 gap: 12px; ··· 156 flex: 1; 157 min-width: 300px; 158 padding: 10px 14px; 159 + border: 1px solid var(--border-secondary); 160 border-radius: 6px; 161 font-size: 14px; 162 + background: var(--bg-secondary); 163 + color: var(--text-primary); 164 transition: all 0.15s; 165 } 166 167 .connection-panel input:focus { 168 outline: none; 169 + border-color: var(--accent-primary); 170 box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); 171 } 172 173 button { 174 padding: 10px 20px; 175 + background: var(--accent-primary); 176 color: white; 177 border: none; 178 border-radius: 6px; ··· 180 font-size: 14px; 181 font-weight: 500; 182 transition: all 0.15s; 183 + box-shadow: var(--shadow-sm); 184 } 185 186 button:hover { 187 + background: var(--accent-hover); 188 } 189 190 button:active { ··· 192 } 193 194 button:disabled { 195 + background: var(--text-tertiary); 196 cursor: not-allowed; 197 transform: none; 198 } 199 200 button.secondary { 201 + background: var(--bg-secondary); 202 + color: var(--text-secondary); 203 + border: 1px solid var(--border-secondary); 204 } 205 206 button.secondary:hover { 207 + background: var(--bg-hover); 208 } 209 210 .status { ··· 216 } 217 218 .status.success { 219 + background: var(--success-bg); 220 + color: var(--success-text); 221 + border-color: var(--success-border); 222 } 223 224 .status.error { 225 + background: var(--error-bg); 226 + color: var(--error-text); 227 + border-color: var(--error-border); 228 } 229 230 .main-content { ··· 235 236 .sidebar { 237 width: 300px; 238 + background: var(--bg-secondary); 239 border-radius: 8px; 240 + border: 1px solid var(--border-primary); 241 + box-shadow: var(--shadow-md); 242 flex-shrink: 0; 243 } 244 ··· 246 font-size: 16px; 247 font-weight: 600; 248 padding: 16px 20px; 249 + border-bottom: 1px solid var(--border-primary); 250 + color: var(--text-heading); 251 display: flex; 252 align-items: center; 253 justify-content: space-between; ··· 255 256 .repo-info { 257 padding: 20px; 258 } 259 260 .repo-info h3 { 261 font-size: 14px; 262 font-weight: 600; 263 margin-bottom: 12px; 264 + color: var(--text-tertiary); 265 } 266 267 .repo-info .label { 268 font-size: 12px; 269 + color: var(--text-tertiary); 270 margin-bottom: 4px; 271 font-weight: 500; 272 text-transform: uppercase; ··· 275 276 .repo-info .value { 277 font-size: 13px; 278 + color: var(--text-primary); 279 margin-bottom: 12px; 280 + font-family: IBMPlexMono, ui-monospace, monospace; 281 } 282 283 .clone-url { 284 display: flex; 285 align-items: center; 286 gap: 8px; 287 + background: var(--bg-tertiary); 288 padding: 8px 12px; 289 border-radius: 6px; 290 + border: 1px solid var(--border-primary); 291 margin-bottom: 12px; 292 } 293 294 .clone-url code { 295 flex: 1; 296 font-size: 12px; 297 + color: var(--text-secondary); 298 overflow: hidden; 299 text-overflow: ellipsis; 300 } ··· 306 } 307 308 .copy-btn:hover { 309 + background: var(--accent-hover); 310 } 311 312 .branches-section { 313 + border-top: 1px solid var(--border-primary); 314 } 315 316 .branch-list { ··· 322 padding: 10px 20px; 323 cursor: pointer; 324 transition: background 0.15s; 325 + border-bottom: 1px solid var(--border-light); 326 font-size: 13px; 327 + color: var(--text-secondary); 328 display: flex; 329 align-items: center; 330 gap: 8px; 331 } 332 333 .branch-item:hover { 334 + background: var(--bg-hover); 335 } 336 337 .branch-item.active { 338 + background: var(--accent-light); 339 + color: var(--accent-primary); 340 font-weight: 500; 341 } 342 343 .viewer { 344 flex: 1; 345 + background: var(--bg-secondary); 346 border-radius: 8px; 347 + border: 1px solid var(--border-primary); 348 + box-shadow: var(--shadow-md); 349 overflow: hidden; 350 } 351 352 .breadcrumb { 353 padding: 16px 20px; 354 + border-bottom: 1px solid var(--border-primary); 355 font-size: 13px; 356 + color: var(--text-tertiary); 357 + background: var(--bg-tertiary); 358 display: flex; 359 align-items: center; 360 flex-wrap: wrap; 361 } 362 363 .breadcrumb a { 364 + color: var(--accent-primary); 365 text-decoration: none; 366 transition: color 0.15s; 367 cursor: pointer; 368 } 369 370 .breadcrumb a:hover { 371 + color: var(--accent-hover); 372 text-decoration: underline; 373 } 374 ··· 377 } 378 379 .breadcrumb .current { 380 + color: var(--text-primary); 381 font-weight: 500; 382 } 383 ··· 392 display: flex; 393 align-items: center; 394 gap: 12px; 395 + border-bottom: 1px solid var(--border-light); 396 cursor: pointer !important; 397 } 398 ··· 401 } 402 403 .file-item:hover { 404 + background: var(--bg-hover); 405 } 406 407 .file-icon { 408 width: 20px; 409 height: 20px; 410 flex-shrink: 0; 411 + color: var(--text-tertiary); 412 cursor: pointer; 413 } 414 415 .file-name { 416 flex: 1; 417 + color: var(--text-primary); 418 font-size: 14px; 419 cursor: pointer; 420 } 421 422 .file-size { 423 + color: var(--text-tertiary); 424 font-size: 12px; 425 cursor: pointer; 426 } ··· 428 .file-content { 429 padding: 0; 430 overflow-x: auto; 431 + background: var(--code-block-bg); 432 + font-family: IBMPlexMono, Monaco, Menlo, monospace; 433 font-size: 13px; 434 } 435 ··· 452 .line-numbers { 453 display: flex; 454 gap: 0; 455 + background: var(--code-block-bg); 456 } 457 458 .line-numbers .numbers { 459 + color: var(--code-block-line-numbers); 460 text-align: right; 461 user-select: none; 462 min-width: 50px; 463 padding: 20px 16px 20px 20px; 464 + border-right: 1px solid var(--code-block-border); 465 + background: var(--code-block-bg); 466 line-height: 1.5; 467 } 468 ··· 474 .loading { 475 padding: 40px; 476 text-align: center; 477 + color: var(--text-tertiary); 478 } 479 480 .spinner { 481 width: 40px; 482 height: 40px; 483 margin: 0 auto 16px; 484 + border: 3px solid var(--border-primary); 485 + border-top-color: var(--accent-primary); 486 border-radius: 50%; 487 animation: spin 0.8s linear infinite; 488 } ··· 502 width: 64px; 503 height: 64px; 504 margin: 0 auto 20px; 505 + color: var(--text-tertiary); 506 display: block; 507 } 508 509 .empty-state h3 { 510 font-size: 18px; 511 + color: var(--text-secondary); 512 margin-bottom: 8px; 513 } 514 515 .empty-state p { 516 + color: var(--text-tertiary); 517 font-size: 14px; 518 } 519 520 + .welcome-hero { 521 + padding: 80px 40px; 522 + text-align: center; 523 + max-width: 700px; 524 + margin: 0 auto; 525 + } 526 + 527 + .welcome-hero svg { 528 + width: 96px; 529 + height: 96px; 530 + margin: 0 auto 32px; 531 + color: var(--accent-primary); 532 + display: block; 533 + } 534 + 535 + .welcome-hero h2 { 536 + font-size: 32px; 537 + color: var(--text-heading); 538 + margin-bottom: 16px; 539 + font-weight: 700; 540 + } 541 + 542 + .welcome-hero .subtitle { 543 + font-size: 18px; 544 + color: var(--text-secondary); 545 + margin-bottom: 48px; 546 + line-height: 1.6; 547 + } 548 + 549 + .feature-list { 550 + display: grid; 551 + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); 552 + gap: 24px; 553 + margin-top: 48px; 554 + text-align: left; 555 + } 556 + 557 + .feature-item { 558 + padding: 20px; 559 + background: var(--bg-tertiary); 560 + border-radius: 8px; 561 + border: 1px solid var(--border-primary); 562 + } 563 + 564 + .feature-item h4 { 565 + font-size: 16px; 566 + color: var(--text-heading); 567 + margin-bottom: 8px; 568 + display: flex; 569 + align-items: center; 570 + gap: 8px; 571 + } 572 + 573 + .feature-item p { 574 + font-size: 14px; 575 + color: var(--text-tertiary); 576 + line-height: 1.5; 577 + margin: 0; 578 + } 579 + 580 + .getting-started { 581 + margin-top: 48px; 582 + padding: 24px; 583 + background: var(--bg-tertiary); 584 + border-radius: 8px; 585 + border: 1px solid var(--border-primary); 586 + text-align: left; 587 + } 588 + 589 + .getting-started h3 { 590 + font-size: 18px; 591 + color: var(--text-heading); 592 + margin-bottom: 16px; 593 + } 594 + 595 + .getting-started ol { 596 + margin-left: 20px; 597 + color: var(--text-secondary); 598 + } 599 + 600 + .getting-started li { 601 + margin-bottom: 8px; 602 + line-height: 1.6; 603 + } 604 + 605 .error-message { 606 padding: 40px; 607 text-align: center; 608 + color: var(--error-text); 609 + background: var(--error-bg); 610 margin: 20px; 611 border-radius: 8px; 612 + border: 1px solid var(--error-border); 613 } 614 615 .file-header { 616 padding: 16px 20px; 617 + border-bottom: 1px solid var(--border-primary); 618 + background: var(--bg-tertiary); 619 display: flex; 620 justify-content: space-between; 621 align-items: center; ··· 623 624 .file-header h3 { 625 font-size: 15px; 626 + color: var(--text-primary); 627 font-weight: 600; 628 } 629 ··· 644 .user-header { 645 font-size: 16px; 646 font-weight: 600; 647 + color: var(--text-heading); 648 margin-bottom: 12px; 649 padding: 12px; 650 + background: var(--bg-tertiary); 651 border-radius: 6px; 652 } 653 654 .repo-item { 655 padding: 12px; 656 margin-bottom: 8px; 657 + background: var(--bg-secondary); 658 + border: 1px solid var(--border-primary); 659 border-radius: 6px; 660 cursor: pointer; 661 transition: all 0.15s; 662 } 663 664 .repo-item:hover { 665 + border-color: var(--accent-primary); 666 box-shadow: 0 2px 4px rgba(59, 130, 246, 0.1); 667 } 668 669 .repo-item strong { 670 display: block; 671 font-size: 14px; 672 + color: var(--text-primary); 673 margin-bottom: 4px; 674 } 675 676 .repo-item small { 677 font-size: 12px; 678 + color: var(--text-tertiary); 679 + font-family: IBMPlexMono, monospace; 680 } 681 682 .markdown-content { 683 padding: 20px 40px; 684 + background: var(--bg-secondary); 685 + font-family: InterVariable, system-ui, sans-serif; 686 font-size: 15px; 687 line-height: 1.6; 688 + color: var(--text-primary); 689 } 690 691 .markdown-content h1, ··· 698 margin-bottom: 16px; 699 font-weight: 600; 700 line-height: 1.25; 701 + color: var(--text-heading); 702 } 703 704 .markdown-content h1 { 705 font-size: 2em; 706 padding-bottom: 0.3em; 707 + border-bottom: 1px solid var(--border-primary); 708 } 709 710 .markdown-content h2 { 711 font-size: 1.5em; 712 padding-bottom: 0.3em; 713 + border-bottom: 1px solid var(--border-primary); 714 } 715 716 .markdown-content h3 { ··· 727 728 .markdown-content h6 { 729 font-size: 0.85em; 730 + color: var(--text-tertiary); 731 } 732 733 .markdown-content p { ··· 750 padding: 0.2em 0.4em; 751 margin: 0; 752 font-size: 85%; 753 + background: var(--code-bg); 754 border-radius: 6px; 755 + font-family: IBMPlexMono, Monaco, Menlo, monospace; 756 + color: var(--code-text); 757 } 758 759 .markdown-content pre { ··· 761 overflow: auto; 762 font-size: 85%; 763 line-height: 1.45; 764 + background: var(--code-block-bg); 765 border-radius: 6px; 766 margin-bottom: 16px; 767 } ··· 775 word-wrap: normal; 776 background: transparent; 777 border: 0; 778 + color: var(--code-block-text); 779 } 780 781 .markdown-content pre code.hljs { ··· 784 785 .markdown-content blockquote { 786 padding: 0 1em; 787 + color: var(--text-tertiary); 788 + border-left: 0.25em solid var(--border-secondary); 789 margin: 0 0 16px 0; 790 } 791 ··· 808 .markdown-content table th, 809 .markdown-content table td { 810 padding: 6px 13px; 811 + border: 1px solid var(--border-primary); 812 } 813 814 .markdown-content table th { 815 font-weight: 600; 816 + background: var(--bg-tertiary); 817 } 818 819 .markdown-content table tr { 820 + background: var(--bg-secondary); 821 + border-top: 1px solid var(--border-primary); 822 } 823 824 .markdown-content table tr:nth-child(2n) { 825 + background: var(--bg-tertiary); 826 } 827 828 .markdown-content img { ··· 832 } 833 834 .markdown-content a { 835 + color: var(--accent-primary); 836 text-decoration: none; 837 } 838 ··· 844 height: 0.25em; 845 padding: 0; 846 margin: 24px 0; 847 + background-color: var(--border-primary); 848 border: 0; 849 } 850 ··· 853 flex-direction: column; 854 } 855 856 + .sidebar { 857 + width: 100%; 858 + } 859 + 860 .connection-panel { 861 flex-direction: column; 862 } ··· 867 868 .markdown-content { 869 padding: 20px; 870 + } 871 + 872 + .welcome-hero { 873 + padding: 40px 20px; 874 } 875 }