Skip to content

Commit

Permalink
에디터 기능 구현
Browse files Browse the repository at this point in the history
* feat: 에디터 및 페이지 추가

* chore: MDX 에디터 라이브러리 추가

* style: 에디터 내 마크다운 스타일을 위한 reset style 수정

* feat: 페이지 라우트 추가

* feat: 질문 모델 생성중

* feat: 에디터 추가

* fix: 질문글 폴더 구조 변경
  • Loading branch information
anveloper authored Apr 6, 2024
1 parent 4781a65 commit a0a0970
Show file tree
Hide file tree
Showing 14 changed files with 2,914 additions and 88 deletions.
2,756 changes: 2,671 additions & 85 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"dependencies": {
"@hookform/resolvers": "^3.3.4",
"@mdxeditor/editor": "^2.19.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-toast": "^1.1.5",
"@suspensive/react": "^1.26.7",
Expand Down
52 changes: 49 additions & 3 deletions src/app/provider/global-styled-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,55 @@
import { createGlobalStyle } from "styled-components";
import reset from "styled-reset";

export const GlobalStyle = createGlobalStyle`
${reset}
html, body, div, span, applet, object, iframe,
p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
h1, h2, h3, h4, h5, h6 {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
* {
box-sizing: border-box;
Expand All @@ -13,7 +60,6 @@ export const GlobalStyle = createGlobalStyle`
color: ${(props) => props.theme.colors.white};
}
`;

export const GlobalStyleProvider = () => {
return (
<>
Expand Down
9 changes: 9 additions & 0 deletions src/app/router/router.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createBrowserRouter } from "react-router-dom";

import { QuestionPage } from "~/pages/question";
import { RootPage } from "~/pages/root";

import { ROUTE } from "~/shared/route";
Expand All @@ -9,4 +10,12 @@ export const router = createBrowserRouter([
path: ROUTE.root,
element: <RootPage />,
},
{
path: ROUTE.question,
element: <QuestionPage />,
},
{
path: ROUTE.questionWrite,
element: <QuestionPage />,
},
]);
13 changes: 13 additions & 0 deletions src/entities/question/model/question.atom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { atom } from "recoil";

import { QuestionType } from "./question.type";

export const questionAtom = atom<QuestionType>({
key: "question",
default: {
title: "",
language: "",
purpose: "",
content: "",
},
});
15 changes: 15 additions & 0 deletions src/entities/question/model/question.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export type QuestionType = {
title: string;
language?: string;
purpose: string;
content: string;
};

export type RegisteredQuestionType = QuestionType & {
id: number;
createdAt: Date;
likeCount: number;
viewCount: number;
categories: string[];
comments: string[];
};
Empty file added src/features/question/index.ts
Empty file.
2 changes: 2 additions & 0 deletions src/pages/question/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./question.page";
export * from "./question-write.page";
5 changes: 5 additions & 0 deletions src/pages/question/question-write.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const QuestionWritePage = () => {
return <div>QuestionWritePage</div>;
};

export default QuestionWritePage;
23 changes: 23 additions & 0 deletions src/pages/question/question.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useRef, useState } from "react";

import { MDXEditorMethods } from "@mdxeditor/editor";

import Editor from "~/shared/common-ui/editor/editor";

export const QuestionPage = () => {
const ref = useRef<MDXEditorMethods>(null);
const [markdown, setMarkdown] = useState<string>("");
const [content, setContent] = useState<string>("");
const handleButton = () => {
if (ref.current) {
setContent(ref.current.getMarkdown());
}
};
return (
<div>
<Editor ref={ref} onChange={(s) => setMarkdown(s)} markdown={markdown} />
<button onClick={handleButton}>{"저장"}</button>
{content}
</div>
);
};
121 changes: 121 additions & 0 deletions src/shared/common-ui/editor/editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react";

import {
BoldItalicUnderlineToggles,
ChangeCodeMirrorLanguage,
ConditionalContents,
InsertCodeBlock,
InsertSandpack,
InsertTable,
MDXEditor,
SandpackConfig,
ShowSandpackInfo,
UndoRedo,
codeBlockPlugin,
codeMirrorPlugin,
headingsPlugin,
linkPlugin,
listsPlugin,
markdownShortcutPlugin,
quotePlugin,
sandpackPlugin,
tablePlugin,
thematicBreakPlugin,
toolbarPlugin,
} from "@mdxeditor/editor";
import "@mdxeditor/editor/style.css";

const defaultSnippetContent = `
const App = () => {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
export default App;
`.trim();

const simpleSandpackConfig: SandpackConfig = {
defaultPreset: "react",
presets: [
{
label: "React",
name: "react",
meta: "live react",
sandpackTemplate: "react",
sandpackTheme: "light",
snippetFileName: "/App.js",
snippetLanguage: "jsx",
initialSnippetContent: defaultSnippetContent,
},
],
};

/*
props
ref
현재 페이지에 보여질 상태 //
변경할 setter함수
*/

type EditorProps = {
markdown: string;
onChange?: (str: string) => void;
};

const Editor = forwardRef<ElementRef<typeof MDXEditor>, ComponentPropsWithoutRef<typeof MDXEditor> & EditorProps>(
({ markdown, onChange }, ref) => {
return (
<MDXEditor
ref={ref}
markdown={markdown}
onChange={onChange}
plugins={[
toolbarPlugin({
toolbarContents: () => (
<>
<UndoRedo />
<BoldItalicUnderlineToggles />
<InsertTable />
<ConditionalContents
options={[
{
when: (editor) => editor?.editorType === "codeblock",
contents: () => <ChangeCodeMirrorLanguage />,
},
{ when: (editor) => editor?.editorType === "sandpack", contents: () => <ShowSandpackInfo /> },
{
fallback: () => (
<>
<InsertCodeBlock />
<InsertSandpack />
</>
),
},
]}
/>
</>
),
}),
codeBlockPlugin({ defaultCodeBlockLanguage: "js" }),
sandpackPlugin({ sandpackConfig: simpleSandpackConfig }),
codeMirrorPlugin({ codeBlockLanguages: { js: "JavaScript", css: "CSS", java: "Java" } }),
headingsPlugin(),
listsPlugin(),
tablePlugin(),
linkPlugin(),
quotePlugin(),
markdownShortcutPlugin(),
thematicBreakPlugin(),
]}
/>
);
}
);

Editor.displayName = "editor";

export default Editor;
1 change: 1 addition & 0 deletions src/shared/common-ui/editor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./editor";
1 change: 1 addition & 0 deletions src/shared/common-ui/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./header";
export * from "./error";
export * from "./loading";
export * from "./editor";
3 changes: 3 additions & 0 deletions src/shared/route/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export const ROUTE = {
root: "/",
question: "/question",
questionWrite: "/question/write",
questionDetail: "/question/:id",
//만약 동적인 파라미터가 필요한경우
// somethingDynamicRoute: (param:string) => `/page/${param}`
};

0 comments on commit a0a0970

Please sign in to comment.