vibecarbon 0.8.0 → 0.10.0
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.
- package/LICENSE +110 -663
- package/README.md +4 -4
- package/carbon/.env.example +11 -0
- package/carbon/backup/compose-backup.sh +8 -0
- package/carbon/docker-compose.yml +11 -0
- package/carbon/ha/primary-init.sql +10 -2
- package/carbon/k8s/base/backup/cronjob.yaml +9 -0
- package/carbon/k8s/base/repl-gateway/kustomization.yaml +11 -0
- package/carbon/k8s/base/repl-gateway/repl-gateway.yaml +92 -0
- package/carbon/k8s/values/supabase.values.yaml +6 -1
- package/carbon/scripts/dev-init.js +6 -2
- package/carbon/src/client/assets/vibecarbon-icon.svg +6 -6
- package/carbon/src/client/assets/vibecarbon-wordmark-text-dark.svg +12 -0
- package/carbon/src/client/assets/vibecarbon-wordmark-text-light.svg +12 -0
- package/carbon/src/client/components/AIIntegrationSection.tsx +1 -3
- package/carbon/src/client/components/AppSidebar.tsx +35 -28
- package/carbon/src/client/components/CTAFooter.tsx +1 -1
- package/carbon/src/client/components/ComparisonSection.tsx +1 -3
- package/carbon/src/client/components/ContentPanel.tsx +1 -1
- package/carbon/src/client/components/DeploymentScenariosSection.tsx +1 -3
- package/carbon/src/client/components/FAQSection.tsx +1 -1
- package/carbon/src/client/components/Hero.tsx +13 -1
- package/carbon/src/client/components/Logo.tsx +66 -49
- package/carbon/src/client/components/Nav.tsx +1 -1
- package/carbon/src/client/components/NewsletterSignup.tsx +1 -1
- package/carbon/src/client/components/NotificationDrawer.tsx +3 -3
- package/carbon/src/client/components/PageHeader.tsx +1 -1
- package/carbon/src/client/components/PricingSection.tsx +2 -6
- package/carbon/src/client/components/TechStackSection.tsx +1 -3
- package/carbon/src/client/components/effects/FilmGrainOverlay.tsx +5 -0
- package/carbon/src/client/components/ui/button.tsx +1 -1
- package/carbon/src/client/components/ui/card.tsx +1 -1
- package/carbon/src/client/components/ui/dialog.tsx +1 -1
- package/carbon/src/client/components/ui/dropdown-menu.tsx +2 -2
- package/carbon/src/client/components/ui/popover.tsx +1 -1
- package/carbon/src/client/components/ui/select.tsx +1 -1
- package/carbon/src/client/components/ui/sidebar.tsx +1 -1
- package/carbon/src/client/index.css +186 -104
- package/carbon/src/client/lib/supabase.ts +41 -0
- package/carbon/src/client/lib/theme.ts +14 -14
- package/carbon/src/client/locales/de.json +27 -12
- package/carbon/src/client/locales/en.json +33 -18
- package/carbon/src/client/locales/es.json +27 -12
- package/carbon/src/client/locales/fr.json +27 -12
- package/carbon/src/client/locales/pt.json +27 -12
- package/carbon/src/client/pages/Blog.tsx +1 -1
- package/carbon/src/client/pages/Changelog.tsx +1 -1
- package/carbon/src/client/pages/Checkout.tsx +1 -1
- package/carbon/src/client/pages/Dashboard.tsx +33 -40
- package/carbon/src/client/pages/Docs.tsx +1 -1
- package/carbon/src/client/pages/Home.tsx +1 -1
- package/carbon/src/client/pages/Legal.tsx +1 -1
- package/carbon/src/server/billing/providers/paddle.ts +21 -2
- package/carbon/src/server/billing/providers/polar.ts +14 -0
- package/carbon/src/server/index.ts +12 -9
- package/carbon/src/server/lib/client-ip.ts +68 -0
- package/carbon/src/server/lib/env.ts +20 -6
- package/carbon/src/server/lib/rate-limiter.ts +11 -65
- package/carbon/src/server/lib/supabase.ts +10 -4
- package/carbon/src/server/middleware/requireOrgRole.ts +76 -0
- package/carbon/src/server/middleware/requirePlan.ts +64 -34
- package/carbon/src/server/middleware/requireSuperAdmin.ts +26 -0
- package/carbon/src/server/routes/v1/admin/contact.ts +5 -20
- package/carbon/src/server/routes/v1/admin/jobs.ts +6 -20
- package/carbon/src/server/routes/v1/admin/newsletter.ts +26 -23
- package/carbon/src/server/routes/v1/auth.ts +5 -2
- package/carbon/src/server/routes/v1/billing.ts +24 -64
- package/carbon/src/server/routes/v1/index.ts +8 -1
- package/carbon/src/server/routes/v1/newsletter.ts +18 -12
- package/carbon/src/server/routes/v1/theme.ts +36 -15
- package/carbon/supabase/migrations/00003_pg_cron.sql +2 -2
- package/carbon/supabase/migrations/00004_contact_newsletter.sql +24 -14
- package/carbon/tests/component/supabase-env-guard.test.ts +54 -0
- package/carbon/tests/integration/server/middleware/rate-limit-ip-spoof.test.ts +48 -0
- package/carbon/tests/integration/server/middleware/require-plan.test.ts +101 -0
- package/carbon/tests/integration/server/routes/admin-newsletter.test.ts +93 -0
- package/carbon/tests/integration/server/routes/billing-subscription-idor.test.ts +92 -0
- package/carbon/tests/integration/server/routes/newsletter-unsubscribe.test.ts +65 -0
- package/carbon/tests/integration/server/routes/theme-validation.test.ts +66 -0
- package/carbon/tests/unit/server/client-ip.test.ts +76 -0
- package/carbon/tests/unit/server/env-bool.test.ts +63 -0
- package/carbon/tests/unit/server/paddle-webhook.test.ts +57 -0
- package/carbon/tests/unit/server/polar-webhook.test.ts +63 -0
- package/carbon/tests/unit/server/supabase-client.test.ts +30 -0
- package/carbon/volumes/db/wal-archive.sh +36 -0
- package/package.json +2 -2
- package/src/backup.js +0 -2
- package/src/cli.js +16 -0
- package/src/deploy.js +16 -5
- package/src/destroy.js +78 -0
- package/src/failover.js +118 -237
- package/src/lib/command.js +19 -1
- package/src/lib/deploy/compose/ha.js +180 -102
- package/src/lib/deploy/compose/index.js +63 -20
- package/src/lib/deploy/image.js +19 -23
- package/src/lib/deploy/k8s/ha/index.js +397 -150
- package/src/lib/deploy/k8s/k3s.js +65 -14
- package/src/lib/deploy/orchestrator.js +176 -6
- package/src/lib/deploy/remote-build.js +8 -1
- package/src/lib/deploy/replication.js +540 -0
- package/src/lib/deploy/state.js +62 -5
- package/src/lib/deploy/utils.js +30 -2
- package/src/lib/deploy/wireguard.js +146 -0
- package/src/lib/host-keys.js +120 -5
- package/src/lib/iac/index.js +57 -23
- package/src/lib/licensing/gate.js +59 -0
- package/src/lib/licensing/index.js +1 -1
- package/src/lib/licensing/tiers.js +6 -5
- package/src/lib/prod-confirm.js +65 -0
- package/src/lib/providers/hetzner-s3.js +85 -0
- package/src/lib/ssh.js +35 -35
- package/src/restore.js +102 -14
- package/src/scale.js +4 -2
- package/src/status.js +122 -0
- package/src/upgrade.js +0 -4
- package/carbon/ha/activate-standby.sh +0 -52
- package/carbon/ha/standby-init.sh +0 -74
- package/carbon/src/client/assets/vibecarbon-logo-dark.svg +0 -29
- package/carbon/src/client/assets/vibecarbon-logo-light.svg +0 -29
- package/carbon/src/server/lib/request.ts +0 -34
- package/src/lib/pod-backups.js +0 -53
|
@@ -32,146 +32,169 @@ body {
|
|
|
32
32
|
|
|
33
33
|
@custom-variant dark (&:is(.dark *));
|
|
34
34
|
|
|
35
|
-
/* Theme:
|
|
36
|
-
/* Primary:
|
|
37
|
-
|
|
35
|
+
/* Theme: Refined Depth (dark) / Light Glass (light) */
|
|
36
|
+
/* Primary: Teal, Secondary Accent: Magenta — single interactive accent,
|
|
37
|
+
semantic colors reserved for status, glass applied selectively (.glass) */
|
|
38
|
+
/* Typography: Noto Sans (body + display), JetBrains Mono (code/data) */
|
|
38
39
|
|
|
39
40
|
:root {
|
|
40
41
|
/* ============================================
|
|
41
42
|
CUSTOMIZE YOUR BRAND - Edit these values
|
|
42
43
|
============================================ */
|
|
43
|
-
--primary: oklch(0.
|
|
44
|
-
--primary-dim: oklch(0.
|
|
45
|
-
--primary-foreground: oklch(0.
|
|
46
|
-
--secondary-accent: oklch(0.
|
|
44
|
+
--primary: oklch(0.52 0.124 192); /* Brand primary (deep teal, AA on light surfaces) */
|
|
45
|
+
--primary-dim: oklch(0.42 0.1 192); /* Dimmed variant */
|
|
46
|
+
--primary-foreground: oklch(0.99 0.005 192);
|
|
47
|
+
--secondary-accent: oklch(0.47 0.2 350); /* Brand accent (magenta) */
|
|
47
48
|
--secondary-accent-foreground: oklch(0.99 0 0);
|
|
48
|
-
--destructive: oklch(0.
|
|
49
|
+
--destructive: oklch(0.5 0.21 3.958);
|
|
49
50
|
--info: var(--primary);
|
|
50
|
-
--warning: oklch(0.
|
|
51
|
-
--success: oklch(0.
|
|
51
|
+
--warning: oklch(0.62 0.13 75);
|
|
52
|
+
--success: oklch(0.5 0.12 181);
|
|
52
53
|
--radius: 0.625rem; /* Border radius base */
|
|
53
54
|
--radius-card: var(--radius-xl); /* Cards, dialogs, panels */
|
|
54
55
|
|
|
55
56
|
/* Glow effects (derived from brand colors) */
|
|
56
|
-
--glow-primary: oklch(0.
|
|
57
|
-
--glow-accent: oklch(0.
|
|
57
|
+
--glow-primary: oklch(0.52 0.124 192 / 0.12);
|
|
58
|
+
--glow-accent: oklch(0.47 0.2 350 / 0.1);
|
|
58
59
|
|
|
59
|
-
/*
|
|
60
|
-
--gradient-start: oklch(
|
|
61
|
-
--gradient-end: oklch(0.
|
|
60
|
+
/* Canvas - pale cool gradient + faint ambient wash */
|
|
61
|
+
--gradient-start: oklch(0.985 0.005 220);
|
|
62
|
+
--gradient-end: oklch(0.945 0.014 215);
|
|
63
|
+
--canvas-wash: oklch(0.52 0.124 192 / 0.05);
|
|
62
64
|
|
|
63
65
|
/* ============================================
|
|
64
66
|
SURFACE COLORS - Rarely need customization
|
|
65
67
|
============================================ */
|
|
66
|
-
|
|
67
|
-
--
|
|
68
|
+
/* Transparent background to show canvas (both modes) */
|
|
69
|
+
--background: transparent;
|
|
70
|
+
--foreground: oklch(0.17 0.025 250);
|
|
71
|
+
|
|
72
|
+
/* Standard cards - quiet near-opaque surfaces (glass is opt-in via .glass) */
|
|
73
|
+
--card: oklch(0.995 0.004 210 / 0.92);
|
|
74
|
+
--card-foreground: oklch(0.17 0.025 250);
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
--
|
|
76
|
+
/* Glass surfaces - alpha gradient, light source top-left */
|
|
77
|
+
--glass-from: oklch(1 0 0 / 0.78);
|
|
78
|
+
--glass-to: oklch(0.97 0.01 215 / 0.58);
|
|
79
|
+
--glass-edge: oklch(1 0 0 / 0.65);
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
--popover
|
|
81
|
+
/* Popovers/dropdowns - SOLID (float over arbitrary content) */
|
|
82
|
+
--popover: oklch(0.99 0.004 210);
|
|
83
|
+
--popover-foreground: oklch(0.17 0.025 250);
|
|
74
84
|
|
|
75
|
-
--secondary: oklch(0.
|
|
76
|
-
--secondary-foreground: oklch(0.
|
|
85
|
+
--secondary: oklch(0.93 0.012 220 / 0.8);
|
|
86
|
+
--secondary-foreground: oklch(0.25 0.025 245);
|
|
77
87
|
|
|
78
|
-
--muted: oklch(0.
|
|
79
|
-
--muted-foreground: oklch(0.
|
|
88
|
+
--muted: oklch(0.94 0.01 220 / 0.7);
|
|
89
|
+
--muted-foreground: oklch(0.44 0.025 240);
|
|
80
90
|
|
|
81
|
-
/* Accent
|
|
82
|
-
--accent:
|
|
83
|
-
--accent-foreground:
|
|
91
|
+
/* Accent - subtle primary tint for hover states */
|
|
92
|
+
--accent: oklch(0.52 0.124 192 / 0.1);
|
|
93
|
+
--accent-foreground: oklch(0.3 0.08 192);
|
|
94
|
+
|
|
95
|
+
/* Hairline borders */
|
|
96
|
+
--border: oklch(0.45 0.03 230 / 0.16);
|
|
97
|
+
--input: oklch(0.5 0.03 230 / 0.3);
|
|
98
|
+
--ring: var(--primary);
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
--
|
|
87
|
-
--
|
|
100
|
+
/* Elevation shadows - soft diffuse, cool-tinted */
|
|
101
|
+
--shadow-card: 0 1px 2px oklch(0.3 0.04 240 / 0.05), 0 10px 30px -10px oklch(0.3 0.05 240 / 0.12);
|
|
102
|
+
--shadow-pop: 0 4px 12px oklch(0.3 0.04 240 / 0.08), 0 16px 40px -12px oklch(0.3 0.05 240 / 0.18);
|
|
88
103
|
|
|
89
|
-
/* Chart colors -
|
|
104
|
+
/* Chart colors - brand pair first, then supporting hues */
|
|
90
105
|
--chart-1: var(--primary);
|
|
91
|
-
--chart-2: var(--
|
|
92
|
-
--chart-3:
|
|
93
|
-
--chart-4:
|
|
94
|
-
--chart-5: oklch(0.
|
|
95
|
-
|
|
96
|
-
/* Sidebar -
|
|
97
|
-
--sidebar: oklch(0.
|
|
98
|
-
--sidebar-foreground: oklch(0.
|
|
106
|
+
--chart-2: var(--secondary-accent);
|
|
107
|
+
--chart-3: oklch(0.5 0.17 275);
|
|
108
|
+
--chart-4: oklch(0.62 0.13 75);
|
|
109
|
+
--chart-5: oklch(0.54 0.11 155);
|
|
110
|
+
|
|
111
|
+
/* Sidebar - light glass rail */
|
|
112
|
+
--sidebar: oklch(0.975 0.007 212 / 0.55);
|
|
113
|
+
--sidebar-foreground: oklch(0.22 0.025 248);
|
|
99
114
|
--sidebar-primary: var(--primary);
|
|
100
115
|
--sidebar-primary-foreground: var(--primary-foreground);
|
|
101
|
-
--sidebar-accent:
|
|
102
|
-
--sidebar-accent-foreground:
|
|
103
|
-
--sidebar-border: oklch(0.
|
|
104
|
-
--sidebar-ring:
|
|
116
|
+
--sidebar-accent: oklch(0.52 0.124 192 / 0.12);
|
|
117
|
+
--sidebar-accent-foreground: oklch(0.3 0.08 192);
|
|
118
|
+
--sidebar-border: oklch(0.45 0.03 230 / 0.12);
|
|
119
|
+
--sidebar-ring: var(--primary);
|
|
105
120
|
}
|
|
106
121
|
|
|
107
122
|
.dark {
|
|
108
|
-
/* Primary - brighter dim variant
|
|
123
|
+
/* Primary - bright teal on dark, brighter dim variant */
|
|
109
124
|
--primary: oklch(0.82 0.14 192);
|
|
110
125
|
--primary-dim: oklch(0.65 0.12 192);
|
|
111
|
-
--primary-foreground: oklch(0.
|
|
126
|
+
--primary-foreground: oklch(0.1 0.02 220);
|
|
112
127
|
|
|
113
128
|
/* Secondary accent (magenta) - brighter in dark mode */
|
|
114
129
|
--secondary-accent: oklch(0.65 0.26 350);
|
|
115
130
|
--secondary-accent-foreground: oklch(0.99 0 0);
|
|
116
131
|
|
|
117
|
-
/* Glow colors */
|
|
118
|
-
--glow-primary: oklch(0.82 0.14 192 / 0.
|
|
119
|
-
--glow-accent: oklch(0.65 0.26 350 / 0.
|
|
132
|
+
/* Glow colors - restrained, focal points only */
|
|
133
|
+
--glow-primary: oklch(0.82 0.14 192 / 0.28);
|
|
134
|
+
--glow-accent: oklch(0.65 0.26 350 / 0.25);
|
|
120
135
|
|
|
121
|
-
/*
|
|
122
|
-
--gradient-start: oklch(0.
|
|
123
|
-
--gradient-end: oklch(0.
|
|
136
|
+
/* Canvas - deep teal-tinted near-black + faint ambient wash */
|
|
137
|
+
--gradient-start: oklch(0.105 0.018 252);
|
|
138
|
+
--gradient-end: oklch(0.145 0.028 228);
|
|
139
|
+
--canvas-wash: oklch(0.82 0.14 192 / 0.09);
|
|
124
140
|
|
|
125
|
-
/* Transparent background to show
|
|
141
|
+
/* Transparent background to show canvas */
|
|
126
142
|
--background: transparent;
|
|
127
|
-
--foreground: oklch(0.
|
|
143
|
+
--foreground: oklch(0.96 0.005 210);
|
|
144
|
+
|
|
145
|
+
/* Standard cards - quiet near-opaque surfaces */
|
|
146
|
+
--card: oklch(0.19 0.024 242 / 0.78);
|
|
147
|
+
--card-foreground: oklch(0.96 0.005 210);
|
|
128
148
|
|
|
129
|
-
/*
|
|
130
|
-
--
|
|
131
|
-
--
|
|
149
|
+
/* Glass surfaces - alpha gradient, light source top-left */
|
|
150
|
+
--glass-from: oklch(0.25 0.028 238 / 0.6);
|
|
151
|
+
--glass-to: oklch(0.16 0.022 246 / 0.45);
|
|
152
|
+
--glass-edge: oklch(1 0 0 / 0.1);
|
|
132
153
|
|
|
133
|
-
/* Popovers/dropdowns - cool-tinted to match
|
|
134
|
-
--popover: oklch(0.
|
|
135
|
-
--popover-foreground: oklch(0.
|
|
154
|
+
/* Popovers/dropdowns - SOLID, cool-tinted to match canvas */
|
|
155
|
+
--popover: oklch(0.175 0.022 242);
|
|
156
|
+
--popover-foreground: oklch(0.97 0 0);
|
|
136
157
|
|
|
137
|
-
|
|
138
|
-
--secondary: oklch(0.
|
|
139
|
-
--secondary-foreground: oklch(0.9 0 0);
|
|
158
|
+
--secondary: oklch(0.25 0.02 240);
|
|
159
|
+
--secondary-foreground: oklch(0.92 0.008 220);
|
|
140
160
|
|
|
141
|
-
|
|
142
|
-
--muted: oklch(0.
|
|
143
|
-
--muted-foreground: oklch(0.707 0.022 261.325);
|
|
161
|
+
--muted: oklch(0.2 0.02 240 / 0.7);
|
|
162
|
+
--muted-foreground: oklch(0.71 0.02 228);
|
|
144
163
|
|
|
145
164
|
/* Accent - subtle primary tint for hover states */
|
|
146
|
-
--accent: oklch(0.
|
|
147
|
-
--accent-foreground: oklch(0.
|
|
165
|
+
--accent: oklch(0.82 0.14 192 / 0.13);
|
|
166
|
+
--accent-foreground: oklch(0.96 0.005 210);
|
|
148
167
|
|
|
149
|
-
/*
|
|
150
|
-
--destructive: oklch(0.
|
|
168
|
+
/* Status - lifted for dark-bg contrast */
|
|
169
|
+
--destructive: oklch(0.62 0.21 3.958);
|
|
151
170
|
--info: var(--primary);
|
|
152
|
-
--warning: oklch(0.
|
|
171
|
+
--warning: oklch(0.77 0.188 70.08);
|
|
153
172
|
--success: oklch(0.704 0.14 181);
|
|
154
173
|
|
|
155
|
-
/*
|
|
156
|
-
--border: oklch(0.
|
|
157
|
-
--input: oklch(1 0 0 /
|
|
174
|
+
/* Hairline borders - faint teal */
|
|
175
|
+
--border: oklch(0.9 0.03 200 / 0.12);
|
|
176
|
+
--input: oklch(1 0 0 / 0.12);
|
|
158
177
|
--ring: var(--primary);
|
|
159
178
|
|
|
160
|
-
/*
|
|
179
|
+
/* Elevation shadows - inner top edge-light + deep soft drop */
|
|
180
|
+
--shadow-card: inset 0 1px 0 oklch(1 0 0 / 0.06), 0 8px 24px -12px oklch(0 0 0 / 0.5);
|
|
181
|
+
--shadow-pop: inset 0 1px 0 oklch(1 0 0 / 0.08), 0 16px 48px -16px oklch(0 0 0 / 0.65);
|
|
182
|
+
|
|
183
|
+
/* Chart colors - brand pair first, then supporting hues */
|
|
161
184
|
--chart-1: var(--primary);
|
|
162
|
-
--chart-2: var(--
|
|
163
|
-
--chart-3:
|
|
164
|
-
--chart-4:
|
|
165
|
-
--chart-5: oklch(0.
|
|
185
|
+
--chart-2: var(--secondary-accent);
|
|
186
|
+
--chart-3: oklch(0.72 0.15 275);
|
|
187
|
+
--chart-4: oklch(0.8 0.15 80);
|
|
188
|
+
--chart-5: oklch(0.76 0.12 155);
|
|
166
189
|
|
|
167
|
-
/* Sidebar */
|
|
190
|
+
/* Sidebar - transparent rail, canvas shows through */
|
|
168
191
|
--sidebar: transparent;
|
|
169
|
-
--sidebar-foreground: oklch(0.
|
|
192
|
+
--sidebar-foreground: oklch(0.96 0.005 210);
|
|
170
193
|
--sidebar-primary: var(--primary);
|
|
171
|
-
--sidebar-primary-foreground: oklch(0.
|
|
172
|
-
--sidebar-accent:
|
|
173
|
-
--sidebar-accent-foreground: oklch(0.
|
|
174
|
-
--sidebar-border:
|
|
194
|
+
--sidebar-primary-foreground: oklch(0.1 0.02 220);
|
|
195
|
+
--sidebar-accent: oklch(0.82 0.14 192 / 0.13);
|
|
196
|
+
--sidebar-accent-foreground: oklch(0.96 0.005 210);
|
|
197
|
+
--sidebar-border: oklch(0.9 0.03 200 / 0.08);
|
|
175
198
|
--sidebar-ring: var(--primary);
|
|
176
199
|
}
|
|
177
200
|
|
|
@@ -179,6 +202,12 @@ body {
|
|
|
179
202
|
/* Typography */
|
|
180
203
|
--font-sans: "Noto Sans Variable", "Noto Sans", system-ui, sans-serif;
|
|
181
204
|
--font-mono: "JetBrains Mono", ui-monospace, monospace;
|
|
205
|
+
/* Display slot kept as an extension point; defaults to the body sans face. */
|
|
206
|
+
--font-display: var(--font-sans);
|
|
207
|
+
|
|
208
|
+
/* Elevation shadows (values cascade from :root/.dark) */
|
|
209
|
+
--shadow-card: var(--shadow-card);
|
|
210
|
+
--shadow-pop: var(--shadow-pop);
|
|
182
211
|
|
|
183
212
|
/* Extended primary colors */
|
|
184
213
|
--color-primary-dim: var(--primary-dim);
|
|
@@ -242,21 +271,31 @@ body {
|
|
|
242
271
|
body {
|
|
243
272
|
@apply font-sans bg-background text-foreground antialiased cursor-default;
|
|
244
273
|
}
|
|
245
|
-
|
|
246
|
-
|
|
274
|
+
/* Canvas: gradient + faint ambient wash (the "light" glass surfaces catch).
|
|
275
|
+
Both modes — --background is transparent so this shows through. */
|
|
276
|
+
body {
|
|
277
|
+
background:
|
|
278
|
+
radial-gradient(120% 80% at 75% -20%, var(--canvas-wash), transparent 55%),
|
|
279
|
+
linear-gradient(180deg, var(--gradient-start) 0%, var(--gradient-end) 100%);
|
|
247
280
|
background-attachment: fixed;
|
|
248
281
|
}
|
|
249
282
|
html {
|
|
250
283
|
@apply font-sans;
|
|
251
284
|
}
|
|
252
285
|
|
|
253
|
-
/*
|
|
286
|
+
/* Headlines: refined weights + balanced wrapping (display slot = body sans) */
|
|
254
287
|
h1,
|
|
255
|
-
h2
|
|
288
|
+
h2 {
|
|
289
|
+
font-family: var(--font-display);
|
|
290
|
+
font-weight: 700;
|
|
291
|
+
letter-spacing: -0.015em;
|
|
292
|
+
text-wrap: balance;
|
|
293
|
+
}
|
|
256
294
|
h3,
|
|
257
295
|
h4 {
|
|
258
|
-
font-weight:
|
|
259
|
-
letter-spacing: -0.
|
|
296
|
+
font-weight: 700;
|
|
297
|
+
letter-spacing: -0.01em;
|
|
298
|
+
text-wrap: balance;
|
|
260
299
|
}
|
|
261
300
|
}
|
|
262
301
|
|
|
@@ -274,8 +313,19 @@ body {
|
|
|
274
313
|
EFFECTS SYSTEM
|
|
275
314
|
============================================ */
|
|
276
315
|
|
|
277
|
-
/*
|
|
278
|
-
.
|
|
316
|
+
/* Glass surface — the ONLY glass treatment; applied selectively
|
|
317
|
+
(KPI strip, sidebar rail, marketing hero panels). Alpha gradient
|
|
318
|
+
mimics a top-left light source; border-top catches the light. */
|
|
319
|
+
.glass {
|
|
320
|
+
background: linear-gradient(135deg, var(--glass-from), var(--glass-to));
|
|
321
|
+
backdrop-filter: blur(14px);
|
|
322
|
+
border: 1px solid var(--border);
|
|
323
|
+
border-top-color: var(--glass-edge);
|
|
324
|
+
box-shadow: var(--shadow-card);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* Film Grain Overlay (dark mode only — reads as dirt on light surfaces) */
|
|
328
|
+
.dark .film-grain::after {
|
|
279
329
|
content: "";
|
|
280
330
|
position: fixed;
|
|
281
331
|
inset: 0;
|
|
@@ -287,30 +337,37 @@ body {
|
|
|
287
337
|
background-repeat: repeat;
|
|
288
338
|
}
|
|
289
339
|
|
|
290
|
-
/*
|
|
340
|
+
/* Active nav — teal icon, the sidebar's single focal accent */
|
|
341
|
+
[data-sidebar="menu-button"][data-active] svg {
|
|
342
|
+
color: var(--primary);
|
|
343
|
+
filter: drop-shadow(0 0 6px var(--glow-primary));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* Glow utilities — restrained radii; reserved for focal points
|
|
347
|
+
(active nav, primary CTA, brand marks). Do not add new consumers. */
|
|
291
348
|
.glow-teal {
|
|
292
|
-
box-shadow: 0 0
|
|
349
|
+
box-shadow: 0 0 12px var(--glow-primary), 0 0 28px var(--glow-primary);
|
|
293
350
|
}
|
|
294
351
|
|
|
295
352
|
.glow-magenta {
|
|
296
|
-
box-shadow: 0 0
|
|
353
|
+
box-shadow: 0 0 12px var(--glow-accent), 0 0 28px var(--glow-accent);
|
|
297
354
|
}
|
|
298
355
|
|
|
299
356
|
.glow-teal-subtle {
|
|
300
|
-
box-shadow: 0 0
|
|
357
|
+
box-shadow: 0 0 10px var(--glow-primary);
|
|
301
358
|
}
|
|
302
359
|
|
|
303
360
|
.glow-magenta-subtle {
|
|
304
|
-
box-shadow: 0 0
|
|
361
|
+
box-shadow: 0 0 10px var(--glow-accent);
|
|
305
362
|
}
|
|
306
363
|
|
|
307
364
|
/* Text glow */
|
|
308
365
|
.text-glow-teal {
|
|
309
|
-
text-shadow: 0 0
|
|
366
|
+
text-shadow: 0 0 12px var(--glow-primary), 0 0 28px var(--glow-primary);
|
|
310
367
|
}
|
|
311
368
|
|
|
312
369
|
.text-glow-magenta {
|
|
313
|
-
text-shadow: 0 0
|
|
370
|
+
text-shadow: 0 0 12px var(--glow-accent), 0 0 28px var(--glow-accent);
|
|
314
371
|
}
|
|
315
372
|
|
|
316
373
|
/* Border glow on hover */
|
|
@@ -319,11 +376,11 @@ body {
|
|
|
319
376
|
}
|
|
320
377
|
|
|
321
378
|
.border-glow-teal:hover {
|
|
322
|
-
box-shadow: 0 0 0 1px var(--primary), 0 0
|
|
379
|
+
box-shadow: 0 0 0 1px var(--primary), 0 0 10px var(--glow-primary);
|
|
323
380
|
}
|
|
324
381
|
|
|
325
382
|
.border-glow-magenta:hover {
|
|
326
|
-
box-shadow: 0 0 0 1px var(--secondary-accent), 0 0
|
|
383
|
+
box-shadow: 0 0 0 1px var(--secondary-accent), 0 0 10px var(--glow-accent);
|
|
327
384
|
}
|
|
328
385
|
|
|
329
386
|
/* Sparkle shimmer for premium badges */
|
|
@@ -336,6 +393,7 @@ body {
|
|
|
336
393
|
background-size: 200% 100%;
|
|
337
394
|
animation: shimmer 3s ease-in-out infinite;
|
|
338
395
|
}
|
|
396
|
+
@media (prefers-reduced-motion: reduce) { .badge-shimmer { animation: none; } }
|
|
339
397
|
|
|
340
398
|
/* Marquee for LogoStrip */
|
|
341
399
|
@keyframes marquee-scroll {
|
|
@@ -357,8 +415,9 @@ body {
|
|
|
357
415
|
.hero-orb { animation: orb-pulse 6s ease-in-out infinite; }
|
|
358
416
|
@media (prefers-reduced-motion: reduce) { .hero-orb { animation: none; } }
|
|
359
417
|
|
|
360
|
-
/* Spotlight particle dots for glass containers
|
|
361
|
-
|
|
418
|
+
/* Spotlight particle dots for glass containers (dark mode only — white dots
|
|
419
|
+
read as noise on light surfaces) */
|
|
420
|
+
.dark .spotlight-particles {
|
|
362
421
|
background-image: radial-gradient(circle, oklch(1 0 0 / 0.5) 1px, transparent 1px);
|
|
363
422
|
background-size: 24px 24px;
|
|
364
423
|
mask-image: radial-gradient(ellipse 80% 50% at 50% 0%, black 0%, transparent 80%);
|
|
@@ -458,4 +517,27 @@ body {
|
|
|
458
517
|
:where(tr):not(:where([class~="not-prose"], [class~="not-prose"] *)):hover {
|
|
459
518
|
background-color: oklch(0.20 0.02 260 / 0.3);
|
|
460
519
|
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/* ============================================
|
|
523
|
+
REDUCED TRANSPARENCY - solidify glass surfaces
|
|
524
|
+
============================================ */
|
|
525
|
+
|
|
526
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
527
|
+
:root {
|
|
528
|
+
--card: oklch(0.99 0.004 210);
|
|
529
|
+
--sidebar: oklch(0.975 0.007 212);
|
|
530
|
+
--glass-from: oklch(0.99 0.004 210);
|
|
531
|
+
--glass-to: oklch(0.97 0.008 212);
|
|
532
|
+
}
|
|
533
|
+
.dark {
|
|
534
|
+
--card: oklch(0.19 0.024 242);
|
|
535
|
+
--sidebar: oklch(0.13 0.02 245);
|
|
536
|
+
--glass-from: oklch(0.21 0.024 242);
|
|
537
|
+
--glass-to: oklch(0.17 0.022 244);
|
|
538
|
+
}
|
|
539
|
+
.glass,
|
|
540
|
+
[data-slot="sidebar-inner"] {
|
|
541
|
+
backdrop-filter: none;
|
|
542
|
+
}
|
|
461
543
|
}
|
|
@@ -5,9 +5,50 @@ const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
|
|
|
5
5
|
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
|
|
6
6
|
|
|
7
7
|
if (!supabaseUrl || !supabaseAnonKey) {
|
|
8
|
+
const missing = [
|
|
9
|
+
!supabaseUrl ? 'VITE_SUPABASE_URL' : null,
|
|
10
|
+
!supabaseAnonKey ? 'VITE_SUPABASE_ANON_KEY' : null,
|
|
11
|
+
].filter((name): name is string => name !== null);
|
|
12
|
+
renderConfigError(missing);
|
|
8
13
|
throw new Error('Missing Supabase environment variables');
|
|
9
14
|
}
|
|
10
15
|
|
|
16
|
+
// This module is evaluated before React mounts, so a bare throw leaves #root
|
|
17
|
+
// empty — a black page with the only clue in the console. Paint a readable
|
|
18
|
+
// error with plain DOM APIs first, then let the throw halt the app.
|
|
19
|
+
function renderConfigError(missing: string[]): void {
|
|
20
|
+
if (typeof document === 'undefined') return;
|
|
21
|
+
|
|
22
|
+
const screen = document.createElement('div');
|
|
23
|
+
screen.style.cssText =
|
|
24
|
+
'position:fixed;inset:0;display:flex;align-items:center;justify-content:center;' +
|
|
25
|
+
'background:#0a0f14;color:#e6edf3;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;' +
|
|
26
|
+
'padding:2rem;z-index:2147483647;text-align:left';
|
|
27
|
+
|
|
28
|
+
const box = document.createElement('div');
|
|
29
|
+
box.style.cssText = 'max-width:40rem';
|
|
30
|
+
|
|
31
|
+
const heading = document.createElement('h1');
|
|
32
|
+
heading.textContent = 'Configuration error';
|
|
33
|
+
heading.style.cssText = 'font-size:1.25rem;margin:0 0 0.75rem;color:#f47067';
|
|
34
|
+
|
|
35
|
+
const detail = document.createElement('p');
|
|
36
|
+
detail.textContent =
|
|
37
|
+
`This build is missing required environment variables: ${missing.join(', ')}. ` +
|
|
38
|
+
'The frontend cannot start without them.';
|
|
39
|
+
detail.style.cssText = 'margin:0 0 0.75rem;line-height:1.5';
|
|
40
|
+
|
|
41
|
+
const hint = document.createElement('p');
|
|
42
|
+
hint.textContent =
|
|
43
|
+
'Rebuild with the variables set — deploys inject them automatically; ' +
|
|
44
|
+
'for local development, check your .env file.';
|
|
45
|
+
hint.style.cssText = 'margin:0;line-height:1.5;opacity:0.7';
|
|
46
|
+
|
|
47
|
+
box.append(heading, detail, hint);
|
|
48
|
+
screen.append(box);
|
|
49
|
+
document.body.append(screen);
|
|
50
|
+
}
|
|
51
|
+
|
|
11
52
|
/**
|
|
12
53
|
* Cookie-based storage adapter for Supabase auth.
|
|
13
54
|
* Stores auth tokens in cookies so they're sent with requests to /admin/* routes,
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
// Default values mirroring index.css
|
|
2
2
|
export const DEFAULT_THEME = {
|
|
3
3
|
light: {
|
|
4
|
-
gradientStart: 'oklch(
|
|
5
|
-
gradientEnd: 'oklch(0.
|
|
6
|
-
card: 'oklch(
|
|
7
|
-
primary: 'oklch(0.
|
|
8
|
-
primaryDim: 'oklch(0.
|
|
9
|
-
primaryForeground: 'oklch(0.
|
|
10
|
-
secondaryAccent: 'oklch(0.
|
|
4
|
+
gradientStart: 'oklch(0.985 0.005 220)',
|
|
5
|
+
gradientEnd: 'oklch(0.945 0.014 215)',
|
|
6
|
+
card: 'oklch(0.995 0.004 210 / 0.92)',
|
|
7
|
+
primary: 'oklch(0.52 0.124 192)',
|
|
8
|
+
primaryDim: 'oklch(0.42 0.1 192)',
|
|
9
|
+
primaryForeground: 'oklch(0.99 0.005 192)',
|
|
10
|
+
secondaryAccent: 'oklch(0.47 0.2 350)',
|
|
11
11
|
secondaryAccentForeground: 'oklch(0.99 0 0)',
|
|
12
|
-
destructive: 'oklch(0.
|
|
13
|
-
warning: 'oklch(0.
|
|
14
|
-
success: 'oklch(0.
|
|
12
|
+
destructive: 'oklch(0.5 0.21 3.958)',
|
|
13
|
+
warning: 'oklch(0.62 0.13 75)',
|
|
14
|
+
success: 'oklch(0.5 0.12 181)',
|
|
15
15
|
},
|
|
16
16
|
dark: {
|
|
17
|
-
gradientStart: 'oklch(0.
|
|
18
|
-
gradientEnd: 'oklch(0.
|
|
19
|
-
card: 'oklch(0.
|
|
17
|
+
gradientStart: 'oklch(0.105 0.018 252)',
|
|
18
|
+
gradientEnd: 'oklch(0.145 0.028 228)',
|
|
19
|
+
card: 'oklch(0.19 0.024 242 / 0.78)',
|
|
20
20
|
primary: 'oklch(0.82 0.14 192)',
|
|
21
21
|
primaryDim: 'oklch(0.65 0.12 192)',
|
|
22
|
-
primaryForeground: 'oklch(0.
|
|
22
|
+
primaryForeground: 'oklch(0.1 0.02 220)',
|
|
23
23
|
secondaryAccent: 'oklch(0.65 0.26 350)',
|
|
24
24
|
secondaryAccentForeground: 'oklch(0.99 0 0)',
|
|
25
25
|
},
|
|
@@ -293,7 +293,7 @@
|
|
|
293
293
|
},
|
|
294
294
|
"deploy": {
|
|
295
295
|
"label": "Deployen",
|
|
296
|
-
"description": "In Produktion pushen mit
|
|
296
|
+
"description": "In Produktion pushen mit Skalierung, Hochverfügbarkeit, Monitoring, CI/CD und mehr."
|
|
297
297
|
}
|
|
298
298
|
},
|
|
299
299
|
"techStack": {
|
|
@@ -352,7 +352,7 @@
|
|
|
352
352
|
"traffic": {
|
|
353
353
|
"risk": "Traffic überlastet",
|
|
354
354
|
"protection": "Auto-Scaling",
|
|
355
|
-
"how": "Kubernetes-Autoscaling
|
|
355
|
+
"how": "Kubernetes-Pod-Autoscaling plus Worker-Skalierung per Befehl"
|
|
356
356
|
},
|
|
357
357
|
"redundancy": {
|
|
358
358
|
"risk": "Keine Redundanz",
|
|
@@ -401,25 +401,40 @@
|
|
|
401
401
|
"compose": {
|
|
402
402
|
"name": "Docker Compose",
|
|
403
403
|
"tagline": "Ein VPS, dein kompletter Stack inklusive.",
|
|
404
|
-
"features": [
|
|
404
|
+
"features": [
|
|
405
|
+
"1 Server",
|
|
406
|
+
"Einzelne Region"
|
|
407
|
+
],
|
|
405
408
|
"bestFor": "MVPs & interne Tools"
|
|
406
409
|
},
|
|
407
410
|
"composeHa": {
|
|
408
411
|
"name": "Compose HA",
|
|
409
|
-
"tagline": "Zwei
|
|
410
|
-
"features": [
|
|
412
|
+
"tagline": "Zwei Regionen, Failover per Befehl.",
|
|
413
|
+
"features": [
|
|
414
|
+
"2 Server",
|
|
415
|
+
"Streaming-Replikation",
|
|
416
|
+
"Failover per Befehl"
|
|
417
|
+
],
|
|
411
418
|
"bestFor": "Produktions-SaaS ohne Kubernetes"
|
|
412
419
|
},
|
|
413
420
|
"k8s": {
|
|
414
421
|
"name": "Kubernetes",
|
|
415
|
-
"tagline": "
|
|
416
|
-
"features": [
|
|
422
|
+
"tagline": "Produktionsreifer k3s-Cluster.",
|
|
423
|
+
"features": [
|
|
424
|
+
"Einzelne Region",
|
|
425
|
+
"Horizontale Autoskalierung",
|
|
426
|
+
"Rollierende Updates"
|
|
427
|
+
],
|
|
417
428
|
"bestFor": "Anwendungen mit hohem Traffic"
|
|
418
429
|
},
|
|
419
430
|
"k8sHa": {
|
|
420
431
|
"name": "Kubernetes HA",
|
|
421
432
|
"tagline": "Multi-Region-Cluster, maximale Verfügbarkeit.",
|
|
422
|
-
"features": [
|
|
433
|
+
"features": [
|
|
434
|
+
"2 Regionen",
|
|
435
|
+
"Regions-Failover",
|
|
436
|
+
"Pod-Autoscaling"
|
|
437
|
+
],
|
|
423
438
|
"bestFor": "Geschäftskritisch & global"
|
|
424
439
|
}
|
|
425
440
|
},
|
|
@@ -459,7 +474,7 @@
|
|
|
459
474
|
"backups": "Automatische S3-Backups",
|
|
460
475
|
"cicd": "CI/CD via GitHub Actions",
|
|
461
476
|
"unlimited": "Unbegrenzte Server & Projekte",
|
|
462
|
-
"commercial": "
|
|
477
|
+
"commercial": "FSL-Ausnahme (Einbetten, White-Label, Weiterverkauf)"
|
|
463
478
|
}
|
|
464
479
|
},
|
|
465
480
|
"fullerene": {
|
|
@@ -467,7 +482,7 @@
|
|
|
467
482
|
"cta": "Fullerene kaufen",
|
|
468
483
|
"features": {
|
|
469
484
|
"diamond": "Alles in Diamond",
|
|
470
|
-
"commercial": "
|
|
485
|
+
"commercial": "FSL-Ausnahme: Vibecarbon einbetten, als White-Label anbieten oder Vibecarbon-basierte Services weiterverkaufen",
|
|
471
486
|
"clients": "Bereitstellung für Kunden & Organisationen",
|
|
472
487
|
"corporate": "Agenturen & Enterprise-Teams",
|
|
473
488
|
"support": "Prioritäts-E-Mail-Support",
|
|
@@ -496,7 +511,7 @@
|
|
|
496
511
|
},
|
|
497
512
|
"q5": {
|
|
498
513
|
"question": "Wie funktioniert die Preisgestaltung?",
|
|
499
|
-
"answer": "Graphite ist dauerhaft kostenlos — Projekte erstellen, lokal entwickeln, alle Add-ons nutzen. Diamond (149 $ einmalig) bietet volle Automatisierung für Indie-Entwickler und Startups — alle Deployment-Modi, Backups, CI/CD und Skalierung. Fullerene (499 $ einmalig)
|
|
514
|
+
"answer": "Graphite ist dauerhaft kostenlos — Projekte erstellen, lokal entwickeln, alle Add-ons nutzen. Diamond (149 $ einmalig) bietet volle Automatisierung für Indie-Entwickler und Startups — alle Deployment-Modi, Backups, CI/CD und Skalierung. Fullerene (499 $ einmalig) richtet sich an Agenturen und Unternehmen — für Kunden deployen, plus die FSL-Ausnahme, um Vibecarbon einzubetten, als White-Label anzubieten oder Vibecarbon-basierte Services weiterzuverkaufen. Einmalige Zahlung, kein Abo."
|
|
500
515
|
},
|
|
501
516
|
"q6": {
|
|
502
517
|
"question": "Wie viele Projekte kann ich mit einer Lizenz erstellen?",
|
|
@@ -508,7 +523,7 @@
|
|
|
508
523
|
},
|
|
509
524
|
"q8": {
|
|
510
525
|
"question": "Was passiert, wenn Vibecarbon eingestellt wird?",
|
|
511
|
-
"answer": "Für deine App ändert sich nichts. Der generierte Code steht unter MIT-Lizenz ohne jegliche Laufzeitabhängigkeit von Vibecarbon — es ist einfach eine Codebasis, die dir vollständig gehört. Die CLI ist
|
|
526
|
+
"answer": "Für deine App ändert sich nichts. Der generierte Code steht unter MIT-Lizenz ohne jegliche Laufzeitabhängigkeit von Vibecarbon — es ist einfach eine Codebasis, die dir vollständig gehört. Die CLI ist Fair Source (FSL) — du kannst sie für jede nicht konkurrierende Nutzung dauerhaft aus dem Quellcode ausführen, und jedes Release wird zwei Jahre nach Veröffentlichung MIT-Open-Source. Deine Infrastruktur läuft auf deinen eigenen Servern."
|
|
512
527
|
},
|
|
513
528
|
"q9": {
|
|
514
529
|
"question": "Brauche ich DevOps-Erfahrung, um bereitzustellen?",
|