mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Add theme utils
This commit is contained in:
parent
cbbd04efb6
commit
000f7cbfe1
@ -38,18 +38,17 @@ import { Library, LibraryP, Page, Paged } from "~/models";
|
|||||||
import { QueryIdentifier, useFetch } from "~/utils/query";
|
import { QueryIdentifier, useFetch } from "~/utils/query";
|
||||||
import { ErrorSnackbar } from "./errors";
|
import { ErrorSnackbar } from "./errors";
|
||||||
|
|
||||||
const KyooTitle = (props: { sx: SxProps<Theme> }) => {
|
const KyooTitle = () => {
|
||||||
const { t } = useTranslation("common");
|
const { t } = useTranslation("common");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title={t("navbar.home")}>
|
<Tooltip title={t("navbar.home")}>
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
sx={{
|
css={{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
color: "inherit",
|
color: "inherit",
|
||||||
textDecoration: "inherit",
|
textDecoration: "inherit",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
...props.sx,
|
|
||||||
}}
|
}}
|
||||||
href="/"
|
href="/"
|
||||||
>
|
>
|
||||||
@ -57,7 +56,7 @@ const KyooTitle = (props: { sx: SxProps<Theme> }) => {
|
|||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
noWrap
|
noWrap
|
||||||
sx={{
|
css={{
|
||||||
ml: 1,
|
ml: 1,
|
||||||
mr: 2,
|
mr: 2,
|
||||||
fontFamily: "monospace",
|
fontFamily: "monospace",
|
||||||
@ -90,7 +89,7 @@ export const Navbar = (barProps: AppBarProps) => {
|
|||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Box sx={{ flexGrow: 1, display: { sx: "flex", sm: "none" } }} />
|
<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: { sx: "flex", sm: "none" } }} />
|
||||||
<Box sx={{ flexGrow: 1, display: { xs: "none", sm: "flex" } }}>
|
<Box sx={{ flexGrow: 1, display: { xs: "none", sm: "flex" } }}>
|
||||||
{isSuccess
|
{isSuccess
|
||||||
@ -110,7 +109,7 @@ export const Navbar = (barProps: AppBarProps) => {
|
|||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
<Tooltip title={t("navbar.login")}>
|
<Tooltip title={t("navbar.login")}>
|
||||||
<IconButton sx={{ p: 0 }} href="/auth/login">
|
<IconButton css={{ p: 0 }} href="/auth/login">
|
||||||
<Avatar alt={t("navbar.login")} />
|
<Avatar alt={t("navbar.login")} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
67
front/src/components/primitives/text.tsx
Normal file
67
front/src/components/primitives/text.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
});
|
@ -18,59 +18,83 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* 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 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 NextApp, { AppContext } from "next/app";
|
||||||
import type { AppProps } from "next/app";
|
import type { AppProps } from "next/app";
|
||||||
import { Hydrate, QueryClientProvider } from "react-query";
|
import { Hydrate, QueryClientProvider } from "react-query";
|
||||||
import { createQueryClient, fetchQuery, QueryIdentifier, QueryPage } from "~/utils/query";
|
import { createQueryClient, fetchQuery, QueryIdentifier, QueryPage } from "~/utils/query";
|
||||||
import { defaultTheme } from "~/utils/themes/default-theme";
|
|
||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useMobileHover } from "~/utils/utils";
|
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)
|
// Simply silence a SSR warning (see https://github.com/facebook/react/issues/14927 for more details)
|
||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
React.useLayoutEffect = React.useEffect;
|
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 App = ({ Component, pageProps }: AppProps) => {
|
||||||
const [queryClient] = useState(() => createQueryClient());
|
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);
|
const getLayout = (Component as QueryPage).getLayout ?? ((page) => page);
|
||||||
|
|
||||||
useMobileHover();
|
useMobileHover();
|
||||||
|
|
||||||
return (
|
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>
|
<Head>
|
||||||
<title>Kyoo</title>
|
<title>Kyoo</title>
|
||||||
</Head>
|
</Head>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<Hydrate state={queryState}>
|
<Hydrate state={queryState}>
|
||||||
<ThemeProvider theme={defaultTheme}>{getLayout(<Component {...props} />)}</ThemeProvider>
|
<ThemeSelector>
|
||||||
|
<GlobalCssTheme />
|
||||||
|
{getLayout(<Component {...props} />)}
|
||||||
|
</ThemeSelector>
|
||||||
</Hydrate>
|
</Hydrate>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</>
|
</>
|
||||||
|
@ -18,36 +18,17 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Property } from "csstype";
|
import { ThemeBuilder } from "./theme";
|
||||||
|
|
||||||
// TODO: Add specifics colors
|
export const catppuccin: ThemeBuilder = {
|
||||||
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 = {
|
|
||||||
fonts: {
|
fonts: {
|
||||||
heading: "Pacifico",
|
heading: "Pacifico",
|
||||||
paragraph: "Poppins",
|
paragraph: "Poppins",
|
||||||
},
|
},
|
||||||
light: {
|
light: {
|
||||||
appbar: "#e64553",
|
appbar: "#e64553",
|
||||||
|
contrast: "#cdd6f4",
|
||||||
|
subcontrast: "#bac2de",
|
||||||
default: {
|
default: {
|
||||||
background: "#eff1f5",
|
background: "#eff1f5",
|
||||||
accent: "#ea76cb",
|
accent: "#ea76cb",
|
||||||
@ -63,10 +44,12 @@ export const catppuccin: Theme = {
|
|||||||
heading: "#4c4f69",
|
heading: "#4c4f69",
|
||||||
paragraph: "#5c5f77",
|
paragraph: "#5c5f77",
|
||||||
subtext: "#6c6f85",
|
subtext: "#6c6f85",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
appbar: "#94e2d5",
|
appbar: "#94e2d5",
|
||||||
|
contrast: "#cdd6f4",
|
||||||
|
subcontrast: "#bac2de",
|
||||||
default: {
|
default: {
|
||||||
background: "#1e1e2e",
|
background: "#1e1e2e",
|
||||||
accent: "##f5c2e7",
|
accent: "##f5c2e7",
|
||||||
@ -83,5 +66,5 @@ export const catppuccin: Theme = {
|
|||||||
paragraph: "#bac2de",
|
paragraph: "#bac2de",
|
||||||
subtext: "#a6adc8",
|
subtext: "#a6adc8",
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
86
front/src/utils/themes/theme.tsx
Normal file
86
front/src/utils/themes/theme.tsx
Normal 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>;
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user