Add theme utils

This commit is contained in:
Zoe Roux 2022-10-30 02:25:24 +09:00
parent cbbd04efb6
commit 000f7cbfe1
No known key found for this signature in database
GPG Key ID: B2AB52A2636E5C46
5 changed files with 217 additions and 58 deletions

View File

@ -38,18 +38,17 @@ import { Library, LibraryP, Page, Paged } from "~/models";
import { QueryIdentifier, useFetch } from "~/utils/query";
import { ErrorSnackbar } from "./errors";
const KyooTitle = (props: { sx: SxProps<Theme> }) => {
const KyooTitle = () => {
const { t } = useTranslation("common");
return (
<Tooltip title={t("navbar.home")}>
<ButtonLink
sx={{
css={{
alignItems: "center",
color: "inherit",
textDecoration: "inherit",
display: "flex",
...props.sx,
}}
href="/"
>
@ -57,7 +56,7 @@ const KyooTitle = (props: { sx: SxProps<Theme> }) => {
<Typography
variant="h6"
noWrap
sx={{
css={{
ml: 1,
mr: 2,
fontFamily: "monospace",
@ -90,7 +89,7 @@ export const Navbar = (barProps: AppBarProps) => {
<MenuIcon />
</IconButton>
<Box sx={{ flexGrow: 1, display: { sx: "flex", sm: "none" } }} />
<KyooTitle sx={{ mr: 1 }} />
<KyooTitle css={{ mr: 1 }} />
<Box sx={{ flexGrow: 1, display: { sx: "flex", sm: "none" } }} />
<Box sx={{ flexGrow: 1, display: { xs: "none", sm: "flex" } }}>
{isSuccess
@ -110,7 +109,7 @@ export const Navbar = (barProps: AppBarProps) => {
))}
</Box>
<Tooltip title={t("navbar.login")}>
<IconButton sx={{ p: 0 }} href="/auth/login">
<IconButton css={{ p: 0 }} href="/auth/login">
<Avatar alt={t("navbar.login")} />
</IconButton>
</Tooltip>

View File

@ -0,0 +1,67 @@
/*
* Kyoo - A portable and vast media library solution.
* Copyright (c) Kyoo.
*
* See AUTHORS.md and LICENSE file in the project root for full license information.
*
* Kyoo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Kyoo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { forwardRef } from "react";
export const Heading = forwardRef<
HTMLHeadingElement,
{
variant: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
children?: JSX.Element | JSX.Element[];
}
>(function Heading({ variant = "h1", children, ...props }, ref) {
const H = variant;
return (
<H
ref={ref}
{...props}
css={(theme) => ({
font: theme.fonts.heading,
color: theme.heading,
})}
className={`Heading Heading-${variant}`}
>
{children}
</H>
);
});
export const Paragraph = forwardRef<
HTMLParagraphElement,
{
variant: "normal" | "subtext";
children?: JSX.Element | JSX.Element[];
}
>(function Paragraph({ variant, children, ...props }, ref) {
return (
<p
ref={ref}
{...props}
css={(theme) => ({
font: theme.fonts.paragraph,
color: variant === "normal" ? theme.paragraph : theme.subtext,
})}
className={`Paragraph Paragraph-${variant}`}
>
{children}
</p>
);
});

View File

@ -18,59 +18,83 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import React, { useState } from "react";
import React, { ReactNode, useState } from "react";
import appWithI18n from "next-translate/appWithI18n";
import { ThemeProvider } from "@mui/material";
import { ThemeProvider, useTheme } from "@emotion/react";
import { createTheme, ThemeProvider as MTheme } from "@mui/material";
import NextApp, { AppContext } from "next/app";
import type { AppProps } from "next/app";
import { Hydrate, QueryClientProvider } from "react-query";
import { createQueryClient, fetchQuery, QueryIdentifier, QueryPage } from "~/utils/query";
import { defaultTheme } from "~/utils/themes/default-theme";
import superjson from "superjson";
import Head from "next/head";
import { useMobileHover } from "~/utils/utils";
import { catppuccin } from "~/utils/themes/catppuccin";
import { selectMode } from "~/utils/themes/theme";
// Simply silence a SSR warning (see https://github.com/facebook/react/issues/14927 for more details)
if (typeof window === "undefined") {
React.useLayoutEffect = React.useEffect;
}
const ThemeSelector = ({ children }: { children?: ReactNode | ReactNode[] }) => {
// TODO: Handle user selected mode (light, dark, auto)
// TODO: Hande theme change.
return (
<MTheme theme={createTheme()}>
<ThemeProvider theme={selectMode(catppuccin, "light")}>
{children}
</ThemeProvider>
</MTheme>
)
}
const GlobalCssTheme = () => {
const theme = useTheme();
return (
<style jsx global>{`
body {
margin: 0px;
padding: 0px;
background-color: ${theme.background};
}
*::-webkit-scrollbar {
height: 6px;
width: 6px;
background: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: #999;
border-radius: 90px;
}
*:hover::-webkit-scrollbar-thumb {
background-color: rgb(134, 127, 127);
}
`}</style>
);
};
const App = ({ Component, pageProps }: AppProps) => {
const [queryClient] = useState(() => createQueryClient());
const { queryState, ...props } = superjson.deserialize<any>(pageProps ?? {});
const { queryState, ...props } = superjson.deserialize<any>(pageProps ?? { json: {} });
const getLayout = (Component as QueryPage).getLayout ?? ((page) => page);
useMobileHover();
return (
<>
<style jsx global>{`
body {
margin: 0px;
padding: 0px;
background-color: ${defaultTheme.palette.background.default};
}
*::-webkit-scrollbar {
height: 6px;
width: 6px;
background: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: #999;
border-radius: 90px;
}
*:hover::-webkit-scrollbar-thumb {
background-color: rgb(134, 127, 127);
}
`}</style>
<Head>
<title>Kyoo</title>
</Head>
<QueryClientProvider client={queryClient}>
<Hydrate state={queryState}>
<ThemeProvider theme={defaultTheme}>{getLayout(<Component {...props} />)}</ThemeProvider>
<ThemeSelector>
<GlobalCssTheme />
{getLayout(<Component {...props} />)}
</ThemeSelector>
</Hydrate>
</QueryClientProvider>
</>

View File

@ -18,36 +18,17 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { Property } from "csstype";
import { ThemeBuilder } from "./theme";
// TODO: Add specifics colors
export type Theme = {
fonts: {
heading: string,
paragraph: string,
},
light: {
appbar: Property.Color,
default: {
background: Property.Color,
accent: Property.Color,
divider: Property.Color,
heading: Property.Color,
paragraph: Property.Color,
subtext: Property.Color,
},
variant: Theme["light"]["default"],
},
dark: Theme["light"]
}
export const catppuccin: Theme = {
export const catppuccin: ThemeBuilder = {
fonts: {
heading: "Pacifico",
paragraph: "Poppins",
},
light: {
appbar: "#e64553",
contrast: "#cdd6f4",
subcontrast: "#bac2de",
default: {
background: "#eff1f5",
accent: "#ea76cb",
@ -63,10 +44,12 @@ export const catppuccin: Theme = {
heading: "#4c4f69",
paragraph: "#5c5f77",
subtext: "#6c6f85",
}
},
},
dark: {
appbar: "#94e2d5",
contrast: "#cdd6f4",
subcontrast: "#bac2de",
default: {
background: "#1e1e2e",
accent: "##f5c2e7",
@ -83,5 +66,5 @@ export const catppuccin: Theme = {
paragraph: "#bac2de",
subtext: "#a6adc8",
},
}
}
},
};

View File

@ -0,0 +1,86 @@
/*
* Kyoo - A portable and vast media library solution.
* Copyright (c) Kyoo.
*
* See AUTHORS.md and LICENSE file in the project root for full license information.
*
* Kyoo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Kyoo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { Property } from "csstype";
import "@emotion/react";
import { Theme, ThemeProvider, useTheme } from "@emotion/react";
type ThemeSettings = {
fonts: {
heading: string;
paragraph: string;
};
};
type Mode = Variant & {
appbar: Property.Color;
/*
* The color used in texts or button that are hover black shades on images (ShowHeader, player...)
*/
contrast: Property.Color;
subcontrast: Property.Color;
variant: Variant;
};
type Variant = {
background: Property.Color;
accent: Property.Color;
divider: Property.Color;
heading: Property.Color;
paragraph: Property.Color;
subtext: Property.Color;
};
declare module "@emotion/react" {
// TODO: Add specifics colors
export interface Theme extends ThemeSettings, Mode {}
}
export type { Theme } from "@emotion/react";
export type ThemeBuilder = ThemeSettings & {
light: Mode;
dark: Mode;
};
export const selectMode = (theme: ThemeBuilder, mode: "light" | "dark"): Theme => {
const value = (mode === "light" ? theme.light : theme.dark);
return { fonts: theme.fonts, ...(value.default), variant: value.variant };
};
export const switchVariant = (theme: Theme) => {
return {
...theme,
...theme.variant,
variant: {
background: theme.background,
accent: theme.accent,
divider: theme.divider,
heading: theme.heading,
paragraph: theme.paragraph,
subtext: theme.subtext,
},
};
};
export const SwitchVariant = ({ children }: { children?: JSX.Element | JSX.Element[] }) => {
const theme = useTheme();
return <ThemeProvider theme={switchVariant(theme)}>{children}</ThemeProvider>;
};