├── app ├── favicon.ico ├── twitter-image.png ├── opengraph-image.png ├── robots.txt ├── sitemap.ts ├── blocks │ └── preview │ │ └── [blockId] │ │ └── page.tsx ├── (blocks) │ └── layout.tsx └── demo │ └── page.tsx ├── content ├── components │ ├── onboarding │ │ └── index.ts │ ├── command-menu │ │ └── index.ts │ ├── grid-list │ │ ├── index.ts │ │ └── grid-list-02.tsx │ ├── ai │ │ └── index.ts │ ├── tables │ │ └── index.ts │ ├── form-layout │ │ └── index.tsx │ ├── index.ts │ ├── sidebar │ │ ├── index.tsx │ │ ├── sidebar-06 │ │ │ └── app │ │ │ │ └── page.tsx │ │ ├── sidebar-05 │ │ │ └── app │ │ │ │ └── page.tsx │ │ ├── sidebar-02 │ │ │ ├── index.tsx │ │ │ ├── logo.tsx │ │ │ └── nav-notifications.tsx │ │ ├── sidebar-03 │ │ │ ├── index.tsx │ │ │ ├── logo.tsx │ │ │ └── nav-notifications.tsx │ │ ├── sidebar-01 │ │ │ ├── index.tsx │ │ │ ├── nav-main.tsx │ │ │ └── types.ts │ │ └── sidebar-04 │ │ │ ├── mail-context.tsx │ │ │ └── app │ │ │ └── page.tsx │ ├── file-upload │ │ ├── index.ts │ │ ├── file-upload-01 │ │ │ ├── file-list.tsx │ │ │ ├── dropzone.tsx │ │ │ ├── file-item.tsx │ │ │ └── form.tsx │ │ └── file-upload-02.tsx │ ├── login │ │ ├── index.ts │ │ └── login-03.tsx │ ├── dialogs │ │ ├── index.ts │ │ ├── dialog-04.tsx │ │ ├── dialog-01.tsx │ │ ├── dialog-03.tsx │ │ ├── dialog-02.tsx │ │ ├── dialog-05.tsx │ │ └── dialog-06.tsx │ └── stats │ │ ├── index.ts │ │ ├── stats-15.tsx │ │ ├── stats-09.tsx │ │ ├── stats-03.tsx │ │ ├── stats-01.tsx │ │ ├── stats-05.tsx │ │ └── stats-04.tsx ├── markdown │ ├── form-layout │ │ └── index.mdx │ ├── sidebar │ │ └── index.mdx │ ├── stats │ │ ├── stats-15.mdx │ │ ├── stats-09.mdx │ │ ├── stats-03.mdx │ │ ├── stats-01.mdx │ │ ├── stats-05.mdx │ │ └── stats-04.mdx │ ├── dialogs │ │ ├── dialog-04.mdx │ │ ├── dialog-01.mdx │ │ ├── dialog-03.mdx │ │ ├── dialog-02.mdx │ │ ├── dialog-05.mdx │ │ └── dialog-06.mdx │ ├── grid-list │ │ └── grid-list-02.mdx │ ├── file-upload │ │ └── file-upload-02.mdx │ └── login │ │ └── login-03.mdx └── declarations.ts ├── public ├── avatar-01.png ├── avatar-02.jpg ├── avatar-03.png ├── avatar-04.jpg ├── font │ └── font-medium.otf ├── vercel.svg ├── window.svg ├── file.svg ├── manifest.webmanifest ├── writer.svg ├── writer-solid.svg ├── globe.svg ├── next.svg └── r │ ├── stats-15.json │ ├── dialog-04.json │ ├── stats-09.json │ ├── dialog-01.json │ ├── dialog-03.json │ ├── stats-03.json │ ├── dialog-02.json │ ├── stats-01.json │ ├── stats-05.json │ ├── grid-list-02.json │ └── file-upload-02.json ├── lib ├── resolve-theme.ts ├── utils.ts └── highlight-code.ts ├── postcss.config.mjs ├── biome.jsonc ├── components ├── ui │ ├── aspect-ratio.tsx │ ├── skeleton.tsx │ ├── spinner.tsx │ ├── label.tsx │ ├── separator.tsx │ ├── textarea.tsx │ ├── mdx.tsx │ ├── progress.tsx │ ├── collapsible.tsx │ ├── kbd.tsx │ ├── input.tsx │ ├── sonner.tsx │ ├── switch.tsx │ ├── avatar.tsx │ ├── checkbox.tsx │ ├── radio-group.tsx │ ├── hover-card.tsx │ ├── toggle.tsx │ ├── badge.tsx │ ├── popover.tsx │ ├── alert.tsx │ ├── scroll-area.tsx │ ├── tooltip.tsx │ ├── tabs.tsx │ ├── resizable.tsx │ ├── slider.tsx │ ├── accordion.tsx │ ├── button.tsx │ ├── card.tsx │ ├── button-group.tsx │ ├── input-otp.tsx │ ├── toggle-group.tsx │ ├── breadcrumb.tsx │ └── empty.tsx ├── breadcrumb-jsonld.tsx ├── tailwind-indicator.tsx ├── add-command.tsx ├── open-in-v0-button.tsx ├── single-file-code-view.tsx ├── footer.tsx ├── header.tsx └── icons.tsx ├── components.json ├── hooks ├── use-mobile.ts └── use-copy.ts ├── config.ts ├── next.config.ts ├── .gitignore ├── tsconfig.json ├── LICENSE.md ├── README.md └── scripts ├── lib └── types.ts └── generate-rss.ts /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /content/components/onboarding/index.ts: -------------------------------------------------------------------------------- 1 | export { Onboarding01 } from "./onboarding-01"; 2 | -------------------------------------------------------------------------------- /app/twitter-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/app/twitter-image.png -------------------------------------------------------------------------------- /public/avatar-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/public/avatar-01.png -------------------------------------------------------------------------------- /public/avatar-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/public/avatar-02.jpg -------------------------------------------------------------------------------- /public/avatar-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/public/avatar-03.png -------------------------------------------------------------------------------- /public/avatar-04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/public/avatar-04.jpg -------------------------------------------------------------------------------- /app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/app/opengraph-image.png -------------------------------------------------------------------------------- /lib/resolve-theme.ts: -------------------------------------------------------------------------------- 1 | export function resolveTheme(_theme?: string): "light" { 2 | return "light"; 3 | } 4 | -------------------------------------------------------------------------------- /public/font/font-medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ephraimduncan/blocks/HEAD/public/font/font-medium.otf -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/2.1.2/schema.json", 3 | "extends": [ 4 | "ultracite" 5 | ] 6 | } -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | Disallow: /private/ 4 | Disallow: /blocks/preview/ 5 | Disallow: /demo/ 6 | 7 | Sitemap: https://blocks.so/sitemap.xml 8 | -------------------------------------------------------------------------------- /content/components/command-menu/index.ts: -------------------------------------------------------------------------------- 1 | export { CommandMenu01 } from './command-menu-01'; 2 | export { CommandMenu02 } from './command-menu-02'; 3 | export { CommandMenu03 } from './command-menu-03'; 4 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /content/components/grid-list/index.ts: -------------------------------------------------------------------------------- 1 | export { default as GridList01 } from "./grid-list-01"; 2 | export { default as GridList02 } from "./grid-list-02"; 3 | export { default as GridList03 } from "./grid-list-03"; 4 | -------------------------------------------------------------------------------- /content/components/ai/index.ts: -------------------------------------------------------------------------------- 1 | // Export your components here 2 | export { default as Ai01 } from "./ai-01"; 3 | export { default as Ai02 } from "./ai-02"; 4 | export { default as Ai03 } from "./ai-03"; 5 | export { default as Ai04 } from "./ai-04"; 6 | -------------------------------------------------------------------------------- /content/components/tables/index.ts: -------------------------------------------------------------------------------- 1 | // Export your components here 2 | export { default as Table01 } from "./table-01"; 3 | export { default as Table02 } from "./table-02"; 4 | export { default as Table03 } from "./table-03"; 5 | export { default as Table04 } from "./table-04"; 6 | export { default as Table05 } from "./table-05"; 7 | -------------------------------------------------------------------------------- /content/components/form-layout/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as FormLayout01 } from "./form-layout-01"; 2 | export { default as FormLayout02 } from "./form-layout-02"; 3 | export { default as FormLayout03 } from "./form-layout-03"; 4 | export { default as FormLayout04 } from "./form-layout-04"; 5 | export { default as FormLayout05 } from "./form-layout-05"; 6 | -------------------------------------------------------------------------------- /components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 4 | 5 | function AspectRatio({ 6 | ...props 7 | }: React.ComponentProps) { 8 | return 9 | } 10 | 11 | export { AspectRatio } 12 | -------------------------------------------------------------------------------- /components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<"div">) { 4 | return ( 5 |
10 | ) 11 | } 12 | 13 | export { Skeleton } 14 | -------------------------------------------------------------------------------- /content/markdown/form-layout/index.mdx: -------------------------------------------------------------------------------- 1 | ````tsx 2 | export { default as FormLayout01 } from "./form-layout-01"; 3 | export { default as FormLayout02 } from "./form-layout-02"; 4 | export { default as FormLayout03 } from "./form-layout-03"; 5 | export { default as FormLayout04 } from "./form-layout-04"; 6 | export { default as FormLayout05 } from "./form-layout-05"; 7 | ```` -------------------------------------------------------------------------------- /content/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./command-menu"; 2 | export * from "./dialogs"; 3 | export * from "./file-upload"; 4 | export * from "./form-layout"; 5 | export * from "./grid-list"; 6 | export * from "./login"; 7 | export * from "./sidebar"; 8 | export * from "./stats"; 9 | export * from "./ai"; 10 | export * from "./tables"; 11 | export * from "./onboarding"; 12 | -------------------------------------------------------------------------------- /public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /content/components/sidebar/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as Sidebar01 } from "./sidebar-01"; 2 | export { default as Sidebar02 } from "./sidebar-02"; 3 | export { default as Sidebar03 } from "./sidebar-03"; 4 | export { default as Sidebar04 } from "./sidebar-04/app/page"; 5 | export { default as Sidebar05 } from "./sidebar-05/app/page"; 6 | export { default as Sidebar06 } from "./sidebar-06/app/page"; 7 | -------------------------------------------------------------------------------- /public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /content/components/sidebar/sidebar-06/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { SidebarProvider } from "@/components/ui/sidebar"; 4 | import { AppSidebar } from "../app-sidebar"; 5 | 6 | export default function Page() { 7 | return ( 8 | 9 |
10 | 11 |
12 |
13 | ); 14 | } -------------------------------------------------------------------------------- /content/components/sidebar/sidebar-05/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { SidebarProvider } from "@/components/ui/sidebar"; 4 | import { AppSidebar } from "../app-sidebar"; 5 | 6 | export default function Page() { 7 | return ( 8 | 9 |
10 | 11 |
12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /content/components/file-upload/index.ts: -------------------------------------------------------------------------------- 1 | export { default as FileUpload01 } from "./file-upload-01"; 2 | export { default as FileUpload02 } from "./file-upload-02"; 3 | export { default as FileUpload03 } from "./file-upload-03"; 4 | export { default as FileUpload04 } from "./file-upload-04"; 5 | export { default as FileUpload05 } from "./file-upload-05"; 6 | export { default as FileUpload06 } from "./file-upload-06"; 7 | -------------------------------------------------------------------------------- /content/markdown/sidebar/index.mdx: -------------------------------------------------------------------------------- 1 | ````tsx 2 | export { default as Sidebar01 } from "./sidebar-01"; 3 | export { default as Sidebar02 } from "./sidebar-02"; 4 | export { default as Sidebar03 } from "./sidebar-03"; 5 | export { default as Sidebar04 } from "./sidebar-04/app/page"; 6 | export { default as Sidebar05 } from "./sidebar-05/app/page"; 7 | export { default as Sidebar06 } from "./sidebar-06/app/page"; 8 | ```` -------------------------------------------------------------------------------- /public/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blocks.so — Building Blocks for the Web", 3 | "short_name": "blocks.so", 4 | "start_url": "/", 5 | "display": "standalone", 6 | "background_color": "#000000", 7 | "theme_color": "#000000", 8 | "icons": [ 9 | { 10 | "src": "/favicon.ico", 11 | "sizes": "32x32 48x48 64x64", 12 | "type": "image/x-icon" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /components/ui/spinner.tsx: -------------------------------------------------------------------------------- 1 | import { Loader2Icon } from "lucide-react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | function Spinner({ className, ...props }: React.ComponentProps<"svg">) { 6 | return ( 7 | 13 | ) 14 | } 15 | 16 | export { Spinner } 17 | -------------------------------------------------------------------------------- /public/writer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /content/components/sidebar/sidebar-02/index.tsx: -------------------------------------------------------------------------------- 1 | import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; 2 | import { DashboardSidebar } from "./app-sidebar"; 3 | 4 | export default function Sidebar02() { 5 | return ( 6 | 7 |
8 | 9 | 10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /content/components/sidebar/sidebar-03/index.tsx: -------------------------------------------------------------------------------- 1 | import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; 2 | import { DashboardSidebar } from "./app-sidebar"; 3 | 4 | export default function Sidebar03() { 5 | return ( 6 | 7 |
8 | 9 | 10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /content/components/login/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Login01 } from "./login-01"; 2 | export { default as Login02 } from "./login-02"; 3 | export { default as Login03 } from "./login-03"; 4 | export { default as Login04 } from "./login-04"; 5 | export { default as Login05 } from "./login-05"; 6 | export { default as Login06 } from "./login-06"; 7 | export { default as Login07 } from "./login-07"; 8 | export { default as Login08 } from "./login-08"; 9 | export { default as Login09 } from "./login-09"; 10 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } 22 | -------------------------------------------------------------------------------- /app/sitemap.ts: -------------------------------------------------------------------------------- 1 | import type { MetadataRoute } from "next"; 2 | 3 | import { blocksCategoriesMetadata } from "@/content/blocks-categories"; 4 | 5 | export default function sitemap(): MetadataRoute.Sitemap { 6 | const home = { 7 | url: "https://blocks.so", 8 | lastModified: new Date(), 9 | changeFrequency: "weekly" as const, 10 | priority: 1, 11 | }; 12 | 13 | const blocksPages = blocksCategoriesMetadata.map((category) => ({ 14 | url: `https://blocks.so/${category.id}`, 15 | lastModified: new Date(), 16 | changeFrequency: "weekly" as const, 17 | priority: 0.8, 18 | })); 19 | 20 | return [home, ...blocksPages]; 21 | } 22 | -------------------------------------------------------------------------------- /hooks/use-mobile.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | const MOBILE_BREAKPOINT = 768 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState(undefined) 7 | 8 | React.useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 | } 13 | mql.addEventListener("change", onChange) 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 | return () => mql.removeEventListener("change", onChange) 16 | }, []) 17 | 18 | return !!isMobile 19 | } 20 | -------------------------------------------------------------------------------- /public/writer-solid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /config.ts: -------------------------------------------------------------------------------- 1 | export const siteConfig = { 2 | name: "blocks.so", 3 | url: "https://blocks.so", 4 | ogImage: "https://blocks.so/opengraph-image.png", 5 | description: 6 | "Free shadcn/ui blocks and components built with React, Tailwind CSS, and Next.js. Copy and paste 60+ beautifully designed, accessible UI blocks into your projects. Open source forever.", 7 | links: { 8 | website: "https://ephraimduncan.com?utm_source=blocks.so", 9 | twitter: "https://twitter.com/ephraimduncan_?utm_source=blocks.so", 10 | github: "https://github.com/ephraimduncan/blocks?utm_source=blocks.so", 11 | }, 12 | }; 13 | 14 | export type SiteConfig = typeof siteConfig; 15 | -------------------------------------------------------------------------------- /content/components/dialogs/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Dialog01 } from "./dialog-01"; 2 | export { default as Dialog02 } from "./dialog-02"; 3 | export { default as Dialog03 } from "./dialog-03"; 4 | export { default as Dialog04 } from "./dialog-04"; 5 | export { default as Dialog05 } from "./dialog-05"; 6 | export { default as Dialog06 } from "./dialog-06"; 7 | export { default as Dialog07 } from "./dialog-07"; 8 | export { default as Dialog08 } from "./dialog-08"; 9 | export { default as Dialog09 } from "./dialog-09"; 10 | export { default as Dialog10 } from "./dialog-10"; 11 | export { default as Dialog11 } from "./dialog-11"; 12 | export { default as Dialog12 } from "./dialog-12"; 13 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | transpilePackages: ["next-mdx-remote"], 5 | async redirects() { 6 | return [ 7 | // Redirect common OG image paths that crawlers might try 8 | { 9 | source: "/og", 10 | destination: "/opengraph-image.png", 11 | permanent: true, 12 | }, 13 | { 14 | source: "/og.png", 15 | destination: "/opengraph-image.png", 16 | permanent: true, 17 | }, 18 | { 19 | source: "/og-image", 20 | destination: "/opengraph-image.png", 21 | permanent: true, 22 | }, 23 | ]; 24 | }, 25 | }; 26 | 27 | export default nextConfig; 28 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | function Label({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ) 22 | } 23 | 24 | export { Label } 25 | -------------------------------------------------------------------------------- /content/components/sidebar/sidebar-01/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | SidebarInset, 3 | SidebarProvider, 4 | SidebarTrigger, 5 | } from "@/components/ui/sidebar"; 6 | import { AppSidebar } from "./app-sidebar"; 7 | 8 | export default function Sidebar01() { 9 | return ( 10 | 11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 |
19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /components/breadcrumb-jsonld.tsx: -------------------------------------------------------------------------------- 1 | import { siteConfig } from "@/config"; 2 | 3 | type BreadcrumbItem = { 4 | name: string; 5 | path?: string; 6 | }; 7 | 8 | type BreadcrumbJsonLdProps = { 9 | items: BreadcrumbItem[]; 10 | }; 11 | 12 | export function BreadcrumbJsonLd({ items }: BreadcrumbJsonLdProps) { 13 | const data = { 14 | "@context": "https://schema.org", 15 | "@type": "BreadcrumbList", 16 | itemListElement: items.map((item, index) => ({ 17 | "@type": "ListItem", 18 | position: index + 1, 19 | name: item.name, 20 | item: item.path ? `${siteConfig.url}${item.path}` : siteConfig.url, 21 | })), 22 | }; 23 | 24 | return ( 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /components/tailwind-indicator.tsx: -------------------------------------------------------------------------------- 1 | export function TailwindIndicator() { 2 | if (process.env.NODE_ENV === "production") { 3 | return null; 4 | } 5 | 6 | return ( 7 |
11 |
xs
12 |
sm
13 |
md
14 |
lg
15 |
xl
16 |
2xl
17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /content/declarations.ts: -------------------------------------------------------------------------------- 1 | export type BlocksCategoryMetadata = { 2 | id: string; 3 | name: string; 4 | thumbnail?: string; 5 | thumbnailCustomClasses?: string; 6 | count: string; 7 | hasCharts?: boolean; 8 | }; 9 | 10 | export type BlocksMetadata = { 11 | id: string; 12 | category: string; 13 | name: string; 14 | iframeHeight?: string; 15 | type: "file" | "directory"; 16 | }; 17 | 18 | export const categoryIds: { [key: string]: string } = { 19 | FileUpload: "file-upload", 20 | FormLayout: "form-layout", 21 | Login: "login", 22 | Stats: "stats", 23 | GridList: "grid-list", 24 | Dialogs: "dialogs", 25 | Sidebar: "sidebar", 26 | CommandMenu: "command-menu", 27 | 28 | AI: "ai", 29 | Tables: "tables", 30 | Onboarding: "onboarding", 31 | }; 32 | -------------------------------------------------------------------------------- /content/components/stats/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Stats01 } from "./stats-01"; 2 | export { default as Stats02 } from "./stats-02"; 3 | export { default as Stats03 } from "./stats-03"; 4 | export { default as Stats04 } from "./stats-04"; 5 | export { default as Stats05 } from "./stats-05"; 6 | export { default as Stats06 } from "./stats-06"; 7 | export { default as Stats07 } from "./stats-07"; 8 | export { default as Stats08 } from "./stats-08"; 9 | export { default as Stats09 } from "./stats-09"; 10 | export { default as Stats10 } from "./stats-10"; 11 | export { default as Stats11 } from "./stats-11"; 12 | export { default as Stats12 } from "./stats-12"; 13 | export { default as Stats13 } from "./stats-13"; 14 | export { Stats14 } from "./stats-14"; 15 | export { Stats15 } from "./stats-15"; 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | 43 | # generated files 44 | /.component-sources 45 | content/index.ts 46 | 47 | # AI 48 | .claude 49 | .cursor 50 | .vscode 51 | CLAUDE.md 52 | -------------------------------------------------------------------------------- /hooks/use-copy.ts: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | 5 | export function useCopyToClipboard({ 6 | timeout = 2000, 7 | onCopy, 8 | }: { 9 | timeout?: number 10 | onCopy?: () => void 11 | } = {}) { 12 | const [isCopied, setIsCopied] = React.useState(false) 13 | 14 | const copyToClipboard = (value: string) => { 15 | if (typeof window === "undefined" || !navigator.clipboard.writeText) { 16 | return 17 | } 18 | 19 | if (!value) return 20 | 21 | navigator.clipboard.writeText(value).then(() => { 22 | setIsCopied(true) 23 | 24 | if (onCopy) { 25 | onCopy() 26 | } 27 | 28 | setTimeout(() => { 29 | setIsCopied(false) 30 | }, timeout) 31 | }, console.error) 32 | } 33 | 34 | return { isCopied, copyToClipboard } 35 | } -------------------------------------------------------------------------------- /components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SeparatorPrimitive from "@radix-ui/react-separator" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | function Separator({ 9 | className, 10 | orientation = "horizontal", 11 | decorative = true, 12 | ...props 13 | }: React.ComponentProps) { 14 | return ( 15 | 25 | ) 26 | } 27 | 28 | export { Separator } 29 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { 6 | return ( 7 |