UNPKG

theme-switcher-nextjs

Version:

A beautifully designed theme switcher component for Next.js apps based on the Vercel's Geist design system.

264 lines (260 loc) 7.9 kB
"use client" // src/components/theme-switcher.tsx import React2, { useEffect, useState } from "react"; import { useTheme } from "next-themes"; // src/icons/index.tsx import React from "react"; var SunIcon = ({ size = 16, className }) => /* @__PURE__ */ React.createElement( "svg", { width: size, height: size, viewBox: "0 0 256 256", fill: "currentColor", className }, /* @__PURE__ */ React.createElement("rect", { width: "256", height: "256", fill: "none" }), /* @__PURE__ */ React.createElement( "line", { x1: "128", y1: "40", x2: "128", y2: "16", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "circle", { cx: "128", cy: "128", r: "56", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "line", { x1: "64", y1: "64", x2: "48", y2: "48", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "line", { x1: "64", y1: "192", x2: "48", y2: "208", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "line", { x1: "192", y1: "64", x2: "208", y2: "48", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "line", { x1: "192", y1: "192", x2: "208", y2: "208", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "line", { x1: "40", y1: "128", x2: "16", y2: "128", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "line", { x1: "128", y1: "216", x2: "128", y2: "240", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ), /* @__PURE__ */ React.createElement( "line", { x1: "216", y1: "128", x2: "240", y2: "128", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ) ); var MoonIcon = ({ size = 16, className }) => /* @__PURE__ */ React.createElement( "svg", { width: size, height: size, viewBox: "0 0 256 256", fill: "currentColor", className }, /* @__PURE__ */ React.createElement("rect", { width: "256", height: "256", fill: "none" }), /* @__PURE__ */ React.createElement( "path", { d: "M108.11,28.11A96.09,96.09,0,0,0,227.89,147.89,96,96,0,1,1,108.11,28.11Z", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "16" } ) ); var GearSixIcon = ({ size = 16, className }) => /* @__PURE__ */ React.createElement( "svg", { width: size, height: size, viewBox: "0 0 256 256", fill: "currentColor", className }, /* @__PURE__ */ React.createElement( "path", { d: "M128,80a48,48,0,1,0,48,48A48.05,48.05,0,0,0,128,80Zm0,80a32,32,0,1,1,32-32A32,32,0,0,1,128,160Zm109.94-52.79a8,8,0,0,0-3.89-5.4l-29.83-17-.12-33.62a8,8,0,0,0-2.83-6.08,111.91,111.91,0,0,0-36.72-20.67,8,8,0,0,0-6.46.59L128,41.85,97.88,25a8,8,0,0,0-6.47-.6A112.1,112.1,0,0,0,54.73,45.15a8,8,0,0,0-2.83,6.07l-.15,33.65-29.83,17a8,8,0,0,0-3.89,5.4,106.47,106.47,0,0,0,0,41.56,8,8,0,0,0,3.89,5.4l29.83,17,.12,33.62a8,8,0,0,0,2.83,6.08,111.91,111.91,0,0,0,36.72,20.67,8,8,0,0,0,6.46-.59L128,214.15,158.12,231a7.91,7.91,0,0,0,3.9,1,8.09,8.09,0,0,0,2.57-.42,112.1,112.1,0,0,0,36.68-20.73,8,8,0,0,0,2.83-6.07l.15-33.65,29.83-17a8,8,0,0,0,3.89-5.4A106.47,106.47,0,0,0,237.94,107.21Zm-15,34.91-28.57,16.25a8,8,0,0,0-3,3c-.58,1-1.19,2.06-1.81,3.06a7.94,7.94,0,0,0-1.22,4.21l-.15,32.25a95.89,95.89,0,0,1-25.37,14.3L134,199.13a8,8,0,0,0-3.91-1h-.19c-1.21,0-2.43,0-3.64,0a8.08,8.08,0,0,0-4.1,1l-28.84,16.1A96,96,0,0,1,67.88,201l-.11-32.2a8,8,0,0,0-1.22-4.22c-.62-1-1.23-2-1.8-3.06a8.09,8.09,0,0,0-3-3.06l-28.6-16.29a90.49,90.49,0,0,1,0-28.26L61.67,97.63a8,8,0,0,0,3-3c.58-1,1.19-2.06,1.81-3.06a7.94,7.94,0,0,0,1.22-4.21l.15-32.25a95.89,95.89,0,0,1,25.37-14.3L122,56.87a8,8,0,0,0,4.1,1c1.21,0,2.43,0,3.64,0a8.08,8.08,0,0,0,4.1-1l28.84-16.1A96,96,0,0,1,188.12,55l.11,32.2a8,8,0,0,0,1.22,4.22c.62,1,1.23,2,1.8,3.06a8.09,8.09,0,0,0,3,3.06l28.6,16.29A90.49,90.49,0,0,1,222.9,142.12Z" } ) ); // src/lib/utils.ts import { clsx } from "clsx"; import { twMerge } from "tailwind-merge"; function cn(...inputs) { return twMerge(clsx(inputs)); } // src/components/theme-switcher.tsx var ThemeSwitcher = ({ className, defaultTheme = "system", themes = ["light", "dark", "system"], size = "sm", includeSystem = true, ...props }) => { const { theme, setTheme } = useTheme(); const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); const filteredThemes = includeSystem ? themes : themes.filter((t) => t !== "system"); useEffect(() => { if (!includeSystem && theme === "system") { setTheme("light"); } }, [includeSystem, theme, setTheme]); if (!mounted) { return null; } const getIcon = (t) => { const iconSize = size === "sm" ? 16 : size === "md" ? 24 : 32; switch (t) { case "light": return /* @__PURE__ */ React2.createElement(SunIcon, { size: iconSize, className: "rounded-full" }); case "dark": return /* @__PURE__ */ React2.createElement(MoonIcon, { size: iconSize, className: "rounded-full" }); case "system": return /* @__PURE__ */ React2.createElement(GearSixIcon, { size: iconSize, className: "rounded-full" }); } }; return /* @__PURE__ */ React2.createElement( "div", { className: cn( "flex gap-1 rounded-full h-fit w-fit border border-zinc-200 bg-zinc-100 dark:bg-[#1F1F22] dark:border-zinc-600", className ), ...props }, filteredThemes.map((t) => /* @__PURE__ */ React2.createElement( "button", { key: t, type: "button", onClick: () => setTheme(t), className: cn( `${size === "sm" ? "h-6 w-6" : size === "md" ? "h-10 w-10" : "h-12 w-12"}`, "inline-flex items-center justify-center whitespace-nowrap text-sm font-medium relative rounded-full bg-zinc-100 dark:bg-[#1F1F22]", theme === t ? `bg-white hover:bg-white text-zinc-700 dark:text-zinc-50 dark:bg-neutral-900 dark:hover:bg-neutral-900 dark:hover:text-zinc-50 shadow-[0_0_0_1px_rgba(228,228,231,1)] dark:shadow-[0_0_0_1px_rgba(82,82,91,1)]` : "text-zinc-400 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-50" ) }, /* @__PURE__ */ React2.createElement( "div", { className: "transition-transform duration-300 ease-in-out", style: { transform: theme === t ? "scale(1.15)" : "scale(1)" } }, getIcon(t) ), /* @__PURE__ */ React2.createElement("span", { className: "sr-only" }, t.charAt(0).toUpperCase() + t.slice(1), " theme") )) ); }; export { ThemeSwitcher, cn }; //# sourceMappingURL=index.js.map