Updates
This commit is contained in:
@@ -1,6 +1,18 @@
|
||||
import React, { type DetailedHTMLProps, type HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { Moon, Sun } from "lucide-react";
|
||||
import type { TWUIButtonSizeType } from "../layout/Button";
|
||||
|
||||
const SizeMap: Record<
|
||||
TWUIButtonSizeType,
|
||||
{ icon: number; className: string }
|
||||
> = {
|
||||
smaller: { icon: 16, className: "w-4 h-4" },
|
||||
small: { icon: 20, className: "w-5 h-5" },
|
||||
normal: { icon: 24, className: "w-6 h-6" },
|
||||
large: { icon: 28, className: "w-7 h-7" },
|
||||
larger: { icon: 32, className: "w-8 h-8" },
|
||||
};
|
||||
|
||||
type Props = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
@@ -13,6 +25,11 @@ type Props = DetailedHTMLProps<
|
||||
HTMLDivElement
|
||||
>;
|
||||
defaultScheme?: "light" | "dark";
|
||||
/**
|
||||
* Icon size. Matches the twui `Button` size scale.
|
||||
* @default "normal"
|
||||
*/
|
||||
size?: TWUIButtonSizeType;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -24,8 +41,10 @@ export default function ColorSchemeSelector({
|
||||
setActive: externalSetActive,
|
||||
iconWrapperProps,
|
||||
defaultScheme,
|
||||
size = "normal",
|
||||
...props
|
||||
}: Props) {
|
||||
const { icon: iconSize, className: sizeClassName } = SizeMap[size];
|
||||
const [active, setActive] = React.useState(initialActive);
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -49,7 +68,7 @@ export default function ColorSchemeSelector({
|
||||
} else if (existingTheme === "light") {
|
||||
setActive(false);
|
||||
} else if (defaultScheme) {
|
||||
setActive(defaultScheme == "dark" ? false : true);
|
||||
setActive(defaultScheme == "dark");
|
||||
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||
setActive(true);
|
||||
} else if (typeof active == "undefined") {
|
||||
@@ -60,15 +79,21 @@ export default function ColorSchemeSelector({
|
||||
React.useEffect(() => {
|
||||
if (typeof active == "undefined") return;
|
||||
|
||||
if (active) {
|
||||
document.documentElement.className = "dark";
|
||||
localStorage.setItem("theme", "dark");
|
||||
} else {
|
||||
document.documentElement.className = "light";
|
||||
localStorage.setItem("theme", "light");
|
||||
}
|
||||
document.documentElement.classList.remove("dark", "light");
|
||||
document.documentElement.classList.add(active ? "dark" : "light");
|
||||
}, [active]);
|
||||
|
||||
/**
|
||||
* Only an explicit toggle is persisted, so visitors who never choose
|
||||
* keep following their OS preference.
|
||||
*/
|
||||
function toggleScheme() {
|
||||
const next = !active;
|
||||
setActive(next);
|
||||
externalSetActive?.(next);
|
||||
localStorage.setItem("theme", next ? "dark" : "light");
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
@@ -80,7 +105,7 @@ export default function ColorSchemeSelector({
|
||||
>
|
||||
<button
|
||||
title="Color Scheme Selector Button"
|
||||
onClick={() => setActive(!active)}
|
||||
onClick={toggleScheme}
|
||||
className={twMerge(
|
||||
"cursor-pointer hover:opacity-70 flex items-center justify-center",
|
||||
)}
|
||||
@@ -88,12 +113,13 @@ export default function ColorSchemeSelector({
|
||||
<div
|
||||
{...iconWrapperProps}
|
||||
className={twMerge(
|
||||
"w-6 h-6 flex items-center justify-center",
|
||||
"flex items-center justify-center",
|
||||
sizeClassName,
|
||||
iconWrapperProps?.className,
|
||||
)}
|
||||
>
|
||||
{active == false && <Sun />}
|
||||
{active == true && <Moon />}
|
||||
{active == false && <Sun size={iconSize} />}
|
||||
{active == true && <Moon size={iconSize} />}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user