| name | mdx-components |
| description | Use when creating, modifying, or importing custom MDX React components for Code Complete chapter pages โ Verdict badge, MemberOpinion callout with emoji, VotingBar, DevilsAdvocate quote, BestPickCallout, VerdictDistribution chart, BestDiscussions list. Also use when a new visual element is needed in a chapter page beyond these seven, or when component props need to align with YAML human_only zone keys. |
mdx-components
Overview
Code Complete ์ฑํฐ ํ์ด์ง๋ Docusaurus ๊ธฐ๋ณธ ๋งํฌ๋ค์ด์ผ๋ก๋ ํํ์ด ๋น์ฝํ๋ค. 7๊ฐ ์ ์ฉ ์ปดํฌ๋ํธ๊ฐ "๋ง๊น๋๊ฒ"์ ์๊ฐ ์ถ์ ๋ด๋นํ๋ค. ์ด ์คํฌ์ ๊ฐ ์ปดํฌ๋ํธ์ props ๊ณ์ฝ์ ์ ์ํ๊ณ YAML Zone๊ณผ์ ๋งคํ์ ๊ณ ์ ํ๋ค.
When to Use
- ์ ์ฑํฐ MDX๋ฅผ ์์ฑํ ๋ ์ด๋ค ์ปดํฌ๋ํธ๋ฅผ importํด์ผ ํ๋์ง ๋ชจ๋ฅผ ๋
- ๊ธฐ์กด ์ปดํฌ๋ํธ props๋ฅผ ๋ฐ๊พธ๋ ค ํ ๋ (YAML ์คํค๋ง์ ๋๊ธฐํ ํ์)
- ์ ์ปดํฌ๋ํธ๋ฅผ ์ถ๊ฐํ๋ ค ํ ๋ (๊ธฐ๋ณธ 7์ข
์ธ 8๋ฒ์งธ ์ด์)
์ปดํฌ๋ํธ ๋ชฉ๋ก
| ์ปดํฌ๋ํธ | Zone ์ถ์ฒ | ์ญํ |
|---|
<Verdict> | ai_assist.verdict | ํ์ด์ง ์ต์๋จ ํ
|
<MemberOpinion> | human_only.member_opinions[] | ๋ฉค๋ฒ ์๊ฒฌ 1๋ช
|
<VotingBar> | human_only.votes | ํฌํ ํ๊ท ์๊ฐํ |
<DevilsAdvocate> | human_only.devils_advocate | ๋ฐ๋ฐ์ ์ธ์ฉ |
<BestPickCallout> | human_only.best_pick | ๋ฒ ์คํธ ํ ๋ก ํ์ด๋ผ์ดํธ |
<VerdictDistribution> | dashboard.yml | ๋ถ๋ก ์ฐจํธ |
<BestDiscussions> | dashboard.yml | ๋ถ๋ก ๋ฆฌ์คํธ |
Props ๊ณ์ฝ
<Verdict>
interface VerdictProps {
rating: '๐ข ์์กด' | '๐ก ๋ณํ' | '๐ด ์ฌ๋ง';
rationale: string;
}
์ฌ์ฉ:
<Verdict rating="๐ข ์์กด" rationale="2026๋
FE์์๋ ๋ค์ด๋ฐ ์์น์ ๊ทธ๋๋ก ์ ํจ" />
<MemberOpinion>
interface MemberOpinionProps {
author: 'Alice' | 'Amber' | 'Crong' | 'diego' | 'Jay' | 'Leo' | 'zinii';
emoji: string;
opinion: string;
experience: string;
}
์ค์: opinion๊ณผ experience๋ YAML human_only.member_opinions[].{opinion,experience}๋ฅผ literal ๊ทธ๋๋ก ์ ๋ฌ. ํ ๊ธ์๋ ์์ ๊ธ์ง.
<VotingBar>
interface VotingBarProps {
average: number;
votes: Record<MemberName, number | null>;
}
์๊ฐํ: ์ํ ๋ฐ (fill ratio = average/5). null ํฌํ๋ ํ์ tick์ผ๋ก.
<DevilsAdvocate>
interface DevilsAdvocateProps {
author: MemberName;
argument: string;
}
์ธ์ฉ ๋ธ๋ก + ๐ ์ด๋ชจ์ง. argument๋ literal.
<BestPickCallout>
interface BestPickCalloutProps {
content: string;
reason: string;
}
๐ ์ด๋ชจ์ง + quote ์คํ์ผ.
๋ถ๋ก ์ ์ฉ
interface VerdictDistributionProps {
alive: number;
evolved: number;
dead: number;
other?: number;
}
interface BestDiscussionsProps {
items: Array<{
chapter: number;
content: string;
reason: string;
contributedBy: MemberName[];
}>;
}
ํ์ผ ์์น
src/components/
โโโ Verdict.tsx
โโโ MemberOpinion.tsx
โโโ VotingBar.tsx
โโโ DevilsAdvocate.tsx
โโโ BestPickCallout.tsx
โโโ VerdictDistribution.tsx
โโโ BestDiscussions.tsx
โโโ types.ts # ๊ณตํต MemberName ํ์
๊ณตํต ํ์
(types.ts):
export type MemberName = 'Alice' | 'Amber' | 'Crong' | 'diego' | 'Jay' | 'Leo' | 'zinii';
export type Verdict = '๐ข ์์กด' | '๐ก ๋ณํ' | '๐ด ์ฌ๋ง';
๋์์ธ ์์น (v1 ๋ฏธ๋๋ฉ)
- ๋ฐ์ดํฐ ๋ ๋๋ฌ๋ง โ ์ฅ์ ๊ธ์ง. ์ซ์/ํ
์คํธ๋ฅผ ์๋ ๊ทธ๋๋ก ๋ณด์ฌ์ฃผ๋ ๊ฒ ์ฃผ ์ญํ
- ์ด๋ชจ์ง 1๊ฐ + ํ
์คํธ โ ์ถ๊ฐ ์์ด์ฝ/์ผ๋ฌ์คํธ ๊ธ์ง (UI ์ฌ๋กญ ํํผ)
- ๋คํฌ ๋ชจ๋ respect โ Docusaurus
useColorMode ํ์ฉ, ์ง์ ์์ ํ๋์ฝ๋ฉ ๊ธ์ง
- ๋ชจ๋ฐ์ผ ์ฐ์ โ ๋ชจ๋ ์ปดํฌ๋ํธ 320px ๋๋น์์ ๊นจ์ง์ง ์์์ผ ํจ
Common Mistakes
| ์ค์ | ๊ฒฐ๊ณผ | ์์ |
|---|
opinion ํ
์คํธ๋ฅผ ๋งํฌ๋ค์ด์ผ๋ก ํ์ด๋์ | Human-only ์์ญ ์นจ๋ฒ ๊ฐ๋ฅ์ฑ | props๋ก๋ง ์ ๋ฌ, ๋ณธ๋ฌธ์ ์ฐ์ง ๋ง ๊ฒ |
| ์ปดํฌ๋ํธ ๋ด๋ถ์์ YAML ์ง์ import | ๋ฐํ์ ์์กด์ฑ ๋ณต์ก๋โ | ์์ presentational, props๋ง ๋ฐ๊ธฐ |
votes ๊ฐ์ฒด์ ์๋ ๋ฉค๋ฒ ์ถ๊ฐ | VotingBar ๋ ๋ ๊นจ์ง | YAML meta.members์ ๋๊ธฐํ ํ์ |
emoji prop์ ์ฌ๋ฌ ์ด๋ชจ์ง | ์๊ฐ ์ฐ๋ง | ์ ํํ 1๊ฐ (MemberName โ emoji ๋งคํ ์ ์ง) |
Import ํจํด (mdx-writer๊ฐ ์๋ ์ฝ์
)
๋ชจ๋ ์ฑํฐ MDX ์ต์๋จ:
import Verdict from '@site/src/components/Verdict';
import MemberOpinion from '@site/src/components/MemberOpinion';
import VotingBar from '@site/src/components/VotingBar';
import DevilsAdvocate from '@site/src/components/DevilsAdvocate';
import BestPickCallout from '@site/src/components/BestPickCallout';
๋ถ๋ก ํ์ด์ง๋ง:
import VerdictDistribution from '@site/src/components/VerdictDistribution';
import BestDiscussions from '@site/src/components/BestDiscussions';