mirror of
https://github.com/supabase/supabase.git
synced 2026-10-16 06:39:09 +03:00
Add needed components for documenting components.
This commit is contained in:
1 parent
87997e61d2
commit
d9d46737f0
17 files changed
+504
-103
No files matched your search
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "app/globals.css",
|
||||
"baseColor": "gray",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/registry/default/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/registry/default/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
'use client'
|
||||
|
||||
import { RegistryNode } from '@/lib/process-registry'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@ui/components/shadcn/ui/tabs'
|
||||
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock'
|
||||
import { File, Folder } from 'fumadocs-ui/components/files'
|
||||
import { useState } from 'react'
|
||||
import { BlockItemPreview } from './block-item'
|
||||
|
||||
interface BlockItemCodeProps {
|
||||
files: RegistryNode[]
|
||||
}
|
||||
|
||||
const demoUrls: Record<string, string> = {
|
||||
'src/registry/blocks/password-based-auth-nextjs/app/login/page.tsx':
|
||||
'/blocks/password-based-auth-nextjs/login',
|
||||
'src/registry/blocks/password-based-auth-nextjs/app/sign-up/page.tsx':
|
||||
'/blocks/password-based-auth-nextjs/sign-up',
|
||||
'src/registry/blocks/password-based-auth-nextjs/app/sign-up-success/page.tsx':
|
||||
'/blocks/password-based-auth-nextjs/sign-up-success',
|
||||
'src/registry/blocks/password-based-auth-nextjs/app/forgot-password/page.tsx':
|
||||
'/blocks/password-based-auth-nextjs/forgot-password',
|
||||
'src/registry/blocks/password-based-auth-nextjs/app/update-password/page.tsx':
|
||||
'/blocks/password-based-auth-nextjs/update-password',
|
||||
}
|
||||
|
||||
function FileTree({
|
||||
items,
|
||||
onFileSelect,
|
||||
}: {
|
||||
items: RegistryNode[]
|
||||
onFileSelect: (file: RegistryNode) => void
|
||||
}) {
|
||||
if (items.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{items.map((item, index) => {
|
||||
if (item.type === 'directory') {
|
||||
return (
|
||||
<Folder key={index} name={item.name} defaultOpen>
|
||||
<FileTree onFileSelect={onFileSelect} items={item.children ?? []} />
|
||||
</Folder>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<File
|
||||
key={index}
|
||||
name={item.name}
|
||||
onClick={() => onFileSelect(item)}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function BlockItemCode({ files }: BlockItemCodeProps) {
|
||||
const initialFile = files.find((file) => file.type === 'file') || null
|
||||
const [selectedFile, setSelectedFile] = useState(initialFile)
|
||||
|
||||
const selectedFilePath = selectedFile?.path.startsWith('/')
|
||||
? selectedFile?.path.slice(1)
|
||||
: selectedFile?.path
|
||||
const selectedFileExtension = (selectedFile?.name.split('.').pop() ?? 'ts') as 'ts' | 'tsx'
|
||||
|
||||
const selectedFileDemoUrl = selectedFile?.originalPath
|
||||
? demoUrls[selectedFile?.originalPath]
|
||||
: null
|
||||
|
||||
return (
|
||||
<div className="flex border rounded-lg overflow-hidden h-[652px] not-prose">
|
||||
{/* File browser sidebar */}
|
||||
<div className="w-64 border-r bg-muted/30 overflow-y-auto">
|
||||
<div className="border-b bg-muted/50 h-12 items-center flex px-2">
|
||||
<h3 className="font-medium text-sm">Files</h3>
|
||||
</div>
|
||||
<div className="p-2">
|
||||
<FileTree items={files} onFileSelect={setSelectedFile} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Code display area */}
|
||||
<div className="flex-1 overflow-auto bg-muted/10" key={selectedFile?.path}>
|
||||
{selectedFile?.content ? (
|
||||
<div className="h-full">
|
||||
<Tabs defaultValue="code" className="h-full gap-0">
|
||||
<div className="h-12 flex items-center justify-between px-2">
|
||||
<span>{selectedFilePath}</span>
|
||||
{selectedFileDemoUrl && (
|
||||
<TabsList>
|
||||
<TabsTrigger value="preview">Preview</TabsTrigger>
|
||||
<TabsTrigger value="code">Code</TabsTrigger>
|
||||
</TabsList>
|
||||
)}
|
||||
</div>
|
||||
<TabsContent
|
||||
value="code"
|
||||
className="rounded-none [&_figure]:rounded-none [&_figure]:h-full [&_div[data-radix-scroll-area-viewport]]:min-h-[600px]"
|
||||
>
|
||||
<DynamicCodeBlock lang={selectedFileExtension} code={selectedFile?.content} />
|
||||
</TabsContent>
|
||||
<TabsContent value="preview" className="h-full flex-1">
|
||||
{selectedFileDemoUrl && <BlockItemPreview title="" src={selectedFileDemoUrl} />}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-muted-foreground">
|
||||
No file selected or file content unavailable
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Command } from '@/components/command'
|
||||
import { OpenInV0Button } from '@/components/open-in-v0-button'
|
||||
|
||||
interface BlockItemProps {
|
||||
name: string
|
||||
title: string
|
||||
description: string
|
||||
src: string
|
||||
}
|
||||
|
||||
export const BlockItem = ({ name, description }: BlockItemProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 p-4 relative">
|
||||
<Command name={name} />
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-sm text-muted-foreground sm:pl-3">{description}</h2>
|
||||
<OpenInV0Button name={name} className="w-fit" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const BlockItemPreview = ({ title, src }: { title: string; src: string }) => {
|
||||
return (
|
||||
<div className="flex items-center justify-center relative border rounded-lg">
|
||||
<iframe src={src} className="w-full h-[600px] border-0 rounded-md" title={title} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
'use client'
|
||||
|
||||
import { Check, Copy } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Button_Shadcn_ } from 'ui'
|
||||
|
||||
export function CommandCopyButton({ command }: { command: string }) {
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (copied) {
|
||||
const timeout = setTimeout(() => setCopied(false), 2000)
|
||||
return () => clearTimeout(timeout)
|
||||
}
|
||||
}, [copied])
|
||||
|
||||
return (
|
||||
<Button_Shadcn_
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-[#888] hover:text-white"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(command)
|
||||
setCopied(true)
|
||||
}}
|
||||
>
|
||||
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
||||
</Button_Shadcn_>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { CommandCopyButton } from "./command-copy-button"
|
||||
|
||||
interface CommandCopyProps {
|
||||
name: string
|
||||
}
|
||||
|
||||
export function Command({ name }: CommandCopyProps) {
|
||||
const command = `npx shadcn@latest add ${
|
||||
process.env.VERCEL_TARGET_ENV === "production"
|
||||
? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
|
||||
: process.env.VERCEL_TARGET_ENV === "preview"
|
||||
? `https://${process.env.VERCEL_PROJECT_PREVIEW_URL}`
|
||||
: "http://localhost:3000"
|
||||
}/r/${name}.json`
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative flex items-center rounded-lg bg-black px-4 py-3">
|
||||
<div className="flex-1 font-mono text-sm text-white">
|
||||
<span className="mr-2 text-[#888]">$</span>
|
||||
{command}
|
||||
</div>
|
||||
<CommandCopyButton command={command} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { Index } from '@/__registry__'
|
||||
import * as React from 'react'
|
||||
|
||||
import { useConfig } from '@/hooks/use-config'
|
||||
import {
|
||||
Button,
|
||||
CollapsibleContent_Shadcn_,
|
||||
@@ -10,22 +11,6 @@ import {
|
||||
Collapsible_Shadcn_,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { useConfig } from '@/hooks/use-config'
|
||||
import {
|
||||
// CopyButton,
|
||||
CopyWithClassNames,
|
||||
} from '@/components/copy-button'
|
||||
// import { Icons } from '@/components/icons'
|
||||
// import { StyleSwitcher } from '@/components/style-switcher'
|
||||
// import { ThemeWrapper } from '@/components/theme-wrapper'
|
||||
import {
|
||||
Tabs_Shadcn_ as Tabs,
|
||||
TabsContent_Shadcn_ as TabsContent,
|
||||
TabsList_Shadcn_ as TabsList,
|
||||
TabsTrigger_Shadcn_ as TabsTrigger,
|
||||
} from 'ui'
|
||||
|
||||
// import { LoaderCircle } from 'lucide-react'
|
||||
|
||||
import { styles } from '@/registry/styles'
|
||||
import { ChevronRight, Expand } from 'lucide-react'
|
||||
@@ -57,18 +42,10 @@ export function ComponentPreview({
|
||||
const [config] = useConfig()
|
||||
const index = styles.findIndex((style) => style.name === config.style)
|
||||
|
||||
const Codes = React.Children.toArray(children) as React.ReactElement[]
|
||||
const Code = Codes[index]
|
||||
|
||||
const [expand, setExpandState] = React.useState(false)
|
||||
|
||||
const Preview = React.useMemo(() => {
|
||||
// console.log('Index', Index)
|
||||
// console.log('name', name)
|
||||
// console.log('config.style', config.style)
|
||||
|
||||
const Component = Index[config.style][name]?.component
|
||||
// const Component = Index[name]?.component
|
||||
|
||||
if (!Component) {
|
||||
return (
|
||||
@@ -85,19 +62,14 @@ export function ComponentPreview({
|
||||
return <Component />
|
||||
}, [name, config.style])
|
||||
|
||||
const codeString = React.useMemo(() => {
|
||||
if (typeof Code?.props['data-rehype-pretty-code-fragment'] !== 'undefined') {
|
||||
const [, Button] = React.Children.toArray(Code.props.children) as React.ReactElement[]
|
||||
return Button?.props?.value || Button?.props?.__rawString__ || null
|
||||
}
|
||||
}, [Code])
|
||||
const Codes = React.Children.toArray(children) as React.ReactElement[]
|
||||
const Code = Codes[index]
|
||||
|
||||
const ComponentPreview = React.useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
{/* <ThemeWrapper defaultTheme="zinc"> */}
|
||||
<div
|
||||
className={cn('preview flex min-h-[350px] w-full justify-center p-10', {
|
||||
className={cn('preview flex min-h-[350px] w-full justify-center p-10 theme-original', {
|
||||
'items-center': align === 'center',
|
||||
'items-start': align === 'start',
|
||||
'items-end': align === 'end',
|
||||
@@ -105,17 +77,12 @@ export function ComponentPreview({
|
||||
>
|
||||
<React.Suspense
|
||||
fallback={
|
||||
<div className="flex items-center text-sm text-muted-foreground">
|
||||
{/* <Icons.spinner className="mr-2 h-4 w-4 animate-spin" /> */}
|
||||
{/* <LoaderCircle className="mr-2 h-4 w-4 animate-spin" /> */}
|
||||
Loading...
|
||||
</div>
|
||||
<div className="flex items-center text-sm text-muted-foreground">Loading...</div>
|
||||
}
|
||||
>
|
||||
{Preview}
|
||||
</React.Suspense>
|
||||
</div>
|
||||
{/* </ThemeWrapper> */}
|
||||
</>
|
||||
)
|
||||
}, [Preview, align])
|
||||
@@ -219,40 +186,4 @@ export function ComponentPreview({
|
||||
</Collapsible_Shadcn_>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn('group relative my-4 flex flex-col gap-2', wideClasses, className)}
|
||||
{...props}
|
||||
>
|
||||
<Tabs defaultValue="preview" className="relative mr-auto w-full">
|
||||
<div className="flex items-center justify-between pb-3">
|
||||
<TabsList className="w-full justify-start rounded-none border-b bg-transparent p-0">
|
||||
<TabsTrigger
|
||||
value="preview"
|
||||
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
Preview
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="code"
|
||||
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
Code
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
<TabsContent value="preview" className="relative rounded-md border bg-studio">
|
||||
{ComponentPreview}
|
||||
</TabsContent>
|
||||
<TabsContent value="code">
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="w-full rounded-md [&_pre]:my-0 [&_pre]:max-h-[350px] [&_pre]:overflow-auto">
|
||||
{Code}
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,53 +1,49 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { useMDXComponent } from 'next-contentlayer2/hooks'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { useMDXComponent } from 'next-contentlayer2/hooks'
|
||||
import * as React from 'react'
|
||||
// import { NpmCommands } from 'types/unist'
|
||||
// import { Event } from '@/lib/events'
|
||||
import { cn } from 'ui'
|
||||
import { useConfig } from '@/hooks/use-config'
|
||||
import { Callout } from '@/components/callout'
|
||||
import { CodeBlockWrapper } from '@/components/code-block-wrapper'
|
||||
import { ComponentExample } from '@/components/component-example'
|
||||
import { ComponentPreview } from '@/components/component-preview'
|
||||
import { ComponentSource } from '@/components/component-source'
|
||||
import {
|
||||
CopyButton,
|
||||
// CopyNpmCommandButton
|
||||
} from '@/components/copy-button'
|
||||
import { CopyButton } from '@/components/copy-button'
|
||||
import { useConfig } from '@/hooks/use-config'
|
||||
import { cn } from 'ui'
|
||||
// import { FrameworkDocs } from '@/components/framework-docs'
|
||||
import { StyleWrapper } from './style-wrapper'
|
||||
import { CodeFragment } from '@/components/code-fragment'
|
||||
import { Colors } from '@/components/colors'
|
||||
import { Icons } from '@/components/icons'
|
||||
import { ThemeSettings } from '@/components/theme-settings'
|
||||
import { Style } from '@/registry/styles'
|
||||
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock'
|
||||
import {
|
||||
Accordion_Shadcn_ as Accordion,
|
||||
AccordionContent_Shadcn_ as AccordionContent,
|
||||
AccordionItem_Shadcn_ as AccordionItem,
|
||||
AccordionTrigger_Shadcn_ as AccordionTrigger,
|
||||
} from 'ui'
|
||||
import {
|
||||
Alert_Shadcn_ as Alert,
|
||||
AlertDescription_Shadcn_ as AlertDescription,
|
||||
AlertTitle_Shadcn_ as AlertTitle,
|
||||
} from 'ui'
|
||||
import { AspectRatio } from 'ui'
|
||||
import {
|
||||
AspectRatio,
|
||||
Tabs_Shadcn_ as Tabs,
|
||||
TabsContent_Shadcn_ as TabsContent,
|
||||
TabsList_Shadcn_ as TabsList,
|
||||
TabsTrigger_Shadcn_ as TabsTrigger,
|
||||
} from 'ui'
|
||||
import { ComponentProps } from './component-props'
|
||||
import { Style } from '@/registry/styles'
|
||||
import { Colors } from '@/components/colors'
|
||||
import { Icons } from '@/components/icons'
|
||||
import { ThemeSettings } from '@/components/theme-settings'
|
||||
import { CodeFragment } from '@/components/code-fragment'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { BlockItem } from './block-item'
|
||||
import { ComponentProps } from './component-props'
|
||||
import { SonnerExpandConfig } from './sonner-expand-config'
|
||||
import { SonnerPositionConfig } from './sonner-expand-position'
|
||||
import { StyleWrapper } from './style-wrapper'
|
||||
|
||||
const components = {
|
||||
DynamicCodeBlock,
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
@@ -277,6 +273,7 @@ const components = {
|
||||
Admonition,
|
||||
SonnerExpandConfig,
|
||||
SonnerPositionConfig,
|
||||
BlockItem,
|
||||
}
|
||||
|
||||
interface MdxProps {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
'use client'
|
||||
|
||||
import { useTheme } from 'next-themes'
|
||||
import * as React from 'react'
|
||||
|
||||
import { Moon, Sun } from 'lucide-react'
|
||||
import { Button_Shadcn_ } from 'ui'
|
||||
|
||||
export function ModeToggle() {
|
||||
const { setTheme, resolvedTheme } = useTheme()
|
||||
const [, startTransition] = React.useTransition()
|
||||
|
||||
return (
|
||||
<Button_Shadcn_
|
||||
className="h-7 w-7"
|
||||
onClick={() => {
|
||||
startTransition(() => {
|
||||
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')
|
||||
})
|
||||
}}
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
>
|
||||
<Moon className="dark:hidden" />
|
||||
<Sun className="hidden dark:block" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button_Shadcn_>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button_Shadcn_ } from 'ui'
|
||||
|
||||
export function OpenInV0Button({
|
||||
name,
|
||||
className,
|
||||
}: { name: string } & React.ComponentProps<typeof Button_Shadcn_>) {
|
||||
return (
|
||||
<Button_Shadcn_
|
||||
aria-label="Open in v0"
|
||||
className={cn(
|
||||
'h-7 gap-1 rounded-lg shadow-none bg-black px-3 text-xs text-white hover:bg-black hover:text-white dark:bg-white dark:text-black',
|
||||
className
|
||||
)}
|
||||
asChild
|
||||
>
|
||||
<a
|
||||
href={`https://v0.dev/chat/api/open?url=https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}/r/${name}.json`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Open in{' '}
|
||||
<svg
|
||||
viewBox="0 0 40 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5 text-current"
|
||||
>
|
||||
<path
|
||||
d="M23.3919 0H32.9188C36.7819 0 39.9136 3.13165 39.9136 6.99475V16.0805H36.0006V6.99475C36.0006 6.90167 35.9969 6.80925 35.9898 6.71766L26.4628 16.079C26.4949 16.08 26.5272 16.0805 26.5595 16.0805H36.0006V19.7762H26.5595C22.6964 19.7762 19.4788 16.6139 19.4788 12.7508V3.68923H23.3919V12.7508C23.3919 12.9253 23.4054 13.0977 23.4316 13.2668L33.1682 3.6995C33.0861 3.6927 33.003 3.68923 32.9188 3.68923H23.3919V0Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
d="M13.7688 19.0956L0 3.68759H5.53933L13.6231 12.7337V3.68759H17.7535V17.5746C17.7535 19.6705 15.1654 20.6584 13.7688 19.0956Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</Button_Shadcn_>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
"use client"
|
||||
|
||||
import { ThemeProvider } from "next-themes"
|
||||
|
||||
export function Providers({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
disableTransitionOnChange
|
||||
enableSystem
|
||||
>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 'use server'
|
||||
|
||||
// import { generateRegistryTree } from '@/lib/process-registry'
|
||||
// import path from 'path'
|
||||
// import { BlockItemCode } from './block-item-code'
|
||||
|
||||
// export async function RegistryBlock({ itemName }: { itemName: string }) {
|
||||
// const registryPath = path.join(process.cwd(), 'public', 'r', `${itemName}.json`)
|
||||
// const tree = generateRegistryTree(itemName, registryPath)
|
||||
|
||||
// return <BlockItemCode files={tree} />
|
||||
// }
|
||||
@@ -0,0 +1,15 @@
|
||||
export function TailwindIndicator() {
|
||||
if (process.env.NODE_ENV === 'production' || process.env.HIDE_TAILWIND_INDICATOR === '1')
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-1 left-1 z-50 flex h-6 w-6 items-center justify-center rounded-full bg-zinc-800 p-3 font-mono text-xs text-white">
|
||||
<div className="block sm:hidden">xs</div>
|
||||
<div className="hidden sm:block md:hidden">sm</div>
|
||||
<div className="hidden md:block lg:hidden">md</div>
|
||||
<div className="hidden lg:block xl:hidden">lg</div>
|
||||
<div className="hidden xl:block 2xl:hidden">xl</div>
|
||||
<div className="hidden 2xl:block">2xl</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
import { Style } from '@/registry/styles'
|
||||
import { Theme } from '@/registry/themes'
|
||||
// import { Theme } from '@/registry/themes'
|
||||
import { useAtom } from 'jotai'
|
||||
import { atomWithStorage } from 'jotai/utils'
|
||||
import { ComponentProps } from 'react'
|
||||
import { SonnerToaster } from 'ui'
|
||||
// import { BackendProvider } from '@/registry/backend-provider'
|
||||
|
||||
type Config = {
|
||||
style: Style['name']
|
||||
theme: Theme['name']
|
||||
// theme: Theme['name']
|
||||
radius: number
|
||||
sonnerPosition: ComponentProps<typeof SonnerToaster>['position']
|
||||
sonnerExpand: boolean
|
||||
@@ -17,11 +16,10 @@ type Config = {
|
||||
|
||||
const configAtom = atomWithStorage<Config>('config', {
|
||||
style: 'default',
|
||||
theme: 'zinc',
|
||||
// theme: 'zinc',
|
||||
radius: 0.5,
|
||||
sonnerPosition: 'bottom-right',
|
||||
sonnerExpand: false,
|
||||
// backendProvider: 'nextjs-auth',
|
||||
})
|
||||
|
||||
export function useConfig() {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import * as fs from 'fs'
|
||||
|
||||
export interface RegistryNode {
|
||||
name: string
|
||||
path: string
|
||||
originalPath: string
|
||||
type: 'directory' | 'file'
|
||||
children?: RegistryNode[]
|
||||
content?: string
|
||||
}
|
||||
|
||||
interface RegistryFile {
|
||||
path: string
|
||||
target?: string
|
||||
type: string
|
||||
content: string
|
||||
}
|
||||
|
||||
const DEFAULT_PATHS = {
|
||||
component: '/components',
|
||||
hook: '/hooks',
|
||||
util: '/lib',
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Converts a flat registry array into a hierarchical file tree structure
|
||||
*/
|
||||
export function generateRegistryTree(blockName: string, registryPath: string): RegistryNode[] {
|
||||
const registry = JSON.parse(fs.readFileSync(registryPath, 'utf-8')) as { files: RegistryFile[] }
|
||||
const tree: RegistryNode[] = []
|
||||
|
||||
const sortedRegistry = [...registry.files].sort((a, b) => a.path.localeCompare(b.path))
|
||||
|
||||
for (const file of sortedRegistry) {
|
||||
const itemPath = file.target || getDefaultPath(file)
|
||||
const pathParts = itemPath.split('/').filter(Boolean)
|
||||
let currentLevel = tree
|
||||
|
||||
for (let i = 0; i < pathParts.length; i++) {
|
||||
const part = pathParts[i]
|
||||
const isLast = i === pathParts.length - 1
|
||||
const path = '/' + pathParts.slice(0, i + 1).join('/')
|
||||
|
||||
let node = currentLevel.find((n) => n.name === part)
|
||||
|
||||
// Remove any paths in the file content that point to the block directory.
|
||||
const content = file.content
|
||||
.replaceAll(/@\/registry\/blocks\/.+?\//gi, '@/')
|
||||
.replaceAll(/@\/registry\//gi, '@/')
|
||||
|
||||
if (!node) {
|
||||
node = {
|
||||
name: part,
|
||||
path,
|
||||
originalPath: file.path,
|
||||
type: isLast ? 'file' : 'directory',
|
||||
...(isLast ? { content } : { children: [] }),
|
||||
}
|
||||
currentLevel.push(node)
|
||||
}
|
||||
|
||||
if (!isLast) {
|
||||
node.children = node.children || []
|
||||
currentLevel = node.children
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the default path for an item based on its type
|
||||
*/
|
||||
function getDefaultPath(item: RegistryFile): string {
|
||||
const type = item.type.toLowerCase() || ''
|
||||
const basePath = DEFAULT_PATHS[type as keyof typeof DEFAULT_PATHS] || ''
|
||||
// clean all paths that start with paths specific to this repo organization
|
||||
const filePath = item.path.replace(/src\/registry\/blocks\/.+?\//, '')
|
||||
|
||||
return `${basePath}/${filePath}`
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { withContentlayer } from 'next-contentlayer2'
|
||||
|
||||
const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH || '/design-system'
|
||||
const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH || '/ui'
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
transpilePackages: ['ui', 'common', 'shared-data', 'icons', 'tsconfig'],
|
||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH || '/design-system',
|
||||
basePath: BASE_PATH,
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
@@ -36,6 +36,10 @@ const nextConfig = {
|
||||
: []),
|
||||
]
|
||||
},
|
||||
eslint: {
|
||||
// We are already running linting via GH action, this will skip linting during production build on Vercel
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
}
|
||||
|
||||
export default withContentlayer(nextConfig)
|
||||
@@ -1,6 +1,7 @@
|
||||
const config = require('config/tailwind.config')
|
||||
|
||||
module.exports = config({
|
||||
darkMode: ['class'],
|
||||
content: [
|
||||
'./app/**/*.{js,ts,jsx,tsx}',
|
||||
'./components/**/*.{js,ts,jsx,tsx}',
|
||||
@@ -16,6 +17,55 @@ module.exports = config({
|
||||
maxWidth: {
|
||||
site: '128rem',
|
||||
},
|
||||
// The following variables are needed for the shadcn components in the examples to work. They're not clashing
|
||||
// with the variables in the ui package.
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
colors: {
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
chart: {
|
||||
1: 'hsl(var(--chart-1))',
|
||||
2: 'hsl(var(--chart-2))',
|
||||
3: 'hsl(var(--chart-3))',
|
||||
4: 'hsl(var(--chart-4))',
|
||||
5: 'hsl(var(--chart-5))',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -12,7 +12,7 @@
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
|
||||
Reference in new issue
Block a user