Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit 22f6689

Browse files
committed
feat: add dark mode
1 parent f423b48 commit 22f6689

File tree

10 files changed

+163
-86
lines changed

10 files changed

+163
-86
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"@trpc/server": "^10.0.0-proxy-beta.23",
5151
"bullmq": "^2.3.2",
5252
"contrast-color": "^1.0.1",
53+
"cookies-next": "^2.1.1",
5354
"cron-parser": "^4.6.0",
5455
"cronstrue": "^2.14.0",
5556
"dayjs": "^1.11.5",

pnpm-lock.yaml

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/addManga/form.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const useStyles = createStyles((theme) => ({
2121
right: '55px',
2222
width: 'calc(100% - 55px)',
2323
height: '50px',
24-
background: 'white',
24+
background: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.white,
2525
},
2626
}));
2727

src/components/addManga/index.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const useStyles = createStyles((theme) => ({
1111
display: 'flex',
1212
justifyContent: 'center',
1313
alignItems: 'center',
14-
backgroundColor: theme.colors.gray[4],
14+
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[4],
1515
cursor: 'pointer',
1616

1717
transition: 'transform 150ms ease, box-shadow 150ms ease',
@@ -21,6 +21,10 @@ const useStyles = createStyles((theme) => ({
2121
boxShadow: theme.shadows.md,
2222
},
2323
},
24+
25+
plusIcon: {
26+
color: theme.colorScheme === 'light' ? theme.colors.dark[4] : theme.colors.gray[4],
27+
},
2428
}));
2529

2630
export const useAddMangaModal = () => {
@@ -58,7 +62,7 @@ export function AddManga({ onAdd }: { onAdd: () => void }) {
5862
return (
5963
<Tooltip label="Add a new manga" position="bottom">
6064
<Paper shadow="lg" p="md" radius="md" className={classes.card} onClick={() => addMangaModal(onAdd)}>
61-
<IconPlus color="darkblue" opacity={0.5} size={96} />
65+
<IconPlus className={classes.plusIcon} opacity={0.5} size={96} />
6266
</Paper>
6367
</Tooltip>
6468
);

src/components/addManga/mangaSearchResult.tsx

+61-53
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,40 @@
1-
import { createStyles, Image, SimpleGrid, Text, UnstyledButton } from '@mantine/core';
1+
import { createStyles, Image, ScrollArea, SimpleGrid, Text, UnstyledButton } from '@mantine/core';
22
import { useUncontrolled } from '@mantine/hooks';
33
import { useEffect, useState } from 'react';
44

5-
const useStyles = createStyles((theme, { checked, disabled }: { checked: boolean; disabled: boolean }) => ({
6-
button: {
7-
display: 'flex',
8-
alignItems: 'center',
9-
width: '100%',
10-
transition: 'background-color 150ms ease, border-color 150ms ease',
11-
border: `1px solid ${
12-
checked
13-
? theme.fn.variant({ variant: 'outline', color: theme.primaryColor }).border
14-
: theme.colorScheme === 'dark'
15-
? theme.colors.dark[8]
16-
: theme.colors.gray[3]
17-
}`,
18-
borderRadius: theme.radius.sm,
19-
padding: theme.spacing.sm,
20-
backgroundColor: checked
21-
? theme.fn.variant({ variant: 'light', color: theme.primaryColor }).background
22-
: disabled
23-
? theme.colors.gray[3]
24-
: theme.white,
25-
},
5+
const useStyles = createStyles((theme, { checked, disabled }: { checked: boolean; disabled: boolean }) => {
6+
let backgroundColor = 'light';
7+
if (disabled) {
8+
backgroundColor = theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[4];
9+
}
10+
if (checked) {
11+
backgroundColor = theme.fn.variant({ variant: 'light', color: theme.primaryColor }).background!;
12+
}
13+
return {
14+
button: {
15+
display: 'flex',
16+
alignItems: 'center',
17+
width: '100%',
18+
transition: 'background-color 150ms ease, border-color 150ms ease',
19+
border: `1px solid ${
20+
checked
21+
? theme.fn.variant({ variant: 'outline', color: theme.primaryColor }).border
22+
: theme.colorScheme === 'dark'
23+
? theme.colors.dark[8]
24+
: theme.colors.gray[3]
25+
}`,
26+
borderRadius: theme.radius.sm,
27+
padding: theme.spacing.sm,
28+
backgroundColor,
29+
outline: 'none !important',
30+
},
2631

27-
body: {
28-
flex: 1,
29-
marginLeft: theme.spacing.md,
30-
},
31-
}));
32+
body: {
33+
flex: 1,
34+
marginLeft: theme.spacing.md,
35+
},
36+
};
37+
});
3238

3339
interface ImageCheckboxProps {
3440
checked?: boolean;
@@ -115,31 +121,33 @@ export function MangaSearchResult({
115121
}, [items]);
116122

117123
return (
118-
<SimpleGrid
119-
cols={2}
120-
breakpoints={[
121-
{ maxWidth: 'md', cols: 2 },
122-
{ maxWidth: 'sm', cols: 1 },
123-
]}
124-
>
125-
{items.map((m) => (
126-
<ImageCheckbox
127-
key={m.title}
128-
image={m.cover || '/cover-not-found.jpg'}
129-
title={m.title}
130-
disabled={selected && m.title !== selected.title}
131-
description={m.status}
132-
onChange={(checked) => {
133-
if (checked) {
134-
setSelected(m);
135-
onSelect(m);
136-
} else {
137-
setSelected(undefined);
138-
onSelect(undefined);
139-
}
140-
}}
141-
/>
142-
))}
143-
</SimpleGrid>
124+
<ScrollArea sx={{ height: 350 }}>
125+
<SimpleGrid
126+
cols={2}
127+
breakpoints={[
128+
{ maxWidth: 'md', cols: 2 },
129+
{ maxWidth: 'sm', cols: 1 },
130+
]}
131+
>
132+
{items.map((m) => (
133+
<ImageCheckbox
134+
key={m.title}
135+
image={m.cover || '/cover-not-found.jpg'}
136+
title={m.title}
137+
disabled={selected && m.title !== selected.title}
138+
description={m.status}
139+
onChange={(checked) => {
140+
if (checked) {
141+
setSelected(m);
142+
onSelect(m);
143+
} else {
144+
setSelected(undefined);
145+
onSelect(undefined);
146+
}
147+
}}
148+
/>
149+
))}
150+
</SimpleGrid>
151+
</ScrollArea>
144152
);
145153
}

src/components/headerSearch.tsx

+17-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ const useStyles = createStyles((theme) => ({
1717
backgroundColor: theme.white,
1818
cursor: 'pointer',
1919
outline: '0 !important',
20+
21+
'&:hover': {
22+
backgroundColor: theme.colors.gray[0],
23+
},
24+
},
25+
26+
kbd: {
27+
backgroundColor: theme.colors.gray[4],
28+
borderColor: theme.colors.gray[4],
29+
color: theme.black,
2030
},
2131
}));
2232

@@ -87,7 +97,13 @@ export function SearchControl() {
8797
</Grid.Col>
8898
<Grid.Col span="content">
8999
<Group spacing={5}>
90-
<Kbd py={0}>Ctrl</Kbd>+<Kbd py={0}>P</Kbd>
100+
<Kbd className={classes.kbd} py={0}>
101+
Ctrl
102+
</Kbd>
103+
+
104+
<Kbd className={classes.kbd} py={0}>
105+
P
106+
</Kbd>
91107
</Group>
92108
</Grid.Col>
93109
</Grid>

src/components/madeWith.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function MadeWith({ minimized }: { minimized: boolean }): JSX.Element {
3636
{hearth}
3737
</Box>
3838
in{' '}
39-
<b style={{ marginLeft: '4px', color: '#051D49' }}>
39+
<b style={{ marginLeft: '4px' }}>
4040
<Tooltip withArrow label={<Text weight="lighter">a.k.a. Turkey</Text>} inline position="top-start">
4141
<Text component="span">Isekai</Text>
4242
</Tooltip>

src/components/mangaCard.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,14 @@ const useStyles = createStyles((theme, _params, getRef) => ({
5959
},
6060
editButton: {
6161
ref: getRef('editButton'),
62+
backgroundColor: theme.white,
63+
color: theme.colors.blue[6],
6264
position: 'absolute',
6365
right: 10,
6466
bottom: 10,
6567
display: 'none',
6668
'&:hover': {
67-
backgroundColor: theme.white,
69+
backgroundColor: theme.colors.gray[0],
6870
},
6971
},
7072
title: {

src/components/navbar.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ const useStyles = createStyles((theme) => ({
5959
paddingTop: theme.spacing.xs,
6060
paddingBottom: theme.spacing.xs,
6161
borderRadius: theme.radius.sm,
62-
color: theme.colors.gray[7],
62+
color: theme.colorScheme === 'dark' ? theme.colors.gray[5] : theme.colors.gray[8],
6363

6464
'&:hover': {
65-
backgroundColor: theme.colors.gray[0],
65+
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.gray[9] : theme.colors.gray[0],
6666
},
6767
},
6868
}));

src/pages/_app.tsx

+53-25
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,72 @@
1-
import { AppShell, MantineProvider } from '@mantine/core';
1+
import { AppShell, ColorScheme, ColorSchemeProvider, MantineProvider } from '@mantine/core';
2+
import { useColorScheme, useHotkeys } from '@mantine/hooks';
23
import { ModalsProvider } from '@mantine/modals';
34
import { NotificationsProvider } from '@mantine/notifications';
5+
import { getCookie, setCookie } from 'cookies-next';
46
import type { AppProps } from 'next/app';
57
import Head from 'next/head';
8+
import { useEffect, useState } from 'react';
69
import { KaizokuHeader } from '../components/header';
710
import { KaizokuNavbar } from '../components/navbar';
811
import '../styles/globals.css';
912
import { trpc } from '../utils/trpc';
1013

11-
function MyApp({ Component, pageProps }: AppProps) {
14+
function MyApp(props: AppProps) {
15+
const { Component, pageProps } = props;
16+
const preferredColorScheme = useColorScheme();
17+
const [colorScheme, setColorScheme] = useState<ColorScheme>('light');
18+
useEffect(() => {
19+
let followSystem = getCookie('follow-system');
20+
if (followSystem === undefined) {
21+
followSystem = true;
22+
setCookie('follow-system', '1');
23+
}
24+
if (followSystem === '1') {
25+
setColorScheme(preferredColorScheme);
26+
} else {
27+
setColorScheme((getCookie('mantine-color-scheme') as ColorScheme) || preferredColorScheme);
28+
}
29+
}, [preferredColorScheme]);
30+
const toggleColorScheme = (value?: ColorScheme) => {
31+
const nextColorScheme = value || (colorScheme === 'dark' ? 'light' : 'dark');
32+
setColorScheme(nextColorScheme);
33+
setCookie('mantine-color-scheme', nextColorScheme, { maxAge: 60 * 60 * 24 * 30 });
34+
};
35+
36+
useHotkeys([['shift+t', () => toggleColorScheme()]]);
37+
1238
return (
1339
<>
1440
<Head>
1541
<title>Kaizoku</title>
1642
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
1743
</Head>
1844

19-
<MantineProvider
20-
withGlobalStyles
21-
withNormalizeCSS
22-
theme={{
23-
fontFamily: 'Inter',
24-
colorScheme: 'light',
25-
}}
26-
>
27-
<ModalsProvider>
28-
<NotificationsProvider position="top-center" limit={5}>
29-
<AppShell
30-
padding="md"
31-
navbar={<KaizokuNavbar />}
32-
header={<KaizokuHeader />}
33-
styles={(theme) => ({
34-
main: { backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.colors.gray[0] },
35-
})}
36-
>
37-
<Component {...pageProps} />
38-
</AppShell>
39-
</NotificationsProvider>
40-
</ModalsProvider>
41-
</MantineProvider>
45+
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
46+
<MantineProvider
47+
withGlobalStyles
48+
withNormalizeCSS
49+
theme={{
50+
fontFamily: 'Inter',
51+
colorScheme,
52+
}}
53+
>
54+
<ModalsProvider>
55+
<NotificationsProvider position="top-center" limit={5}>
56+
<AppShell
57+
padding="md"
58+
navbar={<KaizokuNavbar />}
59+
header={<KaizokuHeader />}
60+
styles={(theme) => ({
61+
main: { backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.colors.gray[0] },
62+
})}
63+
>
64+
<Component {...pageProps} />
65+
</AppShell>
66+
</NotificationsProvider>
67+
</ModalsProvider>
68+
</MantineProvider>
69+
</ColorSchemeProvider>
4270
</>
4371
);
4472
}

0 commit comments

Comments
 (0)