Skip to content

Commit f3a3cbf

Browse files
authored
Merge pull request #16 from pythonkr/feature/admin-editor
feat: `MDXEditor` 추가
2 parents 137f001 + 0e63368 commit f3a3cbf

File tree

9 files changed

+969
-49
lines changed

9 files changed

+969
-49
lines changed

apps/pyconkr/src/components/layout/index.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,17 @@ const LayoutContainer = styled.div`
5656
const MainContent = styled.main`
5757
flex: 1;
5858
59+
width: 100%;
60+
height: 100%;
61+
min-height: 100%;
5962
display: flex;
6063
flex-direction: column;
6164
justify-content: center;
6265
align-items: center;
66+
67+
> * {
68+
flex-grow: 1;
69+
}
6370
`;
6471

6572
export default function MainLayout() {
Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
11
import * as React from "react";
22

3-
import { Box, Button } from "@mui/material";
3+
import { Button, Stack } from "@mui/material";
44

55
import { BackendTestPage } from '../../debug/page/backend_test';
66
import { MdiTestPage } from "../../debug/page/mdi_test";
77
import { ShopTestPage } from "../../debug/page/shop_test";
88

9+
const LOCAL_STORAGE_KEY = "selectedTab";
910
type SelectedTabType = "shop" | "mdi" | "backend";
1011

12+
const getTabFromLocalStorage = (): SelectedTabType => localStorage.getItem(LOCAL_STORAGE_KEY) as SelectedTabType || "shop";
13+
14+
const setTabToLocalStorage = (tab: SelectedTabType) => {
15+
localStorage.setItem(LOCAL_STORAGE_KEY, tab);
16+
return tab;
17+
};
18+
19+
const TabList: { [key in SelectedTabType]: React.ReactNode } = {
20+
shop: <ShopTestPage />,
21+
mdi: <MdiTestPage />,
22+
backend: <BackendTestPage />,
23+
};
24+
1125
export const Test: React.FC = () => {
12-
const [selectedTab, setSelectedTab] = React.useState<SelectedTabType>("mdi");
13-
14-
return (
15-
<Box>
16-
<Button variant="contained" onClick={() => setSelectedTab("shop")}>
17-
Shop Test
18-
</Button>
19-
<Button variant="contained" onClick={() => setSelectedTab("mdi")}>
20-
MDI Test
21-
</Button>
22-
<Button variant="contained" onClick={() => setSelectedTab("backend")}>
23-
Backend Test
24-
</Button>
25-
{selectedTab === "shop" && <ShopTestPage />}
26-
{selectedTab === "mdi" && <MdiTestPage />}
27-
{selectedTab === "backend" && <BackendTestPage />}
28-
</Box>
29-
);
26+
const [selectedTab, setSelectedTab] = React.useState<SelectedTabType>(getTabFromLocalStorage());
27+
const selectTab = (tab: SelectedTabType) => setSelectedTab(setTabToLocalStorage(tab));
28+
const TabButton: React.FC<{ tab: SelectedTabType }> = ({ tab }) => <Button variant={selectedTab === tab ? "contained" : "outlined"} onClick={() => selectTab(tab)}>{tab} Test</Button>;
29+
30+
return <Stack>
31+
<Stack direction="row" spacing={2} sx={{ width: "100%", justifyContent: "center" }}>
32+
{Object.keys(TabList).map((tab) => <TabButton key={tab} tab={tab as SelectedTabType} />)}
33+
</Stack>
34+
{TabList[selectedTab]}
35+
</Stack>;
3036
};
Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,24 @@
11
import React from "react";
22

3-
import { Box, Button, Stack } from "@mui/material";
3+
import { Box, Stack } from "@mui/material";
44

5-
import { MDX_HELP_TEXT } from "@apps/pyconkr/consts/mdx_help_text";
65
import * as Common from "@frontend/common";
76

8-
const LOCAL_STEORAGE_KEY = "mdi_test_input";
9-
10-
const getMdxInputFromLocalStorage: () => string = () => {
11-
const input = localStorage.getItem(LOCAL_STEORAGE_KEY);
12-
return input ? input : "";
13-
}
14-
15-
const setMdxInputToLocalStorage: (input: string) => string = (input) => {
16-
localStorage.setItem(LOCAL_STEORAGE_KEY, input);
17-
return input;
18-
}
7+
const HalfWidthStyle: React.CSSProperties = { width: "50%", maxWidth: "50%" };
198

209
export const MdiTestPage: React.FC = () => {
2110
const inputRef = React.useRef<HTMLTextAreaElement>(null);
22-
const [state, setState] = React.useState<{ text: string, resetKey: number }>({
23-
text: getMdxInputFromLocalStorage(),
24-
resetKey: Math.random()
25-
});
26-
27-
const setMDXInput = (text: string) => setState({ text: setMdxInputToLocalStorage(text), resetKey: Math.random() });
11+
const [state, setState] = React.useState<{ text: string, resetKey: number }>({ text: "", resetKey: Math.random() });
12+
const setMDXInput = (text: string) => setState({ text, resetKey: Math.random() });
13+
const onLoad = (text: string) => {
14+
setState((prev) => ({ ...prev, text }));
15+
if (inputRef.current) inputRef.current.value = text;
16+
}
2817

2918
return (
30-
<Stack direction="row" spacing={2} sx={{ width: "100%", flexGrow: 1, p: 2 }}>
31-
<Stack direction="column" spacing={2} sx={{ width: "50%", maxWidth: "50%" }}>
32-
<textarea ref={inputRef} defaultValue={state.text} style={{ flexGrow: 1 }} />
33-
<Stack direction="column" spacing={2} sx={{ mb: 2 }}>
34-
<Button variant="contained" sx={{ flexGrow: 1 }} onClick={() => inputRef.current && setMDXInput(inputRef.current.value)}>변환</Button>
35-
<Button variant="contained" sx={{ flexGrow: 1 }} onClick={() => setMDXInput(MDX_HELP_TEXT)}>Help Text 로딩</Button>
36-
</Stack>
37-
</Stack>
38-
<Box sx={{ width: "50%", maxWidth: "50%", overflowY: "scroll" }}>
39-
<Common.Components.MDXRenderer {...state} />
40-
</Box>
19+
<Stack direction="row" spacing={2} sx={{ width: "100%", height: "100%", minHeight: "100%", maxHeight: "100%", flexGrow: 1, py: 2 }}>
20+
<Box sx={HalfWidthStyle}><Common.Components.MDXEditor inputRef={inputRef} defaultValue={state.text} onLoad={onLoad} onSave={setMDXInput} ctrlSMode="save" /></Box>
21+
<Box sx={HalfWidthStyle}><Common.Components.MDXRenderer {...state} /></Box>
4122
</Stack>
4223
);
4324
};

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
"@mui/material": "^7.1.0",
3030
"@suspensive/react": "^3.2.0",
3131
"@tanstack/react-query": "^5.76.1",
32+
"@uiw/react-md-editor": "^4.0.7",
3233
"astring": "^1.9.0",
3334
"axios": "^1.9.0",
35+
"crypto-js": "^4.2.0",
3436
"globals": "^15.15.0",
3537
"mui-mdx-components": "^0.5.0",
3638
"notistack": "^3.0.2",
@@ -46,6 +48,7 @@
4648
"@rollup/plugin-node-resolve": "^16.0.1",
4749
"@rollup/plugin-replace": "^6.0.2",
4850
"@tanstack/react-query-devtools": "^5.76.1",
51+
"@types/crypto-js": "^4.2.2",
4952
"@types/mdx": "^2.0.13",
5053
"@types/node": "^22.15.18",
5154
"@types/react": "^19.1.4",
@@ -64,6 +67,7 @@
6467
"iamport-typings": "^1.4.0",
6568
"prettier": "^3.5.3",
6669
"rollup": "^4.40.2",
70+
"rollup-plugin-import-css": "^3.5.8",
6771
"rollup-plugin-typescript2": "^0.36.0",
6872
"typescript": "~5.7.3",
6973
"typescript-eslint": "^8.32.1",

packages/common/rollup.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import commonjs from "@rollup/plugin-commonjs";
22
import json from "@rollup/plugin-json";
33
import resolve, { nodeResolve } from "@rollup/plugin-node-resolve";
4+
import css from "rollup-plugin-import-css";
45
import typescript from "rollup-plugin-typescript2";
56

67
export default {
@@ -41,6 +42,7 @@ export default {
4142
"@tanstack/react-query",
4243
],
4344
plugins: [
45+
css(),
4446
json(),
4547
typescript({ tsconfig: "./tsconfig.json" }),
4648
resolve(),

packages/common/src/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import {
66
} from './dynamic_route';
77
import { ErrorFallback as ErrorFallbackComponent } from './error_handler';
88
import { MDXRenderer as MDXRendererComponent } from "./mdx";
9+
import { MDXEditor as MDXEditorComponent } from './mdx_editor';
910
import { PythonKorea as PythonKoreaComponent } from './pythonkorea';
1011

1112
namespace Components {
1213
export const CommonContextProvider = CommonContextProviderComponent;
1314
export const RouteRenderer = RouteRendererComponent;
1415
export const PageRenderer = PageRendererComponent;
1516
export const PageIdParamRenderer = PageIdParamRendererComponent;
17+
export const MDXEditor = MDXEditorComponent;
1618
export const MDXRenderer = MDXRendererComponent;
1719
export const PythonKorea = PythonKoreaComponent;
1820
export const ErrorFallback = ErrorFallbackComponent;

0 commit comments

Comments
 (0)