opentwig 1.0.7 → 1.1.1

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.
Files changed (62) hide show
  1. package/AGENTS.md +172 -0
  2. package/API.md +582 -0
  3. package/CODE_OF_CONDUCT.md +91 -0
  4. package/CONTRIBUTING.md +312 -0
  5. package/README.md +164 -7
  6. package/SECURITY.md +56 -0
  7. package/THEME_DEVELOPMENT.md +388 -0
  8. package/package.json +19 -4
  9. package/src/constants.js +14 -2
  10. package/src/index.js +14 -2
  11. package/src/live-ui/editor.js +174 -0
  12. package/src/live-ui/preview.js +77 -0
  13. package/src/live-ui/sidebar.js +525 -0
  14. package/src/utils/escapeHTML.js +10 -0
  15. package/src/utils/favicon.js +20 -0
  16. package/src/utils/generateOGImage.js +51 -10
  17. package/src/utils/loadConfig.js +3 -1
  18. package/src/utils/parseArgs.js +33 -2
  19. package/src/utils/readImageAsBase64.js +16 -4
  20. package/src/utils/setupWatcher.js +69 -0
  21. package/src/utils/showHelp.js +15 -2
  22. package/src/utils/startLiveServer.js +221 -0
  23. package/src/utils/websocketServer.js +53 -0
  24. package/theme/dark/style.css +1 -0
  25. package/theme/default/index.js +12 -8
  26. package/validateConfig.js +59 -0
  27. package/vitest.config.js +20 -0
  28. package/website/README.md +42 -0
  29. package/website/components.json +16 -0
  30. package/website/eslint.config.js +36 -0
  31. package/website/package-lock.json +4136 -0
  32. package/website/package.json +41 -0
  33. package/website/shadcn-svelte.md +118 -0
  34. package/website/src/app.d.ts +13 -0
  35. package/website/src/lib/components/ui/badge/badge.svelte +50 -0
  36. package/website/src/lib/components/ui/badge/index.ts +2 -0
  37. package/website/src/lib/components/ui/button/button.svelte +82 -0
  38. package/website/src/lib/components/ui/button/index.ts +17 -0
  39. package/website/src/lib/components/ui/card/card-action.svelte +20 -0
  40. package/website/src/lib/components/ui/card/card-content.svelte +15 -0
  41. package/website/src/lib/components/ui/card/card-description.svelte +20 -0
  42. package/website/src/lib/components/ui/card/card-footer.svelte +20 -0
  43. package/website/src/lib/components/ui/card/card-header.svelte +23 -0
  44. package/website/src/lib/components/ui/card/card-title.svelte +20 -0
  45. package/website/src/lib/components/ui/card/card.svelte +23 -0
  46. package/website/src/lib/components/ui/card/index.ts +25 -0
  47. package/website/src/lib/components/ui/separator/index.ts +7 -0
  48. package/website/src/lib/components/ui/separator/separator.svelte +21 -0
  49. package/website/src/lib/components/ui/tooltip/index.ts +19 -0
  50. package/website/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  51. package/website/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  52. package/website/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  53. package/website/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  54. package/website/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  55. package/website/src/lib/index.ts +1 -0
  56. package/website/src/lib/utils.ts +13 -0
  57. package/website/src/routes/+layout.svelte +23 -0
  58. package/website/src/routes/+page.server.ts +82 -0
  59. package/website/src/routes/+page.svelte +892 -0
  60. package/website/static/robots.txt +3 -0
  61. package/website/svelte.config.js +31 -0
  62. package/website/vite.config.ts +5 -0
