Skip to content

Commit bdb98ad

Browse files
author
k.golikov
committed
Add Data Url Generator
1 parent 3e9d001 commit bdb98ad

21 files changed

+384
-28
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"classnames": "^2.3.1",
2020
"emmet-monaco-es": "^5.1.0",
2121
"immer": "^9.0.12",
22+
"js-base64": "^3.7.2",
2223
"konva": "^8.3.5",
2324
"lodash": "^4.17.21",
2425
"moment": "^2.29.1",

src/constants/router/menuItems.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,28 @@ const menuItems: MenuItem[] = [
6464
{
6565
route: routes.htmlEditor
6666
},
67+
{
68+
route: routes.dataUrl
69+
},
70+
{
71+
route: routes.base64,
72+
isHidden: true
73+
},
6774
{
6875
route: routes.imageCompressor,
69-
isGray: true
76+
isHidden: true
7077
},
7178
{
7279
route: routes.dateUtils,
73-
isGray: true
80+
isHidden: true
7481
},
7582
{
7683
route: routes.templateTextGenerator,
77-
isGray: true
84+
isHidden: true
7885
},
7986
{
8087
route: routes.unitConverter,
81-
isGray: true
88+
isHidden: true
8289
}
8390
]
8491
},

src/constants/router/routes.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,15 @@ import NotificationsTestPage from '../../pages/notificationsTestPage/Notificatio
2626
import DateUtilsPage from '../../pages/dateUtilsPage/DateUtilsPage';
2727
import ImageCompressorPage from '../../pages/imageCompressorPage/ImageCompressorPage';
2828
import HtmlEditorPage from '../../pages/htmlEditorPage/HtmlEditorPage';
29+
import Base64Page from '../../pages/base64Page/Base64Page';
30+
import DataUrlPage from '../../pages/dataUrlPage/DataUrlPage';
31+
import DataUrlViewPage from '../../pages/dataUrlViewPage/DataUrlViewPage';
2932

3033
export interface AppRoute extends Omit<RouteProps, 'element'> {
3134
path: string;
3235
component: ComponentType;
3336
title: string;
37+
isLayoutHidden?: boolean;
3438
}
3539

