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

make css a package

+1501 -615
+1
apps/main-app/package.json
··· 32 32 "@radix-ui/react-tabs": "^1.1.13", 33 33 "@tanstack/react-query": "^5.90.2", 34 34 "@wisp/atproto-utils": "workspace:*", 35 + "@wisp/css": "workspace:*", 35 36 "@wisp/constants": "workspace:*", 36 37 "@wisp/database": "workspace:*", 37 38 "@wisp/fs-utils": "workspace:*",
+5 -217
apps/main-app/public/editor/acceptable-use.html
··· 8 8 <link rel="preconnect" href="https://fonts.googleapis.com"> 9 9 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 10 10 <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> 11 + <link rel="stylesheet" href="/wisp.css"> 11 12 <style> 12 - * { margin: 0; padding: 0; box-sizing: border-box; } 13 - 14 - :root { 15 - --bg: oklch(0.92 0.012 35); 16 - --bg-alt: oklch(0.88 0.01 35); 17 - --text: oklch(0.15 0.015 30); 18 - --text-muted: oklch(0.35 0.02 30); 19 - --text-subtle: oklch(0.50 0.02 30); 20 - --border: oklch(0.30 0.025 35); 21 - --border-light: oklch(0.65 0.02 30); 22 - --accent: oklch(0.65 0.18 345); 23 - --cta-bg: oklch(0.30 0.025 35); 24 - --cta-text: oklch(0.96 0.008 35); 25 - --code-bg: oklch(0.95 0.008 35); 26 - --success: oklch(0.65 0.20 145); 27 - --red: oklch(0.60 0.20 25); 28 - --yellow: oklch(0.70 0.15 85); 29 - --blue: oklch(0.60 0.15 240); 30 - } 31 - 32 - @media (prefers-color-scheme: dark) { 33 - :root { 34 - --bg: oklch(0.23 0.015 285); 35 - --bg-alt: oklch(0.20 0.015 285); 36 - --text: oklch(0.90 0.005 285); 37 - --text-muted: oklch(0.72 0.01 285); 38 - --text-subtle: oklch(0.55 0.01 285); 39 - --border: oklch(0.90 0.005 285); 40 - --border-light: oklch(0.38 0.02 285); 41 - --accent: oklch(0.85 0.08 5); 42 - --cta-bg: oklch(0.70 0.10 295); 43 - --cta-text: oklch(0.23 0.015 285); 44 - --code-bg: oklch(0.28 0.015 285); 45 - --success: oklch(0.65 0.20 145); 46 - --red: oklch(0.65 0.20 25); 47 - --yellow: oklch(0.75 0.15 85); 48 - --blue: oklch(0.65 0.18 240); 49 - } 50 - } 51 - 52 - body { 53 - font-family: "JetBrains Mono", monospace; 54 - background: var(--bg); 55 - color: var(--text); 56 - line-height: 1.6; 57 - min-height: 100vh; 58 - display: flex; 59 - flex-direction: column; 60 - } 61 - 62 - header { 63 - border-bottom: 1px solid var(--border-light); 64 - padding: 1rem 2rem; 65 - background: var(--bg); 66 - position: sticky; 67 - top: 0; 68 - z-index: 100; 69 - } 70 - 71 - .header-inner { 72 - max-width: 1100px; 73 - margin: 0 auto; 74 - display: flex; 75 - justify-content: space-between; 76 - align-items: center; 77 - } 78 - 79 - .logo { 80 - font-size: 1.125rem; 81 - font-weight: 700; 82 - color: var(--text); 83 - letter-spacing: -0.02em; 84 - display: flex; 85 - align-items: center; 86 - gap: 0.5rem; 87 - } 88 - 89 - .logo img { width: 2rem; height: 2rem; } 90 - 91 - .back-link { 92 - color: var(--text-muted); 93 - text-decoration: none; 94 - font-size: 0.875rem; 95 - } 96 - 97 - .back-link:hover { color: var(--text); } 98 - 99 13 .hero { 100 14 background: linear-gradient(to bottom, var(--code-bg), var(--bg)); 101 15 border-bottom: 1px solid var(--border-light); ··· 116 30 margin-bottom: 1.5rem; 117 31 } 118 32 119 - h1 { 33 + .hero h1 { 120 34 font-size: 2.5rem; 121 - margin-bottom: 1.5rem; 122 - color: var(--text); 123 35 } 124 36 125 37 .meta { ··· 135 47 width: 1px; 136 48 height: 1rem; 137 49 background: var(--border-light); 138 - } 139 - 140 - .container { 141 - max-width: 900px; 142 - margin: 0 auto; 143 - padding: 3rem 1rem; 144 50 } 145 51 146 52 article { margin-bottom: 3rem; } 147 - 148 53 section { margin-bottom: 3rem; } 54 + .card { margin-bottom: 2rem; } 149 55 150 56 h2 { 151 - font-size: 1.875rem; 152 - margin-bottom: 1.5rem; 153 - color: var(--text); 154 57 display: flex; 155 58 align-items: center; 156 59 gap: 0.75rem; 157 60 } 158 61 159 - h3 { 160 - font-size: 1.5rem; 161 - margin-bottom: 1rem; 162 - color: var(--text); 163 - } 164 - 165 - p { 166 - color: var(--text-muted); 167 - margin-bottom: 1rem; 168 - font-size: 1rem; 169 - line-height: 1.7; 170 - } 171 - 172 - strong { color: var(--text); font-weight: 600; } 173 - 174 - .card { 175 - background: var(--bg-alt); 176 - border: 1px solid var(--border-light); 177 - border-radius: 0.5rem; 178 - padding: 1.5rem; 179 - margin-bottom: 2rem; 180 - } 181 - 182 - .card.success { 183 - background: color-mix(in oklch, var(--success) 5%, var(--bg-alt)); 184 - border-color: color-mix(in oklch, var(--success) 20%, transparent); 185 - } 186 - 187 - .card.danger { 188 - background: color-mix(in oklch, var(--red) 5%, var(--bg-alt)); 189 - border-color: color-mix(in oklch, var(--red) 30%, transparent); 190 - border-width: 2px; 191 - } 192 - 193 - .card.info { 194 - background: color-mix(in oklch, var(--blue) 5%, var(--bg-alt)); 195 - border-color: color-mix(in oklch, var(--blue) 20%, transparent); 196 - } 197 - 198 - .card.thick { border-width: 2px; } 199 - 200 - .card-flex { 201 - display: flex; 202 - gap: 1rem; 203 - align-items: start; 204 - } 205 - 206 - .card-icon { 207 - flex-shrink: 0; 208 - width: 2rem; 209 - height: 2rem; 210 - } 211 - 212 - ul { 213 - list-style: none; 214 - margin: 1rem 0; 215 - } 216 - 217 62 li { 218 63 display: flex; 219 64 align-items: start; ··· 222 67 color: var(--text-muted); 223 68 } 224 69 225 - .bullet { 226 - flex-shrink: 0; 227 - margin-top: 0.25rem; 228 - } 229 - 230 - .bullet.red { color: var(--red); } 231 - .bullet.green { color: var(--success); } 232 - .bullet.yellow { color: var(--yellow); } 233 - .bullet.accent { color: var(--accent); } 234 - 235 - .alert { 236 - background: var(--code-bg); 237 - border-left: 4px solid var(--red); 238 - padding: 1rem; 239 - border-radius: 0.25rem; 240 - margin: 1rem 0; 241 - } 242 - 243 70 .alert p { margin: 0; } 244 71 245 - ol { 246 - list-style: none; 247 - counter-reset: item; 248 - margin: 1rem 0; 249 - } 250 - 251 - ol li { 252 - counter-increment: item; 253 - } 254 - 255 - ol li::before { 256 - content: counter(item) "."; 257 - font-weight: 700; 258 - color: var(--accent); 259 - margin-right: 0.75rem; 260 - } 261 - 262 - a { 263 - color: var(--accent); 264 - text-decoration: none; 265 - font-weight: 500; 266 - } 267 - 268 - a:hover { opacity: 0.8; } 269 - 270 - footer { 271 - border-top: 1px solid var(--border-light); 272 - background: var(--bg-alt); 273 - padding: 2rem 1rem; 274 - margin-top: auto; 275 - text-align: center; 276 - font-size: 0.875rem; 277 - color: var(--text-muted); 278 - } 279 - 280 - footer p { margin-bottom: 0.5rem; } 281 - 282 72 @media (max-width: 768px) { 283 - h1 { font-size: 2rem; } 284 - h2 { font-size: 1.5rem; } 285 - h3 { font-size: 1.25rem; } 73 + .hero h1 { font-size: 2rem; } 286 74 .meta { flex-direction: column; gap: 0.5rem; } 287 75 .meta-divider { display: none; } 288 76 } ··· 538 326 </article> 539 327 </div> 540 328 541 - <footer> 329 + <footer class="simple"> 542 330 <p> 543 331 Built by <a href="https://bsky.app/profile/nekomimi.pet" target="_blank">@nekomimi.pet</a> • 544 332 Contact: <a href="mailto:contact@wisp.place">contact@wisp.place</a> •
+5 -116
apps/main-app/public/editor/onboarding.html
··· 8 8 <link rel="preconnect" href="https://fonts.googleapis.com"> 9 9 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 10 10 <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> 11 + <link rel="stylesheet" href="/wisp.css"> 11 12 <style> 12 - * { margin: 0; padding: 0; box-sizing: border-box; } 13 - 14 - :root { 15 - --bg: oklch(0.92 0.012 35); 16 - --bg-alt: oklch(0.88 0.01 35); 17 - --text: oklch(0.15 0.015 30); 18 - --text-muted: oklch(0.35 0.02 30); 19 - --text-subtle: oklch(0.50 0.02 30); 20 - --border: oklch(0.30 0.025 35); 21 - --border-light: oklch(0.65 0.02 30); 22 - --accent: oklch(0.65 0.18 345); 23 - --cta-bg: oklch(0.30 0.025 35); 24 - --cta-text: oklch(0.96 0.008 35); 25 - --code-bg: oklch(0.95 0.008 35); 26 - --success: oklch(0.65 0.20 145); 27 - } 28 - 29 - @media (prefers-color-scheme: dark) { 30 - :root { 31 - --bg: oklch(0.23 0.015 285); 32 - --bg-alt: oklch(0.20 0.015 285); 33 - --text: oklch(0.90 0.005 285); 34 - --text-muted: oklch(0.72 0.01 285); 35 - --text-subtle: oklch(0.55 0.01 285); 36 - --border: oklch(0.90 0.005 285); 37 - --border-light: oklch(0.38 0.02 285); 38 - --accent: oklch(0.85 0.08 5); 39 - --cta-bg: oklch(0.70 0.10 295); 40 - --cta-text: oklch(0.23 0.015 285); 41 - --code-bg: oklch(0.28 0.015 285); 42 - } 43 - } 44 - 45 - body { 46 - font-family: "JetBrains Mono", monospace; 47 - background: var(--bg); 48 - color: var(--text); 49 - line-height: 1.6; 50 - } 51 - .container { max-width: 600px; margin: 0 auto; padding: 3rem 1rem; } 52 - header { 53 - border-bottom: 1px solid var(--border-light); 54 - padding: 1rem 2rem; 55 - background: var(--bg); 56 - position: sticky; 57 - top: 0; 58 - z-index: 100; 59 - } 60 - .logo { font-size: 1.125rem; font-weight: 700; color: var(--text); letter-spacing: -0.02em; } 13 + .container { max-width: 600px; } 61 14 .progress { display: flex; justify-content: center; align-items: center; gap: 1rem; margin-bottom: 2rem; } 62 15 .step-indicator { 63 16 width: 2rem; height: 2rem; border-radius: 50%; ··· 68 21 .step-indicator.active { background: var(--cta-bg); color: var(--cta-text); } 69 22 .step-indicator.complete { background: var(--success); color: var(--bg); } 70 23 .progress-line { width: 4rem; height: 2px; background: var(--border-light); } 71 - .card { 72 - background: var(--bg-alt); 73 - border: 1px solid var(--border-light); 74 - border-radius: 0.5rem; 75 - padding: 1.5rem; 76 - } 77 - h1 { font-size: 1.5rem; margin-bottom: 0.5rem; text-align: center; color: var(--text); } 78 - h2 { font-size: 1.25rem; margin-bottom: 1rem; color: var(--text); } 79 - p { color: var(--text-muted); margin-bottom: 1rem; } 80 - .text-center { text-align: center; } 81 - .text-muted { color: var(--text-muted); font-size: 0.875rem; } 82 - label { display: block; margin-bottom: 0.5rem; font-size: 0.875rem; font-weight: 500; color: var(--text); } 83 - input { 84 - width: 100%; 85 - padding: 0.5rem 0.75rem; 86 - background: var(--bg); 87 - border: 1px solid var(--border-light); 88 - border-radius: 0.375rem; 89 - color: var(--text); 90 - font-size: 0.875rem; 91 - font-family: "JetBrains Mono", monospace; 92 - } 93 - input:focus { outline: 2px solid var(--accent); outline-offset: 2px; } 94 - button { 95 - width: 100%; 96 - padding: 0.5rem 1rem; 97 - background: var(--cta-bg); 98 - color: var(--cta-text); 99 - border: none; 100 - border-radius: 0.375rem; 101 - font-weight: 600; 102 - cursor: pointer; 103 - font-size: 0.875rem; 104 - font-family: "JetBrains Mono", monospace; 105 - } 106 - button:hover { opacity: 0.9; } 107 - button:disabled { opacity: 0.5; cursor: not-allowed; } 108 - button.outline { 109 - background: transparent; 110 - color: var(--text); 111 - border: 1px solid var(--border-light); 112 - } 24 + h1 { font-size: 1.5rem; margin-bottom: 0.5rem; text-align: center; } 25 + h2 { font-size: 1.25rem; margin-bottom: 1rem; } 26 + button { width: 100%; } 113 27 .input-wrapper { position: relative; margin-bottom: 1rem; } 114 28 .input-icon { 115 29 position: absolute; ··· 117 31 top: 50%; 118 32 transform: translateY(-50%); 119 33 } 120 - .spinner { 121 - display: inline-block; 122 - width: 1rem; height: 1rem; 123 - border: 2px solid var(--border-light); 124 - border-top-color: var(--accent); 125 - border-radius: 50%; 126 - animation: spin 0.6s linear infinite; 127 - } 128 - @keyframes spin { to { transform: rotate(360deg); } } 129 - .success { color: var(--success); } 130 - .error { color: var(--accent); } 131 - .hidden { display: none; } 132 - .mb-1 { margin-bottom: 0.5rem; } 133 - .mb-2 { margin-bottom: 1rem; } 134 - .mb-4 { margin-bottom: 1.5rem; } 135 - .mt-4 { margin-top: 1.5rem; } 136 - .flex { display: flex; } 137 - .gap-2 { gap: 0.5rem; } 138 34 .upload-zone { 139 35 border: 2px dashed var(--border-light); 140 36 border-radius: 0.5rem; ··· 144 40 transition: border-color 0.2s; 145 41 } 146 42 .upload-zone:hover { border-color: var(--accent); } 147 - .alert { 148 - padding: 1rem; 149 - border-radius: 0.5rem; 150 - margin-bottom: 1rem; 151 - } 152 - .alert-success { background: var(--code-bg); border: 1px solid var(--border-light); color: var(--success); } 153 - .alert-info { background: var(--code-bg); color: var(--text-muted); } 154 43 </style> 155 44 </head> 156 45 <body>
+2 -267
apps/main-app/public/landingpage.html
··· 31 31 <link rel="preconnect" href="https://fonts.googleapis.com"> 32 32 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 33 33 <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> 34 + <link rel="stylesheet" href="/wisp.css"> 34 35 35 36 <style> 36 - * { 37 - margin: 0; 38 - padding: 0; 39 - box-sizing: border-box; 40 - } 41 - 42 - :root { 43 - --bg: oklch(0.92 0.012 35); 44 - --bg-alt: oklch(0.88 0.01 35); 45 - --text: oklch(0.15 0.015 30); 46 - --text-muted: oklch(0.35 0.02 30); 47 - --text-subtle: oklch(0.50 0.02 30); 48 - --border: oklch(0.30 0.025 35); 49 - --border-light: oklch(0.65 0.02 30); 50 - --accent: oklch(0.65 0.18 345); 51 - --accent-muted: oklch(0.75 0.14 345); 52 - --cta-bg: oklch(0.30 0.025 35); 53 - --cta-text: oklch(0.96 0.008 35); 54 - --code-bg: oklch(0.95 0.008 35); 55 - --success: oklch(0.65 0.20 145); 56 - } 57 - 58 - @media (prefers-color-scheme: dark) { 59 - :root { 60 - --bg: oklch(0.23 0.015 285); 61 - --bg-alt: oklch(0.20 0.015 285); 62 - --text: oklch(0.90 0.005 285); 63 - --text-muted: oklch(0.72 0.01 285); 64 - --text-subtle: oklch(0.55 0.01 285); 65 - --border: oklch(0.90 0.005 285); 66 - --border-light: oklch(0.38 0.02 285); 67 - --accent: oklch(0.85 0.08 5); 68 - --accent-muted: oklch(0.70 0.10 295); 69 - --cta-bg: oklch(0.70 0.10 295); 70 - --cta-text: oklch(0.23 0.015 285); 71 - --code-bg: oklch(0.28 0.015 285); 72 - } 73 - } 74 - 75 - html { 76 - scroll-behavior: smooth; 77 - } 78 - 79 - body { 80 - font-family: "JetBrains Mono", monospace; 81 - background: var(--bg); 82 - color: var(--text); 83 - min-height: 100vh; 84 - display: flex; 85 - flex-direction: column; 86 - line-height: 1.6; 87 - } 88 - 89 - /* Header */ 90 - header { 91 - position: sticky; 92 - top: 0; 93 - background: var(--bg); 94 - border-bottom: 1px solid var(--border-light); 95 - padding: 1rem 2rem; 96 - z-index: 100; 97 - } 98 - 99 - .header-inner { 100 - max-width: 1100px; 101 - margin: 0 auto; 102 - display: flex; 103 - justify-content: space-between; 104 - align-items: center; 105 - } 106 - 107 - .logo { 108 - font-weight: 700; 109 - font-size: 1.125rem; 110 - text-decoration: none; 111 - color: var(--text); 112 - letter-spacing: -0.02em; 113 - } 114 - 115 - nav { 116 - display: flex; 117 - gap: 2rem; 118 - align-items: center; 119 - } 120 - 121 - nav a { 122 - color: var(--text-muted); 123 - text-decoration: none; 124 - font-size: 1rem; 125 - transition: color 0.15s; 126 - } 127 - 128 - nav a:hover { 129 - color: var(--text); 130 - } 131 - 132 - .nav-cta { 133 - background: var(--cta-bg); 134 - color: var(--cta-text); 135 - padding: 0.5rem 1rem; 136 - border: 1px solid var(--border); 137 - font-weight: 600; 138 - font-size: 0.875rem; 139 - text-decoration: none; 140 - text-transform: uppercase; 141 - letter-spacing: 0.05em; 142 - transition: all 0.15s; 143 - } 144 - 145 - .nav-cta:hover { 146 - background: var(--bg); 147 - color: var(--text); 148 - } 149 - 150 37 /* Hero */ 151 38 .hero { 152 39 padding: 8rem 2rem 6rem; ··· 170 57 border: 1px solid var(--accent); 171 58 } 172 59 173 - h1 { 60 + .hero h1 { 174 61 font-size: clamp(2.75rem, 7vw, 4.25rem); 175 - font-weight: 700; 176 - line-height: 1.1; 177 - margin-bottom: 1.5rem; 178 - letter-spacing: -0.03em; 179 62 text-align: center; 180 63 } 181 64 ··· 201 84 justify-content: center; 202 85 } 203 86 204 - .cta-primary { 205 - background: var(--cta-bg); 206 - color: var(--cta-text); 207 - padding: 1rem 2rem; 208 - border: 2px solid var(--border); 209 - font-weight: 600; 210 - font-size: 1rem; 211 - text-decoration: none; 212 - text-transform: uppercase; 213 - letter-spacing: 0.05em; 214 - transition: all 0.15s; 215 - } 216 - 217 - .cta-primary:hover { 218 - background: var(--bg); 219 - color: var(--text); 220 - } 221 - 222 - .cta-secondary { 223 - background: transparent; 224 - color: var(--text); 225 - padding: 1rem 2rem; 226 - border: 2px solid var(--border); 227 - font-weight: 600; 228 - font-size: 1rem; 229 - text-decoration: none; 230 - text-transform: uppercase; 231 - letter-spacing: 0.05em; 232 - transition: all 0.15s; 233 - } 234 - 235 - .cta-secondary:hover { 236 - background: var(--cta-bg); 237 - color: var(--cta-text); 238 - } 239 - 240 87 .hero-cmd { 241 88 color: var(--text-subtle); 242 89 font-size: 1rem; ··· 533 380 margin-bottom: 2rem; 534 381 } 535 382 536 - /* Footer */ 537 - footer { 538 - padding: 4rem 2rem 2rem; 539 - border-top: 1px solid var(--border-light); 540 - margin-top: auto; 541 - } 542 - 543 - .footer-inner { 544 - max-width: 1100px; 545 - margin: 0 auto; 546 - display: grid; 547 - grid-template-columns: 2fr repeat(3, 1fr); 548 - gap: 3rem; 549 - } 550 - 551 - .footer-brand p:first-child { 552 - font-weight: 700; 553 - margin-bottom: 0.75rem; 554 - } 555 - 556 - .footer-brand p:last-child { 557 - color: var(--text-muted); 558 - font-size: 1rem; 559 - line-height: 1.6; 560 - } 561 - 562 - .footer-col h4 { 563 - font-size: 0.875rem; 564 - font-weight: 600; 565 - color: var(--text-subtle); 566 - text-transform: uppercase; 567 - letter-spacing: 0.05em; 568 - margin-bottom: 1rem; 569 - } 570 - 571 - .footer-col ul { 572 - list-style: none; 573 - } 574 - 575 - .footer-col li { 576 - margin-bottom: 0.5rem; 577 - } 578 - 579 - .footer-col a { 580 - color: var(--text-muted); 581 - text-decoration: none; 582 - font-size: 1rem; 583 - transition: color 0.15s; 584 - } 585 - 586 - .footer-col a:hover { 587 - color: var(--text); 588 - } 589 - 590 - .footer-bottom { 591 - max-width: 1100px; 592 - margin: 3rem auto 0; 593 - padding-top: 2rem; 594 - border-top: 1px solid var(--border-light); 595 - display: flex; 596 - justify-content: space-between; 597 - align-items: center; 598 - } 599 - 600 - .footer-bottom p { 601 - color: var(--text-subtle); 602 - font-size: 0.875rem; 603 - } 604 - 605 - .footer-bottom nav { 606 - gap: 1.5rem; 607 - } 608 - 609 - .footer-bottom a { 610 - color: var(--text-subtle); 611 - text-decoration: none; 612 - font-size: 0.875rem; 613 - transition: color 0.15s; 614 - } 615 - 616 - .footer-bottom a:hover { 617 - color: var(--text); 618 - } 619 - 620 383 /* Responsive */ 621 384 @media (max-width: 768px) { 622 385 .hero { 623 386 padding: 5rem 1.5rem 4rem; 624 387 } 625 388 626 - nav a:not(.nav-cta) { 627 - display: none; 628 - } 629 - 630 389 .steps { 631 390 grid-template-columns: 1fr; 632 391 gap: 2rem; ··· 640 399 grid-template-columns: 1fr; 641 400 } 642 401 643 - .footer-inner { 644 - grid-template-columns: 1fr 1fr; 645 - } 646 - 647 - .footer-brand { 648 - grid-column: span 2; 649 - } 650 - 651 - .footer-bottom { 652 - flex-direction: column; 653 - gap: 1rem; 654 - text-align: center; 655 - } 656 - 657 402 .cta-buttons { 658 403 flex-direction: column; 659 404 width: 100%; ··· 662 407 .cta-primary, .cta-secondary { 663 408 width: 100%; 664 409 text-align: center; 665 - } 666 - } 667 - 668 - @media (max-width: 480px) { 669 - .footer-inner { 670 - grid-template-columns: 1fr; 671 - } 672 - 673 - .footer-brand { 674 - grid-column: span 1; 675 410 } 676 411 } 677 412 </style>
+6
apps/main-app/src/index.ts
··· 25 25 import { DNSVerificationWorker } from './lib/dns-verification-worker' 26 26 import { createLogger, logCollector, initializeGrafanaExporters } from '@wisp/observability' 27 27 import { observabilityMiddleware } from '@wisp/observability/middleware/elysia' 28 + import { css as wispCss } from '@wisp/css' 28 29 import { promptAdminSetup } from './lib/admin-auth' 29 30 import { adminRoutes } from './routes/admin' 30 31 ··· 225 226 }) 226 227 : (app) => app 227 228 ) 229 + .get('/wisp.css', ({ set }) => { 230 + set.headers['Content-Type'] = 'text/css; charset=utf-8' 231 + set.headers['Cache-Control'] = 'public, max-age=86400' 232 + return wispCss 233 + }) 228 234 .get('/acceptable-use', async ({ set }) => { 229 235 set.headers['Content-Type'] = 'text/html; charset=utf-8' 230 236 return await Bun.file('./apps/main-app/public/editor/acceptable-use.html').text()
+8 -1
bun.lock
··· 71 71 "@tanstack/react-query": "^5.90.2", 72 72 "@wisp/atproto-utils": "workspace:*", 73 73 "@wisp/constants": "workspace:*", 74 + "@wisp/css": "workspace:*", 74 75 "@wisp/database": "workspace:*", 75 76 "@wisp/fs-utils": "workspace:*", 76 77 "@wisp/lexicons": "workspace:*", ··· 154 155 }, 155 156 "packages/@wisp/constants": { 156 157 "name": "@wisp/constants", 158 + "version": "1.0.0", 159 + }, 160 + "packages/@wisp/css": { 161 + "name": "@wisp/css", 157 162 "version": "1.0.0", 158 163 }, 159 164 "packages/@wisp/database": { ··· 837 842 838 843 "@wisp/constants": ["@wisp/constants@workspace:packages/@wisp/constants"], 839 844 845 + "@wisp/css": ["@wisp/css@workspace:packages/@wisp/css"], 846 + 840 847 "@wisp/database": ["@wisp/database@workspace:packages/@wisp/database"], 841 848 842 849 "@wisp/fs-utils": ["@wisp/fs-utils@workspace:packages/@wisp/fs-utils"], ··· 889 896 890 897 "bun-plugin-tailwind": ["bun-plugin-tailwind@0.1.2", "", { "peerDependencies": { "bun": ">=1.0.0" } }, "sha512-41jNC1tZRSK3s1o7pTNrLuQG8kL/0vR/JgiTmZAJ1eHwe0w5j6HFPKeqEk0WAD13jfrUC7+ULuewFBBCoADPpg=="], 891 898 892 - "bun-types": ["bun-types@1.3.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-qyschsA03Qz+gou+apt6HNl6HnI+sJJLL4wLDke4iugsE6584CMupOtTY1n+2YC9nGVrEKUlTs99jjRLKgWnjQ=="], 899 + "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], 893 900 894 901 "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], 895 902
+143
packages/@wisp/css/README.md
··· 1 + # wisp.css 2 + 3 + A minimal, monospace-first CSS stylesheet with automatic light/dark mode. See it live on https://wisp.place or https://sites.wisp.place/wisp.place/wisp.css for a demo. 4 + 5 + ## Quick Start 6 + 7 + ### CDN 8 + ```html 9 + <link rel="stylesheet" href="https://sites.wisp.place/wisp.place/wisp.css/wisp.css"> 10 + ``` 11 + 12 + ### Self-hosted 13 + 14 + Just copy `wisp.css` to your project and link to it: 15 + 16 + ```html 17 + <link rel="stylesheet" href="/wisp.css"> 18 + ``` 19 + 20 + ## Features 21 + 22 + - **Automatic dark mode** via `prefers-color-scheme` 23 + - **CSS custom properties** for easy theming 24 + - **JetBrains Mono** typography 25 + - **Components**: cards, buttons, alerts, forms 26 + - **Utility classes**: spacing, flexbox, text styling 27 + - **Responsive** with mobile-first breakpoints 28 + 29 + ## CSS Variables 30 + 31 + All variables use the `--wisp-` prefix. Unprefixed aliases are also available for convenience. 32 + 33 + ### Colors 34 + 35 + ```css 36 + --wisp-bg /* Main background */ 37 + --wisp-bg-alt /* Alternate background (cards, etc) */ 38 + --wisp-text /* Primary text */ 39 + --wisp-text-muted /* Secondary text */ 40 + --wisp-text-subtle /* Tertiary text */ 41 + --wisp-border /* Strong borders */ 42 + --wisp-border-light /* Light borders */ 43 + --wisp-accent /* Accent/link color */ 44 + --wisp-cta-bg /* Button background */ 45 + --wisp-cta-text /* Button text */ 46 + --wisp-code-bg /* Code block background */ 47 + --wisp-success /* Success state */ 48 + --wisp-danger /* Error/danger state */ 49 + --wisp-warning /* Warning state */ 50 + --wisp-info /* Info state */ 51 + ``` 52 + 53 + ### Customizing 54 + 55 + Override variables in your own CSS: 56 + 57 + ```css 58 + :root { 59 + --wisp-accent: oklch(0.65 0.20 200); /* Blue accent */ 60 + } 61 + ``` 62 + 63 + ## Components 64 + 65 + ### Cards 66 + 67 + ```html 68 + <div class="card">Basic card</div> 69 + <div class="card success">Success card</div> 70 + <div class="card danger">Danger card</div> 71 + <div class="card info">Info card</div> 72 + ``` 73 + 74 + ### Buttons 75 + 76 + ```html 77 + <button>Primary button</button> 78 + <button class="outline">Outline button</button> 79 + <a class="cta-primary" href="#">CTA Primary</a> 80 + <a class="cta-secondary" href="#">CTA Secondary</a> 81 + ``` 82 + 83 + ### Alerts 84 + 85 + ```html 86 + <div class="alert alert-success">Success message</div> 87 + <div class="alert alert-danger">Error message</div> 88 + <div class="alert alert-warning">Warning message</div> 89 + <div class="alert alert-info">Info message</div> 90 + ``` 91 + 92 + ### Forms 93 + 94 + ```html 95 + <label for="email">Email</label> 96 + <input type="email" id="email" placeholder="you@example.com"> 97 + ``` 98 + 99 + ## Utility Classes 100 + 101 + ### Spacing 102 + 103 + - `.m-{0-4}` - margin 104 + - `.mt-{0-6}`, `.mb-{0-6}`, `.ml-{0-4}`, `.mr-{0-4}` - directional margin 105 + - `.p-{0-6}` - padding 106 + - `.px-{1-4}`, `.py-{1-4}` - horizontal/vertical padding 107 + - `.gap-{1-6}` - flex/grid gap 108 + 109 + ### Flexbox 110 + 111 + - `.flex`, `.inline-flex` 112 + - `.flex-col`, `.flex-wrap` 113 + - `.items-start`, `.items-center`, `.items-end` 114 + - `.justify-start`, `.justify-center`, `.justify-end`, `.justify-between` 115 + 116 + ### Text 117 + 118 + - `.text-left`, `.text-center`, `.text-right` 119 + - `.text-sm`, `.text-base`, `.text-lg`, `.text-xl` 120 + - `.font-normal`, `.font-medium`, `.font-semibold`, `.font-bold` 121 + - `.text-muted`, `.text-subtle`, `.text-accent`, `.text-success`, `.text-danger` 122 + 123 + ### Display 124 + 125 + - `.hidden`, `.block`, `.inline`, `.inline-block`, `.flex`, `.grid` 126 + - `.hide-mobile` - hidden on screens < 768px 127 + - `.hide-desktop` - hidden on screens >= 769px 128 + 129 + ## Layout 130 + 131 + ```html 132 + <div class="container"> 133 + <!-- max-width: 900px, centered with padding --> 134 + </div> 135 + 136 + <div class="container-wide"> 137 + <!-- max-width: 1100px, centered with padding --> 138 + </div> 139 + ``` 140 + 141 + ## License 142 + 143 + MIT
+400
packages/@wisp/css/index.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title>wisp.css - Example</title> 7 + <link rel="preconnect" href="https://fonts.googleapis.com"> 8 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 9 + <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> 10 + <link rel="stylesheet" href="./wisp.css"> 11 + </head> 12 + <body> 13 + <header> 14 + <div class="header-inner"> 15 + <a href="#" class="logo">wisp.css</a> 16 + <nav> 17 + <a href="#typography">Typography</a> 18 + <a href="#components">Components</a> 19 + <a href="#utilities">Utilities</a> 20 + <button id="theme-toggle" class="outline" style="padding: 0.4rem 0.75rem;"> 21 + <span id="theme-icon">◐</span> <span id="theme-label">System</span> 22 + </button> 23 + </nav> 24 + </div> 25 + </header> 26 + 27 + <div class="container"> 28 + <!-- Hero Section --> 29 + <section class="text-center mb-6"> 30 + <h1>wisp.css</h1> 31 + <p class="text-lg">A minimal, monospace-first CSS stylesheet with automatic light/dark mode.</p> 32 + <div class="flex justify-center gap-3 mt-4"> 33 + <a href="#" class="cta-primary">Get Started</a> 34 + <a href="#" class="cta-secondary">View Source</a> 35 + </div> 36 + </section> 37 + 38 + <!-- Typography --> 39 + <section id="typography" class="mb-6"> 40 + <h2>Typography</h2> 41 + 42 + <div class="card"> 43 + <h1>Heading 1</h1> 44 + <h2>Heading 2</h2> 45 + <h3>Heading 3</h3> 46 + <h4>Heading 4</h4> 47 + <p>This is a paragraph with <strong>bold text</strong> and <a href="#">a link</a>. The stylesheet uses JetBrains Mono for that clean monospace aesthetic.</p> 48 + <p><small>This is small text for captions or metadata.</small></p> 49 + <p>Here's some <code>inline code</code> in a sentence.</p> 50 + <pre><code>// Code block 51 + const greeting = "Hello, wisp.css!"; 52 + console.log(greeting);</code></pre> 53 + </div> 54 + </section> 55 + 56 + <!-- Buttons --> 57 + <section id="buttons" class="mb-6"> 58 + <h2>Buttons</h2> 59 + 60 + <div class="card"> 61 + <h3>Standard Buttons</h3> 62 + <div class="flex gap-3 flex-wrap mb-4"> 63 + <button>Primary</button> 64 + <button class="outline">Outline</button> 65 + <button disabled>Disabled</button> 66 + </div> 67 + 68 + <h3>CTA Buttons</h3> 69 + <div class="flex gap-3 flex-wrap mb-4"> 70 + <a href="#" class="cta-primary">CTA Primary</a> 71 + <a href="#" class="cta-secondary">CTA Secondary</a> 72 + </div> 73 + 74 + <h3>Button Sizes</h3> 75 + <div class="flex gap-3 items-center flex-wrap"> 76 + <button>Default</button> 77 + <button class="btn-lg">Large</button> 78 + </div> 79 + </div> 80 + </section> 81 + 82 + <!-- Cards --> 83 + <section id="components" class="mb-6"> 84 + <h2>Cards</h2> 85 + 86 + <div class="card"> 87 + <h3>Default Card</h3> 88 + <p class="mb-0">This is a basic card component with some content inside.</p> 89 + </div> 90 + 91 + <div class="card success"> 92 + <h3>Success Card</h3> 93 + <p class="mb-0">Use this for positive feedback or confirmations.</p> 94 + </div> 95 + 96 + <div class="card danger"> 97 + <h3>Danger Card</h3> 98 + <p class="mb-0">Use this for errors or destructive actions.</p> 99 + </div> 100 + 101 + <div class="card warning"> 102 + <h3>Warning Card</h3> 103 + <p class="mb-0">Use this for warnings or important notices.</p> 104 + </div> 105 + 106 + <div class="card info"> 107 + <h3>Info Card</h3> 108 + <p class="mb-0">Use this for informational messages.</p> 109 + </div> 110 + 111 + <div class="card thick"> 112 + <div class="card-flex"> 113 + <div class="card-icon">💡</div> 114 + <div> 115 + <h3 class="mt-0">Card with Icon</h3> 116 + <p class="mb-0">Use <code>card-flex</code> and <code>card-icon</code> for icon layouts.</p> 117 + </div> 118 + </div> 119 + </div> 120 + </section> 121 + 122 + <!-- Alerts --> 123 + <section id="alerts" class="mb-6"> 124 + <h2>Alerts</h2> 125 + 126 + <div class="alert alert-success"> 127 + <strong>Success!</strong> Your changes have been saved. 128 + </div> 129 + 130 + <div class="alert alert-info"> 131 + <strong>Info:</strong> This is some helpful information. 132 + </div> 133 + 134 + <div class="alert alert-warning"> 135 + <strong>Warning:</strong> Please review before continuing. 136 + </div> 137 + 138 + <div class="alert alert-danger"> 139 + <strong>Error:</strong> Something went wrong. Please try again. 140 + </div> 141 + </section> 142 + 143 + <!-- Forms --> 144 + <section id="forms" class="mb-6"> 145 + <h2>Forms</h2> 146 + 147 + <div class="card"> 148 + <div class="mb-4"> 149 + <label for="name">Name</label> 150 + <input type="text" id="name" placeholder="Enter your name"> 151 + </div> 152 + 153 + <div class="mb-4"> 154 + <label for="email">Email</label> 155 + <input type="email" id="email" placeholder="you@example.com"> 156 + </div> 157 + 158 + <div class="mb-4"> 159 + <label for="message">Message</label> 160 + <textarea id="message" rows="4" placeholder="Write your message..."></textarea> 161 + </div> 162 + 163 + <div class="flex gap-3"> 164 + <button>Submit</button> 165 + <button class="outline">Cancel</button> 166 + </div> 167 + </div> 168 + </section> 169 + 170 + <!-- Lists --> 171 + <section id="lists" class="mb-6"> 172 + <h2>Lists</h2> 173 + 174 + <div class="card"> 175 + <h3>Ordered List</h3> 176 + <ol> 177 + <li>First item with automatic numbering</li> 178 + <li>Second item in the list</li> 179 + <li>Third item completes the set</li> 180 + </ol> 181 + 182 + <h3>Unordered List with Bullets</h3> 183 + <ul> 184 + <li class="flex gap-2"><span class="bullet green">•</span> Success item</li> 185 + <li class="flex gap-2"><span class="bullet red">•</span> Danger item</li> 186 + <li class="flex gap-2"><span class="bullet yellow">•</span> Warning item</li> 187 + <li class="flex gap-2"><span class="bullet accent">•</span> Accent item</li> 188 + </ul> 189 + </div> 190 + </section> 191 + 192 + <!-- Spinner --> 193 + <section id="spinner" class="mb-6"> 194 + <h2>Spinners</h2> 195 + 196 + <div class="card"> 197 + <div class="flex gap-4 items-center"> 198 + <span class="spinner"></span> 199 + <span>Default spinner</span> 200 + </div> 201 + <div class="flex gap-4 items-center mt-4"> 202 + <span class="spinner spinner-lg"></span> 203 + <span>Large spinner</span> 204 + </div> 205 + </div> 206 + </section> 207 + 208 + <!-- Utilities --> 209 + <section id="utilities" class="mb-6"> 210 + <h2>Utility Classes</h2> 211 + 212 + <div class="card"> 213 + <h3>Text Colors</h3> 214 + <p class="text-muted mb-2">text-muted - Secondary text</p> 215 + <p class="text-subtle mb-2">text-subtle - Tertiary text</p> 216 + <p class="text-accent mb-2">text-accent - Accent color</p> 217 + <p class="text-success mb-2">text-success - Success state</p> 218 + <p class="text-danger mb-2">text-danger - Danger state</p> 219 + <p class="text-warning mb-0">text-warning - Warning state</p> 220 + </div> 221 + 222 + <div class="card"> 223 + <h3>Text Alignment</h3> 224 + <p class="text-left border p-2 mb-2">text-left</p> 225 + <p class="text-center border p-2 mb-2">text-center</p> 226 + <p class="text-right border p-2 mb-0">text-right</p> 227 + </div> 228 + 229 + <div class="card"> 230 + <h3>Flexbox</h3> 231 + <div class="flex justify-between items-center border p-3 mb-3"> 232 + <span>justify-between</span> 233 + <span>items-center</span> 234 + </div> 235 + <div class="flex flex-col gap-2 border p-3"> 236 + <span>flex-col</span> 237 + <span>with gap-2</span> 238 + </div> 239 + </div> 240 + 241 + <div class="card"> 242 + <h3>Spacing</h3> 243 + <div class="bg-alt p-4 mb-2">p-4 (padding)</div> 244 + <div class="bg-alt p-2 mb-4">p-2 with mb-4 (margin-bottom)</div> 245 + <div class="flex gap-4"> 246 + <div class="bg-alt p-2">gap-4</div> 247 + <div class="bg-alt p-2">between</div> 248 + <div class="bg-alt p-2">items</div> 249 + </div> 250 + </div> 251 + </section> 252 + 253 + <!-- Color Palette --> 254 + <section id="colors" class="mb-6"> 255 + <h2>Color Palette</h2> 256 + <p>Colors automatically adapt to light/dark mode via CSS custom properties.</p> 257 + 258 + <div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));" id="color-grid"> 259 + <div class="card text-center" data-color="--wisp-bg"> 260 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-bg); border: 1px solid var(--wisp-border-light);">bg</div> 261 + <small>--wisp-bg</small><br> 262 + <code class="hex-code text-sm"></code> 263 + </div> 264 + <div class="card text-center" data-color="--wisp-bg-alt"> 265 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-bg-alt);">bg-alt</div> 266 + <small>--wisp-bg-alt</small><br> 267 + <code class="hex-code text-sm"></code> 268 + </div> 269 + <div class="card text-center" data-color="--wisp-text"> 270 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-text); color: var(--wisp-bg);">text</div> 271 + <small>--wisp-text</small><br> 272 + <code class="hex-code text-sm"></code> 273 + </div> 274 + <div class="card text-center" data-color="--wisp-accent"> 275 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-accent); color: white;">accent</div> 276 + <small>--wisp-accent</small><br> 277 + <code class="hex-code text-sm"></code> 278 + </div> 279 + <div class="card text-center" data-color="--wisp-success"> 280 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-success); color: white;">success</div> 281 + <small>--wisp-success</small><br> 282 + <code class="hex-code text-sm"></code> 283 + </div> 284 + <div class="card text-center" data-color="--wisp-danger"> 285 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-danger); color: white;">danger</div> 286 + <small>--wisp-danger</small><br> 287 + <code class="hex-code text-sm"></code> 288 + </div> 289 + <div class="card text-center" data-color="--wisp-warning"> 290 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-warning); color: black;">warning</div> 291 + <small>--wisp-warning</small><br> 292 + <code class="hex-code text-sm"></code> 293 + </div> 294 + <div class="card text-center" data-color="--wisp-info"> 295 + <div class="p-4 rounded mb-2 color-swatch" style="background: var(--wisp-info); color: white;">info</div> 296 + <small>--wisp-info</small><br> 297 + <code class="hex-code text-sm"></code> 298 + </div> 299 + </div> 300 + </section> 301 + </div> 302 + 303 + <footer> 304 + <div class="footer-inner"> 305 + <div class="footer-brand"> 306 + <p>wisp.css</p> 307 + <p>A minimal CSS stylesheet for developers who appreciate monospace aesthetics.</p> 308 + </div> 309 + <div class="footer-col"> 310 + <h4>Docs</h4> 311 + <ul> 312 + <li><a href="#typography">Typography</a></li> 313 + <li><a href="#components">Components</a></li> 314 + <li><a href="#utilities">Utilities</a></li> 315 + </ul> 316 + </div> 317 + <div class="footer-col"> 318 + <h4>Resources</h4> 319 + <ul> 320 + <li><a href="#">GitHub</a></li> 321 + <li><a href="#">npm</a></li> 322 + <li><a href="#">CDN</a></li> 323 + </ul> 324 + </div> 325 + <div class="footer-col"> 326 + <h4>More</h4> 327 + <ul> 328 + <li><a href="#">wisp.place</a></li> 329 + <li><a href="#">AT Protocol</a></li> 330 + </ul> 331 + </div> 332 + </div> 333 + <div class="footer-bottom"> 334 + <p>MIT License</p> 335 + <nav> 336 + <a href="#">GitHub</a> 337 + </nav> 338 + </div> 339 + </footer> 340 + 341 + <script> 342 + // Theme switcher 343 + const themes = ['system', 'light', 'dark'] 344 + const icons = { system: '◐', light: '☀', dark: '☾' } 345 + const labels = { system: 'System', light: 'Light', dark: 'Dark' } 346 + let currentTheme = localStorage.getItem('wisp-theme') || 'system' 347 + 348 + function applyTheme(theme) { 349 + if (theme === 'system') { 350 + document.documentElement.removeAttribute('data-theme') 351 + } else { 352 + document.documentElement.setAttribute('data-theme', theme) 353 + } 354 + document.getElementById('theme-icon').textContent = icons[theme] 355 + document.getElementById('theme-label').textContent = labels[theme] 356 + localStorage.setItem('wisp-theme', theme) 357 + setTimeout(updateHexCodes, 50) 358 + } 359 + 360 + document.getElementById('theme-toggle').addEventListener('click', () => { 361 + const idx = themes.indexOf(currentTheme) 362 + currentTheme = themes[(idx + 1) % themes.length] 363 + applyTheme(currentTheme) 364 + }) 365 + 366 + applyTheme(currentTheme) 367 + 368 + // Hex code display 369 + function rgbToHex(r, g, b) { 370 + return '#' + [r, g, b].map(x => { 371 + const hex = Math.round(x).toString(16) 372 + return hex.length === 1 ? '0' + hex : hex 373 + }).join('') 374 + } 375 + 376 + function parseColor(color) { 377 + const canvas = document.createElement('canvas') 378 + canvas.width = canvas.height = 1 379 + const ctx = canvas.getContext('2d') 380 + ctx.fillStyle = color 381 + ctx.fillRect(0, 0, 1, 1) 382 + const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data 383 + return rgbToHex(r, g, b) 384 + } 385 + 386 + function updateHexCodes() { 387 + document.querySelectorAll('[data-color]').forEach(card => { 388 + const varName = card.dataset.color 389 + const computed = getComputedStyle(document.documentElement).getPropertyValue(varName) 390 + const hex = parseColor(computed.trim()) 391 + card.querySelector('.hex-code').textContent = hex.toUpperCase() 392 + }) 393 + } 394 + 395 + // Update hex codes on load and theme change 396 + updateHexCodes() 397 + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateHexCodes) 398 + </script> 399 + </body> 400 + </html>
+6
packages/@wisp/css/index.ts
··· 1 + import { readFileSync } from 'node:fs' 2 + import { fileURLToPath } from 'node:url' 3 + import { dirname, join } from 'node:path' 4 + 5 + const __dirname = dirname(fileURLToPath(import.meta.url)) 6 + export const css = readFileSync(join(__dirname, 'wisp.css'), 'utf-8')
+25
packages/@wisp/css/package.json
··· 1 + { 2 + "name": "@wisp/css", 3 + "version": "1.0.0", 4 + "description": "A minimal, monospace-first CSS stylesheet with automatic light/dark mode", 5 + "main": "index.ts", 6 + "types": "index.ts", 7 + "style": "wisp.css", 8 + "files": [ 9 + "index.ts", 10 + "wisp.css" 11 + ], 12 + "keywords": [ 13 + "css", 14 + "stylesheet", 15 + "monospace", 16 + "dark-mode", 17 + "minimal" 18 + ], 19 + "author": "nekomimi.pet", 20 + "license": "MIT", 21 + "repository": { 22 + "type": "git", 23 + "url": "https://github.com/nekomimi-pet/wisp.place-monorepo" 24 + } 25 + }
+896
packages/@wisp/css/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 + }
+3 -2
packages/@wisp/observability/src/middleware/elysia.ts
··· 49 49 service 50 50 ) 51 51 52 - // Don't log 404 errors 53 - if (statusCode !== 404) { 52 + // Don't log 404 errors or expected auth failures 53 + const isAuthError = error?.message === 'Authentication required' 54 + if (statusCode !== 404 && !isAuthError) { 54 55 logCollector.error( 55 56 `Request failed: ${request.method} ${url.pathname}`, 56 57 service,
+1 -12
scripts/codegen.sh
··· 7 7 # Parse arguments 8 8 AUTO_ACCEPT="" 9 9 if [[ "$1" == "-y" || "$1" == "--yes" ]]; then 10 - AUTO_ACCEPT="yes |" 10 + AUTO_ACCEPT="yes |" 11 11 fi 12 12 13 13 echo "=== Generating TypeScript lexicons ===" 14 14 cd "$ROOT_DIR/packages/@wisp/lexicons" 15 15 eval "$AUTO_ACCEPT npm run codegen" 16 - 17 - echo "=== Generating Rust lexicons ===" 18 - echo "Installing jacquard-lexgen..." 19 - cargo install jacquard-lexgen --version 0.9.5 2>/dev/null || true 20 - echo "Running jacquard-codegen..." 21 - echo " Input: $ROOT_DIR/lexicons" 22 - echo " Output: $ROOT_DIR/cli/crates/lexicons/src" 23 - jacquard-codegen -i "$ROOT_DIR/lexicons" -o "$ROOT_DIR/cli/crates/lexicons/src" 24 - 25 - # Add extern crate alloc for the macro to work 26 - sed -i '' '1s/^/extern crate alloc;\n\n/' "$ROOT_DIR/cli/crates/lexicons/src/lib.rs" 27 16 28 17 echo "=== Done ==="