|
2 | 2 | "$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
3 | 3 | "name": "theme-provider",
|
4 | 4 | "type": "registry:component",
|
5 |
| - "title": "Theme Provider & Toggle", |
| 5 | + "title": "Theme Provider & Toggle & Select", |
6 | 6 | "author": "Refine <info@refine.dev>",
|
7 | 7 | "description": "A complete theme system with provider and toggle components. Supports dark, light, and system themes with localStorage persistence.",
|
8 | 8 | "dependencies": ["lucide-react"],
|
|
19 | 19 | "content": "\"use client\";\n\nimport { useTheme } from \"@/registry/default/refine-ui/layout/theme-provider\";\nimport { Button } from \"@/registry/default/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { Moon, Sun, Monitor } from \"lucide-react\";\n\ntype ThemeToggleProps = {\n className?: string;\n};\n\nexport function ThemeToggle({ className }: ThemeToggleProps) {\n const { theme, setTheme } = useTheme();\n\n const cycleTheme = () => {\n switch (theme) {\n case \"light\":\n setTheme(\"dark\");\n break;\n case \"dark\":\n setTheme(\"system\");\n break;\n case \"system\":\n setTheme(\"light\");\n break;\n default:\n setTheme(\"light\");\n }\n };\n\n return (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={cycleTheme}\n className={cn(\n \"rounded-full\",\n \"border-sidebar-border\",\n \"bg-transparent\",\n className,\n )}\n >\n <Sun\n className={cn(\n \"h-[1.2rem]\",\n \"w-[1.2rem]\",\n \"rotate-0\",\n \"scale-100\",\n \"transition-all\",\n \"duration-200\",\n {\n \"-rotate-90 scale-0\": theme === \"dark\" || theme === \"system\",\n },\n )}\n />\n <Moon\n className={cn(\n \"absolute\",\n \"h-[1.2rem]\",\n \"w-[1.2rem]\",\n \"rotate-90\",\n \"scale-0\",\n \"transition-all\",\n \"duration-200\",\n {\n \"rotate-0 scale-100\": theme === \"dark\",\n \"rotate-90 scale-0\": theme === \"light\" || theme === \"system\",\n },\n )}\n />\n <Monitor\n className={cn(\n \"absolute\",\n \"h-[1.2rem]\",\n \"w-[1.2rem]\",\n \"rotate-0\",\n \"scale-0\",\n \"transition-all\",\n \"duration-200\",\n {\n \"scale-100\": theme === \"system\",\n \"scale-0\": theme === \"light\" || theme === \"dark\",\n },\n )}\n />\n <span className=\"sr-only\">Toggle theme (Light → Dark → System)</span>\n </Button>\n );\n}\n\nThemeToggle.displayName = \"ThemeToggle\";\n",
|
20 | 20 | "type": "registry:component",
|
21 | 21 | "target": "src/components/refine-ui/layout/theme-toggle.tsx"
|
| 22 | + }, |
| 23 | + { |
| 24 | + "path": "registry/default/refine-ui/layout/theme-select.tsx", |
| 25 | + "content": "\"use client\";\n\nimport React from \"react\";\nimport { useTheme } from \"./theme-provider\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\";\nimport { Button } from \"@/registry/default/ui/button\";\nimport { Moon, Sun, Monitor, ChevronDown, Check } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\ntype ThemeOption = {\n value: \"light\" | \"dark\" | \"system\";\n label: string;\n icon: React.ReactNode;\n};\n\nconst themeOptions: ThemeOption[] = [\n {\n value: \"light\",\n label: \"Light\",\n icon: <Sun className=\"h-4 w-4\" />,\n },\n {\n value: \"dark\",\n label: \"Dark\",\n icon: <Moon className=\"h-4 w-4\" />,\n },\n {\n value: \"system\",\n label: \"System\",\n icon: <Monitor className=\"h-4 w-4\" />,\n },\n];\n\nexport function ThemeSelect() {\n const { theme, setTheme } = useTheme();\n\n const currentTheme = themeOptions.find((option) => option.value === theme);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"lg\"\n className={cn(\n \"w-full\",\n \"justify-between\",\n \"px-3\",\n \"text-left\",\n \"text-sm\",\n \"font-normal\",\n \"text-foreground\",\n \"hover:bg-accent\",\n \"hover:text-accent-foreground\",\n \"focus-visible:outline-none\",\n \"focus-visible:ring-2\",\n \"focus-visible:ring-ring\",\n )}\n >\n <div className=\"flex items-center gap-2\">\n {currentTheme?.icon}\n <span>{currentTheme?.label}</span>\n </div>\n <ChevronDown className=\"h-4 w-4 opacity-50\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"min-w-40 space-y-1\">\n {themeOptions.map((option) => {\n const isSelected = theme === option.value;\n\n return (\n <DropdownMenuItem\n key={option.value}\n onClick={() => setTheme(option.value)}\n className={cn(\n \"flex items-center gap-2 cursor-pointer relative pr-8\",\n {\n \"bg-accent text-accent-foreground\": isSelected,\n },\n )}\n >\n {option.icon}\n <span>{option.label}</span>\n {isSelected && (\n <Check className=\"h-4 w-4 absolute right-2 text-primary\" />\n )}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nThemeSelect.displayName = \"ThemeSelect\";\n", |
| 26 | + "type": "registry:component", |
| 27 | + "target": "src/components/refine-ui/layout/theme-select.tsx" |
22 | 28 | }
|
23 | 29 | ],
|
24 | 30 | "docs": "https://github.com/refinedev/refine",
|
25 |
| - "categories": ["theme", "dark-mode", "toggle", "provider"] |
| 31 | + "categories": ["theme", "dark-mode", "toggle", "select", "provider"] |
26 | 32 | }
|
0 commit comments