Skip to content

Commit e0782f8

Browse files
authored
Merge pull request #15 from pythonkr/feature/admin-editor
2 parents cbb9de8 + df04d5c commit e0782f8

File tree

19 files changed

+404
-241
lines changed

19 files changed

+404
-241
lines changed

apps/pyconkr/index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
<meta name="robots" content="index, follow" />
4040

4141
<script src="https://cdn.iamport.kr/v1/iamport.js"></script>
42-
<link rel="stylesheet" href="github-markdown.css">
4342

4443
<title>PyCon Korea 2025</title>
4544
</head>

apps/pyconkr/src/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export const App: React.FC = () => {
1313
<Routes>
1414
<Route element={<MainLayout />}>
1515
{ IS_DEBUG_ENV && <Route path="/debug" element={<Test />} /> }
16-
<Route path="*" element={<Common.Components.DynamicRoutePage />} />
16+
<Route path="/pages/:id" element={<Common.Components.PageIdParamRenderer />} />
17+
<Route path="*" element={<Common.Components.RouteRenderer />} />
1718
</Route>
1819
</Routes>
1920
</BrowserRouter>
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// 후대의 개발자님께 : 컴포넌트 맨 첫글자가 대문자로 시작하지 않으면 JSX 컴포넌트가 아니라 일반 HTML 태그로 인식합니다. 제발 대문자로 시작해주세요.
2+
import * as mui from "@mui/material";
3+
import type { MDXComponents } from "mdx/types.js";
4+
5+
import * as Shop from "@frontend/shop";
6+
7+
const MUIMDXComponents: MDXComponents = {
8+
Mui__material__Accordion: mui.Accordion,
9+
Mui__material__AccordionActions: mui.AccordionActions,
10+
Mui__material__AccordionDetails: mui.AccordionDetails,
11+
Mui__material__AccordionSummary: mui.AccordionSummary,
12+
Mui__material__Alert: mui.Alert,
13+
Mui__material__AlertTitle: mui.AlertTitle,
14+
Mui__material__AppBar: mui.AppBar,
15+
Mui__material__Autocomplete: mui.Autocomplete,
16+
Mui__material__Avatar: mui.Avatar,
17+
Mui__material__AvatarGroup: mui.AvatarGroup,
18+
Mui__material__Backdrop: mui.Backdrop,
19+
Mui__material__Badge: mui.Badge,
20+
Mui__material__BottomNavigation: mui.BottomNavigation,
21+
Mui__material__BottomNavigationAction: mui.BottomNavigationAction,
22+
Mui__material__Box: mui.Box,
23+
Mui__material__Breadcrumbs: mui.Breadcrumbs,
24+
Mui__material__Button: mui.Button,
25+
Mui__material__ButtonBase: mui.ButtonBase,
26+
Mui__material__ButtonGroup: mui.ButtonGroup,
27+
Mui__material__Card: mui.Card,
28+
Mui__material__CardActionArea: mui.CardActionArea,
29+
Mui__material__CardActions: mui.CardActions,
30+
Mui__material__CardContent: mui.CardContent,
31+
Mui__material__CardHeader: mui.CardHeader,
32+
Mui__material__CardMedia: mui.CardMedia,
33+
Mui__material__Checkbox: mui.Checkbox,
34+
Mui__material__Chip: mui.Chip,
35+
Mui__material__CircularProgress: mui.CircularProgress,
36+
Mui__material__Collapse: mui.Collapse,
37+
Mui__material__Container: mui.Container,
38+
Mui__material__Dialog: mui.Dialog,
39+
Mui__material__DialogActions: mui.DialogActions,
40+
Mui__material__DialogContent: mui.DialogContent,
41+
Mui__material__DialogContentText: mui.DialogContentText,
42+
Mui__material__DialogTitle: mui.DialogTitle,
43+
Mui__material__Divider: mui.Divider,
44+
Mui__material__Drawer: mui.Drawer,
45+
Mui__material__Fab: mui.Fab,
46+
Mui__material__Fade: mui.Fade,
47+
Mui__material__FilledInput: mui.FilledInput,
48+
Mui__material__FormControl: mui.FormControl,
49+
Mui__material__FormControlLabel: mui.FormControlLabel,
50+
Mui__material__FormGroup: mui.FormGroup,
51+
Mui__material__FormHelperText: mui.FormHelperText,
52+
Mui__material__FormLabel: mui.FormLabel,
53+
Mui__material__Grid: mui.Grid,
54+
Mui__material__Grow: mui.Grow,
55+
Mui__material__Icon: mui.Icon,
56+
Mui__material__IconButton: mui.IconButton,
57+
Mui__material__ImageList: mui.ImageList,
58+
Mui__material__ImageListItem: mui.ImageListItem,
59+
Mui__material__ImageListItemBar: mui.ImageListItemBar,
60+
Mui__material__Input: mui.Input,
61+
Mui__material__InputAdornment: mui.InputAdornment,
62+
Mui__material__InputBase: mui.InputBase,
63+
Mui__material__InputLabel: mui.InputLabel,
64+
Mui__material__LinearProgress: mui.LinearProgress,
65+
Mui__material__Link: mui.Link,
66+
Mui__material__List: mui.List,
67+
Mui__material__ListItem: mui.ListItem,
68+
Mui__material__ListItemAvatar: mui.ListItemAvatar,
69+
Mui__material__ListItemButton: mui.ListItemButton,
70+
Mui__material__ListItemIcon: mui.ListItemIcon,
71+
Mui__material__ListItemSecondaryAction: mui.ListItemSecondaryAction,
72+
Mui__material__ListItemText: mui.ListItemText,
73+
Mui__material__ListSubheader: mui.ListSubheader,
74+
Mui__material__Menu: mui.Menu,
75+
Mui__material__MenuItem: mui.MenuItem,
76+
Mui__material__MenuList: mui.MenuList,
77+
Mui__material__MobileStepper: mui.MobileStepper,
78+
Mui__material__Modal: mui.Modal,
79+
Mui__material__NativeSelect: mui.NativeSelect,
80+
Mui__material__NoSsr: mui.NoSsr,
81+
Mui__material__OutlinedInput: mui.OutlinedInput,
82+
Mui__material__Pagination: mui.Pagination,
83+
Mui__material__PaginationItem: mui.PaginationItem,
84+
Mui__material__Paper: mui.Paper,
85+
Mui__material__Popover: mui.Popover,
86+
Mui__material__Popper: mui.Popper,
87+
Mui__material__Portal: mui.Portal,
88+
Mui__material__Radio: mui.Radio,
89+
Mui__material__RadioGroup: mui.RadioGroup,
90+
Mui__material__Rating: mui.Rating,
91+
Mui__material__Select: mui.Select,
92+
Mui__material__Skeleton: mui.Skeleton,
93+
Mui__material__Slide: mui.Slide,
94+
Mui__material__Slider: mui.Slider,
95+
Mui__material__Snackbar: mui.Snackbar,
96+
Mui__material__SnackbarContent: mui.SnackbarContent,
97+
Mui__material__SpeedDial: mui.SpeedDial,
98+
Mui__material__SpeedDialAction: mui.SpeedDialAction,
99+
Mui__material__SpeedDialIcon: mui.SpeedDialIcon,
100+
Mui__material__Stack: mui.Stack,
101+
Mui__material__Step: mui.Step,
102+
Mui__material__StepButton: mui.StepButton,
103+
Mui__material__StepConnector: mui.StepConnector,
104+
Mui__material__StepContent: mui.StepContent,
105+
Mui__material__StepIcon: mui.StepIcon,
106+
Mui__material__StepLabel: mui.StepLabel,
107+
Mui__material__Stepper: mui.Stepper,
108+
Mui__material__SvgIcon: mui.SvgIcon,
109+
Mui__material__SwipeableDrawer: mui.SwipeableDrawer,
110+
Mui__material__Switch: mui.Switch,
111+
Mui__material__Tab: mui.Tab,
112+
Mui__material__Table: mui.Table,
113+
Mui__material__TableBody: mui.TableBody,
114+
Mui__material__TableCell: mui.TableCell,
115+
Mui__material__TableContainer: mui.TableContainer,
116+
Mui__material__TableFooter: mui.TableFooter,
117+
Mui__material__TableHead: mui.TableHead,
118+
Mui__material__TablePagination: mui.TablePagination,
119+
Mui__material__TableRow: mui.TableRow,
120+
Mui__material__TableSortLabel: mui.TableSortLabel,
121+
Mui__material__Tabs: mui.Tabs,
122+
Mui__material__TabScrollButton: mui.TabScrollButton,
123+
Mui__material__TextField: mui.TextField,
124+
Mui__material__TextareaAutosize: mui.TextareaAutosize,
125+
Mui__material__ToggleButton: mui.ToggleButton,
126+
Mui__material__ToggleButtonGroup: mui.ToggleButtonGroup,
127+
Mui__material__Toolbar: mui.Toolbar,
128+
Mui__material__Tooltip: mui.Tooltip,
129+
Mui__material__Typography: mui.Typography,
130+
Mui__material__Zoom: mui.Zoom,
131+
};
132+
133+
const PythonKRShopMDXComponents: MDXComponents = {
134+
Shop__Common__PriceDisplay: Shop.Components.Common.PriceDisplay,
135+
Shop__Common__SignInGuard: Shop.Components.Common.SignInGuard,
136+
Shop__Common__ContextProvider: Shop.Components.Common.ShopContextProvider,
137+
Shop__Feature__CartStatus: Shop.Components.Features.CartStatus,
138+
Shop__Feature__ProductList: Shop.Components.Features.ProductList,
139+
Shop__Feature__OrderList: Shop.Components.Features.OrderList,
140+
Shop__Feature__UserInfo: Shop.Components.Features.UserInfo,
141+
};
142+
143+
export const PyConKRMDXComponents = {
144+
...MUIMDXComponents,
145+
...PythonKRShopMDXComponents,
146+
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export const MDX_HELP_TEXT = `\
2+
MDX 간단 사용 설명서
3+
4+
긴 가로줄을 넣고 싶다면, \`---\`를 사용해주세요!
5+
6+
---
7+
8+
제목은 아래와 같이 표현해요.
9+
# H1
10+
## H2
11+
### H3
12+
#### H4
13+
##### H5
14+
###### H6
15+
16+
---
17+
18+
**굵은 글자는 이렇게**
19+
*이탤릭(기울어진 글자)는 요렇게*
20+
응용 표현으로 ***굵으면서 기울어진 글자는 요렇게***
21+
22+
[링크는 이렇게 사용하고요,](https://pycon.kr)
23+
변수명과 같은 짧은 코드는 \`이렇게\` 표현해요!
24+
\`\`\`
25+
# 긴 코드는 이렇게 표현할 수 있어요.
26+
import antigravity
27+
\`\`\`
28+
29+
---
30+
31+
HTML 태그 중 일부를 사용할 수 있어요!
32+
33+
예를 들면 <sub>sub</sub> 태그나
34+
위로 가는 <sup>sup</sup> 태그도 있고요,
35+
밑줄도 <ins>표현할 수 있죠!</ins>
36+
37+
---
38+
39+
> 인용구는 이렇게 표현해요.
40+
> 여러 줄을 표현할수도 있고요!
41+
42+
---
43+
44+
사진 첨부는 이렇게 해요!
45+
![OctoCat](https://myoctocat.com/assets/images/base-octocat.svg)
46+
47+
만약 크기 조절을 하고 싶다면 HTML 태그도 가능해요!
48+
<img width="150px" src="https://myoctocat.com/assets/images/base-octocat.svg" />
49+
50+
---
51+
52+
- 순번이 없는 목록은 이렇게 사용해요.
53+
- 만약 하위 항목을 표현하고 싶으시다면
54+
- 이렇게 앞에 공백 2개를 붙여주세요!
55+
56+
---
57+
58+
1. 순번이 있는 목록은 이렇게 사용해요.
59+
2. 실수로 다음의 숫자를 잘못 적어도
60+
1. 자동으로 제대로 3번으로 나와요!
61+
62+
---
63+
64+
{ /*
65+
화면 상에는 노출되지 않는 주석은 이렇게 사용해요.
66+
주의하실 점은, 서버에서 클라이언트로 페이지의 내용을 응답할때는 요 주석 데이터도 같이 보내지므로, 절때 민감한 내용을 주석에 담지는 말아주세요!
67+
*/ }
68+
`
Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,35 @@
11
import * as React from "react";
2-
import * as R from "remeda";
32

4-
import { Button, CircularProgress, MenuItem, Select, Stack } from '@mui/material';
5-
import { ErrorBoundary, Suspense } from '@suspensive/react';
3+
import { CircularProgress, MenuItem, Select, SelectProps, Stack } from '@mui/material';
4+
import { Suspense } from '@suspensive/react';
65

76
import * as Common from "@frontend/common";
87

9-
const SiteMapRenderer: React.FC = () => {
10-
const { data } = Common.Hooks.BackendAPI.useFlattenSiteMapQuery();
11-
return <pre style={{ whiteSpace: "pre-wrap" }}>{JSON.stringify(Common.Utils.buildNestedSiteMap(data), null, 2)}</pre>
12-
};
13-
14-
const PageIdSelector: React.FC<{ inputRef: React.Ref<HTMLSelectElement> }> = ({ inputRef }) => {
15-
const { data } = Common.Hooks.BackendAPI.useFlattenSiteMapQuery();
16-
17-
return <Select inputRef={inputRef}>
18-
{data.map((siteMap) => <MenuItem key={siteMap.id} value={siteMap.page}>{siteMap.name}</MenuItem>)}
19-
</Select>
20-
}
21-
22-
const SuspenseWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
23-
<ErrorBoundary fallback={Common.Components.ErrorFallback}>
24-
<Suspense fallback={<CircularProgress />}>
25-
{children}
26-
</Suspense>
27-
</ErrorBoundary>
28-
)
8+
const SiteMapRenderer: React.FC = Suspense.with(
9+
{ fallback: <CircularProgress /> },
10+
() => {
11+
const backendClient = Common.Hooks.BackendAPI.useBackendClient();
12+
const { data } = Common.Hooks.BackendAPI.useFlattenSiteMapQuery(backendClient);
13+
return <pre style={{ whiteSpace: "pre-wrap" }}>{JSON.stringify(Common.Utils.buildNestedSiteMap(data), null, 2)}</pre>
14+
}
15+
);
16+
17+
const PageIdSelector: React.FC<{ onChange: SelectProps['onChange'] }> = Suspense.with(
18+
{ fallback: <CircularProgress /> },
19+
({ onChange }) => {
20+
const backendClient = Common.Hooks.BackendAPI.useBackendClient();
21+
const { data } = Common.Hooks.BackendAPI.useFlattenSiteMapQuery(backendClient);
22+
23+
return <Select onChange={onChange}>{data.map((s) => <MenuItem key={s.id} value={s.page}>{s.name}</MenuItem>)}</Select>
24+
}
25+
);
2926

3027
export const BackendTestPage: React.FC = () => {
31-
const inputRef = React.useRef<HTMLSelectElement>(null);
3228
const [pageId, setPageId] = React.useState<string | null>(null);
3329

34-
return <Stack>
35-
<br />
36-
<SuspenseWrapper><SiteMapRenderer /></SuspenseWrapper>
37-
<br />
38-
<SuspenseWrapper><PageIdSelector inputRef={inputRef} /></SuspenseWrapper>
39-
<br />
40-
<Button variant="outlined" onClick={() => setPageId(inputRef.current?.value ?? null)}>페이지 렌더링</Button>
41-
<br />
42-
{R.isString(pageId) ? <SuspenseWrapper><Common.Components.PageRenderer id={pageId} /></SuspenseWrapper> : <>페이지를 선택해주세요.</>}
30+
return <Stack spacing={2}>
31+
<SiteMapRenderer />
32+
<PageIdSelector onChange={(e) => setPageId(e.target.value as string)} />
33+
{Common.Utils.isFilledString(pageId) ? <Common.Components.PageRenderer id={pageId} /> : <>페이지를 선택해주세요.</>}
4334
</Stack>
44-
}
35+
};

0 commit comments

Comments
 (0)