Skip to content

Commit 0b59b4c

Browse files
committed
add :colors for user can pic colors
1 parent 5e7881d commit 0b59b4c

24 files changed

+3771
-179
lines changed

app/colors/layout.tsx

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Metadata } from "next"
2+
import Link from "next/link"
3+
4+
import { Announcement } from "@/components/announcement"
5+
import {
6+
PageActions,
7+
PageHeader,
8+
PageHeaderDescription,
9+
PageHeaderHeading,
10+
} from "@/components/page-header"
11+
import {Button} from "@/components/ui/button"
12+
13+
export const metadata: Metadata = {
14+
title: "Tailwind Colors",
15+
description: "All colors in all formats.",
16+
}
17+
18+
export default function ChartsLayout({
19+
children,
20+
}: {
21+
children: React.ReactNode
22+
}) {
23+
return (
24+
<div className="container relative">
25+
<PageHeader>
26+
27+
<PageHeaderHeading>Tailwind Colors</PageHeaderHeading>
28+
<PageHeaderDescription>
29+
Tailwind CSS colors in HSL, RGB, and HEX formats.
30+
</PageHeaderDescription>
31+
<PageActions>
32+
<Button asChild size="sm">
33+
<a href="#colors">Browse Colors</a>
34+
</Button>
35+
<Button asChild variant="ghost" size="sm">
36+
<Link href="/components">Components</Link>
37+
</Button>
38+
</PageActions>
39+
</PageHeader>
40+
<section id="charts" className="scroll-mt-20">
41+
{children}
42+
</section>
43+
</div>
44+
)
45+
}

app/colors/page.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { getColors } from "@/lib/colors"
2+
import { ColorPalette } from "@/components/color-palette"
3+
4+
const colors = getColors()
5+
6+
export default function ColorsPage() {
7+
return (
8+
<div id="colors" className="grid scroll-mt-20 gap-8">
9+
{colors.map((colorPalette) => (
10+
<ColorPalette key={colorPalette.name} colorPalette={colorPalette} />
11+
))}
12+
</div>
13+
)
14+
}

components/announcement.tsx

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Link from "next/link"
2+
import { ArrowRightIcon } from "lucide-react"
3+
import { Blocks, PieChart } from "lucide-react"
4+
5+
import { Separator } from "@/components/ui/separator"
6+
7+
export function Announcement() {
8+
return (
9+
<Link
10+
href="/docs/components/sidebar"
11+
className="group inline-flex items-center px-0.5 text-sm font-medium"
12+
>
13+
<PieChart className="h-4 w-4" />{" "}
14+
<Separator className="mx-2 h-4" orientation="vertical" />{" "}
15+
<span className="underline-offset-4 group-hover:underline">
16+
New sidebar component
17+
</span>
18+
<ArrowRightIcon className="ml-1 h-4 w-4" />
19+
</Link>
20+
)
21+
}

