themes lol
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
Box,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
UnstyledButton,
|
||||
useComputedColorScheme,
|
||||
} from "@mantine/core";
|
||||
import { CaretRightIcon } from "@phosphor-icons/react";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import Sheet from "@/components/sheet/sheet";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import { updateUserTheme } from "@/features/settings/server";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { DEFAULT_THEME_ID, THEME_LIST, getTheme } from "@/themes/registry";
|
||||
import ThemePreview from "./theme-preview";
|
||||
|
||||
const ThemePicker = () => {
|
||||
const { metadata, user, set } = useAuth();
|
||||
const { t } = useLingui();
|
||||
const sheet = useSheet();
|
||||
const scheme = useComputedColorScheme("dark");
|
||||
const currentId = metadata.theme || DEFAULT_THEME_ID;
|
||||
const current = getTheme(currentId);
|
||||
|
||||
const handleSelect = async (id: string) => {
|
||||
if (!user || id === currentId) return;
|
||||
const previous = metadata;
|
||||
set({ metadata: { ...metadata, theme: id } });
|
||||
try {
|
||||
await updateUserTheme({ data: id });
|
||||
} catch {
|
||||
set({ metadata: previous });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Text fw={500} size="sm" mb="xs">
|
||||
<Trans>Theme</Trans>
|
||||
</Text>
|
||||
<UnstyledButton
|
||||
onClick={sheet.open}
|
||||
w="100%"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "var(--mantine-spacing-sm)",
|
||||
padding: "var(--mantine-spacing-xs)",
|
||||
border: "1px solid var(--mantine-color-default-border)",
|
||||
borderRadius: "var(--mantine-radius-md)",
|
||||
}}
|
||||
>
|
||||
<Box w="3.25rem" style={{ flexShrink: 0 }}>
|
||||
<ThemePreview
|
||||
manifest={current}
|
||||
scheme={scheme}
|
||||
height="2.25rem"
|
||||
scale={0.5}
|
||||
/>
|
||||
</Box>
|
||||
<Text size="sm" fw={500} style={{ flex: 1, textAlign: "left" }}>
|
||||
{t(current.label)}
|
||||
</Text>
|
||||
<CaretRightIcon size={16} color="var(--mantine-color-dimmed)" />
|
||||
</UnstyledButton>
|
||||
|
||||
<Sheet title={t`Theme`} {...sheet.props}>
|
||||
<SimpleGrid cols={3} spacing="sm" py="sm">
|
||||
{[...THEME_LIST]
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(a.order ?? 100) - (b.order ?? 100) ||
|
||||
t(a.label).localeCompare(t(b.label))
|
||||
)
|
||||
.map((manifest) => {
|
||||
const isSelected = manifest.id === currentId;
|
||||
return (
|
||||
<UnstyledButton
|
||||
key={manifest.id}
|
||||
onClick={() => handleSelect(manifest.id)}
|
||||
>
|
||||
<Stack gap={6} align="center">
|
||||
<Box
|
||||
w="100%"
|
||||
p="0.125rem"
|
||||
bd={
|
||||
isSelected
|
||||
? "0.125rem solid var(--mantine-color-bright)"
|
||||
: "0.125rem solid transparent"
|
||||
}
|
||||
style={{
|
||||
borderRadius: "calc(var(--mantine-radius-md) + 0.25rem)",
|
||||
}}
|
||||
>
|
||||
<ThemePreview manifest={manifest} scheme={scheme} />
|
||||
</Box>
|
||||
<Text size="xs" fw={isSelected ? 700 : 400} ta="center">
|
||||
{t(manifest.label)}
|
||||
</Text>
|
||||
</Stack>
|
||||
</UnstyledButton>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid>
|
||||
</Sheet>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemePicker;
|
||||
Reference in New Issue
Block a user