[READ-ONLY] a fast, modern browser for the npm registry
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: light theme (#172)

authored by

Jaydip Sanghani and committed by
GitHub
3c847086 1da4592c

+606 -478
-424
app/app.vue
··· 63 63 <ScrollToTop /> 64 64 </div> 65 65 </template> 66 - 67 - <style lang="postcss"> 68 - /* Base reset and defaults */ 69 - *, 70 - *::before, 71 - *::after { 72 - box-sizing: border-box; 73 - } 74 - 75 - html { 76 - -webkit-font-smoothing: antialiased; 77 - -moz-osx-font-smoothing: grayscale; 78 - text-rendering: optimizeLegibility; 79 - } 80 - 81 - /* 82 - * Enable CSS scroll-state container queries for the document 83 - * This allows the footer to query the scroll state using pure CSS 84 - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@container#scroll-state_container_descriptors 85 - */ 86 - @supports (container-type: scroll-state) { 87 - html { 88 - container-type: scroll-state; 89 - } 90 - } 91 - 92 - body { 93 - margin: 0; 94 - background-color: #0a0a0a; 95 - color: #fafafa; 96 - line-height: 1.6; 97 - padding-bottom: var(--footer-height, 0); 98 - } 99 - 100 - /* Default link styling for accessibility on dark background */ 101 - a { 102 - color: #fafafa; 103 - text-decoration: underline; 104 - text-underline-offset: 3px; 105 - text-decoration-color: #404040; 106 - transition: 107 - color 0.2s ease, 108 - text-decoration-color 0.2s ease; 109 - } 110 - 111 - a:hover { 112 - color: #ffffff; 113 - text-decoration-color: #a1a1a1; 114 - } 115 - 116 - a:focus-visible { 117 - outline: 2px solid rgba(250, 250, 250, 0.2); 118 - outline-offset: 2px; 119 - border-radius: 2px; 120 - } 121 - 122 - /* Reset dd margin (browser default is margin-left: 40px) */ 123 - dd { 124 - margin: 0; 125 - } 126 - 127 - /* Reset button styles */ 128 - button { 129 - background: transparent; 130 - border: none; 131 - cursor: pointer; 132 - font: inherit; 133 - padding: 0; 134 - } 135 - 136 - /* Selection */ 137 - ::selection { 138 - background-color: rgba(255, 255, 255, 0.15); 139 - } 140 - 141 - /* Scrollbar styling */ 142 - ::-webkit-scrollbar { 143 - width: 8px; 144 - height: 8px; 145 - } 146 - 147 - ::-webkit-scrollbar-track { 148 - background: #0a0a0a; 149 - } 150 - 151 - ::-webkit-scrollbar-thumb { 152 - background: #262626; 153 - border-radius: 4px; 154 - } 155 - 156 - ::-webkit-scrollbar-thumb:hover { 157 - background: #404040; 158 - } 159 - 160 - /* Skip link */ 161 - .skip-link { 162 - position: absolute; 163 - top: -100%; 164 - left: 0; 165 - padding: 0.5rem 1rem; 166 - background: #fafafa; 167 - color: #0a0a0a; 168 - font-size: 0.875rem; 169 - z-index: 100; 170 - transition: top 0.2s ease; 171 - } 172 - 173 - .skip-link:focus { 174 - top: 0; 175 - } 176 - 177 - /* README prose styling */ 178 - .readme-content { 179 - color: #a1a1a1; 180 - line-height: 1.75; 181 - /* Prevent horizontal overflow on mobile */ 182 - overflow-wrap: break-word; 183 - word-wrap: break-word; 184 - word-break: break-word; 185 - /* Contain all children */ 186 - overflow: hidden; 187 - min-width: 0; 188 - } 189 - 190 - /* README headings - styled by visual level (data-level), not semantic level */ 191 - .readme-content h3, 192 - .readme-content h4, 193 - .readme-content h5, 194 - .readme-content h6 { 195 - color: #fafafa; 196 - @apply font-mono; 197 - font-weight: 500; 198 - margin-top: 2rem; 199 - margin-bottom: 1rem; 200 - line-height: 1.3; 201 - 202 - a { 203 - text-decoration: none; 204 - } 205 - } 206 - 207 - /* Visual styling based on original README heading level */ 208 - .readme-content [data-level='1'] { 209 - font-size: 1.5rem; 210 - } 211 - .readme-content [data-level='2'] { 212 - font-size: 1.25rem; 213 - padding-bottom: 0.5rem; 214 - border-bottom: 1px solid #262626; 215 - } 216 - .readme-content [data-level='3'] { 217 - font-size: 1.125rem; 218 - } 219 - .readme-content [data-level='4'] { 220 - font-size: 1rem; 221 - } 222 - .readme-content [data-level='5'] { 223 - font-size: 0.925rem; 224 - } 225 - .readme-content [data-level='6'] { 226 - font-size: 0.875rem; 227 - } 228 - 229 - .readme-content p { 230 - margin-bottom: 1rem; 231 - } 232 - 233 - .readme-content a { 234 - color: #fafafa; 235 - text-decoration: underline; 236 - text-underline-offset: 4px; 237 - text-decoration-color: #404040; 238 - transition: text-decoration-color 0.2s ease; 239 - } 240 - 241 - .readme-content a:hover { 242 - text-decoration-color: #fafafa; 243 - } 244 - 245 - .readme-content code { 246 - @apply font-mono; 247 - font-size: 0.875em; 248 - background: #1a1a1a; 249 - padding: 0.2em 0.4em; 250 - border-radius: 4px; 251 - border: 1px solid #262626; 252 - } 253 - 254 - /* Code blocks - including Shiki output */ 255 - .readme-content pre, 256 - .readme-content .shiki { 257 - background: #111111 !important; 258 - border: 1px solid #262626; 259 - border-radius: 8px; 260 - padding: 1rem; 261 - overflow-x: auto; 262 - margin: 1.5rem 0; 263 - /* Fix horizontal overflow */ 264 - max-width: 100%; 265 - box-sizing: border-box; 266 - } 267 - 268 - .readme-content pre code, 269 - .readme-content .shiki code { 270 - background: transparent !important; 271 - border: none; 272 - padding: 0; 273 - @apply font-mono; 274 - font-size: 0.875rem; 275 - color: #fafafa; 276 - /* Prevent code from forcing width */ 277 - white-space: pre; 278 - word-break: normal; 279 - overflow-wrap: normal; 280 - } 281 - 282 - .readme-content ul, 283 - .readme-content ol { 284 - margin: 1rem 0; 285 - padding-left: 1.5rem; 286 - } 287 - 288 - .readme-content ul { 289 - list-style-type: disc; 290 - } 291 - 292 - .readme-content ol { 293 - list-style-type: decimal; 294 - } 295 - 296 - .readme-content li { 297 - margin-bottom: 0.5rem; 298 - display: list-item; 299 - } 300 - 301 - .readme-content li::marker { 302 - color: #404040; 303 - } 304 - 305 - .readme-content blockquote { 306 - border-left: 2px solid #262626; 307 - padding-left: 1rem; 308 - margin: 1.5rem 0; 309 - color: #8a8a8a; 310 - font-style: italic; 311 - } 312 - 313 - /* GitHub-style callouts/alerts */ 314 - .readme-content blockquote[data-callout] { 315 - border-left-width: 3px; 316 - border-radius: 6px; 317 - padding: 1rem 1rem 1rem 1.25rem; 318 - background: #111111; 319 - font-style: normal; 320 - color: #a1a1a1; 321 - } 322 - 323 - .readme-content blockquote[data-callout]::before { 324 - display: block; 325 - @apply font-mono; 326 - font-size: 0.75rem; 327 - font-weight: 500; 328 - text-transform: uppercase; 329 - letter-spacing: 0.05em; 330 - margin-bottom: 0.5rem; 331 - } 332 - 333 - .readme-content blockquote[data-callout] > p:first-child { 334 - margin-top: 0; 335 - } 336 - 337 - .readme-content blockquote[data-callout] > p:last-child { 338 - margin-bottom: 0; 339 - } 340 - 341 - /* Note - blue */ 342 - .readme-content blockquote[data-callout='note'] { 343 - border-left-color: #3b82f6; 344 - background: rgba(59, 130, 246, 0.05); 345 - } 346 - .readme-content blockquote[data-callout='note']::before { 347 - content: 'Note'; 348 - color: #3b82f6; 349 - } 350 - 351 - /* Tip - green */ 352 - .readme-content blockquote[data-callout='tip'] { 353 - border-left-color: #22c55e; 354 - background: rgba(34, 197, 94, 0.05); 355 - } 356 - .readme-content blockquote[data-callout='tip']::before { 357 - content: 'Tip'; 358 - color: #22c55e; 359 - } 360 - 361 - /* Important - purple */ 362 - .readme-content blockquote[data-callout='important'] { 363 - border-left-color: #a855f7; 364 - background: rgba(168, 85, 247, 0.05); 365 - } 366 - .readme-content blockquote[data-callout='important']::before { 367 - content: 'Important'; 368 - color: #a855f7; 369 - } 370 - 371 - /* Warning - yellow/orange */ 372 - .readme-content blockquote[data-callout='warning'] { 373 - border-left-color: #eab308; 374 - background: rgba(234, 179, 8, 0.05); 375 - } 376 - .readme-content blockquote[data-callout='warning']::before { 377 - content: 'Warning'; 378 - color: #eab308; 379 - } 380 - 381 - /* Caution - red */ 382 - .readme-content blockquote[data-callout='caution'] { 383 - border-left-color: #ef4444; 384 - background: rgba(239, 68, 68, 0.05); 385 - } 386 - .readme-content blockquote[data-callout='caution']::before { 387 - content: 'Caution'; 388 - color: #ef4444; 389 - } 390 - 391 - /* Table wrapper for horizontal scroll on mobile */ 392 - .readme-content table { 393 - display: block; 394 - width: 100%; 395 - overflow-x: auto; 396 - border-collapse: collapse; 397 - margin: 1.5rem 0; 398 - font-size: 0.875rem; 399 - } 400 - 401 - .readme-content th, 402 - .readme-content td { 403 - border: 1px solid #262626; 404 - padding: 0.75rem 1rem; 405 - text-align: left; 406 - } 407 - 408 - .readme-content th { 409 - background: #111111; 410 - color: #fafafa; 411 - font-weight: 500; 412 - } 413 - 414 - .readme-content tr:hover { 415 - background: #111111; 416 - } 417 - 418 - .readme-content img { 419 - max-width: 100%; 420 - height: auto; 421 - border-radius: 8px; 422 - margin: 1rem 0; 423 - } 424 - 425 - .readme-content hr { 426 - border: none; 427 - border-top: 1px solid #262626; 428 - margin: 2rem 0; 429 - } 430 - 431 - /* Badge images inline */ 432 - .readme-content p > a > img, 433 - .readme-content p > img { 434 - display: inline-block; 435 - margin: 0 0.25rem 0.25rem 0; 436 - border-radius: 4px; 437 - } 438 - 439 - /* Inline code in package descriptions */ 440 - p > span > code, 441 - .line-clamp-2 code { 442 - @apply font-mono; 443 - font-size: 0.85em; 444 - background: #1a1a1a; 445 - padding: 0.1em 0.3em; 446 - border-radius: 3px; 447 - border: 1px solid #262626; 448 - } 449 - 450 - /* View transition for search box (includes / and input) */ 451 - .search-box { 452 - view-transition-name: search-box; 453 - } 454 - 455 - /* Safari search input fixes */ 456 - input[type='search'] { 457 - -webkit-appearance: none; 458 - appearance: none; 459 - } 460 - 461 - input[type='search']::-webkit-search-decoration, 462 - input[type='search']::-webkit-search-cancel-button, 463 - input[type='search']::-webkit-search-results-button, 464 - input[type='search']::-webkit-search-results-decoration { 465 - -webkit-appearance: none; 466 - appearance: none; 467 - } 468 - 469 - /* View transition for logo (hero -> header) */ 470 - .hero-logo, 471 - .header-logo { 472 - view-transition-name: site-logo; 473 - } 474 - 475 - /* Disable the default fade transition on page navigation */ 476 - ::view-transition-old(root), 477 - ::view-transition-new(root) { 478 - animation: none; 479 - } 480 - 481 - /* Customize the view transition animations for specific elements */ 482 - ::view-transition-old(search-box), 483 - ::view-transition-new(search-box), 484 - ::view-transition-old(site-logo), 485 - ::view-transition-new(site-logo) { 486 - animation-duration: 0.3s; 487 - animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); 488 - } 489 - </style>
+470
app/assets/main.css
··· 1 + /* Base reset and defaults */ 2 + *, 3 + *::before, 4 + *::after { 5 + box-sizing: border-box; 6 + } 7 + 8 + :root[data-theme='dark'] { 9 + /* background colors */ 10 + --bg: oklch(0.145 0 0); 11 + --bg-subtle: oklch(0.178 0 0); 12 + --bg-muted: oklch(0.218 0 0); 13 + --bg-elevated: oklch(0.252 0 0); 14 + 15 + /* text colors */ 16 + --fg: oklch(0.985 0 0); 17 + --fg-muted: oklch(0.709 0 0); 18 + --fg-subtle: oklch(0.633 0 0); 19 + 20 + /* border, seperator colors */ 21 + --border: oklch(0.269 0 0); 22 + --border-subtle: oklch(0.239 0 0); 23 + --border-hover: oklch(0.371 0 0); 24 + 25 + --accent: var(--accent-color, oklch(1 0 0)); 26 + --accent-muted: var(--accent-color, oklch(0.922 0 0)); 27 + 28 + --syntax-fn: oklch(0.727 0.137 299.149); 29 + --syntax-str: oklch(0.829 0.088 252.458); 30 + --syntax-kw: oklch(0.721 0.162 15.494); 31 + --syntax-comment: oklch(0.551 0.019 250.976); 32 + } 33 + 34 + :root[data-theme='light'] { 35 + --bg: oklch(1 0 0); 36 + --bg-subtle: oklch(0.979 0.001 286.375); 37 + --bg-muted: oklch(0.979 0.001 286.375 / 90%); 38 + --bg-elevated: oklch(0.955 0 0); 39 + 40 + --fg: oklch(0.145 0 0); 41 + --fg-muted: oklch(0.439 0 0); 42 + --fg-subtle: oklch(0.52 0 0); 43 + 44 + --border: oklch(0.8514 0 0); 45 + --border-subtle: oklch(0.922 0 0); 46 + --border-hover: oklch(0.715 0 0); 47 + 48 + --accent: var(--accent-color, oklch(0.145 0 0)); 49 + --accent-muted: var(--accent-color, oklch(0.205 0 0)); 50 + 51 + --syntax-fn: oklch(0.502 0.188 294.988); 52 + --syntax-str: oklch(0.54 0.191 257.481); 53 + --syntax-kw: oklch(0.588 0.193 20.469); 54 + --syntax-comment: oklch(0.551 0.019 250.976); 55 + } 56 + 57 + html { 58 + -webkit-font-smoothing: antialiased; 59 + -moz-osx-font-smoothing: grayscale; 60 + text-rendering: optimizeLegibility; 61 + } 62 + 63 + /* 64 + * Enable CSS scroll-state container queries for the document 65 + * This allows the footer to query the scroll state using pure CSS 66 + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@container#scroll-state_container_descriptors 67 + */ 68 + @supports (container-type: scroll-state) { 69 + html { 70 + container-type: scroll-state; 71 + } 72 + } 73 + 74 + body { 75 + margin: 0; 76 + background-color: var(--bg); 77 + color: var(--fg); 78 + line-height: 1.6; 79 + padding-bottom: var(--footer-height, 0); 80 + } 81 + 82 + /* Default link styling for accessibility on dark background */ 83 + a { 84 + color: var(--fg); 85 + text-decoration: underline; 86 + text-underline-offset: 3px; 87 + text-decoration-color: var(--fg-subtle); 88 + transition: 89 + color 0.2s ease, 90 + text-decoration-color 0.2s ease; 91 + } 92 + 93 + a:hover { 94 + color: var(--accent); 95 + text-decoration-color: var(--accent); 96 + } 97 + 98 + a:focus-visible { 99 + outline: 2px solid var(--border); 100 + outline-offset: 2px; 101 + border-radius: 2px; 102 + } 103 + 104 + /* Reset dd margin (browser default is margin-left: 40px) */ 105 + dd { 106 + margin: 0; 107 + } 108 + 109 + /* Reset button styles */ 110 + button { 111 + background: transparent; 112 + border: none; 113 + cursor: pointer; 114 + font: inherit; 115 + padding: 0; 116 + } 117 + 118 + /* Selection */ 119 + ::selection { 120 + background-color: var(--fg-muted); 121 + color: var(--bg-subtle); 122 + } 123 + 124 + /* Scrollbar styling */ 125 + ::-webkit-scrollbar { 126 + width: 8px; 127 + height: 8px; 128 + } 129 + 130 + ::-webkit-scrollbar-track { 131 + background: var(--bg); 132 + } 133 + 134 + ::-webkit-scrollbar-thumb { 135 + background: var(--border); 136 + border-radius: 4px; 137 + } 138 + 139 + ::-webkit-scrollbar-thumb:hover { 140 + background: #404040; 141 + } 142 + 143 + /* Skip link */ 144 + .skip-link { 145 + position: absolute; 146 + top: -100%; 147 + left: 0; 148 + padding: 0.5rem 1rem; 149 + background: var(--fg); 150 + color: var(--bg); 151 + font-size: 0.875rem; 152 + z-index: 100; 153 + transition: top 0.2s ease; 154 + } 155 + 156 + .skip-link:focus { 157 + top: 0; 158 + } 159 + 160 + /* README prose styling */ 161 + .readme-content { 162 + color: var(--fg-muted); 163 + line-height: 1.75; 164 + /* Prevent horizontal overflow on mobile */ 165 + overflow-wrap: break-word; 166 + word-wrap: break-word; 167 + word-break: break-word; 168 + /* Contain all children */ 169 + overflow: hidden; 170 + min-width: 0; 171 + } 172 + 173 + /* README headings - styled by visual level (data-level), not semantic level */ 174 + .readme-content h3, 175 + .readme-content h4, 176 + .readme-content h5, 177 + .readme-content h6 { 178 + color: var(--fg); 179 + @apply font-mono; 180 + font-weight: 500; 181 + margin-top: 2rem; 182 + margin-bottom: 1rem; 183 + line-height: 1.3; 184 + 185 + a { 186 + text-decoration: none; 187 + } 188 + } 189 + 190 + /* Visual styling based on original README heading level */ 191 + .readme-content [data-level='1'] { 192 + font-size: 1.5rem; 193 + } 194 + .readme-content [data-level='2'] { 195 + font-size: 1.25rem; 196 + padding-bottom: 0.5rem; 197 + border-bottom: 1px solid var(--border); 198 + } 199 + .readme-content [data-level='3'] { 200 + font-size: 1.125rem; 201 + } 202 + .readme-content [data-level='4'] { 203 + font-size: 1rem; 204 + } 205 + .readme-content [data-level='5'] { 206 + font-size: 0.925rem; 207 + } 208 + .readme-content [data-level='6'] { 209 + font-size: 0.875rem; 210 + } 211 + 212 + .readme-content p { 213 + margin-bottom: 1rem; 214 + } 215 + 216 + .readme-content a { 217 + color: var(--fg); 218 + text-decoration: underline; 219 + text-underline-offset: 4px; 220 + text-decoration-color: var(--fg-subtle); 221 + transition: text-decoration-color 0.2s ease; 222 + } 223 + 224 + .readme-content a:hover { 225 + text-decoration-color: var(--accent); 226 + } 227 + 228 + .readme-content code { 229 + @apply font-mono; 230 + font-size: 0.875em; 231 + background: var(--bg-muted); 232 + padding: 0.2em 0.4em; 233 + border-radius: 4px; 234 + border: 1px solid var(--border); 235 + } 236 + 237 + /* Code blocks - including Shiki output */ 238 + .readme-content pre, 239 + .readme-content .shiki { 240 + background: oklch(0.145 0 0) !important; 241 + border: 1px solid oklch(0.2686 0 0); 242 + border-radius: 8px; 243 + padding: 1rem; 244 + overflow-x: auto; 245 + margin: 1.5rem 0; 246 + /* Fix horizontal overflow */ 247 + max-width: 100%; 248 + box-sizing: border-box; 249 + } 250 + 251 + .readme-content pre code, 252 + .readme-content .shiki code { 253 + background: transparent !important; 254 + border: none; 255 + padding: 0; 256 + @apply font-mono; 257 + font-size: 0.875rem; 258 + color: var(--fg); 259 + /* Prevent code from forcing width */ 260 + white-space: pre; 261 + word-break: normal; 262 + overflow-wrap: normal; 263 + } 264 + 265 + .readme-content ul, 266 + .readme-content ol { 267 + margin: 1rem 0; 268 + padding-left: 1.5rem; 269 + } 270 + 271 + .readme-content ul { 272 + list-style-type: disc; 273 + } 274 + 275 + .readme-content ol { 276 + list-style-type: decimal; 277 + } 278 + 279 + .readme-content li { 280 + margin-bottom: 0.5rem; 281 + display: list-item; 282 + } 283 + 284 + .readme-content li::marker { 285 + color: var(--border-hover); 286 + } 287 + 288 + .readme-content blockquote { 289 + border-left: 2px solid var(--border); 290 + padding-left: 1rem; 291 + margin: 1.5rem 0; 292 + color: var(--fg-subtle); 293 + font-style: italic; 294 + } 295 + 296 + /* GitHub-style callouts/alerts */ 297 + .readme-content blockquote[data-callout] { 298 + border-left-width: 3px; 299 + padding: 1rem 1rem 1rem 1.25rem; 300 + background: var(--bg-subtle); 301 + font-style: normal; 302 + color: var(--fg-subtle); 303 + } 304 + 305 + .readme-content blockquote[data-callout]::before { 306 + display: block; 307 + @apply font-mono; 308 + font-size: 0.75rem; 309 + font-weight: 500; 310 + text-transform: uppercase; 311 + letter-spacing: 0.05em; 312 + margin-bottom: 0.5rem; 313 + } 314 + 315 + .readme-content blockquote[data-callout] > p:first-child { 316 + margin-top: 0; 317 + } 318 + 319 + .readme-content blockquote[data-callout] > p:last-child { 320 + margin-bottom: 0; 321 + } 322 + 323 + /* Note - blue */ 324 + .readme-content blockquote[data-callout='note'] { 325 + border-left-color: var(--syntax-str); 326 + background: rgba(59, 130, 246, 0.05); 327 + } 328 + .readme-content blockquote[data-callout='note']::before { 329 + content: 'Note'; 330 + color: #3b82f6; 331 + } 332 + 333 + /* Tip - green */ 334 + .readme-content blockquote[data-callout='tip'] { 335 + border-left-color: #22c55e; 336 + background: rgba(34, 197, 94, 0.05); 337 + } 338 + .readme-content blockquote[data-callout='tip']::before { 339 + content: 'Tip'; 340 + color: #22c55e; 341 + } 342 + 343 + /* Important - purple */ 344 + .readme-content blockquote[data-callout='important'] { 345 + border-left-color: var(--syntax-fn); 346 + background: rgba(168, 85, 247, 0.05); 347 + } 348 + .readme-content blockquote[data-callout='important']::before { 349 + content: 'Important'; 350 + color: var(--syntax-fn); 351 + } 352 + 353 + /* Warning - yellow/orange */ 354 + .readme-content blockquote[data-callout='warning'] { 355 + border-left-color: #eab308; 356 + background: rgba(234, 179, 8, 0.05); 357 + } 358 + .readme-content blockquote[data-callout='warning']::before { 359 + content: 'Warning'; 360 + color: #eab308; 361 + } 362 + 363 + /* Caution - red */ 364 + .readme-content blockquote[data-callout='caution'] { 365 + border-left-color: #ef4444; 366 + background: rgba(239, 68, 68, 0.05); 367 + } 368 + .readme-content blockquote[data-callout='caution']::before { 369 + content: 'Caution'; 370 + color: #ef4444; 371 + } 372 + 373 + /* Table wrapper for horizontal scroll on mobile */ 374 + .readme-content table { 375 + display: block; 376 + width: 100%; 377 + overflow-x: auto; 378 + border-collapse: collapse; 379 + margin: 1.5rem 0; 380 + font-size: 0.875rem; 381 + } 382 + 383 + .readme-content th, 384 + .readme-content td { 385 + border: 1px solid var(--border); 386 + padding: 0.75rem 1rem; 387 + text-align: left; 388 + } 389 + 390 + .readme-content th { 391 + background: var(--bg-subtle); 392 + color: var(--fg); 393 + font-weight: 500; 394 + } 395 + 396 + .readme-content tr:hover { 397 + background: var(--bg-subtle); 398 + } 399 + 400 + .readme-content img { 401 + max-width: 100%; 402 + height: auto; 403 + border-radius: 8px; 404 + margin: 1rem 0; 405 + } 406 + 407 + .readme-content hr { 408 + border: none; 409 + border-top: 1px solid var(--border); 410 + margin: 2rem 0; 411 + } 412 + 413 + /* Badge images inline */ 414 + .readme-content p > a > img, 415 + .readme-content p > img { 416 + display: inline-block; 417 + margin: 0 0.25rem 0.25rem 0; 418 + border-radius: 4px; 419 + } 420 + 421 + /* Inline code in package descriptions */ 422 + p > span > code, 423 + .line-clamp-2 code { 424 + @apply font-mono; 425 + font-size: 0.85em; 426 + background: var(--bg-muted); 427 + padding: 0.1em 0.3em; 428 + border-radius: 3px; 429 + border: 1px solid var(--border); 430 + } 431 + 432 + /* View transition for search box (includes / and input) */ 433 + .search-box { 434 + view-transition-name: search-box; 435 + } 436 + 437 + /* Safari search input fixes */ 438 + input[type='search'] { 439 + -webkit-appearance: none; 440 + appearance: none; 441 + } 442 + 443 + input[type='search']::-webkit-search-decoration, 444 + input[type='search']::-webkit-search-cancel-button, 445 + input[type='search']::-webkit-search-results-button, 446 + input[type='search']::-webkit-search-results-decoration { 447 + -webkit-appearance: none; 448 + appearance: none; 449 + } 450 + 451 + /* View transition for logo (hero -> header) */ 452 + .hero-logo, 453 + .header-logo { 454 + view-transition-name: site-logo; 455 + } 456 + 457 + /* Disable the default fade transition on page navigation */ 458 + ::view-transition-old(root), 459 + ::view-transition-new(root) { 460 + animation: none; 461 + } 462 + 463 + /* Customize the view transition animations for specific elements */ 464 + ::view-transition-old(search-box), 465 + ::view-transition-new(search-box), 466 + ::view-transition-old(site-logo), 467 + ::view-transition-new(site-logo) { 468 + animation-duration: 0.3s; 469 + animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); 470 + }
+32 -9
app/components/PackageWeeklyDownloadStats.vue
··· 56 56 style: { 57 57 backgroundColor: 'transparent', 58 58 animation: { show: false }, 59 - area: { color: '#6A6A6A', useGradient: false, opacity: 10 }, 60 - dataLabel: { offsetX: -10, fontSize: 28, bold: false, color: '#FAFAFA' }, 59 + area: { 60 + color: 'oklch(0.5243 0 0)', // css variable doesn't seem to work here 61 + useGradient: false, 62 + opacity: 10, 63 + }, 64 + dataLabel: { 65 + offsetX: -10, 66 + fontSize: 28, 67 + bold: false, 68 + color: 'var(--fg)', 69 + }, 61 70 line: { 62 - color: '#6A6A6A', 71 + color: 'var(--fg-subtle)', 63 72 pulse: { 64 73 show: true, 65 - loop: true, 74 + loop: true, // runs only once if false 66 75 radius: 2, 67 - color: '#8A8A8A', 76 + color: 'var(--fg-muted)', 68 77 easing: 'ease-in-out', 69 - trail: { show: true, length: 6 }, 78 + trail: { 79 + show: true, 80 + length: 6, 81 + }, 70 82 }, 71 83 }, 72 - plot: { radius: 6, stroke: '#FAFAFA' }, 73 - title: { text: lastDatapoint.value, fontSize: 12, color: '#8A8A8A', bold: false }, 74 - verticalIndicator: { strokeDasharray: 0, color: '#FAFAFA' }, 84 + plot: { 85 + radius: 6, 86 + stroke: 'var(--fg)', 87 + }, 88 + title: { 89 + text: lastDatapoint.value, 90 + fontSize: 12, 91 + color: 'var(--fg)', 92 + bold: false, 93 + }, 94 + verticalIndicator: { 95 + strokeDasharray: 0, 96 + color: 'var(--fg-muted)', 97 + }, 75 98 }, 76 99 })) 77 100 </script>
+35 -6
app/components/SettingsMenu.vue
··· 3 3 4 4 const { settings } = useSettings() 5 5 const { locale, locales, setLocale } = useI18n() 6 + const colorMode = useColorMode() 6 7 7 8 const availableLocales = computed(() => 8 9 locales.value.map(l => (typeof l === 'string' ? { code: l, name: l } : l)), ··· 96 97 > 97 98 <span class="text-sm text-fg select-none">{{ $t('settings.relative_dates') }}</span> 98 99 <span 99 - class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent transition-[background-color] duration-200 ease-in-out motion-reduce:transition-none" 100 - :class="settings.relativeDates ? 'bg-fg' : 'bg-bg-subtle'" 100 + class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent transition-[background-color] duration-200 ease-in-out motion-reduce:transition-none shadow" 101 + :class="settings.relativeDates ? 'bg-fg' : 'bg-bg'" 101 102 aria-hidden="true" 102 103 > 103 104 <span 104 105 class="pointer-events-none inline-block h-4 w-4 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none" 105 106 :class=" 106 - settings.relativeDates ? 'translate-x-4 bg-bg' : 'translate-x-0 bg-fg-muted' 107 + settings.relativeDates 108 + ? 'translate-x-4 bg-bg-subtle' 109 + : 'translate-x-0 bg-fg-muted' 107 110 " 108 111 /> 109 112 </span> ··· 121 124 $t('settings.include_types') 122 125 }}</span> 123 126 <span 124 - class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent transition-[background-color] duration-200 ease-in-out motion-reduce:transition-none" 125 - :class="settings.includeTypesInInstall ? 'bg-fg' : 'bg-bg-subtle'" 127 + class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent transition-[background-color] duration-200 ease-in-out motion-reduce:transition-none border border-border shadow" 128 + :class="settings.includeTypesInInstall ? 'bg-fg' : 'bg-bg'" 126 129 aria-hidden="true" 127 130 > 128 131 <span 129 132 class="pointer-events-none inline-block h-4 w-4 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none" 130 133 :class=" 131 134 settings.includeTypesInInstall 132 - ? 'translate-x-4 bg-bg' 135 + ? 'translate-x-4 bg-bg-subtle' 133 136 : 'translate-x-0 bg-fg-muted' 134 137 " 135 138 /> 136 139 </span> 137 140 </button> 141 + 142 + <!-- Theme selector --> 143 + <div class="pt-2 mt-2 border-t border-border"> 144 + <div class="px-2 py-1"> 145 + <label for="theme-select" class="text-xs text-fg-subtle uppercase tracking-wider"> 146 + {{ $t('settings.theme') }} 147 + </label> 148 + </div> 149 + <div class="px-2 py-1"> 150 + <select 151 + id="theme-select" 152 + :value="colorMode.preference" 153 + class="w-full bg-bg-muted border border-border rounded-md px-2 py-1.5 text-sm text-fg focus:outline-none focus:ring-2 focus:ring-fg/50 cursor-pointer" 154 + @change=" 155 + colorMode.preference = ($event.target as HTMLSelectElement).value as 156 + | 'light' 157 + | 'dark' 158 + | 'system' 159 + " 160 + > 161 + <option value="system">{{ $t('settings.theme_system') }}</option> 162 + <option value="light">{{ $t('settings.theme_light') }}</option> 163 + <option value="dark">{{ $t('settings.theme_dark') }}</option> 164 + </select> 165 + </div> 166 + </div> 138 167 139 168 <!-- Language selector --> 140 169 <div class="pt-2 mt-2 border-t border-border">
+6 -6
app/composables/useSettings.ts
··· 90 90 // Colors must be hardcoded since ACCENT_COLORS can't be referenced. 91 91 onPrehydrate(() => { 92 92 const colors: Record<AccentColorId, string> = { 93 - rose: '#e9aeba', 94 - amber: '#fbbf24', 95 - emerald: '#34d399', 96 - sky: '#38bdf8', 97 - violet: '#a78bfa', 98 - coral: '#fb7185', 93 + rose: 'oklch(0.797 0.084 11.056)', 94 + amber: 'oklch(0.828 0.165 84.429)', 95 + emerald: 'oklch(0.792 0.153 166.95)', 96 + sky: 'oklch(0.787 0.128 230.318)', 97 + violet: 'oklch(0.714 0.148 286.067)', 98 + coral: 'oklch(0.704 0.177 14.75)', 99 99 } 100 100 const settings = JSON.parse(localStorage.getItem('npmx-settings') || '{}') 101 101 const color = settings.accentColorId ? colors[settings.accentColorId as AccentColorId] : null
+8 -8
app/pages/[...package].vue
··· 762 762 </h2> 763 763 <!-- Package manager tabs --> 764 764 <div 765 - class="flex items-center gap-1 p-0.5 bg-bg-subtle border border-border rounded-md" 765 + class="flex items-center gap-1 p-0.5 bg-bg-subtle border border-border-subtle rounded-md" 766 766 role="tablist" 767 767 :aria-label="$t('package.install.pm_label')" 768 768 > ··· 772 772 :key="pm.id" 773 773 role="tab" 774 774 :aria-selected="selectedPM === pm.id" 775 - class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 775 + class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 776 776 :class=" 777 777 selectedPM === pm.id 778 - ? 'bg-bg-elevated text-fg' 779 - : 'text-fg-subtle hover:text-fg-muted' 778 + ? 'bg-bg shadow text-fg border-border' 779 + : 'text-fg-subtle hover:text-fg border-transparent' 780 780 " 781 781 @click="selectedPM = pm.id" 782 782 > ··· 797 797 </div> 798 798 <div class="relative group"> 799 799 <!-- Terminal-style install command --> 800 - <div class="bg-[#0d0d0d] border border-border rounded-lg overflow-hidden"> 800 + <div class="bg-bg-subtle border border-border rounded-lg overflow-hidden"> 801 801 <div class="flex gap-1.5 px-3 pt-2 sm:px-4 sm:pt-3"> 802 - <span class="w-2.5 h-2.5 rounded-full bg-[#333]" /> 803 - <span class="w-2.5 h-2.5 rounded-full bg-[#333]" /> 804 - <span class="w-2.5 h-2.5 rounded-full bg-[#333]" /> 802 + <span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" /> 803 + <span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" /> 804 + <span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" /> 805 805 </div> 806 806 <div class="space-y-1 px-3 pt-2 pb-3 sm:px-4 sm:pt-3 sm:pb-4"> 807 807 <!-- Main package install -->
+4
i18n/locales/en.json
··· 43 43 "settings": { 44 44 "relative_dates": "Relative dates", 45 45 "include_types": "Include {'@'}types in install", 46 + "theme": "Theme", 47 + "theme_light": "Light", 48 + "theme_dark": "Dark", 49 + "theme_system": "System", 46 50 "language": "Language", 47 51 "help_translate": "Help translate npmx" 48 52 },
+9 -1
nuxt.config.ts
··· 31 31 '@vite-pwa/nuxt', 32 32 '@vueuse/nuxt', 33 33 '@nuxtjs/i18n', 34 + '@nuxtjs/color-mode', 34 35 ], 35 36 36 - css: ['vue-data-ui/style.css'], 37 + colorMode: { 38 + preference: 'system', 39 + fallback: 'dark', 40 + dataValue: 'theme', 41 + storageKey: 'npmx-color-mode', 42 + }, 43 + 44 + css: ['~/assets/main.css', 'vue-data-ui/style.css'], 37 45 38 46 devtools: { enabled: true }, 39 47
+1
package.json
··· 32 32 "@nuxt/a11y": "1.0.0-alpha.1", 33 33 "@nuxt/fonts": "^0.13.0", 34 34 "@nuxt/scripts": "^0.13.2", 35 + "@nuxtjs/color-mode": "^4.0.0", 35 36 "@nuxtjs/html-validator": "^2.1.0", 36 37 "@nuxtjs/i18n": "10.2.1", 37 38 "@shikijs/langs": "^3.21.0",
+18 -1
pnpm-lock.yaml
··· 30 30 '@nuxt/scripts': 31 31 specifier: ^0.13.2 32 32 version: 0.13.2(@unhead/vue@2.1.2(vue@3.5.27(typescript@5.9.3)))(db0@0.3.4(better-sqlite3@12.5.0))(ioredis@5.9.2)(magicast@0.5.1)(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)) 33 + '@nuxtjs/color-mode': 34 + specifier: ^4.0.0 35 + version: 4.0.0(magicast@0.5.1) 33 36 '@nuxtjs/html-validator': 34 37 specifier: ^2.1.0 35 38 version: 2.1.0(@voidzero-dev/vite-plus-test@0.0.0-ffb4d08a8edafe855c59736c0a38ee85a2373ebb(@types/node@24.10.9)(esbuild@0.27.2)(happy-dom@20.3.5)(jiti@2.6.1)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))(magicast@0.5.1) ··· 1806 1809 1807 1810 '@nuxtjs/color-mode@3.5.2': 1808 1811 resolution: {integrity: sha512-cC6RfgZh3guHBMLLjrBB2Uti5eUoGM9KyauOaYS9ETmxNWBMTvpgjvSiSJp1OFljIXPIqVTJ3xtJpSNZiO3ZaA==} 1812 + 1813 + '@nuxtjs/color-mode@4.0.0': 1814 + resolution: {integrity: sha512-xyaVR/TPLdMuRa2VOgH6b75jvmFEsn9QKL6ISldaAw38ooFJfWY1ts2F3ye43wcT/goCbcuvPuskF2f8yUZhlw==} 1809 1815 1810 1816 '@nuxtjs/html-validator@2.1.0': 1811 1817 resolution: {integrity: sha512-ldo8ioSsH3OEumtgwDMokTxlhjgO9FxjJWViAxisq5l/wjvaVX8SYTQ02wjtQcQQPSvS6BwgypAp400RlyFHng==} ··· 7903 7909 tar@7.5.6: 7904 7910 resolution: {integrity: sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==} 7905 7911 engines: {node: '>=18'} 7912 + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me 7906 7913 7907 7914 temp-dir@2.0.0: 7908 7915 resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} ··· 9566 9573 dependencies: 9567 9574 '@babel/code-frame': 7.28.6 9568 9575 '@babel/generator': 7.28.6 9569 - '@babel/parser': 7.27.7 9576 + '@babel/parser': 7.28.6 9570 9577 '@babel/template': 7.28.6 9571 9578 '@babel/types': 7.28.6 9572 9579 debug: 4.4.3 ··· 11008 11015 '@nuxt/kit': 3.21.0(magicast@0.5.1) 11009 11016 pathe: 1.1.2 11010 11017 pkg-types: 1.3.1 11018 + semver: 7.7.3 11019 + transitivePeerDependencies: 11020 + - magicast 11021 + 11022 + '@nuxtjs/color-mode@4.0.0(magicast@0.5.1)': 11023 + dependencies: 11024 + '@nuxt/kit': 4.3.0(magicast@0.5.1) 11025 + exsolve: 1.0.8 11026 + pathe: 2.0.3 11027 + pkg-types: 2.3.0 11011 11028 semver: 7.7.3 11012 11029 transitivePeerDependencies: 11013 11030 - magicast
+6 -6
shared/utils/constants.ts
··· 19 19 20 20 // Theming 21 21 export const ACCENT_COLORS = { 22 - rose: '#e9aeba', 23 - amber: '#fbbf24', 24 - emerald: '#34d399', 25 - sky: '#38bdf8', 26 - violet: '#a78bfa', 27 - coral: '#fb7185', 22 + rose: 'oklch(0.797 0.084 11.056)', 23 + amber: 'oklch(0.828 0.165 84.429)', 24 + emerald: 'oklch(0.792 0.153 166.95)', 25 + sky: 'oklch(0.787 0.128 230.318)', 26 + violet: 'oklch(0.714 0.148 286.067)', 27 + coral: 'oklch(0.704 0.177 14.75)', 28 28 } as const
+17 -17
uno.config.ts
··· 31 31 colors: { 32 32 // Minimal black & white palette with subtle grays 33 33 bg: { 34 - DEFAULT: '#0a0a0a', 35 - subtle: '#111111', 36 - muted: '#1a1a1a', 37 - elevated: '#222222', 34 + DEFAULT: 'var(--bg)', 35 + subtle: 'var(--bg-subtle)', 36 + muted: 'var(--bg-muted)', 37 + elevated: 'var(--bg-elevated)', 38 38 }, 39 39 fg: { 40 - DEFAULT: '#fafafa', 41 - muted: '#a1a1a1', 42 - subtle: '#8A8A8A', 40 + DEFAULT: 'var(--fg)', 41 + muted: 'var(--fg-muted)', 42 + subtle: 'var(--fg-subtle)', 43 43 }, 44 44 border: { 45 - DEFAULT: '#262626', 46 - subtle: '#1f1f1f', 47 - hover: '#404040', 45 + DEFAULT: 'var(--border)', 46 + subtle: 'var(--border-subtle)', 47 + hover: 'var(--border-hover)', 48 48 }, 49 49 accent: { 50 - DEFAULT: 'var(--accent-color, #666666)', 51 - fallback: '#666666', 50 + DEFAULT: 'var(--accent)', 51 + fallback: 'var(--accent-muted)', 52 52 }, 53 53 // Syntax highlighting colors (inspired by GitHub Dark) 54 54 syntax: { 55 - fn: '#b392f0', // function/command - purple 56 - str: '#9ecbff', // string/argument - light blue 57 - kw: '#f97583', // keyword - red/pink 58 - comment: '#6a737d', // comment - gray 55 + fn: 'var(--syntax-fn)', 56 + str: 'var(--syntax-str)', 57 + kw: 'var(--syntax-kw)', 58 + comment: 'var(--syntax-comment)', 59 59 }, 60 60 // Playground provider brand colors 61 61 provider: { ··· 101 101 ['container', 'max-w-4xl mx-auto px-4 sm:px-6'], 102 102 103 103 // Focus states - subtle but accessible 104 - ['focus-ring', 'outline-none focus-visible:(ring-2 ring-fg/20 ring-offset-2 ring-offset-bg)'], 104 + ['focus-ring', 'outline-none focus-visible:(ring-2 ring-fg/10 ring-offset-2)'], 105 105 106 106 // Buttons 107 107 [