blumenjs 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,489 @@
1
+ import React, { useState } from "react";
2
+
3
+ interface Endpoint {
4
+ method: string;
5
+ path: string;
6
+ description: string;
7
+ status: number;
8
+ response: string;
9
+ }
10
+
11
+ const ApiPage: React.FC = () => {
12
+ const [activeEndpoint, setActiveEndpoint] = useState(0);
13
+
14
+ const endpoints: Endpoint[] = [
15
+ {
16
+ method: "GET",
17
+ path: "/api/users",
18
+ description: "List all users with pagination",
19
+ status: 200,
20
+ response: JSON.stringify({
21
+ data: [
22
+ { id: 1, name: "Sarah Chen", email: "sarah@example.com", role: "admin" },
23
+ { id: 2, name: "Alex Rivera", email: "alex@example.com", role: "user" },
24
+ { id: 3, name: "Jamie Park", email: "jamie@example.com", role: "user" },
25
+ ],
26
+ meta: { page: 1, total: 42, per_page: 10 },
27
+ }, null, 2),
28
+ },
29
+ {
30
+ method: "POST",
31
+ path: "/api/users",
32
+ description: "Create a new user account",
33
+ status: 201,
34
+ response: JSON.stringify({
35
+ data: { id: 43, name: "New User", email: "new@example.com", role: "user" },
36
+ message: "User created successfully",
37
+ }, null, 2),
38
+ },
39
+ {
40
+ method: "GET",
41
+ path: "/api/users/:id",
42
+ description: "Fetch a single user by ID",
43
+ status: 200,
44
+ response: JSON.stringify({
45
+ data: {
46
+ id: 1,
47
+ name: "Sarah Chen",
48
+ email: "sarah@example.com",
49
+ role: "admin",
50
+ created_at: "2024-01-15T08:30:00Z",
51
+ projects: 12,
52
+ },
53
+ }, null, 2),
54
+ },
55
+ {
56
+ method: "DELETE",
57
+ path: "/api/users/:id",
58
+ description: "Remove a user permanently",
59
+ status: 204,
60
+ response: JSON.stringify({
61
+ message: "User deleted",
62
+ status: 204,
63
+ }, null, 2),
64
+ },
65
+ ];
66
+
67
+ const current = endpoints[activeEndpoint];
68
+
69
+ const methodColor: Record<string, string> = {
70
+ GET: "#22c55e",
71
+ POST: "#3b82f6",
72
+ PUT: "#f59e0b",
73
+ DELETE: "#ef4444",
74
+ };
75
+
76
+ return (
77
+ <div className="bl-api">
78
+ <style
79
+ dangerouslySetInnerHTML={{
80
+ __html: `
81
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap');
82
+
83
+ @keyframes fade-up {
84
+ from { opacity: 0; transform: translateY(20px); }
85
+ to { opacity: 1; transform: translateY(0); }
86
+ }
87
+
88
+ @keyframes slide-in {
89
+ from { opacity: 0; transform: translateX(-10px); }
90
+ to { opacity: 1; transform: translateX(0); }
91
+ }
92
+
93
+ @keyframes blink {
94
+ 0%, 100% { opacity: 1; }
95
+ 50% { opacity: 0; }
96
+ }
97
+
98
+ .bl-api * { box-sizing: border-box; margin: 0; padding: 0; }
99
+
100
+ .bl-api {
101
+ min-height: 100vh;
102
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
103
+ background: #09090b;
104
+ color: #fafafa;
105
+ }
106
+
107
+ /* ── Hero ── */
108
+ .bl-api-hero {
109
+ text-align: center;
110
+ padding: 80px 24px 60px;
111
+ position: relative;
112
+ overflow: hidden;
113
+ }
114
+
115
+ .bl-api-hero::before {
116
+ content: '';
117
+ position: absolute;
118
+ top: 0; left: 50%;
119
+ width: 800px; height: 400px;
120
+ transform: translateX(-50%);
121
+ background: radial-gradient(ellipse, rgba(34, 197, 94, 0.08) 0%, transparent 70%);
122
+ pointer-events: none;
123
+ }
124
+
125
+ .bl-api-badge {
126
+ display: inline-flex;
127
+ align-items: center;
128
+ gap: 8px;
129
+ padding: 6px 16px;
130
+ border-radius: 100px;
131
+ background: rgba(34, 197, 94, 0.08);
132
+ border: 1px solid rgba(34, 197, 94, 0.2);
133
+ font-size: 0.78rem;
134
+ font-weight: 600;
135
+ color: #4ade80;
136
+ text-transform: uppercase;
137
+ letter-spacing: 0.06em;
138
+ margin-bottom: 24px;
139
+ animation: fade-up 0.6s ease-out both;
140
+ }
141
+
142
+ .bl-api-badge-dot {
143
+ width: 6px; height: 6px;
144
+ border-radius: 50%;
145
+ background: #22c55e;
146
+ }
147
+
148
+ .bl-api-title {
149
+ font-size: clamp(2.5rem, 5vw, 4rem);
150
+ font-weight: 900;
151
+ letter-spacing: -0.04em;
152
+ line-height: 1.1;
153
+ background: linear-gradient(135deg, #fafafa 0%, #4ade80 50%, #22c55e 100%);
154
+ -webkit-background-clip: text;
155
+ -webkit-text-fill-color: transparent;
156
+ background-clip: text;
157
+ margin-bottom: 16px;
158
+ animation: fade-up 0.6s ease-out 0.1s both;
159
+ }
160
+
161
+ .bl-api-subtitle {
162
+ font-size: 1.1rem;
163
+ color: #6b7280;
164
+ font-weight: 400;
165
+ max-width: 500px;
166
+ margin: 0 auto;
167
+ line-height: 1.6;
168
+ animation: fade-up 0.6s ease-out 0.2s both;
169
+ }
170
+
171
+ /* ── API Explorer ── */
172
+ .bl-api-explorer {
173
+ max-width: 1100px;
174
+ margin: 0 auto;
175
+ padding: 0 24px 80px;
176
+ display: grid;
177
+ grid-template-columns: 340px 1fr;
178
+ gap: 20px;
179
+ animation: fade-up 0.6s ease-out 0.3s both;
180
+ }
181
+
182
+ /* ── Endpoint List ── */
183
+ .bl-endpoints {
184
+ border-radius: 16px;
185
+ background: #111114;
186
+ border: 1px solid rgba(255,255,255,0.06);
187
+ padding: 20px;
188
+ }
189
+
190
+ .bl-endpoints-title {
191
+ font-size: 0.78rem;
192
+ font-weight: 700;
193
+ color: #6b7280;
194
+ text-transform: uppercase;
195
+ letter-spacing: 0.08em;
196
+ margin-bottom: 16px;
197
+ padding: 0 4px;
198
+ }
199
+
200
+ .bl-endpoint {
201
+ display: flex;
202
+ align-items: center;
203
+ gap: 12px;
204
+ padding: 14px 16px;
205
+ border-radius: 12px;
206
+ cursor: pointer;
207
+ transition: all 0.2s;
208
+ margin-bottom: 6px;
209
+ border: 1px solid transparent;
210
+ background: none;
211
+ width: 100%;
212
+ font-family: inherit;
213
+ text-align: left;
214
+ color: inherit;
215
+ }
216
+
217
+ .bl-endpoint:hover {
218
+ background: rgba(255,255,255,0.03);
219
+ }
220
+
221
+ .bl-endpoint.active {
222
+ background: rgba(255,255,255,0.05);
223
+ border-color: rgba(255,255,255,0.08);
224
+ }
225
+
226
+ .bl-method {
227
+ font-family: 'JetBrains Mono', monospace;
228
+ font-size: 0.7rem;
229
+ font-weight: 700;
230
+ padding: 3px 8px;
231
+ border-radius: 5px;
232
+ min-width: 52px;
233
+ text-align: center;
234
+ letter-spacing: 0.02em;
235
+ }
236
+
237
+ .bl-endpoint-info {
238
+ flex: 1;
239
+ min-width: 0;
240
+ }
241
+
242
+ .bl-endpoint-path {
243
+ font-family: 'JetBrains Mono', monospace;
244
+ font-size: 0.82rem;
245
+ font-weight: 500;
246
+ color: #e5e7eb;
247
+ }
248
+
249
+ .bl-endpoint-desc {
250
+ font-size: 0.75rem;
251
+ color: #6b7280;
252
+ margin-top: 3px;
253
+ }
254
+
255
+ /* ── Response Panel ── */
256
+ .bl-response {
257
+ border-radius: 16px;
258
+ background: #111114;
259
+ border: 1px solid rgba(255,255,255,0.06);
260
+ overflow: hidden;
261
+ }
262
+
263
+ .bl-response-header {
264
+ display: flex;
265
+ align-items: center;
266
+ justify-content: space-between;
267
+ padding: 16px 24px;
268
+ border-bottom: 1px solid rgba(255,255,255,0.06);
269
+ background: rgba(255,255,255,0.02);
270
+ }
271
+
272
+ .bl-response-url {
273
+ display: flex;
274
+ align-items: center;
275
+ gap: 10px;
276
+ font-family: 'JetBrains Mono', monospace;
277
+ font-size: 0.85rem;
278
+ }
279
+
280
+ .bl-response-status {
281
+ display: inline-flex;
282
+ align-items: center;
283
+ gap: 6px;
284
+ padding: 4px 12px;
285
+ border-radius: 6px;
286
+ font-size: 0.75rem;
287
+ font-weight: 700;
288
+ font-family: 'JetBrains Mono', monospace;
289
+ }
290
+
291
+ .bl-response-body {
292
+ padding: 24px;
293
+ overflow-x: auto;
294
+ }
295
+
296
+ .bl-response-body pre {
297
+ font-family: 'JetBrains Mono', monospace;
298
+ font-size: 0.82rem;
299
+ line-height: 1.7;
300
+ color: #d1d5db;
301
+ white-space: pre-wrap;
302
+ }
303
+
304
+ .bl-cursor {
305
+ display: inline-block;
306
+ width: 2px; height: 1em;
307
+ background: #22c55e;
308
+ margin-left: 2px;
309
+ vertical-align: text-bottom;
310
+ animation: blink 1s step-end infinite;
311
+ }
312
+
313
+ /* ── Architecture Section ── */
314
+ .bl-arch {
315
+ max-width: 1100px;
316
+ margin: 0 auto;
317
+ padding: 0 24px 80px;
318
+ animation: fade-up 0.6s ease-out 0.4s both;
319
+ }
320
+
321
+ .bl-arch-title {
322
+ font-size: 1.3rem;
323
+ font-weight: 800;
324
+ text-align: center;
325
+ margin-bottom: 32px;
326
+ letter-spacing: -0.02em;
327
+ }
328
+
329
+ .bl-arch-flow {
330
+ display: flex;
331
+ align-items: center;
332
+ justify-content: center;
333
+ gap: 0;
334
+ flex-wrap: wrap;
335
+ }
336
+
337
+ .bl-arch-node {
338
+ padding: 20px 28px;
339
+ border-radius: 14px;
340
+ text-align: center;
341
+ border: 1px solid rgba(255,255,255,0.06);
342
+ }
343
+
344
+ .bl-arch-node-icon {
345
+ font-size: 1.5rem;
346
+ margin-bottom: 8px;
347
+ }
348
+
349
+ .bl-arch-node-label {
350
+ font-size: 0.82rem;
351
+ font-weight: 700;
352
+ margin-bottom: 4px;
353
+ }
354
+
355
+ .bl-arch-node-sub {
356
+ font-size: 0.72rem;
357
+ color: #6b7280;
358
+ }
359
+
360
+ .bl-arch-arrow {
361
+ font-size: 1.2rem;
362
+ color: #4b5563;
363
+ padding: 0 8px;
364
+ }
365
+
366
+ @media (max-width: 768px) {
367
+ .bl-api-explorer {
368
+ grid-template-columns: 1fr;
369
+ }
370
+ .bl-arch-flow {
371
+ flex-direction: column;
372
+ gap: 8px;
373
+ }
374
+ .bl-arch-arrow {
375
+ transform: rotate(90deg);
376
+ }
377
+ }
378
+ `,
379
+ }}
380
+ />
381
+
382
+ {/* Hero */}
383
+ <div className="bl-api-hero">
384
+ <div className="bl-api-badge">
385
+ <span className="bl-api-badge-dot" />
386
+ API Template
387
+ </div>
388
+ <h1 className="bl-api-title">
389
+ Build APIs<br />at Go speed.
390
+ </h1>
391
+ <p className="bl-api-subtitle">
392
+ Server-side data fetching powered by Go. Consume external APIs
393
+ or build your own endpoints with native performance.
394
+ </p>
395
+ </div>
396
+
397
+ {/* API Explorer */}
398
+ <div className="bl-api-explorer">
399
+ {/* Endpoint List */}
400
+ <div className="bl-endpoints">
401
+ <div className="bl-endpoints-title">Endpoints</div>
402
+ {endpoints.map((ep, i) => (
403
+ <button
404
+ key={i}
405
+ className={`bl-endpoint ${activeEndpoint === i ? "active" : ""}`}
406
+ onClick={() => setActiveEndpoint(i)}
407
+ >
408
+ <span
409
+ className="bl-method"
410
+ style={{
411
+ background: `${methodColor[ep.method]}15`,
412
+ color: methodColor[ep.method],
413
+ }}
414
+ >
415
+ {ep.method}
416
+ </span>
417
+ <div className="bl-endpoint-info">
418
+ <div className="bl-endpoint-path">{ep.path}</div>
419
+ <div className="bl-endpoint-desc">{ep.description}</div>
420
+ </div>
421
+ </button>
422
+ ))}
423
+ </div>
424
+
425
+ {/* Response Panel */}
426
+ <div className="bl-response">
427
+ <div className="bl-response-header">
428
+ <div className="bl-response-url">
429
+ <span
430
+ className="bl-method"
431
+ style={{
432
+ background: `${methodColor[current.method]}15`,
433
+ color: methodColor[current.method],
434
+ }}
435
+ >
436
+ {current.method}
437
+ </span>
438
+ <span style={{ color: "#9ca3af" }}>{current.path}</span>
439
+ </div>
440
+ <span
441
+ className="bl-response-status"
442
+ style={{
443
+ background: current.status < 300 ? "rgba(34, 197, 94, 0.1)" : "rgba(239, 68, 68, 0.1)",
444
+ color: current.status < 300 ? "#4ade80" : "#f87171",
445
+ }}
446
+ >
447
+ ● {current.status} {current.status === 200 ? "OK" : current.status === 201 ? "Created" : "No Content"}
448
+ </span>
449
+ </div>
450
+ <div className="bl-response-body">
451
+ <pre>{current.response}<span className="bl-cursor" /></pre>
452
+ </div>
453
+ </div>
454
+ </div>
455
+
456
+ {/* Architecture Flow */}
457
+ <div className="bl-arch">
458
+ <h2 className="bl-arch-title">How it works</h2>
459
+ <div className="bl-arch-flow">
460
+ <div className="bl-arch-node" style={{ background: "rgba(59, 130, 246, 0.06)" }}>
461
+ <div className="bl-arch-node-icon">🌐</div>
462
+ <div className="bl-arch-node-label">Browser</div>
463
+ <div className="bl-arch-node-sub">React SPA</div>
464
+ </div>
465
+ <div className="bl-arch-arrow">→</div>
466
+ <div className="bl-arch-node" style={{ background: "rgba(34, 197, 94, 0.06)" }}>
467
+ <div className="bl-arch-node-icon">⚡</div>
468
+ <div className="bl-arch-node-label">Go Server</div>
469
+ <div className="bl-arch-node-sub">HTTP + Routing</div>
470
+ </div>
471
+ <div className="bl-arch-arrow">→</div>
472
+ <div className="bl-arch-node" style={{ background: "rgba(168, 85, 247, 0.06)" }}>
473
+ <div className="bl-arch-node-icon">⚛️</div>
474
+ <div className="bl-arch-node-label">Node SSR</div>
475
+ <div className="bl-arch-node-sub">React Rendering</div>
476
+ </div>
477
+ <div className="bl-arch-arrow">→</div>
478
+ <div className="bl-arch-node" style={{ background: "rgba(245, 158, 11, 0.06)" }}>
479
+ <div className="bl-arch-node-icon">🗃️</div>
480
+ <div className="bl-arch-node-label">Your API</div>
481
+ <div className="bl-arch-node-sub">C#, Python, etc.</div>
482
+ </div>
483
+ </div>
484
+ </div>
485
+ </div>
486
+ );
487
+ };
488
+
489
+ export default ApiPage;