|
103 | 103 | .cmt { color: #546e7a; font-style: italic; } |
104 | 104 | .num { color: #f78c6c; } |
105 | 105 |
|
| 106 | + /* === Use Case Carousel === */ |
| 107 | + .use-carousel { max-width: 880px; margin: 40px auto 0; position: relative; } |
| 108 | + .use-slides { overflow: hidden; border-radius: var(--radius-lg); } |
| 109 | + .use-slide { |
| 110 | + display: none; grid-template-columns: auto 1fr; |
| 111 | + gap: 28px; align-items: start; |
| 112 | + background: var(--bg-card); border: 1px solid var(--border-card); |
| 113 | + border-radius: var(--radius-lg); padding: 28px 32px; |
| 114 | + animation: useFadeIn 0.4s ease; |
| 115 | + } |
| 116 | + .use-slide.active { display: grid; } |
| 117 | + @keyframes useFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } |
| 118 | + .use-icon { |
| 119 | + display: flex; flex-direction: column; align-items: center; gap: 8px; |
| 120 | + padding: 16px 20px; border-radius: var(--radius-md); |
| 121 | + font-family: var(--font-mono); font-size: 12px; text-align: center; |
| 122 | + min-width: 110px; background: var(--accent-subtle); border: 1px solid rgba(56,189,248,0.2); |
| 123 | + } |
| 124 | + .use-icon .u-emoji { font-size: 28px; } |
| 125 | + .use-icon .u-label { font-size: 10px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600; } |
| 126 | + .use-body { min-width: 0; } |
| 127 | + .use-body h4 { font-size: 16px; font-weight: 600; color: #fff; margin-bottom: 6px; } |
| 128 | + .use-body p { font-size: 13px; color: var(--text-secondary); line-height: 1.55; margin-bottom: 12px; } |
| 129 | + .use-body .use-code { |
| 130 | + font-family: var(--font-mono); font-size: 12px; color: var(--text-secondary); |
| 131 | + background: #111113; border: 1px solid var(--border-subtle); |
| 132 | + border-radius: var(--radius-sm); padding: 10px 14px; |
| 133 | + white-space: pre; overflow-x: auto; |
| 134 | + } |
| 135 | + .use-body .use-code .kw { color: #c792ea; } |
| 136 | + .use-body .use-code .fn { color: #82aaff; } |
| 137 | + .use-body .use-code .str { color: #c3e88d; } |
| 138 | + .use-body .use-code .cmt { color: #546e7a; font-style: italic; } |
| 139 | + .use-body .use-code .num { color: #f78c6c; } |
| 140 | + .use-controls { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 14px; } |
| 141 | + .use-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--border-card); border: none; cursor: pointer; transition: all 0.2s; padding: 0; } |
| 142 | + .use-dot.active { background: var(--accent); box-shadow: 0 0 8px rgba(56,189,248,0.3); } |
| 143 | + .use-dot:hover { background: var(--text-tertiary); } |
| 144 | + .use-label { font-family: var(--font-mono); font-size: 11px; color: var(--text-tertiary); margin-left: 8px; letter-spacing: 0.5px; } |
| 145 | + |
106 | 146 | /* === Security rows === */ |
107 | 147 | .security-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; } |
108 | 148 | .badge { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px; font-size: 12px; font-weight: 500; } |
|
114 | 154 | .stats { gap: 20px; } |
115 | 155 | .stat .num { font-size: 24px; } |
116 | 156 | .section-inner { padding: 48px 16px; } |
| 157 | + .use-slide { grid-template-columns: 1fr; gap: 16px; padding: 20px; } |
| 158 | + .use-icon { flex-direction: row; min-width: auto; justify-content: center; gap: 12px; } |
117 | 159 | } |
118 | 160 | </style> |
119 | 161 |
|
@@ -196,6 +238,114 @@ <h1 style="font-size:clamp(40px,6vw,64px);font-weight:700;color:#fff;letter-spac |
196 | 238 | <div class="stat"><div class="num">8+</div><div class="label">LB Strategies</div></div> |
197 | 239 | <div class="stat"><div class="num">TLS 1.3</div><div class="label">Enterprise Security</div></div> |
198 | 240 | </div> |
| 241 | + |
| 242 | + <!-- Use Case Carousel --> |
| 243 | + <div class="use-carousel"> |
| 244 | + <div class="use-slides"> |
| 245 | + <div class="use-slide active"> |
| 246 | + <div class="use-icon"><div class="u-emoji">🚀</div><div class="u-label">Microservices</div></div> |
| 247 | + <div class="use-body"> |
| 248 | + <h4>API Gateway for Microservices</h4> |
| 249 | + <p>Route traffic to dozens of backend services with intelligent load balancing, JWT auth, and per-route rate limiting — all from a single config file.</p> |
| 250 | + <div class="use-code"><span class="kw">const</span> gateway = <span class="kw">new</span> <span class="fn">BunGateway</span>({ |
| 251 | + server: { port: <span class="num">8080</span> }, |
| 252 | + cluster: { enabled: <span class="kw">true</span>, workers: <span class="num">4</span> }, |
| 253 | + auth: { secret: process.env.<span class="fn">JWT_SECRET</span> }, |
| 254 | + cors: { origin: [<span class="str">'https://myapp.com'</span>] }, |
| 255 | +}) |
| 256 | +gateway.<span class="fn">addRoute</span>({ pattern: <span class="str">'/users/*'</span>, target: <span class="str">'http://user-svc:3001'</span>, rateLimit: { max: <span class="num">100</span>, windowMs: <span class="num">60000</span> } }) |
| 257 | +gateway.<span class="fn">addRoute</span>({ pattern: <span class="str">'/payments/*'</span>, target: <span class="str">'http://pay-svc:3002'</span>, circuitBreaker: { enabled: <span class="kw">true</span>, failureThreshold: <span class="num">3</span> } })</div> |
| 258 | + </div> |
| 259 | + </div> |
| 260 | + <div class="use-slide"> |
| 261 | + <div class="use-icon"><div class="u-emoji">🎯</div><div class="u-label">Load Balancer</div></div> |
| 262 | + <div class="use-body"> |
| 263 | + <h4>Intelligent Load Balancer with Health Checks</h4> |
| 264 | + <p>Distribute traffic across backend pools with 8+ strategies. Automatic health checks detect unhealthy targets and reroute traffic without dropping requests.</p> |
| 265 | + <div class="use-code">gateway.<span class="fn">addRoute</span>({ |
| 266 | + pattern: <span class="str">'/api/*'</span>, |
| 267 | + loadBalancer: { |
| 268 | + strategy: <span class="str">'least-connections'</span>, |
| 269 | + targets: [ |
| 270 | + { url: <span class="str">'http://api1:3000'</span>, weight: <span class="num">3</span> }, |
| 271 | + { url: <span class="str">'http://api2:3000'</span>, weight: <span class="num">2</span> }, |
| 272 | + { url: <span class="str">'http://api3:3000'</span>, weight: <span class="num">1</span> }, |
| 273 | + ], |
| 274 | + healthCheck: { enabled: <span class="kw">true</span>, interval: <span class="num">15000</span>, path: <span class="str">'/health'</span> }, |
| 275 | + stickySessions: { enabled: <span class="kw">true</span> }, |
| 276 | + }, |
| 277 | +})</div> |
| 278 | + </div> |
| 279 | + </div> |
| 280 | + <div class="use-slide"> |
| 281 | + <div class="use-icon"><div class="u-emoji">🔒</div><div class="u-label">TLS Proxy</div></div> |
| 282 | + <div class="use-body"> |
| 283 | + <h4>TLS Termination with Auto HTTP→HTTPS Redirect</h4> |
| 284 | + <p>Terminate TLS 1.3 at the edge with automatic certificate loading, strong cipher suites, and seamless HTTP-to-HTTPS redirection. Zero config beyond pointing at your cert files.</p> |
| 285 | + <div class="use-code"><span class="kw">const</span> gateway = <span class="kw">new</span> <span class="fn">BunGateway</span>({ |
| 286 | + server: { port: <span class="num">443</span> }, |
| 287 | + security: { |
| 288 | + tls: { |
| 289 | + enabled: <span class="kw">true</span>, |
| 290 | + cert: <span class="str">'./cert.pem'</span>, |
| 291 | + key: <span class="str">'./key.pem'</span>, |
| 292 | + minVersion: <span class="str">'TLSv1.3'</span>, |
| 293 | + redirectHTTP: <span class="kw">true</span>, |
| 294 | + redirectPort: <span class="num">80</span>, |
| 295 | + }, |
| 296 | + }, |
| 297 | +})</div> |
| 298 | + </div> |
| 299 | + </div> |
| 300 | + <div class="use-slide"> |
| 301 | + <div class="use-icon"><div class="u-emoji">⚡</div><div class="u-label">Cluster Mode</div></div> |
| 302 | + <div class="use-body"> |
| 303 | + <h4>Multi-Process Cluster with Zero-Downtime Restarts</h4> |
| 304 | + <p>Scale horizontally across all CPU cores. Rolling restarts spawn replacements before stopping old workers — zero dropped connections during deployments.</p> |
| 305 | + <div class="use-code"><span class="kw">const</span> gateway = <span class="kw">new</span> <span class="fn">BunGateway</span>({ |
| 306 | + server: { port: <span class="num">3000</span> }, |
| 307 | + cluster: { |
| 308 | + enabled: <span class="kw">true</span>, |
| 309 | + workers: <span class="num">8</span>, |
| 310 | + restartWorkers: <span class="kw">true</span>, |
| 311 | + shutdownTimeout: <span class="num">30000</span>, |
| 312 | + maxRestarts: <span class="num">10</span>, |
| 313 | + }, |
| 314 | +}) |
| 315 | +<span class="cmt">// Scale at runtime: kill -s SIGUSR2 <pid> → rolling restart</span> |
| 316 | +<span class="cmt">// Increase workers: gateway.cluster.scale(12)</span></div> |
| 317 | + </div> |
| 318 | + </div> |
| 319 | + <div class="use-slide"> |
| 320 | + <div class="use-icon"><div class="u-emoji">🛡️</div><div class="u-label">Edge Proxy</div></div> |
| 321 | + <div class="use-body"> |
| 322 | + <h4>Secure Edge Proxy with Defense-in-Depth</h4> |
| 323 | + <p>Every request passes through TLS termination, input validation, JWT verification, and security headers — before reaching your backend. OWASP Top 10 covered by default.</p> |
| 324 | + <div class="use-code"><span class="kw">const</span> gateway = <span class="kw">new</span> <span class="fn">BunGateway</span>({ |
| 325 | + security: { |
| 326 | + tls: { enabled: <span class="kw">true</span>, cert: <span class="str">'./cert.pem'</span>, key: <span class="str">'./key.pem'</span> }, |
| 327 | + jwtKeyRotation: { |
| 328 | + secrets: [{ key: process.env.<span class="fn">JWT_NEW</span>, kid: <span class="str">'2025-05'</span>, primary: <span class="kw">true</span> }], |
| 329 | + jwksUri: <span class="str">'https://auth.example.com/.well-known/jwks.json'</span>, |
| 330 | + }, |
| 331 | + inputValidation: { |
| 332 | + blockedPatterns: [<span class="str">/\.\./</span>, <span class="str">/%00/</span>, <span class="str">/<script>/i</span>], |
| 333 | + }, |
| 334 | + securityHeaders: { enabled: <span class="kw">true</span> }, |
| 335 | + }, |
| 336 | +})</div> |
| 337 | + </div> |
| 338 | + </div> |
| 339 | + </div> |
| 340 | + <div class="use-controls"> |
| 341 | + <button class="use-dot active" data-index="0" aria-label="Microservices Gateway"></button> |
| 342 | + <button class="use-dot" data-index="1" aria-label="Load Balancer"></button> |
| 343 | + <button class="use-dot" data-index="2" aria-label="TLS Proxy"></button> |
| 344 | + <button class="use-dot" data-index="3" aria-label="Cluster Mode"></button> |
| 345 | + <button class="use-dot" data-index="4" aria-label="Edge Proxy"></button> |
| 346 | + <span class="use-label">use cases</span> |
| 347 | + </div> |
| 348 | + </div> |
199 | 349 | </section> |
200 | 350 |
|
201 | 351 | <!-- Features --> |
@@ -380,6 +530,39 @@ <h2 style="font-size:clamp(28px,3.5vw,40px);font-weight:700;color:#fff;letter-sp |
380 | 530 | }); |
381 | 531 | }); |
382 | 532 | }); |
| 533 | + |
| 534 | + // Use Case Carousel |
| 535 | + (function(){ |
| 536 | + var slides = document.querySelectorAll('.use-slide'); |
| 537 | + var dots = document.querySelectorAll('.use-dot'); |
| 538 | + var current = 0; |
| 539 | + var interval = 6000; |
| 540 | + var timer; |
| 541 | + |
| 542 | + function show(idx) { |
| 543 | + slides[current].classList.remove('active'); |
| 544 | + dots[current].classList.remove('active'); |
| 545 | + current = (idx + slides.length) % slides.length; |
| 546 | + slides[current].classList.add('active'); |
| 547 | + dots[current].classList.add('active'); |
| 548 | + } |
| 549 | + |
| 550 | + function next() { show(current + 1); } |
| 551 | + |
| 552 | + dots.forEach(function(dot) { |
| 553 | + dot.addEventListener('click', function() { |
| 554 | + show(parseInt(this.dataset.index)); |
| 555 | + clearInterval(timer); |
| 556 | + timer = setInterval(next, interval); |
| 557 | + }); |
| 558 | + }); |
| 559 | + |
| 560 | + timer = setInterval(next, interval); |
| 561 | + |
| 562 | + var carousel = document.querySelector('.use-carousel'); |
| 563 | + carousel.addEventListener('mouseenter', function(){ clearInterval(timer); }); |
| 564 | + carousel.addEventListener('mouseleave', function(){ timer = setInterval(next, interval); }); |
| 565 | + })(); |
383 | 566 | </script> |
384 | 567 |
|
385 | 568 | </body> |
|
0 commit comments