Skip to content

Commit

Permalink
마크다운 컴포넌트 분리 및 UI 정리 (#35)
Browse files Browse the repository at this point in the history
* refactor: 마크다운 컴포넌트 분리

* feat: 선택지에 마크다운 적용 및 인라인 코드블럭 적용 안되는 문제 수정

* style: 마크다운 내 요소의 margin 조정

* feat: UI 정리

* style: 인라인 코드 블럭 텍스트 색상 변경

* style: 인라인 코드 블럭 양 끝 따옴표 제거

* style: 인라인 코드 블럭 px 조절
  • Loading branch information
bbearcookie authored Dec 23, 2023
1 parent 2730c7e commit fa2e1d6
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 53 deletions.
12 changes: 12 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@
}
}

.markdown {
@apply prose;
}

.markdown * {
@apply my-2;
}

.markdown code::before, .markdown code::after {
display: none;
}

#background {
@apply fixed h-full w-full bg-slate-50 lg:bg-gradient-to-r lg:from-sky-400 lg:to-indigo-400;
}
Expand Down
28 changes: 17 additions & 11 deletions app/quizzes/[id]/choice-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useGetChoicesOfQuiz, useSubmitQuiz } from '@/services/quiz/hooks';
import { useRouter } from 'next/navigation';
import Button from '@/components/common/buttons/button';
import LoadingSpinner from '@/components/common/loading-spinner/loading-spinner';
import MarkDown from '@/components/ui/markdown';

export default function ChoiceForm({ quizId }: { quizId: number }) {
const [errorMessage, setErrorMessage] = useState('');
Expand Down Expand Up @@ -41,17 +42,22 @@ export default function ChoiceForm({ quizId }: { quizId: number }) {

return (
<form onSubmit={handleSubmit}>
{choices?.map((choice) => (
<label className="flex gap-2" key={choice.id} htmlFor={`${choice.id}`}>
<input
id={`${choice.id}`}
value={`${choice.id}`}
type="radio"
name="choice"
onChange={() => setErrorMessage('')}
/>
<p className="my-1.5">{choice.description}</p>
</label>
{choices?.map((choice, idx) => (
<div className="flex flex-col gap-4" key={choice.id}>
<label className="mt-4 flex gap-2" htmlFor={`${choice.id}`}>
<input
id={`${choice.id}`}
value={`${choice.id}`}
type="radio"
name="choice"
onChange={() => setErrorMessage('')}
/>
<h2 className="grow font-bold">{idx + 1}번 선택지</h2>
</label>
<MarkDown wrapLine={true} wrapLongLines={true}>
{choice.description}
</MarkDown>
</div>
))}
{errorMessage && <p className="my-2 text-red-500">{errorMessage}</p>}
<Button
Expand Down
57 changes: 15 additions & 42 deletions app/quizzes/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import {
QueryClient,
dehydrate,
} from '@tanstack/react-query';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { dracula } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import MarkDown from '@/components/ui/markdown';
import Link from 'next/link';
import ChoiceForm from './choice-form';
import quizOptions from '@/services/quiz/options';
Expand All @@ -23,46 +21,21 @@ export default async function Page({ params }: { params: { id: string } }) {
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<section className="mb-10">
<h2 className="text-2xl font-bold">출제자</h2>
{/* TODO: 추후 상세 유저 페이지 라우팅 경로로 변경하기 */}
<Link className="underline" href={`/users/${quiz?.users?.id}`}>
{quiz?.users?.name}
</Link>
</section>

<section className="mb-10">
<h2 className="text-2xl font-bold">문제</h2>
<Markdown
className="prose"
remarkPlugins={[remarkGfm]}
components={{
code({ className, children, ...rest }) {
const match = /language-(\w+)/.exec(className || '');
return match ? (
<SyntaxHighlighter
{...rest}
PreTag="div"
language={match[1]}
style={dracula}
ref={null}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code {...rest} className={className}>
{children}
</code>
);
},
}}
>
{quiz?.description}
</Markdown>
</section>

<section className="mb-10">
<ChoiceForm quizId={quizId} />
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold">
{quiz?.id} {quiz?.title}
</h1>
<p>
By{' '}
<Link className="underline" href={`/users/${quiz?.users?.id}`}>
{/* TODO: 추후 상세 유저 페이지 라우팅 경로로 변경하기 */}
{quiz?.users?.name}
</Link>
</p>
</div>
</section>
<MarkDown style={dracula}>{quiz?.description ?? ''}</MarkDown>
<ChoiceForm quizId={quizId} />
</HydrationBoundary>
);
}
52 changes: 52 additions & 0 deletions components/ui/markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { cn } from '@/libs/utils';
import React from 'react';
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { dracula } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import remarkGfm from 'remark-gfm';

interface MarkdownProps extends React.ComponentProps<typeof SyntaxHighlighter> {
className?: string;
}

export default function MarkDown({
children,
className,
style = dracula,
...props
}: MarkdownProps) {
return (
<ReactMarkdown
className={cn('markdown', className)}
remarkPlugins={[remarkGfm]}
components={{
code({ className, children, ...rest }) {
const language = className?.replace('language-', '');

return language ? (
<SyntaxHighlighter
{...rest}
customStyle={{ padding: '0', overflow: 'hidden' }}
language={language}
style={style}
ref={null}
{...props}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code
{...rest}
className={cn('bg-gray-300 py-1 px-1.5 rounded-md', className)}
style={{ color: '#FF5262' }}
>
{children}
</code>
);
},
}}
>
{String(children)}
</ReactMarkdown>
);
}

0 comments on commit fa2e1d6

Please sign in to comment.