Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.

fix build script

+904 -7
+8 -1
apps/main-app/build.ts
··· 3 3 import { rm, mkdir } from 'fs/promises' 4 4 import { existsSync } from 'fs' 5 5 import path from 'path' 6 + import { css as wispCss } from '@wispplace/css' 6 7 7 8 console.log('🔨 Building main-app frontend...') 8 9 ··· 196 197 197 198 await Bun.write(`${distDir}/admin/index.html`, adminHtmlContent) 198 199 200 + // Write wisp.css to public directory so it can be served by static plugin 201 + await Bun.write(`${publicDir}/wisp.css`, wispCss) 202 + 199 203 console.log('✅ Build successful!') 200 - console.log(`📦 Generated ${editorResult.outputs.length + adminResult.outputs.length + 2} file(s):`) 204 + console.log(`📦 Generated ${editorResult.outputs.length + adminResult.outputs.length + 4} file(s):`) 201 205 console.log(`\n Editor:`) 202 206 console.log(` - ${distDir}/editor/index.html`) 203 207 for (const output of editorResult.outputs) { ··· 208 212 for (const output of adminResult.outputs) { 209 213 console.log(` - ${output.path}`) 210 214 } 215 + console.log(`\n CSS:`) 216 + console.log(` - ${publicDir}/wisp.css`) 217 + console.log(` - ${distDir}/wisp.css`)
+896
apps/main-app/public/wisp.css
··· 1 + /** 2 + * wisp.css - A minimal, monospace-first CSS framework 3 + * 4 + * Usage: 5 + * <link rel="stylesheet" href="https://sites.wisp.place/wisp.place/wisp.css/wisp.css"> 6 + * 7 + * Requires JetBrains Mono font: 8 + * <link rel="preconnect" href="https://fonts.googleapis.com"> 9 + * <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 10 + * <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> 11 + * 12 + * Features: 13 + * - Light/dark mode via prefers-color-scheme 14 + * - CSS custom properties for easy theming 15 + * - Monospace typography with JetBrains Mono 16 + * - Minimal component styles (cards, buttons, alerts) 17 + * - Utility classes for spacing and layout 18 + * 19 + * License: MIT 20 + */ 21 + 22 + /* ========================================================================== 23 + CSS Custom Properties (Theme) 24 + ========================================================================== */ 25 + 26 + :root { 27 + /* Background colors */ 28 + --wisp-bg: oklch(0.92 0.012 35); 29 + --wisp-bg-alt: oklch(0.88 0.01 35); 30 + 31 + /* Text colors */ 32 + --wisp-text: oklch(0.15 0.015 30); 33 + --wisp-text-muted: oklch(0.35 0.02 30); 34 + --wisp-text-subtle: oklch(0.50 0.02 30); 35 + 36 + /* Border colors */ 37 + --wisp-border: oklch(0.30 0.025 35); 38 + --wisp-border-light: oklch(0.65 0.02 30); 39 + 40 + /* Accent colors */ 41 + --wisp-accent: oklch(0.65 0.18 345); 42 + --wisp-accent-muted: oklch(0.75 0.14 345); 43 + 44 + /* CTA/Button colors */ 45 + --wisp-cta-bg: oklch(0.30 0.025 35); 46 + --wisp-cta-text: oklch(0.96 0.008 35); 47 + 48 + /* Semantic colors */ 49 + --wisp-code-bg: oklch(0.95 0.008 35); 50 + --wisp-success: oklch(0.65 0.20 145); 51 + --wisp-danger: oklch(0.60 0.20 25); 52 + --wisp-warning: oklch(0.70 0.15 85); 53 + --wisp-info: oklch(0.60 0.15 240); 54 + 55 + /* Layout */ 56 + --wisp-max-width: 900px; 57 + --wisp-header-max-width: 1100px; 58 + 59 + /* Typography */ 60 + --wisp-font-family: "JetBrains Mono", ui-monospace, monospace; 61 + --wisp-line-height: 1.6; 62 + 63 + /* Spacing scale */ 64 + --wisp-space-1: 0.25rem; 65 + --wisp-space-2: 0.5rem; 66 + --wisp-space-3: 1rem; 67 + --wisp-space-4: 1.5rem; 68 + --wisp-space-5: 2rem; 69 + --wisp-space-6: 3rem; 70 + 71 + /* Border radius */ 72 + --wisp-radius-sm: 0.25rem; 73 + --wisp-radius: 0.375rem; 74 + --wisp-radius-lg: 0.5rem; 75 + 76 + /* Backward-compatible aliases (unprefixed) */ 77 + --bg: var(--wisp-bg); 78 + --bg-alt: var(--wisp-bg-alt); 79 + --text: var(--wisp-text); 80 + --text-muted: var(--wisp-text-muted); 81 + --text-subtle: var(--wisp-text-subtle); 82 + --border: var(--wisp-border); 83 + --border-light: var(--wisp-border-light); 84 + --accent: var(--wisp-accent); 85 + --accent-muted: var(--wisp-accent-muted); 86 + --cta-bg: var(--wisp-cta-bg); 87 + --cta-text: var(--wisp-cta-text); 88 + --code-bg: var(--wisp-code-bg); 89 + --success: var(--wisp-success); 90 + --red: var(--wisp-danger); 91 + --yellow: var(--wisp-warning); 92 + --blue: var(--wisp-info); 93 + } 94 + 95 + @media (prefers-color-scheme: dark) { 96 + :root:not([data-theme="light"]) { 97 + --wisp-bg: oklch(0.23 0.015 285); 98 + --wisp-bg-alt: oklch(0.20 0.015 285); 99 + --wisp-text: oklch(0.90 0.005 285); 100 + --wisp-text-muted: oklch(0.72 0.01 285); 101 + --wisp-text-subtle: oklch(0.55 0.01 285); 102 + --wisp-border: oklch(0.90 0.005 285); 103 + --wisp-border-light: oklch(0.38 0.02 285); 104 + --wisp-accent: oklch(0.85 0.08 5); 105 + --wisp-accent-muted: oklch(0.70 0.10 295); 106 + --wisp-cta-bg: oklch(0.70 0.10 295); 107 + --wisp-cta-text: oklch(0.23 0.015 285); 108 + --wisp-code-bg: oklch(0.28 0.015 285); 109 + --wisp-success: oklch(0.65 0.20 145); 110 + --wisp-danger: oklch(0.65 0.20 25); 111 + --wisp-warning: oklch(0.75 0.15 85); 112 + --wisp-info: oklch(0.65 0.18 240); 113 + 114 + /* Backward-compatible aliases */ 115 + --bg: var(--wisp-bg); 116 + --bg-alt: var(--wisp-bg-alt); 117 + --text: var(--wisp-text); 118 + --text-muted: var(--wisp-text-muted); 119 + --text-subtle: var(--wisp-text-subtle); 120 + --border: var(--wisp-border); 121 + --border-light: var(--wisp-border-light); 122 + --accent: var(--wisp-accent); 123 + --accent-muted: var(--wisp-accent-muted); 124 + --cta-bg: var(--wisp-cta-bg); 125 + --cta-text: var(--wisp-cta-text); 126 + --code-bg: var(--wisp-code-bg); 127 + --success: var(--wisp-success); 128 + --red: var(--wisp-danger); 129 + --yellow: var(--wisp-warning); 130 + --blue: var(--wisp-info); 131 + } 132 + } 133 + 134 + /* Manual dark theme override */ 135 + :root[data-theme="dark"] { 136 + --wisp-bg: oklch(0.23 0.015 285); 137 + --wisp-bg-alt: oklch(0.20 0.015 285); 138 + --wisp-text: oklch(0.90 0.005 285); 139 + --wisp-text-muted: oklch(0.72 0.01 285); 140 + --wisp-text-subtle: oklch(0.55 0.01 285); 141 + --wisp-border: oklch(0.90 0.005 285); 142 + --wisp-border-light: oklch(0.38 0.02 285); 143 + --wisp-accent: oklch(0.85 0.08 5); 144 + --wisp-accent-muted: oklch(0.70 0.10 295); 145 + --wisp-cta-bg: oklch(0.70 0.10 295); 146 + --wisp-cta-text: oklch(0.23 0.015 285); 147 + --wisp-code-bg: oklch(0.28 0.015 285); 148 + --wisp-success: oklch(0.65 0.20 145); 149 + --wisp-danger: oklch(0.65 0.20 25); 150 + --wisp-warning: oklch(0.75 0.15 85); 151 + --wisp-info: oklch(0.65 0.18 240); 152 + 153 + /* Backward-compatible aliases */ 154 + --bg: var(--wisp-bg); 155 + --bg-alt: var(--wisp-bg-alt); 156 + --text: var(--wisp-text); 157 + --text-muted: var(--wisp-text-muted); 158 + --text-subtle: var(--wisp-text-subtle); 159 + --border: var(--wisp-border); 160 + --border-light: var(--wisp-border-light); 161 + --accent: var(--wisp-accent); 162 + --accent-muted: var(--wisp-accent-muted); 163 + --cta-bg: var(--wisp-cta-bg); 164 + --cta-text: var(--wisp-cta-text); 165 + --code-bg: var(--wisp-code-bg); 166 + --success: var(--wisp-success); 167 + --red: var(--wisp-danger); 168 + --yellow: var(--wisp-warning); 169 + --blue: var(--wisp-info); 170 + } 171 + 172 + /* ========================================================================== 173 + Base / Reset 174 + ========================================================================== */ 175 + 176 + *, *::before, *::after { 177 + margin: 0; 178 + padding: 0; 179 + box-sizing: border-box; 180 + } 181 + 182 + html { 183 + scroll-behavior: smooth; 184 + -webkit-text-size-adjust: 100%; 185 + } 186 + 187 + body { 188 + font-family: var(--wisp-font-family); 189 + background: var(--wisp-bg); 190 + color: var(--wisp-text); 191 + min-height: 100vh; 192 + display: flex; 193 + flex-direction: column; 194 + line-height: var(--wisp-line-height); 195 + } 196 + 197 + /* ========================================================================== 198 + Typography 199 + ========================================================================== */ 200 + 201 + h1, h2, h3, h4, h5, h6 { 202 + color: var(--wisp-text); 203 + font-weight: 700; 204 + line-height: 1.2; 205 + } 206 + 207 + h1 { 208 + font-size: clamp(2rem, 5vw, 2.5rem); 209 + margin-bottom: var(--wisp-space-4); 210 + letter-spacing: -0.03em; 211 + } 212 + 213 + h2 { 214 + font-size: 1.875rem; 215 + margin-bottom: var(--wisp-space-4); 216 + letter-spacing: -0.02em; 217 + } 218 + 219 + h3 { 220 + font-size: 1.5rem; 221 + font-weight: 600; 222 + margin-bottom: var(--wisp-space-3); 223 + } 224 + 225 + h4 { 226 + font-size: 1.25rem; 227 + font-weight: 600; 228 + margin-bottom: var(--wisp-space-2); 229 + } 230 + 231 + p { 232 + color: var(--wisp-text-muted); 233 + margin-bottom: var(--wisp-space-3); 234 + line-height: 1.7; 235 + } 236 + 237 + strong, b { 238 + color: var(--wisp-text); 239 + font-weight: 600; 240 + } 241 + 242 + small { 243 + font-size: 0.875rem; 244 + color: var(--wisp-text-muted); 245 + } 246 + 247 + a { 248 + color: var(--wisp-accent); 249 + text-decoration: none; 250 + transition: opacity 0.15s; 251 + } 252 + 253 + a:hover { 254 + opacity: 0.8; 255 + } 256 + 257 + code { 258 + font-family: var(--wisp-font-family); 259 + background: var(--wisp-code-bg); 260 + padding: 0.125rem 0.375rem; 261 + border-radius: var(--wisp-radius-sm); 262 + font-size: 0.875em; 263 + } 264 + 265 + pre { 266 + background: var(--wisp-code-bg); 267 + padding: var(--wisp-space-3); 268 + border-radius: var(--wisp-radius); 269 + overflow-x: auto; 270 + margin-bottom: var(--wisp-space-3); 271 + } 272 + 273 + pre code { 274 + background: none; 275 + padding: 0; 276 + } 277 + 278 + /* ========================================================================== 279 + Layout 280 + ========================================================================== */ 281 + 282 + .container { 283 + max-width: var(--wisp-max-width); 284 + margin: 0 auto; 285 + padding: var(--wisp-space-6) var(--wisp-space-3); 286 + } 287 + 288 + .container-wide { 289 + max-width: var(--wisp-header-max-width); 290 + margin: 0 auto; 291 + padding: var(--wisp-space-6) var(--wisp-space-3); 292 + } 293 + 294 + /* ========================================================================== 295 + Header 296 + ========================================================================== */ 297 + 298 + header { 299 + position: sticky; 300 + top: 0; 301 + background: var(--wisp-bg); 302 + border-bottom: 1px solid var(--wisp-border-light); 303 + padding: var(--wisp-space-3) var(--wisp-space-5); 304 + z-index: 100; 305 + } 306 + 307 + .header-inner { 308 + max-width: var(--wisp-header-max-width); 309 + margin: 0 auto; 310 + display: flex; 311 + justify-content: space-between; 312 + align-items: center; 313 + } 314 + 315 + .logo { 316 + font-weight: 700; 317 + font-size: 1.125rem; 318 + text-decoration: none; 319 + color: var(--wisp-text); 320 + letter-spacing: -0.02em; 321 + display: flex; 322 + align-items: center; 323 + gap: var(--wisp-space-2); 324 + } 325 + 326 + .logo:hover { 327 + opacity: 1; 328 + } 329 + 330 + .logo img { 331 + width: 2rem; 332 + height: 2rem; 333 + } 334 + 335 + nav { 336 + display: flex; 337 + gap: var(--wisp-space-5); 338 + align-items: center; 339 + } 340 + 341 + nav a { 342 + color: var(--wisp-text-muted); 343 + font-size: 1rem; 344 + transition: color 0.15s; 345 + } 346 + 347 + nav a:hover { 348 + color: var(--wisp-text); 349 + opacity: 1; 350 + } 351 + 352 + /* ========================================================================== 353 + Buttons 354 + ========================================================================== */ 355 + 356 + button, .btn { 357 + display: inline-flex; 358 + align-items: center; 359 + justify-content: center; 360 + gap: var(--wisp-space-2); 361 + padding: var(--wisp-space-2) var(--wisp-space-3); 362 + background: var(--wisp-cta-bg); 363 + color: var(--wisp-cta-text); 364 + border: none; 365 + border-radius: var(--wisp-radius); 366 + font-weight: 600; 367 + font-size: 0.875rem; 368 + font-family: var(--wisp-font-family); 369 + cursor: pointer; 370 + transition: opacity 0.15s; 371 + text-decoration: none; 372 + } 373 + 374 + button:hover, .btn:hover { 375 + opacity: 0.9; 376 + } 377 + 378 + button:disabled, .btn:disabled { 379 + opacity: 0.5; 380 + cursor: not-allowed; 381 + } 382 + 383 + button.outline, .btn.outline { 384 + background: transparent; 385 + color: var(--wisp-text); 386 + border: 1px solid var(--wisp-border-light); 387 + } 388 + 389 + button.outline:hover, .btn.outline:hover { 390 + background: var(--wisp-bg-alt); 391 + opacity: 1; 392 + } 393 + 394 + .btn-lg { 395 + padding: var(--wisp-space-3) var(--wisp-space-5); 396 + font-size: 1rem; 397 + } 398 + 399 + .cta-primary { 400 + background: var(--wisp-cta-bg); 401 + color: var(--wisp-cta-text); 402 + padding: var(--wisp-space-3) var(--wisp-space-5); 403 + border: 2px solid var(--wisp-border); 404 + font-weight: 600; 405 + font-size: 1rem; 406 + text-decoration: none; 407 + text-transform: uppercase; 408 + letter-spacing: 0.05em; 409 + transition: all 0.15s; 410 + } 411 + 412 + .cta-primary:hover { 413 + background: var(--wisp-bg); 414 + color: var(--wisp-text); 415 + opacity: 1; 416 + } 417 + 418 + .cta-secondary { 419 + background: transparent; 420 + color: var(--wisp-text); 421 + padding: var(--wisp-space-3) var(--wisp-space-5); 422 + border: 2px solid var(--wisp-border); 423 + font-weight: 600; 424 + font-size: 1rem; 425 + text-decoration: none; 426 + text-transform: uppercase; 427 + letter-spacing: 0.05em; 428 + transition: all 0.15s; 429 + } 430 + 431 + .cta-secondary:hover { 432 + background: var(--wisp-cta-bg); 433 + color: var(--wisp-cta-text); 434 + opacity: 1; 435 + } 436 + 437 + .nav-cta { 438 + background: var(--wisp-cta-bg); 439 + color: var(--wisp-cta-text); 440 + padding: var(--wisp-space-2) var(--wisp-space-3); 441 + border: 1px solid var(--wisp-border); 442 + font-weight: 600; 443 + font-size: 0.875rem; 444 + text-transform: uppercase; 445 + letter-spacing: 0.05em; 446 + transition: all 0.15s; 447 + } 448 + 449 + .nav-cta:hover { 450 + background: var(--wisp-bg); 451 + color: var(--wisp-text); 452 + opacity: 1; 453 + } 454 + 455 + /* ========================================================================== 456 + Forms 457 + ========================================================================== */ 458 + 459 + label { 460 + display: block; 461 + margin-bottom: var(--wisp-space-2); 462 + font-size: 0.875rem; 463 + font-weight: 500; 464 + color: var(--wisp-text); 465 + } 466 + 467 + input, textarea, select { 468 + width: 100%; 469 + padding: var(--wisp-space-2) 0.75rem; 470 + background: var(--wisp-bg); 471 + border: 1px solid var(--wisp-border-light); 472 + border-radius: var(--wisp-radius); 473 + color: var(--wisp-text); 474 + font-size: 0.875rem; 475 + font-family: var(--wisp-font-family); 476 + } 477 + 478 + input:focus, textarea:focus, select:focus { 479 + outline: 2px solid var(--wisp-accent); 480 + outline-offset: 2px; 481 + } 482 + 483 + input::placeholder, textarea::placeholder { 484 + color: var(--wisp-text-subtle); 485 + } 486 + 487 + /* ========================================================================== 488 + Cards 489 + ========================================================================== */ 490 + 491 + .card { 492 + background: var(--wisp-bg-alt); 493 + border: 1px solid var(--wisp-border-light); 494 + border-radius: var(--wisp-radius-lg); 495 + padding: var(--wisp-space-4); 496 + margin-bottom: var(--wisp-space-3); 497 + } 498 + 499 + .card.success { 500 + background: color-mix(in oklch, var(--wisp-success) 5%, var(--wisp-bg-alt)); 501 + border-color: color-mix(in oklch, var(--wisp-success) 20%, transparent); 502 + } 503 + 504 + .card.danger { 505 + background: color-mix(in oklch, var(--wisp-danger) 5%, var(--wisp-bg-alt)); 506 + border-color: color-mix(in oklch, var(--wisp-danger) 30%, transparent); 507 + border-width: 2px; 508 + } 509 + 510 + .card.warning { 511 + background: color-mix(in oklch, var(--wisp-warning) 5%, var(--wisp-bg-alt)); 512 + border-color: color-mix(in oklch, var(--wisp-warning) 20%, transparent); 513 + } 514 + 515 + .card.info { 516 + background: color-mix(in oklch, var(--wisp-info) 5%, var(--wisp-bg-alt)); 517 + border-color: color-mix(in oklch, var(--wisp-info) 20%, transparent); 518 + } 519 + 520 + .card.thick { 521 + border-width: 2px; 522 + } 523 + 524 + .card-flex { 525 + display: flex; 526 + gap: var(--wisp-space-3); 527 + align-items: start; 528 + } 529 + 530 + .card-icon { 531 + flex-shrink: 0; 532 + width: 2rem; 533 + height: 2rem; 534 + } 535 + 536 + /* ========================================================================== 537 + Alerts 538 + ========================================================================== */ 539 + 540 + .alert { 541 + padding: var(--wisp-space-3); 542 + border-radius: var(--wisp-radius-lg); 543 + margin-bottom: var(--wisp-space-3); 544 + } 545 + 546 + .alert-success { 547 + background: var(--wisp-code-bg); 548 + border: 1px solid var(--wisp-border-light); 549 + color: var(--wisp-success); 550 + } 551 + 552 + .alert-info { 553 + background: var(--wisp-code-bg); 554 + color: var(--wisp-text-muted); 555 + } 556 + 557 + .alert-warning { 558 + background: var(--wisp-code-bg); 559 + border-left: 4px solid var(--wisp-warning); 560 + } 561 + 562 + .alert-danger { 563 + background: var(--wisp-code-bg); 564 + border-left: 4px solid var(--wisp-danger); 565 + } 566 + 567 + /* ========================================================================== 568 + Lists 569 + ========================================================================== */ 570 + 571 + ul, ol { 572 + list-style: none; 573 + margin: var(--wisp-space-3) 0; 574 + } 575 + 576 + ol { 577 + counter-reset: item; 578 + } 579 + 580 + ol li { 581 + counter-increment: item; 582 + } 583 + 584 + ol li::before { 585 + content: counter(item) "."; 586 + font-weight: 700; 587 + color: var(--wisp-accent); 588 + margin-right: 0.75rem; 589 + } 590 + 591 + .bullet { 592 + flex-shrink: 0; 593 + margin-top: 0.25rem; 594 + } 595 + 596 + .bullet.red, .bullet.danger { color: var(--wisp-danger); } 597 + .bullet.green, .bullet.success { color: var(--wisp-success); } 598 + .bullet.yellow, .bullet.warning { color: var(--wisp-warning); } 599 + .bullet.accent { color: var(--wisp-accent); } 600 + 601 + /* ========================================================================== 602 + Footer 603 + ========================================================================== */ 604 + 605 + footer { 606 + padding: var(--wisp-space-6) var(--wisp-space-5) var(--wisp-space-5); 607 + border-top: 1px solid var(--wisp-border-light); 608 + margin-top: auto; 609 + } 610 + 611 + .footer-inner { 612 + max-width: var(--wisp-header-max-width); 613 + margin: 0 auto; 614 + display: grid; 615 + grid-template-columns: 2fr repeat(3, 1fr); 616 + gap: var(--wisp-space-6); 617 + } 618 + 619 + .footer-brand p:first-child { 620 + font-weight: 700; 621 + margin-bottom: 0.75rem; 622 + } 623 + 624 + .footer-brand p:last-child { 625 + color: var(--wisp-text-muted); 626 + line-height: 1.6; 627 + } 628 + 629 + .footer-col h4 { 630 + font-size: 0.875rem; 631 + color: var(--wisp-text-subtle); 632 + text-transform: uppercase; 633 + letter-spacing: 0.05em; 634 + margin-bottom: var(--wisp-space-3); 635 + } 636 + 637 + .footer-col ul { 638 + margin: 0; 639 + } 640 + 641 + .footer-col li { 642 + margin-bottom: var(--wisp-space-2); 643 + } 644 + 645 + .footer-col a { 646 + color: var(--wisp-text-muted); 647 + transition: color 0.15s; 648 + } 649 + 650 + .footer-col a:hover { 651 + color: var(--wisp-text); 652 + opacity: 1; 653 + } 654 + 655 + .footer-bottom { 656 + max-width: var(--wisp-header-max-width); 657 + margin: var(--wisp-space-6) auto 0; 658 + padding-top: var(--wisp-space-5); 659 + border-top: 1px solid var(--wisp-border-light); 660 + display: flex; 661 + justify-content: space-between; 662 + align-items: center; 663 + } 664 + 665 + .footer-bottom p { 666 + color: var(--wisp-text-subtle); 667 + font-size: 0.875rem; 668 + } 669 + 670 + .footer-bottom nav { 671 + gap: var(--wisp-space-4); 672 + } 673 + 674 + .footer-bottom a { 675 + color: var(--wisp-text-subtle); 676 + font-size: 0.875rem; 677 + } 678 + 679 + .footer-bottom a:hover { 680 + color: var(--wisp-text); 681 + opacity: 1; 682 + } 683 + 684 + footer.simple { 685 + background: var(--wisp-bg-alt); 686 + padding: var(--wisp-space-5) var(--wisp-space-3); 687 + text-align: center; 688 + font-size: 0.875rem; 689 + color: var(--wisp-text-muted); 690 + } 691 + 692 + footer.simple p { 693 + margin-bottom: var(--wisp-space-2); 694 + } 695 + 696 + /* ========================================================================== 697 + Spinner 698 + ========================================================================== */ 699 + 700 + .spinner { 701 + display: inline-block; 702 + width: 1rem; 703 + height: 1rem; 704 + border: 2px solid var(--wisp-border-light); 705 + border-top-color: var(--wisp-accent); 706 + border-radius: 50%; 707 + animation: wisp-spin 0.6s linear infinite; 708 + } 709 + 710 + .spinner-lg { 711 + width: 2rem; 712 + height: 2rem; 713 + border-width: 3px; 714 + } 715 + 716 + @keyframes wisp-spin { 717 + to { transform: rotate(360deg); } 718 + } 719 + 720 + /* ========================================================================== 721 + Utility Classes 722 + ========================================================================== */ 723 + 724 + /* Display */ 725 + .hidden { display: none; } 726 + .block { display: block; } 727 + .inline { display: inline; } 728 + .inline-block { display: inline-block; } 729 + .flex { display: flex; } 730 + .inline-flex { display: inline-flex; } 731 + .grid { display: grid; } 732 + 733 + /* Flexbox */ 734 + .flex-col { flex-direction: column; } 735 + .flex-wrap { flex-wrap: wrap; } 736 + .items-start { align-items: flex-start; } 737 + .items-center { align-items: center; } 738 + .items-end { align-items: flex-end; } 739 + .justify-start { justify-content: flex-start; } 740 + .justify-center { justify-content: center; } 741 + .justify-end { justify-content: flex-end; } 742 + .justify-between { justify-content: space-between; } 743 + 744 + /* Gap */ 745 + .gap-1 { gap: var(--wisp-space-1); } 746 + .gap-2 { gap: var(--wisp-space-2); } 747 + .gap-3 { gap: var(--wisp-space-3); } 748 + .gap-4 { gap: var(--wisp-space-4); } 749 + .gap-5 { gap: var(--wisp-space-5); } 750 + .gap-6 { gap: var(--wisp-space-6); } 751 + 752 + /* Margin */ 753 + .m-0 { margin: 0; } 754 + .m-1 { margin: var(--wisp-space-1); } 755 + .m-2 { margin: var(--wisp-space-2); } 756 + .m-3 { margin: var(--wisp-space-3); } 757 + .m-4 { margin: var(--wisp-space-4); } 758 + 759 + .mt-0 { margin-top: 0; } 760 + .mt-1 { margin-top: var(--wisp-space-1); } 761 + .mt-2 { margin-top: var(--wisp-space-2); } 762 + .mt-3 { margin-top: var(--wisp-space-3); } 763 + .mt-4 { margin-top: var(--wisp-space-4); } 764 + .mt-5 { margin-top: var(--wisp-space-5); } 765 + .mt-6 { margin-top: var(--wisp-space-6); } 766 + 767 + .mb-0 { margin-bottom: 0; } 768 + .mb-1 { margin-bottom: var(--wisp-space-1); } 769 + .mb-2 { margin-bottom: var(--wisp-space-2); } 770 + .mb-3 { margin-bottom: var(--wisp-space-3); } 771 + .mb-4 { margin-bottom: var(--wisp-space-4); } 772 + .mb-5 { margin-bottom: var(--wisp-space-5); } 773 + .mb-6 { margin-bottom: var(--wisp-space-6); } 774 + 775 + .ml-0 { margin-left: 0; } 776 + .ml-1 { margin-left: var(--wisp-space-1); } 777 + .ml-2 { margin-left: var(--wisp-space-2); } 778 + .ml-3 { margin-left: var(--wisp-space-3); } 779 + .ml-4 { margin-left: var(--wisp-space-4); } 780 + 781 + .mr-0 { margin-right: 0; } 782 + .mr-1 { margin-right: var(--wisp-space-1); } 783 + .mr-2 { margin-right: var(--wisp-space-2); } 784 + .mr-3 { margin-right: var(--wisp-space-3); } 785 + .mr-4 { margin-right: var(--wisp-space-4); } 786 + 787 + /* Padding */ 788 + .p-0 { padding: 0; } 789 + .p-1 { padding: var(--wisp-space-1); } 790 + .p-2 { padding: var(--wisp-space-2); } 791 + .p-3 { padding: var(--wisp-space-3); } 792 + .p-4 { padding: var(--wisp-space-4); } 793 + .p-5 { padding: var(--wisp-space-5); } 794 + .p-6 { padding: var(--wisp-space-6); } 795 + 796 + .px-1 { padding-left: var(--wisp-space-1); padding-right: var(--wisp-space-1); } 797 + .px-2 { padding-left: var(--wisp-space-2); padding-right: var(--wisp-space-2); } 798 + .px-3 { padding-left: var(--wisp-space-3); padding-right: var(--wisp-space-3); } 799 + .px-4 { padding-left: var(--wisp-space-4); padding-right: var(--wisp-space-4); } 800 + 801 + .py-1 { padding-top: var(--wisp-space-1); padding-bottom: var(--wisp-space-1); } 802 + .py-2 { padding-top: var(--wisp-space-2); padding-bottom: var(--wisp-space-2); } 803 + .py-3 { padding-top: var(--wisp-space-3); padding-bottom: var(--wisp-space-3); } 804 + .py-4 { padding-top: var(--wisp-space-4); padding-bottom: var(--wisp-space-4); } 805 + 806 + /* Width */ 807 + .w-full { width: 100%; } 808 + .w-auto { width: auto; } 809 + .max-w-sm { max-width: 24rem; } 810 + .max-w-md { max-width: 28rem; } 811 + .max-w-lg { max-width: 32rem; } 812 + .max-w-xl { max-width: 36rem; } 813 + 814 + /* Text */ 815 + .text-left { text-align: left; } 816 + .text-center { text-align: center; } 817 + .text-right { text-align: right; } 818 + 819 + .text-sm { font-size: 0.875rem; } 820 + .text-base { font-size: 1rem; } 821 + .text-lg { font-size: 1.125rem; } 822 + .text-xl { font-size: 1.25rem; } 823 + 824 + .font-normal { font-weight: 400; } 825 + .font-medium { font-weight: 500; } 826 + .font-semibold { font-weight: 600; } 827 + .font-bold { font-weight: 700; } 828 + 829 + .text-muted { color: var(--wisp-text-muted); } 830 + .text-subtle { color: var(--wisp-text-subtle); } 831 + .text-accent { color: var(--wisp-accent); } 832 + .text-success { color: var(--wisp-success); } 833 + .text-danger { color: var(--wisp-danger); } 834 + .text-warning { color: var(--wisp-warning); } 835 + .text-info { color: var(--wisp-info); } 836 + 837 + /* Background */ 838 + .bg-alt { background: var(--wisp-bg-alt); } 839 + .bg-code { background: var(--wisp-code-bg); } 840 + 841 + /* Border */ 842 + .border { border: 1px solid var(--wisp-border-light); } 843 + .border-2 { border: 2px solid var(--wisp-border-light); } 844 + .rounded { border-radius: var(--wisp-radius); } 845 + .rounded-lg { border-radius: var(--wisp-radius-lg); } 846 + 847 + /* Other */ 848 + .cursor-pointer { cursor: pointer; } 849 + .select-none { user-select: none; } 850 + .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } 851 + 852 + /* ========================================================================== 853 + Responsive 854 + ========================================================================== */ 855 + 856 + @media (max-width: 768px) { 857 + nav a:not(.nav-cta) { 858 + display: none; 859 + } 860 + 861 + .footer-inner { 862 + grid-template-columns: 1fr 1fr; 863 + } 864 + 865 + .footer-brand { 866 + grid-column: span 2; 867 + } 868 + 869 + .footer-bottom { 870 + flex-direction: column; 871 + gap: var(--wisp-space-3); 872 + text-align: center; 873 + } 874 + 875 + h1 { font-size: 2rem; } 876 + h2 { font-size: 1.5rem; } 877 + h3 { font-size: 1.25rem; } 878 + 879 + .hide-mobile { display: none; } 880 + } 881 + 882 + @media (max-width: 480px) { 883 + .footer-inner { 884 + grid-template-columns: 1fr; 885 + } 886 + 887 + .footer-brand { 888 + grid-column: span 1; 889 + } 890 + 891 + .hide-sm { display: none; } 892 + } 893 + 894 + @media (min-width: 769px) { 895 + .hide-desktop { display: none; } 896 + }
-6
apps/main-app/src/index.ts
··· 25 25 import { DNSVerificationWorker } from './lib/dns-verification-worker' 26 26 import { createLogger, logCollector, initializeGrafanaExporters } from '@wispplace/observability' 27 27 import { observabilityMiddleware } from '@wispplace/observability/middleware/elysia' 28 - import { css as wispCss } from '@wispplace/css' 29 28 import { promptAdminSetup } from './lib/admin-auth' 30 29 import { adminRoutes } from './routes/admin' 31 30 ··· 249 248 }) 250 249 : (app) => app 251 250 ) 252 - .get('/wisp.css', ({ set }) => { 253 - set.headers['Content-Type'] = 'text/css; charset=utf-8' 254 - set.headers['Cache-Control'] = 'public, max-age=86400' 255 - return wispCss 256 - }) 257 251 .get('/acceptable-use', async ({ set }) => { 258 252 set.headers['Content-Type'] = 'text/html; charset=utf-8' 259 253 return await Bun.file('./apps/main-app/public/editor/acceptable-use.html').text()