components/app-sidebar.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ const data = {
2626
url: "/components", // Main components page
2727
items: [
2828
{
29-
title: "Input Fields",
29+
title: "Input Designs",
3030
url: "/components/input-fields", // Correct relative path
3131
},
3232
{
33-
title: "Buttons",
33+
title: "Buttons Designs",
3434
url: "/components/buttons", // Correct relative path
3535
},
3636
{
@@ -70,15 +70,15 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
7070
{/* We create a SidebarGroup for each parent. */}
7171
{data.navMain.map((item) => (
7272
<SidebarGroup key={item.title}>
73-
<SidebarGroupLabel>{item.title}</SidebarGroupLabel>
73+
<SidebarGroupLabel className="text-teal-300">{item.title}</SidebarGroupLabel>
7474
<SidebarGroupContent>
7575
<SidebarMenu>
7676
{item.items.map((subItem) => (
7777
<SidebarMenuItem key={subItem.title}>
7878
<SidebarMenuButton
7979
asChild
8080
className={
81-
activeItem === subItem.title ? "active-class" : ""
81+
activeItem === subItem.title ? "active-class " : ""
8282
}
8383
onClick={() => handleItemClick(subItem.title)} // Handle click
8484
>

components/color-format-selector.tsx

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
5+
import { getColorFormat, type Color } from "@/lib/colors"
6+
import { cn } from "@/lib/utils"
7+
import { useColors } from "@/hooks/use-colors"
8+
import {
9+
Select,
10+
SelectContent,
11+
SelectItem,
12+
SelectTrigger,
13+
SelectValue,
14+
} from "@/components/ui/select"
15+
import { Skeleton } from "@/components/ui/skeleton"
16+
17+
export function ColorFormatSelector({
18+
color,
19+
className,
20+
...props
21+
}: Omit<React.ComponentProps<typeof SelectTrigger>, "color"> & {
22+
color: Color
23+
}) {
24+
const { format, setFormat, isLoading } = useColors()
25+
const formats = React.useMemo(() => getColorFormat(color), [color])
26+
27+
if (isLoading) {
28+
return <ColorFormatSelectorSkeleton />
29+
}
30+
31+
return (
32+
<Select value={format} onValueChange={setFormat}>
33+
<SelectTrigger
34+
className={cn("h-7 w-auto gap-1.5 rounded-lg pr-2 text-xs", className)}
35+
{...props}
36+
>
37+
<span className="font-medium">Format: </span>
38+
<span className="font-mono text-xs text-muted-foreground">
39+
{format}
40+
</span>
41+
</SelectTrigger>
42+
<SelectContent align="end" className="rounded-xl">
43+
{Object.entries(formats).map(([format, value]) => (
44+
<SelectItem
45+
key={format}
46+
value={format}
47+
className="gap-2 rounded-lg [&>span]:flex [&>span]:items-center [&>span]:gap-2"
48+
>
49+
<span className="font-medium">{format}</span>
50+
<span className="font-mono text-xs text-muted-foreground">
51+
{value}
52+
</span>
53+
</SelectItem>
54+
))}
55+
</SelectContent>
56+
</Select>
57+
)
58+
}
59+
60+
export function ColorFormatSelectorSkeleton({
61+
className,
62+
...props
63+
}: React.ComponentProps<typeof Skeleton>) {
64+
return (
65+
<Skeleton
66+
className={cn("h-7 w-[116px] gap-1.5 rounded-lg", className)}
67+
{...props}
68+
/>
69+
)
70+
}

components/color-palette.tsx

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as React from "react"
2+
3+
import { type ColorPalette } from "@/lib/colors"
4+
import { Color } from "@/components/color"
5+
import {
6+
ColorFormatSelector,
7+
ColorFormatSelectorSkeleton,
8+
} from "@/components/color-format-selector"
9+
10+
export function ColorPalette({ colorPalette }: { colorPalette: ColorPalette }) {
11+
return (
12+
<div
13+
id={colorPalette.name}
14+
className="rounded-lg shadow-sm ring-1 ring-border"
15+
>
16+
<div className="flex items-center p-2 pb-0">
17+
<div className="flex-1 pl-1 text-sm font-medium">
18+
<h2 className="capitalize">{colorPalette.name}</h2>
19+
</div>
20+
<React.Suspense fallback={<ColorFormatSelectorSkeleton />}>
21+
<ColorFormatSelector
22+
color={colorPalette.colors[0]}
23+
className="ml-auto"
24+
/>
25+
</React.Suspense>
26+
</div>
27+
<div className="flex flex-col gap-1 p-2 sm:flex-row sm:gap-2">
28+
{colorPalette.colors.map((color) => (
29+
<Color key={color.hex} color={color} />
30+
))}
31+
</div>
32+
</div>
33+
)
34+
}

components/color.tsx

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"use client"
2+
3+
import { Check, Clipboard } from "lucide-react"
4+
import { toast } from "sonner"
5+
6+
7+
import { type Color } from "@/lib/colors"
8+
import { trackEvent } from "@/lib/events"
9+
import { useColors } from "@/hooks/use-colors"
10+
import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"
11+
import { copyToClipboardWithMeta } from "@/components/copy-button"
12+
13+
export function Color({ color }: { color: Color }) {
14+
const { format } = useColors()
15+
const { isCopied, copyToClipboard } = useCopyToClipboard()
16+
17+
return (
18+
<button
19+
key={color.hex}
20+
className="group relative flex aspect-[3/1] w-full flex-1 flex-col gap-2 text-[--text] sm:aspect-[2/3] sm:h-auto sm:w-auto [&>svg]:absolute [&>svg]:right-4 [&>svg]:top-4 [&>svg]:h-3.5 [&>svg]:w-3.5 [&>svg]:opacity-0 [&>svg]:transition-opacity"
21+
style={
22+
{
23+
"--bg": `hsl(${color.hsl})`,
24+
"--text": color.foreground,
25+
} as React.CSSProperties
26+
}
27+
onClick={() => {
28+
copyToClipboard(color[format])
29+
trackEvent({
30+
name: "copy_color",
31+
properties: {
32+
color: color.id,
33+
value: color[format],
34+
format,
35+
},
36+
})
37+
toast.success(`Copied ${color[format]} to clipboard.`)
38+
}}
39+
>
40+
{isCopied ? (
41+
<Check className="group-hover:opacity-100" />
42+
) : (
43+
<Clipboard className="group-hover:opacity-100" />
44+
)}
45+
<div className="w-full flex-1 rounded-md bg-[--bg] md:rounded-lg" />
46+
<div className="flex w-full flex-col items-center justify-center gap-1">
47+
<span className="hidden font-mono text-xs tabular-nums text-muted-foreground transition-colors group-hover:text-foreground lg:flex">
48+
{color.className}
49+
</span>
50+
<span className="font-mono text-xs tabular-nums text-muted-foreground transition-colors group-hover:text-foreground lg:hidden">
51+
{color.scale}
52+
</span>
53+
</div>
54+
</button>
55+
)
56+
}

0 commit comments

Comments
 (0)