Skip to content

Commit 2124dfe

Browse files
committed
new: theme selector
1 parent 6cdde50 commit 2124dfe

File tree

24 files changed

+243
-61
lines changed

24 files changed

+243
-61
lines changed

src/components/Page/Page.tsx

+10-6
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@ import "./Page.sass";
22

33
import { AllHTMLAttributes, FC } from "react";
44
import cn from "clsx";
5-
import clsx from "clsx";
5+
6+
import { ModalProvider } from "modals";
67

78
interface PageProps extends AllHTMLAttributes<HTMLElement> {
89
containerClassName?: string;
910
}
1011

1112
const Page: FC<PageProps> = (props) => {
1213
return (
13-
<section className={clsx("Page", props.className)}>
14-
<div className={cn("Page__container", props.containerClassName)}>
15-
{props.children}
16-
</div>
17-
</section>
14+
<>
15+
<ModalProvider />
16+
<section className={cn("Page", props.className)}>
17+
<div className={cn("Page__container", props.containerClassName)}>
18+
{props.children}
19+
</div>
20+
</section>
21+
</>
1822
);
1923
};
2024

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.ThemeCard
2+
cursor: pointer
3+
4+
&_active
5+
border: 1px solid var(--accent) !important
6+
7+
& ~ p
8+
color: var(--accent) !important
9+
opacity: 1
10+
11+
& > p
12+
text-align: center
13+
margin-top: 6px
14+
15+
&::first-letter
16+
text-transform: uppercase
17+
18+
&__content
19+
width: 100px
20+
aspect-ratio: 2 / 1.5
21+
position: relative
22+
overflow: hidden
23+
border-radius: 10px
24+
25+
&_light
26+
background: var(--light-theme_background)
27+
border: 1px solid var(--dark-theme_background)
28+
29+
&::before
30+
content: ""
31+
background: var(--light-theme_secondary)
32+
width: 100%
33+
aspect-ratio: 1 / 1
34+
border-radius: 999999px
35+
position: absolute
36+
left: -50%
37+
top: -50%
38+
39+
&_dark
40+
background: var(--dark-theme_background)
41+
border: 1px solid var(--light-theme_background)
42+
43+
&::before
44+
content: ""
45+
background: var(--dark-theme_secondary)
46+
width: 100%
47+
aspect-ratio: 1 / 1
48+
border-radius: 999999px
49+
position: absolute
50+
right: -50%
51+
top: -50%
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import "./ThemeCard.sass";
2+
3+
import { FC } from "react";
4+
import cn from "clsx";
5+
6+
import { Text } from "uikit";
7+
8+
import { THEME, themes } from "vars";
9+
10+
const ThemeCard: FC<{ type: (typeof themes)[number] }> = (props) => {
11+
const handleChangeTheme = () => {
12+
if (props.type === THEME) return;
13+
localStorage.setItem("theme", props.type);
14+
location.reload();
15+
};
16+
17+
return (
18+
<div className="ThemeCard" onClick={handleChangeTheme}>
19+
<div
20+
className={cn(
21+
"ThemeCard__content",
22+
`ThemeCard_${props.type}`,
23+
props.type === THEME && "ThemeCard_active",
24+
)}
25+
/>
26+
<Text isDescription>{props.type}</Text>
27+
</div>
28+
);
29+
};
30+
31+
export default ThemeCard;

src/components/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { default as FilePreview } from "./FilePreview/FilePreview";
66
export { default as Files } from "./Files/Files";
77
export { default as Help } from "./Help/Help";
88
export { default as ResourceCell } from "./ResourceCell/ResourceCell";
9+
export { default as ThemeCard } from "./ThemeCard/ThemeCard";

src/core/Home/Home.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import "./Home.sass";
33
import { type FC } from "react";
44
import { useTranslation } from "i18nano";
55
import { useSelector } from "react-redux";
6+
import { useModal } from "hooks";
67
import { objectToArray } from "utils";
78

89
import { FileLoader, Files, Help, Page, ResourceCell } from "components";
@@ -17,13 +18,16 @@ import {
1718
IconLanguage,
1819
} from "assets/icons";
1920

21+
import { ModalID } from "models";
22+
2023
import { LANG, THEME } from "vars";
2124

2225
const saveCells = ["prev", "next", "all"] as const;
2326

