Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/pyconkr/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<meta name="robots" content="index, follow" />

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

<title>PyCon Korea 2025</title>
</head>
Expand Down
4 changes: 4 additions & 0 deletions apps/pyconkr/src/components/layout/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ const HeaderContainer = styled.header`
justify-content: space-between;
align-items: center;
position: relative;

ul {
list-style: none;
}
`;

const HeaderLogo = styled.div`
Expand Down
2 changes: 1 addition & 1 deletion apps/pyconkr/src/components/pages/test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ShopTestPage } from "../../debug/page/shop_test";
type SelectedTabType = "shop" | "mdi";

export const Test: React.FC = () => {
const [selectedTab, setSelectedTab] = React.useState<SelectedTabType>("shop");
const [selectedTab, setSelectedTab] = React.useState<SelectedTabType>("mdi");

return (
<Box>
Expand Down
181 changes: 95 additions & 86 deletions apps/pyconkr/src/debug/page/mdi_test.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,105 @@
import styled from "@emotion/styled";
import { evaluate } from "@mdx-js/mdx";
import { MDXProvider } from "@mdx-js/react";
import {
Box,
Button,
Card,
CardContent,
Stack,
TextField,
Typography,
} from "@mui/material";
import React, { useState } from "react";
import * as runtime from "react/jsx-runtime";

// styled 컴포넌트 방식
const StyledCard = styled(Card)`
transition: transform 0.2s;
&:hover {
transform: translateY(-4px);
}
`;

const StyledCardContent = styled(CardContent)`
animation: fadeIn 0.5s ease-in;
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
`;
import React from "react";

import { Box, Button, Card, CardContent, TextField, Typography } from "@mui/material";

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

const LOCAL_STEORAGE_KEY = "mdi_test_input";
const MDX_TEST_STRING = `\
MDX 간단 사용 설명서

긴 가로줄을 넣고 싶다면, \`---\`를 사용해주세요!

---

제목은 아래와 같이 표현해요.
# H1
## H2
### H3
#### H4
##### H5
###### H6

---

**굵은 글자는 이렇게**
*이탤릭(기울어진 글자)는 요렇게*
응용 표현으로 ***굵으면서 기울어진 글자는 요렇게***

[링크는 이렇게 사용하고요,](https://pycon.kr)
변수명과 같은 짧은 코드는 \`이렇게\` 표현해요!
\`\`\`
# 긴 코드는 이렇게 표현할 수 있어요.
import antigravity
\`\`\`

---

HTML 태그 중 일부를 사용할 수 있어요!

예를 들면 <sub>sub</sub> 태그나
위로 가는 <sup>sup</sup> 태그도 있고요,
밑줄도 <ins>표현할 수 있죠!</ins>

---

> 인용구는 이렇게 표현해요.
> 여러 줄을 표현할수도 있고요!

---

사진 첨부는 이렇게 해요!
![OctoCat](https://myoctocat.com/assets/images/base-octocat.svg)

만약 크기 조절을 하고 싶다면 HTML 태그도 가능해요!
<img width="150px" src="https://myoctocat.com/assets/images/base-octocat.svg" />

---

- 순번이 없는 목록은 이렇게 사용해요.
- 만약 하위 항목을 표현하고 싶으시다면
- 이렇게 앞에 공백 2개를 붙여주세요!

---

1. 순번이 있는 목록은 이렇게 사용해요.
2. 실수로 다음의 숫자를 잘못 적어도
1. 자동으로 제대로 3번으로 나와요!

---

{ /*
화면 상에는 노출되지 않는 주석은 이렇게 사용해요.
주의하실 점은, 서버에서 클라이언트로 페이지의 내용을 응답할때는 요 주석 데이터도 같이 보내지므로, 절때 민감한 내용을 주석에 담지는 말아주세요!
*/ }
`

const getMdxInputFromLocalStorage: () => string = () => {
const input = localStorage.getItem(LOCAL_STEORAGE_KEY);
return input ? input : "";
}

const setMdxInputToLocalStorage: (input: string) => string = (input) => {
localStorage.setItem(LOCAL_STEORAGE_KEY, input);
return input;
}

