mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-07-01 08:34:12 +00:00
Compare commits
1 Commits
dependabot
...
shadcn/req
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84eb464ae1 |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"shadcn": patch
|
||||
---
|
||||
|
||||
Fix utils import transform when workspace alias does not start with @
|
||||
131
.github/workflows/request.yml
vendored
Normal file
131
.github/workflows/request.yml
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
name: "Convert requests to discussions"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# This runs every hour: https://crontab.guru/#0_*_*_*_*
|
||||
- cron: "0 * * * *"
|
||||
|
||||
jobs:
|
||||
convert:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'shadcn-ui'
|
||||
steps:
|
||||
- name: "Convert issues to discussions"
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
// Fetch issues with "area: request" label (limit 20).
|
||||
const { data: issues } = await github.rest.issues.listForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: 'area: request',
|
||||
state: 'open',
|
||||
per_page: 20,
|
||||
sort: 'created',
|
||||
direction: 'asc',
|
||||
});
|
||||
|
||||
console.log(`Found ${issues.length} issues with "area: request" label`);
|
||||
|
||||
if (issues.length === 0) {
|
||||
console.log('No issues to convert');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the repository node ID for GraphQL queries.
|
||||
const repoQuery = `
|
||||
query getRepo($owner: String!, $repo: String!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
id
|
||||
discussionCategories(first: 20) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const repoResult = await github.graphql(repoQuery, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
const requestsCategory = repoResult.repository.discussionCategories.nodes.find(
|
||||
cat => cat.name.toLowerCase() === 'requests' || cat.slug.toLowerCase() === 'requests'
|
||||
);
|
||||
|
||||
if (!requestsCategory) {
|
||||
throw new Error('Requests category not found in discussions. Available categories: ' +
|
||||
repoResult.repository.discussionCategories.nodes.map(c => c.name).join(', '));
|
||||
}
|
||||
|
||||
// Convert each issue to a discussion.
|
||||
for (const issue of issues) {
|
||||
try {
|
||||
// Create discussion from issue using GraphQL.
|
||||
const discussionTitle = issue.title;
|
||||
const discussionBody = `**Converted from issue #${issue.number}**
|
||||
|
||||
${issue.body || ''}
|
||||
|
||||
---
|
||||
|
||||
_This discussion was automatically created from [issue #${issue.number}](${issue.html_url})_`;
|
||||
|
||||
const createDiscussionMutation = `
|
||||
mutation createDiscussion($repositoryId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
|
||||
createDiscussion(input: {
|
||||
repositoryId: $repositoryId
|
||||
categoryId: $categoryId
|
||||
title: $title
|
||||
body: $body
|
||||
}) {
|
||||
discussion {
|
||||
id
|
||||
number
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const discussionResult = await github.graphql(createDiscussionMutation, {
|
||||
repositoryId: repoResult.repository.id,
|
||||
categoryId: requestsCategory.id,
|
||||
title: discussionTitle,
|
||||
body: discussionBody,
|
||||
});
|
||||
|
||||
const discussion = discussionResult.createDiscussion.discussion;
|
||||
console.log(`Created discussion #${discussion.number} from issue #${issue.number}`);
|
||||
|
||||
// Add a comment to the original issue linking to the discussion.
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
body: `This issue has been converted to a discussion: [#${discussion.number}](${discussion.url})`,
|
||||
});
|
||||
|
||||
// Close the original issue.
|
||||
await github.rest.issues.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
state: 'closed',
|
||||
});
|
||||
|
||||
console.log(`Closed issue #${issue.number}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to convert issue #${issue.number}:`, error);
|
||||
// Continue with next issue instead of failing the entire workflow.
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Completed processing ${issues.length} issues`);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { Metadata } from "next"
|
||||
import { NuqsAdapter } from "nuqs/adapters/next/app"
|
||||
|
||||
import { META_THEME_COLORS, siteConfig } from "@/lib/config"
|
||||
import { fontVariables } from "@/lib/fonts"
|
||||
@@ -85,20 +84,18 @@ export default function RootLayout({
|
||||
</head>
|
||||
<body
|
||||
className={cn(
|
||||
"group/body overscroll-none antialiased [--footer-height:calc(var(--spacing)*14)] [--header-height:calc(var(--spacing)*14)] xl:[--footer-height:calc(var(--spacing)*24)]",
|
||||
"group/body theme-blue overscroll-none antialiased [--footer-height:calc(var(--spacing)*14)] [--header-height:calc(var(--spacing)*14)] xl:[--footer-height:calc(var(--spacing)*24)]",
|
||||
fontVariables
|
||||
)}
|
||||
>
|
||||
<ThemeProvider>
|
||||
<LayoutProvider>
|
||||
<NuqsAdapter>
|
||||
<ActiveThemeProvider>
|
||||
{children}
|
||||
<TailwindIndicator />
|
||||
<Toaster position="top-center" />
|
||||
<Analytics />
|
||||
</ActiveThemeProvider>
|
||||
</NuqsAdapter>
|
||||
<ActiveThemeProvider initialTheme="blue">
|
||||
{children}
|
||||
<TailwindIndicator />
|
||||
<Toaster position="top-center" />
|
||||
<Analytics />
|
||||
</ActiveThemeProvider>
|
||||
</LayoutProvider>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
useState,
|
||||
} from "react"
|
||||
|
||||
const DEFAULT_THEME = "default"
|
||||
const DEFAULT_THEME = "blue"
|
||||
|
||||
type ThemeContextType = {
|
||||
activeTheme: string
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { IconArrowUpRight } from "@tabler/icons-react"
|
||||
|
||||
import { useSearchRegistry } from "@/hooks/use-search-registry"
|
||||
import { DirectoryAddButton } from "@/components/directory-add-button"
|
||||
import globalRegistries from "@/registry/directory.json"
|
||||
import registries from "@/registry/directory.json"
|
||||
import { Button } from "@/registry/new-york-v4/ui/button"
|
||||
import {
|
||||
Item,
|
||||
@@ -19,72 +16,55 @@ import {
|
||||
ItemTitle,
|
||||
} from "@/registry/new-york-v4/ui/item"
|
||||
|
||||
import { SearchDirectory } from "./search-directory"
|
||||
|
||||
function getHomepageUrl(homepage: string) {
|
||||
const url = new URL(homepage)
|
||||
url.searchParams.set("utm_source", "ui.shadcn.com")
|
||||
url.searchParams.set("utm_medium", "referral")
|
||||
url.searchParams.set("utm_campaign", "directory")
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
export function DirectoryList() {
|
||||
const { registries } = useSearchRegistry()
|
||||
|
||||
return (
|
||||
<div className="mt-6">
|
||||
<SearchDirectory />
|
||||
<ItemGroup className="my-8">
|
||||
{registries.map((registry, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<Item className="group/item relative gap-6 px-0">
|
||||
<ItemMedia
|
||||
variant="image"
|
||||
dangerouslySetInnerHTML={{ __html: registry.logo }}
|
||||
className="*:[svg]:fill-foreground grayscale *:[svg]:size-8"
|
||||
/>
|
||||
<ItemContent>
|
||||
<ItemTitle>
|
||||
<a
|
||||
href={getHomepageUrl(registry.homepage)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer external"
|
||||
>
|
||||
{registry.name}
|
||||
</a>
|
||||
</ItemTitle>
|
||||
{registry.description && (
|
||||
<ItemDescription className="text-pretty">
|
||||
{registry.description}
|
||||
</ItemDescription>
|
||||
)}
|
||||
</ItemContent>
|
||||
<ItemActions className="relative z-10 hidden self-start sm:flex">
|
||||
<Button size="sm" variant="outline" asChild>
|
||||
<a
|
||||
href={getHomepageUrl(registry.homepage)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer external"
|
||||
>
|
||||
View <IconArrowUpRight />
|
||||
</a>
|
||||
</Button>
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemActions>
|
||||
<ItemFooter className="justify-start pl-16 sm:hidden">
|
||||
<Button size="sm" variant="outline">
|
||||
<ItemGroup className="my-8">
|
||||
{registries.map((registry, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<Item className="group/item relative gap-6 px-0 sm:px-4">
|
||||
<ItemMedia
|
||||
variant="image"
|
||||
dangerouslySetInnerHTML={{ __html: registry.logo }}
|
||||
className="*:[svg]:fill-foreground grayscale *:[svg]:size-8"
|
||||
/>
|
||||
<ItemContent>
|
||||
<ItemTitle>
|
||||
<a
|
||||
href={registry.homepage}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{registry.name}
|
||||
</a>
|
||||
</ItemTitle>
|
||||
{registry.description && (
|
||||
<ItemDescription className="text-pretty">
|
||||
{registry.description}
|
||||
</ItemDescription>
|
||||
)}
|
||||
</ItemContent>
|
||||
<ItemActions className="relative z-10 hidden self-start sm:flex">
|
||||
<Button size="sm" variant="outline" asChild>
|
||||
<a
|
||||
href={registry.homepage}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
View <IconArrowUpRight />
|
||||
</Button>
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemFooter>
|
||||
</Item>
|
||||
{index < globalRegistries.length - 1 && (
|
||||
<ItemSeparator className="my-1" />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ItemGroup>
|
||||
</div>
|
||||
</a>
|
||||
</Button>
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemActions>
|
||||
<ItemFooter className="justify-start pl-16 sm:hidden">
|
||||
<Button size="sm" variant="outline">
|
||||
View <IconArrowUpRight />
|
||||
</Button>
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemFooter>
|
||||
</Item>
|
||||
{index < registries.length - 1 && <ItemSeparator className="my-1" />}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ItemGroup>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,20 +21,15 @@ export function GitHubLink() {
|
||||
|
||||
export async function StarsCount() {
|
||||
const data = await fetch("https://api.github.com/repos/shadcn-ui/ui", {
|
||||
next: { revalidate: 86400 },
|
||||
next: { revalidate: 86400 }, // Cache for 1 day (86400 seconds)
|
||||
})
|
||||
const json = await data.json()
|
||||
|
||||
const formattedCount =
|
||||
json.stargazers_count >= 1000
|
||||
? json.stargazers_count % 1000 === 0
|
||||
? `${Math.floor(json.stargazers_count / 1000)}k`
|
||||
: `${(json.stargazers_count / 1000).toFixed(1)}k`
|
||||
: json.stargazers_count.toLocaleString()
|
||||
|
||||
return (
|
||||
<span className="text-muted-foreground w-fit text-xs tabular-nums">
|
||||
{formattedCount.replace(".0k", "k")}
|
||||
<span className="text-muted-foreground w-8 text-xs tabular-nums">
|
||||
{json.stargazers_count >= 1000
|
||||
? `${(json.stargazers_count / 1000).toFixed(1)}k`
|
||||
: json.stargazers_count.toLocaleString()}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { Search, X } from "lucide-react"
|
||||
|
||||
import { useSearchRegistry } from "@/hooks/use-search-registry"
|
||||
import { Field } from "@/registry/new-york-v4/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupInput,
|
||||
} from "@/registry/new-york-v4/ui/input-group"
|
||||
|
||||
export const SearchDirectory = () => {
|
||||
const { query, setQuery } = useSearchRegistry()
|
||||
|
||||
const onQueryChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value
|
||||
setQuery(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<Field>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<Search />
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput
|
||||
placeholder="Search"
|
||||
value={query}
|
||||
onChange={onQueryChange}
|
||||
/>
|
||||
<InputGroupAddon
|
||||
align="inline-end"
|
||||
data-disabled={!query.length}
|
||||
className="data-[disabled=true]:hidden"
|
||||
>
|
||||
<InputGroupButton
|
||||
aria-label="Clear"
|
||||
title="Clear"
|
||||
size="icon-xs"
|
||||
onClick={() => setQuery(null)}
|
||||
>
|
||||
<X />
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)
|
||||
}
|
||||
@@ -124,7 +124,9 @@ export function CopyCodeButton({
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="h-auto">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle className="capitalize">{activeThemeName}</DrawerTitle>
|
||||
<DrawerTitle className="capitalize">
|
||||
{activeThemeName === "neutral" ? "Default" : activeThemeName}
|
||||
</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Copy and paste the following code into your CSS file.
|
||||
</DrawerDescription>
|
||||
@@ -147,7 +149,9 @@ export function CopyCodeButton({
|
||||
</DialogTrigger>
|
||||
<DialogContent className="rounded-xl border-none bg-clip-padding shadow-2xl ring-4 ring-neutral-200/80 outline-none md:max-w-2xl dark:bg-neutral-800 dark:ring-neutral-900">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="capitalize">{activeThemeName}</DialogTitle>
|
||||
<DialogTitle className="capitalize">
|
||||
{activeThemeName === "neutral" ? "Default" : activeThemeName}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Copy and paste the following code into your CSS file.
|
||||
</DialogDescription>
|
||||
@@ -161,7 +165,7 @@ export function CopyCodeButton({
|
||||
|
||||
function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
const [hasCopied, setHasCopied] = React.useState(false)
|
||||
const [tailwindVersion, setTailwindVersion] = React.useState("v4-oklch")
|
||||
const [tailwindVersion, setTailwindVersion] = React.useState("v4")
|
||||
const activeTheme = React.useMemo(
|
||||
() => baseColors.find((theme) => theme.name === themeName),
|
||||
[themeName]
|
||||
@@ -187,11 +191,10 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
className="min-w-0 px-4 pb-4 md:p-0"
|
||||
>
|
||||
<TabsList>
|
||||
<TabsTrigger value="v4-oklch">OKLCH</TabsTrigger>
|
||||
<TabsTrigger value="v4-hsl">HSL</TabsTrigger>
|
||||
<TabsTrigger value="v4">Tailwind v4</TabsTrigger>
|
||||
<TabsTrigger value="v3">Tailwind v3</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="v4-oklch">
|
||||
<TabsContent value="v4">
|
||||
<figure
|
||||
data-rehype-pretty-code-figure
|
||||
className="!mx-0 mt-0 rounded-lg"
|
||||
@@ -213,12 +216,14 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
className="bg-code text-code-foreground absolute top-3 right-2 z-10 size-7 shadow-none hover:opacity-100 focus-visible:opacity-100"
|
||||
onClick={() => {
|
||||
copyToClipboardWithMeta(
|
||||
getThemeCodeOKLCH(activeThemeOKLCH, 0.65),
|
||||
tailwindVersion === "v3"
|
||||
? getThemeCode(activeTheme, 0.65)
|
||||
: getThemeCodeOKLCH(activeThemeOKLCH, 0.65),
|
||||
{
|
||||
name: "copy_theme_code",
|
||||
properties: {
|
||||
theme: themeName,
|
||||
radius: 0.65,
|
||||
radius: 0.5,
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -241,8 +246,7 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
className="line text-code-foreground"
|
||||
key={key}
|
||||
>
|
||||
--{key}: <ColorIndicator color={value} />{" "}
|
||||
{value};
|
||||
--{key}: {value};
|
||||
</span>
|
||||
))}
|
||||
<span data-line className="line text-code-foreground">
|
||||
@@ -260,8 +264,7 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
className="line text-code-foreground"
|
||||
key={key}
|
||||
>
|
||||
--{key}: <ColorIndicator color={value} />{" "}
|
||||
{value};
|
||||
--{key}: {value};
|
||||
</span>
|
||||
))}
|
||||
<span data-line className="line text-code-foreground">
|
||||
@@ -271,90 +274,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
</pre>
|
||||
</figure>
|
||||
</TabsContent>
|
||||
<TabsContent value="v4-hsl">
|
||||
<figure
|
||||
data-rehype-pretty-code-figure
|
||||
className="!mx-0 mt-0 rounded-lg"
|
||||
>
|
||||
<figcaption
|
||||
className="text-code-foreground [&_svg]:text-code-foreground flex items-center gap-2 [&_svg]:size-4 [&_svg]:opacity-70"
|
||||
data-rehype-pretty-code-title=""
|
||||
data-language="css"
|
||||
data-theme="github-dark github-light-default"
|
||||
>
|
||||
<Icons.css className="fill-foreground" />
|
||||
app/globals.css
|
||||
</figcaption>
|
||||
<pre className="no-scrollbar max-h-[300px] min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0 md:max-h-[450px]">
|
||||
<Button
|
||||
data-slot="copy-button"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="bg-code text-code-foreground absolute top-3 right-2 z-10 size-7 shadow-none hover:opacity-100 focus-visible:opacity-100"
|
||||
onClick={() => {
|
||||
copyToClipboardWithMeta(
|
||||
getThemeCodeHSLV4(activeTheme, 0.65),
|
||||
{
|
||||
name: "copy_theme_code",
|
||||
properties: {
|
||||
theme: themeName,
|
||||
radius: 0.65,
|
||||
},
|
||||
}
|
||||
)
|
||||
setHasCopied(true)
|
||||
}}
|
||||
>
|
||||
<span className="sr-only">Copy</span>
|
||||
{hasCopied ? <IconCheck /> : <IconCopy />}
|
||||
</Button>
|
||||
<code data-line-numbers data-language="css">
|
||||
<span data-line className="line text-code-foreground">
|
||||
:root {
|
||||
</span>
|
||||
<span data-line className="line text-code-foreground">
|
||||
--radius: 0.65rem;
|
||||
</span>
|
||||
{Object.entries(activeTheme?.cssVars.light || {}).map(
|
||||
([key, value]) => (
|
||||
<span
|
||||
data-line
|
||||
className="line text-code-foreground"
|
||||
key={key}
|
||||
>
|
||||
--{key}:{" "}
|
||||
<ColorIndicator color={`hsl(${value})`} /> hsl({value});
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
<span data-line className="line text-code-foreground">
|
||||
}
|
||||
</span>
|
||||
<span data-line className="line text-code-foreground">
|
||||
|
||||
</span>
|
||||
<span data-line className="line text-code-foreground">
|
||||
.dark {
|
||||
</span>
|
||||
{Object.entries(activeTheme?.cssVars.dark || {}).map(
|
||||
([key, value]) => (
|
||||
<span
|
||||
data-line
|
||||
className="line text-code-foreground"
|
||||
key={key}
|
||||
>
|
||||
--{key}:{" "}
|
||||
<ColorIndicator color={`hsl(${value})`} /> hsl({value});
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
<span data-line className="line text-code-foreground">
|
||||
}
|
||||
</span>
|
||||
</code>
|
||||
</pre>
|
||||
</figure>
|
||||
</TabsContent>
|
||||
<TabsContent value="v3">
|
||||
<figure
|
||||
data-rehype-pretty-code-figure
|
||||
@@ -376,13 +295,18 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
variant="ghost"
|
||||
className="bg-code text-code-foreground absolute top-3 right-2 z-10 size-7 shadow-none hover:opacity-100 focus-visible:opacity-100"
|
||||
onClick={() => {
|
||||
copyToClipboardWithMeta(getThemeCode(activeTheme, 0.5), {
|
||||
name: "copy_theme_code",
|
||||
properties: {
|
||||
theme: themeName,
|
||||
radius: 0.5,
|
||||
},
|
||||
})
|
||||
copyToClipboardWithMeta(
|
||||
tailwindVersion === "v3"
|
||||
? getThemeCode(activeTheme, 0.65)
|
||||
: getThemeCodeOKLCH(activeThemeOKLCH, 0.65),
|
||||
{
|
||||
name: "copy_theme_code",
|
||||
properties: {
|
||||
theme: themeName,
|
||||
radius: 0.5,
|
||||
},
|
||||
}
|
||||
)
|
||||
setHasCopied(true)
|
||||
}}
|
||||
>
|
||||
@@ -398,16 +322,10 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--background:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.light["background"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.light["background"]};
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--foreground:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.light["foreground"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.light["foreground"]};
|
||||
</span>
|
||||
{[
|
||||
@@ -422,13 +340,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
<React.Fragment key={prefix}>
|
||||
<span data-line className="line">
|
||||
--{prefix}:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${
|
||||
activeTheme?.cssVars.light[
|
||||
prefix as keyof typeof activeTheme.cssVars.light
|
||||
]
|
||||
})`}
|
||||
/>{" "}
|
||||
{
|
||||
activeTheme?.cssVars.light[
|
||||
prefix as keyof typeof activeTheme.cssVars.light
|
||||
@@ -438,13 +349,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--{prefix}-foreground:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${
|
||||
activeTheme?.cssVars.light[
|
||||
`${prefix}-foreground` as keyof typeof activeTheme.cssVars.light
|
||||
]
|
||||
})`}
|
||||
/>{" "}
|
||||
{
|
||||
activeTheme?.cssVars.light[
|
||||
`${prefix}-foreground` as keyof typeof activeTheme.cssVars.light
|
||||
@@ -456,23 +360,14 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
))}
|
||||
<span data-line className="line">
|
||||
--border:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.light["border"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.light["border"]};
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--input:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.light["input"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.light["input"]};
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--ring:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.light["ring"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.light["ring"]};
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
@@ -483,13 +378,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
<React.Fragment key={prefix}>
|
||||
<span data-line className="line">
|
||||
--{prefix}:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${
|
||||
activeTheme?.cssVars.light[
|
||||
prefix as keyof typeof activeTheme.cssVars.light
|
||||
]
|
||||
})`}
|
||||
/>{" "}
|
||||
{
|
||||
activeTheme?.cssVars.light[
|
||||
prefix as keyof typeof activeTheme.cssVars.light
|
||||
@@ -511,16 +399,10 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--background:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.dark["background"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.dark["background"]};
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--foreground:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.dark["foreground"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.dark["foreground"]};
|
||||
</span>
|
||||
{[
|
||||
@@ -535,13 +417,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
<React.Fragment key={prefix}>
|
||||
<span data-line className="line">
|
||||
--{prefix}:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${
|
||||
activeTheme?.cssVars.dark[
|
||||
prefix as keyof typeof activeTheme.cssVars.dark
|
||||
]
|
||||
})`}
|
||||
/>{" "}
|
||||
{
|
||||
activeTheme?.cssVars.dark[
|
||||
prefix as keyof typeof activeTheme.cssVars.dark
|
||||
@@ -551,13 +426,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--{prefix}-foreground:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${
|
||||
activeTheme?.cssVars.dark[
|
||||
`${prefix}-foreground` as keyof typeof activeTheme.cssVars.dark
|
||||
]
|
||||
})`}
|
||||
/>{" "}
|
||||
{
|
||||
activeTheme?.cssVars.dark[
|
||||
`${prefix}-foreground` as keyof typeof activeTheme.cssVars.dark
|
||||
@@ -569,23 +437,14 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
))}
|
||||
<span data-line className="line">
|
||||
--border:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.dark["border"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.dark["border"]};
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--input:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.dark["input"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.dark["input"]};
|
||||
</span>
|
||||
<span data-line className="line">
|
||||
--ring:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${activeTheme?.cssVars.dark["ring"]})`}
|
||||
/>{" "}
|
||||
{activeTheme?.cssVars.dark["ring"]};
|
||||
</span>
|
||||
{["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"].map(
|
||||
@@ -593,13 +452,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
<React.Fragment key={prefix}>
|
||||
<span data-line className="line">
|
||||
--{prefix}:{" "}
|
||||
<ColorIndicator
|
||||
color={`hsl(${
|
||||
activeTheme?.cssVars.dark[
|
||||
prefix as keyof typeof activeTheme.cssVars.dark
|
||||
]
|
||||
})`}
|
||||
/>{" "}
|
||||
{
|
||||
activeTheme?.cssVars.dark[
|
||||
prefix as keyof typeof activeTheme.cssVars.dark
|
||||
@@ -625,15 +477,6 @@ function CustomizerCode({ themeName }: { themeName: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
function ColorIndicator({ color }: { color: string }) {
|
||||
return (
|
||||
<span
|
||||
className="border-border/50 inline-block size-3 border"
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function getThemeCodeOKLCH(theme: BaseColorOKLCH | undefined, radius: number) {
|
||||
if (!theme) {
|
||||
return ""
|
||||
@@ -666,27 +509,6 @@ function getThemeCode(theme: BaseColor | undefined, radius: number) {
|
||||
})
|
||||
}
|
||||
|
||||
function getThemeCodeHSLV4(theme: BaseColor | undefined, radius: number) {
|
||||
if (!theme) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const rootSection =
|
||||
":root {\n --radius: " +
|
||||
radius +
|
||||
"rem;\n" +
|
||||
Object.entries(theme.cssVars.light)
|
||||
.map((entry) => " --" + entry[0] + ": hsl(" + entry[1] + ");")
|
||||
.join("\n") +
|
||||
"\n}\n\n.dark {\n" +
|
||||
Object.entries(theme.cssVars.dark)
|
||||
.map((entry) => " --" + entry[0] + ": hsl(" + entry[1] + ");")
|
||||
.join("\n") +
|
||||
"\n}\n"
|
||||
|
||||
return rootSection
|
||||
}
|
||||
|
||||
const BASE_STYLES_WITH_VARIABLES = `
|
||||
@layer base {
|
||||
:root {
|
||||
|
||||
@@ -17,14 +17,12 @@ import { CopyCodeButton } from "./theme-customizer"
|
||||
export function ThemeSelector({ className }: React.ComponentProps<"div">) {
|
||||
const { activeTheme, setActiveTheme } = useThemeConfig()
|
||||
|
||||
const value = activeTheme === "default" ? "neutral" : activeTheme
|
||||
|
||||
return (
|
||||
<div className={cn("flex items-center gap-2", className)}>
|
||||
<Label htmlFor="theme-selector" className="sr-only">
|
||||
Theme
|
||||
</Label>
|
||||
<Select value={value} onValueChange={setActiveTheme}>
|
||||
<Select value={activeTheme} onValueChange={setActiveTheme}>
|
||||
<SelectTrigger
|
||||
id="theme-selector"
|
||||
size="sm"
|
||||
@@ -40,7 +38,7 @@ export function ThemeSelector({ className }: React.ComponentProps<"div">) {
|
||||
value={theme.name}
|
||||
className="data-[state=checked]:opacity-50"
|
||||
>
|
||||
{theme.label}
|
||||
{theme.label === "Neutral" ? "Default" : theme.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -24,7 +24,7 @@ To create a new monorepo project, run the `init` command. You will be prompted
|
||||
to select the type of project you are creating.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest init
|
||||
npx shadcn@canary init
|
||||
```
|
||||
|
||||
Select the `Next.js (Monorepo)` option.
|
||||
@@ -51,15 +51,15 @@ cd apps/web
|
||||
```
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add [COMPONENT]
|
||||
npx shadcn@canary add [COMPONENT]
|
||||
```
|
||||
|
||||
The CLI will figure out what type of component you are adding and install the
|
||||
correct files to the correct path.
|
||||
|
||||
For example, if you run `npx shadcn@latest add button`, the CLI will install the button component under `packages/ui` and update the import path for components in `apps/web`.
|
||||
For example, if you run `npx shadcn@canary add button`, the CLI will install the button component under `packages/ui` and update the import path for components in `apps/web`.
|
||||
|
||||
If you run `npx shadcn@latest add login-01`, the CLI will install the `button`, `label`, `input` and `card` components under `packages/ui` and the `login-form` component under `apps/web/components`.
|
||||
If you run `npx shadcn@canary add login-01`, the CLI will install the `button`, `label`, `input` and `card` components under `packages/ui` and the `login-form` component under `apps/web/components`.
|
||||
|
||||
### Importing components
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ You can now build your chart using Recharts components.
|
||||
|
||||
<Callout className="mt-4 bg-amber-50 border-amber-200 dark:bg-amber-950/50 dark:border-amber-950">
|
||||
|
||||
**Important:** Remember to set a `min-h-[VALUE]` on the `ChartContainer` component. This is required for the chart to be responsive.
|
||||
**Important:** Remember to set a `min-h-[VALUE]` on the `ChartContainer` component. This is required for the chart be responsive.
|
||||
|
||||
</Callout>
|
||||
|
||||
@@ -370,7 +370,7 @@ The chart config is where you define the labels, icons and colors for a chart.
|
||||
|
||||
It is intentionally decoupled from chart data.
|
||||
|
||||
This allows you to share config and color tokens between charts. It can also work independently for cases where your data or color tokens live remotely or in a different format.
|
||||
This allows you to share config and color tokens between charts. It can also works independently for cases where your data or color tokens live remotely or in a different format.
|
||||
|
||||
```tsx showLineNumbers /ChartConfig/
|
||||
import { Monitor } from "lucide-react"
|
||||
@@ -394,7 +394,7 @@ const chartConfig = {
|
||||
|
||||
## Theming
|
||||
|
||||
Charts have built-in support for theming. You can use css variables (recommended) or color values in any color format, such as hex, hsl or oklch.
|
||||
Charts has built-in support for theming. You can use css variables (recommended) or color values in any color format, such as hex, hsl or oklch.
|
||||
|
||||
### CSS Variables
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Empty
|
||||
description: Use the Empty component to display an empty state.
|
||||
description: Use the Empty component to display a empty state.
|
||||
component: true
|
||||
---
|
||||
|
||||
@@ -70,7 +70,7 @@ import {
|
||||
|
||||
### Outline
|
||||
|
||||
Use the `border` utility class to create an outline empty state.
|
||||
Use the `border` utility class to create a outline empty state.
|
||||
|
||||
<ComponentPreview
|
||||
name="empty-outline"
|
||||
|
||||
@@ -18,7 +18,7 @@ npx create-tsrouter-app@latest my-app --template file-router --tailwind --add-on
|
||||
You can now start adding components to your project.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add button
|
||||
npx shadcn@canary add button
|
||||
```
|
||||
|
||||
The command above will add the `Button` component to your project. You can then import it like this:
|
||||
|
||||
@@ -7,18 +7,109 @@ description: Install and configure shadcn/ui for TanStack Start.
|
||||
|
||||
### Create project
|
||||
|
||||
Run the following command to create a new TanStack Start project with shadcn/ui:
|
||||
Start by creating a new TanStack Start project by following the [Build a Project from Scratch](https://tanstack.com/start/latest/docs/framework/react/build-from-scratch) guide on the TanStack Start website.
|
||||
|
||||
**Do not add Tailwind yet. We'll install Tailwind v4 in the next step.**
|
||||
|
||||
### Add Tailwind
|
||||
|
||||
Install `tailwindcss` and its dependencies.
|
||||
|
||||
```bash
|
||||
npm create @tanstack/start@latest --tailwind --add-ons shadcn
|
||||
npm install tailwindcss @tailwindcss/postcss postcss
|
||||
```
|
||||
|
||||
### Add Components
|
||||
### Create postcss.config.ts
|
||||
|
||||
Create a `postcss.config.ts` file at the root of your project.
|
||||
|
||||
```ts title="postcss.config.ts" showLineNumbers
|
||||
export default {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Create `app/styles/app.css`
|
||||
|
||||
Create an `app.css` file in the `app/styles` directory and import `tailwindcss`
|
||||
|
||||
```css title="app/styles/app.css"
|
||||
@import "tailwindcss" source("../");
|
||||
```
|
||||
|
||||
### Import `app.css`
|
||||
|
||||
```tsx title="app/routes/__root.tsx" showLineNumbers {5,21-26} showLineNumbers
|
||||
import type { ReactNode } from "react"
|
||||
import { createRootRoute, Outlet } from "@tanstack/react-router"
|
||||
import { Meta, Scripts } from "@tanstack/start"
|
||||
|
||||
import appCss from "@/styles/app.css?url"
|
||||
|
||||
export const Route = createRootRoute({
|
||||
head: () => ({
|
||||
meta: [
|
||||
{
|
||||
charSet: "utf-8",
|
||||
},
|
||||
{
|
||||
name: "viewport",
|
||||
content: "width=device-width, initial-scale=1",
|
||||
},
|
||||
{
|
||||
title: "TanStack Start Starter",
|
||||
},
|
||||
],
|
||||
links: [
|
||||
{
|
||||
rel: "stylesheet",
|
||||
href: appCss,
|
||||
},
|
||||
],
|
||||
}),
|
||||
component: RootComponent,
|
||||
})
|
||||
```
|
||||
|
||||
### Edit tsconfig.json file
|
||||
|
||||
Add the following code to the `tsconfig.json` file to resolve paths.
|
||||
|
||||
```ts title="tsconfig.json" showLineNumbers {9-12}
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "Bundler",
|
||||
"module": "ESNext",
|
||||
"target": "ES2022",
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./app/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Run the CLI
|
||||
|
||||
Run the `shadcn` init command to setup your project:
|
||||
|
||||
```bash
|
||||
npx shadcn@canary init
|
||||
```
|
||||
|
||||
This will create a `components.json` file in the root of your project and configure CSS variables inside `app/styles/app.css`.
|
||||
|
||||
### That's it
|
||||
|
||||
You can now start adding components to your project.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add button
|
||||
npx shadcn@canary add button
|
||||
```
|
||||
|
||||
The command above will add the `Button` component to your project. You can then import it like this:
|
||||
@@ -26,7 +117,10 @@ The command above will add the `Button` component to your project. You can then
|
||||
```tsx title="app/routes/index.tsx" showLineNumbers {1,6}
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
function App() {
|
||||
function Home() {
|
||||
const router = useRouter()
|
||||
const state = Route.useLoaderData()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button>Click me</Button>
|
||||
@@ -36,9 +130,3 @@ function App() {
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
If you want to add all `shadcn/ui` components, you can run the following command:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add --all
|
||||
```
|
||||
|
||||
@@ -103,7 +103,7 @@ You can read more about the registry item schema and file types in the [registry
|
||||
### Install the shadcn CLI
|
||||
|
||||
```bash
|
||||
npm install shadcn@latest
|
||||
npm install shadcn@canary
|
||||
```
|
||||
|
||||
### Add a build script
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { debounce, useQueryState } from "nuqs"
|
||||
|
||||
import globalRegistries from "@/registry/directory.json"
|
||||
|
||||
const normalizeQuery = (query: string) =>
|
||||
query.toLowerCase().replaceAll(" ", "").replaceAll("@", "")
|
||||
|
||||
function finderFn<T extends (typeof globalRegistries)[0]>(
|
||||
registry: T,
|
||||
query: string
|
||||
) {
|
||||
const normalizedName = normalizeQuery(registry.name)
|
||||
const normalizedDecription = normalizeQuery(registry.description)
|
||||
const normalizedQuery = normalizeQuery(query)
|
||||
|
||||
return (
|
||||
normalizedName.includes(normalizedQuery) ||
|
||||
normalizedDecription.includes(normalizedQuery)
|
||||
)
|
||||
}
|
||||
|
||||
const searchDirectory = (query: string | null) => {
|
||||
if (!query) return globalRegistries
|
||||
|
||||
return globalRegistries.filter((registry) => finderFn(registry, query))
|
||||
}
|
||||
|
||||
export const useSearchRegistry = () => {
|
||||
const [query, setQuery] = useQueryState("q", {
|
||||
defaultValue: "",
|
||||
limitUrlUpdates: debounce(250),
|
||||
})
|
||||
|
||||
return {
|
||||
query,
|
||||
registries: searchDirectory(query),
|
||||
setQuery,
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { baseColors } from "@/registry/base-colors"
|
||||
|
||||
export const THEMES = baseColors
|
||||
.filter((theme) => !["slate", "stone", "gray", "zinc"].includes(theme.name))
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
export const THEMES = baseColors.filter(
|
||||
(theme) => !["slate", "stone", "gray", "zinc"].includes(theme.name)
|
||||
)
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@faker-js/faker": "^10.1.0",
|
||||
"@faker-js/faker": "^8.2.0",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@radix-ui/react-accessible-icon": "^1.1.1",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-accordion": "^1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.5",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.1",
|
||||
"@radix-ui/react-avatar": "^1.1.2",
|
||||
@@ -38,7 +38,7 @@
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@radix-ui/react-label": "^2.1.1",
|
||||
"@radix-ui/react-menubar": "^1.1.5",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.14",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.4",
|
||||
"@radix-ui/react-popover": "^1.1.5",
|
||||
"@radix-ui/react-portal": "^1.1.3",
|
||||
"@radix-ui/react-progress": "^1.1.1",
|
||||
@@ -51,9 +51,9 @@
|
||||
"@radix-ui/react-switch": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.2",
|
||||
"@radix-ui/react-toast": "^1.2.5",
|
||||
"@radix-ui/react-toggle": "^1.1.10",
|
||||
"@radix-ui/react-toggle": "^1.1.1",
|
||||
"@radix-ui/react-toggle-group": "^1.1.1",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@radix-ui/react-tooltip": "^1.1.7",
|
||||
"@tabler/icons-react": "^3.31.0",
|
||||
"@tailwindcss/postcss": "^4.1.11",
|
||||
"@tanstack/react-form": "^1.20.0",
|
||||
@@ -73,14 +73,13 @@
|
||||
"fumadocs-mdx": "13.0.2",
|
||||
"fumadocs-ui": "16.0.5",
|
||||
"input-otp": "^1.4.2",
|
||||
"jotai": "^2.15.0",
|
||||
"jotai": "^2.1.0",
|
||||
"little-date": "^1.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "0.474.0",
|
||||
"motion": "^12.12.1",
|
||||
"next": "16.0.0",
|
||||
"next-themes": "0.4.6",
|
||||
"nuqs": "^2.7.2",
|
||||
"postcss": "^8.5.1",
|
||||
"react": "19.2.0",
|
||||
"react-day-picker": "^9.7.0",
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
"@8bitcn": "https://8bitcn.com/r/{name}.json",
|
||||
"@97cn": "https://97cn.itzik.co/r/{name}.json",
|
||||
"@aceternity": "https://ui.aceternity.com/registry/{name}.json",
|
||||
"@aevr": "https://ui.aevr.space/r/{name}.json",
|
||||
"@ai-elements": "https://registry.ai-sdk.dev/{name}.json",
|
||||
"@alexcarpenter": "https://ui.alexcarpenter.me/r/{name}.json",
|
||||
"@algolia": "https://sitesearch.algolia.com/r/{name}.json",
|
||||
"@alpine": "https://alpine-registry.vercel.app/r/{name}.json",
|
||||
"@aliimam": "https://aliimam.in/r/{name}.json",
|
||||
"@animate-ui": "https://animate-ui.com/r/{name}.json",
|
||||
"@assistant-ui": "https://r.assistant-ui.com/{name}.json",
|
||||
"@austin-ui": "https://austin-ui.netlify.app/r/{name}.json",
|
||||
@@ -18,9 +16,7 @@
|
||||
"@bucharitesh": "https://bucharitesh.in/r/{name}.json",
|
||||
"@clerk": "https://clerk.com/r/{name}.json",
|
||||
"@coss": "https://coss.com/ui/r/{name}.json",
|
||||
"@commercn": "https://commercn.com/r/{name}.json",
|
||||
"@chisom-ui": "https://chisom-ui.netlify.app/r/{name}.json",
|
||||
"@creative-tim": "https://www.creative-tim.com/ui/r/{name}.json",
|
||||
"@cult-ui": "https://cult-ui.com/r/{name}.json",
|
||||
"@diceui": "https://diceui.com/r/{name}.json",
|
||||
"@efferd": "https://efferd.com/r/{name}.json",
|
||||
@@ -35,21 +31,17 @@
|
||||
"@kibo-ui": "https://www.kibo-ui.com/r/{name}.json",
|
||||
"@kanpeki": "https://kanpeki.vercel.app/r/{name}.json",
|
||||
"@kokonutui": "https://kokonutui.com/r/{name}.json",
|
||||
"@lens-blocks": "https://lensblocks.com/r/{name}.json",
|
||||
"@limeplay": "https://limeplay.winoffrg.dev/r/{name}.json",
|
||||
"@lytenyte": "https://www.1771technologies.com/r/{name}.json",
|
||||
"@magicui": "https://magicui.design/r/{name}.json",
|
||||
"@magicui-pro": "https://pro.magicui.design/registry/{name}",
|
||||
"@motion-primitives": "https://motion-primitives.com/c/{name}.json",
|
||||
"@mui-treasury": "https://mui-treasury.com/r/{name}.json",
|
||||
"@nativeui": "https://nativeui.io/registry/{name}.json",
|
||||
"@ncdai": "https://chanhdai.com/r/{name}.json",
|
||||
"@nuqs": "https://nuqs.dev/r/{name}.json",
|
||||
"@oui": "https://oui.mw10013.workers.dev/r/{name}.json",
|
||||
"@paceui": "https://ui.paceui.com/r/{name}.json",
|
||||
"@plate": "https://platejs.org/r/{name}.json",
|
||||
"@prompt-kit": "https://prompt-kit.com/c/{name}.json",
|
||||
"@prosekit": "https://prosekit.dev/r/{name}.json",
|
||||
"@react-bits": "https://reactbits.dev/r/{name}.json",
|
||||
"@react-market": "https://www.react-market.com/get/{name}.json",
|
||||
"@retroui": "https://retroui.dev/r/{name}.json",
|
||||
@@ -58,7 +50,6 @@
|
||||
"@roiui": "https://roiui.com/r/{name}.json",
|
||||
"@solaceui": "https://www.solaceui.com/r/{name}.json",
|
||||
"@scrollxui": "https://www.scrollxui.dev/registry/{name}.json",
|
||||
"@systaliko-ui": "https://systaliko-ui.vercel.app/r/{name}.json",
|
||||
"@shadcn-editor": "https://shadcn-editor.vercel.app/r/{name}.json",
|
||||
"@shadcn-map": "http://shadcn-map.vercel.app/r/{name}.json",
|
||||
"@shadcn-studio": "https://shadcnstudio.com/r/{name}.json",
|
||||
@@ -75,14 +66,10 @@
|
||||
"@wds": "https://wds-shadcn-registry.netlify.app/r/{name}.json",
|
||||
"@wandry-ui": "https://ui.wandry.com.ua/r/{name}.json",
|
||||
"@wigggle-ui": "https://wigggle-ui.vercel.app/r/{name}.json",
|
||||
"@paykit-sdk": "https://www.usepaykit.dev/r/{name}.json",
|
||||
"@pixelact-ui": "https://www.pixelactui.com/r/{name}.json",
|
||||
"@zippystarter": "https://zippystarter.com/r/{name}.json",
|
||||
"@shadcndesign": "https://shadcndesign-free.vercel.app/r/{name}.json",
|
||||
"@ha-components": "https://hacomponents.keshuac.com/r/{name}.json",
|
||||
"@shadix-ui": "https://shadix-ui.vercel.app/r/{name}.json",
|
||||
"@utilcn": "https://utilcn.dev/r/{name}.json",
|
||||
"@hextaui": "https://hextaui.com/r/{name}.json",
|
||||
"@taki": "https://taki-ui.com/r/{name}.json",
|
||||
"@square-ui": "https://square.lndev.me/registry/{name}.json"
|
||||
"@utilcn": "https://utilcn.dev/r/{name}.json"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -150,7 +150,7 @@
|
||||
@apply bg-selection text-selection-foreground;
|
||||
}
|
||||
html {
|
||||
@apply overscroll-y-none scroll-smooth;
|
||||
@apply overscroll-none scroll-smooth;
|
||||
}
|
||||
body {
|
||||
font-synthesis-weight: none;
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.1",
|
||||
"@changesets/changelog-github": "^0.5.1",
|
||||
"@changesets/changelog-github": "^0.4.8",
|
||||
"@changesets/cli": "^2.26.1",
|
||||
"@commitlint/cli": "^20.1.0",
|
||||
"@commitlint/cli": "^17.6.3",
|
||||
"@commitlint/config-conventional": "^17.6.3",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^3.7.2",
|
||||
"@manypkg/cli": "^0.20.0",
|
||||
|
||||
@@ -7,12 +7,8 @@ export const transformImport: Transformer = async ({
|
||||
config,
|
||||
isRemote,
|
||||
}) => {
|
||||
const utilsAlias = config.aliases?.utils
|
||||
const workspaceAlias =
|
||||
typeof utilsAlias === "string" && utilsAlias.includes("/")
|
||||
? utilsAlias.split("/")[0]
|
||||
: "@"
|
||||
const utilsImport = `${workspaceAlias}/lib/utils`
|
||||
const workspaceAlias = config.aliases?.utils?.split("/")[0]?.slice(1)
|
||||
const utilsImport = `@${workspaceAlias}/lib/utils`
|
||||
|
||||
if (![".tsx", ".ts", ".jsx", ".js"].includes(sourceFile.getExtension())) {
|
||||
return sourceFile
|
||||
@@ -35,9 +31,7 @@ export const transformImport: Transformer = async ({
|
||||
?.getNamedImports()
|
||||
.some((namedImport) => namedImport.getName() === "cn")
|
||||
|
||||
if (!isCnImport || !config.aliases.utils) {
|
||||
continue
|
||||
}
|
||||
if (!isCnImport) continue
|
||||
|
||||
specifier.setLiteralValue(
|
||||
utilsImport === updated
|
||||
|
||||
@@ -70,7 +70,7 @@ import { Foo } from "bar"
|
||||
import { Label} from "ui/label"
|
||||
import { Box } from "~/src/components/box"
|
||||
|
||||
import { cn, foo, bar } from "~/lib"
|
||||
import { cn, foo, bar } from "~/lib/utils"
|
||||
import { bar } from "~/lib/utils/bar"
|
||||
"
|
||||
`;
|
||||
@@ -82,7 +82,7 @@ import { Foo } from "bar"
|
||||
import { Label} from "ui/label"
|
||||
import { Box } from "~/src/components/box"
|
||||
|
||||
import { cn } from "~/src/utils"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { bar } from "~/lib/utils/bar"
|
||||
"
|
||||
`;
|
||||
@@ -94,7 +94,7 @@ import { Foo } from "bar"
|
||||
import { Label} from "ui/label"
|
||||
import { Box } from "~/src/components/box"
|
||||
|
||||
import { cn } from "~/src/utils"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { bar } from "~/lib/utils/bar"
|
||||
"
|
||||
`;
|
||||
@@ -106,7 +106,7 @@ import { Foo } from "bar"
|
||||
import { Label} from "ui/label"
|
||||
import { Box } from "~/src/components/box"
|
||||
|
||||
import { cn } from "~/src/utils"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { bar } from "~/lib/utils/bar"
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -2,38 +2,6 @@ import { expect, test } from "vitest"
|
||||
|
||||
import { transform } from "../../src/utils/transformers"
|
||||
|
||||
|
||||
test('transform nested workspace folder for utils, website/src/utils', async () => {
|
||||
expect(
|
||||
await transform({
|
||||
filename: "test.ts",
|
||||
|
||||
raw: `import { Button } from "website/src/components/ui/button"
|
||||
import { Box } from "website/src/components/box"
|
||||
import { cn } from "website/src/utils"
|
||||
`,
|
||||
config: {
|
||||
tsx: true,
|
||||
tailwind: {
|
||||
baseColor: "neutral",
|
||||
cssVariables: true,
|
||||
},
|
||||
aliases: {
|
||||
components: "website/src/components",
|
||||
lib: "website/src/lib",
|
||||
utils: "website/src/utils",
|
||||
},
|
||||
},
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
"import { Button } from "website/src/components/ui/button"
|
||||
import { Box } from "website/src/components/box"
|
||||
import { cn } from "website/src/utils"
|
||||
"
|
||||
`)
|
||||
|
||||
})
|
||||
|
||||
test("transform import", async () => {
|
||||
expect(
|
||||
await transform({
|
||||
|
||||
1236
pnpm-lock.yaml
generated
1236
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user