From 173261b7c1df5500ca1a95509587fba0c079703a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20V=C3=ADt?= Date: Wed, 5 Aug 2026 11:19:55 +0200 Subject: [PATCH] refactor(www): move the marketing and design sites to the host build The landing page and the design-system site are cloud-company surfaces rather than open-core product surface, so they move to the host repository and this app keeps only what a self-hosted deployment needs. - `/` now hands off to the studio. The route shell stays here because a host cannot add a second `/` route without colliding with this one; instead `_marketing/index.tsx` renders `features/www/marketing-home-slot`, which hosts replace the same way as the other extension points. - `features/www/landing` and the whole `features/design` + `routes/design` tree move out. `hero-shader` stays as `components/hero-shader` because the auth pages use it, and `lib/waitlist` / `lib/paths` stay because the studio and auth flows depend on them. - `source.config.ts` keeps only the product-docs collection. A host that adds documentation surfaces replaces this config wholesale, since two `mdx()` instances would clobber each other's `.source` output. - Drop `features/www/{button,logo,refraction-stripes,section,navbar,hero}` and the `voidhash-gradient-*` cluster, which were reachable only from the unreferenced `hero/hero.tsx` that this change removes. Co-Authored-By: Claude Opus 5 (1M context) --- apps/www/.source/browser.ts | 7 - apps/www/.source/server.ts | 15 - .../www/hero => components}/hero-shader.tsx | 0 .../voidhash-gradient-background.tsx | 224 ---- .../components/voidhash-gradient-canvas.tsx | 328 ----- .../components/voidhash-gradient-controls.tsx | 175 --- .../components/voidhash-gradient-settings.ts | 102 -- .../components/auth-lenticular-background.tsx | 2 +- .../design/components/docs/colors/index.tsx | 282 ----- .../design/components/docs/colors/tokens.ts | 452 ------- .../components/docs/component-overview.tsx | 14 - .../cards/account-access.tsx | 86 -- .../cards/card-overview.tsx | 77 -- .../cards/claimable-balance.tsx | 51 - .../cards/contribution-history.tsx | 92 -- .../component-overview/cards/cover-art.tsx | 48 - .../cards/dividend-income.tsx | 123 -- .../cards/empty-connect-bank.tsx | 40 - .../cards/empty-distribute-track.tsx | 41 - .../cards/empty-explore-catalog.tsx | 40 - .../docs/component-overview/cards/faq.tsx | 103 -- .../component-overview/cards/front-door.tsx | 41 - .../cards/index-investing.tsx | 22 - .../cards/kitchen-island.tsx | 161 --- .../component-overview/cards/loading-card.tsx | 25 - .../cards/new-milestone.tsx | 50 - .../cards/notification-settings.tsx | 98 -- .../component-overview/cards/payments.tsx | 169 --- .../cards/payout-threshold.tsx | 101 -- .../component-overview/cards/power-usage.tsx | 81 -- .../component-overview/cards/preferences.tsx | 92 -- .../cards/project-actions.tsx | 96 -- .../component-overview/cards/qr-connect.tsx | 36 - .../cards/receiving-method.tsx | 90 -- .../cards/recent-transactions.tsx | 276 ----- .../cards/release-catalog.tsx | 99 -- .../cards/roller-shades.tsx | 69 -- .../cards/savings-progress.tsx | 93 -- .../cards/savings-targets.tsx | 116 -- .../component-overview/cards/sidebar-nav.tsx | 285 ----- .../component-overview/cards/social-links.tsx | 85 -- .../cards/stock-performance.tsx | 119 -- .../cards/syncing-state.tsx | 34 - .../cards/transfer-funds.tsx | 107 -- .../cards/upcoming-payments.tsx | 54 - .../component-overview/icon-placeholder.tsx | 31 - .../docs/component-overview/index.tsx | 100 -- .../docs/component-overview/preview-config.ts | 10 - .../components/docs/component-registry.tsx | 34 - .../design/components/docs/preview.tsx | 24 - .../design/components/layout/docs.tsx | 227 ---- .../design/components/layout/page.tsx | 126 -- .../features/design/components/nav-bar.tsx | 66 - .../design/components/theme-toggle.tsx | 15 - .../content/docs/components/accordion.mdx | 115 -- .../content/docs/components/alert-dialog.mdx | 119 -- .../design/content/docs/components/alert.mdx | 85 -- .../design/content/docs/components/avatar.mdx | 110 -- .../design/content/docs/components/badge.mdx | 89 -- .../content/docs/components/breadcrumb.mdx | 132 -- .../design/content/docs/components/button.mdx | 184 --- .../content/docs/components/calendar.mdx | 93 -- .../design/content/docs/components/card.mdx | 153 --- .../content/docs/components/carousel.mdx | 126 -- .../design/content/docs/components/chart.mdx | 138 --- .../content/docs/components/checkbox.mdx | 105 -- .../content/docs/components/collapsible.mdx | 101 -- .../content/docs/components/command.mdx | 159 --- .../content/docs/components/context-menu.mdx | 127 -- .../design/content/docs/components/dialog.mdx | 156 --- .../design/content/docs/components/drawer.mdx | 169 --- .../content/docs/components/dropdown-menu.mdx | 195 --- .../content/docs/components/dropzone.mdx | 102 -- .../design/content/docs/components/form.mdx | 186 --- .../content/docs/components/hover-card.mdx | 137 --- .../content/docs/components/input-otp.mdx | 136 --- .../design/content/docs/components/input.mdx | 113 -- .../design/content/docs/components/label.mdx | 81 -- .../content/docs/components/menubar.mdx | 136 --- .../design/content/docs/components/meta.yaml | 53 - .../docs/components/navigation-menu.mdx | 156 --- .../content/docs/components/overview.mdx | 7 - .../content/docs/components/page-bar.mdx | 57 - .../content/docs/components/pagination.mdx | 146 --- .../design/content/docs/components/phone.mdx | 57 - .../content/docs/components/popover.mdx | 146 --- .../content/docs/components/progress.mdx | 92 -- .../content/docs/components/radio-group.mdx | 146 --- .../content/docs/components/resizable.mdx | 144 --- .../content/docs/components/scroll-area.mdx | 109 -- .../design/content/docs/components/select.mdx | 185 --- .../content/docs/components/separator.mdx | 84 -- .../design/content/docs/components/sheet.mdx | 177 --- .../content/docs/components/sidebar.mdx | 179 --- .../content/docs/components/skeleton.mdx | 91 -- .../design/content/docs/components/slider.mdx | 105 -- .../design/content/docs/components/sonner.mdx | 120 -- .../design/content/docs/components/switch.mdx | 105 -- .../design/content/docs/components/table.mdx | 148 --- .../design/content/docs/components/tabs.mdx | 126 -- .../content/docs/components/textarea.mdx | 96 -- .../content/docs/components/toggle-group.mdx | 136 --- .../design/content/docs/components/toggle.mdx | 146 --- .../content/docs/components/tooltip.mdx | 140 --- .../docs/components/underline-tabs.mdx | 97 -- .../content/docs/foundations/colors.mdx | 116 -- .../design/content/docs/foundations/meta.yaml | 4 - .../design/content/docs/introduction.mdx | 4 - .../features/design/content/docs/meta.yaml | 6 - apps/www/src/features/design/lib/basepath.ts | 1 - apps/www/src/features/design/lib/cn.ts | 1 - .../src/features/design/lib/layout.shared.tsx | 8 - apps/www/src/features/design/lib/source.ts | 35 - apps/www/src/features/design/source.config.ts | 30 - .../src/features/design/styles/globals.css | 32 - apps/www/src/features/source.config.ts | 19 +- apps/www/src/features/www/button.tsx | 58 - apps/www/src/features/www/hero/footer.tsx | 61 - apps/www/src/features/www/hero/hero.tsx | 72 -- .../assets/agent-icons/antigravity.png | Bin 9026 -> 0 bytes .../assets/agent-icons/claude-code.png | Bin 21744 -> 0 bytes .../www/landing/assets/agent-icons/codex.png | Bin 17775 -> 0 bytes .../www/landing/assets/agent-icons/cursor.png | Bin 6164 -> 0 bytes .../landing/assets/agent-icons/opencode.png | Bin 10326 -> 0 bytes .../features/www/landing/asteroids/engine.ts | 1088 ----------------- .../features/www/landing/asteroids/frame.ts | 7 - .../features/www/landing/asteroids/game.tsx | 444 ------- .../features/www/landing/asteroids/post.ts | 209 ---- .../src/features/www/landing/landing-page.tsx | 43 - .../www/landing/marketing-nav-config.ts | 14 - apps/www/src/features/www/landing/motion.tsx | 236 ---- .../paywall-build/agent-transcript.tsx | 163 --- .../landing/paywall-build/lenscal-paywall.tsx | 356 ------ .../landing/paywall-build/paywall-build.tsx | 102 -- .../www/landing/paywall-build/transcript.ts | 125 -- .../paywall-build/use-transcript-playback.ts | 118 -- .../paywall-build/working-indicator.tsx | 147 --- .../landing/sections/agent-compatibility.tsx | 57 - .../www/landing/sections/analytics.tsx | 531 -------- .../www/landing/sections/asteroids.tsx | 161 --- .../src/features/www/landing/sections/crm.tsx | 337 ----- .../www/landing/sections/developers.tsx | 168 --- .../features/www/landing/sections/divider.tsx | 8 - .../www/landing/sections/experimentation.tsx | 221 ---- .../features/www/landing/sections/footer.tsx | 134 -- .../www/landing/sections/get-started.tsx | 117 -- .../features/www/landing/sections/hero.tsx | 52 - .../features/www/landing/sections/navbar.tsx | 216 ---- .../www/landing/sections/paywalls.tsx | 576 --------- .../features/www/landing/sections/problem.tsx | 19 - apps/www/src/features/www/landing/shared.tsx | 151 --- apps/www/src/features/www/logo.tsx | 92 -- .../src/features/www/marketing-home-slot.tsx | 20 + .../src/features/www/navbar/navigation.tsx | 49 - .../src/features/www/refraction-stripes.tsx | 38 - .../www/section/section-container.tsx | 15 - apps/www/src/routeTree.gen.ts | 92 -- apps/www/src/routes/_marketing/index.tsx | 17 +- apps/www/src/routes/design/$.tsx | 174 --- apps/www/src/routes/design/api/search.ts | 19 - apps/www/src/routes/design/index.tsx | 13 - apps/www/src/routes/design/route.tsx | 42 - 162 files changed, 29 insertions(+), 18418 deletions(-) rename apps/www/src/{features/www/hero => components}/hero-shader.tsx (100%) delete mode 100644 apps/www/src/components/voidhash-gradient-background.tsx delete mode 100644 apps/www/src/components/voidhash-gradient-canvas.tsx delete mode 100644 apps/www/src/components/voidhash-gradient-controls.tsx delete mode 100644 apps/www/src/components/voidhash-gradient-settings.ts delete mode 100644 apps/www/src/features/design/components/docs/colors/index.tsx delete mode 100644 apps/www/src/features/design/components/docs/colors/tokens.ts delete mode 100644 apps/www/src/features/design/components/docs/component-overview.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/account-access.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/card-overview.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/claimable-balance.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/contribution-history.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/cover-art.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/dividend-income.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/empty-connect-bank.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/empty-distribute-track.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/empty-explore-catalog.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/faq.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/front-door.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/index-investing.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/kitchen-island.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/loading-card.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/new-milestone.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/notification-settings.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/payments.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/payout-threshold.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/power-usage.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/preferences.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/project-actions.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/qr-connect.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/receiving-method.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/recent-transactions.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/release-catalog.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/roller-shades.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/savings-progress.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/savings-targets.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/sidebar-nav.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/social-links.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/stock-performance.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/syncing-state.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/transfer-funds.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/cards/upcoming-payments.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/icon-placeholder.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/index.tsx delete mode 100644 apps/www/src/features/design/components/docs/component-overview/preview-config.ts delete mode 100644 apps/www/src/features/design/components/docs/component-registry.tsx delete mode 100644 apps/www/src/features/design/components/docs/preview.tsx delete mode 100644 apps/www/src/features/design/components/layout/docs.tsx delete mode 100644 apps/www/src/features/design/components/layout/page.tsx delete mode 100644 apps/www/src/features/design/components/nav-bar.tsx delete mode 100644 apps/www/src/features/design/components/theme-toggle.tsx delete mode 100644 apps/www/src/features/design/content/docs/components/accordion.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/alert-dialog.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/alert.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/avatar.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/badge.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/breadcrumb.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/button.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/calendar.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/card.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/carousel.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/chart.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/checkbox.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/collapsible.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/command.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/context-menu.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/dialog.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/drawer.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/dropdown-menu.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/dropzone.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/form.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/hover-card.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/input-otp.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/input.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/label.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/menubar.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/meta.yaml delete mode 100644 apps/www/src/features/design/content/docs/components/navigation-menu.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/overview.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/page-bar.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/pagination.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/phone.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/popover.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/progress.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/radio-group.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/resizable.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/scroll-area.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/select.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/separator.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/sheet.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/sidebar.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/skeleton.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/slider.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/sonner.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/switch.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/table.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/tabs.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/textarea.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/toggle-group.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/toggle.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/tooltip.mdx delete mode 100644 apps/www/src/features/design/content/docs/components/underline-tabs.mdx delete mode 100644 apps/www/src/features/design/content/docs/foundations/colors.mdx delete mode 100644 apps/www/src/features/design/content/docs/foundations/meta.yaml delete mode 100644 apps/www/src/features/design/content/docs/introduction.mdx delete mode 100644 apps/www/src/features/design/content/docs/meta.yaml delete mode 100644 apps/www/src/features/design/lib/basepath.ts delete mode 100644 apps/www/src/features/design/lib/cn.ts delete mode 100644 apps/www/src/features/design/lib/layout.shared.tsx delete mode 100644 apps/www/src/features/design/lib/source.ts delete mode 100644 apps/www/src/features/design/source.config.ts delete mode 100644 apps/www/src/features/design/styles/globals.css delete mode 100644 apps/www/src/features/www/button.tsx delete mode 100644 apps/www/src/features/www/hero/footer.tsx delete mode 100644 apps/www/src/features/www/hero/hero.tsx delete mode 100644 apps/www/src/features/www/landing/assets/agent-icons/antigravity.png delete mode 100644 apps/www/src/features/www/landing/assets/agent-icons/claude-code.png delete mode 100644 apps/www/src/features/www/landing/assets/agent-icons/codex.png delete mode 100644 apps/www/src/features/www/landing/assets/agent-icons/cursor.png delete mode 100644 apps/www/src/features/www/landing/assets/agent-icons/opencode.png delete mode 100644 apps/www/src/features/www/landing/asteroids/engine.ts delete mode 100644 apps/www/src/features/www/landing/asteroids/frame.ts delete mode 100644 apps/www/src/features/www/landing/asteroids/game.tsx delete mode 100644 apps/www/src/features/www/landing/asteroids/post.ts delete mode 100644 apps/www/src/features/www/landing/landing-page.tsx delete mode 100644 apps/www/src/features/www/landing/marketing-nav-config.ts delete mode 100644 apps/www/src/features/www/landing/motion.tsx delete mode 100644 apps/www/src/features/www/landing/paywall-build/agent-transcript.tsx delete mode 100644 apps/www/src/features/www/landing/paywall-build/lenscal-paywall.tsx delete mode 100644 apps/www/src/features/www/landing/paywall-build/paywall-build.tsx delete mode 100644 apps/www/src/features/www/landing/paywall-build/transcript.ts delete mode 100644 apps/www/src/features/www/landing/paywall-build/use-transcript-playback.ts delete mode 100644 apps/www/src/features/www/landing/paywall-build/working-indicator.tsx delete mode 100644 apps/www/src/features/www/landing/sections/agent-compatibility.tsx delete mode 100644 apps/www/src/features/www/landing/sections/analytics.tsx delete mode 100644 apps/www/src/features/www/landing/sections/asteroids.tsx delete mode 100644 apps/www/src/features/www/landing/sections/crm.tsx delete mode 100644 apps/www/src/features/www/landing/sections/developers.tsx delete mode 100644 apps/www/src/features/www/landing/sections/divider.tsx delete mode 100644 apps/www/src/features/www/landing/sections/experimentation.tsx delete mode 100644 apps/www/src/features/www/landing/sections/footer.tsx delete mode 100644 apps/www/src/features/www/landing/sections/get-started.tsx delete mode 100644 apps/www/src/features/www/landing/sections/hero.tsx delete mode 100644 apps/www/src/features/www/landing/sections/navbar.tsx delete mode 100644 apps/www/src/features/www/landing/sections/paywalls.tsx delete mode 100644 apps/www/src/features/www/landing/sections/problem.tsx delete mode 100644 apps/www/src/features/www/landing/shared.tsx delete mode 100644 apps/www/src/features/www/logo.tsx create mode 100644 apps/www/src/features/www/marketing-home-slot.tsx delete mode 100644 apps/www/src/features/www/navbar/navigation.tsx delete mode 100644 apps/www/src/features/www/refraction-stripes.tsx delete mode 100644 apps/www/src/features/www/section/section-container.tsx delete mode 100644 apps/www/src/routes/design/$.tsx delete mode 100644 apps/www/src/routes/design/api/search.ts delete mode 100644 apps/www/src/routes/design/index.tsx delete mode 100644 apps/www/src/routes/design/route.tsx diff --git a/apps/www/.source/browser.ts b/apps/www/.source/browser.ts index a20e34d72..f8c66bc1b 100644 --- a/apps/www/.source/browser.ts +++ b/apps/www/.source/browser.ts @@ -15,12 +15,5 @@ const browserCollections = { }, "eager": false })), - design: create.doc("design", import.meta.glob(["./**/*.{mdx,md}"], { - "base": "./../src/features/design/content/docs", - "query": { - "collection": "design" - }, - "eager": false - })), }; export default browserCollections; \ No newline at end of file diff --git a/apps/www/.source/server.ts b/apps/www/.source/server.ts index 25501242d..0b72d6d61 100644 --- a/apps/www/.source/server.ts +++ b/apps/www/.source/server.ts @@ -21,19 +21,4 @@ export const docs = await create.docs("docs", "src/features/docs/content/docs", "collection": "docs" }, "eager": true -})); - -export const design = await create.docs("design", "src/features/design/content/docs", import.meta.glob(["./**/*.{json,yaml}"], { - "base": "./../src/features/design/content/docs", - "query": { - "collection": "design" - }, - "import": "default", - "eager": true -}), import.meta.glob(["./**/*.{mdx,md}"], { - "base": "./../src/features/design/content/docs", - "query": { - "collection": "design" - }, - "eager": true })); \ No newline at end of file diff --git a/apps/www/src/features/www/hero/hero-shader.tsx b/apps/www/src/components/hero-shader.tsx similarity index 100% rename from apps/www/src/features/www/hero/hero-shader.tsx rename to apps/www/src/components/hero-shader.tsx diff --git a/apps/www/src/components/voidhash-gradient-background.tsx b/apps/www/src/components/voidhash-gradient-background.tsx deleted file mode 100644 index 9450994f6..000000000 --- a/apps/www/src/components/voidhash-gradient-background.tsx +++ /dev/null @@ -1,224 +0,0 @@ -"use client"; - -import { lazy, Suspense, useCallback, useEffect, useMemo, useState, type CSSProperties } from "react"; - -import { cn } from "@/lib/utils"; - -import { VoidhashGradientControls } from "./voidhash-gradient-controls"; -import { - DEFAULT_VOIDHASH_GRADIENT_SETTINGS, - mergeVoidhashGradientSettings, - VOIDHASH_GRADIENT_CONTROLS_STORAGE_KEY, - VOIDHASH_GRADIENT_STORAGE_KEY, - type VoidhashGradientSettings, -} from "./voidhash-gradient-settings"; - -const VoidhashGradientCanvas = lazy(async () => { - const module = await import("./voidhash-gradient-canvas"); - - return { - default: module.VoidhashGradientCanvas, - }; -}); - -type VoidhashGradientPlacement = "bottom" | "top"; -type ReadyPlacements = Record; - -function getFadeMask(settings: VoidhashGradientSettings, placement: VoidhashGradientPlacement) { - const start = Math.min(settings.fadeStart, settings.fadeEnd - 1); - const end = Math.max(settings.fadeEnd, start + 1); - const mid = start + (end - start) * 0.35; - const direction = placement === "top" ? "to top" : "to bottom"; - - return `linear-gradient(${direction}, transparent 0%, transparent ${start}%, rgba(0, 0, 0, 0.12) ${mid}%, black ${end}%, black 100%)`; -} - -function getLayerStyle(settings: VoidhashGradientSettings, placement: VoidhashGradientPlacement): CSSProperties { - return { - [placement]: `${placement === "top" ? settings.topOffset : settings.bottomOffset}%`, - filter: `blur(${settings.blur}px)`, - height: `${settings.effectHeight}%`, - maskImage: getFadeMask(settings, placement), - WebkitMaskImage: getFadeMask(settings, placement), - }; -} - -function VoidhashGradientEntryVeil({ isVisible }: { isVisible: boolean }) { - return ( -
- ); -} - -function VoidhashGradientLayer({ - isRevealed, - onReady, - placement, - settings, -}: { - isRevealed: boolean; - onReady: (placement: VoidhashGradientPlacement) => void; - placement: VoidhashGradientPlacement; - settings: VoidhashGradientSettings; -}) { - const [isCanvasReady, setIsCanvasReady] = useState(false); - - return ( -
-
- { - setIsCanvasReady(true); - onReady(placement); - }} - seed={placement === "top" ? settings.topSeed : settings.bottomSeed} - settings={settings} - /> -
-
- ); -} - -export type VoidhashGradientBackgroundProps = { - className?: string; - controlsQueryParam?: string; - controlsStorageKey?: string; - controlsTitle?: string; - settings?: Partial; - settingsStorageKey?: string; -}; - -/** Renders the reusable blurred Three.js gradient background used across Voidhash surfaces. */ -export function VoidhashGradientBackground({ - className, - controlsQueryParam = "gradientControls", - controlsStorageKey = VOIDHASH_GRADIENT_CONTROLS_STORAGE_KEY, - controlsTitle = "Gradient FX", - settings: settingsProp, - settingsStorageKey = VOIDHASH_GRADIENT_STORAGE_KEY, -}: VoidhashGradientBackgroundProps) { - const baseSettings = useMemo( - () => mergeVoidhashGradientSettings(settingsProp ?? DEFAULT_VOIDHASH_GRADIENT_SETTINGS), - [settingsProp], - ); - const [isMounted, setIsMounted] = useState(false); - const [canDropEntryVeil, setCanDropEntryVeil] = useState(false); - const [hasRevealed, setHasRevealed] = useState(false); - const [readyPlacements, setReadyPlacements] = useState({ bottom: false, top: false }); - const [settings, setSettings] = useState(baseSettings); - const [showControls, setShowControls] = useState(false); - - useEffect(() => { - setIsMounted(true); - - const params = new URLSearchParams(window.location.search); - const controlsEnabled = params.has(controlsQueryParam) || localStorage.getItem(controlsStorageKey) === "1"; - const savedSettings = localStorage.getItem(settingsStorageKey); - - if (savedSettings) { - try { - setSettings(mergeVoidhashGradientSettings(JSON.parse(savedSettings), baseSettings)); - } catch { - localStorage.removeItem(settingsStorageKey); - } - } - - if (controlsEnabled) { - setShowControls(true); - localStorage.setItem(controlsStorageKey, "1"); - } - }, [baseSettings, controlsQueryParam, controlsStorageKey, settingsStorageKey]); - - useEffect(() => { - if (!isMounted) { - return; - } - - const veilTimer = window.setTimeout(() => setCanDropEntryVeil(true), 1800); - - return () => window.clearTimeout(veilTimer); - }, [isMounted]); - - useEffect(() => { - if (isMounted && showControls) { - localStorage.setItem(settingsStorageKey, JSON.stringify(settings)); - } - }, [isMounted, settings, settingsStorageKey, showControls]); - - const handleLayerReady = useCallback((placement: VoidhashGradientPlacement) => { - setReadyPlacements((current) => { - if (current[placement]) { - return current; - } - - return { ...current, [placement]: true }; - }); - }, []); - - const isShaderReady = readyPlacements.bottom && (!settings.topEnabled || readyPlacements.top); - - useEffect(() => { - if (!hasRevealed && isMounted && (isShaderReady || canDropEntryVeil)) { - setHasRevealed(true); - } - }, [canDropEntryVeil, hasRevealed, isMounted, isShaderReady]); - - const rootClassName = cn("relative isolate h-full w-full overflow-hidden bg-black", className); - - if (!isMounted) { - return ( -
- -
- ); - } - - return ( -
- - - {settings.topEnabled ? ( - - ) : null} - - - - {showControls ? ( - { - setShowControls(false); - localStorage.removeItem(controlsStorageKey); - }} - onReset={() => { - setSettings(baseSettings); - localStorage.removeItem(settingsStorageKey); - }} - settings={settings} - title={controlsTitle} - /> - ) : null} -
- ); -} diff --git a/apps/www/src/components/voidhash-gradient-canvas.tsx b/apps/www/src/components/voidhash-gradient-canvas.tsx deleted file mode 100644 index 3c437287c..000000000 --- a/apps/www/src/components/voidhash-gradient-canvas.tsx +++ /dev/null @@ -1,328 +0,0 @@ -"use client"; - -import { Canvas, useFrame } from "@react-three/fiber"; -import { useEffect, useMemo, useRef } from "react"; -import * as THREE from "three"; - -import type { VoidhashGradientSettings } from "./voidhash-gradient-settings"; - -const vertexShader = ` -uniform float uTime; -uniform float uAmplitude; -uniform float uFrequency; -uniform float uMidFrequency; -uniform float uHighFrequency; -uniform float uLift; -uniform float uSeed; - -varying vec2 vUv; -varying vec3 vNormal; -varying vec3 vViewPosition; -varying float vWave; - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec3 mod289(vec3 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) { - return mod289(((x * 34.0) + 10.0) * x); -} - -vec4 taylorInvSqrt(vec4 r) { - return 1.79284291400159 - 0.85373472095314 * r; -} - -float snoise(vec3 v) { - const vec2 c = vec2(1.0 / 6.0, 1.0 / 3.0); - const vec4 d = vec4(0.0, 0.5, 1.0, 2.0); - - vec3 i = floor(v + dot(v, c.yyy)); - vec3 x0 = v - i + dot(i, c.xxx); - - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min(g.xyz, l.zxy); - vec3 i2 = max(g.xyz, l.zxy); - - vec3 x1 = x0 - i1 + c.xxx; - vec3 x2 = x0 - i2 + c.yyy; - vec3 x3 = x0 - d.yyy; - - i = mod289(i); - vec4 p = permute(permute(permute( - i.z + vec4(0.0, i1.z, i2.z, 1.0)) - + i.y + vec4(0.0, i1.y, i2.y, 1.0)) - + i.x + vec4(0.0, i1.x, i2.x, 1.0)); - - float n_ = 0.142857142857; - vec3 ns = n_ * d.wyz - d.xzx; - - vec4 j = p - 49.0 * floor(p * ns.z * ns.z); - - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_); - - vec4 x = x_ * ns.x + ns.yyyy; - vec4 y = y_ * ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); - - vec4 b0 = vec4(x.xy, y.xy); - vec4 b1 = vec4(x.zw, y.zw); - - vec4 s0 = floor(b0) * 2.0 + 1.0; - vec4 s1 = floor(b1) * 2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); - - vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; - vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; - - vec3 p0 = vec3(a0.xy, h.x); - vec3 p1 = vec3(a0.zw, h.y); - vec3 p2 = vec3(a1.xy, h.z); - vec3 p3 = vec3(a1.zw, h.w); - - vec4 norm = taylorInvSqrt(vec4( - dot(p0, p0), - dot(p1, p1), - dot(p2, p2), - dot(p3, p3) - )); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - - vec4 m = max(0.6 - vec4( - dot(x0, x0), - dot(x1, x1), - dot(x2, x2), - dot(x3, x3) - ), 0.0); - m = m * m; - - return 42.0 * dot(m * m, vec4( - dot(p0, x0), - dot(p1, x1), - dot(p2, x2), - dot(p3, x3) - )); -} - -float surfaceHeight(vec2 p, float time) { - vec2 seedOffset = vec2(uSeed * 1.37, uSeed * -0.73); - vec2 q = vec2(p.x * uFrequency, p.y * uFrequency * 2.55) + seedOffset; - float seedTime = time + uSeed * 0.11; - float low = snoise(vec3(q, seedTime)); - float mid = snoise(vec3(q * uMidFrequency + vec2(7.4, -3.2) + seedOffset * 0.43, seedTime * 1.65)); - float high = snoise(vec3(q * uHighFrequency + vec2(-2.0, 5.7) - seedOffset * 0.26, seedTime * 2.4)); - - return (low * 0.62 + mid * 0.28 + high * 0.1) * uAmplitude; -} - -void main() { - vUv = uv; - - float lift = smoothstep(0.02, 0.92, uv.y); - float height = surfaceHeight(position.xy, uTime) * (0.72 + lift * 0.62); - float epsilon = 0.08; - float heightX = surfaceHeight(position.xy + vec2(epsilon, 0.0), uTime); - float heightY = surfaceHeight(position.xy + vec2(0.0, epsilon), uTime); - - vec3 displaced = position; - displaced.y += lift * uLift; - displaced.z += height; - - vec3 displacedNormal = normalize(vec3( - (height - heightX) / epsilon, - (height - heightY) / epsilon, - 1.0 - )); - - vec4 mvPosition = modelViewMatrix * vec4(displaced, 1.0); - - vNormal = normalize(normalMatrix * displacedNormal); - vViewPosition = -mvPosition.xyz; - vWave = height; - - gl_Position = projectionMatrix * mvPosition; -} -`; - -const fragmentShader = ` -uniform vec3 uBaseColor; -uniform vec3 uFresnelColor; -uniform float uFresnelPower; -uniform float uFresnelStrength; -uniform float uHorizonStrength; -uniform float uLateralStrength; -uniform float uIntensity; -uniform float uBaseGlow; -uniform float uOpacity; - -varying vec2 vUv; -varying vec3 vNormal; -varying vec3 vViewPosition; -varying float vWave; - -void main() { - vec3 normal = normalize(vNormal); - vec3 viewDirection = normalize(vViewPosition); - float fresnel = pow(1.0 - max(dot(normal, viewDirection), 0.0), uFresnelPower); - float horizon = smoothstep(0.18, 0.94, vUv.y); - float lateralFresnel = smoothstep(0.18, 1.0, vUv.x); - float blue = clamp( - fresnel * uFresnelStrength - + horizon * uHorizonStrength - + lateralFresnel * uLateralStrength - + vWave * 0.08, - 0.0, - 1.0 - ); - float alpha = smoothstep(0.0, 0.1, vUv.y) * (1.0 - smoothstep(0.8, 1.0, vUv.y)); - float intensity = clamp(uIntensity + fresnel * 0.28 + horizon * 0.12, 0.0, 1.0); - float purpleBalance = clamp(uBaseGlow, 0.0, 1.5); - vec3 color = mix(uBaseColor, uFresnelColor, blue) * intensity; - color = mix(color, uBaseColor * intensity, min(purpleBalance, 1.0)); - color = min(color, max(uBaseColor, uFresnelColor)); - - gl_FragColor = vec4(color, alpha * uOpacity); -} -`; - -function setUniformColor(color: THREE.Color, hex: string) { - const value = Number.parseInt(hex.slice(1), 16); - - color.r = ((value >> 16) & 255) / 255; - color.g = ((value >> 8) & 255) / 255; - color.b = (value & 255) / 255; -} - -function AnimatedPlane({ - inverted, - onReady, - seed, - settings, -}: { - inverted: boolean; - onReady?: () => void; - seed: number; - settings: VoidhashGradientSettings; -}) { - const materialRef = useRef(null); - const didReportReadyRef = useRef(false); - const isMountedRef = useRef(true); - const uniforms = useMemo(() => { - const baseColor = new THREE.Color(); - const fresnelColor = new THREE.Color(); - - setUniformColor(baseColor, settings.baseColor); - setUniformColor(fresnelColor, settings.fresnelColor); - - return { - uBaseColor: { value: baseColor }, - uFresnelColor: { value: fresnelColor }, - uAmplitude: { value: settings.amplitude }, - uBaseGlow: { value: settings.baseGlow }, - uFresnelPower: { value: settings.fresnelPower }, - uFresnelStrength: { value: settings.fresnelStrength }, - uFrequency: { value: settings.frequency }, - uHighFrequency: { value: settings.highFrequency }, - uHorizonStrength: { value: settings.horizonStrength }, - uIntensity: { value: settings.intensity }, - uLateralStrength: { value: settings.lateralStrength }, - uLift: { value: settings.lift }, - uMidFrequency: { value: settings.midFrequency }, - uOpacity: { value: settings.opacity }, - uSeed: { value: seed }, - uTime: { value: 0 }, - }; - }, [seed, settings]); - - useEffect(() => { - return () => { - isMountedRef.current = false; - }; - }, []); - - useEffect(() => { - uniforms.uAmplitude.value = settings.amplitude; - setUniformColor(uniforms.uBaseColor.value, settings.baseColor); - uniforms.uBaseGlow.value = settings.baseGlow; - setUniformColor(uniforms.uFresnelColor.value, settings.fresnelColor); - uniforms.uFresnelPower.value = settings.fresnelPower; - uniforms.uFresnelStrength.value = settings.fresnelStrength; - uniforms.uFrequency.value = settings.frequency; - uniforms.uHighFrequency.value = settings.highFrequency; - uniforms.uHorizonStrength.value = settings.horizonStrength; - uniforms.uIntensity.value = settings.intensity; - uniforms.uLateralStrength.value = settings.lateralStrength; - uniforms.uLift.value = settings.lift; - uniforms.uMidFrequency.value = settings.midFrequency; - uniforms.uOpacity.value = settings.opacity; - uniforms.uSeed.value = seed; - }, [seed, settings, uniforms]); - - useFrame(({ clock }) => { - if (materialRef.current) { - materialRef.current.uniforms.uTime.value = clock.elapsedTime * settings.speed; - } - - if (!didReportReadyRef.current) { - didReportReadyRef.current = true; - requestAnimationFrame(() => { - if (isMountedRef.current) { - onReady?.(); - } - }); - } - }); - - return ( - - - - - - - ); -} - -/** Renders the WebGL plane used by reusable Voidhash gradient backgrounds. */ -export function VoidhashGradientCanvas({ - inverted = false, - onReady, - seed, - settings, -}: { - inverted?: boolean; - onReady?: () => void; - seed: number; - settings: VoidhashGradientSettings; -}) { - return ( - { - gl.outputColorSpace = THREE.SRGBColorSpace; - gl.setClearColor(0x000000, 0); - }} - > - - - ); -} diff --git a/apps/www/src/components/voidhash-gradient-controls.tsx b/apps/www/src/components/voidhash-gradient-controls.tsx deleted file mode 100644 index 2f49f5f00..000000000 --- a/apps/www/src/components/voidhash-gradient-controls.tsx +++ /dev/null @@ -1,175 +0,0 @@ -"use client"; - -import { useState, type Dispatch, type SetStateAction } from "react"; - -import type { VoidhashGradientSettings } from "./voidhash-gradient-settings"; - -type NumericSettingKey = { - [Key in keyof VoidhashGradientSettings]: VoidhashGradientSettings[Key] extends number ? Key : never; -}[keyof VoidhashGradientSettings]; - -type BooleanSettingKey = { - [Key in keyof VoidhashGradientSettings]: VoidhashGradientSettings[Key] extends boolean ? Key : never; -}[keyof VoidhashGradientSettings]; - -type ColorSettingKey = { - [Key in keyof VoidhashGradientSettings]: VoidhashGradientSettings[Key] extends string ? Key : never; -}[keyof VoidhashGradientSettings]; - -const booleanControls: Array<{ key: BooleanSettingKey; label: string }> = [ - { key: "topEnabled", label: "Top effect" }, -]; - -const numericControls: Array<{ - key: NumericSettingKey; - label: string; - min: number; - max: number; - step: number; -}> = [ - { key: "blur", label: "Blur", min: 0, max: 90, step: 1 }, - { key: "effectHeight", label: "Height", min: 70, max: 180, step: 1 }, - { key: "bottomOffset", label: "Bottom", min: -60, max: 20, step: 1 }, - { key: "topOffset", label: "Top", min: -20, max: 60, step: 1 }, - { key: "bottomSeed", label: "Bottom seed", min: 0, max: 80, step: 0.1 }, - { key: "topSeed", label: "Top seed", min: 0, max: 80, step: 0.1 }, - { key: "fadeStart", label: "Fade start", min: 0, max: 80, step: 1 }, - { key: "fadeEnd", label: "Fade full", min: 10, max: 100, step: 1 }, - { key: "planeY", label: "Plane Y", min: -2.4, max: 0.2, step: 0.01 }, - { key: "rotationX", label: "Tilt", min: -1.4, max: -0.25, step: 0.01 }, - { key: "scaleX", label: "Width", min: 0.8, max: 2.2, step: 0.01 }, - { key: "scaleY", label: "Depth", min: 0.5, max: 1.8, step: 0.01 }, - { key: "amplitude", label: "Amplitude", min: 0, max: 1.8, step: 0.01 }, - { key: "frequency", label: "Frequency", min: 0.05, max: 0.5, step: 0.01 }, - { key: "midFrequency", label: "Mid noise", min: 0.8, max: 4, step: 0.01 }, - { key: "highFrequency", label: "Fine noise", min: 1.5, max: 7, step: 0.01 }, - { key: "speed", label: "Speed", min: 0, max: 0.2, step: 0.001 }, - { key: "lift", label: "Lift", min: 0, max: 1, step: 0.01 }, - { key: "fresnelPower", label: "Fresnel pow", min: 0.5, max: 4, step: 0.01 }, - { key: "fresnelStrength", label: "Fresnel", min: 0, max: 3, step: 0.01 }, - { key: "horizonStrength", label: "Horizon", min: 0, max: 2, step: 0.01 }, - { key: "lateralStrength", label: "Blue bias", min: 0, max: 1.5, step: 0.01 }, - { key: "intensity", label: "Intensity", min: 0.2, max: 2, step: 0.01 }, - { key: "baseGlow", label: "Purple mix", min: 0, max: 1.5, step: 0.01 }, - { key: "opacity", label: "Opacity", min: 0, max: 1, step: 0.01 }, -]; - -const colorControls: Array<{ key: ColorSettingKey; label: string }> = [ - { key: "baseColor", label: "Base" }, - { key: "fresnelColor", label: "Fresnel" }, -]; - -function formatValue(value: number) { - if (Math.abs(value) >= 10) { - return value.toFixed(0); - } - - return value.toFixed(2); -} - -/** Renders the debug tuner for Voidhash gradient background settings. */ -export function VoidhashGradientControls({ - onChange, - onHide, - onReset, - settings, - title = "Gradient FX", -}: { - onChange: Dispatch>; - onHide: () => void; - onReset: () => void; - settings: VoidhashGradientSettings; - title?: string; -}) { - const [copied, setCopied] = useState(false); - - return ( -
-
-
{title}
- -
- -
- {booleanControls.map((control) => ( - - ))} - - {colorControls.map((control) => ( - - ))} - - {numericControls.map((control) => ( - - ))} -
- -
- - -
-
- ); -} diff --git a/apps/www/src/components/voidhash-gradient-settings.ts b/apps/www/src/components/voidhash-gradient-settings.ts deleted file mode 100644 index bf826f336..000000000 --- a/apps/www/src/components/voidhash-gradient-settings.ts +++ /dev/null @@ -1,102 +0,0 @@ -export type VoidhashGradientSettings = { - blur: number; - effectHeight: number; - bottomOffset: number; - topEnabled: boolean; - topOffset: number; - bottomSeed: number; - topSeed: number; - fadeStart: number; - fadeEnd: number; - planeY: number; - rotationX: number; - scaleX: number; - scaleY: number; - amplitude: number; - frequency: number; - midFrequency: number; - highFrequency: number; - speed: number; - lift: number; - fresnelPower: number; - fresnelStrength: number; - horizonStrength: number; - lateralStrength: number; - intensity: number; - baseGlow: number; - opacity: number; - baseColor: string; - fresnelColor: string; -}; - -export const VOIDHASH_GRADIENT_STORAGE_KEY = "voidhash:gradient-background-settings"; -export const VOIDHASH_GRADIENT_CONTROLS_STORAGE_KEY = "voidhash:gradient-background-controls"; - -export const DEFAULT_VOIDHASH_GRADIENT_SETTINGS: VoidhashGradientSettings = { - blur: 7, - effectHeight: 98, - bottomOffset: 0, - topEnabled: false, - topOffset: 0, - bottomSeed: 0, - topSeed: 28.7, - fadeStart: 22, - fadeEnd: 58, - planeY: -2.4, - rotationX: -0.86, - scaleX: 1.42, - scaleY: 0.96, - amplitude: 1.42, - frequency: 0.19, - midFrequency: 0.8, - highFrequency: 1.5, - speed: 0.072, - lift: 0.58, - fresnelPower: 0.96, - fresnelStrength: 1.7, - horizonStrength: 0, - lateralStrength: 0.52, - intensity: 1.03, - baseGlow: 0, - opacity: 1, - baseColor: "#7f14ff", - fresnelColor: "#0673ff", -}; - -const HEX_COLOR_PATTERN = /^#[0-9a-f]{6}$/i; - -/** Merges persisted or caller-provided values with the supported gradient settings. */ -export function mergeVoidhashGradientSettings( - value: unknown, - defaults: VoidhashGradientSettings = DEFAULT_VOIDHASH_GRADIENT_SETTINGS, -): VoidhashGradientSettings { - if (!value || typeof value !== "object") { - return defaults; - } - - const settings: VoidhashGradientSettings = { ...defaults }; - const entries = Object.entries(value as Partial>); - - for (const [key, entryValue] of entries) { - if (!(key in settings)) { - continue; - } - - const settingKey = key as keyof VoidhashGradientSettings; - const defaultValue = settings[settingKey]; - - if (typeof defaultValue === "number" && typeof entryValue === "number" && Number.isFinite(entryValue)) { - settings[settingKey] = entryValue as never; - } - - if (typeof defaultValue === "boolean" && typeof entryValue === "boolean") { - settings[settingKey] = entryValue as never; - } - - if (typeof defaultValue === "string" && typeof entryValue === "string" && HEX_COLOR_PATTERN.test(entryValue)) { - settings[settingKey] = entryValue.toLowerCase() as never; - } - } - - return settings; -} diff --git a/apps/www/src/features/auth/components/auth-lenticular-background.tsx b/apps/www/src/features/auth/components/auth-lenticular-background.tsx index 6ace73fe9..c92abc7eb 100644 --- a/apps/www/src/features/auth/components/auth-lenticular-background.tsx +++ b/apps/www/src/features/auth/components/auth-lenticular-background.tsx @@ -1,6 +1,6 @@ "use client"; -import { HeroShader } from "@/features/www/hero/hero-shader"; +import { HeroShader } from "@/components/hero-shader"; import { cn } from "@/lib/utils"; /** Renders the landing lenticular composition with the animated Perlin surface as its source. */ diff --git a/apps/www/src/features/design/components/docs/colors/index.tsx b/apps/www/src/features/design/components/docs/colors/index.tsx deleted file mode 100644 index 0b50c638b..000000000 --- a/apps/www/src/features/design/components/docs/colors/index.tsx +++ /dev/null @@ -1,282 +0,0 @@ -"use client"; - -import { CheckIcon, CopyIcon } from "lucide-react"; -import { useCallback, useState } from "react"; - -import { cn } from "@/features/design/lib/cn"; - -import { - BRAND_SCALES, - isLightColor, - resolveToken, - scaleSteps, - SEMANTIC_GROUPS, - type SemanticToken, - type ThemeName, -} from "./tokens"; - -const THEMES: ThemeName[] = ["light", "dark"]; - -const useCopyValue = () => { - const [copied, setCopied] = useState(undefined); - - const copy = useCallback((value: string) => { - void navigator.clipboard.writeText(value).then(() => { - setCopied(value); - setTimeout(() => setCopied((current) => (current === value ? undefined : current)), 1200); - }); - }, []); - - return { copied, copy }; -}; - -interface CopyButtonProps { - className?: string; - copied: boolean; - label: string; - onCopy: () => void; - value: string; -} - -function CopyButton({ className, copied, label, onCopy, value }: CopyButtonProps) { - return ( - - ); -} - -interface TokenSwatchProps { - theme: ThemeName; - token: SemanticToken; -} - -function TokenSwatch({ theme, token }: TokenSwatchProps) { - const resolved = resolveToken(token.name, theme); - if (!resolved) { - return null; - } - - const on = token.on ? resolveToken(token.on, theme) : undefined; - const fallbackText = isLightColor(resolved.value) ? "oklch(0% 0 0)" : "oklch(100% 0 0)"; - - return ( -
- - {token.on ? "Aa" : theme === "light" ? "L" : "D"} - -
- ); -} - -interface TokenValueProps { - copiedValue: string | undefined; - onCopy: (value: string) => void; - theme: ThemeName; - token: SemanticToken; -} - -function TokenValue({ copiedValue, onCopy, theme, token }: TokenValueProps) { - const resolved = resolveToken(token.name, theme); - if (!resolved) { - return null; - } - - return ( -
- {theme} - onCopy(resolved.value)} - value={resolved.value} - /> - {resolved.alias ? via {resolved.alias} : null} -
- ); -} - -interface SemanticTokenCardProps { - copiedValue: string | undefined; - onCopy: (value: string) => void; - token: SemanticToken; -} - -function SemanticTokenCard({ copiedValue, onCopy, token }: SemanticTokenCardProps) { - const variable = `var(--${token.name})`; - - return ( -
-
- {THEMES.map((theme) => ( - - ))} -
- -
-
- onCopy(variable)} - value={`--${token.name}`} - /> - {token.on ? ( - - on --{token.on} - - ) : null} -
- -

{token.meaning}

- -
- {token.utilities.map((utility) => ( - - {utility} - - ))} -
- -
- {THEMES.map((theme) => ( - - ))} -
-
-
- ); -} - -/** - * Renders every semantic theme token grouped by intent, with its light and dark - * value, the alias it resolves through, and the Tailwind utilities that map to - * it. Values are read from `@voidhash/ui/styles/brand-theme.css`, so this page - * cannot drift from the theme. - */ -export function SemanticColorTokens() { - const { copied, copy } = useCopyValue(); - - return ( -
- {SEMANTIC_GROUPS.map((group) => ( -
-
-

{group.title}

-

{group.description}

-
- -
- {group.tokens.map((token) => ( - - ))} -
-
- ))} -
- ); -} - -/** - * Renders the raw brand ramps every semantic token is built from. Scales are - * theme-independent — only the semantic tokens above remap between light and - * dark. - */ -export function BrandColorScales() { - const { copied, copy } = useCopyValue(); - - return ( -
- {BRAND_SCALES.map((scale) => { - const steps = scaleSteps(scale.prefix); - - return ( -
-
-

{scale.title}

-

{scale.meaning}

-
- -
- {steps.map((step) => { - const name = `${scale.prefix}-${step}`; - const resolved = resolveToken(name, "light"); - if (!resolved) { - return null; - } - - const variable = `var(--${name})`; - - return ( - - ); - })} -
-
- ); - })} -
- ); -} diff --git a/apps/www/src/features/design/components/docs/colors/tokens.ts b/apps/www/src/features/design/components/docs/colors/tokens.ts deleted file mode 100644 index 9f9124708..000000000 --- a/apps/www/src/features/design/components/docs/colors/tokens.ts +++ /dev/null @@ -1,452 +0,0 @@ -import brandThemeCss from "@voidhash/ui/styles/brand-theme.css?raw"; - -export type ThemeName = "light" | "dark"; - -export interface ResolvedToken { - /** Final color value with every `var()` indirection followed. */ - value: string; - /** The variable this token points at, when it is defined as an alias. */ - alias?: string; -} - -export interface SemanticToken { - /** Custom property name without the leading dashes, e.g. `primary`. */ - name: string; - /** What the token is for and when to reach for it. */ - meaning: string; - /** Tailwind utilities that map onto this token. */ - utilities: string[]; - /** Token used for text/icons placed on top of this one, if there is a pair. */ - on?: string; -} - -export interface SemanticGroup { - title: string; - description: string; - tokens: SemanticToken[]; -} - -export interface BrandScale { - /** Custom property prefix, e.g. `blue-ribbon` for `--blue-ribbon-500`. */ - prefix: string; - title: string; - meaning: string; -} - -const SELECTOR_LIGHT = ":root"; -const SELECTOR_DARK = ".dark"; -const ALIAS_PATTERN = /^var\((--[\w-]+)\)$/; - -/** - * Reads the custom properties declared in a single flat rule block. The brand - * theme keeps `:root` and `.dark` free of nested rules, so a brace scan is - * enough — no CSS parser needed. - */ -const readDeclarations = (css: string, selector: string): Record => { - const selectorStart = css.indexOf(`${selector} {`); - if (selectorStart === -1) { - return {}; - } - - const blockStart = css.indexOf("{", selectorStart); - const blockEnd = css.indexOf("}", blockStart); - const declarations: Record = {}; - - for (const declaration of css.slice(blockStart + 1, blockEnd).split(";")) { - const separator = declaration.indexOf(":"); - if (separator === -1) { - continue; - } - - const name = declaration.slice(0, separator).trim(); - if (name.startsWith("--")) { - declarations[name] = declaration.slice(separator + 1).trim(); - } - } - - return declarations; -}; - -const LIGHT_DECLARATIONS = readDeclarations(brandThemeCss, SELECTOR_LIGHT); -const DARK_DECLARATIONS = { - ...LIGHT_DECLARATIONS, - ...readDeclarations(brandThemeCss, SELECTOR_DARK), -}; - -const declarationsFor = (theme: ThemeName) => - theme === "dark" ? DARK_DECLARATIONS : LIGHT_DECLARATIONS; - -const follow = (declarations: Record, value: string, depth = 0): string => { - const alias = ALIAS_PATTERN.exec(value); - const target = alias ? declarations[alias[1]] : undefined; - if (!target || depth > 10) { - return value; - } - - return follow(declarations, target, depth + 1); -}; - -/** - * Resolves a theme token to its literal color, following alias chains such as - * `--primary` → `--blue-ribbon-600` → `oklch(…)`. Returns `undefined` when the - * token is not declared for the given theme. - */ -export const resolveToken = (name: string, theme: ThemeName): ResolvedToken | undefined => { - const declarations = declarationsFor(theme); - const raw = declarations[`--${name}`]; - if (!raw) { - return undefined; - } - - const alias = ALIAS_PATTERN.exec(raw); - return { - alias: alias?.[1], - value: follow(declarations, raw), - }; -}; - -/** Lists the steps declared for a scale prefix, ordered light to dark. */ -export const scaleSteps = (prefix: string): number[] => - Object.keys(LIGHT_DECLARATIONS) - .map((name) => { - const match = new RegExp(`^--${prefix}-(\\d+)$`).exec(name); - return match ? Number(match[1]) : undefined; - }) - .filter((step): step is number => step !== undefined) - .sort((a, b) => a - b); - -/** - * Estimates whether a color is light enough to need dark text on top. Handles - * the two literal formats used by the theme: `oklch(L% C H)` and hex. - */ -export const isLightColor = (value: string): boolean => { - const oklch = /^oklch\(\s*([\d.]+)%/.exec(value); - if (oklch) { - return Number(oklch[1]) >= 62; - } - - const hex = /^#([\da-f]{6})$/i.exec(value); - if (hex) { - const int = Number.parseInt(hex[1], 16); - const luminance = - (0.2126 * ((int >> 16) & 0xff) + 0.7152 * ((int >> 8) & 0xff) + 0.0722 * (int & 0xff)) / 255; - return luminance >= 0.55; - } - - return true; -}; - -export const SEMANTIC_GROUPS: SemanticGroup[] = [ - { - description: - "The stack of neutral surfaces, from the page canvas up to floating layers. Pick the one that matches how far the element is lifted off the page, not the color you want.", - title: "Surfaces", - tokens: [ - { - meaning: - "The app canvas. Everything else sits on top of it. Set once on `body` — components should not repaint it.", - name: "background", - on: "foreground", - utilities: ["bg-background"], - }, - { - meaning: - "A neutral surface raised off the canvas: toolbars, inspector rails, list rows that need separation without a card border.", - name: "surface", - on: "foreground", - utilities: ["bg-surface"], - }, - { - meaning: - "A recessed surface for wells and tracks — slider rails, progress backgrounds, inset code blocks.", - name: "surface-muted", - on: "foreground", - utilities: ["bg-surface-muted"], - }, - { - meaning: - "Content containers. Use with `--border` for the outline; in dark mode it reads lighter than the canvas so cards float.", - name: "card", - on: "card-foreground", - utilities: ["bg-card"], - }, - { - meaning: "Text and icons inside a card.", - name: "card-foreground", - utilities: ["text-card-foreground"], - }, - { - meaning: - "App chrome around the workspace — designer and editor panels. Slightly darker than `--card` in dark mode so tooling recedes behind content.", - name: "panel", - on: "foreground", - utilities: ["bg-panel"], - }, - { - meaning: - "Layers that float above the page: dropdowns, menus, tooltips, comboboxes, date pickers.", - name: "popover", - on: "popover-foreground", - utilities: ["bg-popover"], - }, - { - meaning: "Text and icons inside a popover layer.", - name: "popover-foreground", - utilities: ["text-popover-foreground"], - }, - ], - }, - { - description: - "Text and icon colors. Body copy is `--foreground`; anything quieter steps down to `--muted-foreground` rather than lowering opacity.", - title: "Content", - tokens: [ - { - meaning: "Default body text, headings, and icons on the canvas.", - name: "foreground", - utilities: ["text-foreground"], - }, - { - meaning: - "Secondary text: labels, helper copy, placeholders, timestamps, inactive icons. The lowest-emphasis text that still meets contrast.", - name: "muted-foreground", - utilities: ["text-muted-foreground"], - }, - { - meaning: - "Quiet neutral fill for badges, skeletons, disabled controls, and hovered table rows.", - name: "muted", - on: "muted-foreground", - utilities: ["bg-muted"], - }, - ], - }, - { - description: - "Interactive intent. One primary action per view; everything competing with it drops to secondary or ghost styling.", - title: "Actions", - tokens: [ - { - meaning: - "The primary action and brand accent — solid buttons, selected states, links, active nav items.", - name: "primary", - on: "primary-foreground", - utilities: ["bg-primary", "text-primary", "border-primary"], - }, - { - meaning: "Text and icons on a primary fill. Stays white in both themes.", - name: "primary-foreground", - utilities: ["text-primary-foreground"], - }, - { - meaning: "Neutral, lower-emphasis actions that sit next to a primary button.", - name: "secondary", - on: "secondary-foreground", - utilities: ["bg-secondary"], - }, - { - meaning: "Text and icons on a secondary fill.", - name: "secondary-foreground", - utilities: ["text-secondary-foreground"], - }, - { - meaning: - "Hover and highlight state for list-like surfaces: menu items, command results, sidebar rows, ghost buttons.", - name: "accent", - on: "accent-foreground", - utilities: ["bg-accent", "hover:bg-accent"], - }, - { - meaning: "Text and icons on an accent highlight.", - name: "accent-foreground", - utilities: ["text-accent-foreground"], - }, - ], - }, - { - description: - "Status colors. Reserved for outcomes and risk — never used decoratively, so their appearance always carries meaning.", - title: "Feedback", - tokens: [ - { - meaning: - "Destructive and irreversible actions, error states, invalid fields. Pair with a confirmation for anything unrecoverable.", - name: "destructive", - on: "destructive-foreground", - utilities: ["bg-destructive", "text-destructive", "border-destructive"], - }, - { - meaning: "Text and icons on a destructive fill.", - name: "destructive-foreground", - utilities: ["text-destructive-foreground"], - }, - { - meaning: "Successful outcomes and healthy status — completed steps, live deployments.", - name: "success", - on: "success-foreground", - utilities: ["bg-success", "text-success"], - }, - { - meaning: "Text and icons on a success fill.", - name: "success-foreground", - utilities: ["text-success-foreground"], - }, - ], - }, - { - description: - "Hairlines, control outlines, and focus. These are the only tokens allowed to draw structure — do not fake borders with a background color.", - title: "Borders and focus", - tokens: [ - { - meaning: - "Default hairline between surfaces. Applied globally by the base layer, so most elements inherit it without a border utility.", - name: "border", - utilities: ["border-border"], - }, - { - meaning: "Outline of form controls — inputs, textareas, selects, checkboxes.", - name: "input", - utilities: ["border-input"], - }, - { - meaning: - "Keyboard focus ring. The base layer renders it at 50% opacity (`outline-ring/50`), so focus reads clearly without shouting.", - name: "ring", - utilities: ["ring-ring", "outline-ring/50"], - }, - ], - }, - { - description: - "The sidebar runs its own surface stack so navigation can go darker than the app without dragging the rest of the UI with it.", - title: "Sidebar", - tokens: [ - { - meaning: "Sidebar background. Pure black in dark mode, pinning navigation to the far edge.", - name: "sidebar", - on: "sidebar-foreground", - utilities: ["bg-sidebar"], - }, - { - meaning: "Sidebar labels and icons.", - name: "sidebar-foreground", - utilities: ["text-sidebar-foreground"], - }, - { - meaning: - "Active navigation item. Deliberately neutral rather than brand blue so the sidebar does not compete with in-page primary actions.", - name: "sidebar-primary", - on: "sidebar-primary-foreground", - utilities: ["bg-sidebar-primary"], - }, - { - meaning: "Text on an active navigation item.", - name: "sidebar-primary-foreground", - utilities: ["text-sidebar-primary-foreground"], - }, - { - meaning: "Hovered navigation item.", - name: "sidebar-accent", - on: "sidebar-accent-foreground", - utilities: ["bg-sidebar-accent"], - }, - { - meaning: "Text on a hovered navigation item.", - name: "sidebar-accent-foreground", - utilities: ["text-sidebar-accent-foreground"], - }, - { - meaning: "Dividers inside the sidebar and the seam against the app canvas.", - name: "sidebar-border", - utilities: ["border-sidebar-border"], - }, - { - meaning: "Focus ring for sidebar controls.", - name: "sidebar-ring", - utilities: ["ring-sidebar-ring"], - }, - ], - }, - { - description: - "Categorical series colors, ordered by how they should be assigned. Use them in sequence so the same series index keeps the same color across charts.", - title: "Data visualization", - tokens: [ - { - meaning: "First series — the metric the chart is about.", - name: "chart-1", - utilities: ["fill-chart-1", "stroke-chart-1"], - }, - { - meaning: "Second series.", - name: "chart-2", - utilities: ["fill-chart-2", "stroke-chart-2"], - }, - { - meaning: "Third series.", - name: "chart-3", - utilities: ["fill-chart-3", "stroke-chart-3"], - }, - { - meaning: "Fourth series.", - name: "chart-4", - utilities: ["fill-chart-4", "stroke-chart-4"], - }, - { - meaning: "Fifth series. Beyond five categories, group the tail into an “Other” bucket.", - name: "chart-5", - utilities: ["fill-chart-5", "stroke-chart-5"], - }, - ], - }, -]; - -export const BRAND_SCALES: BrandScale[] = [ - { - meaning: - "The Voidhash brand hue. Step 600 is `--primary`, step 500 is `--ring`. Lighter steps back tinted surfaces; darker steps are for text on tinted backgrounds.", - prefix: "blue-ribbon", - title: "Blue Ribbon", - }, - { - meaning: - "Secondary brand hue. Used for the second chart series and for AI/agent surfaces that need to read as distinct from primary actions.", - prefix: "electric-violet", - title: "Electric Violet", - }, - { - meaning: "Third chart series and accent illustrations. Not used for interactive states.", - prefix: "fuchsia-pink", - title: "Fuchsia Pink", - }, - { - meaning: - "Danger. Step 600 is `--destructive` in light mode, step 500 in dark mode where the surface is darker.", - prefix: "radical-red", - title: "Radical Red", - }, - { - meaning: - "Reserved for high-urgency, non-destructive states. No semantic token maps to it yet, so reference the scale directly and document the usage.", - prefix: "blaze-orange", - title: "Blaze Orange", - }, - { - meaning: - "Warnings and pending states — there is no `--warning` token, so use `amber-500`/`amber-600` when you need caution without danger. Also the fourth chart series.", - prefix: "amber", - title: "Amber", - }, - { - meaning: "Success and healthy status. Step 600 is `--success`; step 500 is the fifth series.", - prefix: "pistachio", - title: "Pistachio", - }, - { - meaning: - "The neutral ramp every surface, border, and text token is built from. Light mode maps 50–200 to surfaces and 500–900 to text; dark mode inverts that.", - prefix: "zinc", - title: "Zinc", - }, -]; diff --git a/apps/www/src/features/design/components/docs/component-overview.tsx b/apps/www/src/features/design/components/docs/component-overview.tsx deleted file mode 100644 index f2488d0cc..000000000 --- a/apps/www/src/features/design/components/docs/component-overview.tsx +++ /dev/null @@ -1,14 +0,0 @@ -"use client"; - -import Preview02Example from "./component-overview/index"; - -/** - * Renders shadcn's preview-02 composition using the Voidhash UI primitives. - */ -export function ComponentOverview() { - return ( -
- -
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/account-access.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/account-access.tsx deleted file mode 100644 index 24981f391..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/account-access.tsx +++ /dev/null @@ -1,86 +0,0 @@ -"use client"; - -import { Button } from "@voidhash/ui"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { Field, FieldGroup, FieldLabel } from "@voidhash/ui"; -import { Input } from "@voidhash/ui"; -import { Item, ItemContent, ItemDescription, ItemMedia, ItemTitle } from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function AccountAccess() { - return ( - - - Account Access - Update your credentials or re-authenticate. - - - - - Email Address - - - -
- Current Password - - Forgot? - -
- -
-
-
- - - - - - - - - Danger Zone - - Archive account and remove catalog - - - - - - -
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/card-overview.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/card-overview.tsx deleted file mode 100644 index 74c81fe07..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/card-overview.tsx +++ /dev/null @@ -1,77 +0,0 @@ -"use client"; - -import { Bar, BarChart, XAxis } from "recharts"; - -import { Badge } from "@voidhash/ui"; -import { Button } from "@voidhash/ui"; -import { Card, CardContent, CardDescription, CardTitle } from "@voidhash/ui"; -import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@voidhash/ui"; - -const activityData = [ - { month: "Jan", amount: 40 }, - { month: "Feb", amount: 55 }, - { month: "Mar", amount: 35 }, - { month: "Apr", amount: 60 }, - { month: "May", amount: 45 }, - { month: "Jun", amount: 50 }, - { month: "Jul", amount: 65 }, - { month: "Aug", amount: 40 }, - { month: "Sep", amount: 55 }, - { month: "Oct", amount: 70 }, - { month: "Nov", amount: 45 }, - { month: "Dec", amount: 80 }, -]; - -const chartConfig = { - amount: { - label: "Activity", - color: "var(--chart-2)", - }, -} satisfies ChartConfig; - -export function CardOverview() { - return ( -
- - - Card Balance - US$12.94 - US$11,337.06 Available - - - - -
- Payment Due - 1 Apr -
- -
-
- - -
- Yearly Activity - +US$0.25 Daily Cash -
- - - String(v).slice(0, 1)} - className="text-[10px]" - /> - } /> - - - -
-
-
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/claimable-balance.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/claimable-balance.tsx deleted file mode 100644 index 1c7e3f98f..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/claimable-balance.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Badge } from "@voidhash/ui"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { Item, ItemContent } from "@voidhash/ui"; -import { Separator } from "@voidhash/ui"; - -export function ClaimableBalance() { - return ( - - - Claimable Balance - $0.00 - - - Pending Setup - - - - - -
- Net Royalties - $0.00 -
-
- Processing Fee - -$0.00 -
- -
- Total Ready to Claim - $0.00 USD -
-
-
-
- - - Once your bank is connected, balances over $10.00 are automatically eligible for monthly - distribution on the 15th of each month. - - -
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/contribution-history.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/contribution-history.tsx deleted file mode 100644 index 120fb2ecf..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/contribution-history.tsx +++ /dev/null @@ -1,92 +0,0 @@ -"use client"; - -import { Bar, BarChart, XAxis } from "recharts"; - -import { Button } from "@voidhash/ui"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@voidhash/ui"; -import { Item, ItemContent, ItemDescription } from "@voidhash/ui"; -import { useDesignSystemSearchParams } from "../preview-config"; - -const chartData = [ - { month: "Dec", amount: 800 }, - { month: "Jan", amount: 1100 }, - { month: "Feb", amount: 900 }, - { month: "Mar", amount: 1300 }, - { month: "Apr", amount: 750 }, - { month: "May", amount: 1400 }, -]; - -const chartConfig = { - amount: { - label: "Contribution", - color: "var(--chart-2)", - }, -} satisfies ChartConfig; - -export function ContributionHistory() { - const [params] = useDesignSystemSearchParams(); - const isRounded = !["lyra", "sera"].includes(params.style); - - return ( - - - Contribution History - Last 6 months of activity - - - - - - } - /> - - - - - -
- - - - Upcoming - - May 25, 2024 - $1,000 scheduled - - - - - - Auto-Save Plan - - Accelerated - Recurring weekly - - -
-
- - - -
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/cover-art.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/cover-art.tsx deleted file mode 100644 index 383abf71e..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/cover-art.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Button } from "@voidhash/ui"; -import { Card, CardContent, CardDescription, CardFooter } from "@voidhash/ui"; -import { Item } from "@voidhash/ui"; -import { Label } from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function CoverArt() { - return ( - - - - - - - - - - - - Minimum 3000 × 3000px -
- JPEG or PNG only -
-
-
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/dividend-income.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/dividend-income.tsx deleted file mode 100644 index d1c67686c..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/dividend-income.tsx +++ /dev/null @@ -1,123 +0,0 @@ -"use client"; - -import { Bar, BarChart } from "recharts"; - -import { Button } from "@voidhash/ui"; -import { - Card, - CardAction, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@voidhash/ui"; -import { Item, ItemContent, ItemDescription, ItemGroup, ItemTitle } from "@voidhash/ui"; -import { useDesignSystemSearchParams } from "../preview-config"; -import { IconPlaceholder } from "../icon-placeholder"; - -const HOLDINGS = [ - { - name: "Vanguard VIG", - shares: "450 Shares", - amount: "$1,842.10", - data: [ - { q: "Q1", value: 380 }, - { q: "Q2", value: 420 }, - { q: "Q3", value: 390 }, - { q: "Q4", value: 652 }, - ], - }, - { - name: "S&P 500 VOO", - shares: "112 Shares", - amount: "$928.40", - data: [ - { q: "Q1", value: 180 }, - { q: "Q2", value: 210 }, - { q: "Q3", value: 320 }, - { q: "Q4", value: 218 }, - ], - }, - { - name: "Apple AAPL", - shares: "85 Shares", - amount: "$340.00", - data: [ - { q: "Q1", value: 60 }, - { q: "Q2", value: 70 }, - { q: "Q3", value: 120 }, - { q: "Q4", value: 90 }, - ], - }, - { - name: "Realty Income", - shares: "320 Shares", - amount: "$1,139.50", - data: [ - { q: "Q1", value: 240 }, - { q: "Q2", value: 260 }, - { q: "Q3", value: 280 }, - { q: "Q4", value: 360 }, - ], - }, -]; - -const miniChartConfig = { - value: { - label: "Dividend", - color: "var(--chart-2)", - }, -} satisfies ChartConfig; - -export function DividendIncome() { - const [params] = useDesignSystemSearchParams(); - const isRounded = !["lyra", "sera"].includes(params.style); - - return ( - - - Q2 Dividend Income - - Quarterly dividend payouts across your portfolio holdings. - - - - - - - - {HOLDINGS.map((holding) => ( - - - {holding.name} - {holding.shares} - - - - } /> - - - - - {holding.amount} - - - ))} - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/empty-connect-bank.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/empty-connect-bank.tsx deleted file mode 100644 index 9f37a47ed..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/empty-connect-bank.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Button } from "@voidhash/ui"; -import { Card, CardContent } from "@voidhash/ui"; -import { - Empty, - EmptyContent, - EmptyDescription, - EmptyHeader, - EmptyMedia, - EmptyTitle, -} from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function EmptyConnectBank() { - return ( - - - - - - - - Connect Bank - - Link your payout method to receive monthly royalty distributions automatically. - - - - - - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/empty-distribute-track.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/empty-distribute-track.tsx deleted file mode 100644 index 7f79c0ed0..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/empty-distribute-track.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Button } from "@voidhash/ui"; -import { Card, CardContent } from "@voidhash/ui"; -import { - Empty, - EmptyContent, - EmptyDescription, - EmptyHeader, - EmptyMedia, - EmptyTitle, -} from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function EmptyDistributeTrack() { - return ( - - - - - - - - Distribute Track - - Upload your first master to start reaching listeners on Spotify, Apple Music, and - more. - - - - - - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/empty-explore-catalog.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/empty-explore-catalog.tsx deleted file mode 100644 index 7411baae8..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/empty-explore-catalog.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Button } from "@voidhash/ui"; -import { Card, CardContent } from "@voidhash/ui"; -import { - Empty, - EmptyContent, - EmptyDescription, - EmptyHeader, - EmptyMedia, - EmptyTitle, -} from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function EmptyExploreCatalog() { - return ( - - - - - - - - Explore Catalog - - Check your ISRC codes, metadata, and visual assets before going live. - - - - - - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/faq.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/faq.tsx deleted file mode 100644 index b895b6033..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/faq.tsx +++ /dev/null @@ -1,103 +0,0 @@ -"use client"; - -import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@voidhash/ui"; -import { Button } from "@voidhash/ui"; -import { Card, CardContent, CardFooter } from "@voidhash/ui"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@voidhash/ui"; - -const GENERAL_QUESTIONS = [ - { - q: "How secure is my financial data with Ledger?", - a: "We use bank-level AES-256 encryption, SOC 2 Type II certified infrastructure, and never store your credentials. All connections use read-only access tokens. We are a SEC registered investment advisor.", - }, - { - q: "How do I connect my bank or investment accounts?", - a: "Go to Settings > Linked Accounts and search for your institution. We support over 12,000 banks and brokerages via Plaid and MX.", - }, - { - q: "Can I export my data for tax purposes?", - a: "Yes. Navigate to Reports > Tax Export to download a CSV or PDF summary of your transactions, dividends, and capital gains for any tax year.", - }, -]; - -const SYNC_QUESTIONS = [ - { - q: "How often does data refresh?", - a: "Connected institutions sync every six hours, and you can pull a manual refresh from the account detail view at any time.", - }, - { - q: "Why is a transaction missing?", - a: "Pending transactions appear once the institution posts them. If a posted transaction is still missing after 48 hours, reconnect the account from Settings.", - }, - { - q: "Can I import a statement manually?", - a: "Yes. Upload a CSV or OFX file from the account detail view and map the columns once — the mapping is remembered for later imports.", - }, -]; - -const GOALS_QUESTIONS = [ - { - q: "How do I set up a custom financial goal?", - a: "Click New Goal from the Savings Targets card. Choose a category, set a target amount and date, and we'll calculate the monthly contribution needed.", - }, - { - q: "Can I track multiple goals at once?", - a: "Yes. Pro accounts can track unlimited goals. Basic accounts support up to 3 active goals.", - }, - { - q: "How are monthly contributions calculated?", - a: "We divide the remaining amount by the number of months until your target date, adjusted for your current savings rate and any auto-transfer schedules.", - }, -]; - -function QuestionList({ questions }: { questions: { q: string; a: string }[] }) { - return ( - - {questions.map((item, index) => ( - - {item.q} - {item.a} - - ))} - - ); -} - -export function Faq() { - return ( - - - - - - General - - - Sync - - - Goals - - - - - - - - - - - - - - - - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/front-door.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/front-door.tsx deleted file mode 100644 index 240d3a142..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/front-door.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Badge } from "@voidhash/ui"; -import { - Card, - CardAction, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function FrontDoor() { - return ( - - - Front Door - Smart Lock Pro - -
- Locked - -
-
-
- -
- - Live - -
-
-
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/index-investing.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/index-investing.tsx deleted file mode 100644 index d5d5b2cc3..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/index-investing.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@voidhash/ui"; - -export function IndexInvesting() { - return ( - - - Dollar-Cost Averaging - A strategy for building wealth over time. - - - - - Over time - - , this smooths out the average cost of your investments. When prices drop, your fixed - amount buys more shares. When prices rise, you buy fewer. The result is a lower average - cost per share compared to lump-sum investing during volatile periods. - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/kitchen-island.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/kitchen-island.tsx deleted file mode 100644 index db97fc696..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/kitchen-island.tsx +++ /dev/null @@ -1,161 +0,0 @@ -"use client"; - -import * as React from "react"; - -import { - Card, - CardAction, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { Item, ItemActions, ItemContent, ItemGroup, ItemMedia, ItemTitle } from "@voidhash/ui"; -import { Slider } from "@voidhash/ui"; -import { Switch } from "@voidhash/ui"; -import { ToggleGroup, ToggleGroupItem } from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -const SCENES = { - cooking: { brightness: [90], colorTemp: [70], volume: [30], fade: [0] }, - dining: { brightness: [50], colorTemp: [40], volume: [20], fade: [60] }, - nightlight: { brightness: [15], colorTemp: [20], volume: [0], fade: [80] }, - focus: { brightness: [100], colorTemp: [85], volume: [0], fade: [0] }, -} as const; - -export function KitchenIsland() { - const [enabled, setEnabled] = React.useState(true); - const [scene, setScene] = React.useState("cooking"); - const [brightness, setBrightness] = React.useState([90]); - const [colorTemp, setColorTemp] = React.useState([70]); - const [volume, setVolume] = React.useState([30]); - const [fade, setFade] = React.useState([0]); - - const handleSceneChange = (value: string) => { - if (!value) return; - setScene(value); - const preset = SCENES[value as keyof typeof SCENES]; - setBrightness([...preset.brightness]); - setColorTemp([...preset.colorTemp]); - setVolume([...preset.volume]); - setFade([...preset.fade]); - }; - - return ( - - - Kitchen Island - Hue Color Ambient - - - - - -
- Scenes - - - Cooking - - - Dining - - - Nightlight - - - Focus - - -
- - - - - - - Brightness - - - - - - - - - - - Color Temp - - - - - - - - - - - Volume - - - - - - - - - - - Fade - - - - - - -
-
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/loading-card.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/loading-card.tsx deleted file mode 100644 index 38dc57158..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/loading-card.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Card, CardContent, CardHeader } from "@voidhash/ui"; -import { Skeleton } from "@voidhash/ui"; - -export function LoadingCard() { - return ( - - - - - - - -
- - - -
-
- - -
-
-
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/new-milestone.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/new-milestone.tsx deleted file mode 100644 index 0bc6c3d2f..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/new-milestone.tsx +++ /dev/null @@ -1,50 +0,0 @@ -"use client"; - -import { Button } from "@voidhash/ui"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { Field, FieldGroup, FieldLabel } from "@voidhash/ui"; -import { Input } from "@voidhash/ui"; - -export function NewMilestone() { - return ( - - - Set a new milestone - - Define your financial target and we'll help you pace your savings. - - - - - - Goal Name - - -
- - Target Amount - - - - Target Date - - -
-
-
- - - - -
- ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/notification-settings.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/notification-settings.tsx deleted file mode 100644 index 3074bebb6..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/notification-settings.tsx +++ /dev/null @@ -1,98 +0,0 @@ -"use client"; - -import * as React from "react"; - -import { Button } from "@voidhash/ui"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { Checkbox } from "@voidhash/ui"; -import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel } from "@voidhash/ui"; - -const NOTIFICATIONS = [ - { - id: "transactions", - label: "Transaction alerts", - description: "Deposits, withdrawals, and transfers.", - defaultChecked: true, - }, - { - id: "security", - label: "Security alerts", - description: "Login attempts and account changes.", - defaultChecked: true, - }, - { - id: "goals", - label: "Goal milestones", - description: "Updates at 25%, 50%, 75%, and 100%.", - defaultChecked: false, - }, - { - id: "market", - label: "Market updates", - description: "Daily portfolio summary and price alerts.", - defaultChecked: false, - }, -]; - -export function NotificationSettings() { - const [checked, setChecked] = React.useState>( - Object.fromEntries(NOTIFICATIONS.map((n) => [n.id, n.defaultChecked])), - ); - - const allChecked = NOTIFICATIONS.every((n) => checked[n.id]); - const someChecked = NOTIFICATIONS.some((n) => checked[n.id]) && !allChecked; - - const handleSelectAll = (value: boolean) => { - setChecked(Object.fromEntries(NOTIFICATIONS.map((n) => [n.id, value]))); - }; - - const handleToggle = (id: string, value: boolean) => { - setChecked((prev) => ({ ...prev, [id]: value })); - }; - - return ( - - - Notifications - Choose what you want to be notified about. - - - - - handleSelectAll(!!v)} - /> - - Select all - - - {NOTIFICATIONS.map((n) => ( - - handleToggle(n.id, !!v)} - /> - - {n.label} - {n.description} - - - ))} - - - - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/payments.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/payments.tsx deleted file mode 100644 index 0e7be017d..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/payments.tsx +++ /dev/null @@ -1,169 +0,0 @@ -"use client"; - -import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbList, - BreadcrumbPage, - BreadcrumbSeparator, -} from "@voidhash/ui"; -import { Button } from "@voidhash/ui"; -import { Card, CardContent, CardHeader } from "@voidhash/ui"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@voidhash/ui"; -import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function Payments() { - return ( - - - - - - Home - - - - - - - - - - Profile - Statements - Documents - - - - - - - Payments - - - - - - - - - - - - - Change transfer limit - Adjust how much you can send from your balance. - - - - - - - - - - - Scheduled transfers - Set up a transfer to send at a later date. - - - - - - - - - - - Direct Debits - Set up and manage regular payments. - - - - - - - - - - - Recurring card payments - Manage your repeated card transactions. - - - - - - - - ); -} diff --git a/apps/www/src/features/design/components/docs/component-overview/cards/payout-threshold.tsx b/apps/www/src/features/design/components/docs/component-overview/cards/payout-threshold.tsx deleted file mode 100644 index a8a402735..000000000 --- a/apps/www/src/features/design/components/docs/component-overview/cards/payout-threshold.tsx +++ /dev/null @@ -1,101 +0,0 @@ -"use client"; - -import * as React from "react"; - -import { Button } from "@voidhash/ui"; -import { - Card, - CardAction, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@voidhash/ui"; -import { Field, FieldDescription, FieldGroup, FieldLabel } from "@voidhash/ui"; -import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectTrigger, - SelectValue, -} from "@voidhash/ui"; -import { Slider } from "@voidhash/ui"; -import { Textarea } from "@voidhash/ui"; -import { IconPlaceholder } from "../icon-placeholder"; - -export function PayoutThreshold() { - const [amount, setAmount] = React.useState([2500]); - - return ( - - - Payout Threshold - - Set the minimum balance required before a payout is triggered. - - - - - - - - - Preferred Currency - - - -
- Minimum Payout Amount - ${amount[0].toFixed(2)} -
- -
- $50 (MIN) - $10,000 (MAX) -
-
- - Notes -