export const MdiTestPage: React.FC = () => {
const [mdxInput, setMdxInput] = useState("");
const [Content, setContent] = useState<React.ComponentType>(() => () => null);
const [count, setCount] = useState(0);

const handleInputChange = async (text: string) => {
setMdxInput(text);
try {
const { default: Content } = await evaluate(text, {
...runtime,
baseUrl: import.meta.url,
});
setContent(() => Content);
} catch (error) {
console.error("MDX 변환 오류:", error);
}
};
const inputRef = React.useRef<HTMLTextAreaElement>(null);
const [mdxInput, setMdxInput] = React.useState(getMdxInputFromLocalStorage());

return (
<Box sx={{ p: 3 }}>
<StyledCard sx={{ mb: 3 }}>
<StyledCardContent>
<Typography variant="h4" gutterBottom>
MUI 테스트
</Typography>
<Stack direction="row" spacing={2} sx={{ mb: 2 }}>
<Button variant="contained" onClick={() => setCount(count + 1)}>
카운트: {count}
</Button>
<Button variant="outlined" color="secondary">
세컨더리
</Button>
</Stack>
<TextField
fullWidth
label="테스트 입력"
variant="outlined"
sx={{ mb: 2 }}
/>
</StyledCardContent>
</StyledCard>

<Typography variant="h5" gutterBottom>
MDX 에디터
</Typography>
<TextField
multiline
fullWidth
minRows={4}
value={mdxInput}
onChange={(e) => handleInputChange(e.target.value)}
sx={{ mb: 2 }}
/>
<Typography variant="h5" gutterBottom>MDX 에디터</Typography>
<TextField inputRef={inputRef} defaultValue={mdxInput} multiline fullWidth minRows={4} sx={{ my: 2 }} />
<Button variant="contained" onClick={() => inputRef.current && setMdxInput(setMdxInputToLocalStorage(inputRef.current.value))}>변환</Button>
&nbsp;
<Button variant="contained" onClick={() => setMdxInput(MDX_TEST_STRING)}>테스트용 Help Text 로딩</Button>
<br />
<br />
<Card>
<CardContent>
<MDXProvider>
<Content />
</MDXProvider>
<Common.Components.MDXRenderer text={mdxInput} />
</CardContent>
</Card>
</Box>
Expand Down
3 changes: 2 additions & 1 deletion apps/pyconkr/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ const queryClient = new QueryClient({
});

const CommonOptions: Common.Contexts.ContextOptions = {
baseUrl: import.meta.env.VITE_API_BASE_URL,
debug: import.meta.env.MODE === "development",
baseUrl: '.',
};

const ShopOptions: Shop.Contexts.ContextOptions = {
Expand Down
28 changes: 5 additions & 23 deletions apps/pyconkr/src/styles/globalStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,6 @@ export const muiTheme = createTheme({
export const globalStyles = css`
@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css");

* {
margin: 0;
padding: 0;
box-sizing: border-box;

-webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
-o-user-drag: none;
user-drag: none;
}

html,
body {
font-family:
Expand Down Expand Up @@ -98,21 +86,15 @@ export const globalStyles = css`
word-break: keep-all;
overflow-wrap: break-all;

-webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
-o-user-drag: none;
user-drag: none;
}

a {
text-decoration: none;
color: inherit;
}

button {
border: none;
background: none;
cursor: pointer;
}

ul,
ol {
list-style: none;
}
`;
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
"@tanstack/react-query": "^5.76.1",
"astring": "^1.9.0",
"axios": "^1.9.0",
"github-markdown-css": "^5.8.1",
"globals": "^15.15.0",
"mui-mdx-components": "^0.5.0",
"notistack": "^3.0.2",
"react": "^19.1.0",
"react-dom": "^19.1.0",
Expand Down
50 changes: 50 additions & 0 deletions packages/common/src/components/error_handler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as React from "react";

import { Button, Typography } from "@mui/material";
import { Suspense } from "@suspensive/react";

import CommonContext from '../hooks/';

const DetailedErrorFallback: React.FC<{ error: Error, reset: () => void }> = ({ error, reset }) => {
const errorObject = Object.getOwnPropertyNames(error).reduce((acc, key) => ({ ...acc, [key]: (error as unknown as { [key: string]: unknown })[key] }), {});
return <>
<Typography variant="body2" color="error">error.message = {error.message}</Typography>
<details open>
<summary>오류 상세</summary>
<pre style={{
whiteSpace: "pre-wrap",
backgroundColor: "#f5f5f5",
padding: "1em",
borderRadius: "4px",
userSelect: "text",
}}>
<code>{JSON.stringify(errorObject, null, 2)}</code>
</pre>
</details>
<br />
<Button variant="outlined" onClick={reset}>다시 시도</Button>
</>;
};

const SimplifiedErrorFallback: React.FC<{ reset: () => void }> = ({ reset }) => {
return <>
<Typography variant="body2" color="error">
문제가 발생했습니다, 잠시 후 다시 시도해주세요.<br />
만약 문제가 계속 발생한다면, 파이콘 한국 준비 위원회에게 알려주세요!<br />
<br />
An error occurred, please try again later.<br />
If the problem persists, please let the PyCon Korea organizing committee know!
</Typography>
<br />
<Button variant="outlined" onClick={reset}>다시 시도 | Retry</Button>
</>;
}

export const ErrorFallback: React.FC<{ error: Error, reset: () => void }> = ({ error, reset }) => {
const InnerErrorFallback: React.FC<{ error: Error, reset: () => void }> = ({ error, reset }) => {
const { debug } = CommonContext.useCommonContext();
return debug ? <DetailedErrorFallback error={error} reset={reset} /> : <SimplifiedErrorFallback reset={reset} />;
}

return <Suspense fallback={<>로딩 중...</>}><InnerErrorFallback error={error} reset={reset} /></Suspense>
}
2 changes: 2 additions & 0 deletions packages/common/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { CommonContextProvider as CommonContextProviderComponent } from './common_context';
import { ErrorFallback as ErrorFallbackComponent } from './error_handler';
import { MDXRenderer as MDXRendererComponent } from "./mdx";
import { PythonKorea as PythonKoreaComponent } from './pythonkorea';

namespace Components {
export const CommonContextProvider = CommonContextProviderComponent;
export const MDXRenderer = MDXRendererComponent;
export const PythonKorea = PythonKoreaComponent;
export const ErrorFallback = ErrorFallbackComponent;
}

export default Components;
Loading