3640
type AppRoutesMap = Readonly<{
@@ -55,6 +59,9 @@ type AppRoutesMap = Readonly<{
5559
dateUtils: AppRoute;
5660
imageCompressor: AppRoute;
5761
htmlEditor: AppRoute;
62+
base64: AppRoute;
63+
dataUrl: AppRoute;
64+
dataUrlView: AppRoute;
5865
settings: AppRoute;
5966
about: AppRoute;
6067
}>;
@@ -165,6 +172,22 @@ export const routes: AppRoutesMap = {
165172
component: HtmlEditorPage,
166173
title: 'HTML Editor'
167174
},
175+
base64: {
176+
path: '/tools/base64',
177+
component: Base64Page,
178+
title: 'Base64 Tools'
179+
},
180+
dataUrl: {
181+
path: '/tools/data-url',
182+
component: DataUrlPage,
183+
title: 'Data URL Generator'
184+
},
185+
dataUrlView: {
186+
path: '/tools/data-url/view',
187+
component: DataUrlViewPage,
188+
title: 'Content View',
189+
isLayoutHidden: true
190+
},
168191
settings: {
169192
path: '/settings',
170193
component: SettingsPage,

src/hooks/useAppLocation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { AppRoute, appRoutesList } from '../constants/router/routes';
22
import { useLocation } from 'react-router-dom';
33
import { useMemo } from 'react';
44

5-
const useAppLocation = (): AppRoute => {
5+
const useAppLocation = (): AppRoute | undefined => {
66
const { pathname } = useLocation();
77

8-
return useMemo(() => appRoutesList.find((route) => route.path === pathname) as AppRoute, [pathname]);
8+
return useMemo(() => appRoutesList.find((route) => route.path === pathname), [pathname]);
99
};
1010

1111
export default useAppLocation;

src/hooks/useQuery.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useMemo } from 'react';
2+
import { useLocation } from 'react-router-dom';
3+
4+
const useQuery = <T extends object = Record<string, string>>(): T extends any[] ? never : T => {
5+
const { search } = useLocation();
6+
7+
return useMemo(() => Object.fromEntries(new URLSearchParams(search)) as any, [search]);
8+
};
9+
10+
export default useQuery;

src/hooks/useStateProducer.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Dispatch, SetStateAction, useCallback } from 'react';
2+
import produce, { Draft } from 'immer';
3+
import { Nothing } from 'immer/src/internal';
4+
5+
type ValidRecipeReturnType<State> = State | void | undefined | (State extends undefined ? Nothing : never);
6+
7+
type RecipeReturnType<State> = ValidRecipeReturnType<State> | Promise<ValidRecipeReturnType<State>>;
8+
9+
type Recipe<S> = (draft: Draft<S>) => RecipeReturnType<Draft<S>>;
10+
11+
export const produceState = <S extends object>(
12+
setState: Dispatch<SetStateAction<S>>,
13+
recipe: Recipe<S>
14+
): void | Promise<void> => {
15+
setState((state) => {
16+
return produce(state, recipe as any);
17+
});
18+
};
19+
20+
const useStateProducer = <S extends object>(setState: Dispatch<SetStateAction<S>>) => {
21+
return useCallback(
22+
(recipe: Recipe<S>) => {
23+
produceState(setState, recipe);
24+
},
25+
[setState]
26+
);
27+
};
28+
29+
export default useStateProducer;

src/layouts/appLayout/AppLayout.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ const AppLayout: FunctionComponent = ({ children }) => {
1515

1616
const isFooterShown = !isFooterHidden || appRoute === routes.root;
1717

18+
const isLayoutHidden = appRoute?.isLayoutHidden === true;
19+
20+
if (isLayoutHidden) {
21+
return <>{children}</>;
22+
}
23+
1824
return (
1925
<Layout className={styles.container}>
2026
<AppHeader />

src/layouts/appLayout/utils/routeMenuItems.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import classNames from 'classnames';
77
import { ItemType } from 'antd/lib/menu/hooks/useItems';
88
import AppSettings from '../../../types/AppSettings';
99

10-
export const renderRoute = ({ route, title, icon, isGray }: MenuRouteItem): ItemType => {
10+
export const renderRoute = ({ route, title, icon, isHidden }: MenuRouteItem): ItemType => {
1111
const { path } = route;
1212

1313
return {
1414
key: path,
1515
icon: renderComponent(icon),
1616
label: (
17-
<Link to={path ?? ''} className={classNames({ 'opacity-50': isGray })}>
17+
<Link to={path ?? ''} className={classNames({ 'opacity-50': isHidden })}>
1818
{title ?? route.title}
1919
</Link>
2020
)
@@ -36,7 +36,7 @@ interface MenuItemBase {
3636
export interface MenuRouteItem extends MenuItemBase {
3737
title?: string;
3838
route: AppRoute;
39-
isGray?: boolean;
39+
isHidden?: boolean;
4040
}
4141

4242
export interface SubMenuItem extends MenuItemBase {
@@ -63,7 +63,7 @@ export const renderMenuItem = (menuItem: MenuItem, index: number, settings: AppS
6363
return true;
6464
}
6565

66-
return !('route' in item) || !item.isGray;
66+
return !('route' in item) || !item.isHidden;
6767
})
6868
.map((item, index) => renderMenuItem(item, index, settings))
6969
: [

src/pages/base64Page/Base64Page.module.scss

Whitespace-only changes.

src/pages/base64Page/Base64Page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import React, { FunctionComponent } from 'react';
2+
import PageContainer from '../../layouts/pages/pageContainer/PageContainer';
3+
4+
const Base64Page: FunctionComponent = () => {
5+
return <PageContainer title="Base64Page"></PageContainer>;
6+
};
7+
8+
export default Base64Page;

0 commit comments

Comments
 (0)