2427
const Home: FC = () => {
2528
const t = useTranslation();
2629
const { files } = useSelector(dndFilesSelector);
30+
const { openModal } = useModal();
2731

2832
const getFilesSize = (type: "compressed" | "default") => {
2933
const arr = objectToArray(files);
@@ -94,13 +98,17 @@ const Home: FC = () => {
9498
</div>
9599
<div className="Home_flex">
96100
<Cell
97-
onClick={() => {}}
101+
onClick={() => {
102+
openModal(ModalID.Theme);
103+
}}
98104
icon={<IconBrush />}
99105
title={t(`app.theme.title`)}
100106
text={t(`app.theme.${THEME}`)}
101107
/>
102108
<Cell
103-
onClick={() => {}}
109+
onClick={() => {
110+
openModal(ModalID.Language);
111+
}}
104112
icon={<IconLanguage />}
105113
title={t(`app.language.title`)}
106114
text={t(`app.language.${LANG}`)}

src/hooks/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./useModal";

src/hooks/useModal.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useSearchParams } from "react-router-dom";
2+
3+
import { ModalID } from "models";
4+
5+
export const useModal = () => {
6+
const key = "modal";
7+
const [urlParams, setUrlParams] = useSearchParams();
8+
9+
return {
10+
activeModal: urlParams.get(key),
11+
openModal(modal: ModalID) {
12+
setUrlParams((s) => {
13+
s.set(key, modal);
14+
return s;
15+
});
16+
},
17+
closeModal() {
18+
setUrlParams(
19+
(s) => {
20+
s.delete(key);
21+
return s;
22+
},
23+
{ replace: true },
24+
);
25+
},
26+
};
27+
};

src/modals/Language/Language.sass

Whitespace-only changes.

src/modals/Language/Language.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { type FC } from "react";
2+
3+
import { Card } from "uikit";
4+
5+
const Language: FC = () => {
6+
return <Card>Language Select</Card>;
7+
};
8+
9+
export default Language;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.ModalProvider
2+
position: fixed
3+
width: 100vw
4+
height: 100vh
5+
top: 0
6+
left: 0
7+
background: rgba(0,0,0,.3)
8+
z-index: 10
9+
display: flex
10+
align-items: center
11+
justify-content: center
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import "./ModalProvider.sass";
2+
3+
import { FC } from "react";
4+
5+
import { useModal } from "hooks";
6+
import { modals } from "routes";
7+
8+
const ModalProvider: FC = () => {
9+
const { activeModal, closeModal } = useModal();
10+
11+
if (!activeModal) return null;
12+
13+
return (
14+
<div className="ModalProvider" onClick={(e) => closeModal()}>
15+
{modals
16+
.filter((m) => m.key === activeModal)
17+
.map((m) => {
18+
return (
19+
<div
20+
key={m.key}
21+
className="ModalProvider__wrapper"
22+
onClick={(e) => e.stopPropagation()}
23+
>
24+
{m.component}
25+
</div>
26+
);
27+
})}
28+
</div>
29+
);
30+
};
31+
32+
export default ModalProvider;

src/modals/Theme/Theme.sass

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.Theme
2+
display: flex
3+
gap: 15px

src/modals/Theme/Theme.tsx

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import "./Theme.sass";
2+
3+
import { type FC } from "react";
4+
5+
import { Card } from "uikit";
6+
7+
import { ThemeCard } from "components";
8+
9+
import { themes } from "vars";
10+
11+
const Theme: FC = () => {
12+
return (
13+
<Card className="Theme">
14+
{themes.map((t) => (
15+
<ThemeCard key={t} type={t} />
16+
))}
17+
</Card>
18+
);
19+
};
20+
21+
export default Theme;

src/modals/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { default as ModalProvider } from "./ModalProvider/ModalProvider";
2+
3+
export { default as LanguageModal } from "./Language/Language";
4+
export { default as ThemeModal } from "./Theme/Theme";

src/models/service.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
export enum RouteID {
1+
export const enum RouteID {
22
App = "app",
33

44
Home = "home",
5+
}
56

6-
HowToUse = "howToUse",
7+
export const enum ModalID {
8+
Theme = "theme",
9+
Language = "language",
710
}

src/routes/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from "./routes";
2+
export * from "./modals";

src/routes/modals.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { LanguageModal, ThemeModal } from "modals";
2+
3+
import { ModalID } from "models";
4+
5+
const modals = [
6+
{ key: ModalID.Language, component: <LanguageModal /> },
7+
{ key: ModalID.Theme, component: <ThemeModal /> },
8+
];
9+
10+
export { modals };

src/styles/variables/_colors.sass

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
body
2+
--light-theme_background: #F4F4F4
3+
--light-theme_secondary: #ffffff
4+
--dark-theme_background: #171717
5+
--dark-theme_secondary: #262626
6+
27
--red: #F54F4F
38
--green: #24D33E
49
--purple: #E530D9
510
--accent: #e54c70
611
--active: #95cbf5
712
--hover: #EBEFF9
813

9-
--background: #F4F4F4
10-
--secondary: #ffffff
14+
--background: var(--light-theme_background)
15+
--secondary: var(--light-theme_secondary)
1116
--tertiary: #d1d1d1
1217
--primary: #32353e
1318

@@ -20,8 +25,8 @@ body
2025
--active: #28292B
2126
--hover: #5D6169
2227

23-
--background: #171717
24-
--secondary: #262626
28+
--background: var(--dark-theme_background)
29+
--secondary: var(--dark-theme_secondary)
2530
--tertiary: #353535
2631

2732
--text-primary: #FFFFFF

src/uikit/Form/Dropdown/Dropdown.sass

-6
This file was deleted.

src/uikit/Form/Dropdown/Dropdown.tsx

-35
This file was deleted.

src/uikit/Form/Separator/Separator.sass

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
margin: 0
44
border-color: var(--background)
55
color: var(--background)
6-
-webkit-tap-highlight-color: var(--background)
6+
-webkit-tap-highlight-color: var(--background)
7+
opacity: .2

src/uikit/Form/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export { default as Cell } from "./Cell/Cell";
22
export { default as Separator } from "./Separator/Separator";
3-
export { default as Dropdown } from "./Dropdown/Dropdown";
43
export { default as Button } from "./Button/Button";

0 commit comments

Comments
 (0)