Kaiky Santos
Kaiky Santos

Reputation: 31

How to create a theme customizer like the theme pages in shadcn/ui?

I want to create a theme customizer like the theme page on shadcn/ui, for a personal project.

But I'm having trouble. I did a git clone of the shadcn project to try to understand how it works, but I didn't have any success!

I tried three things:

  1. I created a useConfig hook.
import { useAtom } from "jotai"
import { atomWithStorage } from "jotai/utils"

type Config = {
  theme: string
}

const configAtom = atomWithStorage<Config>("config", {
  theme: "zinc",
})

export function useConfig() {
  return useAtom(configAtom)
}
  1. I created a themeWrapper that wraps the entire application.
"use client"

import { cn } from "@/lib/utils"
import { useConfig } from "@/hooks/use-config"

export function ThemeWrapper({
  children,
  className,
}: React.ComponentProps<"div">) {
  const [config] = useConfig()

  return (
    <div
      className={cn(
        `theme-${config.theme}`,
        className
      )}
    >
      {children}
    </div>
  )
}
  1. I created a toggle theme.
"use client"

import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { Button } from "./ui/button";
import { Palette } from "lucide-react";
import { useConfig } from "@/hooks/use-config";

type Colors = "violet" | "rose" | "green" | "blue" | "yellow" | "orange"

const colors: Colors[] = ["violet", "rose", "green", "blue", "yellow", "orange"]

export function ToggleStyle() {
  const [config, setConfig] = useConfig()

  const bgColors = {
    violet: "bg-violet-600",
    rose: "bg-rose-600",
    green: "bg-green-600",
    blue: "bg-blue-600",
    yellow: "bg-yellow-600",
    orange: "bg-orange-600"
  }

  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button className="group" variant="ghost" size="icon">
          <Palette className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all group-hover:rotate-45" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-max p-3">
        <p className="text-popover-foreground text-xs font-medium mb-2">
          Color
        </p>
        <ToggleGroup
          className="grid grid-cols-2"
          type="single"
          variant="outline"
          value={config.theme}
          onValueChange={(value) => {
            if (value) setConfig({ theme: value })
          }}
        >
          {colors.map(color => (
            <ToggleGroupItem size="sm" value={color} className="capitalize flex justify-start items-center gap-2 text-xs">
              <div className={`w-5 h-5 rounded-full ${bgColors[color]}`} />
              {color}
            </ToggleGroupItem>
          ))}
        </ToggleGroup>
      </PopoverContent>
    </Popover>
  )
}

I did everything exactly as it was in the shadcn code! Am I forgetting something?

Upvotes: 3

Views: 939

Answers (0)

Related Questions