From 7172f787ac2fb9e45a281becd443f4d444f40fa5 Mon Sep 17 00:00:00 2001 From: shadcn Date: Thu, 19 Feb 2026 10:51:37 +0400 Subject: [PATCH] feat --- .../(root)/explore/copy-preset-button.tsx | 31 +++++ apps/v4/app/(app)/(root)/explore/page.tsx | 71 +++++++++++ .../app/(create)/components/random-button.tsx | 15 ++- apps/v4/app/(create)/lib/randomize-biases.ts | 6 +- apps/v4/lib/config.ts | 4 + apps/v4/lib/explore.ts | 11 ++ apps/v4/package.json | 1 + apps/v4/public/presets/A1D5CKfo-dark.png | Bin 0 -> 117401 bytes apps/v4/public/presets/A1D5CKfo-light.png | Bin 0 -> 116742 bytes apps/v4/public/presets/A1DN5Lx2-dark.png | Bin 0 -> 112956 bytes apps/v4/public/presets/A1DN5Lx2-light.png | Bin 0 -> 112779 bytes apps/v4/public/presets/A1DOCw6i-dark.png | Bin 0 -> 90824 bytes apps/v4/public/presets/A1DOCw6i-light.png | Bin 0 -> 90409 bytes apps/v4/public/presets/A1DyXaky-dark.png | Bin 0 -> 90756 bytes apps/v4/public/presets/A1DyXaky-light.png | Bin 0 -> 90229 bytes apps/v4/public/presets/A1zDJJ-dark.png | Bin 0 -> 130816 bytes apps/v4/public/presets/A1zDJJ-light.png | Bin 0 -> 131813 bytes apps/v4/public/presets/A2He4G-dark.png | Bin 0 -> 99797 bytes apps/v4/public/presets/A2He4G-light.png | Bin 0 -> 99655 bytes apps/v4/public/presets/AL1Qw4-dark.png | Bin 0 -> 118881 bytes apps/v4/public/presets/AL1Qw4-light.png | Bin 0 -> 119523 bytes apps/v4/public/presets/AbYAmrx-dark.png | Bin 0 -> 129908 bytes apps/v4/public/presets/AbYAmrx-light.png | Bin 0 -> 129400 bytes apps/v4/public/presets/AbZIu0W-dark.png | Bin 0 -> 126064 bytes apps/v4/public/presets/AbZIu0W-light.png | Bin 0 -> 125637 bytes apps/v4/public/presets/AcRnsyu-dark.png | Bin 0 -> 131177 bytes apps/v4/public/presets/AcRnsyu-light.png | Bin 0 -> 130955 bytes apps/v4/public/presets/AuFzoPZ-dark.png | Bin 0 -> 105393 bytes apps/v4/public/presets/AuFzoPZ-light.png | Bin 0 -> 104108 bytes apps/v4/public/presets/Aumd2e-dark.png | Bin 0 -> 103966 bytes apps/v4/public/presets/Aumd2e-light.png | Bin 0 -> 104438 bytes apps/v4/public/presets/AvM5aK-dark.png | Bin 0 -> 119093 bytes apps/v4/public/presets/AvM5aK-light.png | Bin 0 -> 119379 bytes .../v4/registry/bases/base/blocks/preview.tsx | 36 ++++-- .../v4/registry/bases/base/ui/radio-group.tsx | 10 +- .../registry/bases/radix/blocks/preview.tsx | 36 ++++-- .../registry/bases/radix/ui/radio-group.tsx | 10 +- apps/v4/registry/styles/style-maia.css | 6 +- apps/v4/registry/styles/style-mira.css | 2 +- apps/v4/registry/styles/style-nova.css | 2 +- apps/v4/registry/styles/style-vega.css | 2 +- apps/v4/scripts/capture-explore.mts | 111 ++++++++++++++++++ package.json | 1 + 43 files changed, 306 insertions(+), 49 deletions(-) create mode 100644 apps/v4/app/(app)/(root)/explore/copy-preset-button.tsx create mode 100644 apps/v4/app/(app)/(root)/explore/page.tsx create mode 100644 apps/v4/lib/explore.ts create mode 100644 apps/v4/public/presets/A1D5CKfo-dark.png create mode 100644 apps/v4/public/presets/A1D5CKfo-light.png create mode 100644 apps/v4/public/presets/A1DN5Lx2-dark.png create mode 100644 apps/v4/public/presets/A1DN5Lx2-light.png create mode 100644 apps/v4/public/presets/A1DOCw6i-dark.png create mode 100644 apps/v4/public/presets/A1DOCw6i-light.png create mode 100644 apps/v4/public/presets/A1DyXaky-dark.png create mode 100644 apps/v4/public/presets/A1DyXaky-light.png create mode 100644 apps/v4/public/presets/A1zDJJ-dark.png create mode 100644 apps/v4/public/presets/A1zDJJ-light.png create mode 100644 apps/v4/public/presets/A2He4G-dark.png create mode 100644 apps/v4/public/presets/A2He4G-light.png create mode 100644 apps/v4/public/presets/AL1Qw4-dark.png create mode 100644 apps/v4/public/presets/AL1Qw4-light.png create mode 100644 apps/v4/public/presets/AbYAmrx-dark.png create mode 100644 apps/v4/public/presets/AbYAmrx-light.png create mode 100644 apps/v4/public/presets/AbZIu0W-dark.png create mode 100644 apps/v4/public/presets/AbZIu0W-light.png create mode 100644 apps/v4/public/presets/AcRnsyu-dark.png create mode 100644 apps/v4/public/presets/AcRnsyu-light.png create mode 100644 apps/v4/public/presets/AuFzoPZ-dark.png create mode 100644 apps/v4/public/presets/AuFzoPZ-light.png create mode 100644 apps/v4/public/presets/Aumd2e-dark.png create mode 100644 apps/v4/public/presets/Aumd2e-light.png create mode 100644 apps/v4/public/presets/AvM5aK-dark.png create mode 100644 apps/v4/public/presets/AvM5aK-light.png create mode 100644 apps/v4/scripts/capture-explore.mts diff --git a/apps/v4/app/(app)/(root)/explore/copy-preset-button.tsx b/apps/v4/app/(app)/(root)/explore/copy-preset-button.tsx new file mode 100644 index 000000000..71fa22a74 --- /dev/null +++ b/apps/v4/app/(app)/(root)/explore/copy-preset-button.tsx @@ -0,0 +1,31 @@ +"use client" + +import * as React from "react" + +import { Badge } from "@/examples/radix/ui/badge" +import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard" + +export function CopyPresetButton({ code }: { code: string }) { + const { copyToClipboard, isCopied } = useCopyToClipboard() + const presetValue = `--preset ${code}` + + return ( + + + + ) +} diff --git a/apps/v4/app/(app)/(root)/explore/page.tsx b/apps/v4/app/(app)/(root)/explore/page.tsx new file mode 100644 index 000000000..d09f138f2 --- /dev/null +++ b/apps/v4/app/(app)/(root)/explore/page.tsx @@ -0,0 +1,71 @@ +import { type Metadata } from "next" +import Image from "next/image" +import Link from "next/link" +import { CopyPresetButton } from "./copy-preset-button" +import { decodePreset } from "shadcn/preset" + +import { EXPLORE_PRESETS } from "@/lib/explore" + +export const dynamic = "force-static" +export const revalidate = false + +const title = "Explore" +const description = + "Browse curated design system presets. Pick one and make it your own." + +export const metadata: Metadata = { + title, + description, +} + +export default function ExplorePage() { + const presets = EXPLORE_PRESETS.map((code) => ({ + code, + config: decodePreset(code), + })).filter( + (p): p is { code: string; config: NonNullable } => + p.config !== null + ) + + return ( +
+
+
+ {presets.map(({ code, config }) => ( + +
+
+
+ +
+
+ {`${config.style} + {`${config.style} +
+
+ + ))} +
+
+
+ ) +} diff --git a/apps/v4/app/(create)/components/random-button.tsx b/apps/v4/app/(create)/components/random-button.tsx index f6d5279c1..e91290d1b 100644 --- a/apps/v4/app/(create)/components/random-button.tsx +++ b/apps/v4/app/(create)/components/random-button.tsx @@ -41,10 +41,6 @@ export function RandomButton() { const [params, setParams] = useDesignSystemSearchParams() const handleRandomize = React.useCallback(() => { - // Use current value if locked, otherwise randomize. - const baseColor = locks.has("baseColor") - ? params.baseColor - : randomItem(BASE_COLORS).name const selectedStyle = locks.has("style") ? params.style : randomItem(STYLES).name @@ -52,9 +48,18 @@ export function RandomButton() { // Build context for bias application. const context: RandomizeContext = { style: selectedStyle, - baseColor, } + const availableBaseColors = applyBias( + BASE_COLORS, + context, + RANDOMIZE_BIASES.baseColors + ) + const baseColor = locks.has("baseColor") + ? params.baseColor + : randomItem(availableBaseColors).name + context.baseColor = baseColor + const availableThemes = getThemesForBaseColor(baseColor) const availableFonts = applyBias(FONTS, context, RANDOMIZE_BIASES.fonts) const availableRadii = applyBias(RADII, context, RANDOMIZE_BIASES.radius) diff --git a/apps/v4/app/(create)/lib/randomize-biases.ts b/apps/v4/app/(create)/lib/randomize-biases.ts index c6505b73b..de04164bf 100644 --- a/apps/v4/app/(create)/lib/randomize-biases.ts +++ b/apps/v4/app/(create)/lib/randomize-biases.ts @@ -1,4 +1,5 @@ import type { + BaseColor, BaseColorName, Radius, StyleName, @@ -24,11 +25,11 @@ export type BiasFilter = ( ) => readonly T[] export type RandomizeBiases = { + baseColors?: BiasFilter fonts?: BiasFilter<(typeof FONTS)[number]> radius?: BiasFilter // Add more bias filters as needed: // styles?: BiasFilter