Skip to content

Commit c26c2e2

Browse files
author
k.golikov
committed
Add JSON to TypeScript converter, WIP
1 parent cc8bfb5 commit c26c2e2

File tree

22 files changed

+394
-61
lines changed

22 files changed

+394
-61
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { FunctionComponent } from 'react';
2+
import { DiffEditor, DiffEditorProps } from '@monaco-editor/react';
3+
import classNames from 'classnames';
4+
import useAppTheme from '../../hooks/useAppTheme';
5+
import { Spin } from 'antd';
6+
7+
const loadingNode = <Spin size="large" />;
8+
9+
type Props = DiffEditorProps;
10+
11+
const AppDiffEditor: FunctionComponent<Props> = ({ className, loading, theme, ...props }) => {
12+
const { isDarkMode } = useAppTheme();
13+
14+
return (
15+
<DiffEditor
16+
theme={theme ?? (isDarkMode ? 'vs-dark' : 'light')}
17+
className={classNames('app-monaco-editor', className)}
18+
loading={loading ?? loadingNode}
19+
{...props}
20+
/>
21+
);
22+
};
23+
24+
export default AppDiffEditor;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React, { FunctionComponent, useCallback } from 'react';
2+
import Editor, { EditorProps, OnChange } from '@monaco-editor/react';
3+
import useAppTheme from '../../hooks/useAppTheme';
4+
import { Spin } from 'antd';
5+
import classNames from 'classnames';
6+
import * as monaco from 'monaco-editor';
7+
import MonacoLanguage from '../../types/MonacoLanguage';
8+
9+
const loadingNode = <Spin size="large" />;
10+
11+
export type AppOnChange = (value: string, ev: monaco.editor.IModelContentChangedEvent) => void;
12+
13+
interface Props extends Omit<EditorProps, 'onChange'> {
14+
onChange?: AppOnChange;
15+
language?: MonacoLanguage;
16+
}
17+
18+
const AppEditor: FunctionComponent<Props> = ({ className, loading, theme, onChange, ...props }) => {
19+
const { isDarkMode } = useAppTheme();
20+
21+
const handleChange = useCallback<OnChange>(
22+
(value, ev) => {
23+
onChange?.(value ?? '', ev);
24+
},
25+
[onChange]
26+
);
27+
28+
return (
29+
<Editor
30+
theme={theme ?? (isDarkMode ? 'vs-dark' : 'light')}
31+
className={classNames('app-monaco-editor', className)}
32+
loading={loading ?? loadingNode}
33+
onChange={handleChange}
34+
{...props}
35+
/>
36+
);
37+
};
38+
39+
export default AppEditor;

src/components/pageContainer/PageContainer.module.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
flex-direction: column;
77
gap: 8px;
88

