Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
891818443a | ||
|
|
532d8e692c | ||
|
|
e45833b5f2 | ||
|
|
dffa6cef34 | ||
|
|
04407e9cb5 | ||
|
|
9f0e37d8c3 | ||
|
|
bf18ef7a35 | ||
|
|
edda5a41b8 | ||
|
|
320885b073 | ||
|
|
d97b670580 | ||
|
|
b8ecd6c408 | ||
|
|
4086d54305 | ||
|
|
6831117b97 | ||
|
|
6ea1042d44 | ||
|
|
d9f090bb53 | ||
|
|
e1184390dc | ||
|
|
a42e158a07 | ||
|
|
6347fe0aeb | ||
|
|
f08abfe55a | ||
|
|
fbe58782d9 | ||
|
|
16ffaea878 | ||
|
|
a4f1a1c16f | ||
|
|
8ed0e27d73 | ||
|
|
9958dde439 | ||
|
|
e64e9cdbdc | ||
|
|
095773b2da | ||
|
|
926985e5ad | ||
|
|
24ace5354a | ||
|
|
412ee93a25 | ||
|
|
751111a0d7 | ||
|
|
8dab1688f7 | ||
|
|
7887485e95 | ||
|
|
3e1283365a | ||
|
|
8919c32d0f | ||
|
|
be95271bc4 | ||
|
|
f2752141ff | ||
|
|
b6311022f3 | ||
|
|
07f1182d52 | ||
|
|
bacd545b67 | ||
|
|
d95693b61a | ||
|
|
dce79e1309 |
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git push:*)",
|
||||
"Bash(pnpm registry:build:*)",
|
||||
"Bash(pnpm build:*)",
|
||||
"Bash(pnpm add:*)",
|
||||
"Bash(pnpm dev)",
|
||||
"Bash(jq:*)",
|
||||
"Bash(curl:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
name: NPM Publish
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -78,7 +82,7 @@ jobs:
|
||||
|
||||
- name: Bump version and publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_CONFIG_PROVENANCE: true
|
||||
run: |
|
||||
# Set up npm and pnpm auth
|
||||
|
||||
@@ -57,8 +57,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
@@ -48,6 +48,7 @@ jobs:
|
||||
run: pnpm build
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
NEXT_PUBLIC_APP_URL: https://ui.hanzo.ai
|
||||
|
||||
- name: Run component health check
|
||||
run: pnpm health-check
|
||||
|
||||
@@ -78,3 +78,5 @@ playwright-report/
|
||||
.fleet
|
||||
|
||||
.notes
|
||||
.claude/settings.local.json
|
||||
pkg/ui/dist-test/
|
||||
|
||||
+430
-8
File diff suppressed because one or more lines are too long
+12
-5
@@ -1,8 +1,15 @@
|
||||
// @ts-nocheck
|
||||
import { dynamic } from '@hanzo/docs-mdx/runtime/dynamic';
|
||||
import * as Config from '../source.config';
|
||||
import { dynamic } from "@hanzo/docs-mdx/runtime/dynamic"
|
||||
|
||||
const create = await dynamic<typeof Config, import("@hanzo/docs-mdx/runtime/types").InternalTypeConfig & {
|
||||
DocData: {
|
||||
import * as Config from "../source.config"
|
||||
|
||||
const create = await dynamic<
|
||||
typeof Config,
|
||||
import("@hanzo/docs-mdx/runtime/types").InternalTypeConfig & {
|
||||
DocData: {}
|
||||
}
|
||||
}>(Config, {"configPath":"source.config.ts","environment":"next","outDir":".docs"}, {"doc":{"passthroughs":["extractedReferences"]}});
|
||||
>(
|
||||
Config,
|
||||
{ configPath: "source.config.ts", environment: "next", outDir: ".docs" },
|
||||
{ doc: { passthroughs: ["extractedReferences"] } }
|
||||
)
|
||||
|
||||
+388
-192
File diff suppressed because one or more lines are too long
@@ -203,6 +203,17 @@ export const Index: Record<string, any> = {
|
||||
subcategory: "undefined",
|
||||
chunks: []
|
||||
},
|
||||
"direction": {
|
||||
name: "direction",
|
||||
type: "components:ui",
|
||||
registryDependencies: undefined,
|
||||
component: React.lazy(() => import("@/registry/default/ui/direction")),
|
||||
source: "",
|
||||
files: ["registry/default/ui/direction.tsx"],
|
||||
category: "undefined",
|
||||
subcategory: "undefined",
|
||||
chunks: []
|
||||
},
|
||||
"dialog": {
|
||||
name: "dialog",
|
||||
type: "components:ui",
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* docs-no-404.test.ts
|
||||
*
|
||||
* Static validation: every URL in docs.ts config has a matching MDX file.
|
||||
* No server needed — runs in CI before deployment.
|
||||
*
|
||||
* Run: pnpm test (via vitest)
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
const CONTENT_DIR = path.resolve(__dirname, '../content/docs')
|
||||
const CONFIG_PATH = path.resolve(__dirname, '../config/docs.ts')
|
||||
|
||||
/** Extract all href values from docs.ts config */
|
||||
function extractUrlsFromConfig(): string[] {
|
||||
const content = fs.readFileSync(CONFIG_PATH, 'utf-8')
|
||||
const hrefRegex = /href:\s*["'`]([^"'`]+)["'`]/g
|
||||
const urls: string[] = []
|
||||
let match
|
||||
while ((match = hrefRegex.exec(content)) !== null) {
|
||||
urls.push(match[1])
|
||||
}
|
||||
return urls.filter(u => u.startsWith('/docs'))
|
||||
}
|
||||
|
||||
/** Convert a /docs/... URL to its expected MDX file path */
|
||||
function urlToMdxPath(url: string): string[] {
|
||||
// /docs -> index.mdx
|
||||
// /docs/charts/bar -> charts/bar.mdx OR charts/bar/index.mdx
|
||||
const slug = url.replace(/^\/docs\/?/, '') || ''
|
||||
if (!slug) {
|
||||
return [path.join(CONTENT_DIR, 'index.mdx')]
|
||||
}
|
||||
return [
|
||||
path.join(CONTENT_DIR, `${slug}.mdx`),
|
||||
path.join(CONTENT_DIR, slug, 'index.mdx'),
|
||||
]
|
||||
}
|
||||
|
||||
/** Recursively find all MDX files in content/docs */
|
||||
function findAllMdxFiles(dir: string, prefix = ''): string[] {
|
||||
const results: string[] = []
|
||||
if (!fs.existsSync(dir)) return results
|
||||
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const fullPath = path.join(dir, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
results.push(...findAllMdxFiles(fullPath, `${prefix}${entry.name}/`))
|
||||
} else if (entry.name.endsWith('.mdx')) {
|
||||
const slug = entry.name === 'index.mdx'
|
||||
? prefix.replace(/\/$/, '')
|
||||
: `${prefix}${entry.name.replace('.mdx', '')}`
|
||||
if (slug) {
|
||||
results.push(`/docs/${slug}`)
|
||||
} else {
|
||||
results.push('/docs')
|
||||
}
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
describe('Documentation pages — zero 404s', () => {
|
||||
const configUrls = extractUrlsFromConfig()
|
||||
const mdxPages = findAllMdxFiles(CONTENT_DIR)
|
||||
|
||||
it('should find docs config with URLs', () => {
|
||||
expect(configUrls.length).toBeGreaterThan(100)
|
||||
})
|
||||
|
||||
it('should find MDX content files', () => {
|
||||
expect(mdxPages.length).toBeGreaterThan(100)
|
||||
})
|
||||
|
||||
describe('every config URL has a matching MDX file', () => {
|
||||
for (const url of configUrls) {
|
||||
it(`${url}`, () => {
|
||||
const possiblePaths = urlToMdxPath(url)
|
||||
const exists = possiblePaths.some(p => fs.existsSync(p))
|
||||
if (!exists) {
|
||||
throw new Error(
|
||||
`Missing MDX file for ${url}. Expected one of:\n` +
|
||||
possiblePaths.map(p => ` - ${p}`).join('\n')
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('every MDX file is reachable from config', () => {
|
||||
const configSet = new Set(configUrls)
|
||||
const unreachable: string[] = []
|
||||
|
||||
for (const page of mdxPages) {
|
||||
if (!configSet.has(page)) {
|
||||
unreachable.push(page)
|
||||
}
|
||||
}
|
||||
|
||||
it('should have no orphaned MDX files (or document known exceptions)', () => {
|
||||
// Allow a small number of known orphans (category index pages, etc.)
|
||||
const KNOWN_ORPHANS = new Set([
|
||||
'/docs/ai/voice-settings',
|
||||
'/docs/components/animation-components',
|
||||
])
|
||||
const unexpected = unreachable.filter(u => !KNOWN_ORPHANS.has(u))
|
||||
if (unexpected.length > 0) {
|
||||
console.warn(`Orphaned MDX files (not in nav config):\n${unexpected.map(u => ` ${u}`).join('\n')}`)
|
||||
}
|
||||
// Warn but don't fail for orphans — they just won't be in nav
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('summary: config URLs vs MDX files', () => {
|
||||
const configSet = new Set(configUrls)
|
||||
const mdxSet = new Set(mdxPages)
|
||||
|
||||
const missingMdx = configUrls.filter(u => {
|
||||
const paths = urlToMdxPath(u)
|
||||
return !paths.some(p => fs.existsSync(p))
|
||||
})
|
||||
const orphanedMdx = mdxPages.filter(p => !configSet.has(p))
|
||||
|
||||
console.log(`\n📊 Docs coverage report:`)
|
||||
console.log(` Config URLs: ${configUrls.length}`)
|
||||
console.log(` MDX files: ${mdxPages.length}`)
|
||||
console.log(` Missing MDX: ${missingMdx.length}`)
|
||||
console.log(` Orphaned: ${orphanedMdx.length}`)
|
||||
|
||||
if (missingMdx.length > 0) {
|
||||
console.error(`\n❌ URLs with no MDX file:\n${missingMdx.map(u => ` ${u}`).join('\n')}`)
|
||||
}
|
||||
if (orphanedMdx.length > 0) {
|
||||
console.warn(`\n⚠️ MDX files not in nav:\n${orphanedMdx.map(u => ` ${u}`).join('\n')}`)
|
||||
}
|
||||
|
||||
// This is the hard check — every config URL must have content
|
||||
expect(missingMdx).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -1,8 +1,9 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { AlertCircle, RefreshCw } from "lucide-react"
|
||||
import { Index } from "@/__registry__"
|
||||
import { AlertCircle, RefreshCw } from "lucide-react"
|
||||
|
||||
import { Badge } from "@/registry/default/ui/badge"
|
||||
import { Button } from "@/registry/default/ui/button"
|
||||
import { Card } from "@/registry/default/ui/card"
|
||||
@@ -64,24 +65,21 @@ function BlockPreview({ blockName }: { blockName: string }) {
|
||||
setState({ loaded: true, error: true, showContent: true })
|
||||
}, [])
|
||||
|
||||
const handleRetry = React.useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setState({ loaded: false, error: false, showContent: false })
|
||||
if (iframeRef.current) {
|
||||
// Force reload by resetting src
|
||||
const src = iframeRef.current.src
|
||||
iframeRef.current.src = ""
|
||||
setTimeout(() => {
|
||||
if (iframeRef.current) {
|
||||
iframeRef.current.src = src
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
const handleRetry = React.useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setState({ loaded: false, error: false, showContent: false })
|
||||
if (iframeRef.current) {
|
||||
// Force reload by resetting src
|
||||
const src = iframeRef.current.src
|
||||
iframeRef.current.src = ""
|
||||
setTimeout(() => {
|
||||
if (iframeRef.current) {
|
||||
iframeRef.current.src = src
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
@@ -92,7 +90,10 @@ function BlockPreview({ blockName }: { blockName: string }) {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="relative aspect-[4/3] min-h-[400px] bg-muted/50">
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative aspect-[4/3] min-h-[400px] bg-muted/50"
|
||||
>
|
||||
{/* Loading skeleton */}
|
||||
{!state.showContent && (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
@@ -273,15 +274,14 @@ export default function BuilderPage() {
|
||||
<h3 className="text-base font-semibold leading-tight">
|
||||
{blockName}
|
||||
</h3>
|
||||
{block?.category &&
|
||||
block?.category !== "undefined" && (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="shrink-0 text-xs font-medium"
|
||||
>
|
||||
{block.category}
|
||||
</Badge>
|
||||
)}
|
||||
{block?.category && block?.category !== "undefined" && (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="shrink-0 text-xs font-medium"
|
||||
>
|
||||
{block.category}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{block?.subcategory &&
|
||||
block?.subcategory !== "undefined" && (
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import Link from "next/link"
|
||||
import { notFound } from "next/navigation"
|
||||
import { mdxComponents } from "@/mdx-components"
|
||||
import { findNeighbour } from "@hanzo/docs-core/page-tree"
|
||||
import {
|
||||
IconArrowLeft,
|
||||
IconArrowRight,
|
||||
IconArrowUpRight,
|
||||
} from "@tabler/icons-react"
|
||||
import { findNeighbour } from "@hanzo/docs-core/page-tree"
|
||||
|
||||
import { source } from "@/lib/source"
|
||||
import { absoluteUrl } from "@/lib/utils"
|
||||
|
||||
+5
-5
@@ -2,11 +2,6 @@ import "@/styles/globals.css"
|
||||
|
||||
import { Metadata, Viewport } from "next"
|
||||
|
||||
const META_THEME_COLORS = {
|
||||
light: "white",
|
||||
dark: "black",
|
||||
}
|
||||
|
||||
import { siteConfig } from "@/config/site"
|
||||
import { fontMono, fontSans } from "@/lib/fonts"
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -23,6 +18,11 @@ import {
|
||||
Toaster as NewYorkToaster,
|
||||
} from "@/registry/default/ui/toaster"
|
||||
|
||||
const META_THEME_COLORS = {
|
||||
light: "white",
|
||||
dark: "black",
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
default: siteConfig.name,
|
||||
|
||||
@@ -222,7 +222,11 @@ function BlockViewerToolbar({ styleName }: { styleName: Style["name"] }) {
|
||||
}}
|
||||
title="Copy install command"
|
||||
>
|
||||
{isCopied ? <Check className="!h-3.5 !w-3.5" /> : <Clipboard className="!h-3.5 !w-3.5" />}
|
||||
{isCopied ? (
|
||||
<Check className="!h-3.5 !w-3.5" />
|
||||
) : (
|
||||
<Clipboard className="!h-3.5 !w-3.5" />
|
||||
)}
|
||||
<span className="sr-only">Copy install command</span>
|
||||
</Button>
|
||||
<Separator orientation="vertical" className="mx-1 !h-4" />
|
||||
|
||||
@@ -97,6 +97,82 @@ export const docsConfig: DocsConfig = {
|
||||
href: "/docs/changelog",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "MCP Server",
|
||||
href: "/docs/mcp",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "About",
|
||||
href: "/docs/about",
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Installation",
|
||||
items: [
|
||||
{
|
||||
title: "Next.js",
|
||||
href: "/docs/installation/next",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Vite",
|
||||
href: "/docs/installation/vite",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Remix",
|
||||
href: "/docs/installation/remix",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Astro",
|
||||
href: "/docs/installation/astro",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Gatsby",
|
||||
href: "/docs/installation/gatsby",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Laravel",
|
||||
href: "/docs/installation/laravel",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Manual",
|
||||
href: "/docs/installation/manual",
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Dark Mode",
|
||||
items: [
|
||||
{
|
||||
title: "Next.js",
|
||||
href: "/docs/dark-mode/next",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Vite",
|
||||
href: "/docs/dark-mode/vite",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Remix",
|
||||
href: "/docs/dark-mode/remix",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Astro",
|
||||
href: "/docs/dark-mode/astro",
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -143,6 +219,12 @@ export const docsConfig: DocsConfig = {
|
||||
href: "/docs/components/button",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Button Group",
|
||||
href: "/docs/components/button-group",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Calendar",
|
||||
href: "/docs/components/calendar",
|
||||
@@ -188,6 +270,30 @@ export const docsConfig: DocsConfig = {
|
||||
href: "/docs/components/data-table",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Desktop",
|
||||
href: "/docs/components/desktop",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Desktop Hooks",
|
||||
href: "/docs/components/desktop-hooks",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Desktop Spotlight",
|
||||
href: "/docs/components/desktop-spotlight",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Desktop Window",
|
||||
href: "/docs/components/desktop-window",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Date Picker",
|
||||
href: "/docs/components/date-picker",
|
||||
@@ -198,6 +304,12 @@ export const docsConfig: DocsConfig = {
|
||||
href: "/docs/components/dialog",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Direction",
|
||||
href: "/docs/components/direction",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Drawer",
|
||||
href: "/docs/components/drawer",
|
||||
@@ -208,6 +320,18 @@ export const docsConfig: DocsConfig = {
|
||||
href: "/docs/components/dropdown-menu",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Empty State",
|
||||
href: "/docs/components/empty",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Field",
|
||||
href: "/docs/components/field",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Form",
|
||||
href: "/docs/components/form",
|
||||
@@ -223,12 +347,24 @@ export const docsConfig: DocsConfig = {
|
||||
href: "/docs/components/input",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Input Group",
|
||||
href: "/docs/components/input-group",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Input OTP",
|
||||
href: "/docs/components/input-otp",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Item",
|
||||
href: "/docs/components/item",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Label",
|
||||
href: "/docs/components/label",
|
||||
@@ -613,6 +749,24 @@ export const docsConfig: DocsConfig = {
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Particles Background",
|
||||
href: "/docs/components/particles-background",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Grid Pattern",
|
||||
href: "/docs/components/grid-pattern",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Timeline",
|
||||
href: "/docs/components/timeline",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Pin List",
|
||||
href: "/docs/components/pin-list",
|
||||
@@ -1028,6 +1182,18 @@ export const docsConfig: DocsConfig = {
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "AI Code",
|
||||
href: "/docs/ai/code",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "AI Voice",
|
||||
href: "/docs/ai/voice",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -1174,6 +1340,40 @@ export const docsConfig: DocsConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Guides",
|
||||
items: [
|
||||
{
|
||||
title: "Page Builder",
|
||||
href: "/docs/guides/page-builder",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Visual Workflows",
|
||||
href: "/docs/guides/visual-workflows",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Hanzo React",
|
||||
items: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
href: "/docs/hanzo-react/getting-started",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "Hooks",
|
||||
href: "/docs/hanzo-react/hooks",
|
||||
items: [],
|
||||
label: "New",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Packages",
|
||||
items: [
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Contact Forms
|
||||
description: Contact form sections with validation, multiple fields, and submission handling.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Contact form blocks provide complete form layouts for collecting user inquiries. They include input validation, loading states, and success confirmation.
|
||||
|
||||
## Features
|
||||
|
||||
- **Form Validation**: Built-in HTML5 and custom validation
|
||||
- **Multiple Fields**: Name, email, subject, and message inputs
|
||||
- **Loading States**: Visual feedback during form submission
|
||||
- **Success Message**: Confirmation after successful submission
|
||||
- **Responsive Design**: Adapts to all screen sizes
|
||||
- **Accessible**: Semantic form elements with proper labels
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import ContactBlock from "@/registry/default/block/contact"
|
||||
|
||||
export default function Page() {
|
||||
return <ContactBlock />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: CTA Sections
|
||||
description: Call-to-action sections for driving user conversions and signups.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
CTA (Call-to-Action) blocks are designed to drive user engagement and conversions. They feature prominent buttons, compelling copy, and focused layouts that guide users toward a specific action.
|
||||
|
||||
## Features
|
||||
|
||||
- **Conversion-Focused**: Designed to maximize click-through rates
|
||||
- **Responsive Design**: Adapts to all screen sizes
|
||||
- **Multiple Layouts**: Centered, split, and banner variations
|
||||
- **Button Variants**: Primary, secondary, and ghost CTA styles
|
||||
- **Background Options**: Solid colors, gradients, and image backgrounds
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import CTABlock from "@/registry/default/block/cta"
|
||||
|
||||
export default function Page() {
|
||||
return <CTABlock />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: FAQ Sections
|
||||
description: Frequently asked questions sections with expandable accordions and search.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
FAQ blocks present commonly asked questions in organized, expandable layouts. They use accordion patterns for progressive disclosure and optional search filtering.
|
||||
|
||||
## Features
|
||||
|
||||
- **Accordion Layout**: Expandable question/answer pairs
|
||||
- **Search Filtering**: Optional search to find specific questions
|
||||
- **Categories**: Group questions by topic
|
||||
- **Responsive**: Full-width layout that works on all devices
|
||||
- **Accessible**: Keyboard navigation and screen reader support
|
||||
- **Animated**: Smooth expand/collapse transitions
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import FAQBlock from "@/registry/default/block/faq"
|
||||
|
||||
export default function Page() {
|
||||
return <FAQBlock />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Feature Sections
|
||||
description: Feature grid and list sections for highlighting product capabilities.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Feature blocks display product capabilities in organized grid or list layouts. They combine icons, headings, and descriptions to communicate value propositions clearly.
|
||||
|
||||
## Features
|
||||
|
||||
- **Grid Layouts**: 2, 3, or 4 column responsive grids
|
||||
- **Icon Support**: Lucide icons or custom SVGs
|
||||
- **Responsive**: Stacks to single column on mobile
|
||||
- **Customizable**: Flexible content and styling options
|
||||
- **Accessible**: Semantic HTML with proper heading hierarchy
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import FeaturesBlock from "@/registry/default/block/features"
|
||||
|
||||
export default function Page() {
|
||||
return <FeaturesBlock />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Hero Sections
|
||||
description: Full-width hero sections for landing pages with headlines, CTAs, and imagery.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Hero blocks are viewport-sized sections designed for the top of landing pages. They feature bold typography, call-to-action buttons, and visual elements to capture user attention.
|
||||
|
||||
## Variations
|
||||
|
||||
### App UI Showcase
|
||||
|
||||
<ComponentPreview name="showcase-app-ui-01" />
|
||||
|
||||
A hero section showcasing your app's UI with a centered layout and product screenshot.
|
||||
|
||||
### E-commerce Showcase
|
||||
|
||||
<ComponentPreview name="showcase-ecommerce-01" />
|
||||
|
||||
A hero section designed for e-commerce with product imagery and shopping CTAs.
|
||||
|
||||
### Marketing Showcase
|
||||
|
||||
<ComponentPreview name="showcase-marketing-01" />
|
||||
|
||||
A bold marketing hero section with large typography and conversion-focused design.
|
||||
|
||||
## Features
|
||||
|
||||
- **Responsive Design**: Adapts to all screen sizes
|
||||
- **CTA Buttons**: Primary and secondary call-to-action buttons
|
||||
- **Visual Elements**: Support for images, gradients, and animations
|
||||
- **Typography**: Large, bold headlines with supporting text
|
||||
- **Customizable**: Easy to modify colors, text, and layout
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Stats Sections
|
||||
description: Statistics and metrics sections with counters, charts, and key figures.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Stats blocks display key metrics and achievements in visually impactful layouts. They feature animated counters, comparison figures, and trend indicators.
|
||||
|
||||
## Features
|
||||
|
||||
- **Animated Counters**: Number animations on scroll into view
|
||||
- **Multiple Layouts**: Grid, inline, and featured stat variations
|
||||
- **Trend Indicators**: Up/down arrows with percentage changes
|
||||
- **Responsive**: Adapts from multi-column to single column on mobile
|
||||
- **Icons**: Support for metric-specific icons
|
||||
- **Customizable**: Easy to update values and labels
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import StatsBlock from "@/registry/default/block/stats"
|
||||
|
||||
export default function Page() {
|
||||
return <StatsBlock />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Team Sections
|
||||
description: Team member grid and list sections with photos, roles, and social links.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Team blocks showcase team members with profile photos, names, roles, and social links. They support multiple layout variations for different page contexts.
|
||||
|
||||
## Features
|
||||
|
||||
- **Grid Layout**: Responsive grid with team member cards
|
||||
- **Profile Photos**: Avatar images with fallback initials
|
||||
- **Role Display**: Job titles and department labels
|
||||
- **Social Links**: GitHub, Twitter, LinkedIn integration
|
||||
- **Responsive**: Adapts columns based on screen size
|
||||
- **Hover Effects**: Interactive card hover states
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import TeamBlock from "@/registry/default/block/team"
|
||||
|
||||
export default function Page() {
|
||||
return <TeamBlock />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Testimonials
|
||||
description: Testimonial sections with user quotes, ratings, and social proof.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Testimonial blocks display customer reviews and social proof in visually appealing layouts. They support avatars, star ratings, company logos, and quote formatting.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multiple Layouts**: Grid, carousel, and featured testimonial styles
|
||||
- **Avatar Support**: User photos with name and title
|
||||
- **Star Ratings**: Visual rating display
|
||||
- **Company Logos**: Brand association for B2B testimonials
|
||||
- **Responsive**: Adapts from multi-column to single column on mobile
|
||||
- **Animated**: Optional entrance animations and carousel transitions
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import TestimonialsBlock from "@/registry/default/block/testimonials"
|
||||
|
||||
export default function Page() {
|
||||
return <TestimonialsBlock />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: Area Chart
|
||||
description: Area charts for visualizing trends and cumulative values over time.
|
||||
---
|
||||
|
||||
<ComponentPreview name="chart-demo" description="Area chart example" />
|
||||
|
||||
## Overview
|
||||
|
||||
Area charts are used to show trends over time or across categories. They combine line charts with filled areas beneath the line to emphasize volume.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
|
||||
|
||||
const data = [
|
||||
{ month: "Jan", desktop: 186, mobile: 80 },
|
||||
{ month: "Feb", desktop: 305, mobile: 200 },
|
||||
{ month: "Mar", desktop: 237, mobile: 120 },
|
||||
]
|
||||
|
||||
const config = {
|
||||
desktop: { label: "Desktop", color: "hsl(var(--chart-1))" },
|
||||
mobile: { label: "Mobile", color: "hsl(var(--chart-2))" },
|
||||
}
|
||||
|
||||
export function AreaChartDemo() {
|
||||
return (
|
||||
<ChartContainer config={config}>
|
||||
<AreaChart data={data}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis dataKey="month" />
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Area
|
||||
dataKey="desktop"
|
||||
fill="var(--color-desktop)"
|
||||
stroke="var(--color-desktop)"
|
||||
/>
|
||||
<Area
|
||||
dataKey="mobile"
|
||||
fill="var(--color-mobile)"
|
||||
stroke="var(--color-mobile)"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
### Stacked Area
|
||||
|
||||
Stack multiple areas to show cumulative totals.
|
||||
|
||||
### Gradient Fill
|
||||
|
||||
Apply gradient fills for visual depth.
|
||||
|
||||
### Step Area
|
||||
|
||||
Use `type="step"` for discrete step transitions.
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Bar Chart
|
||||
description: Bar charts for comparing categorical data and distributions.
|
||||
---
|
||||
|
||||
<ComponentPreview name="chart-demo" description="Bar chart example" />
|
||||
|
||||
## Overview
|
||||
|
||||
Bar charts display data with rectangular bars proportional to their values. They are ideal for comparing quantities across categories.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"
|
||||
|
||||
const data = [
|
||||
{ month: "Jan", desktop: 186 },
|
||||
{ month: "Feb", desktop: 305 },
|
||||
{ month: "Mar", desktop: 237 },
|
||||
]
|
||||
|
||||
const config = {
|
||||
desktop: { label: "Desktop", color: "hsl(var(--chart-1))" },
|
||||
}
|
||||
|
||||
export function BarChartDemo() {
|
||||
return (
|
||||
<ChartContainer config={config}>
|
||||
<BarChart data={data}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis dataKey="month" />
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
### Horizontal Bar
|
||||
|
||||
Use `layout="vertical"` for horizontal orientation.
|
||||
|
||||
### Stacked Bar
|
||||
|
||||
Stack multiple bars to show composition within categories.
|
||||
|
||||
### Mixed Bar
|
||||
|
||||
Combine different bar styles and data series.
|
||||
|
||||
### With Labels
|
||||
|
||||
Add data labels directly on bars using custom label components.
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: Charts
|
||||
description: Beautiful, composable chart components built on Recharts.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
@hanzo/ui provides a set of chart components built on top of [Recharts](https://recharts.org/). The chart components are designed to be composable and work with Tailwind CSS theming.
|
||||
|
||||
## Installation
|
||||
|
||||
<Tabs defaultValue="cli">
|
||||
|
||||
<TabsList>
|
||||
<TabsTrigger value="cli">CLI</TabsTrigger>
|
||||
<TabsTrigger value="manual">Manual</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="cli">
|
||||
|
||||
```bash
|
||||
npx @hanzo/ui@latest add chart
|
||||
```
|
||||
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="manual">
|
||||
|
||||
<Steps>
|
||||
|
||||
<Step>Install recharts:</Step>
|
||||
|
||||
```bash
|
||||
pnpm add recharts
|
||||
```
|
||||
|
||||
<Step>Copy the chart components into your project.</Step>
|
||||
|
||||
<ComponentSource name="chart" />
|
||||
|
||||
</Steps>
|
||||
|
||||
</TabsContent>
|
||||
|
||||
</Tabs>
|
||||
|
||||
## Components
|
||||
|
||||
The chart package includes the following components:
|
||||
|
||||
- **ChartContainer** - Responsive container that handles theming and sizing
|
||||
- **ChartTooltip** - Styled tooltip component
|
||||
- **ChartTooltipContent** - Content renderer for tooltips
|
||||
- **ChartLegend** - Chart legend component
|
||||
- **ChartLegendContent** - Content renderer for legends
|
||||
|
||||
## Chart Types
|
||||
|
||||
- [Area Chart](/docs/charts/area) - For showing trends over time
|
||||
- [Bar Chart](/docs/charts/bar) - For comparing categorical data
|
||||
- [Line Chart](/docs/charts/line) - For showing continuous data
|
||||
- [Pie Chart](/docs/charts/pie) - For showing proportional data
|
||||
- [Radar Chart](/docs/charts/radar) - For multivariate data comparison
|
||||
- [Radial Chart](/docs/charts/radial) - For circular data visualization
|
||||
- [Tooltip](/docs/charts/tooltip) - Shared tooltip component
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
import { Bar, BarChart, XAxis } from "recharts"
|
||||
|
||||
const data = [
|
||||
{ month: "Jan", value: 186 },
|
||||
{ month: "Feb", value: 305 },
|
||||
{ month: "Mar", value: 237 },
|
||||
]
|
||||
|
||||
const config = {
|
||||
value: { label: "Value", color: "hsl(var(--chart-1))" },
|
||||
}
|
||||
|
||||
export function MyChart() {
|
||||
return (
|
||||
<ChartContainer config={config}>
|
||||
<BarChart data={data}>
|
||||
<XAxis dataKey="month" />
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Bar dataKey="value" fill="var(--color-value)" />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Theming
|
||||
|
||||
Charts use CSS variables for theming. Define chart colors in your CSS:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: Line Chart
|
||||
description: Line charts for showing continuous data trends and comparisons.
|
||||
---
|
||||
|
||||
<ComponentPreview name="chart-demo" description="Line chart example" />
|
||||
|
||||
## Overview
|
||||
|
||||
Line charts connect data points with straight or curved lines, ideal for showing trends and changes over continuous intervals.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
import { CartesianGrid, Line, LineChart, XAxis } from "recharts"
|
||||
|
||||
const data = [
|
||||
{ month: "Jan", desktop: 186, mobile: 80 },
|
||||
{ month: "Feb", desktop: 305, mobile: 200 },
|
||||
{ month: "Mar", desktop: 237, mobile: 120 },
|
||||
]
|
||||
|
||||
const config = {
|
||||
desktop: { label: "Desktop", color: "hsl(var(--chart-1))" },
|
||||
mobile: { label: "Mobile", color: "hsl(var(--chart-2))" },
|
||||
}
|
||||
|
||||
export function LineChartDemo() {
|
||||
return (
|
||||
<ChartContainer config={config}>
|
||||
<LineChart data={data}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis dataKey="month" />
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Line dataKey="desktop" stroke="var(--color-desktop)" strokeWidth={2} />
|
||||
<Line dataKey="mobile" stroke="var(--color-mobile)" strokeWidth={2} />
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
### With Dots
|
||||
|
||||
Show data point markers on the line.
|
||||
|
||||
### Custom Dots
|
||||
|
||||
Use custom shapes for data point markers.
|
||||
|
||||
### Linear vs Curved
|
||||
|
||||
Toggle between `type="linear"` and `type="monotone"` interpolation.
|
||||
|
||||
### Interactive
|
||||
|
||||
Add hover interactions and clickable data points.
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: Pie Chart
|
||||
description: Pie and donut charts for showing proportional data and distributions.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Pie charts display data as proportional slices of a circle, ideal for showing parts of a whole.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
import { Pie, PieChart } from "recharts"
|
||||
|
||||
const data = [
|
||||
{ browser: "Chrome", visitors: 275, fill: "var(--color-chrome)" },
|
||||
{ browser: "Safari", visitors: 200, fill: "var(--color-safari)" },
|
||||
{ browser: "Firefox", visitors: 187, fill: "var(--color-firefox)" },
|
||||
]
|
||||
|
||||
const config = {
|
||||
chrome: { label: "Chrome", color: "hsl(var(--chart-1))" },
|
||||
safari: { label: "Safari", color: "hsl(var(--chart-2))" },
|
||||
firefox: { label: "Firefox", color: "hsl(var(--chart-3))" },
|
||||
}
|
||||
|
||||
export function PieChartDemo() {
|
||||
return (
|
||||
<ChartContainer config={config}>
|
||||
<PieChart>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Pie data={data} dataKey="visitors" nameKey="browser" />
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
### Donut Chart
|
||||
|
||||
Use `innerRadius` and `outerRadius` to create donut charts.
|
||||
|
||||
### With Labels
|
||||
|
||||
Add labels inside or outside slices.
|
||||
|
||||
### Interactive
|
||||
|
||||
Highlight slices on hover with `activeIndex`.
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Radar Chart
|
||||
description: Radar charts for multivariate data comparison and analysis.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Radar charts display multivariate data on axes starting from the same point, useful for comparing multiple quantitative variables.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts"
|
||||
|
||||
const data = [
|
||||
{ subject: "Math", A: 120, B: 110 },
|
||||
{ subject: "Chinese", A: 98, B: 130 },
|
||||
{ subject: "English", A: 86, B: 130 },
|
||||
{ subject: "Geography", A: 99, B: 100 },
|
||||
{ subject: "Physics", A: 85, B: 90 },
|
||||
{ subject: "History", A: 65, B: 85 },
|
||||
]
|
||||
|
||||
const config = {
|
||||
A: { label: "Student A", color: "hsl(var(--chart-1))" },
|
||||
B: { label: "Student B", color: "hsl(var(--chart-2))" },
|
||||
}
|
||||
|
||||
export function RadarChartDemo() {
|
||||
return (
|
||||
<ChartContainer config={config}>
|
||||
<RadarChart data={data}>
|
||||
<PolarGrid />
|
||||
<PolarAngleAxis dataKey="subject" />
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<Radar dataKey="A" fill="var(--color-A)" fillOpacity={0.6} />
|
||||
<Radar dataKey="B" fill="var(--color-B)" fillOpacity={0.6} />
|
||||
</RadarChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
### Filled Radar
|
||||
|
||||
Use `fillOpacity` to create filled radar areas.
|
||||
|
||||
### Multiple Series
|
||||
|
||||
Compare multiple datasets on the same radar.
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: Radial Chart
|
||||
description: Radial bar charts for circular data visualization and progress indicators.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Radial charts display data in a circular layout, useful for progress indicators, gauges, and circular comparisons.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
import { RadialBar, RadialBarChart } from "recharts"
|
||||
|
||||
const data = [
|
||||
{ name: "Chrome", visitors: 275, fill: "var(--color-chrome)" },
|
||||
{ name: "Safari", visitors: 200, fill: "var(--color-safari)" },
|
||||
{ name: "Firefox", visitors: 187, fill: "var(--color-firefox)" },
|
||||
]
|
||||
|
||||
const config = {
|
||||
chrome: { label: "Chrome", color: "hsl(var(--chart-1))" },
|
||||
safari: { label: "Safari", color: "hsl(var(--chart-2))" },
|
||||
firefox: { label: "Firefox", color: "hsl(var(--chart-3))" },
|
||||
}
|
||||
|
||||
export function RadialChartDemo() {
|
||||
return (
|
||||
<ChartContainer config={config}>
|
||||
<RadialBarChart data={data} innerRadius={30} outerRadius={110}>
|
||||
<ChartTooltip content={<ChartTooltipContent />} />
|
||||
<RadialBar dataKey="visitors" />
|
||||
</RadialBarChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
### Stacked Radial
|
||||
|
||||
Stack multiple radial bars concentrically.
|
||||
|
||||
### With Labels
|
||||
|
||||
Add labels to radial segments for clarity.
|
||||
|
||||
### Progress Gauge
|
||||
|
||||
Use a single radial bar as a progress or gauge indicator.
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: Chart Tooltip
|
||||
description: Customizable tooltip component for all chart types.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The chart tooltip component provides a consistent, themed tooltip across all chart types. It integrates with the chart config system for automatic label and color resolution.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { ChartTooltip, ChartTooltipContent } from "@hanzo/ui"
|
||||
|
||||
// Inside any chart component:
|
||||
;<ChartTooltip content={<ChartTooltipContent />} />
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
### ChartTooltipContent
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ------------- | --------------------------- | ------- | ------------------------- |
|
||||
| hideLabel | boolean | false | Hide the label in tooltip |
|
||||
| hideIndicator | boolean | false | Hide the color indicator |
|
||||
| indicator | "line" \| "dot" \| "dashed" | "dot" | Indicator style |
|
||||
| nameKey | string | - | Key for item names |
|
||||
| labelKey | string | - | Key for labels |
|
||||
|
||||
## Customization
|
||||
|
||||
### Custom Formatter
|
||||
|
||||
```tsx
|
||||
<ChartTooltip
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
formatter={(value, name) => (
|
||||
<span>
|
||||
{name}: ${value.toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom Label
|
||||
|
||||
```tsx
|
||||
<ChartTooltip
|
||||
content={<ChartTooltipContent labelFormatter={(label) => `Date: ${label}`} />}
|
||||
/>
|
||||
```
|
||||
|
||||
## Indicator Styles
|
||||
|
||||
- **dot** - Small colored circle (default)
|
||||
- **line** - Colored line indicator
|
||||
- **dashed** - Dashed line indicator
|
||||
@@ -63,18 +63,28 @@ function Desktop() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => windows.openWindow('Settings')}>Open Settings</button>
|
||||
<button onClick={() => windows.toggleWindow('Terminal')}>Toggle Terminal</button>
|
||||
<button onClick={() => windows.openWindow("Settings")}>
|
||||
Open Settings
|
||||
</button>
|
||||
<button onClick={() => windows.toggleWindow("Terminal")}>
|
||||
Toggle Terminal
|
||||
</button>
|
||||
<button onClick={() => windows.closeAllWindows()}>Close All</button>
|
||||
|
||||
{windows.isOpen('Settings') && (
|
||||
<Window title="Settings" onClose={() => windows.closeWindow('Settings')}>
|
||||
{windows.isOpen("Settings") && (
|
||||
<Window
|
||||
title="Settings"
|
||||
onClose={() => windows.closeWindow("Settings")}
|
||||
>
|
||||
...
|
||||
</Window>
|
||||
)}
|
||||
|
||||
{windows.isOpen('Terminal') && (
|
||||
<Window title="Terminal" onClose={() => windows.closeWindow('Terminal')}>
|
||||
{windows.isOpen("Terminal") && (
|
||||
<Window
|
||||
title="Terminal"
|
||||
onClose={() => windows.closeWindow("Terminal")}
|
||||
>
|
||||
...
|
||||
</Window>
|
||||
)}
|
||||
@@ -85,17 +95,17 @@ function Desktop() {
|
||||
|
||||
#### API
|
||||
|
||||
| Method | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `isOpen` | `(id: string) => boolean` | Check if a window is open |
|
||||
| `openWindow` | `(id: string) => void` | Open a window |
|
||||
| `closeWindow` | `(id: string) => void` | Close a window |
|
||||
| `toggleWindow` | `(id: string) => void` | Toggle a window's open state |
|
||||
| `closeAllWindows` | `() => void` | Close all windows |
|
||||
| `focusWindow` | `(id: string) => void` | Focus/activate a window |
|
||||
| `activeWindow` | `string \| null` | Currently active window |
|
||||
| `openWindows` | `string[]` | List of all open window IDs |
|
||||
| `windows` | `Record<string, boolean>` | Window state map |
|
||||
| Method | Type | Description |
|
||||
| ----------------- | ------------------------- | ---------------------------- |
|
||||
| `isOpen` | `(id: string) => boolean` | Check if a window is open |
|
||||
| `openWindow` | `(id: string) => void` | Open a window |
|
||||
| `closeWindow` | `(id: string) => void` | Close a window |
|
||||
| `toggleWindow` | `(id: string) => void` | Toggle a window's open state |
|
||||
| `closeAllWindows` | `() => void` | Close all windows |
|
||||
| `focusWindow` | `(id: string) => void` | Focus/activate a window |
|
||||
| `activeWindow` | `string \| null` | Currently active window |
|
||||
| `openWindows` | `string[]` | List of all open window IDs |
|
||||
| `windows` | `Record<string, boolean>` | Window state map |
|
||||
|
||||
---
|
||||
|
||||
@@ -150,23 +160,23 @@ function SettingsPanel() {
|
||||
|
||||
#### API
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `theme` | `'light' \| 'dark' \| 'system'` | Current theme |
|
||||
| `setTheme` | `(theme) => void` | Set theme |
|
||||
| `colorScheme` | `string` | Color scheme name |
|
||||
| `setColorScheme` | `(scheme) => void` | Set color scheme |
|
||||
| `showDock` | `boolean` | Whether dock is visible |
|
||||
| `setShowDock` | `(show) => void` | Toggle dock visibility |
|
||||
| `dockPosition` | `'bottom' \| 'left' \| 'right'` | Dock position |
|
||||
| `setDockPosition` | `(position) => void` | Set dock position |
|
||||
| `dockMagnification` | `boolean` | Dock magnification enabled |
|
||||
| `setDockMagnification` | `(enabled) => void` | Toggle magnification |
|
||||
| `fontSize` | `number` | Base font size |
|
||||
| `setFontSize` | `(size) => void` | Set font size |
|
||||
| `windowTransparency` | `number` | Window transparency (0-1) |
|
||||
| `setWindowTransparency` | `(opacity) => void` | Set transparency |
|
||||
| `resetToDefaults` | `() => void` | Reset all settings |
|
||||
| Property | Type | Description |
|
||||
| ----------------------- | ------------------------------- | -------------------------- |
|
||||
| `theme` | `'light' \| 'dark' \| 'system'` | Current theme |
|
||||
| `setTheme` | `(theme) => void` | Set theme |
|
||||
| `colorScheme` | `string` | Color scheme name |
|
||||
| `setColorScheme` | `(scheme) => void` | Set color scheme |
|
||||
| `showDock` | `boolean` | Whether dock is visible |
|
||||
| `setShowDock` | `(show) => void` | Toggle dock visibility |
|
||||
| `dockPosition` | `'bottom' \| 'left' \| 'right'` | Dock position |
|
||||
| `setDockPosition` | `(position) => void` | Set dock position |
|
||||
| `dockMagnification` | `boolean` | Dock magnification enabled |
|
||||
| `setDockMagnification` | `(enabled) => void` | Toggle magnification |
|
||||
| `fontSize` | `number` | Base font size |
|
||||
| `setFontSize` | `(size) => void` | Set font size |
|
||||
| `windowTransparency` | `number` | Window transparency (0-1) |
|
||||
| `setWindowTransparency` | `(opacity) => void` | Set transparency |
|
||||
| `resetToDefaults` | `() => void` | Reset all settings |
|
||||
|
||||
---
|
||||
|
||||
@@ -182,20 +192,18 @@ function Desktop() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => overlays.open('spotlight')}>
|
||||
<button onClick={() => overlays.open("spotlight")}>
|
||||
Open Spotlight (⌘+Space)
|
||||
</button>
|
||||
|
||||
<button onClick={() => overlays.open('about')}>
|
||||
About This Mac
|
||||
</button>
|
||||
<button onClick={() => overlays.open("about")}>About This Mac</button>
|
||||
|
||||
{overlays.isOpen('spotlight') && (
|
||||
<Spotlight onClose={() => overlays.close('spotlight')} />
|
||||
{overlays.isOpen("spotlight") && (
|
||||
<Spotlight onClose={() => overlays.close("spotlight")} />
|
||||
)}
|
||||
|
||||
{overlays.isOpen('about') && (
|
||||
<AboutDialog onClose={() => overlays.close('about')} />
|
||||
{overlays.isOpen("about") && (
|
||||
<AboutDialog onClose={() => overlays.close("about")} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
@@ -204,14 +212,14 @@ function Desktop() {
|
||||
|
||||
#### API
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `overlays` | `OverlayState` | Current overlay states |
|
||||
| `isOpen` | `(id: string) => boolean` | Check if an overlay is open |
|
||||
| `open` | `(id: string) => void` | Open an overlay by id |
|
||||
| `close` | `(id: string) => void` | Close an overlay by id |
|
||||
| `toggle` | `(id: string) => void` | Toggle an overlay |
|
||||
| `closeAll` | `() => void` | Close all overlays |
|
||||
| Property | Type | Description |
|
||||
| ---------- | ------------------------- | --------------------------- |
|
||||
| `overlays` | `OverlayState` | Current overlay states |
|
||||
| `isOpen` | `(id: string) => boolean` | Check if an overlay is open |
|
||||
| `open` | `(id: string) => void` | Open an overlay by id |
|
||||
| `close` | `(id: string) => void` | Close an overlay by id |
|
||||
| `toggle` | `(id: string) => void` | Toggle an overlay |
|
||||
| `closeAll` | `() => void` | Close all overlays |
|
||||
|
||||
Built-in overlay IDs: `spotlight`, `contextMenu`, `modal`, `drawer`
|
||||
|
||||
@@ -259,29 +267,29 @@ function Desktop() {
|
||||
|
||||
#### Shortcut Definition
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `key` | `string` | Key to listen for |
|
||||
| `meta` | `boolean` | Require ⌘ (Mac) / Ctrl (Windows) |
|
||||
| `alt` | `boolean` | Require Alt/Option |
|
||||
| `shift` | `boolean` | Require Shift |
|
||||
| `ctrl` | `boolean` | Require Control |
|
||||
| `action` | `() => void` | Callback when triggered |
|
||||
| Property | Type | Description |
|
||||
| -------- | ------------ | -------------------------------- |
|
||||
| `key` | `string` | Key to listen for |
|
||||
| `meta` | `boolean` | Require ⌘ (Mac) / Ctrl (Windows) |
|
||||
| `alt` | `boolean` | Require Alt/Option |
|
||||
| `shift` | `boolean` | Require Shift |
|
||||
| `ctrl` | `boolean` | Require Control |
|
||||
| `action` | `() => void` | Callback when triggered |
|
||||
|
||||
## Complete Example
|
||||
|
||||
```tsx
|
||||
import {
|
||||
Window,
|
||||
Spotlight,
|
||||
useWindowManager,
|
||||
useDesktopSettings,
|
||||
useKeyboardShortcuts,
|
||||
useOverlayManager,
|
||||
useKeyboardShortcuts
|
||||
useWindowManager,
|
||||
Window,
|
||||
} from "@hanzo/ui/desktop"
|
||||
import { Dock, DockItem } from "@hanzo/ui/dock"
|
||||
|
||||
const apps = ['Finder', 'Terminal', 'Safari', 'Mail', 'Calendar', 'Settings']
|
||||
const apps = ["Finder", "Terminal", "Safari", "Mail", "Calendar", "Settings"]
|
||||
|
||||
export function Desktop() {
|
||||
const windows = useWindowManager()
|
||||
@@ -290,9 +298,9 @@ export function Desktop() {
|
||||
|
||||
// Register keyboard shortcuts
|
||||
useKeyboardShortcuts([
|
||||
{ key: ' ', meta: true, action: overlays.openSpotlight },
|
||||
{ key: 'q', meta: true, action: () => windows.close(windows.activeWindow) },
|
||||
{ key: ',', meta: true, action: () => windows.open('Settings') },
|
||||
{ key: " ", meta: true, action: overlays.openSpotlight },
|
||||
{ key: "q", meta: true, action: () => windows.close(windows.activeWindow) },
|
||||
{ key: ",", meta: true, action: () => windows.open("Settings") },
|
||||
])
|
||||
|
||||
return (
|
||||
@@ -300,33 +308,36 @@ export function Desktop() {
|
||||
className="h-screen w-screen relative"
|
||||
style={{
|
||||
opacity: settings.windowTransparency,
|
||||
fontSize: settings.fontSize
|
||||
fontSize: settings.fontSize,
|
||||
}}
|
||||
>
|
||||
{/* Desktop Background */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500 to-purple-600" />
|
||||
|
||||
{/* Windows */}
|
||||
{apps.map(app => windows.isOpen(app) && (
|
||||
<Window
|
||||
key={app}
|
||||
title={app}
|
||||
onClose={() => windows.close(app)}
|
||||
windowType={settings.theme === 'dark' ? 'dark' : 'default'}
|
||||
>
|
||||
<div className="p-4">{app} content</div>
|
||||
</Window>
|
||||
))}
|
||||
{apps.map(
|
||||
(app) =>
|
||||
windows.isOpen(app) && (
|
||||
<Window
|
||||
key={app}
|
||||
title={app}
|
||||
onClose={() => windows.close(app)}
|
||||
windowType={settings.theme === "dark" ? "dark" : "default"}
|
||||
>
|
||||
<div className="p-4">{app} content</div>
|
||||
</Window>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* Spotlight */}
|
||||
{overlays.spotlight && (
|
||||
<Spotlight
|
||||
isOpen={true}
|
||||
onClose={overlays.closeSpotlight}
|
||||
items={apps.map(app => ({
|
||||
items={apps.map((app) => ({
|
||||
id: app.toLowerCase(),
|
||||
label: app,
|
||||
category: 'Applications'
|
||||
category: "Applications",
|
||||
}))}
|
||||
onSelect={(item) => {
|
||||
windows.open(item.label)
|
||||
@@ -341,7 +352,7 @@ export function Desktop() {
|
||||
position={settings.dockPosition}
|
||||
magnification={settings.dockMagnification ? 60 : 0}
|
||||
>
|
||||
{apps.map(app => (
|
||||
{apps.map((app) => (
|
||||
<DockItem
|
||||
key={app}
|
||||
tooltip={app}
|
||||
|
||||
@@ -57,9 +57,19 @@ npm install framer-motion lucide-react
|
||||
import { Spotlight, SpotlightItem } from "@hanzo/ui/desktop"
|
||||
|
||||
const items: SpotlightItem[] = [
|
||||
{ id: 'settings', title: 'Settings', category: 'Applications', icon: <Settings /> },
|
||||
{ id: 'documents', title: 'Documents', category: 'Folders', icon: <Folder /> },
|
||||
{ id: 'music', title: 'Music', category: 'Applications', icon: <Music /> },
|
||||
{
|
||||
id: "settings",
|
||||
title: "Settings",
|
||||
category: "Applications",
|
||||
icon: <Settings />,
|
||||
},
|
||||
{
|
||||
id: "documents",
|
||||
title: "Documents",
|
||||
category: "Folders",
|
||||
icon: <Folder />,
|
||||
},
|
||||
{ id: "music", title: "Music", category: "Applications", icon: <Music /> },
|
||||
]
|
||||
|
||||
export function SpotlightDemo() {
|
||||
@@ -74,7 +84,7 @@ export function SpotlightDemo() {
|
||||
onClose={() => setIsOpen(false)}
|
||||
items={items}
|
||||
onSelect={(item) => {
|
||||
console.log('Selected:', item)
|
||||
console.log("Selected:", item)
|
||||
setIsOpen(false)
|
||||
}}
|
||||
/>
|
||||
@@ -87,25 +97,25 @@ export function SpotlightDemo() {
|
||||
|
||||
### Spotlight
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `isOpen` | `boolean` | - | Controls visibility of the spotlight dialog |
|
||||
| `onClose` | `() => void` | - | Callback when spotlight is closed |
|
||||
| `items` | `SpotlightItem[]` | - | Array of searchable items |
|
||||
| `onSelect` | `(item: SpotlightItem) => void` | - | Callback when an item is selected |
|
||||
| `placeholder` | `string` | `'Search...'` | Search input placeholder text |
|
||||
| Prop | Type | Default | Description |
|
||||
| ------------- | ------------------------------- | ------------- | ------------------------------------------- |
|
||||
| `isOpen` | `boolean` | - | Controls visibility of the spotlight dialog |
|
||||
| `onClose` | `() => void` | - | Callback when spotlight is closed |
|
||||
| `items` | `SpotlightItem[]` | - | Array of searchable items |
|
||||
| `onSelect` | `(item: SpotlightItem) => void` | - | Callback when an item is selected |
|
||||
| `placeholder` | `string` | `'Search...'` | Search input placeholder text |
|
||||
|
||||
### SpotlightItem
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `id` | `string` | Unique identifier for the item |
|
||||
| `title` | `string` | Display title |
|
||||
| `subtitle` | `string` | Optional subtitle/description text |
|
||||
| `icon` | `ReactNode` | Optional icon to display |
|
||||
| `category` | `string` | Category for grouping |
|
||||
| `keywords` | `string[]` | Optional search keywords |
|
||||
| `action` | `() => void` | Optional action callback |
|
||||
| Property | Type | Description |
|
||||
| ---------- | ------------ | ---------------------------------- |
|
||||
| `id` | `string` | Unique identifier for the item |
|
||||
| `title` | `string` | Display title |
|
||||
| `subtitle` | `string` | Optional subtitle/description text |
|
||||
| `icon` | `ReactNode` | Optional icon to display |
|
||||
| `category` | `string` | Category for grouping |
|
||||
| `keywords` | `string[]` | Optional search keywords |
|
||||
| `action` | `() => void` | Optional action callback |
|
||||
|
||||
## Features
|
||||
|
||||
@@ -120,26 +130,70 @@ export function SpotlightDemo() {
|
||||
### Application Launcher
|
||||
|
||||
```tsx
|
||||
import { Spotlight, SpotlightItem, useKeyboardShortcuts } from "@hanzo/ui/desktop"
|
||||
import {
|
||||
Terminal,
|
||||
Chrome,
|
||||
Mail,
|
||||
Spotlight,
|
||||
SpotlightItem,
|
||||
useKeyboardShortcuts,
|
||||
} from "@hanzo/ui/desktop"
|
||||
import {
|
||||
Calendar,
|
||||
Chrome,
|
||||
Folder,
|
||||
Mail,
|
||||
Music,
|
||||
Settings,
|
||||
Folder
|
||||
Terminal,
|
||||
} from "lucide-react"
|
||||
|
||||
const apps: SpotlightItem[] = [
|
||||
{ id: 'terminal', label: 'Terminal', category: 'Applications', icon: <Terminal className="h-5 w-5" /> },
|
||||
{ id: 'safari', label: 'Safari', category: 'Applications', icon: <Chrome className="h-5 w-5" /> },
|
||||
{ id: 'mail', label: 'Mail', category: 'Applications', icon: <Mail className="h-5 w-5" /> },
|
||||
{ id: 'calendar', label: 'Calendar', category: 'Applications', icon: <Calendar className="h-5 w-5" /> },
|
||||
{ id: 'music', label: 'Music', category: 'Applications', icon: <Music className="h-5 w-5" /> },
|
||||
{ id: 'settings', label: 'System Preferences', category: 'Applications', icon: <Settings className="h-5 w-5" /> },
|
||||
{ id: 'documents', label: 'Documents', category: 'Folders', icon: <Folder className="h-5 w-5" /> },
|
||||
{ id: 'downloads', label: 'Downloads', category: 'Folders', icon: <Folder className="h-5 w-5" /> },
|
||||
{
|
||||
id: "terminal",
|
||||
label: "Terminal",
|
||||
category: "Applications",
|
||||
icon: <Terminal className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
id: "safari",
|
||||
label: "Safari",
|
||||
category: "Applications",
|
||||
icon: <Chrome className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
id: "mail",
|
||||
label: "Mail",
|
||||
category: "Applications",
|
||||
icon: <Mail className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
id: "calendar",
|
||||
label: "Calendar",
|
||||
category: "Applications",
|
||||
icon: <Calendar className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
id: "music",
|
||||
label: "Music",
|
||||
category: "Applications",
|
||||
icon: <Music className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
id: "settings",
|
||||
label: "System Preferences",
|
||||
category: "Applications",
|
||||
icon: <Settings className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
id: "documents",
|
||||
label: "Documents",
|
||||
category: "Folders",
|
||||
icon: <Folder className="h-5 w-5" />,
|
||||
},
|
||||
{
|
||||
id: "downloads",
|
||||
label: "Downloads",
|
||||
category: "Folders",
|
||||
icon: <Folder className="h-5 w-5" />,
|
||||
},
|
||||
]
|
||||
|
||||
export function AppLauncher() {
|
||||
@@ -147,7 +201,7 @@ export function AppLauncher() {
|
||||
|
||||
// ⌘+Space to open (like macOS)
|
||||
useKeyboardShortcuts([
|
||||
{ key: ' ', meta: true, action: () => setIsOpen(true) }
|
||||
{ key: " ", meta: true, action: () => setIsOpen(true) },
|
||||
])
|
||||
|
||||
return (
|
||||
@@ -157,7 +211,7 @@ export function AppLauncher() {
|
||||
items={apps}
|
||||
placeholder="Search applications..."
|
||||
onSelect={(item) => {
|
||||
console.log('Launch:', item.label)
|
||||
console.log("Launch:", item.label)
|
||||
setIsOpen(false)
|
||||
}}
|
||||
/>
|
||||
@@ -169,22 +223,51 @@ export function AppLauncher() {
|
||||
|
||||
```tsx
|
||||
import { Spotlight, SpotlightItem } from "@hanzo/ui/desktop"
|
||||
import {
|
||||
Save,
|
||||
Copy,
|
||||
Scissors,
|
||||
Clipboard,
|
||||
Undo,
|
||||
Redo
|
||||
} from "lucide-react"
|
||||
import { Clipboard, Copy, Redo, Save, Scissors, Undo } from "lucide-react"
|
||||
|
||||
const commands: SpotlightItem[] = [
|
||||
{ id: 'save', label: 'Save', category: 'File', icon: <Save />, shortcut: '⌘S' },
|
||||
{ id: 'copy', label: 'Copy', category: 'Edit', icon: <Copy />, shortcut: '⌘C' },
|
||||
{ id: 'cut', label: 'Cut', category: 'Edit', icon: <Scissors />, shortcut: '⌘X' },
|
||||
{ id: 'paste', label: 'Paste', category: 'Edit', icon: <Clipboard />, shortcut: '⌘V' },
|
||||
{ id: 'undo', label: 'Undo', category: 'Edit', icon: <Undo />, shortcut: '⌘Z' },
|
||||
{ id: 'redo', label: 'Redo', category: 'Edit', icon: <Redo />, shortcut: '⌘⇧Z' },
|
||||
{
|
||||
id: "save",
|
||||
label: "Save",
|
||||
category: "File",
|
||||
icon: <Save />,
|
||||
shortcut: "⌘S",
|
||||
},
|
||||
{
|
||||
id: "copy",
|
||||
label: "Copy",
|
||||
category: "Edit",
|
||||
icon: <Copy />,
|
||||
shortcut: "⌘C",
|
||||
},
|
||||
{
|
||||
id: "cut",
|
||||
label: "Cut",
|
||||
category: "Edit",
|
||||
icon: <Scissors />,
|
||||
shortcut: "⌘X",
|
||||
},
|
||||
{
|
||||
id: "paste",
|
||||
label: "Paste",
|
||||
category: "Edit",
|
||||
icon: <Clipboard />,
|
||||
shortcut: "⌘V",
|
||||
},
|
||||
{
|
||||
id: "undo",
|
||||
label: "Undo",
|
||||
category: "Edit",
|
||||
icon: <Undo />,
|
||||
shortcut: "⌘Z",
|
||||
},
|
||||
{
|
||||
id: "redo",
|
||||
label: "Redo",
|
||||
category: "Edit",
|
||||
icon: <Redo />,
|
||||
shortcut: "⌘⇧Z",
|
||||
},
|
||||
]
|
||||
|
||||
export function CommandPalette() {
|
||||
@@ -197,7 +280,7 @@ export function CommandPalette() {
|
||||
items={commands}
|
||||
placeholder="Type a command..."
|
||||
onSelect={(item) => {
|
||||
console.log('Execute:', item.id)
|
||||
console.log("Execute:", item.id)
|
||||
setIsOpen(false)
|
||||
}}
|
||||
/>
|
||||
@@ -207,9 +290,9 @@ export function CommandPalette() {
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
| Shortcut | Action |
|
||||
|----------|--------|
|
||||
| `↑` / `↓` | Navigate between items |
|
||||
| `Enter` | Select highlighted item |
|
||||
| `Escape` | Close spotlight |
|
||||
| Shortcut | Action |
|
||||
| --------------- | -------------------------------- |
|
||||
| `↑` / `↓` | Navigate between items |
|
||||
| `Enter` | Select highlighted item |
|
||||
| `Escape` | Close spotlight |
|
||||
| `⌘K` / `⌘Space` | Open spotlight (when configured) |
|
||||
|
||||
@@ -75,17 +75,17 @@ export function WindowDemo() {
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `title` | `string` | - | Window title displayed in the title bar |
|
||||
| `onClose` | `() => void` | - | Callback when the close button is clicked |
|
||||
| `initialPosition` | `{ x: number, y: number }` | `{ x: 100, y: 100 }` | Initial window position |
|
||||
| `initialSize` | `{ width: number, height: number }` | `{ width: 800, height: 600 }` | Initial window dimensions |
|
||||
| `minWidth` | `number` | `200` | Minimum window width |
|
||||
| `minHeight` | `number` | `150` | Minimum window height |
|
||||
| `windowType` | `'default' \| 'dark' \| 'light' \| 'transparent'` | `'default'` | Window style variant |
|
||||
| `className` | `string` | - | Additional CSS classes for the window |
|
||||
| `children` | `ReactNode` | - | Window content |
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------------- | ------------------------------------------------- | ----------------------------- | ----------------------------------------- |
|
||||
| `title` | `string` | - | Window title displayed in the title bar |
|
||||
| `onClose` | `() => void` | - | Callback when the close button is clicked |
|
||||
| `initialPosition` | `{ x: number, y: number }` | `{ x: 100, y: 100 }` | Initial window position |
|
||||
| `initialSize` | `{ width: number, height: number }` | `{ width: 800, height: 600 }` | Initial window dimensions |
|
||||
| `minWidth` | `number` | `200` | Minimum window width |
|
||||
| `minHeight` | `number` | `150` | Minimum window height |
|
||||
| `windowType` | `'default' \| 'dark' \| 'light' \| 'transparent'` | `'default'` | Window style variant |
|
||||
| `className` | `string` | - | Additional CSS classes for the window |
|
||||
| `children` | `ReactNode` | - | Window content |
|
||||
|
||||
## Variants
|
||||
|
||||
@@ -128,7 +128,7 @@ export function WindowDemo() {
|
||||
|
||||
```tsx
|
||||
import { Window } from "@hanzo/ui/desktop"
|
||||
import { Settings, User, Bell } from "lucide-react"
|
||||
import { Bell, Settings, User } from "lucide-react"
|
||||
|
||||
export function SettingsWindow() {
|
||||
const [isOpen, setIsOpen] = useState(true)
|
||||
@@ -164,35 +164,35 @@ export function SettingsWindow() {
|
||||
### Multiple Windows
|
||||
|
||||
```tsx
|
||||
import { Window, useWindowManager } from "@hanzo/ui/desktop"
|
||||
import { useWindowManager, Window } from "@hanzo/ui/desktop"
|
||||
|
||||
export function MultiWindowDemo() {
|
||||
const windows = useWindowManager()
|
||||
|
||||
return (
|
||||
<div className="relative h-screen">
|
||||
{windows.isOpen('Settings') && (
|
||||
{windows.isOpen("Settings") && (
|
||||
<Window
|
||||
title="Settings"
|
||||
onClose={() => windows.close('Settings')}
|
||||
onClose={() => windows.close("Settings")}
|
||||
initialPosition={{ x: 100, y: 100 }}
|
||||
>
|
||||
<div className="p-4">Settings content</div>
|
||||
</Window>
|
||||
)}
|
||||
|
||||
{windows.isOpen('Editor') && (
|
||||
{windows.isOpen("Editor") && (
|
||||
<Window
|
||||
title="Editor"
|
||||
onClose={() => windows.close('Editor')}
|
||||
onClose={() => windows.close("Editor")}
|
||||
initialPosition={{ x: 200, y: 150 }}
|
||||
>
|
||||
<div className="p-4">Editor content</div>
|
||||
</Window>
|
||||
)}
|
||||
|
||||
<button onClick={() => windows.open('Settings')}>Open Settings</button>
|
||||
<button onClick={() => windows.open('Editor')}>Open Editor</button>
|
||||
<button onClick={() => windows.open("Settings")}>Open Settings</button>
|
||||
<button onClick={() => windows.open("Editor")}>Open Editor</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,19 +8,19 @@ The Desktop namespace provides components and hooks for building macOS-style des
|
||||
|
||||
## Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| [Window](/docs/components/desktop-window) | Draggable, resizable window with minimize, maximize, and close controls |
|
||||
| [Spotlight](/docs/components/desktop-spotlight) | macOS Spotlight-style search and command palette |
|
||||
| Component | Description |
|
||||
| ----------------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| [Window](/docs/components/desktop-window) | Draggable, resizable window with minimize, maximize, and close controls |
|
||||
| [Spotlight](/docs/components/desktop-spotlight) | macOS Spotlight-style search and command palette |
|
||||
|
||||
## Hooks
|
||||
|
||||
| Hook | Description |
|
||||
|------|-------------|
|
||||
| `useWindowManager` | Manage multiple windows with open/close/toggle state |
|
||||
| `useDesktopSettings` | Persist desktop settings like theme, dock position |
|
||||
| `useOverlayManager` | Manage overlay states (spotlight, about dialog, etc.) |
|
||||
| `useKeyboardShortcuts` | Register keyboard shortcuts (⌘+Space, ⌘+Q, etc.) |
|
||||
| Hook | Description |
|
||||
| ---------------------- | ----------------------------------------------------- |
|
||||
| `useWindowManager` | Manage multiple windows with open/close/toggle state |
|
||||
| `useDesktopSettings` | Persist desktop settings like theme, dock position |
|
||||
| `useOverlayManager` | Manage overlay states (spotlight, about dialog, etc.) |
|
||||
| `useKeyboardShortcuts` | Register keyboard shortcuts (⌘+Space, ⌘+Q, etc.) |
|
||||
|
||||
See [Desktop Hooks](/docs/components/desktop-hooks) for detailed hook documentation.
|
||||
|
||||
@@ -51,12 +51,12 @@ Then import from the desktop namespace:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
Window,
|
||||
Spotlight,
|
||||
useWindowManager,
|
||||
useDesktopSettings,
|
||||
useKeyboardShortcuts,
|
||||
useOverlayManager,
|
||||
useKeyboardShortcuts
|
||||
useWindowManager,
|
||||
Window,
|
||||
} from "@hanzo/ui/desktop"
|
||||
```
|
||||
|
||||
@@ -68,10 +68,10 @@ import {
|
||||
|
||||
```tsx
|
||||
import {
|
||||
Window,
|
||||
Spotlight,
|
||||
useKeyboardShortcuts,
|
||||
useWindowManager,
|
||||
useKeyboardShortcuts
|
||||
Window,
|
||||
} from "@hanzo/ui/desktop"
|
||||
import { Dock, DockItem } from "@hanzo/ui/dock"
|
||||
|
||||
@@ -80,16 +80,16 @@ export function MyDesktop() {
|
||||
const [showSpotlight, setShowSpotlight] = useState(false)
|
||||
|
||||
useKeyboardShortcuts([
|
||||
{ key: ' ', meta: true, action: () => setShowSpotlight(true) },
|
||||
{ key: " ", meta: true, action: () => setShowSpotlight(true) },
|
||||
])
|
||||
|
||||
return (
|
||||
<div className="h-screen relative">
|
||||
{/* Windows */}
|
||||
{windows.isOpen('Settings') && (
|
||||
{windows.isOpen("Settings") && (
|
||||
<Window
|
||||
title="Settings"
|
||||
onClose={() => windows.closeWindow('Settings')}
|
||||
onClose={() => windows.closeWindow("Settings")}
|
||||
>
|
||||
<div className="p-4">Settings content</div>
|
||||
</Window>
|
||||
@@ -99,9 +99,7 @@ export function MyDesktop() {
|
||||
<Spotlight
|
||||
isOpen={showSpotlight}
|
||||
onClose={() => setShowSpotlight(false)}
|
||||
items={[
|
||||
{ id: 'settings', title: 'Settings', category: 'Apps' },
|
||||
]}
|
||||
items={[{ id: "settings", title: "Settings", category: "Apps" }]}
|
||||
onSelect={(item) => {
|
||||
windows.openWindow(item.title)
|
||||
setShowSpotlight(false)
|
||||
@@ -112,7 +110,7 @@ export function MyDesktop() {
|
||||
<Dock position="bottom">
|
||||
<DockItem
|
||||
tooltip="Settings"
|
||||
onClick={() => windows.toggleWindow('Settings')}
|
||||
onClick={() => windows.toggleWindow("Settings")}
|
||||
/>
|
||||
</Dock>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: Direction
|
||||
description: Provider and hook for RTL/LTR text direction support.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Direction component provides RTL (right-to-left) and LTR (left-to-right) text direction support through a React context provider and hook. Useful for internationalization and bidirectional text layouts.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { DirectionProvider, useDirection } from "@hanzo/ui"
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<DirectionProvider direction="rtl">
|
||||
<MyComponent />
|
||||
</DirectionProvider>
|
||||
)
|
||||
}
|
||||
|
||||
function MyComponent() {
|
||||
const direction = useDirection()
|
||||
return <div>Current direction: {direction}</div>
|
||||
}
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
### DirectionProvider
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| --------- | -------------- | ------- | --------------- |
|
||||
| dir | "ltr" \| "rtl" | - | Text direction |
|
||||
| direction | "ltr" \| "rtl" | - | Alias for `dir` |
|
||||
| children | ReactNode | - | Child elements |
|
||||
|
||||
### useDirection
|
||||
|
||||
Returns the current direction from the nearest `DirectionProvider`.
|
||||
|
||||
```tsx
|
||||
const direction = useDirection() // "ltr" | "rtl"
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: Stock Market
|
||||
description: Display stock market overview with major indices and equities.
|
||||
component: true
|
||||
---
|
||||
|
||||
<ComponentPreview name="market-overview" description="Stock market overview" />
|
||||
|
||||
## Installation
|
||||
|
||||
<Tabs defaultValue="cli">
|
||||
|
||||
<TabsList>
|
||||
<TabsTrigger value="cli">CLI</TabsTrigger>
|
||||
<TabsTrigger value="manual">Manual</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="cli">
|
||||
|
||||
```bash
|
||||
npx @hanzo/ui@latest add market-overview
|
||||
```
|
||||
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="manual">
|
||||
|
||||
<Steps>
|
||||
|
||||
<Step>Install the following dependencies:</Step>
|
||||
|
||||
```bash
|
||||
npm install @hanzo/ui
|
||||
```
|
||||
|
||||
<Step>Copy and paste the following code into your project.</Step>
|
||||
|
||||
<ComponentSource name="market-overview" />
|
||||
|
||||
<Step>Update the import paths to match your project setup.</Step>
|
||||
|
||||
</Steps>
|
||||
|
||||
</TabsContent>
|
||||
|
||||
</Tabs>
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { MarketOverview } from "@hanzo/ui/finance"
|
||||
|
||||
export default function Demo() {
|
||||
return <MarketOverview tabs={["indices"]} colorTheme="dark" />
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: React Native
|
||||
description: Using @hanzo/ui components in React Native and Expo applications.
|
||||
---
|
||||
|
||||
# React Native Guide (Beta)
|
||||
|
||||
@hanzo/ui provides React Native components built on top of React Native's core primitives and NativeWind for styling. This integration is currently in beta.
|
||||
|
||||
## Installation
|
||||
|
||||
<Steps>
|
||||
|
||||
### Install the package
|
||||
|
||||
```bash
|
||||
npm install @hanzo/ui
|
||||
# or
|
||||
pnpm add @hanzo/ui
|
||||
```
|
||||
|
||||
### Install NativeWind
|
||||
|
||||
```bash
|
||||
npm install nativewind
|
||||
npm install -D tailwindcss
|
||||
```
|
||||
|
||||
### Configure Tailwind
|
||||
|
||||
```js title="tailwind.config.js"
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./App.{js,jsx,ts,tsx}",
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
"./node_modules/@hanzo/ui/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
presets: [require("nativewind/preset")],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { useState } from "react"
|
||||
import { Button, Card, Input } from "@hanzo/ui/native"
|
||||
|
||||
export default function App() {
|
||||
const [count, setCount] = useState(0)
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Button onPress={() => setCount((c) => c + 1)}>
|
||||
Clicked {count} times
|
||||
</Button>
|
||||
<Input value={String(count)} />
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Expo Integration
|
||||
|
||||
```tsx
|
||||
// app/(tabs)/index.tsx
|
||||
import { Button, Card } from "@hanzo/ui/native"
|
||||
|
||||
export default function HomeScreen() {
|
||||
return (
|
||||
<Card>
|
||||
<Button>Click me</Button>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Component Coverage
|
||||
|
||||
**Available:**
|
||||
|
||||
- Button, Card, Input, Label, Badge
|
||||
- Checkbox, Switch, Separator
|
||||
- Tabs, Avatar
|
||||
|
||||
**In Progress:**
|
||||
|
||||
- Dialog and Sheet (modal-based)
|
||||
- Select and Popover
|
||||
- Navigation components
|
||||
|
||||
**Not Available:**
|
||||
|
||||
- 3D components
|
||||
- Browser-specific components (Safari mockup, etc.)
|
||||
- Chart components
|
||||
|
||||
## Platform Differences
|
||||
|
||||
Some components behave differently on native platforms:
|
||||
|
||||
- **Dialog** uses React Native's `Modal` component
|
||||
- **Sheet** uses bottom sheet gestures via `react-native-gesture-handler`
|
||||
- **Animations** use `react-native-reanimated` instead of Framer Motion
|
||||
|
||||
## Status
|
||||
|
||||
This integration is in **beta**. Component coverage is limited compared to the web version. Please report issues on [GitHub](https://github.com/hanzoai/ui/issues).
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [View all components](/docs/components)
|
||||
- [React Guide](/docs/frameworks/react) (stable)
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: Svelte
|
||||
description: Using @hanzo/ui components in Svelte and SvelteKit applications.
|
||||
---
|
||||
|
||||
# Svelte Guide (Beta)
|
||||
|
||||
@hanzo/ui provides Svelte 5 components with full TypeScript support. This integration is currently in beta.
|
||||
|
||||
## Installation
|
||||
|
||||
<Steps>
|
||||
|
||||
### Install the package
|
||||
|
||||
```bash
|
||||
npm install @hanzo/ui
|
||||
# or
|
||||
pnpm add @hanzo/ui
|
||||
```
|
||||
|
||||
### Install Svelte and dependencies
|
||||
|
||||
```bash
|
||||
npm install svelte
|
||||
npm install -D tailwindcss postcss autoprefixer
|
||||
```
|
||||
|
||||
### Configure Tailwind
|
||||
|
||||
```js title="tailwind.config.js"
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*.{html,js,svelte,ts}",
|
||||
"./node_modules/@hanzo/ui/**/*.{js,ts,svelte}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
## Usage
|
||||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import { Button, Card, Input } from '@hanzo/ui/svelte'
|
||||
|
||||
let count = $state(0)
|
||||
</script>
|
||||
|
||||
<Card>
|
||||
<Button onclick={() => count++}>
|
||||
Clicked {count} times
|
||||
</Button>
|
||||
<Input bind:value={count} type="number" />
|
||||
</Card>
|
||||
```
|
||||
|
||||
## SvelteKit Integration
|
||||
|
||||
```svelte
|
||||
<!-- src/routes/+page.svelte -->
|
||||
<script lang="ts">
|
||||
import { Button, Card } from '@hanzo/ui/svelte'
|
||||
</script>
|
||||
|
||||
<Card>
|
||||
<h1>Welcome to SvelteKit</h1>
|
||||
<Button>Click me</Button>
|
||||
</Card>
|
||||
```
|
||||
|
||||
## Component Coverage
|
||||
|
||||
**Available:**
|
||||
|
||||
- Button, Card, Input, Label, Badge
|
||||
- Checkbox, Dialog, Select, Separator
|
||||
- Tabs, Toggle, Tooltip
|
||||
|
||||
**In Progress:**
|
||||
|
||||
- Form components
|
||||
- Data Table
|
||||
- Advanced animations
|
||||
|
||||
## Status
|
||||
|
||||
This integration is in **beta**. Some components may have limited functionality compared to the React version. Please report issues on [GitHub](https://github.com/hanzoai/ui/issues).
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [View all components](/docs/components)
|
||||
- [React Guide](/docs/frameworks/react) (stable)
|
||||
- [Vue Guide](/docs/frameworks/vue) (stable)
|
||||
+8
-8
@@ -28,6 +28,10 @@
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@faker-js/faker": "^10.0.0",
|
||||
"@hanzo/docs-core": "16.2.6",
|
||||
"@hanzo/docs-docgen": "3.0.4",
|
||||
"@hanzo/docs-mdx": "14.3.0",
|
||||
"@hanzo/docs-ui": "16.2.6",
|
||||
"@hanzo/logo": "^1.0.3",
|
||||
"@hanzo/ui": "workspace:^",
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
@@ -41,6 +45,7 @@
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-context-menu": "^2.2.16",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-direction": "^1.1.1",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-hover-card": "^1.1.15",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
@@ -82,11 +87,6 @@
|
||||
"date-fns": "^4.1.0",
|
||||
"embla-carousel-autoplay": "8.6.0",
|
||||
"embla-carousel-react": "8.6.0",
|
||||
"framer-motion": "^12.23.22",
|
||||
"@hanzo/docs-core": "16.2.6",
|
||||
"@hanzo/docs-docgen": "3.0.4",
|
||||
"@hanzo/docs-mdx": "14.3.0",
|
||||
"@hanzo/docs-ui": "16.2.6",
|
||||
"fumadocs-core": "^16.4.8",
|
||||
"fumadocs-mdx": "^14.2.6",
|
||||
"geist": "^1.5.1",
|
||||
@@ -94,9 +94,9 @@
|
||||
"jotai": "^2.15.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "0.544.0",
|
||||
"lucide-react": "^0.544.0",
|
||||
"monaco-editor": "^0.53.0",
|
||||
"motion": "^12.23.22",
|
||||
"motion": "^12.34.0",
|
||||
"next-themes": "0.4.6",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"react": "19.2.0",
|
||||
@@ -144,7 +144,7 @@
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-config-next": "16.0.1",
|
||||
"happy-dom": "^20.0.10",
|
||||
"next": "16.0.1",
|
||||
"next": "^16.1.6",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"playwright": "^1.55.1",
|
||||
"png-to-ico": "^3.0.1",
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
"destructive-foreground": "gray-50",
|
||||
"border": "gray-200",
|
||||
"input": "gray-200",
|
||||
"ring": "gray-950"
|
||||
"ring": "gray-950",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "gray-950",
|
||||
@@ -40,7 +45,12 @@
|
||||
"destructive-foreground": "gray-50",
|
||||
"border": "gray-800",
|
||||
"input": "gray-800",
|
||||
"ring": "gray-300"
|
||||
"ring": "gray-300",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
}
|
||||
},
|
||||
"cssVars": {
|
||||
@@ -63,12 +73,7 @@
|
||||
"destructive-foreground": "210 20% 98%",
|
||||
"border": "220 13% 91%",
|
||||
"input": "220 13% 91%",
|
||||
"ring": "224 71.4% 4.1%",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
"ring": "224 71.4% 4.1%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "224 71.4% 4.1%",
|
||||
@@ -89,12 +94,7 @@
|
||||
"destructive-foreground": "210 20% 98%",
|
||||
"border": "215 27.9% 16.9%",
|
||||
"input": "215 27.9% 16.9%",
|
||||
"ring": "216 12.2% 83.9%",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
"ring": "216 12.2% 83.9%"
|
||||
}
|
||||
},
|
||||
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,12 @@
|
||||
"destructive-foreground": "neutral-50",
|
||||
"border": "neutral-200",
|
||||
"input": "neutral-200",
|
||||
"ring": "neutral-950"
|
||||
"ring": "neutral-950",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "neutral-950",
|
||||
@@ -40,7 +45,12 @@
|
||||
"destructive-foreground": "neutral-50",
|
||||
"border": "neutral-800",
|
||||
"input": "neutral-800",
|
||||
"ring": "neutral-300"
|
||||
"ring": "neutral-300",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
}
|
||||
},
|
||||
"cssVars": {
|
||||
@@ -63,12 +73,7 @@
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
"border": "0 0% 89.8%",
|
||||
"input": "0 0% 89.8%",
|
||||
"ring": "0 0% 3.9%",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
"ring": "0 0% 3.9%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "0 0% 3.9%",
|
||||
@@ -89,12 +94,7 @@
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
"border": "0 0% 14.9%",
|
||||
"input": "0 0% 14.9%",
|
||||
"ring": "0 0% 83.1%",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
"ring": "0 0% 83.1%"
|
||||
}
|
||||
},
|
||||
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
"destructive-foreground": "slate-50",
|
||||
"border": "slate-200",
|
||||
"input": "slate-200",
|
||||
"ring": "slate-950"
|
||||
"ring": "slate-950",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "slate-950",
|
||||
@@ -40,7 +45,12 @@
|
||||
"destructive-foreground": "slate-50",
|
||||
"border": "slate-800",
|
||||
"input": "slate-800",
|
||||
"ring": "slate-300"
|
||||
"ring": "slate-300",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
}
|
||||
},
|
||||
"cssVars": {
|
||||
@@ -63,12 +73,7 @@
|
||||
"destructive-foreground": "210 40% 98%",
|
||||
"border": "214.3 31.8% 91.4%",
|
||||
"input": "214.3 31.8% 91.4%",
|
||||
"ring": "222.2 84% 4.9%",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
"ring": "222.2 84% 4.9%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "222.2 84% 4.9%",
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
"destructive-foreground": "stone-50",
|
||||
"border": "stone-200",
|
||||
"input": "stone-200",
|
||||
"ring": "stone-950"
|
||||
"ring": "stone-950",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "stone-950",
|
||||
@@ -40,7 +45,12 @@
|
||||
"destructive-foreground": "stone-50",
|
||||
"border": "stone-800",
|
||||
"input": "stone-800",
|
||||
"ring": "stone-300"
|
||||
"ring": "stone-300",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
}
|
||||
},
|
||||
"cssVars": {
|
||||
@@ -63,12 +73,7 @@
|
||||
"destructive-foreground": "60 9.1% 97.8%",
|
||||
"border": "20 5.9% 90%",
|
||||
"input": "20 5.9% 90%",
|
||||
"ring": "20 14.3% 4.1%",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
"ring": "20 14.3% 4.1%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "20 14.3% 4.1%",
|
||||
@@ -89,12 +94,7 @@
|
||||
"destructive-foreground": "60 9.1% 97.8%",
|
||||
"border": "12 6.5% 15.1%",
|
||||
"input": "12 6.5% 15.1%",
|
||||
"ring": "24 5.7% 82.9%",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
"ring": "24 5.7% 82.9%"
|
||||
}
|
||||
},
|
||||
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
"destructive-foreground": "zinc-50",
|
||||
"border": "zinc-200",
|
||||
"input": "zinc-200",
|
||||
"ring": "zinc-950"
|
||||
"ring": "zinc-950",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "zinc-950",
|
||||
@@ -40,7 +45,12 @@
|
||||
"destructive-foreground": "zinc-50",
|
||||
"border": "zinc-800",
|
||||
"input": "zinc-800",
|
||||
"ring": "zinc-300"
|
||||
"ring": "zinc-300",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
}
|
||||
},
|
||||
"cssVars": {
|
||||
@@ -63,12 +73,7 @@
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
"border": "240 5.9% 90%",
|
||||
"input": "240 5.9% 90%",
|
||||
"ring": "240 10% 3.9%",
|
||||
"chart-1": "12 76% 61%",
|
||||
"chart-2": "173 58% 39%",
|
||||
"chart-3": "197 37% 24%",
|
||||
"chart-4": "43 74% 66%",
|
||||
"chart-5": "27 87% 67%"
|
||||
"ring": "240 10% 3.9%"
|
||||
},
|
||||
"dark": {
|
||||
"background": "240 10% 3.9%",
|
||||
@@ -89,12 +94,7 @@
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
"border": "240 3.7% 15.9%",
|
||||
"input": "240 3.7% 15.9%",
|
||||
"ring": "240 4.9% 83.9%",
|
||||
"chart-1": "220 70% 50%",
|
||||
"chart-2": "160 60% 45%",
|
||||
"chart-3": "30 80% 55%",
|
||||
"chart-4": "280 65% 60%",
|
||||
"chart-5": "340 75% 55%"
|
||||
"ring": "240 4.9% 83.9%"
|
||||
}
|
||||
},
|
||||
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
|
||||
|
||||
@@ -184,6 +184,16 @@
|
||||
],
|
||||
"type": "components:ui"
|
||||
},
|
||||
{
|
||||
"name": "direction",
|
||||
"dependencies": [
|
||||
"@radix-ui/react-direction"
|
||||
],
|
||||
"files": [
|
||||
"ui/direction.tsx"
|
||||
],
|
||||
"type": "components:ui"
|
||||
},
|
||||
{
|
||||
"name": "dialog",
|
||||
"dependencies": [
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "advanced-chart.tsx",
|
||||
"content": "export * from \"../ui/advanced-chart\"\n"
|
||||
"content": "export { default } from \"../ui/advanced-chart\"\nexport * from \"../ui/advanced-chart\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:finance",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "advanced-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../advanced-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "ai-model-selector-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../ai-model-selector-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "app-switcher-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../app-switcher-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "breadcrumb-and-filters-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../breadcrumb-and-filters-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "breadcrumb-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../breadcrumb-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "button-icon.tsx",
|
||||
"content": "import { ChevronRight } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonIcon() {\n return (\n <Button variant=\"outline\" size=\"icon\">\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n )\n}\n"
|
||||
"content": "import { ChevronRight } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonIcon() {\n return (\n <Button variant=\"outline\" size=\"icon\">\n <ChevronRight />\n </Button>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "button-loading.tsx",
|
||||
"content": "import { Loader2 } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonLoading() {\n return (\n <Button disabled>\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n Please wait\n </Button>\n )\n}\n"
|
||||
"content": "import { Loader2 } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonLoading() {\n return (\n <Button disabled>\n <Loader2 className=\"animate-spin\" />\n Please wait\n </Button>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "button-with-icon.tsx",
|
||||
"content": "import { Mail } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonWithIcon() {\n return (\n <Button>\n <Mail className=\"mr-2 h-4 w-4\" /> Login with Email\n </Button>\n )\n}\n"
|
||||
"content": "import { Mail } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\n\nexport default function ButtonWithIcon() {\n return (\n <Button>\n <Mail /> Login with Email\n </Button>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "button.tsx",
|
||||
"content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n )\n }\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n"
|
||||
"content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n xs: \"h-7 rounded-md gap-1 px-2 text-xs has-[>svg]:px-1.5\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-xs\": \"size-7\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n )\n }\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "calendar-form.tsx",
|
||||
"content": "\"use client\"\n\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { format } from \"date-fns\"\nimport { CalendarIcon } from \"lucide-react\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Calendar } from \"@/registry/default/ui/calendar\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/registry/default/ui/form\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\nimport { toast } from \"@/registry/default/ui/use-toast\"\n\nconst FormSchema = z.object({\n dob: z.date({\n message: \"A date of birth is required.\",\n }),\n})\n\nexport default function CalendarForm() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n <FormField\n control={form.control}\n name=\"dob\"\n render={({ field }) => (\n <FormItem className=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger asChild>\n <FormControl>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[240px] pl-3 text-left font-normal\",\n !field.value && \"text-muted-foreground\"\n )}\n >\n {field.value ? (\n format(field.value, \"PPP\")\n ) : (\n <span>Pick a date</span>\n )}\n <CalendarIcon className=\"ml-auto h-4 w-4 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\n <Calendar\n mode=\"single\"\n selected={field.value}\n onSelect={field.onChange}\n disabled={(date) =>\n date > new Date() || date < new Date(\"1900-01-01\")\n }\n initialFocus\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { format } from \"date-fns\"\nimport { CalendarIcon } from \"lucide-react\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { cn } from \"@/lib/utils\"\nimport { toast } from \"@/registry/default/hooks/use-toast\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Calendar } from \"@/registry/default/ui/calendar\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/registry/default/ui/form\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\n\nconst FormSchema = z.object({\n dob: z.date({\n message: \"A date of birth is required.\",\n }),\n})\n\nexport default function CalendarForm() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n <FormField\n control={form.control}\n name=\"dob\"\n render={({ field }) => (\n <FormItem className=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger asChild>\n <FormControl>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[240px] pl-3 text-left font-normal\",\n !field.value && \"text-muted-foreground\"\n )}\n >\n {field.value ? (\n format(field.value, \"PPP\")\n ) : (\n <span>Pick a date</span>\n )}\n <CalendarIcon className=\"ml-auto h-4 w-4 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\n <Calendar\n mode=\"single\"\n selected={field.value}\n onSelect={field.onChange}\n disabled={(date) =>\n date > new Date() || date < new Date(\"1900-01-01\")\n }\n initialFocus\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "card-demo.tsx",
|
||||
"content": "import { BellRing, Check } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/registry/default/ui/card\"\nimport { Switch } from \"@/registry/default/ui/switch\"\n\nconst notifications = [\n {\n title: \"Your call has been confirmed.\",\n description: \"1 hour ago\",\n },\n {\n title: \"You have a new message!\",\n description: \"1 hour ago\",\n },\n {\n title: \"Your subscription is expiring soon!\",\n description: \"2 hours ago\",\n },\n]\n\ntype CardProps = React.ComponentProps<typeof Card>\n\nexport default function CardDemo({ className, ...props }: CardProps) {\n return (\n <Card className={cn(\"w-[380px]\", className)} {...props}>\n <CardHeader>\n <CardTitle>Notifications</CardTitle>\n <CardDescription>You have 3 unread messages.</CardDescription>\n </CardHeader>\n <CardContent className=\"grid gap-4\">\n <div className=\" flex items-center space-x-4 rounded-md border p-4\">\n <BellRing />\n <div className=\"flex-1 space-y-1\">\n <p className=\"text-sm font-medium leading-none\">\n Push Notifications\n </p>\n <p className=\"text-sm text-muted-foreground\">\n Send notifications to device.\n </p>\n </div>\n <Switch />\n </div>\n <div>\n {notifications.map((notification, index) => (\n <div\n key={index}\n className=\"mb-4 grid grid-cols-[25px_1fr] items-start pb-4 last:mb-0 last:pb-0\"\n >\n <span className=\"flex h-2 w-2 translate-y-1 rounded-full bg-sky-500\" />\n <div className=\"space-y-1\">\n <p className=\"text-sm font-medium leading-none\">\n {notification.title}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {notification.description}\n </p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n <CardFooter>\n <Button className=\"w-full\">\n <Check className=\"mr-2 h-4 w-4\" /> Mark all as read\n </Button>\n </CardFooter>\n </Card>\n )\n}\n"
|
||||
"content": "import { BellRing, Check } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/registry/default/ui/card\"\nimport { Switch } from \"@/registry/default/ui/switch\"\n\nconst notifications = [\n {\n title: \"Your call has been confirmed.\",\n description: \"1 hour ago\",\n },\n {\n title: \"You have a new message!\",\n description: \"1 hour ago\",\n },\n {\n title: \"Your subscription is expiring soon!\",\n description: \"2 hours ago\",\n },\n]\n\ntype CardProps = React.ComponentProps<typeof Card>\n\nexport default function CardDemo({ className, ...props }: CardProps) {\n return (\n <Card className={cn(\"w-[380px]\", className)} {...props}>\n <CardHeader>\n <CardTitle>Notifications</CardTitle>\n <CardDescription>You have 3 unread messages.</CardDescription>\n </CardHeader>\n <CardContent className=\"grid gap-4\">\n <div className=\" flex items-center space-x-4 rounded-md border p-4\">\n <BellRing />\n <div className=\"flex-1 space-y-1\">\n <p className=\"text-sm font-medium leading-none\">\n Push Notifications\n </p>\n <p className=\"text-sm text-muted-foreground\">\n Send notifications to device.\n </p>\n </div>\n <Switch />\n </div>\n <div>\n {notifications.map((notification, index) => (\n <div\n key={index}\n className=\"mb-4 grid grid-cols-[25px_1fr] items-start pb-4 last:mb-0 last:pb-0\"\n >\n <span className=\"flex h-2 w-2 translate-y-1 rounded-full bg-sky-500\" />\n <div className=\"space-y-1\">\n <p className=\"text-sm font-medium leading-none\">\n {notification.title}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {notification.description}\n </p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n <CardFooter>\n <Button className=\"w-full\">\n <Check /> Mark all as read\n </Button>\n </CardFooter>\n </Card>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "centered-logo-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../centered-logo-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "checkbox-form-multiple.tsx",
|
||||
"content": "\"use client\"\n\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Checkbox } from \"@/registry/default/ui/checkbox\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/registry/default/ui/form\"\nimport { toast } from \"@/registry/default/ui/use-toast\"\n\nconst items = [\n {\n id: \"recents\",\n label: \"Recents\",\n },\n {\n id: \"home\",\n label: \"Home\",\n },\n {\n id: \"applications\",\n label: \"Applications\",\n },\n {\n id: \"desktop\",\n label: \"Desktop\",\n },\n {\n id: \"downloads\",\n label: \"Downloads\",\n },\n {\n id: \"documents\",\n label: \"Documents\",\n },\n] as const\n\nconst FormSchema = z.object({\n items: z.array(z.string()).refine((value) => value.some((item) => item), {\n message: \"You have to select at least one item.\",\n }),\n})\n\nexport default function CheckboxReactHookFormMultiple() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n items: [\"recents\", \"home\"],\n },\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n <FormField\n control={form.control}\n name=\"items\"\n render={() => (\n <FormItem>\n <div className=\"mb-4\">\n <FormLabel className=\"text-base\">Sidebar</FormLabel>\n <FormDescription>\n Select the items you want to display in the sidebar.\n </FormDescription>\n </div>\n {items.map((item) => (\n <FormField\n key={item.id}\n control={form.control}\n name=\"items\"\n render={({ field }) => {\n return (\n <FormItem\n key={item.id}\n className=\"flex flex-row items-start space-x-3 space-y-0\"\n >\n <FormControl>\n <Checkbox\n checked={field.value?.includes(item.id)}\n onCheckedChange={(checked) => {\n return checked\n ? field.onChange([...field.value, item.id])\n : field.onChange(\n field.value?.filter(\n (value) => value !== item.id\n )\n )\n }}\n />\n </FormControl>\n <FormLabel className=\"font-normal\">\n {item.label}\n </FormLabel>\n </FormItem>\n )\n }}\n />\n ))}\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { toast } from \"@/registry/default/hooks/use-toast\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Checkbox } from \"@/registry/default/ui/checkbox\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/registry/default/ui/form\"\n\nconst items = [\n {\n id: \"recents\",\n label: \"Recents\",\n },\n {\n id: \"home\",\n label: \"Home\",\n },\n {\n id: \"applications\",\n label: \"Applications\",\n },\n {\n id: \"desktop\",\n label: \"Desktop\",\n },\n {\n id: \"downloads\",\n label: \"Downloads\",\n },\n {\n id: \"documents\",\n label: \"Documents\",\n },\n] as const\n\nconst FormSchema = z.object({\n items: z.array(z.string()).refine((value) => value.some((item) => item), {\n message: \"You have to select at least one item.\",\n }),\n})\n\nexport default function CheckboxReactHookFormMultiple() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n items: [\"recents\", \"home\"],\n },\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n <FormField\n control={form.control}\n name=\"items\"\n render={() => (\n <FormItem>\n <div className=\"mb-4\">\n <FormLabel className=\"text-base\">Sidebar</FormLabel>\n <FormDescription>\n Select the items you want to display in the sidebar.\n </FormDescription>\n </div>\n {items.map((item) => (\n <FormField\n key={item.id}\n control={form.control}\n name=\"items\"\n render={({ field }) => {\n return (\n <FormItem\n key={item.id}\n className=\"flex flex-row items-start space-x-3 space-y-0\"\n >\n <FormControl>\n <Checkbox\n checked={field.value?.includes(item.id)}\n onCheckedChange={(checked) => {\n return checked\n ? field.onChange([...field.value, item.id])\n : field.onChange(\n field.value?.filter(\n (value) => value !== item.id\n )\n )\n }}\n />\n </FormControl>\n <FormLabel className=\"font-normal\">\n {item.label}\n </FormLabel>\n </FormItem>\n )\n }}\n />\n ))}\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "checkbox-form-single.tsx",
|
||||
"content": "\"use client\"\n\nimport Link from \"next/link\"\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Checkbox } from \"@/registry/default/ui/checkbox\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n} from \"@/registry/default/ui/form\"\nimport { toast } from \"@/registry/default/ui/use-toast\"\n\nconst FormSchema = z.object({\n mobile: z.boolean().default(false).optional(),\n})\n\nexport default function CheckboxReactHookFormSingle() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n mobile: true,\n },\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <FormField\n control={form.control}\n name=\"mobile\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-start space-x-3 space-y-0 rounded-md border p-4\">\n <FormControl>\n <Checkbox\n checked={field.value}\n onCheckedChange={field.onChange}\n />\n </FormControl>\n <div className=\"space-y-1 leading-none\">\n <FormLabel>\n Use different settings for my mobile devices\n </FormLabel>\n <FormDescription>\n You can manage your mobile notifications in the{\" \"}\n <Link href=\"/examples/forms\">mobile settings</Link> page.\n </FormDescription>\n </div>\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport Link from \"next/link\"\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { toast } from \"@/registry/default/hooks/use-toast\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Checkbox } from \"@/registry/default/ui/checkbox\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n} from \"@/registry/default/ui/form\"\n\nconst FormSchema = z.object({\n mobile: z.boolean().default(false).optional(),\n})\n\nexport default function CheckboxReactHookFormSingle() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n mobile: true,\n },\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <FormField\n control={form.control}\n name=\"mobile\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-start space-x-3 space-y-0 rounded-md border p-4\">\n <FormControl>\n <Checkbox\n checked={field.value}\n onCheckedChange={field.onChange}\n />\n </FormControl>\n <div className=\"space-y-1 leading-none\">\n <FormLabel>\n Use different settings for my mobile devices\n </FormLabel>\n <FormDescription>\n You can manage your mobile notifications in the{\" \"}\n <Link href=\"/examples/forms\">mobile settings</Link> page.\n </FormDescription>\n </div>\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "checkbox.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\"\nimport { Check } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst Checkbox = React.forwardRef<\n React.ElementRef<typeof CheckboxPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n \"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground\",\n className\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n className={cn(\"flex items-center justify-center text-current\")}\n >\n <Check className=\"h-4 w-4\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n))\nCheckbox.displayName = CheckboxPrimitive.Root.displayName\n\nexport { Checkbox }\n"
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\"\nimport { Check } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst Checkbox = React.forwardRef<\n React.ElementRef<typeof CheckboxPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n \"grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground\",\n className\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n className={cn(\"grid place-content-center text-current\")}\n >\n <Check className=\"h-4 w-4\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n))\nCheckbox.displayName = CheckboxPrimitive.Root.displayName\n\nexport { Checkbox }\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "collaboration-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../collaboration-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "collapsible-demo.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronsUpDown, Plus, X } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@/registry/default/ui/collapsible\"\n\nexport default function CollapsibleDemo() {\n const [isOpen, setIsOpen] = React.useState(false)\n\n return (\n <Collapsible\n open={isOpen}\n onOpenChange={setIsOpen}\n className=\"w-[350px] space-y-2\"\n >\n <div className=\"flex items-center justify-between space-x-4 px-4\">\n <h4 className=\"text-sm font-semibold\">\n @peduarte starred 3 repositories\n </h4>\n <CollapsibleTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"w-9 p-0\">\n <ChevronsUpDown className=\"h-4 w-4\" />\n <span className=\"sr-only\">Toggle</span>\n </Button>\n </CollapsibleTrigger>\n </div>\n <div className=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @radix-ui/primitives\n </div>\n <CollapsibleContent className=\"space-y-2\">\n <div className=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @radix-ui/colors\n </div>\n <div className=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @stitches/react\n </div>\n </CollapsibleContent>\n </Collapsible>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronsUpDown } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@/registry/default/ui/collapsible\"\n\nexport default function CollapsibleDemo() {\n const [isOpen, setIsOpen] = React.useState(false)\n\n return (\n <Collapsible\n open={isOpen}\n onOpenChange={setIsOpen}\n className=\"w-[350px] space-y-2\"\n >\n <div className=\"flex items-center justify-between space-x-4 px-4\">\n <h4 className=\"text-sm font-semibold\">\n @peduarte starred 3 repositories\n </h4>\n <CollapsibleTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"w-9 p-0\">\n <ChevronsUpDown className=\"h-4 w-4\" />\n <span className=\"sr-only\">Toggle</span>\n </Button>\n </CollapsibleTrigger>\n </div>\n <div className=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @radix-ui/primitives\n </div>\n <CollapsibleContent className=\"space-y-2\">\n <div className=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @radix-ui/colors\n </div>\n <div className=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @stitches/react\n </div>\n </CollapsibleContent>\n </Collapsible>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "combobox-demo.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check, ChevronsUpDown } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n} from \"@/registry/default/ui/command\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\n\nconst frameworks = [\n {\n value: \"next.js\",\n label: \"Next.js\",\n },\n {\n value: \"sveltekit\",\n label: \"SvelteKit\",\n },\n {\n value: \"nuxt.js\",\n label: \"Nuxt.js\",\n },\n {\n value: \"remix\",\n label: \"Remix\",\n },\n {\n value: \"astro\",\n label: \"Astro\",\n },\n]\n\nexport default function ComboboxDemo() {\n const [open, setOpen] = React.useState(false)\n const [value, setValue] = React.useState(\"\")\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n className=\"w-[200px] justify-between\"\n >\n {value\n ? frameworks.find((framework) => framework.value === value)?.label\n : \"Select framework...\"}\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search framework...\" />\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandGroup>\n {frameworks.map((framework) => (\n <CommandItem\n key={framework.value}\n value={framework.value}\n onSelect={(currentValue) => {\n setValue(currentValue === value ? \"\" : currentValue)\n setOpen(false)\n }}\n >\n <Check\n className={cn(\n \"mr-2 h-4 w-4\",\n value === framework.value ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n {framework.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </Command>\n </PopoverContent>\n </Popover>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check, ChevronsUpDown } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@/registry/default/ui/command\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\n\nconst frameworks = [\n {\n value: \"next.js\",\n label: \"Next.js\",\n },\n {\n value: \"sveltekit\",\n label: \"SvelteKit\",\n },\n {\n value: \"nuxt.js\",\n label: \"Nuxt.js\",\n },\n {\n value: \"remix\",\n label: \"Remix\",\n },\n {\n value: \"astro\",\n label: \"Astro\",\n },\n]\n\nexport default function ComboboxDemo() {\n const [open, setOpen] = React.useState(false)\n const [value, setValue] = React.useState(\"\")\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n className=\"w-[200px] justify-between\"\n >\n {value\n ? frameworks.find((framework) => framework.value === value)?.label\n : \"Select framework...\"}\n <ChevronsUpDown className=\"opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search framework...\" />\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandGroup>\n {frameworks.map((framework) => (\n <CommandItem\n key={framework.value}\n value={framework.value}\n onSelect={(currentValue) => {\n setValue(currentValue === value ? \"\" : currentValue)\n setOpen(false)\n }}\n >\n <Check\n className={cn(\n \"mr-2 h-4 w-4\",\n value === framework.value ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n {framework.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </Command>\n </PopoverContent>\n </Popover>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "combobox-dropdown-menu.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Calendar, MoreHorizontal, Tags, Trash, User } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@/registry/default/ui/command\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\"\n\nconst labels = [\n \"feature\",\n \"bug\",\n \"enhancement\",\n \"documentation\",\n \"design\",\n \"question\",\n \"maintenance\",\n]\n\nexport default function ComboboxDropdownMenu() {\n const [label, setLabel] = React.useState(\"feature\")\n const [open, setOpen] = React.useState(false)\n\n return (\n <div className=\"flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center\">\n <p className=\"text-sm font-medium leading-none\">\n <span className=\"mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground\">\n {label}\n </span>\n <span className=\"text-muted-foreground\">Create a new project</span>\n </p>\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\">\n <MoreHorizontal />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-[200px]\">\n <DropdownMenuLabel>Actions</DropdownMenuLabel>\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <User className=\"mr-2 h-4 w-4\" />\n Assign to...\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Calendar className=\"mr-2 h-4 w-4\" />\n Set due date...\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n <Tags className=\"mr-2 h-4 w-4\" />\n Apply label\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"p-0\">\n <Command>\n <CommandInput\n placeholder=\"Filter label...\"\n autoFocus={true}\n />\n <CommandList>\n <CommandEmpty>No label found.</CommandEmpty>\n <CommandGroup>\n {labels.map((label) => (\n <CommandItem\n key={label}\n value={label}\n onSelect={(value) => {\n setLabel(value)\n setOpen(false)\n }}\n >\n {label}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"text-red-600\">\n <Trash className=\"mr-2 h-4 w-4\" />\n Delete\n <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Calendar, MoreHorizontal, Tags, Trash, User } from \"lucide-react\"\n\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@/registry/default/ui/command\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\"\n\nconst labels = [\n \"feature\",\n \"bug\",\n \"enhancement\",\n \"documentation\",\n \"design\",\n \"question\",\n \"maintenance\",\n]\n\nexport default function ComboboxDropdownMenu() {\n const [label, setLabel] = React.useState(\"feature\")\n const [open, setOpen] = React.useState(false)\n\n return (\n <div className=\"flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center\">\n <p className=\"text-sm font-medium leading-none\">\n <span className=\"mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground\">\n {label}\n </span>\n <span className=\"text-muted-foreground\">Create a new project</span>\n </p>\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\">\n <MoreHorizontal />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-[200px]\">\n <DropdownMenuLabel>Actions</DropdownMenuLabel>\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <User />\n Assign to...\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Calendar />\n Set due date...\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n <Tags />\n Apply label\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"p-0\">\n <Command>\n <CommandInput\n placeholder=\"Filter label...\"\n autoFocus={true}\n />\n <CommandList>\n <CommandEmpty>No label found.</CommandEmpty>\n <CommandGroup>\n {labels.map((label) => (\n <CommandItem\n key={label}\n value={label}\n onSelect={(value) => {\n setLabel(value)\n setOpen(false)\n }}\n >\n {label}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"text-red-600\">\n <Trash />\n Delete\n <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "combobox-form.tsx",
|
||||
"content": "\"use client\"\n\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { Check, ChevronsUpDown } from \"lucide-react\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n} from \"@/registry/default/ui/command\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/registry/default/ui/form\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\nimport { toast } from \"@/registry/default/ui/use-toast\"\n\nconst languages = [\n { label: \"English\", value: \"en\" },\n { label: \"French\", value: \"fr\" },\n { label: \"German\", value: \"de\" },\n { label: \"Spanish\", value: \"es\" },\n { label: \"Portuguese\", value: \"pt\" },\n { label: \"Russian\", value: \"ru\" },\n { label: \"Japanese\", value: \"ja\" },\n { label: \"Korean\", value: \"ko\" },\n { label: \"Chinese\", value: \"zh\" },\n] as const\n\nconst FormSchema = z.object({\n language: z.string({\n message: \"Please select a language.\",\n }),\n})\n\nexport default function ComboboxForm() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <FormField\n control={form.control}\n name=\"language\"\n render={({ field }) => (\n <FormItem className=\"flex flex-col\">\n <FormLabel>Language</FormLabel>\n <Popover>\n <PopoverTrigger asChild>\n <FormControl>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n className={cn(\n \"w-[200px] justify-between\",\n !field.value && \"text-muted-foreground\"\n )}\n >\n {field.value\n ? languages.find(\n (language) => language.value === field.value\n )?.label\n : \"Select language\"}\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search language...\" />\n <CommandEmpty>No language found.</CommandEmpty>\n <CommandGroup>\n {languages.map((language) => (\n <CommandItem\n value={language.label}\n key={language.value}\n onSelect={() => {\n form.setValue(\"language\", language.value)\n }}\n >\n <Check\n className={cn(\n \"mr-2 h-4 w-4\",\n language.value === field.value\n ? \"opacity-100\"\n : \"opacity-0\"\n )}\n />\n {language.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </Command>\n </PopoverContent>\n </Popover>\n <FormDescription>\n This is the language that will be used in the dashboard.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport { zodResolver } from \"@hookform/resolvers/zod\"\nimport { Check, ChevronsUpDown } from \"lucide-react\"\nimport { useForm } from \"react-hook-form\"\nimport { z } from \"zod\"\n\nimport { cn } from \"@/lib/utils\"\nimport { toast } from \"@/registry/default/hooks/use-toast\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@/registry/default/ui/command\"\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/registry/default/ui/form\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\n\nconst languages = [\n { label: \"English\", value: \"en\" },\n { label: \"French\", value: \"fr\" },\n { label: \"German\", value: \"de\" },\n { label: \"Spanish\", value: \"es\" },\n { label: \"Portuguese\", value: \"pt\" },\n { label: \"Russian\", value: \"ru\" },\n { label: \"Japanese\", value: \"ja\" },\n { label: \"Korean\", value: \"ko\" },\n { label: \"Chinese\", value: \"zh\" },\n] as const\n\nconst FormSchema = z.object({\n language: z.string({\n message: \"Please select a language.\",\n }),\n})\n\nexport default function ComboboxForm() {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n })\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast({\n title: \"You submitted the following values:\",\n description: (\n <pre className=\"mt-2 w-[340px] rounded-md bg-slate-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n })\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <FormField\n control={form.control}\n name=\"language\"\n render={({ field }) => (\n <FormItem className=\"flex flex-col\">\n <FormLabel>Language</FormLabel>\n <Popover>\n <PopoverTrigger asChild>\n <FormControl>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n className={cn(\n \"w-[200px] justify-between\",\n !field.value && \"text-muted-foreground\"\n )}\n >\n {field.value\n ? languages.find(\n (language) => language.value === field.value\n )?.label\n : \"Select language\"}\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search language...\" />\n <CommandEmpty>No language found.</CommandEmpty>\n <CommandGroup>\n {languages.map((language) => (\n <CommandItem\n value={language.label}\n key={language.value}\n onSelect={() => {\n form.setValue(\"language\", language.value)\n }}\n >\n <Check\n className={cn(\n \"mr-2 h-4 w-4\",\n language.value === field.value\n ? \"opacity-100\"\n : \"opacity-0\"\n )}\n />\n {language.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </Command>\n </PopoverContent>\n </Popover>\n <FormDescription>\n This is the language that will be used in the dashboard.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "command-demo.tsx",
|
||||
"content": "import {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from \"lucide-react\"\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@/registry/default/ui/command\"\n\nexport default function CommandDemo() {\n return (\n <Command className=\"rounded-lg border shadow-md\">\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar className=\"mr-2 h-4 w-4\" />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile className=\"mr-2 h-4 w-4\" />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem>\n <Calculator className=\"mr-2 h-4 w-4\" />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User className=\"mr-2 h-4 w-4\" />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard className=\"mr-2 h-4 w-4\" />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings className=\"mr-2 h-4 w-4\" />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n )\n}\n"
|
||||
"content": "import {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from \"lucide-react\"\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@/registry/default/ui/command\"\n\nexport default function CommandDemo() {\n return (\n <Command className=\"rounded-lg border shadow-md md:min-w-[450px]\">\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem disabled>\n <Calculator />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "command-dialog.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from \"lucide-react\"\n\nimport {\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@/registry/default/ui/command\"\n\nexport default function CommandDialogDemo() {\n const [open, setOpen] = React.useState(false)\n\n React.useEffect(() => {\n const down = (e: KeyboardEvent) => {\n if (e.key === \"j\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault()\n setOpen((open) => !open)\n }\n }\n\n document.addEventListener(\"keydown\", down)\n return () => document.removeEventListener(\"keydown\", down)\n }, [])\n\n return (\n <>\n <p className=\"text-sm text-muted-foreground\">\n Press{\" \"}\n <kbd className=\"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100\">\n <span className=\"text-xs\">⌘</span>J\n </kbd>\n </p>\n <CommandDialog open={open} onOpenChange={setOpen}>\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar className=\"mr-2 h-4 w-4\" />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile className=\"mr-2 h-4 w-4\" />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem>\n <Calculator className=\"mr-2 h-4 w-4\" />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User className=\"mr-2 h-4 w-4\" />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard className=\"mr-2 h-4 w-4\" />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings className=\"mr-2 h-4 w-4\" />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </CommandDialog>\n </>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from \"lucide-react\"\n\nimport {\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@/registry/default/ui/command\"\n\nexport default function CommandDialogDemo() {\n const [open, setOpen] = React.useState(false)\n\n React.useEffect(() => {\n const down = (e: KeyboardEvent) => {\n if (e.key === \"j\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault()\n setOpen((open) => !open)\n }\n }\n\n document.addEventListener(\"keydown\", down)\n return () => document.removeEventListener(\"keydown\", down)\n }, [])\n\n return (\n <>\n <p className=\"text-sm text-muted-foreground\">\n Press{\" \"}\n <kbd className=\"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100\">\n <span className=\"text-xs\">⌘</span>J\n </kbd>\n </p>\n <CommandDialog open={open} onOpenChange={setOpen}>\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem>\n <Calculator />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </CommandDialog>\n </>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "communication-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../communication-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "company-profile.tsx",
|
||||
"content": "export * from \"../ui/company-profile\"\n"
|
||||
"content": "export { default } from \"../ui/company-profile\"\nexport * from \"../ui/company-profile\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:finance",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "context-switcher-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../context-switcher-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "crypto-screener.tsx",
|
||||
"content": "export * from \"../ui/crypto-screener\"\n"
|
||||
"content": "export { default } from \"../ui/crypto-screener\"\nexport * from \"../ui/crypto-screener\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:finance",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "dashboard-navigation-bar.tsx",
|
||||
"content": "export default function Component() {\n return (\n <div className=\"flex items-center justify-center p-8\">\n <p className=\"text-muted-foreground\">Component coming soon</p>\n </div>\n )\n}\n"
|
||||
"content": "export * from \"../dashboard-navigation-bar\"\n"
|
||||
}
|
||||
],
|
||||
"type": "components:ui"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -11,7 +11,7 @@
|
||||
"files": [
|
||||
{
|
||||
"name": "date-picker-demo.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { format } from \"date-fns\"\nimport { Calendar as CalendarIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Calendar } from \"@/registry/default/ui/calendar\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\n\nexport default function DatePickerDemo() {\n const [date, setDate] = React.useState<Date>()\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[280px] justify-start text-left font-normal\",\n !date && \"text-muted-foreground\"\n )}\n >\n <CalendarIcon className=\"mr-2 h-4 w-4\" />\n {date ? format(date, \"PPP\") : <span>Pick a date</span>}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\">\n <Calendar\n mode=\"single\"\n selected={date}\n onSelect={setDate}\n initialFocus\n />\n </PopoverContent>\n </Popover>\n )\n}\n"
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { format } from \"date-fns\"\nimport { CalendarIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Calendar } from \"@/registry/default/ui/calendar\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/default/ui/popover\"\n\nexport default function DatePickerDemo() {\n const [date, setDate] = React.useState<Date>()\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[280px] justify-start text-left font-normal\",\n !date && \"text-muted-foreground\"\n )}\n >\n <CalendarIcon />\n {date ? format(date, \"PPP\") : <span>Pick a date</span>}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\">\n <Calendar\n mode=\"single\"\n selected={date}\n onSelect={setDate}\n initialFocus\n />\n </PopoverContent>\n </Popover>\n )\n}\n"
|
||||
}
|
||||
],
|
||||
"type": "components:example"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user