@@ -0,0 +1,892 @@
1
+ <script lang="ts">
2
+ import { Button } from "$lib/components/ui/button";
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardHeader,
7
+ CardTitle,
8
+ CardDescription,
9
+ } from "$lib/components/ui/card";
10
+ import { Badge } from "$lib/components/ui/badge";
11
+ import { Separator } from "$lib/components/ui/separator";
12
+ import {
13
+ Github,
14
+ Package,
15
+ Star,
16
+ Download,
17
+ Palette,
18
+ Smartphone,
19
+ Zap,
20
+ Code,
21
+ Image,
22
+ QrCode,
23
+ Share2,
24
+ ExternalLink,
25
+ Leaf,
26
+ Command,
27
+ Eye,
28
+ CheckCircle2,
29
+ ArrowRight,
30
+ Sparkles,
31
+ Copy,
32
+ Check,
33
+ } from "@lucide/svelte";
34
+
35
+ import {
36
+ Tooltip,
37
+ TooltipContent,
38
+ TooltipProvider,
39
+ TooltipTrigger,
40
+ } from "$lib/components/ui/tooltip";
41
+ import type { PageData } from "./$types";
42
+
43
+ let { data }: { data: PageData } = $props();
44
+
45
+ let copied = $state(false);
46
+
47
+ const installCommand = "npx opentwig --init";
48
+
49
+ function copyCommand() {
50
+ navigator.clipboard.writeText(installCommand);
51
+ copied = true;
52
+ setTimeout(() => (copied = false), 2000);
53
+ }
54
+
55
+ const features = [
56
+ {
57
+ icon: Palette,
58
+ title: "4 Beautiful Themes",
59
+ description:
60
+ "Choose from default, dark, minimal, and colorful themes. Each crafted with attention to detail.",
61
+ },
62
+ {
63
+ icon: Smartphone,
64
+ title: "Mobile First",
65
+ description:
66
+ "Perfectly responsive design that looks stunning on any device, from phones to desktops.",
67
+ },
68
+ {
69
+ icon: Zap,
70
+ title: "Lightning Fast",
71
+ description:
72
+ "Generates static HTML/CSS with zero JavaScript dependencies. Instant page loads.",
73
+ },
74
+ {
75
+ icon: Eye,
76
+ title: "Live Preview Mode",
77
+ description:
78
+ "Interactive editor with real-time preview. Edit config, see changes instantly.",
79
+ },
80
+ {
81
+ icon: Image,
82
+ title: "Social Previews",
83
+ description:
84
+ "Auto-generated Open Graph images for perfect sharing on social media platforms.",
85
+ },
86
+ {
87
+ icon: QrCode,
88
+ title: "QR Code Built-in",
89
+ description:
90
+ "Every page includes a QR code for easy mobile sharing and offline distribution.",
91
+ },
92
+ ];
93
+
94
+ const themes = [
95
+ {
96
+ name: "Default",
97
+ description: "Clean & Modern",
98
+ style: "bg-gradient-to-br from-slate-50 to-slate-100 border-slate-200",
99
+ },
100
+ {
101
+ name: "Dark",
102
+ description: "Elegant & Sophisticated",
103
+ style: "bg-gradient-to-br from-slate-900 to-slate-800 border-slate-700",
104
+ },
105
+ {
106
+ name: "Minimal",
107
+ description: "Simple & Focused",
108
+ style: "bg-gradient-to-br from-gray-50 to-white border-gray-200",
109
+ },
110
+ {
111
+ name: "Colorful",
112
+ description: "Vibrant & Bold",
113
+ style: "bg-gradient-to-br from-indigo-500 via-purple-500 to-pink-500",
114
+ },
115
+ ];
116
+ </script>
117
+
118
+ <TooltipProvider>
119
+ <div class="min-h-screen bg-background leaf-pattern">
120
+ <!-- Navigation -->
121
+ <nav
122
+ class="sticky top-0 z-50 w-full border-b border-border/50 bg-background/80 backdrop-blur-md"
123
+ >
124
+ <div
125
+ class="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8"
126
+ >
127
+ <div class="flex items-center gap-2">
128
+ <Leaf class="h-6 w-6 text-primary" />
129
+ <span class="text-xl font-bold tracking-tight"
130
+ >OpenTwig</span
131
+ >
132
+ </div>
133
+ <div class="flex items-center gap-4">
134
+ <a
135
+ href="https://github.com/tufantunc/opentwig"
136
+ target="_blank"
137
+ rel="noopener noreferrer"
138
+ class="flex items-center gap-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
139
+ >
140
+ <Github class="h-4 w-4" />
141
+ <span class="hidden sm:inline">GitHub</span>
142
+ </a>
143
+ <a
144
+ href="https://www.npmjs.com/package/opentwig"
145
+ target="_blank"
146
+ rel="noopener noreferrer"
147
+ class="flex items-center gap-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
148
+ >
149
+ <Package class="h-4 w-4" />
150
+ <span class="hidden sm:inline">NPM</span>
151
+ </a>
152
+ </div>
153
+ </div>
154
+ </nav>
155
+
156
+ <!-- Hero Section -->
157
+ <section
158
+ class="relative overflow-hidden px-4 py-20 sm:px-6 sm:py-32 lg:px-8"
159
+ >
160
+ <div class="mx-auto max-w-4xl text-center">
161
+ <!-- Badge -->
162
+ <div class="mb-8 flex justify-center">
163
+ <Badge
164
+ variant="secondary"
165
+ class="gap-1.5 px-3 py-1.5 text-sm font-medium"
166
+ >
167
+ <Sparkles class="h-3.5 w-3.5" />
168
+ <span>100% Free & Open Source</span>
169
+ </Badge>
170
+ </div>
171
+
172
+ <!-- Headline -->
173
+ <h1
174
+ class="mb-6 text-4xl font-extrabold tracking-tight text-foreground sm:text-5xl md:text-6xl lg:text-7xl"
175
+ >
176
+ Create Your
177
+ <span class="gradient-text">Link in Bio</span>
178
+ Page
179
+ </h1>
180
+
181
+ <!-- Subheadline -->
182
+ <p
183
+ class="mx-auto mb-10 max-w-2xl text-lg text-muted-foreground sm:text-xl"
184
+ >
185
+ A beautiful, customizable link page generator that puts you
186
+ in control. No third-party services. No tracking. Just you
187
+ and your links.
188
+ </p>
189
+
190
+ <!-- CTAs -->
191
+ <div
192
+ class="flex flex-col items-center justify-center gap-4 sm:flex-row"
193
+ >
194
+ <Tooltip>
195
+ <TooltipTrigger>
196
+ <Button
197
+ size="lg"
198
+ class="gap-2 px-8"
199
+ href="https://github.com/tufantunc/opentwig"
200
+ target="_blank"
201
+ rel="noopener noreferrer"
202
+ >
203
+ <Github class="h-5 w-5" />
204
+ <span>Star on GitHub</span>
205
+ </Button>
206
+ </TooltipTrigger>
207
+ <TooltipContent>
208
+ <p>Show your support!</p>
209
+ </TooltipContent>
210
+ </Tooltip>
211
+
212
+ <Button
213
+ variant="outline"
214
+ size="lg"
215
+ class="gap-2 px-8"
216
+ href="#get-started"
217
+ >
218
+ <Command class="h-5 w-5" />
219
+ <span>Get Started</span>
220
+ </Button>
221
+ </div>
222
+
223
+ <!-- Stats Bar -->
224
+ <div
225
+ class="mt-16 grid grid-cols-2 gap-8 border-y border-border/50 py-8 sm:grid-cols-4"
226
+ >
227
+ <div class="text-center">
228
+ <div
229
+ class="flex items-center justify-center gap-1.5 text-3xl font-bold text-foreground"
230
+ >
231
+ <Download class="h-6 w-6 text-primary" />
232
+ <span>{data.stats.formattedNpmDownloads}</span>
233
+ </div>
234
+ <p class="mt-1 text-sm text-muted-foreground">
235
+ NPM Downloads
236
+ </p>
237
+ </div>
238
+ <div class="text-center">
239
+ <div
240
+ class="flex items-center justify-center gap-1.5 text-3xl font-bold text-foreground"
241
+ >
242
+ <Star class="h-6 w-6 text-primary" />
243
+ <span>{data.stats.formattedGithubStars}</span>
244
+ </div>
245
+ <p class="mt-1 text-sm text-muted-foreground">
246
+ GitHub Stars
247
+ </p>
248
+ </div>
249
+ <div class="text-center">
250
+ <div
251
+ class="flex items-center justify-center gap-1.5 text-3xl font-bold text-foreground"
252
+ >
253
+ <Palette class="h-6 w-6 text-primary" />
254
+ <span>4</span>
255
+ </div>
256
+ <p class="mt-1 text-sm text-muted-foreground">Themes</p>
257
+ </div>
258
+ <div class="text-center">
259
+ <div
260
+ class="flex items-center justify-center gap-1.5 text-3xl font-bold text-foreground"
261
+ >
262
+ <CheckCircle2 class="h-6 w-6 text-primary" />
263
+ <span>MIT</span>
264
+ </div>
265
+ <p class="mt-1 text-sm text-muted-foreground">
266
+ License
267
+ </p>
268
+ </div>
269
+ </div>
270
+ </div>
271
+ </section>
272
+
273
+ <!-- Features Section -->
274
+ <section id="features" class="px-4 py-20 sm:px-6 lg:px-8">
275
+ <div class="mx-auto max-w-7xl">
276
+ <div class="mb-16 text-center">
277
+ <h2
278
+ class="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl"
279
+ >
280
+ Everything You Need
281
+ </h2>
282
+ <p class="mx-auto max-w-2xl text-lg text-muted-foreground">
283
+ Powerful features packed into a simple CLI tool. No
284
+ bloat, no dependencies, just results.
285
+ </p>
286
+ </div>
287
+
288
+ <div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
289
+ {#each features as feature}
290
+ <Card
291
+ class="group relative overflow-hidden transition-all hover:shadow-lg hover:border-primary/20"
292
+ >
293
+ <CardHeader>
294
+ <div
295
+ class="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10 text-primary transition-colors group-hover:bg-primary group-hover:text-primary-foreground"
296
+ >
297
+ <feature.icon class="h-6 w-6" />
298
+ </div>
299
+ <CardTitle class="text-xl"
300
+ >{feature.title}</CardTitle
301
+ >
302
+ <CardDescription class="text-base">
303
+ {feature.description}
304
+ </CardDescription>
305
+ </CardHeader>
306
+ </Card>
307
+ {/each}
308
+ </div>
309
+ </div>
310
+ </section>
311
+
312
+ <Separator class="mx-auto max-w-7xl" />
313
+
314
+ <!-- Live Preview Demo Section -->
315
+ <section class="px-4 py-20 sm:px-6 lg:px-8">
316
+ <div class="mx-auto max-w-7xl">
317
+ <div class="mb-12 text-center">
318
+ <h2
319
+ class="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl"
320
+ >
321
+ Live Preview Mode
322
+ </h2>
323
+ <p class="mx-auto max-w-2xl text-lg text-muted-foreground">
324
+ Edit your configuration in real-time with our built-in
325
+ live editor. See changes instantly.
326
+ </p>
327
+ </div>
328
+
329
+ <!-- Screenshot Placeholder -->
330
+ <div class="relative mx-auto max-w-5xl">
331
+ <div
332
+ class="relative overflow-hidden rounded-2xl border border-border bg-card shadow-2xl"
333
+ >
334
+ <!-- Browser Chrome -->
335
+ <div
336
+ class="flex items-center gap-2 border-b border-border bg-muted/50 px-4 py-3"
337
+ >
338
+ <div class="flex gap-1.5">
339
+ <div
340
+ class="h-3 w-3 rounded-full bg-red-400"
341
+ ></div>
342
+ <div
343
+ class="h-3 w-3 rounded-full bg-yellow-400"
344
+ ></div>
345
+ <div
346
+ class="h-3 w-3 rounded-full bg-green-400"
347
+ ></div>
348
+ </div>
349
+ <div
350
+ class="ml-4 flex-1 rounded-md bg-background px-3 py-1 text-xs text-muted-foreground"
351
+ >
352
+ localhost:3000
353
+ </div>
354
+ </div>
355
+
356
+ <!-- Placeholder Content -->
357
+ <div
358
+ class="relative overflow-hidden rounded-lg border border-border bg-background shadow-2xl"
359
+ >
360
+ <img
361
+ src="/live-editor.png"
362
+ alt="OpenTwig Live Editor Interface"
363
+ class="w-full h-auto object-cover"
364
+ loading="lazy"
365
+ />
366
+ </div>
367
+ </div>
368
+
369
+ <!-- Floating Features -->
370
+ <div
371
+ class="absolute -right-4 top-1/4 hidden lg:block animate-float"
372
+ >
373
+ <div
374
+ class="rounded-xl border border-border bg-card p-4 shadow-lg"
375
+ >
376
+ <div class="flex items-center gap-2 text-sm">
377
+ <Palette class="h-4 w-4 text-primary" />
378
+ <span>Theme switcher</span>
379
+ </div>
380
+ </div>
381
+ </div>
382
+
383
+ <div
384
+ class="absolute -left-4 bottom-1/4 hidden lg:block animate-float-delayed"
385
+ >
386
+ <div
387
+ class="rounded-xl border border-border bg-card p-4 shadow-lg"
388
+ >
389
+ <div class="flex items-center gap-2 text-sm">
390
+ <Eye class="h-4 w-4 text-primary" />
391
+ <span>Live Preview</span>
392
+ </div>
393
+ </div>
394
+ </div>
395
+
396
+ <div
397
+ class="absolute -right-4 bottom-8 hidden lg:block animate-float"
398
+ >
399
+ <div
400
+ class="rounded-xl border border-border bg-card p-4 shadow-lg"
401
+ >
402
+ <div class="flex items-center gap-3">
403
+ <div
404
+ class="h-2 w-2 rounded-full bg-green-500 animate-pulse"
405
+ ></div>
406
+ <span class="text-sm font-medium"
407
+ >Auto-save enabled</span
408
+ >
409
+ </div>
410
+ </div>
411
+ </div>
412
+ </div>
413
+
414
+ <!-- Feature List -->
415
+ <div class="mt-12 grid gap-6 sm:grid-cols-3">
416
+ <div class="flex items-start gap-3">
417
+ <div
418
+ class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary"
419
+ >
420
+ <CheckCircle2 class="h-4 w-4" />
421
+ </div>
422
+ <div>
423
+ <h4 class="font-semibold text-foreground">
424
+ Real-time Updates
425
+ </h4>
426
+ <p class="text-sm text-muted-foreground">
427
+ See changes as you type with WebSocket-powered
428
+ live reload
429
+ </p>
430
+ </div>
431
+ </div>
432
+ <div class="flex items-start gap-3">
433
+ <div
434
+ class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary"
435
+ >
436
+ <CheckCircle2 class="h-4 w-4" />
437
+ </div>
438
+ <div>
439
+ <h4 class="font-semibold text-foreground">
440
+ Drag & Drop
441
+ </h4>
442
+ <p class="text-sm text-muted-foreground">
443
+ Easily reorder your links with intuitive drag
444
+ and drop
445
+ </p>
446
+ </div>
447
+ </div>
448
+ <div class="flex items-start gap-3">
449
+ <div
450
+ class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary"
451
+ >
452
+ <CheckCircle2 class="h-4 w-4" />
453
+ </div>
454
+ <div>
455
+ <h4 class="font-semibold text-foreground">
456
+ Avatar Upload
457
+ </h4>
458
+ <p class="text-sm text-muted-foreground">
459
+ Upload and preview profile pictures directly in
460
+ the editor
461
+ </p>
462
+ </div>
463
+ </div>
464
+ </div>
465
+ </div>
466
+ </section>
467
+
468
+ <Separator class="mx-auto max-w-7xl" />
469
+
470
+ <!-- Themes Showcase -->
471
+ <section id="themes" class="px-4 py-20 sm:px-6 lg:px-8">
472
+ <div class="mx-auto max-w-7xl">
473
+ <div class="mb-12 text-center">
474
+ <h2
475
+ class="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl"
476
+ >
477
+ Choose Your Style
478
+ </h2>
479
+ <p class="mx-auto max-w-2xl text-lg text-muted-foreground">
480
+ Four carefully crafted themes to match your personality
481
+ and brand.
482
+ </p>
483
+ </div>
484
+
485
+ <div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
486
+ {#each themes as theme}
487
+ <Card
488
+ class="group overflow-hidden transition-all hover:shadow-lg"
489
+ >
490
+ <!-- Theme Preview -->
491
+ <div
492
+ class="relative aspect-[4/3] overflow-hidden border-b"
493
+ >
494
+ <img
495
+ src="/theme-{theme.name.toLowerCase()}.png"
496
+ alt="{theme.name} theme preview"
497
+ class="h-full w-full object-cover object-top transition-transform duration-500 group-hover:scale-105"
498
+ loading="lazy"
499
+ />
500
+ </div>
501
+ <CardHeader class="text-center">
502
+ <CardTitle class="text-lg"
503
+ >{theme.name}</CardTitle
504
+ >
505
+ <CardDescription
506
+ >{theme.description}</CardDescription
507
+ >
508
+ </CardHeader>
509
+ </Card>
510
+ {/each}
511
+ </div>
512
+
513
+ <!-- Theme Preview Screenshots Row -->
514
+ <div class="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
515
+ {#each themes as theme, i}
516
+ <div
517
+ class="relative aspect-[9/16] overflow-hidden rounded-xl border border-border bg-card shadow-lg"
518
+ >
519
+ <img
520
+ src="/theme-{theme.name.toLowerCase()}.png"
521
+ alt="{theme.name} theme preview"
522
+ class="h-full w-full object-cover object-top transition-transform duration-500 group-hover:scale-105"
523
+ loading="lazy"
524
+ />
525
+ <div
526
+ class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent"
527
+ ></div>
528
+ <div
529
+ class="absolute bottom-0 left-0 right-0 p-4 text-white"
530
+ >
531
+ <p class="text-sm font-semibold">
532
+ {theme.name}
533
+ </p>
534
+ <p class="text-xs text-white/80">
535
+ {theme.description}
536
+ </p>
537
+ </div>
538
+ </div>
539
+ {/each}
540
+ </div>
541
+ </div>
542
+ </section>
543
+
544
+ <Separator class="mx-auto max-w-7xl" />
545
+
546
+ <!-- Quick Start Section -->
547
+ <section id="get-started" class="px-4 py-20 sm:px-6 lg:px-8">
548
+ <div class="mx-auto max-w-3xl">
549
+ <div class="mb-12 text-center">
550
+ <h2
551
+ class="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl"
552
+ >
553
+ Get Started in Seconds
554
+ </h2>
555
+ <p class="mx-auto max-w-2xl text-lg text-muted-foreground">
556
+ No complex setup. Just run one command and you're ready
557
+ to go.
558
+ </p>
559
+ </div>
560
+
561
+ <!-- Installation Card -->
562
+ <Card class="overflow-hidden">
563
+ <CardHeader class="bg-muted/50">
564
+ <CardTitle class="flex items-center gap-2 text-lg">
565
+ <Command class="h-5 w-5 text-primary" />
566
+ Installation
567
+ </CardTitle>
568
+ </CardHeader>
569
+ <CardContent class="p-6">
570
+ <div class="relative">
571
+ <pre
572
+ class="relative overflow-x-auto rounded-lg bg-[#1a3320] p-4 text-sm text-[#e8f0e8]"><code
573
+ >{installCommand}</code
574
+ ></pre>
575
+ <Button
576
+ variant="ghost"
577
+ size="sm"
578
+ class="absolute right-2 top-2 gap-1.5 text-[#e8f0e8] hover:bg-[#2d4a35] hover:text-[#e8f0e8]"
579
+ onclick={copyCommand}
580
+ >
581
+ {#if copied}
582
+ <Check class="h-4 w-4" />
583
+ <span>Copied!</span>
584
+ {:else}
585
+ <Copy class="h-4 w-4" />
586
+ <span>Copy</span>
587
+ {/if}
588
+ </Button>
589
+ </div>
590
+ </CardContent>
591
+ </Card>
592
+
593
+ <!-- Steps -->
594
+ <div class="mt-8 space-y-4">
595
+ <div class="flex items-start gap-4">
596
+ <div
597
+ class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold"
598
+ >
599
+ 1
600
+ </div>
601
+ <div class="flex-1 pt-2">
602
+ <h4 class="font-semibold text-foreground">
603
+ Initialize your project
604
+ </h4>
605
+ <p class="text-sm text-muted-foreground">
606
+ Run the command above to create a sample
607
+ config.json file
608
+ </p>
609
+ </div>
610
+ </div>
611
+
612
+ <div class="flex items-start gap-4">
613
+ <div
614
+ class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold"
615
+ >
616
+ 2
617
+ </div>
618
+ <div class="flex-1 pt-2">
619
+ <h4 class="font-semibold text-foreground">
620
+ Edit your configuration
621
+ </h4>
622
+ <p class="text-sm text-muted-foreground">
623
+ Customize your links, bio, theme, and avatar in
624
+ config.json
625
+ </p>
626
+ </div>
627
+ </div>
628
+
629
+ <div class="flex items-start gap-4">
630
+ <div
631
+ class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold"
632
+ >
633
+ 3
634
+ </div>
635
+ <div class="flex-1 pt-2">
636
+ <h4 class="font-semibold text-foreground">
637
+ Generate your page
638
+ </h4>
639
+ <p class="text-sm text-muted-foreground">
640
+ Run <code
641
+ class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono"
642
+ >npx opentwig</code
643
+ > to build your static site
644
+ </p>
645
+ </div>
646
+ </div>
647
+
648
+ <div class="flex items-start gap-4">
649
+ <div
650
+ class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold"
651
+ >
652
+ 4
653
+ </div>
654
+ <div class="flex-1 pt-2">
655
+ <h4 class="font-semibold text-foreground">
656
+ Deploy anywhere
657
+ </h4>
658
+ <p class="text-sm text-muted-foreground">
659
+ Upload the dist/ folder to GitHub Pages,
660
+ Netlify, Vercel, or any static host
661
+ </p>
662
+ </div>
663
+ </div>
664
+ </div>
665
+
666
+ <!-- Live Mode CTA -->
667
+ <Card class="mt-8 border-primary/20 bg-primary/5">
668
+ <CardContent
669
+ class="flex flex-col items-center gap-4 p-6 text-center sm:flex-row sm:text-left"
670
+ >
671
+ <div
672
+ class="flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground"
673
+ >
674
+ <Zap class="h-6 w-6" />
675
+ </div>
676
+ <div class="flex-1">
677
+ <h4 class="font-semibold text-foreground">
678
+ Prefer a visual editor?
679
+ </h4>
680
+ <p class="text-sm text-muted-foreground">
681
+ Use our live preview mode with real-time editing
682
+ and auto-save
683
+ </p>
684
+ </div>
685
+ <Button variant="outline" class="gap-2">
686
+ <span>npx opentwig --live</span>
687
+ <ArrowRight class="h-4 w-4" />
688
+ </Button>
689
+ </CardContent>
690
+ </Card>
691
+ </div>
692
+ </section>
693
+
694
+ <Separator class="mx-auto max-w-7xl" />
695
+
696
+ <!-- Open Source Banner -->
697
+ <section class="px-4 py-20 sm:px-6 lg:px-8">
698
+ <div class="mx-auto max-w-4xl text-center">
699
+ <div
700
+ class="mb-8 inline-flex h-20 w-20 items-center justify-center rounded-2xl bg-primary/10"
701
+ >
702
+ <svg
703
+ class="h-10 w-10 text-primary"
704
+ viewBox="0 0 24 24"
705
+ fill="none"
706
+ stroke="currentColor"
707
+ stroke-width="2"
708
+ stroke-linecap="round"
709
+ stroke-linejoin="round"
710
+ >
711
+ <path
712
+ d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"
713
+ />
714
+ </svg>
715
+ </div>
716
+ <h2
717
+ class="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl"
718
+ >
719
+ Built with Love, Free Forever
720
+ </h2>
721
+ <p class="mx-auto mb-8 max-w-2xl text-lg text-muted-foreground">
722
+ OpenTwig is and always will be 100% free and open source. No
723
+ hidden fees, no premium tiers, no tracking. Just a tool
724
+ built by the community, for the community.
725
+ </p>
726
+ <div class="flex flex-wrap items-center justify-center gap-4">
727
+ <Badge
728
+ variant="secondary"
729
+ class="gap-1.5 px-4 py-2 text-sm"
730
+ >
731
+ <CheckCircle2 class="h-4 w-4" />
732
+ <span>MIT Licensed</span>
733
+ </Badge>
734
+ <Badge
735
+ variant="secondary"
736
+ class="gap-1.5 px-4 py-2 text-sm"
737
+ >
738
+ <CheckCircle2 class="h-4 w-4" />
739
+ <span>No Tracking</span>
740
+ </Badge>
741
+ <Badge
742
+ variant="secondary"
743
+ class="gap-1.5 px-4 py-2 text-sm"
744
+ >
745
+ <CheckCircle2 class="h-4 w-4" />
746
+ <span>No Vendor Lock-in</span>
747
+ </Badge>
748
+ </div>
749
+ </div>
750
+ </section>
751
+
752
+ <!-- Footer -->
753
+ <footer
754
+ class="border-t border-border bg-muted/30 px-4 py-12 sm:px-6 lg:px-8"
755
+ >
756
+ <div class="mx-auto max-w-7xl">
757
+ <div class="grid gap-8 sm:grid-cols-2 lg:grid-cols-4">
758
+ <div>
759
+ <div class="flex items-center gap-2 mb-4">
760
+ <Leaf class="h-5 w-5 text-primary" />
761
+ <span class="font-bold">OpenTwig</span>
762
+ </div>
763
+ <p class="text-sm text-muted-foreground">
764
+ Free and open source link in bio page generator.
765
+ </p>
766
+ </div>
767
+
768
+ <div>
769
+ <h4 class="mb-4 font-semibold text-foreground">
770
+ Product
771
+ </h4>
772
+ <ul class="space-y-2 text-sm">
773
+ <li>
774
+ <a
775
+ href="#features"
776
+ class="text-muted-foreground transition-colors hover:text-foreground"
777
+ >Features</a
778
+ >
779
+ </li>
780
+ <li>
781
+ <a
782
+ href="#themes"
783
+ class="text-muted-foreground transition-colors hover:text-foreground"
784
+ >Themes</a
785
+ >
786
+ </li>
787
+ <li>
788
+ <a
789
+ href="#get-started"
790
+ class="text-muted-foreground transition-colors hover:text-foreground"
791
+ >Documentation</a
792
+ >
793
+ </li>
794
+ </ul>
795
+ </div>
796
+
797
+ <div>
798
+ <h4 class="mb-4 font-semibold text-foreground">
799
+ Resources
800
+ </h4>
801
+ <ul class="space-y-2 text-sm">
802
+ <li>
803
+ <a
804
+ href="https://github.com/tufantunc/opentwig"
805
+ target="_blank"
806
+ rel="noopener noreferrer"
807
+ class="inline-flex items-center gap-1 text-muted-foreground transition-colors hover:text-foreground"
808
+ >
809
+ GitHub
810
+ <ExternalLink class="h-3 w-3" />
811
+ </a>
812
+ </li>
813
+ <li>
814
+ <a
815
+ href="https://www.npmjs.com/package/opentwig"
816
+ target="_blank"
817
+ rel="noopener noreferrer"
818
+ class="inline-flex items-center gap-1 text-muted-foreground transition-colors hover:text-foreground"
819
+ >
820
+ NPM Package
821
+ <ExternalLink class="h-3 w-3" />
822
+ </a>
823
+ </li>
824
+ <li>
825
+ <a
826
+ href="https://github.com/tufantunc/opentwig/issues"
827
+ target="_blank"
828
+ rel="noopener noreferrer"
829
+ class="inline-flex items-center gap-1 text-muted-foreground transition-colors hover:text-foreground"
830
+ >
831
+ Issues
832
+ <ExternalLink class="h-3 w-3" />
833
+ </a>
834
+ </li>
835
+ </ul>
836
+ </div>
837
+
838
+ <div>
839
+ <h4 class="mb-4 font-semibold text-foreground">
840
+ Legal
841
+ </h4>
842
+ <ul class="space-y-2 text-sm">
843
+ <li>
844
+ <a
845
+ href="https://github.com/tufantunc/opentwig/blob/main/LICENSE"
846
+ target="_blank"
847
+ rel="noopener noreferrer"
848
+ class="text-muted-foreground transition-colors hover:text-foreground"
849
+ >
850
+ MIT License
851
+ </a>
852
+ </li>
853
+ <li>
854
+ <span class="text-muted-foreground"
855
+ >© 2025 OpenTwig</span
856
+ >
857
+ </li>
858
+ </ul>
859
+ </div>
860
+ </div>
861
+
862
+ <Separator class="my-8" />
863
+
864
+ <div
865
+ class="flex flex-col items-center justify-between gap-4 sm:flex-row"
866
+ >
867
+ <p class="text-sm text-muted-foreground">
868
+ Made with love for open source community
869
+ </p>
870
+ <div class="flex items-center gap-4">
871
+ <a
872
+ href="https://github.com/tufantunc/opentwig"
873
+ target="_blank"
874
+ rel="noopener noreferrer"
875
+ class="text-muted-foreground transition-colors hover:text-foreground"
876
+ >
877
+ <Github class="h-5 w-5" />
878
+ </a>
879
+ <a
880
+ href="https://www.npmjs.com/package/opentwig"
881
+ target="_blank"
882
+ rel="noopener noreferrer"
883
+ class="text-muted-foreground transition-colors hover:text-foreground"
884
+ >
885
+ <Package class="h-5 w-5" />
886
+ </a>
887
+ </div>
888
+ </div>
889
+ </div>
890
+ </footer>
891
+ </div>
892
+ </TooltipProvider>