9+
&.noPadding {
10+
padding: 0;
11+
}
12+
913
.headingContainer {
1014
width: 100%;
1115
justify-content: space-between;

src/components/pageContainer/PageContainer.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import styles from './PageContainer.module.scss';
33
import { Space, SpaceProps, Tag } from 'antd';
44
import Paragraph from 'antd/lib/typography/Paragraph';
55
import { ClockCircleOutlined, WarningOutlined } from '@ant-design/icons';
6+
import classNames from 'classnames';
67

78
export enum PageTag {
89
WIP = 'WIP',
@@ -14,6 +15,7 @@ interface Props extends Omit<SpaceProps, 'title'> {
1415
description?: ReactNode;
1516
titleExtra?: ReactNode;
1617
tags?: PageTag[];
18+
noPadding?: boolean;
1719
}
1820

1921
const getTagNodes = (key: number | string): Readonly<Record<PageTag, ReactNode>> => ({
@@ -31,11 +33,13 @@ const getTagNodes = (key: number | string): Readonly<Record<PageTag, ReactNode>>
3133

3234
const renderTag = (tag: PageTag, index: number) => getTagNodes(index)[tag];
3335

34-
const PageContainer: FunctionComponent<Props> = ({ title, description, titleExtra, tags, children, ...props }) => {
36+
const PageContainer: FunctionComponent<Props> = (props) => {
37+
const { title, description, titleExtra, tags, noPadding, children, className, ...restProps } = props;
38+
3539
const renderedTags = useMemo(() => tags?.map(renderTag), [tags]);
3640

3741
return (
38-
<div className={styles.container} {...props}>
42+
<div className={classNames(styles.container, { [styles.noPadding]: noPadding }, className)} {...restProps}>
3943
{tags?.length && <div>{renderedTags}</div>}
4044
{title && (
4145
<Space direction="horizontal" size="middle" className={styles.headingContainer}>

src/constants/router/menuItems.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ const menuItems: MenuItem[] = [
5252
{
5353
route: routes.codeFormatter
5454
},
55+
{
56+
route: routes.jsonToTypescript
57+
},
5558
{
5659
route: routes.templateTextGenerator,
5760
isGray: true

src/constants/router/routes.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import SettingsPage from '../../pages/settingsPage/SettingsPage';
2121
import AboutPage from '../../pages/aboutPage/AboutPage';
2222
import CodeFormatterPage from '../../pages/codeFormatterPage/CodeFormatterPage';
2323
import DiffEditorPage from '../../pages/DiffEditorPage';
24+
import JsonToTypeScriptPage from '../../pages/jsonToTypeScriptPage/JsonToTypeScriptPage';
2425

2526
export interface AppRoute extends Omit<RouteProps, 'element'> {
2627
path: string;
@@ -45,6 +46,7 @@ type AppRoutesMap = Readonly<{
4546
uuidGenerator: AppRoute;
4647
diffEditor: AppRoute;
4748
codeFormatter: AppRoute;
49+
jsonToTypescript: AppRoute;
4850
settings: AppRoute;
4951
about: AppRoute;
5052
}>;
@@ -130,6 +132,11 @@ export const routes: AppRoutesMap = {
130132
component: CodeFormatterPage,
131133
title: 'Code Formatter'
132134
},
135+
jsonToTypescript: {
136+
path: '/tools/json-to-typescript',
137+
component: JsonToTypeScriptPage,
138+
title: 'JSON to TypeScript'
139+
},
133140
settings: {
134141
path: '/settings',
135142
component: SettingsPage,
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import '../../styles/main';
2+
13
.loading {
24
position: absolute;
35
width: 100%;
@@ -8,14 +10,18 @@
810

911
overflow: hidden;
1012

11-
background-color: white;
12-
1313
transition-duration: 0.075s;
1414
transition-property: opacity, background-color;
1515
transition-timing-function: linear;
1616

1717
z-index: 999; //eruda=1000
1818

19+
background-color: white;
20+
21+
@include themeDark {
22+
background-color: black;
23+
}
24+
1925
&:not(.loaded) + * {
2026
display: none;
2127
}
@@ -26,9 +32,3 @@
2632
pointer-events: none;
2733
}
2834
}
29-
30-
body[data-theme='dark'] {
31-
.loading {
32-
background-color: black;
33-
}
34-
}

src/pages/DiffEditorPage.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
import React from 'react';
22
import PageContainer from '../components/pageContainer/PageContainer';
3-
import { DiffEditor } from '@monaco-editor/react';
4-
import useAppTheme from '../hooks/useAppTheme';
53
import { editor } from 'monaco-editor';
6-
import { Spin } from 'antd';
7-
8-
const loadingNode = <Spin size="large" />;
4+
import AppDiffEditor from '../components/appDiffEditor/AppDiffEditor';
95

106
const options: editor.IDiffEditorConstructionOptions = {
117
originalEditable: true
128
};
139

1410
const DiffEditorPage = () => {
15-
const { isDarkMode } = useAppTheme();
16-
1711
return (
1812
<PageContainer title="Diff Editor">
19-
<DiffEditor theme={isDarkMode ? 'vs-dark' : 'light'} options={options} loading={loadingNode} />
13+
<AppDiffEditor options={options} />
2014
</PageContainer>
2115
);
2216
};

src/pages/codeFormatterPage/CodeFormatterPage.tsx

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import React, { FunctionComponent, useCallback, useRef, useState } from 'react';
22
import PageContainer from '../../components/pageContainer/PageContainer';
3-
import useAppTheme from '../../hooks/useAppTheme';
4-
import Editor, { OnMount } from '@monaco-editor/react';
5-
import { Button, Col, Row, Select, Spin } from 'antd';
3+
import { OnMount } from '@monaco-editor/react';
4+
import { Button, Col, Row, Select } from 'antd';
65
import styles from './CodeFormatterPage.module.scss';
7-
import classNames from 'classnames';
86
import MonacoLanguage, { monacoLanguages } from '../../types/MonacoLanguage';
97
import { useLocalstorageState } from 'rooks';
108
import { editor, languages } from 'monaco-editor';
119
import CopyButton from '../../components/copyButton/CopyButton';
1210
import formatCode from '../../utils/formatCode';
11+
import AppEditor from '../../components/appEditor/AppEditor';
1312

1413
// interface FormattedLanguage {
1514
// prettierParser: prettier.BuiltInParserName,
@@ -45,15 +44,11 @@ import formatCode from '../../utils/formatCode';
4544
//
4645
// window.prettier = prettier;
4746

48-
const loadingNode = <Spin size="large" />;
49-
5047
const monacoOptions: editor.IStandaloneEditorConstructionOptions = {
5148
formatOnPaste: true
5249
};
5350

5451
const CodeFormatterPage: FunctionComponent = () => {
55-
const { isDarkMode } = useAppTheme();
56-
5752
const [selectedLanguage, setSelectedLanguage] = useLocalstorageState<MonacoLanguage>(
5853
'mrgrd56:code-formatter/selectedLanguage',
5954
'typescript'
@@ -62,10 +57,6 @@ const CodeFormatterPage: FunctionComponent = () => {
6257

6358
const monacoEditorRef = useRef<editor.IStandaloneCodeEditor>();
6459

65-
const handleCodeChange = (value: string | undefined) => {
66-
setCode(value ?? '');
67-
};
68-
6960
const handleMonacoMount = useCallback<OnMount>((editor, monaco) => {
7061
monacoEditorRef.current = editor;
7162

@@ -108,15 +99,13 @@ const CodeFormatterPage: FunctionComponent = () => {
10899
<CopyButton value={code} type="default" />
109100
</Row>
110101
</Col>
111-
<Editor
112-
theme={isDarkMode ? 'vs-dark' : 'light'}
113-
className={classNames('app-monaco-editor', styles.editor)}
102+
<AppEditor
103+
className={styles.editor}
114104
language={selectedLanguage}
115105
value={code}
116-
onChange={handleCodeChange}
106+
onChange={setCode}
117107
options={monacoOptions}
118108
onMount={handleMonacoMount}
119-
loading={loadingNode}
120109
/>
121110
</div>
122111
</PageContainer>
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import '../../styles/main';
2+
13
.outputModeComboBox {
24
width: 100px;
35
}
@@ -7,13 +9,11 @@
79

810
border: 1px solid #d9d9d9;
911

10-
& * {
11-
transition: none !important;
12+
@include themeDark {
13+
border-color: rgb(67, 67, 67);
1214
}
13-
}
1415

15-
body[data-theme='dark'] {
16-
.codeEditor {
17-
border-color: rgb(67, 67, 67);
16+
& * {
17+
transition: none !important;
1818
}
1919
}

0 commit comments

Comments
 (0)