From 2e0074bda35986d81e15f62d95b4b0036f96da94 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 02:16:58 +0400 Subject: [PATCH 01/76] Set web container width to 72rem --- apps/web/src/components/layout/section.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/layout/section.tsx b/apps/web/src/components/layout/section.tsx index e17c620f..9afc79d7 100644 --- a/apps/web/src/components/layout/section.tsx +++ b/apps/web/src/components/layout/section.tsx @@ -21,7 +21,7 @@ export function SectionLine({ orientation }: { orientation: "horizontal" | "vert export function SectionShell({ children, className }: { children: ReactNode; className?: string }) { return ( -
+
From 8ca8a002ccc5247d2da12c5dcb59d8fbc219a009 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 02:17:05 +0400 Subject: [PATCH 02/76] Update dark web theme tokens --- apps/web/src/styles/globals.css | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css index 65cdcf1c..74e99938 100644 --- a/apps/web/src/styles/globals.css +++ b/apps/web/src/styles/globals.css @@ -141,15 +141,15 @@ } .dark { - --background: oklch(0.17 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.1871 0 0); + --background: #0a0a0a; + --foreground: #f5f5f5; + --card: #0a0a0a; --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); --primary: oklch(0.87 0 0); --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.24 0 0); + --secondary: #0a0a0a; --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); --muted-foreground: oklch(0.708 0 0); @@ -157,7 +157,7 @@ --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); --destructive-foreground: oklch(0.637 0.237 25.331); - --border: oklch(26% 0 0); + --border: #1f1f1f; --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); --chart-1: oklch(0.87 0 0); From a9902cd9e04afb991ebafec1d8720a3352f10c46 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 02:17:14 +0400 Subject: [PATCH 03/76] Use GitHub Dark for code highlighting --- apps/web/src/components/ui/code-block-content.tsx | 4 ++-- apps/web/src/components/ui/dynamic-code-block.tsx | 2 +- apps/web/src/lib/shiki-themes.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/ui/code-block-content.tsx b/apps/web/src/components/ui/code-block-content.tsx index 678e289f..2f8f2ba6 100644 --- a/apps/web/src/components/ui/code-block-content.tsx +++ b/apps/web/src/components/ui/code-block-content.tsx @@ -8,7 +8,7 @@ import { cn } from "@/lib/utils"; const defaultThemes = { themes: { light: "github-light" satisfies BundledTheme, - dark: "one-dark-pro" satisfies BundledTheme, + dark: "github-dark" satisfies BundledTheme, }, defaultColor: false as const, }; @@ -42,7 +42,7 @@ export async function InlineCode({ lang, code }: { lang: string; code: string }) const { codeToTokens } = await import("shiki"); const { tokens } = await codeToTokens(code, { lang: lang as BundledLanguage, - theme: "one-dark-pro", + theme: "github-dark", }); return ( diff --git a/apps/web/src/components/ui/dynamic-code-block.tsx b/apps/web/src/components/ui/dynamic-code-block.tsx index 1f394382..751da2f9 100644 --- a/apps/web/src/components/ui/dynamic-code-block.tsx +++ b/apps/web/src/components/ui/dynamic-code-block.tsx @@ -12,7 +12,7 @@ import { cn } from "@/lib/utils"; const defaultThemes = { themes: { light: "github-light" satisfies BundledTheme, - dark: "one-dark-pro" satisfies BundledTheme, + dark: "github-dark" satisfies BundledTheme, }, defaultColor: false as const, }; diff --git a/apps/web/src/lib/shiki-themes.ts b/apps/web/src/lib/shiki-themes.ts index 4b6c50b0..13783173 100644 --- a/apps/web/src/lib/shiki-themes.ts +++ b/apps/web/src/lib/shiki-themes.ts @@ -1,6 +1,6 @@ export const shikiThemes = { light: "github-light", - dark: "one-dark-pro", + dark: "github-dark", } as const; export const shikiHighlightOptions = { From 0cb55491352e95c2e8992bf2c07d378c6320a9b2 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 02:17:26 +0400 Subject: [PATCH 04/76] Remove providers docs section --- .../docs/concepts/payment-providers.mdx | 2 - .../content/docs/get-started/quickstart.mdx | 2 +- apps/web/content/docs/meta.json | 2 - apps/web/content/docs/providers/meta.json | 4 - apps/web/content/docs/providers/stripe.mdx | 167 ------------------ apps/web/content/drafts/docs-index.mdx | 4 +- 6 files changed, 3 insertions(+), 178 deletions(-) delete mode 100644 apps/web/content/docs/providers/meta.json delete mode 100644 apps/web/content/docs/providers/stripe.mdx diff --git a/apps/web/content/docs/concepts/payment-providers.mdx b/apps/web/content/docs/concepts/payment-providers.mdx index cf61106f..06c8d01f 100644 --- a/apps/web/content/docs/concepts/payment-providers.mdx +++ b/apps/web/content/docs/concepts/payment-providers.mdx @@ -23,8 +23,6 @@ export const paykit = createPayKit({ Stripe covers subscriptions, usage-based billing, webhooks, and product syncing out of the box. -See the [Stripe provider page](/docs/providers/stripe) for full setup instructions, webhook configuration, and available options. - ## Stripe IDs stay internal Your app identifies customers and plans with its own IDs. PayKit maps them to Stripe customer IDs, product IDs, and price IDs internally. You never store or reference Stripe IDs in your app code. diff --git a/apps/web/content/docs/get-started/quickstart.mdx b/apps/web/content/docs/get-started/quickstart.mdx index d9d77b9b..d2af549f 100644 --- a/apps/web/content/docs/get-started/quickstart.mdx +++ b/apps/web/content/docs/get-started/quickstart.mdx @@ -149,4 +149,4 @@ export const paykit = createPayKit({ - [Plans & Features](/docs/concepts/plans-and-features) - plan groups, defaults, and feature types - [Subscriptions](/docs/concepts/subscriptions) - upgrade, downgrade, and cancellation behavior - [Entitlements](/docs/concepts/entitlements) - access checks and metered usage -- [Stripe](/docs/providers/stripe) - provider configuration +- [Payment Providers](/docs/concepts/payment-providers) - Stripe configuration diff --git a/apps/web/content/docs/meta.json b/apps/web/content/docs/meta.json index 8bb3411d..e8de517d 100644 --- a/apps/web/content/docs/meta.json +++ b/apps/web/content/docs/meta.json @@ -7,8 +7,6 @@ "concepts", "---Flows---", "flows", - "---Providers---", - "providers", "---Plugins---", "plugins", "---Guides---", diff --git a/apps/web/content/docs/providers/meta.json b/apps/web/content/docs/providers/meta.json deleted file mode 100644 index a058739d..00000000 --- a/apps/web/content/docs/providers/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Providers", - "pages": ["stripe"] -} diff --git a/apps/web/content/docs/providers/stripe.mdx b/apps/web/content/docs/providers/stripe.mdx deleted file mode 100644 index a7e18b23..00000000 --- a/apps/web/content/docs/providers/stripe.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: Stripe -description: Configure Stripe for PayKit, set up webhooks, sync products, and use the customer portal. ---- - -Stripe is built into PayKit. PayKit handles Stripe API interactions, webhook processing, and product syncing. - -## Configuration - -Pass Stripe config to `createPayKit` with your secret key and webhook secret. - -```ts title="paykit.ts" -import { createPayKit } from "paykitjs"; - -export const paykit = createPayKit({ - // ... - stripe: { - secretKey: process.env.STRIPE_SECRET_KEY!, - webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, - }, -}); -``` - -## Environment variables - -Add these two variables to your `.env` file: - -```bash title=".env" -STRIPE_SECRET_KEY=sk_live_... -STRIPE_WEBHOOK_SECRET=whsec_... -``` - -- `STRIPE_SECRET_KEY`: find this in [Stripe Dashboard](https://dashboard.stripe.com) under **Developers > API keys**. -- `STRIPE_WEBHOOK_SECRET`: generated when you create a webhook endpoint. See the section below. - -## Webhook setup - -In the Stripe Dashboard, go to **Developers > Webhooks** and create a new endpoint pointing to: - -``` -https://your-app.com/paykit/webhook -``` - -Select the following events when creating the endpoint: - -- `checkout.session.completed` -- `customer.subscription.created` -- `customer.subscription.updated` -- `customer.subscription.deleted` -- `invoice.created` -- `invoice.finalized` -- `invoice.paid` -- `invoice.payment_failed` -- `invoice.updated` -- `payment_method.detached` - - - Stripe discourages selecting all events as it may cause performance issues. Only the events listed above are required by PayKit. - - -After saving, Stripe displays the signing secret. Copy it as your `STRIPE_WEBHOOK_SECRET`. - -## Local development - -Use the Stripe CLI to forward webhook events to your local server: - -```bash -stripe listen --forward-to localhost:3000/paykit/webhook -``` - -The CLI prints a webhook signing secret at startup. Use that as `STRIPE_WEBHOOK_SECRET` in your local `.env`. - - - Install the Stripe CLI from [stripe.com/docs/stripe-cli](https://stripe.com/docs/stripe-cli). You'll need to run `stripe login` once to authenticate. - - -## Product syncing - -`paykitjs push` creates and updates Stripe products and prices to match your plan definitions. You don't need to touch the Stripe Dashboard for product management. - - - - - Run this once on setup, and again every time you change your plans or pricing. - - -## Customer portal - -PayKit can open Stripe's built-in customer portal so users can manage payment methods, invoices, and subscriptions. - - - - ```ts - const { url } = await paykit.customerPortal({ - customerId: "user_123", - returnUrl: "https://myapp.com/billing", - }); - - // redirect the user to `url` - ``` - - - ```ts - const { url } = await paykitClient.customerPortal({ - returnUrl: window.location.href, - }); - - window.location.href = url; - ``` - - - -The portal is hosted by Stripe, so no additional UI work is needed on your end. - -## Testing mode - -Enable `testing` on your PayKit instance to use Stripe test clocks during development. This lets you simulate time-based billing events like renewals and trial expirations. - -```ts title="paykit.ts" -export const paykit = createPayKit({ - // ... - testing: { - enabled: true, - }, -}); -``` - - - Use your Stripe test mode keys (`sk_test_...`) when testing. Test mode and live mode are completely isolated in Stripe. - - -## API version - -PayKit pins the Stripe SDK to a known-good API version so upstream changes don't silently break your integration. Override it with `apiVersion` if you need a newer version, for example to opt into a preview feature. - -```ts title="paykit.ts" -export const paykit = createPayKit({ - // ... - stripe: { - secretKey: process.env.STRIPE_SECRET_KEY!, - webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, - apiVersion: "2026-03-04.preview", - }, -}); -``` - -The pinned default is exported as `PAYKIT_STRIPE_API_VERSION` if you want to reference it in code. - -## Managed Payments - -Stripe Managed Payments is a preview feature where Stripe takes over tax calculation, payment method selection, and billing address collection on subscription checkout sessions. Enable it with `managedPayments: true`, and set `apiVersion` to the preview version that supports it. - -```ts title="paykit.ts" -export const paykit = createPayKit({ - // ... - stripe: { - secretKey: process.env.STRIPE_SECRET_KEY!, - webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, - apiVersion: "2026-03-04.preview", - managedPayments: true, - }, -}); -``` - - - Managed Payments is a Stripe preview feature and the API version required may change. Review the [Stripe Managed Payments docs](https://docs.stripe.com/payments/managed-payments) before enabling in production. Note: digital products only, no shipping, and several Checkout parameters (`automatic_tax`, `payment_method_types`, Connect fields) are not supported in this mode. - diff --git a/apps/web/content/drafts/docs-index.mdx b/apps/web/content/drafts/docs-index.mdx index 97f7e4a7..1b0f2c26 100644 --- a/apps/web/content/drafts/docs-index.mdx +++ b/apps/web/content/drafts/docs-index.mdx @@ -34,8 +34,8 @@ Subscriptions are intentionally **not** the core docs story right now. - [Code](/docs/code/database) The local billing-state model plus the MVP APIs for checkout, customers, payment methods, charges, and webhooks. -- [Providers](/docs/providers/stripe) - Provider-specific setup notes and current integration status. +- [Payment Providers](/docs/concepts/payment-providers) + Stripe setup notes and current integration status. - [Code](/docs/code/sdks/server-sdk) The planned server SDK, future React SDK direction, and framework handler examples. From 5bc51109c55c1ab232d31d1d012ca3b9c01c8c64 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 02:28:21 +0400 Subject: [PATCH 05/76] Add Aura Shiki theme --- .../src/lib/shiki-themes/shiki-aura-theme.ts | 336 ++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 apps/web/src/lib/shiki-themes/shiki-aura-theme.ts diff --git a/apps/web/src/lib/shiki-themes/shiki-aura-theme.ts b/apps/web/src/lib/shiki-themes/shiki-aura-theme.ts new file mode 100644 index 00000000..c752885e --- /dev/null +++ b/apps/web/src/lib/shiki-themes/shiki-aura-theme.ts @@ -0,0 +1,336 @@ +// NOTE: This theme is intentionally kept as a local Shiki theme because Aura is +// not bundled with Shiki. Source: https://github.com/daltonmenezes/aura-theme + +import type { ThemeRegistrationRaw } from "shiki"; + +/** + * Aura Dark theme for Shiki, converted from the official VS Code theme. + * @see https://github.com/daltonmenezes/aura-theme + */ +const auraDark: ThemeRegistrationRaw = { + name: "aura-dark", + type: "dark", + colors: { + focusBorder: "#a394f033", + foreground: "#edecee", + errorForeground: "#ff6767", + "widget.shadow": "#0f0f0f", + "selection.background": "#3d375e7f", + "titleBar.activeBackground": "#121016", + "titleBar.border": "#000000", + "titleBar.inactiveBackground": "#2d2b38", + "statusBar.background": "#121016", + "statusBar.foreground": "#adacae", + "statusBar.border": "#000000", + "statusBar.debuggingForeground": "#15141b", + "statusBar.debuggingBackground": "#a19c77", + "statusBarItem.activeBackground": "#a277ff", + "dropdown.background": "#15141b", + "dropdown.border": "#3b334b", + "dropdown.foreground": "#cdccce", + "input.background": "#15141b", + "input.border": "#3b334b", + "input.foreground": "#cdccce", + "input.placeholderForeground": "#af8aff7f", + "inputOption.activeBorder": "#a277ff", + "button.background": "#61ffca", + "button.foreground": "#15141b", + "button.hoverBackground": "#49c29a", + "list.activeSelectionBackground": "#2e2b38", + "list.activeSelectionForeground": "#a277ff", + "list.focusBackground": "#3b334b", + "list.focusForeground": "#a277ff", + "list.highlightForeground": "#ffca85", + "list.hoverBackground": "#3b334b", + "list.hoverForeground": "#edecee", + "list.inactiveSelectionBackground": "#2e2b38", + "list.inactiveSelectionForeground": "#a277ff", + "editor.background": "#15141b", + "editor.foreground": "#edecee", + "editorLineNumber.foreground": "#a394f033", + "editorIndentGuide.activeBackground": "#6d6d6d", + "editorCursor.foreground": "#a277ff", + "editor.selectionBackground": "#3d375e7f", + "editor.selectionHighlightBackground": "#3d375e7f", + "editor.inactiveSelectionBackground": "#3d375e7f", + "editor.wordHighlightBackground": "#3d375e7f", + "editor.wordHighlightStrongBackground": "#3d375e7f", + "editor.findMatchBackground": "#3d375e7f", + "editor.findMatchHighlightBackground": "#3d375e7f", + "editor.findRangeHighlightBackground": "#3d375e7f", + "editor.lineHighlightBackground": "#a394f033", + "editor.lineHighlightBorder": "#a394f000", + "editor.stackFrameHighlightBackground": "#353424", + "editorInlayHint.background": "#2e2b38", + "editorInlayHint.foreground": "#cdccce", + "editorLink.activeForeground": "#a277ff", + "editorWhitespace.foreground": "#2d2d2d", + "editorIndentGuide.background": "#2d2d2d", + "editorBracketMatch.border": "#a277ff", + "editorError.foreground": "#ff6767", + "editorError.border": "#ffffff00", + "editorWarning.foreground": "#ffca85", + "editorWarning.border": "#ffffff00", + "editorGutter.modifiedBackground": "#ffca85", + "editorGutter.addedBackground": "#61ffca", + "editorGutter.deletedBackground": "#ff6767", + "editorWidget.background": "#121016", + "editorWidget.border": "#2d2d2d", + "editorSuggestWidget.background": "#121016", + "editorSuggestWidget.border": "#2d2d2d", + "editorSuggestWidget.foreground": "#cdccce", + "editorSuggestWidget.highlightForeground": "#61ffca", + "editorSuggestWidget.selectedBackground": "#4d4d4d", + "editorHoverWidget.background": "#121016", + "editorHoverWidget.border": "#2d2d2d", + "editorGroup.border": "#000000", + "editorGroup.dropBackground": "#3d375e7f", + "editorGroupHeader.tabsBackground": "#15141b", + "editorGroupHeader.tabsBorder": "#000000", + "tab.activeBackground": "#00000000", + "tab.activeForeground": "#61ffca", + "tab.border": "#000000", + "tab.inactiveBackground": "#15141b", + "tab.inactiveForeground": "#6d6d6d", + "tab.activeBorderTop": "#61ffca", + "panel.border": "#000000", + "panelTitle.activeBorder": "#61ffca", + "panelTitle.activeForeground": "#cdccce", + "activityBar.background": "#15141b", + "activityBar.foreground": "#61ffca", + "activityBar.inactiveForeground": "#525156", + "activityBar.border": "#000000", + "activityBarBadge.background": "#a277ff", + "activityBarBadge.foreground": "#15141b", + "activityBar.activeBorder": "#a277ff", + "badge.foreground": "#15141b", + "badge.background": "#a277ff", + "sideBar.background": "#110f18", + "sideBar.foreground": "#cdccce", + "sideBar.border": "#000000", + "sideBarTitle.foreground": "#adacae", + "sideBarSectionHeader.background": "#15141b", + "sideBarSectionHeader.foreground": "#adacae", + "progressBar.background": "#61ffca", + "scrollbar.shadow": "#15141b", + "scrollbarSlider.activeBackground": "#3d375e7f", + "scrollbarSlider.background": "#a394f033", + "scrollbarSlider.hoverBackground": "#a394f033", + "terminal.background": "#15141b", + "terminal.foreground": "#cdccce", + "terminal.ansiBlack": "#15141b", + "terminal.ansiBlue": "#a277ff", + "terminal.ansiBrightBlack": "#2d2d2d", + "terminal.ansiBrightBlue": "#a277ff", + "terminal.ansiBrightCyan": "#61ffca", + "terminal.ansiBrightGreen": "#a277ff", + "terminal.ansiBrightMagenta": "#61ffca", + "terminal.ansiBrightRed": "#ffca85", + "terminal.ansiBrightWhite": "#edecee", + "terminal.ansiBrightYellow": "#ffca85", + "terminal.ansiCyan": "#a277ff", + "terminal.ansiGreen": "#61ffca", + "terminal.ansiMagenta": "#61ffca", + "terminal.ansiRed": "#ff6767", + "terminal.ansiWhite": "#cdccce", + "terminal.ansiYellow": "#ffca85", + "terminal.selectionBackground": "#3d375e7f", + "terminalCursor.background": "#2d2d2d", + "terminalCursor.foreground": "#adacae", + "gitDecoration.modifiedResourceForeground": "#ffca85", + "gitDecoration.deletedResourceForeground": "#ff6767", + "gitDecoration.untrackedResourceForeground": "#61ffca", + "gitDecoration.ignoredResourceForeground": "#4d4d4d", + "gitDecoration.conflictingResourceForeground": "#a277ff", + "diffEditor.insertedTextBackground": "#00d89023", + "diffEditor.removedTextBackground": "#ff474720", + "tree.indentGuidesStroke": "#4d4d4d", + }, + settings: [ + { + name: "Accent1", + scope: [ + "keyword", + "storage", + "support", + "entity.name.tag", + "variable.language", + "keyword.control.flow", + "storage.modifier", + "keyword.operator", + "entity.other.attribute-name.class.css", + "entity.other.keyframe-offset", + "markup.heading", + "markup.underline.link", + "variable.other.env", + "punctuation.definition.list.begin.markdown", + "punctuation.definition.bold.markdown", + "punctuation.definition.italic.markdown", + "punctuation.definition.markdown", + "punctuation.definition.quote.begin.markdown", + "punctuation.definition.raw.markdown", + "constant.length.units.css", + "constant.percentage.units.css", + ], + settings: { + foreground: "#a277ff", + }, + }, + { + name: "Accent2", + scope: [ + "string", + "markup.inserted", + "markup.raw", + "constant", + "source.env", + "support.type.builtin.graphql", + "variable.other.quoted.double", + "markup.inline.raw.string.markdown", + "entity.other.attribute-name.id.css", + "JSXNested", + ], + settings: { + foreground: "#61ffca", + }, + }, + { + name: "Accent3", + scope: [ + "markup.changed", + "entity", + "entity.name.function", + "entity.name.function.elixir", + "entity.name.function-call.elixir", + "support.class.component.tsx", + "support.class.component.open.jsx", + "support.class.component.close.jsx", + "meta.function-call.generic.python", + "entity.name.section.markdown", + "storage.type.annotation.dart", + ], + settings: { + foreground: "#ffca85", + }, + }, + { + name: "Accent5", + scope: ["invalid", "markup.deleted"], + settings: { + foreground: "#ff6767", + }, + }, + { + name: "Accent6", + scope: [ + "string.unquoted", + "punctuation.separator", + "entity.other.attribute-name", + "meta.object-literal.key", + "variable.object.property", + "variable.other.property", + "variable.other.object.property", + "variable.other.constant.property", + "meta.type.annotation", + "support.type.property-name.css", + "support.type.vendored", + "constant.language.symbol.elixir", + "variable.graphql", + "meta.attribute.python", + "source.dart", + ], + settings: { + foreground: "#f694ff", + }, + }, + { + name: "Accent7", + scope: [ + "variable", + "markup.list", + "support.constant.property-value.css", + "variable.parameter.keyframe-list.css", + "source.css", + "support.constant.font-name", + "support.constant.vendored.property-value", + "variable.parameter", + "meta.class", + "meta.method.declaration", + "parameter.variable.function.elixir", + "punctuation.definition.tag", + "punctuation.section.embedded", + "meta.embedded.expression", + "punctuation.terminator.dart", + "punctuation.dot.dart", + "meta.jsx.children", + ], + settings: { + foreground: "#edecee", + }, + }, + { + name: "Accent8", + scope: ["comment", "string.quoted.docstring.multi.python"], + settings: { + foreground: "#6d6d6d", + }, + }, + { + name: "Accent31", + scope: ["entity.name.function", "support.function"], + settings: { + foreground: "#ffca85", + }, + }, + { + name: "Accent32", + scope: [ + "entity.name.type", + "entity.name.class", + "support.class.builtin", + "punctuation.definition.template-expression.begin", + "punctuation.definition.template-expression.end", + "punctuation.quasi.element.begin", + "punctuation.quasi.element.end", + "entity.other.inherited-class", + "variable.other.constant.elixir", + "entity.other.attribute-name.class.css", + "support.class.dart", + ], + settings: { + foreground: "#82e2ff", + }, + }, + { + name: "Italics", + scope: [ + "meta.parameters", + "meta.type.parameters", + "meta.return.type", + "entity.name.type.interface", + "meta.type.annotation", + "meta.function.parameters", + "markup.italic.markdown", + ], + settings: { + fontStyle: "italic", + }, + }, + { + name: "Markup Underline", + scope: "markup.underline", + settings: { + fontStyle: "underline", + }, + }, + { + name: "Bold", + scope: ["markup.bold.markdown", "storage.type.annotation.dart"], + settings: { + fontStyle: "bold", + }, + }, + ], +}; + +export { auraDark }; From 0dc15838323c3b717e52ec8690e4e550d1b3bb32 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 06:00:14 +0400 Subject: [PATCH 06/76] Add testimonials section components --- .../sections/testimonials-content.ts | 120 +++++++++++++ .../sections/testimonials-section.tsx | 159 ++++++++---------- 2 files changed, 187 insertions(+), 92 deletions(-) create mode 100644 apps/web/src/components/sections/testimonials-content.ts diff --git a/apps/web/src/components/sections/testimonials-content.ts b/apps/web/src/components/sections/testimonials-content.ts new file mode 100644 index 00000000..cd1c3047 --- /dev/null +++ b/apps/web/src/components/sections/testimonials-content.ts @@ -0,0 +1,120 @@ +export type Tweet = { + column: number; + name: string; + handle: string; + link: string; + avatar: string; + text: string; + checkmark: boolean; +}; + +export const tweets: Tweet[] = [ + { + column: 1, + name: "Guillermo Rauch", + handle: "rauchg", + link: "https://x.com/rauchg/status/2047218849754571200?s=20", + avatar: "https://pbs.twimg.com/profile_images/1783856060249595904/8TfcCN0r_200x200.jpg", + text: "👀", + checkmark: true, + }, + { + column: 1, + name: "Gruz", + handle: "damnGruz", + link: "https://x.com/damnGruz/status/2042264666135756991?s=20", + avatar: "https://pbs.twimg.com/profile_images/2008805464834973696/xjQGOfAs_200x200.jpg", + text: "sick!!! will try it", + checkmark: true, + }, + { + column: 2, + name: "Andrew Qu", + handle: "andrewqu", + link: "https://x.com/andrewqu/status/2057463195061948506?s=20", + avatar: "https://pbs.twimg.com/profile_images/1976812562143641600/e_E_wlXX_200x200.jpg", + text: "Paykit and opensec are too good", + checkmark: true, + }, + { + column: 4, + name: "Creem 🍦", + handle: "creem_io", + link: "https://x.com/creem_io/status/2042265241157857483?s=20", + avatar: "https://pbs.twimg.com/profile_images/2003816759975944192/3C1xR6B8_200x200.jpg", + text: "Looks amazing Max! 🙌", + checkmark: true, + }, + { + column: 2, + name: "Matteo Scotto", + handle: "442utopy", + link: "https://x.com/442utopy/status/2042500989660418128?s=20", + avatar: "https://pbs.twimg.com/profile_images/1898711224180674560/BrICyHKA_200x200.jpg", + text: "that looks amazing! Congrats for the launch", + checkmark: true, + }, + { + column: 2, + name: "Jonathan Wilke", + handle: "jonathan_wilke", + link: "https://x.com/jonathan_wilke/status/2042492766270234850?s=20", + avatar: "https://pbs.twimg.com/profile_images/1884529433979068416/AhfbeVEh_200x200.jpg", + text: "Honestly, this is probably the best lib project I have come across since better-auth.", + checkmark: true, + }, + { + column: 4, + name: "jan", + handle: "miaugladiator1", + link: "https://x.com/miaugladiator1/status/2039394313059086710?s=20", + avatar: "https://pbs.twimg.com/profile_images/2053193399180705794/7IMR_hhx_200x200.jpg", + text: "just saw paykit and it looks actually soooo cool have to try this out asap", + checkmark: true, + }, + { + column: 1, + name: "jordi", + handle: "jordienr", + link: "https://x.com/jordienr/status/2039374608286007503?s=20", + avatar: "https://pbs.twimg.com/profile_images/2053541405121769475/TUDez6zL_200x200.jpg", + text: "paykit looks very interesting, like a really good abstraction without lock in", + checkmark: true, + }, + { + column: 3, + name: "Lasse", + handle: "lassejv", + link: "https://x.com/lassejv/status/2042902834509656507?s=20", + avatar: "https://pbs.twimg.com/profile_images/2056849088126070784/MCWM6EuB_200x200.jpg", + text: "Holy shit paykit by @maxktz is really good.", + checkmark: true, + }, + { + column: 3, + name: "lakshmi", + handle: "simhskal", + link: "https://x.com/simhskal/status/2042818621492334663?s=20", + avatar: "https://pbs.twimg.com/profile_images/1997855512210427904/Spg8avde_200x200.jpg", + text: "very cool", + checkmark: true, + }, + { + column: 3, + name: "Leo", + handle: "leodev", + link: "https://x.com/leodev/status/2052489939292499986?s=20", + avatar: "https://pbs.twimg.com/profile_images/2060684155013201929/n2cPRDs7_200x200.jpg", + text: "You should check it out, really cool billing framework", + checkmark: true, + }, + { + column: 4, + name: "Saïd Aitmbarek", + handle: "SaidAitmbarek", + link: "https://x.com/SaidAitmbarek/status/2042568317169193320?s=20", + avatar: "https://pbs.twimg.com/profile_images/1891564978177454080/YzRSDzkw_200x200.jpg", + text: "Gotta try this one, brilliant work mate.", + checkmark: true, + }, +]; diff --git a/apps/web/src/components/sections/testimonials-section.tsx b/apps/web/src/components/sections/testimonials-section.tsx index dc678477..cc501dec 100644 --- a/apps/web/src/components/sections/testimonials-section.tsx +++ b/apps/web/src/components/sections/testimonials-section.tsx @@ -1,112 +1,87 @@ -import { Icons } from "@/components/icons"; import { Section, SectionContent } from "@/components/layout/section"; -import { cn } from "@/lib/utils"; +import { tweets } from "@/components/sections/testimonials-content"; +import type { Tweet } from "@/components/sections/testimonials-content"; -const testimonials = [ - { - handle: "@alexdev", - avatar: "/testimonials/placeholder-1.png", - text: "Just integrated PayKit into our SaaS. Went from zero billing to subscriptions + usage limits in under an hour. The DX is insane.", - }, - { - handle: "@sarahbuilds", - avatar: "/testimonials/placeholder-2.png", - text: "PayKit replaced 800 lines of Stripe webhook code with a single subscribe() call. I'm never going back.", - }, - { - handle: "@marcuseng", - avatar: "/testimonials/placeholder-3.png", - text: "The fact that billing state lives in my own Postgres and I can just JOIN it with my tables is a game changer.", - }, - { - handle: "@devpriya", - avatar: "/testimonials/placeholder-4.png", - text: "We switched from Stripe's raw API to PayKit. Took 30 minutes. Our billing code went from 3 files to 1.", - }, - { - handle: "@joshcodes", - avatar: "/testimonials/placeholder-5.png", - text: "check() and report() for usage billing is exactly what I needed. No more custom middleware to gate features.", - }, - { - handle: "@emmaoss", - avatar: "/testimonials/placeholder-6.png", - text: "Open source billing that actually works. No vendor lock-in, no separate dashboard, just npm install and go.", - }, - { - handle: "@ryanships", - avatar: "/testimonials/placeholder-7.png", - text: "The type safety is incredible. Typo a plan ID and TypeScript catches it before you even run the code.", - }, - { - handle: "@linadev", - avatar: "/testimonials/placeholder-8.png", - text: "PayKit feels like what Stripe should have been for framework developers. Simple, embedded, type-safe.", - }, -]; +const columns = [1, 2, 3, 4].map((column) => tweets.filter((tweet) => tweet.column === column)); -// Split into 3 columns for masonry layout -const columns = [ - testimonials.filter((_, i) => i % 3 === 0), - testimonials.filter((_, i) => i % 3 === 1), - testimonials.filter((_, i) => i % 3 === 2), -]; +function VerifiedIcon() { + return ( + + + + + ); +} -function TestimonialCard({ handle, text }: { handle: string; avatar: string; text: string }) { +function TweetCard({ tweet }: { tweet: Tweet }) { return ( -
-
-
-
-
- - {handle} +
+ + View tweet by {tweet.name} + +
+ + {`${tweet.name}'s + +
+
+ {tweet.name} + {tweet.checkmark && }
-
-

{text}

+ + @{tweet.handle} + + +
+
+

{tweet.text}

-
+ ); } export function TestimonialsSection() { return (
- -
-

- Loved by developers + +
+

+ Feedback

-

- See what developers are saying about PayKit. -

- - {/* Masonry columns with fade at edges */} -
-
-
- {columns.map((column, colIdx) => ( -
- {column.map((testimonial) => ( - - ))} -
- ))} -
+
+
+ +
+
+ {columns.map((column, columnIndex) => ( +
+ {column.map((tweet) => ( + + ))} +
+ ))} +
+
+

); } From a1a4878eb67214f75ac8801e4717519479781434 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 06:23:34 +0400 Subject: [PATCH 07/76] chore: update DESIGN.md --- dev/{UI_DESIGN.md => DESIGN.md} | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) rename dev/{UI_DESIGN.md => DESIGN.md} (95%) diff --git a/dev/UI_DESIGN.md b/dev/DESIGN.md similarity index 95% rename from dev/UI_DESIGN.md rename to dev/DESIGN.md index 3a4735b7..24411d75 100644 --- a/dev/UI_DESIGN.md +++ b/dev/DESIGN.md @@ -1,6 +1,13 @@ # UI Design Principles -## Design References +## PayKit's Style + +https://efferd.com/view/dashboard-9 +https://efferd.com/view/auth-2 +https://efferd.com/view/auth-4 +https://efferd.com/view/auth-12 + +## Other References These are web pages we admire and draw inspiration from. We don't copy any of them directly — PayKit has its own identity. Use these as a reference for quality, tone, and craft. From 347e1dccb9c177a2391a81fb727b9d058b41153d Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 06:23:43 +0400 Subject: [PATCH 08/76] chore: update theme --- apps/web/src/styles/globals.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css index 74e99938..548e3dde 100644 --- a/apps/web/src/styles/globals.css +++ b/apps/web/src/styles/globals.css @@ -141,9 +141,9 @@ } .dark { - --background: #0a0a0a; + --background: #070707; --foreground: #f5f5f5; - --card: #0a0a0a; + --card: #070707; --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); From 8a067fc1bbd04ac06ef672f89621f651c5372643 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 08:46:04 +0400 Subject: [PATCH 09/76] chore: update version text in docs --- .../sections/{testimonials-content.ts => feedback-content.ts} | 0 .../sections/{testimonials-section.tsx => feedback-section.tsx} | 0 apps/web/src/lib/consts.ts | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename apps/web/src/components/sections/{testimonials-content.ts => feedback-content.ts} (100%) rename apps/web/src/components/sections/{testimonials-section.tsx => feedback-section.tsx} (100%) diff --git a/apps/web/src/components/sections/testimonials-content.ts b/apps/web/src/components/sections/feedback-content.ts similarity index 100% rename from apps/web/src/components/sections/testimonials-content.ts rename to apps/web/src/components/sections/feedback-content.ts diff --git a/apps/web/src/components/sections/testimonials-section.tsx b/apps/web/src/components/sections/feedback-section.tsx similarity index 100% rename from apps/web/src/components/sections/testimonials-section.tsx rename to apps/web/src/components/sections/feedback-section.tsx diff --git a/apps/web/src/lib/consts.ts b/apps/web/src/lib/consts.ts index 8065ac03..a472932d 100644 --- a/apps/web/src/lib/consts.ts +++ b/apps/web/src/lib/consts.ts @@ -23,7 +23,7 @@ export const URLs = { authorX: "https://x.com/maxktz", } as const; -export const VERSION_TEXT = "v0.1 beta"; +export const VERSION_TEXT = "v0.2"; export const websiteSchema: WithContext = { "@context": "https://schema.org", From 53b05d0d4b5654cb484875a5f5ec999b2e795817 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 08:46:40 +0400 Subject: [PATCH 10/76] Refine button pressed state --- apps/web/src/components/ui/button.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/ui/button.tsx b/apps/web/src/components/ui/button.tsx index 4d891bbe..35a66ab2 100644 --- a/apps/web/src/components/ui/button.tsx +++ b/apps/web/src/components/ui/button.tsx @@ -6,7 +6,7 @@ import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils"; const buttonVariants = cva( - "group/button inline-flex shrink-0 items-center justify-center rounded-sm bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + "group/button inline-flex shrink-0 items-center justify-center rounded-sm bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:scale-[0.99] disabled:pointer-events-none disabled:opacity-50 aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", { variants: { variant: { From 0474a6da520203427224706464f44f7dd37623cf Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 09:58:03 +0400 Subject: [PATCH 11/76] Update docs copy page actions --- apps/web/src/app/docs/[[...slug]]/page.tsx | 6 +-- .../components/docs/copy-markdown-button.tsx | 45 ++++++++++++++++--- apps/web/src/components/ui/button-group.tsx | 4 +- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/apps/web/src/app/docs/[[...slug]]/page.tsx b/apps/web/src/app/docs/[[...slug]]/page.tsx index 09cc1f89..2d62f3fd 100644 --- a/apps/web/src/app/docs/[[...slug]]/page.tsx +++ b/apps/web/src/app/docs/[[...slug]]/page.tsx @@ -53,11 +53,11 @@ export default async function Page({ params }: DocsPageProps) { style: "clerk", }} > - {page.data.title} - {page.data.description} -
+
+ {page.data.title}
+ {page.data.description} - {copied ? : } - {copied ? "Copied" : "Copy Markdown"} - + + + + + } + > + + + + }> + + View as markdown + + }> + + View llms.txt + + } + > + + View llms-full.txt + + + + ); } diff --git a/apps/web/src/components/ui/button-group.tsx b/apps/web/src/components/ui/button-group.tsx index 2588d5b9..14e925cb 100644 --- a/apps/web/src/components/ui/button-group.tsx +++ b/apps/web/src/components/ui/button-group.tsx @@ -11,9 +11,9 @@ const buttonGroupVariants = cva( variants: { orientation: { horizontal: - "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0", + "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-sm! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0 [&>[data-slot]~[data-slot]]:after:border-l-0", vertical: - "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0", + "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-sm! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0 [&>[data-slot]~[data-slot]]:after:border-t-0", }, }, defaultVariants: { From e2e57d387640ef50d927e2de5b70f041775968ca Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:00:15 +0400 Subject: [PATCH 12/76] Update site navigation and section chrome --- apps/web/next.config.js | 1 + .../(marketing)/{donate => sponsor}/page.tsx | 12 +++--- apps/web/src/app/docs/layout.tsx | 5 +-- .../src/components/layout/mini-nav-bar.tsx | 7 +++- .../src/components/layout/navigation-bar.tsx | 37 +++++++++++-------- apps/web/src/components/layout/section.tsx | 6 +-- 6 files changed, 37 insertions(+), 31 deletions(-) rename apps/web/src/app/(marketing)/{donate => sponsor}/page.tsx (85%) diff --git a/apps/web/next.config.js b/apps/web/next.config.js index fa766063..a441df9b 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -43,6 +43,7 @@ const config = { destination: "https://github.com/orgs/getpaykit/projects/1", permanent: false, }, + { source: "/donate", destination: "/sponsor", permanent: true }, ], }; diff --git a/apps/web/src/app/(marketing)/donate/page.tsx b/apps/web/src/app/(marketing)/sponsor/page.tsx similarity index 85% rename from apps/web/src/app/(marketing)/donate/page.tsx rename to apps/web/src/app/(marketing)/sponsor/page.tsx index f428400f..156ec741 100644 --- a/apps/web/src/app/(marketing)/donate/page.tsx +++ b/apps/web/src/app/(marketing)/sponsor/page.tsx @@ -4,20 +4,20 @@ import Link from "next/link"; import { Section, SectionContent } from "@/components/layout/section"; import { FooterSection } from "@/components/sections/footer-section"; -const donateUrl = "https://opencollective.com/maxktz"; +const sponsorUrl = "https://opencollective.com/maxktz"; export const metadata: Metadata = { - title: "Donate", + title: "Sponsor", description: "Support PayKit development through Open Collective.", alternates: { - canonical: "/donate", + canonical: "/sponsor", }, }; -export default function DonatePage() { +export default function SponsorPage() { return (
- +
@@ -34,7 +34,7 @@ export default function DonatePage() {
Continue to Open Collective diff --git a/apps/web/src/app/docs/layout.tsx b/apps/web/src/app/docs/layout.tsx index 8e7f6024..4bc17730 100644 --- a/apps/web/src/app/docs/layout.tsx +++ b/apps/web/src/app/docs/layout.tsx @@ -182,10 +182,7 @@ export default function Layout({ children }: { children: ReactNode }) {
{VERSION_TEXT && ( - + {VERSION_TEXT} )} diff --git a/apps/web/src/components/layout/mini-nav-bar.tsx b/apps/web/src/components/layout/mini-nav-bar.tsx index daca93e8..8aea6652 100644 --- a/apps/web/src/components/layout/mini-nav-bar.tsx +++ b/apps/web/src/components/layout/mini-nav-bar.tsx @@ -16,7 +16,10 @@ export function MiniNavBar() { className="bg-background border-border pointer-events-auto w-full border-b lg:hidden" > - + @@ -28,7 +31,7 @@ export function MiniNavBar() { >
- +
diff --git a/apps/web/src/components/layout/navigation-bar.tsx b/apps/web/src/components/layout/navigation-bar.tsx index fa5c5434..3570fa3e 100644 --- a/apps/web/src/components/layout/navigation-bar.tsx +++ b/apps/web/src/components/layout/navigation-bar.tsx @@ -1,10 +1,11 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { ChevronDown, ExternalLink, Github, Menu, X } from "lucide-react"; +import { ChevronDown, ExternalLink, Menu, X } from "lucide-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useCallback, useEffect, useRef, useState } from "react"; +import { FaGithub } from "react-icons/fa"; import { SectionShell } from "@/components/layout/section"; import { Button } from "@/components/ui/button"; @@ -49,15 +50,15 @@ function NavLink({ // ─── Data ──────────────────────────────────────────────────────────── const navTabs: NavItem[] = [ - { name: "readme", href: "/" }, { name: "docs", href: "/docs", path: "/docs" }, + { name: "blog", href: "/blog", path: "/blog" }, + { name: "sponsors", href: "/sponsor", path: "/sponsor" }, ]; const dropdownLinks: NavItem[] = [ { name: "Discord", href: URLs.discord, external: true }, { name: "Twitter / X", href: URLs.x, external: true }, { name: "LinkedIn", href: URLs.linkedin, external: true }, - { name: "Donate", href: "/donate", external: true }, { name: "llms.txt", href: "/llms.txt", external: true }, ]; @@ -69,8 +70,8 @@ const mobileLinks: NavItem[] = [ // ─── Tab styles ────────────────────────────────────────────────────── const tabBase = - "group/tab relative flex h-full items-center justify-center gap-1.5 px-5.5 py-3.5 transition-colors duration-150"; -const tabActive = "bg-background border-b-2 border-b-foreground/60"; + "group/tab relative flex h-full items-center justify-center gap-1.5 px-4 py-3.5 transition-colors duration-150"; +const tabActive = "bg-background"; const tabInactive = "hover:bg-foreground/[0.03] bg-transparent text-foreground/60 dark:text-foreground/40 hover:text-foreground/70"; const labelBase = @@ -109,10 +110,13 @@ export function NavigationBar({ stars: _stars }: { stars: number | null }) { initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.28, ease: "easeOut" }} - className="bg-background border-border pointer-events-auto w-full border-b lg:hidden" + className="bg-background pointer-events-auto w-full lg:hidden" > - - + +
@@ -252,7 +257,7 @@ export function NavigationBar({ stars: _stars }: { stars: number | null }) { > setMobileMenuOpen(false)} diff --git a/apps/web/src/components/layout/section.tsx b/apps/web/src/components/layout/section.tsx index 9afc79d7..90ebd72d 100644 --- a/apps/web/src/components/layout/section.tsx +++ b/apps/web/src/components/layout/section.tsx @@ -45,7 +45,7 @@ export function Section({ return ( {!last && ( -
+
)} @@ -66,11 +66,11 @@ export function SectionContent({ return
{children}
; } -// ─── SectionSeparator (full viewport-width solid line) ─────────────── +// ─── SectionSeparator ──────────────────────────────────────────────── export function SectionSeparator() { return ( -
+
); From 47b032476e7af5a71d2e149531fd651a8b133c1f Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:00:31 +0400 Subject: [PATCH 13/76] Refine marketing hero --- .../sections/readme-code-content.ts | 4 +- apps/web/src/components/ui/frame-corners.tsx | 12 ++ .../src/components/web/hero-code-block.tsx | 117 +++++++++--------- apps/web/src/components/web/hero-title.tsx | 56 ++------- 4 files changed, 85 insertions(+), 104 deletions(-) create mode 100644 apps/web/src/components/ui/frame-corners.tsx diff --git a/apps/web/src/components/sections/readme-code-content.ts b/apps/web/src/components/sections/readme-code-content.ts index 28f27686..5224440c 100644 --- a/apps/web/src/components/sections/readme-code-content.ts +++ b/apps/web/src/components/sections/readme-code-content.ts @@ -26,14 +26,14 @@ export const heroConfigCode = `import { createPayKit } from "paykitjs" import { free, pro } from "./products" export const paykit = createPayKit({ + database: env.DATABASE_URL, stripe: { secretKey: env.STRIPE_SECRET_KEY, webhookSecret: env.STRIPE_WEBHOOK_SECRET, }, - database: env.DATABASE_URL, products: [free, pro], on: { - "subscription.activated": async ({ customer, plan }) => { + "subscription.activated": async ({ customer, plan }) => { await sendEmail(customer.email, "Welcome to Pro!") }, } diff --git a/apps/web/src/components/ui/frame-corners.tsx b/apps/web/src/components/ui/frame-corners.tsx new file mode 100644 index 00000000..0855cc10 --- /dev/null +++ b/apps/web/src/components/ui/frame-corners.tsx @@ -0,0 +1,12 @@ +import { cn } from "@/lib/utils"; + +export function FrameCorners({ className }: { className?: string }) { + return ( + + ); +} diff --git a/apps/web/src/components/web/hero-code-block.tsx b/apps/web/src/components/web/hero-code-block.tsx index 01d355d9..f8524c86 100644 --- a/apps/web/src/components/web/hero-code-block.tsx +++ b/apps/web/src/components/web/hero-code-block.tsx @@ -1,11 +1,11 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { ChevronLeft, Loader2, Terminal } from "lucide-react"; +import { Loader2 } from "lucide-react"; import type { ReactNode } from "react"; import { useCallback, useState } from "react"; -import { Button } from "@/components/ui/button"; +import { FrameCorners } from "@/components/ui/frame-corners"; import { cn } from "@/lib/utils"; type View = "code" | "terminal"; @@ -133,75 +133,74 @@ export function HeroCodeBlock({ setPushing(false); }, [pushing]); - const backToCode = useCallback(() => { + const selectCodeTab = useCallback((tab: "plans" | "config") => { + setActiveTab(tab); setView("code"); - setTerminalLines([]); }, []); + const selectTerminalTab = useCallback(() => { + if (view === "terminal") return; + + void runPush(); + }, [runPush, view]); + return ( -
-
+
+ +
{/* Tab bar */}
- {view === "code" ? ( - <> - - - - ) : ( - Terminal - )} + + +
{/* Content — fixed height */}
- {/* Push / back button */} -
- -
{view === "code" ? ( <> diff --git a/apps/web/src/components/web/hero-title.tsx b/apps/web/src/components/web/hero-title.tsx index 1d9b7e5a..f164ba60 100644 --- a/apps/web/src/components/web/hero-title.tsx +++ b/apps/web/src/components/web/hero-title.tsx @@ -1,7 +1,7 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { Check, ChevronRight, Copy, Sparkle } from "lucide-react"; +import { Check, ChevronRight, Copy } from "lucide-react"; import Link from "next/link"; import { useCallback, useState } from "react"; @@ -19,22 +19,13 @@ export function HeroTitle() { return (
-
-
-
-

+
+

The billing framework
for TypeScript

-

+

Define plans and features in code. PayKit handles Stripe, webhooks, and usage state - runs inside your app.

@@ -44,41 +35,20 @@ export function HeroTitle() { render={} nativeButton={false} size="lg" - className="px-4 h-9.5" + className="h-9.5 px-5" variant="default" > Read Docs

From f66fb3e06ce0fcaf6cb37e010ed472f437f490ce Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:01:12 +0400 Subject: [PATCH 14/76] Refine marketing sections --- apps/web/src/components/docs/features.tsx | 21 +++--- .../src/components/sections/cta-section.tsx | 4 +- .../sections/demo/demo-app-window.tsx | 2 +- .../sections/demo/demo-backend-panel.tsx | 2 +- .../src/components/sections/demo/index.tsx | 68 +++++++++---------- .../components/sections/features-section.tsx | 18 ++--- .../components/sections/feedback-section.tsx | 18 ++--- 7 files changed, 63 insertions(+), 70 deletions(-) diff --git a/apps/web/src/components/docs/features.tsx b/apps/web/src/components/docs/features.tsx index ea0a9cdf..f052d972 100644 --- a/apps/web/src/components/docs/features.tsx +++ b/apps/web/src/components/docs/features.tsx @@ -13,6 +13,8 @@ import { } from "lucide-react"; import type { ReactNode } from "react"; +import { FrameCorners } from "@/components/ui/frame-corners"; + const features: { icon: ReactNode; title: string; description: string }[] = [ { icon: , @@ -67,18 +69,15 @@ export function Features() { {features.map((feature) => (
-
- - {feature.icon} - -
-

{feature.title}

-

- {feature.description} -

-
+ + + {feature.icon} + +
+

{feature.title}

+

{feature.description}

))} diff --git a/apps/web/src/components/sections/cta-section.tsx b/apps/web/src/components/sections/cta-section.tsx index ece27c93..24ce704d 100644 --- a/apps/web/src/components/sections/cta-section.tsx +++ b/apps/web/src/components/sections/cta-section.tsx @@ -22,10 +22,10 @@ export function CTASection() {
-

+

Ready to add billing?

-

+

One command to get started. Define your plans, connect Stripe, and ship billing in minutes.

diff --git a/apps/web/src/components/sections/demo/demo-app-window.tsx b/apps/web/src/components/sections/demo/demo-app-window.tsx index c57ac4d8..4b2e8621 100644 --- a/apps/web/src/components/sections/demo/demo-app-window.tsx +++ b/apps/web/src/components/sections/demo/demo-app-window.tsx @@ -21,7 +21,7 @@ function WindowChrome({ return (
diff --git a/apps/web/src/components/sections/demo/demo-backend-panel.tsx b/apps/web/src/components/sections/demo/demo-backend-panel.tsx index 8c53c1d0..92f466b5 100644 --- a/apps/web/src/components/sections/demo/demo-backend-panel.tsx +++ b/apps/web/src/components/sections/demo/demo-backend-panel.tsx @@ -21,7 +21,7 @@ export function DemoBackendPanel({ return (
diff --git a/apps/web/src/components/sections/demo/index.tsx b/apps/web/src/components/sections/demo/index.tsx index 0e20d417..726be565 100644 --- a/apps/web/src/components/sections/demo/index.tsx +++ b/apps/web/src/components/sections/demo/index.tsx @@ -294,49 +294,47 @@ export function DemoSection({ snippets }: { snippets: Record - +
-

+

How it works

-

- Click around the app below. Every interaction shows the PayKit code that runs and the - steps it orchestrates, in real time. -

+
+
-
- void handleUpgrade()} - onDowngrade={() => void handleDowngrade()} - onResubscribe={() => void handleResubscribe()} - onPortal={() => void handlePortal()} - /> -
- -
- -
+ void handleUpgrade()} + onDowngrade={() => void handleDowngrade()} + onResubscribe={() => void handleResubscribe()} + onPortal={() => void handlePortal()} + /> + +
diff --git a/apps/web/src/components/sections/features-section.tsx b/apps/web/src/components/sections/features-section.tsx index b995e894..ec45a5e2 100644 --- a/apps/web/src/components/sections/features-section.tsx +++ b/apps/web/src/components/sections/features-section.tsx @@ -51,18 +51,14 @@ export function FeaturesSection() { {features.map((feature) => (
-
- - {feature.icon} - -
-

{feature.title}

-

- {feature.description} -

-
+ + {feature.icon} + +
+

{feature.title}

+

{feature.description}

))} diff --git a/apps/web/src/components/sections/feedback-section.tsx b/apps/web/src/components/sections/feedback-section.tsx index cc501dec..f23c72e3 100644 --- a/apps/web/src/components/sections/feedback-section.tsx +++ b/apps/web/src/components/sections/feedback-section.tsx @@ -1,6 +1,6 @@ import { Section, SectionContent } from "@/components/layout/section"; -import { tweets } from "@/components/sections/testimonials-content"; -import type { Tweet } from "@/components/sections/testimonials-content"; +import { tweets } from "@/components/sections/feedback-content"; +import type { Tweet } from "@/components/sections/feedback-content"; const columns = [1, 2, 3, 4].map((column) => tweets.filter((tweet) => tweet.column === column)); @@ -9,7 +9,7 @@ function VerifiedIcon() { +
{tweet.name} {tweet.checkmark && }
- + @{tweet.handle}
-
+

{tweet.text}

); } -export function TestimonialsSection() { +export function FeedbackSection() { return (
@@ -70,7 +70,7 @@ export function TestimonialsSection() {
-
+
{columns.map((column, columnIndex) => (
@@ -80,7 +80,7 @@ export function TestimonialsSection() {
))}
-
+
); From 9b628b2089188cb934d729fac28ad138a627f396 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:01:28 +0400 Subject: [PATCH 15/76] Update homepage feedback content --- apps/web/content/docs/get-started/index.mdx | 2 -- apps/web/src/app/(marketing)/page.tsx | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/web/content/docs/get-started/index.mdx b/apps/web/content/docs/get-started/index.mdx index 3ebffd07..336ff731 100644 --- a/apps/web/content/docs/get-started/index.mdx +++ b/apps/web/content/docs/get-started/index.mdx @@ -10,5 +10,3 @@ PayKit is an embedded Stripe billing framework for TypeScript apps. It provides PayKit aims to be a complete billing framework. It provides a wide range of features out of the box and allows you to extend it with plugins. - -...and more to come! diff --git a/apps/web/src/app/(marketing)/page.tsx b/apps/web/src/app/(marketing)/page.tsx index e648b2ee..95b4819c 100644 --- a/apps/web/src/app/(marketing)/page.tsx +++ b/apps/web/src/app/(marketing)/page.tsx @@ -1,6 +1,6 @@ import { CTASection } from "@/components/sections/cta-section"; import { DemoSection } from "@/components/sections/demo"; -import { FeaturesSection } from "@/components/sections/features-section"; +import { FeedbackSection } from "@/components/sections/feedback-section"; import { FooterSection } from "@/components/sections/footer-section"; import { HeroSection } from "@/components/sections/hero-section"; import { demoSnippets } from "@/components/sections/readme-code-content"; @@ -29,7 +29,7 @@ export default function HomePage() { resubscribe: , }} /> - +
From d9d33ff952503426d72d98da1bc7f9b6cd9947f9 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:09:13 +0400 Subject: [PATCH 16/76] Stabilize docs copy button width --- apps/web/src/components/docs/copy-markdown-button.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/docs/copy-markdown-button.tsx b/apps/web/src/components/docs/copy-markdown-button.tsx index 915b849d..910c7bb8 100644 --- a/apps/web/src/components/docs/copy-markdown-button.tsx +++ b/apps/web/src/components/docs/copy-markdown-button.tsx @@ -35,7 +35,7 @@ export function CopyMarkdownButton({ markdownUrl }: { markdownUrl: string }) { return ( - From 267b6c6f0ac41ef16ae87a429f4e2bd950d8630d Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:20:08 +0400 Subject: [PATCH 17/76] Align docs TOC path lines --- apps/web/src/styles/globals.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css index 548e3dde..0e4f0683 100644 --- a/apps/web/src/styles/globals.css +++ b/apps/web/src/styles/globals.css @@ -481,6 +481,10 @@ html:not([data-anchor-scrolling]) { inset-inline-start: 0px !important; } +#nd-toc a[href^="#"] > svg.absolute { + translate: -7px 0; +} + #nd-toc .stroke-fd-primary { @apply stroke-fd-muted-foreground; stroke-width: 2; From 72994624e0d32de090f729e9406d762ce1806929 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:21:21 +0400 Subject: [PATCH 18/76] Update Fumadocs dependencies --- apps/web/package.json | 6 ++-- pnpm-lock.yaml | 83 ++++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 4d970ae2..2450a293 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -30,9 +30,9 @@ "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", "framer-motion": "^12.34.3", - "fumadocs-core": "^16.7.11", - "fumadocs-mdx": "^14.2.11", - "fumadocs-ui": "^16.7.11", + "fumadocs-core": "^16.9.3", + "fumadocs-mdx": "^15.0.10", + "fumadocs-ui": "^16.9.3", "geist": "^1.3.1", "input-otp": "^1.4.2", "lucide-react": "^0.575.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 94178a91..aa0926ab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -73,10 +73,10 @@ importers: version: 11.17.0(typescript@5.9.3) autumn-js: specifier: ^1.2.2 - version: 1.2.27(better-auth@1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))))(better-call@1.3.5(zod@4.4.3))(express@5.2.1)(hono@4.12.22)(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) + version: 1.2.27(better-auth@1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))))(better-call@1.3.5(zod@4.4.3))(express@5.2.1)(hono@4.12.22)(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) better-auth: specifier: ^1.6.2 - version: 1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))) + version: 1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -218,10 +218,10 @@ importers: version: 2.0.13 '@vercel/analytics': specifier: ^1.6.1 - version: 1.6.1(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) + version: 1.6.1(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) '@vercel/speed-insights': specifier: ^2.0.0 - version: 2.0.0(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) + version: 2.0.0(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -241,17 +241,17 @@ importers: specifier: ^12.34.3 version: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) fumadocs-core: - specifier: ^16.7.11 - version: 16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76) + specifier: ^16.9.3 + version: 16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76) fumadocs-mdx: - specifier: ^14.2.11 - version: 14.3.2(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)) + specifier: ^15.0.10 + version: 15.0.10(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(rolldown@1.0.2)(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)) fumadocs-ui: - specifier: ^16.7.11 - version: 16.9.0(@tailwindcss/oxide@4.3.0)(@types/mdx@2.0.13)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(fumadocs-core@16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0) + specifier: ^16.9.3 + version: 16.9.3(@tailwindcss/oxide@4.3.0)(@types/mdx@2.0.13)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0) geist: specifier: ^1.3.1 - version: 1.7.1(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)) + version: 1.7.1(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)) input-otp: specifier: ^1.4.2 version: 1.4.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -4956,8 +4956,8 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - fumadocs-core@16.9.0: - resolution: {integrity: sha512-L5bXpKsN0m7kK483KqviQ7g0l6PA7M32K5yCXS0KUrVWJDUu038ASb08G59RFwWjxhahCAHf0H0ntwzF91lqnQ==} + fumadocs-core@16.9.3: + resolution: {integrity: sha512-8RVzKnzBJR5o+tJCccY28ntekfMQYBoYiz7alnYb/d9YJc+XpnsINzTl63lQ1eBMZ9gdhm2MqRtgUjh/8rUrbw==} peerDependencies: '@mdx-js/mdx': '*' '@mixedbread/sdk': 0.x.x @@ -5015,18 +5015,19 @@ packages: zod: optional: true - fumadocs-mdx@14.3.2: - resolution: {integrity: sha512-73SoZkbUuqnD91G/0zBcaQdM1TMnYw5JJzKgkGvQTiZbtLQFuWTt8/uRqnzFMuNIUu/WY9Lo9d1iZ8G+jOVieA==} + fumadocs-mdx@15.0.10: + resolution: {integrity: sha512-kH3S7ESS9yXTAaCkA8dDugsCK/MbnpgyZ5qBEL7cWoavV0O/T4+4YTYFkvNknz7cw+T/r+OG0p2BvlVhkk4fww==} hasBin: true peerDependencies: '@types/mdast': '*' '@types/mdx': '*' '@types/react': '*' - fumadocs-core: ^15.0.0 || ^16.0.0 + fumadocs-core: ^16.7.0 mdast-util-directive: '*' next: ^15.3.0 || ^16.0.0 react: ^19.2.0 - vite: 6.x.x || 7.x.x || 8.x.x + rolldown: '*' + vite: 7.x.x || 8.x.x peerDependenciesMeta: '@types/mdast': optional: true @@ -5040,16 +5041,18 @@ packages: optional: true react: optional: true + rolldown: + optional: true vite: optional: true - fumadocs-ui@16.9.0: - resolution: {integrity: sha512-z4w93vuhrsNp1cup7mcEoo8GSDQRCgDMkGnIvUEz+YB7IwSDhrUqf3lXuSKDaqPLXPdRvR0Cf+BAqARBW71c0Q==} + fumadocs-ui@16.9.3: + resolution: {integrity: sha512-eoVKj1H+ATut0su+WIoPWBLRqzPMGD0hekIBr4GopWvUg1lS997HL4kP+Leyf+3CYlZtFgyXb6ylbvRLFtEj6Q==} peerDependencies: '@takumi-rs/image-response': '*' '@types/mdx': '*' '@types/react': '*' - fumadocs-core: 16.9.0 + fumadocs-core: 16.9.3 next: 16.x.x react: ^19.2.0 react-dom: ^19.2.0 @@ -5741,8 +5744,8 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - lucide-react@1.16.0: - resolution: {integrity: sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==} + lucide-react@1.17.0: + resolution: {integrity: sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -7114,6 +7117,10 @@ packages: resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} @@ -10374,12 +10381,12 @@ snapshots: '@ungap/structured-clone@1.3.1': {} - '@vercel/analytics@1.6.1(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)': + '@vercel/analytics@1.6.1(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)': optionalDependencies: next: 16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 - '@vercel/speed-insights@2.0.0(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)': + '@vercel/speed-insights@2.0.0(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)': optionalDependencies: next: 16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 @@ -10583,13 +10590,13 @@ snapshots: auto-bind@5.0.1: {} - autumn-js@1.2.27(better-auth@1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))))(better-call@1.3.5(zod@4.4.3))(express@5.2.1)(hono@4.12.22)(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6): + autumn-js@1.2.27(better-auth@1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))))(better-call@1.3.5(zod@4.4.3))(express@5.2.1)(hono@4.12.22)(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6): dependencies: query-string: 9.3.1 rou3: 0.6.3 zod: 4.4.3 optionalDependencies: - better-auth: 1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))) + better-auth: 1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))) better-call: 1.3.5(zod@4.4.3) express: 5.2.1 hono: 4.12.22 @@ -10614,7 +10621,7 @@ snapshots: baseline-browser-mapping@2.10.32: {} - better-auth@1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))): + better-auth@1.6.11(@cloudflare/workers-types@4.20260522.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7(@types/node@20.19.41)(msw@2.14.6(@types/node@20.19.41)(typescript@5.9.3))(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))): dependencies: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260522.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/drizzle-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260522.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260522.1)(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.21.0)) @@ -11564,7 +11571,7 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76): + fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76): dependencies: '@orama/orama': 3.1.18 estree-util-value-to-estree: 3.5.0 @@ -11597,20 +11604,19 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-mdx@14.3.2(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)): + fumadocs-mdx@15.0.10(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(rolldown@1.0.2)(vite@8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.1.0 chokidar: 5.0.0 esbuild: 0.28.0 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76) + fumadocs-core: 16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76) js-yaml: 4.1.1 mdast-util-mdx: 3.0.0 - mdast-util-to-markdown: 2.1.2 picocolors: 1.1.1 picomatch: 4.0.4 - tinyexec: 1.1.2 + tinyexec: 1.2.4 tinyglobby: 0.2.16 unified: 11.0.5 unist-util-remove-position: 5.0.0 @@ -11623,11 +11629,12 @@ snapshots: '@types/react': 19.2.15 next: 16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 + rolldown: 1.0.2 vite: 8.0.14(@types/node@20.19.41)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0) transitivePeerDependencies: - supports-color - fumadocs-ui@16.9.0(@tailwindcss/oxide@4.3.0)(@types/mdx@2.0.13)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(fumadocs-core@16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0): + fumadocs-ui@16.9.3(@tailwindcss/oxide@4.3.0)(@types/mdx@2.0.13)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0): dependencies: '@fumadocs/tailwind': 0.0.5(@tailwindcss/oxide@4.3.0)(tailwindcss@4.3.0) '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -11641,8 +11648,8 @@ snapshots: '@radix-ui/react-slot': 1.2.4(@types/react@19.2.15)(react@19.2.6) '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) class-variance-authority: 0.7.1 - fumadocs-core: 16.9.0(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76) - lucide-react: 1.16.0(react@19.2.6) + fumadocs-core: 16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@0.575.0(react@19.2.6))(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@3.25.76) + lucide-react: 1.17.0(react@19.2.6) motion: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) next-themes: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 @@ -11667,7 +11674,7 @@ snapshots: fuzzysort@3.1.0: {} - geist@1.7.1(next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)): + geist@1.7.1(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)): dependencies: next: 16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -12334,7 +12341,7 @@ snapshots: dependencies: react: 19.2.6 - lucide-react@1.16.0(react@19.2.6): + lucide-react@1.17.0(react@19.2.6): dependencies: react: 19.2.6 @@ -14258,6 +14265,8 @@ snapshots: tinyexec@1.1.2: {} + tinyexec@1.2.4: {} + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) From 13333f9c83d756fa1327ef8a0c3b623f63ba9a54 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 10:21:40 +0400 Subject: [PATCH 19/76] Adjust docs TOC footer progress --- apps/web/src/components/docs/toc-footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/docs/toc-footer.tsx b/apps/web/src/components/docs/toc-footer.tsx index c85c8220..343004cf 100644 --- a/apps/web/src/components/docs/toc-footer.tsx +++ b/apps/web/src/components/docs/toc-footer.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { URLs } from "@/lib/consts"; -const progressValue = 15; +const progressValue = 65; export function TocFooter() { return ( From 6c380a93c7b64feb188bbf068091bafcd86d9280 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 3 Jun 2026 11:01:02 +0400 Subject: [PATCH 20/76] Polish docs CTA controls --- apps/web/src/components/docs/copy-markdown-button.tsx | 3 ++- apps/web/src/components/sections/cta-section.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/docs/copy-markdown-button.tsx b/apps/web/src/components/docs/copy-markdown-button.tsx index 910c7bb8..e52b65b3 100644 --- a/apps/web/src/components/docs/copy-markdown-button.tsx +++ b/apps/web/src/components/docs/copy-markdown-button.tsx @@ -1,6 +1,7 @@ "use client"; import { Check, ChevronDown, Copy, ExternalLink } from "lucide-react"; +import { RiMarkdownLine } from "react-icons/ri"; import Link from "next/link"; import { useCallback, useState } from "react"; import { toast } from "sonner"; @@ -49,7 +50,7 @@ export function CopyMarkdownButton({ markdownUrl }: { markdownUrl: string }) { }> - + View as markdown }> diff --git a/apps/web/src/components/sections/cta-section.tsx b/apps/web/src/components/sections/cta-section.tsx index 24ce704d..8558f693 100644 --- a/apps/web/src/components/sections/cta-section.tsx +++ b/apps/web/src/components/sections/cta-section.tsx @@ -30,7 +30,7 @@ export function CTASection() { minutes.

- )} diff --git a/apps/web/src/app/docs/layout.tsx b/apps/web/src/app/docs/layout.tsx index 4bc17730..8fd85762 100644 --- a/apps/web/src/app/docs/layout.tsx +++ b/apps/web/src/app/docs/layout.tsx @@ -1,8 +1,8 @@ import type * as PageTree from "fumadocs-core/page-tree"; import { DocsLayout } from "fumadocs-ui/layouts/docs"; -import { Github } from "lucide-react"; import { cloneElement } from "react"; import type { ReactElement, ReactNode } from "react"; +import { RiGithubFill } from "react-icons/ri"; import { CategoryFolderIcon, @@ -170,7 +170,7 @@ export default function Layout({ children }: { children: ReactNode }) { size="icon" className="docs-sidebar-github-button text-fd-muted-foreground hover:text-fd-accent-foreground" > -
diff --git a/apps/web/src/app/not-found.tsx b/apps/web/src/app/not-found.tsx index bfc052d1..12251c7b 100644 --- a/apps/web/src/app/not-found.tsx +++ b/apps/web/src/app/not-found.tsx @@ -1,7 +1,7 @@ "use client"; -import { ArrowLeft } from "lucide-react"; import Link from "next/link"; +import { RiArrowLeftLine } from "react-icons/ri"; import { MiniNavBar } from "@/components/layout/mini-nav-bar"; import { PageTransition } from "@/components/layout/page-transition"; @@ -50,7 +50,7 @@ export default function NotFound() {
diff --git a/apps/web/src/components/command-menu.tsx b/apps/web/src/components/command-menu.tsx index 890adfa0..bff6b0a3 100644 --- a/apps/web/src/components/command-menu.tsx +++ b/apps/web/src/components/command-menu.tsx @@ -2,9 +2,9 @@ import { AnimatePresence, motion } from "framer-motion"; import { useDocsSearch } from "fumadocs-core/search/client"; -import { FileText, Hash, Search, Text } from "lucide-react"; import { useRouter } from "next/navigation"; import { createContext, use, useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { RiFileTextLine, RiHashtag, RiSearchLine, RiText } from "react-icons/ri"; import { cn } from "@/lib/utils"; @@ -112,7 +112,7 @@ function CommandMenuDialog() { ); } -// ─── Search Mode ───────────────────────────────────────────────────────────── +// ─── RiSearchLine Mode ───────────────────────────────────────────────────────────── function SearchMode({ query, @@ -170,7 +170,7 @@ function SearchMode({ <> {/* Input */}
- + setSelectedIndex(index)} > {item.type === "heading" ? ( - + ) : item.type === "text" ? ( - + ) : ( - + )} {item.content} diff --git a/apps/web/src/components/docs/copy-markdown-button.tsx b/apps/web/src/components/docs/copy-markdown-button.tsx index e52b65b3..46079f5e 100644 --- a/apps/web/src/components/docs/copy-markdown-button.tsx +++ b/apps/web/src/components/docs/copy-markdown-button.tsx @@ -1,9 +1,14 @@ "use client"; -import { Check, ChevronDown, Copy, ExternalLink } from "lucide-react"; -import { RiMarkdownLine } from "react-icons/ri"; import Link from "next/link"; import { useCallback, useState } from "react"; +import { + RiArrowDownSLine, + RiCheckLine, + RiExternalLinkLine, + RiFileCopyLine, + RiMarkdownLine, +} from "react-icons/ri"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -37,7 +42,7 @@ export function CopyMarkdownButton({ markdownUrl }: { markdownUrl: string }) { return ( @@ -46,7 +51,7 @@ export function CopyMarkdownButton({ markdownUrl }: { markdownUrl: string }) { ); } diff --git a/apps/web/src/components/layout/navigation-bar.tsx b/apps/web/src/components/layout/navigation-bar.tsx index 3570fa3e..af0ff1ea 100644 --- a/apps/web/src/components/layout/navigation-bar.tsx +++ b/apps/web/src/components/layout/navigation-bar.tsx @@ -1,11 +1,11 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { ChevronDown, ExternalLink, Menu, X } from "lucide-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useCallback, useEffect, useRef, useState } from "react"; import { FaGithub } from "react-icons/fa"; +import { RiArrowDownSLine, RiCloseLine, RiExternalLinkLine, RiMenuLine } from "react-icons/ri"; import { SectionShell } from "@/components/layout/section"; import { Button } from "@/components/ui/button"; @@ -125,7 +125,7 @@ export function NavigationBar({ stars: _stars }: { stars: number | null }) { onClick={() => setMobileMenuOpen((prev) => !prev)} className="text-foreground/65 dark:text-foreground/50 hover:text-foreground/80 px-5 py-3 transition-colors" > - {mobileMenuOpen ? : } + {mobileMenuOpen ? : } @@ -184,7 +184,7 @@ export function NavigationBar({ stars: _stars }: { stars: number | null }) { className={`${tabBase} gap-1 ${linksOpen ? "text-foreground/70" : tabInactive}`} > links - @@ -207,7 +207,7 @@ export function NavigationBar({ stars: _stars }: { stars: number | null }) { > {link.name} {link.external && ( - + )} ))} @@ -272,7 +272,7 @@ export function NavigationBar({ stars: _stars }: { stars: number | null }) { {item.name} {item.external && ( - + )} diff --git a/apps/web/src/components/sections/cta-section.tsx b/apps/web/src/components/sections/cta-section.tsx index 8558f693..a5a77fbf 100644 --- a/apps/web/src/components/sections/cta-section.tsx +++ b/apps/web/src/components/sections/cta-section.tsx @@ -1,9 +1,9 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { Check, ChevronRight, Copy } from "lucide-react"; import Link from "next/link"; import { useCallback, useState } from "react"; +import { RiArrowRightSLine, RiCheckLine, RiFileCopyLine } from "react-icons/ri"; import { Section, SectionContent } from "@/components/layout/section"; import { Button } from "@/components/ui/button"; @@ -52,7 +52,7 @@ export function CTASection() { transition={{ duration: 0.15 }} className="absolute" > - + ) : hovered ? ( - + ) : ( - + )} diff --git a/apps/web/src/components/sections/demo/demo-app-window.tsx b/apps/web/src/components/sections/demo/demo-app-window.tsx index 4b2e8621..1bb74978 100644 --- a/apps/web/src/components/sections/demo/demo-app-window.tsx +++ b/apps/web/src/components/sections/demo/demo-app-window.tsx @@ -1,8 +1,8 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { Loader2, Send } from "lucide-react"; import type { RefObject } from "react"; +import { RiLoader4Line, RiSendPlaneLine } from "react-icons/ri"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; @@ -134,7 +134,7 @@ export function DemoAppWindow({ > {busy === "downgrade" ? ( <> - + Downgrading... ) : plan === "free" ? ( @@ -169,12 +169,12 @@ export function DemoAppWindow({ > {busy === "upgrade" ? ( <> - + Upgrading... ) : busy === "resubscribe" ? ( <> - + Resubscribing... ) : plan === "pro" && downgradeScheduled ? ( @@ -285,7 +285,7 @@ export function DemoAppWindow({ disabled={blocked || aiState !== "idle" || !input.trim()} className="text-foreground/35 hover:text-foreground/60 disabled:opacity-20" > - +
diff --git a/apps/web/src/components/sections/demo/demo-backend-panel.tsx b/apps/web/src/components/sections/demo/demo-backend-panel.tsx index 92f466b5..2cd61c53 100644 --- a/apps/web/src/components/sections/demo/demo-backend-panel.tsx +++ b/apps/web/src/components/sections/demo/demo-backend-panel.tsx @@ -1,8 +1,8 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { Loader2, User } from "lucide-react"; import type { ReactNode } from "react"; +import { RiLoader4Line, RiUserLine } from "react-icons/ri"; import { cn } from "@/lib/utils"; @@ -63,7 +63,7 @@ function FlowLog({ className="border-foreground/[0.08] shrink-0 overflow-hidden rounded-md border" >
- + {card.trigger}
@@ -88,7 +88,7 @@ function FlowLog({ ) : entry.type === "pending" ? (
- + {entry.label}
) : ( diff --git a/apps/web/src/components/sections/demo/demo-types.tsx b/apps/web/src/components/sections/demo/demo-types.tsx index 6d6838e8..69306905 100644 --- a/apps/web/src/components/sections/demo/demo-types.tsx +++ b/apps/web/src/components/sections/demo/demo-types.tsx @@ -1,18 +1,18 @@ -import { - CalendarCheck, - CalendarX, - CreditCard, - Database, - ExternalLink, - Link2, - RefreshCw, - Shield, - ShieldAlert, - Sparkles, - UserCheck, - Webhook, -} from "lucide-react"; import type { ReactNode } from "react"; +import { + RiBankCardLine, + RiCalendarCheckLine, + RiCalendarCloseLine, + RiDatabase2Line, + RiExternalLinkLine, + RiLink, + RiRefreshLine, + RiShieldFlashLine, + RiShieldLine, + RiSparklingLine, + RiUserFollowLine, + RiWebhookLine, +} from "react-icons/ri"; export type SnippetKey = "subscribe" | "check" | "report" | "portal" | "downgrade" | "resubscribe"; @@ -47,18 +47,18 @@ export function nextCardId() { } export const stepIcons: Record = { - user: , - "credit-card": , - webhook: , - database: , - link: , - "external-link": , - "calendar-x": , - "calendar-check": , - sparkles: , - shield: , - "shield-alert": , - refresh: , + user: , + "credit-card": , + webhook: , + database: , + link: , + "external-link": , + "calendar-x": , + "calendar-check": , + sparkles: , + shield: , + "shield-alert": , + refresh: , }; // Scripted replies for auto-play diff --git a/apps/web/src/components/sections/features-section.tsx b/apps/web/src/components/sections/features-section.tsx index ec45a5e2..ecf318a5 100644 --- a/apps/web/src/components/sections/features-section.tsx +++ b/apps/web/src/components/sections/features-section.tsx @@ -1,35 +1,42 @@ -import { Blocks, Cable, Database, Gauge, ShieldCheck, Webhook } from "lucide-react"; +import { + RiDatabase2Line, + RiPlug2Line, + RiPuzzle2Line, + RiShieldCheckLine, + RiSpeedUpLine, + RiWebhookLine, +} from "react-icons/ri"; import { Section, SectionContent } from "@/components/layout/section"; const features = [ { - icon: , + icon: , title: "Usage billing", description: "Metered features with check() and report(). Zero network latency.", }, { - icon: , + icon: , title: "Webhooks handled", description: "Verified, deduplicated, synced to your database automatically.", }, { - icon: , + icon: , title: "Stripe built in", description: "Subscriptions, webhooks, portal, and product sync without adapter setup.", }, { - icon: , + icon: , title: "Plugins", description: "Extend PayKit with dashboard, analytics, or build your own plugin.", }, { - icon: , + icon: , title: "Your database", description: "Billing state in your Postgres, low latency, joinable with your tables.", }, { - icon: , + icon: , title: "Type-safe", description: "Plan IDs, feature IDs, events. All inferred from your schema.", }, diff --git a/apps/web/src/components/sections/footer-section.tsx b/apps/web/src/components/sections/footer-section.tsx index 0541f986..19286e62 100644 --- a/apps/web/src/components/sections/footer-section.tsx +++ b/apps/web/src/components/sections/footer-section.tsx @@ -1,7 +1,7 @@ "use client"; -import { Github } from "lucide-react"; import Link from "next/link"; +import { RiGithubFill } from "react-icons/ri"; import { Icons } from "@/components/icons"; import { Section, SectionContent } from "@/components/layout/section"; @@ -17,7 +17,7 @@ const socialLinks = [ { label: "Discord", href: URLs.discord, icon: }, { label: "Twitter/X", href: URLs.x, icon: }, { label: "LinkedIn", href: URLs.linkedin, icon: }, - { label: "GitHub", href: URLs.githubRepo, icon: }, + { label: "GitHub", href: URLs.githubRepo, icon: }, ]; const prompt = encodeURIComponent(`Explain what PayKit (paykit.sh) is and why I should use it. diff --git a/apps/web/src/components/sidebar-content.tsx b/apps/web/src/components/sidebar-content.tsx index d9c17192..6850b70d 100644 --- a/apps/web/src/components/sidebar-content.tsx +++ b/apps/web/src/components/sidebar-content.tsx @@ -1,25 +1,25 @@ import type { Folder, Root } from "fumadocs-core/page-tree"; -import type { LucideIcon } from "lucide-react"; -import { - Binoculars, - Book, - CircleHelp, - Database, - Gauge, - Key, - KeyRound, - LucideAArrowDown, - Mail, - Mailbox, - Phone, - ScanFace, - ShieldCheck, - TriangleAlertIcon, - UserCircle, - UserSquare2, - Users2, -} from "lucide-react"; import type { ReactNode, SVGProps } from "react"; +import type { IconType } from "react-icons"; +import { + RiAccountBoxLine, + RiAccountCircleLine, + RiBookLine, + RiDatabase2Line, + RiErrorWarningLine, + RiInboxLine, + RiKey2Line, + RiKeyLine, + RiMailLine, + RiPhoneLine, + RiQuestionLine, + RiSearchEyeLine, + RiShieldCheckLine, + RiSortAlphabetAsc, + RiSpeedUpLine, + RiTeamLine, + RiUserSearchLine, +} from "react-icons/ri"; import { Icons } from "./icons"; @@ -31,7 +31,7 @@ export interface SubpageItem { export interface ListItem { title: string; href: string; - icon: ((props?: SVGProps) => ReactNode) | LucideIcon; + icon: ((props?: SVGProps) => ReactNode) | IconType; group?: boolean; separator?: boolean; isNew?: boolean; @@ -42,7 +42,7 @@ export interface ListItem { interface Content { title: string; href?: string; - Icon: ((props?: SVGProps) => ReactNode) | LucideIcon; + Icon: ((props?: SVGProps) => ReactNode) | IconType; isNew?: boolean; list: ListItem[]; } @@ -418,7 +418,7 @@ export const contents: Content[] = [ { title: "Social Sign-On", group: true, - icon: LucideAArrowDown, + icon: RiSortAlphabetAsc, href: "", }, { @@ -1090,13 +1090,13 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, { title: "Other Relational Databases", href: "/docs/adapters/other-relational-databases", - icon: () => , + icon: () => , }, { group: true, title: "Adapters", href: "", - icon: () => , + icon: () => , }, { title: "Drizzle", @@ -1182,7 +1182,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, group: true, title: "Others", href: "", - icon: () => , + icon: () => , }, { title: "Community Adapters", @@ -1227,7 +1227,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, group: true, title: "Full Stack", href: "", - icon: LucideAArrowDown, + icon: RiSortAlphabetAsc, }, { title: "Astro", @@ -1269,7 +1269,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, group: true, title: "Backend", href: "", - icon: LucideAArrowDown, + icon: RiSortAlphabetAsc, }, { title: "Hono", @@ -1310,7 +1310,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, group: true, title: "Mobile & Desktop", href: "", - icon: LucideAArrowDown, + icon: RiSortAlphabetAsc, }, { title: "Expo", @@ -1342,38 +1342,38 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, title: "Authentication", group: true, href: "", - icon: () => , + icon: () => , }, { title: "Two Factor", - icon: () => , + icon: () => , href: "/docs/plugins/2fa", }, { title: "Username", - icon: () => , + icon: () => , href: "/docs/plugins/username", }, { title: "Anonymous", - icon: () => , + icon: () => , href: "/docs/plugins/anonymous", }, { title: "Phone Number", - icon: () => , + icon: () => , href: "/docs/plugins/phone-number", }, { title: "Magic Link", href: "/docs/plugins/magic-link", - icon: () => , + icon: () => , }, { title: "Email OTP", href: "/docs/plugins/email-otp", - icon: () => , + icon: () => , }, { title: "Passkey", @@ -1436,7 +1436,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, title: "Authorization", group: true, href: "", - icon: () => , + icon: () => , }, { title: "Admin", @@ -1458,7 +1458,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, { title: "API Key", href: "/docs/plugins/api-key", - icon: () => , + icon: () => , }, { title: "MCP", @@ -1494,7 +1494,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, }, { title: "Organization", - icon: () => , + icon: () => , href: "/docs/plugins/organization", }, { @@ -1566,11 +1566,11 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, title: "Utility", group: true, href: "", - icon: () => , + icon: () => , }, { title: "Bearer", - icon: () => , + icon: () => , href: "/docs/plugins/bearer", }, { @@ -1707,7 +1707,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, title: "Payments", group: true, href: "", - icon: () => , + icon: () => , }, { title: "Stripe", @@ -1935,7 +1935,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, { title: "Create a Database Adapter", href: "/docs/guides/create-a-db-adapter", - icon: () => , + icon: () => , }, { title: "Browser Extension Guide", @@ -1976,7 +1976,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, { title: "Optimize for Performance", href: "/docs/guides/optimizing-for-performance", - icon: () => , + icon: () => , }, { title: "Migration", @@ -2210,7 +2210,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, { title: "Errors", href: "/docs/reference/errors", - icon: () => , + icon: () => , hasSubpages: true, subpages: [ { @@ -2275,23 +2275,23 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, { title: "Resources", href: "/docs/reference/resources", - icon: () => , + icon: () => , }, { title: "Security", href: "/docs/reference/security", - icon: () => , + icon: () => , }, { title: "Telemetry", href: "/docs/reference/telemetry", - icon: () => , + icon: () => , }, { title: "FAQ", href: "/docs/reference/faq", - icon: () => , + icon: () => , }, ], }, diff --git a/apps/web/src/components/theme-switcher.tsx b/apps/web/src/components/theme-switcher.tsx index 46393d10..cd2cf53a 100644 --- a/apps/web/src/components/theme-switcher.tsx +++ b/apps/web/src/components/theme-switcher.tsx @@ -1,6 +1,6 @@ "use client"; -import { Moon, Sun } from "lucide-react"; +import { RiMoonLine, RiSunLine } from "react-icons/ri"; import { Button } from "@/components/ui/button"; import { useThemeTransition } from "@/components/use-theme-transition"; @@ -19,9 +19,9 @@ export function ThemeSwitcher() { suppressHydrationWarning > {buttonTheme === "dark" ? ( - + ) : ( - + )} {toggleLabel} diff --git a/apps/web/src/components/ui/accordion.tsx b/apps/web/src/components/ui/accordion.tsx index 075a115c..ae55d76a 100644 --- a/apps/web/src/components/ui/accordion.tsx +++ b/apps/web/src/components/ui/accordion.tsx @@ -1,7 +1,7 @@ "use client"; import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"; -import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"; +import { RiArrowDownSLine, RiArrowUpSLine } from "react-icons/ri"; import { cn } from "@/lib/utils"; @@ -37,11 +37,11 @@ function AccordionTrigger({ className, children, ...props }: AccordionPrimitive. {...props} > {children} - - diff --git a/apps/web/src/components/ui/breadcrumb.tsx b/apps/web/src/components/ui/breadcrumb.tsx index b6381016..1f4e60b9 100644 --- a/apps/web/src/components/ui/breadcrumb.tsx +++ b/apps/web/src/components/ui/breadcrumb.tsx @@ -1,7 +1,7 @@ import { mergeProps } from "@base-ui/react/merge-props"; import { useRender } from "@base-ui/react/use-render"; -import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"; import * as React from "react"; +import { RiArrowRightSLine, RiMoreLine } from "react-icons/ri"; import { cn } from "@/lib/utils"; @@ -72,7 +72,7 @@ function BreadcrumbSeparator({ children, className, ...props }: React.ComponentP className={cn("[&>svg]:size-3.5", className)} {...props} > - {children ?? } + {children ?? } ); } @@ -86,7 +86,7 @@ function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<"span" className={cn("flex size-5 items-center justify-center [&>svg]:size-4", className)} {...props} > - + More ); diff --git a/apps/web/src/components/ui/calendar.tsx b/apps/web/src/components/ui/calendar.tsx index 47d9a1e9..a58f2233 100644 --- a/apps/web/src/components/ui/calendar.tsx +++ b/apps/web/src/components/ui/calendar.tsx @@ -1,8 +1,8 @@ "use client"; -import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react"; import * as React from "react"; import { DayPicker, getDefaultClassNames, type DayButton, type Locale } from "react-day-picker"; +import { RiArrowDownSLine, RiArrowLeftSLine, RiArrowRightSLine } from "react-icons/ri"; import { Button, buttonVariants } from "@/components/ui/button"; import { cn } from "@/lib/utils"; @@ -118,14 +118,14 @@ function Calendar({ }, Chevron: ({ className, orientation, ...props }) => { if (orientation === "left") { - return ; + return ; } if (orientation === "right") { - return ; + return ; } - return ; + return ; }, DayButton: ({ ...props }) => , WeekNumber: ({ children, ...props }) => { diff --git a/apps/web/src/components/ui/carousel.tsx b/apps/web/src/components/ui/carousel.tsx index 73e2e927..6af48cfe 100644 --- a/apps/web/src/components/ui/carousel.tsx +++ b/apps/web/src/components/ui/carousel.tsx @@ -1,8 +1,8 @@ "use client"; import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react"; -import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; import * as React from "react"; +import { RiArrowLeftSLine, RiArrowRightSLine } from "react-icons/ri"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; @@ -184,7 +184,7 @@ function CarouselPrevious({ onClick={scrollPrev} {...props} > - + Previous slide ); @@ -214,7 +214,7 @@ function CarouselNext({ onClick={scrollNext} {...props} > - + Next slide ); diff --git a/apps/web/src/components/ui/checkbox.tsx b/apps/web/src/components/ui/checkbox.tsx index 8180b82a..cac7705e 100644 --- a/apps/web/src/components/ui/checkbox.tsx +++ b/apps/web/src/components/ui/checkbox.tsx @@ -1,7 +1,7 @@ "use client"; import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"; -import { CheckIcon } from "lucide-react"; +import { RiCheckLine } from "react-icons/ri"; import { cn } from "@/lib/utils"; @@ -19,7 +19,7 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) { data-slot="checkbox-indicator" className="grid place-content-center text-current transition-none [&>svg]:size-3.5" > - + ); diff --git a/apps/web/src/components/ui/code-block.tsx b/apps/web/src/components/ui/code-block.tsx index 575a9b43..6dae67be 100644 --- a/apps/web/src/components/ui/code-block.tsx +++ b/apps/web/src/components/ui/code-block.tsx @@ -1,5 +1,5 @@ "use client"; -import { Check, Copy } from "lucide-react"; + import type { ButtonHTMLAttributes, ComponentProps, @@ -9,6 +9,7 @@ import type { RefObject, } from "react"; import { createContext, forwardRef, useCallback, useContext, useMemo, useRef } from "react"; +import { RiCheckLine, RiFileCopyLine } from "react-icons/ri"; import { buttonVariants } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; @@ -195,8 +196,10 @@ function CopyButton({ onClick={onClick} {...props} > - - + + ); } diff --git a/apps/web/src/components/ui/combobox.tsx b/apps/web/src/components/ui/combobox.tsx index 6addd25d..dc5e635c 100644 --- a/apps/web/src/components/ui/combobox.tsx +++ b/apps/web/src/components/ui/combobox.tsx @@ -1,8 +1,8 @@ "use client"; import { Combobox as ComboboxPrimitive } from "@base-ui/react"; -import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react"; import * as React from "react"; +import { RiArrowDownSLine, RiCheckLine, RiCloseLine } from "react-icons/ri"; import { Button } from "@/components/ui/button"; import { @@ -27,7 +27,7 @@ function ComboboxTrigger({ className, children, ...props }: ComboboxPrimitive.Tr {...props} > {children} - + ); } @@ -40,7 +40,7 @@ function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) { className={cn(className)} {...props} > - + ); } @@ -143,7 +143,7 @@ function ComboboxItem({ className, children, ...props }: ComboboxPrimitive.Item. } > - + ); @@ -232,7 +232,7 @@ function ComboboxChip({ className="-ml-1 opacity-50 hover:opacity-100" data-slot="combobox-chip-remove" > - + )} diff --git a/apps/web/src/components/ui/command.tsx b/apps/web/src/components/ui/command.tsx index 78e76940..04c49fbc 100644 --- a/apps/web/src/components/ui/command.tsx +++ b/apps/web/src/components/ui/command.tsx @@ -1,8 +1,8 @@ "use client"; import { Command as CommandPrimitive } from "cmdk"; -import { SearchIcon, CheckIcon } from "lucide-react"; import * as React from "react"; +import { RiCheckLine, RiSearchLine } from "react-icons/ri"; import { Dialog, @@ -73,7 +73,7 @@ function CommandInput({ {...props} /> - +
@@ -150,7 +150,7 @@ function CommandItem({ {...props} > {children} - + ); } diff --git a/apps/web/src/components/ui/context-menu.tsx b/apps/web/src/components/ui/context-menu.tsx index d6b56246..2ce2d233 100644 --- a/apps/web/src/components/ui/context-menu.tsx +++ b/apps/web/src/components/ui/context-menu.tsx @@ -1,8 +1,8 @@ "use client"; import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu"; -import { ChevronRightIcon, CheckIcon } from "lucide-react"; import * as React from "react"; +import { RiArrowRightSLine, RiCheckLine } from "react-icons/ri"; import { cn } from "@/lib/utils"; @@ -135,7 +135,7 @@ function ContextMenuSubTrigger({ {...props} > {children} - + ); } @@ -173,7 +173,7 @@ function ContextMenuCheckboxItem({ > - + {children} @@ -205,7 +205,7 @@ function ContextMenuRadioItem({ > - + {children} diff --git a/apps/web/src/components/ui/dialog.tsx b/apps/web/src/components/ui/dialog.tsx index 3b29b13d..41745c24 100644 --- a/apps/web/src/components/ui/dialog.tsx +++ b/apps/web/src/components/ui/dialog.tsx @@ -1,8 +1,8 @@ "use client"; import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"; -import { XIcon } from "lucide-react"; import * as React from "react"; +import { RiCloseLine } from "react-icons/ri"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; @@ -61,7 +61,7 @@ function DialogContent({ data-slot="dialog-close" render={
); } diff --git a/apps/web/src/components/ui/menubar.tsx b/apps/web/src/components/ui/menubar.tsx index bedfd43f..a63ce43f 100644 --- a/apps/web/src/components/ui/menubar.tsx +++ b/apps/web/src/components/ui/menubar.tsx @@ -2,8 +2,8 @@ import { Menu as MenuPrimitive } from "@base-ui/react/menu"; import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar"; -import { CheckIcon } from "lucide-react"; import * as React from "react"; +import { RiCheckLine } from "react-icons/ri"; import { DropdownMenu, @@ -121,7 +121,7 @@ function MenubarCheckboxItem({ > - + {children} @@ -153,7 +153,7 @@ function MenubarRadioItem({ > - + {children} diff --git a/apps/web/src/components/ui/native-select.tsx b/apps/web/src/components/ui/native-select.tsx index cc077ccf..9cb9ab56 100644 --- a/apps/web/src/components/ui/native-select.tsx +++ b/apps/web/src/components/ui/native-select.tsx @@ -1,5 +1,5 @@ -import { ChevronDownIcon } from "lucide-react"; import * as React from "react"; +import { RiArrowDownSLine } from "react-icons/ri"; import { cn } from "@/lib/utils"; @@ -23,7 +23,7 @@ function NativeSelect({ className, size = "default", ...props }: NativeSelectPro className="h-8 w-full min-w-0 appearance-none rounded-lg border border-input bg-transparent py-1 pr-8 pl-2.5 text-sm transition-colors outline-none select-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-[size=sm]:py-0.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40" {...props} /> -