{children}
@@ -68,50 +71,78 @@ export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
);
},
- // 2. 인용구 + GitHub Alerts 처리
+ // 2. 인용구 + GitHub Alerts 처리 (TypeScript 오류 수정 및 로직 개선)
blockquote({ children }: any) {
- // children 내부에서 텍스트를 추출하여 Alert 패턴 확인
const childArray = React.Children.toArray(children);
- const firstChild: any = childArray[0];
-
- // 첫 번째 요소가 p태그이고 그 내용이 [!TYPE]으로 시작하는지 확인
- if (React.isValidElement(firstChild) && firstChild.props.children) {
- const textContent = String(firstChild.props.children[0]);
- const match = textContent.match(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]/);
+ const firstChild = childArray[0];
+ let alertType: keyof typeof ALERT_VARIANTS | null = null;
- if (match) {
- const type = match[1] as keyof typeof ALERT_VARIANTS;
- const variant = ALERT_VARIANTS[type];
- const Icon = variant.icon;
-
- // [!NOTE] 텍스트 제거 후 나머지 렌더링
- const restContent = React.Children.map(children, (child, index) => {
- if (index === 0 && React.isValidElement(child)) {
- return React.cloneElement(child as any, {
- children: child.props.children.slice(1) // 텍스트 노드 처리 필요 (단순화를 위해 slice 사용)
- });
+ // [수정] 타입스크립트 안전성 확보 및 파싱 로직 강화
+ // React.isValidElement로 체크 후, ReactElement로 단언(assertion)하여 props 접근
+ if (React.isValidElement(firstChild)) {
+ const element = firstChild as React.ReactElement;
+
+ // 보통 blockquote > p 구조임
+ if (element.type === 'p' && element.props.children) {
+ // p 태그의 첫 번째 자식이 텍스트인지 확인
+ const content = element.props.children;
+ const firstText = Array.isArray(content) ? content[0] : content;
+
+ if (typeof firstText === 'string') {
+ const match = firstText.match(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]/);
+ if (match) {
+ alertType = match[1] as keyof typeof ALERT_VARIANTS;
}
- return child;
- });
-
- return (
-
-
-
- {variant.title}
-
-
- {/* [!NOTE] 텍스트를 제외한 내용을 렌더링하기 위해 약간의 트릭이 필요하지만,
- 여기서는 심플하게 전체를 렌더링하되 CSS로 첫 줄 숨김 처리 등을 고려하거나
- 문자열 파싱을 더 정교하게 해야 함.
- 간단한 구현을 위해 여기선 일반 블록쿼트+스타일만 적용 */}
- {children}
-
-
- );
+ }
}
}
-
+
+ // Alert 타입이 감지되면 스타일링된 컴포넌트 반환
+ if (alertType) {
+ const variant = ALERT_VARIANTS[alertType];
+ const Icon = variant.icon;
+
+ // [수정] [!NOTE] 텍스트를 안전하게 제거
+ const restContent = React.Children.map(children, (child, index) => {
+ if (index === 0 && React.isValidElement(child)) {
+ const element = child as React.ReactElement;
+ const content = element.props.children;
+
+ // 내용이 배열일 수도 있고 문자열일 수도 있음
+ if (Array.isArray(content)) {
+ // 첫 번째 텍스트 노드에서 [!NOTE] 부분만 제거
+ const [first, ...rest] = content;
+ if (typeof first === 'string') {
+ const newText = first.replace(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s?/, '');
+ return React.cloneElement(element, {
+ ...element.props,
+ children: [newText, ...rest]
+ });
+ }
+ } else if (typeof content === 'string') {
+ const newText = content.replace(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s?/, '');
+ return React.cloneElement(element, {
+ ...element.props,
+ children: newText
+ });
+ }
+ }
+ return child;
+ });
+
+ return (
+
+
+
+ {variant.title}
+
+
+ {restContent}
+
+
+ );
+ }
+
// 일반 인용구
return (
@@ -123,18 +154,17 @@ export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
// 3. 링크
a({ href, children }) {
const isExternal = href?.startsWith('http');
- // 헤딩 앵커 링크 처리 (rehype-autolink-headings)
if (href?.startsWith('#')) {
- return (
-
-
-
- )
+ return (
+
+
+
+ )
}
return (
-
-
+ />
{alt && {alt} }
@@ -191,43 +221,46 @@ export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
return {children}
;
},
li({ children, className, ...props }: any) {
- // Task List 아이템 스타일링
if (className?.includes('task-list-item')) {
- return {children}
+ return {children}
}
return {children} ;
},
- // 체크박스 커스텀
+ // [수정] 체크박스 ReadOnly 속성 추가
input({ type, ...props }: any) {
- if (type === 'checkbox') {
- return
- }
- return ;
+ if (type === 'checkbox') {
+ return (
+
+ )
+ }
+ return ;
},
- // 7. 헤딩 (앵커 링크 포함)
+ // 7. 헤딩
h1({ children, id }: any) {
return (
-
- {children}
-
+
+ {children}
+
);
},
h2({ children, id }: any) {
return (
-
- {children}
-
+
+ {children}
+
);
},
h3({ children, id }: any) {
- return {children}
;
+ return {children}
;
},
-
- // 수식 렌더링 (KaTeX)
- // p 태그 내부의 수식 렌더링을 위해 p 태그 스타일 유지
p({ children }) {
- return {children}
;
+ return {children}
;
}
}}
>
@@ -237,7 +270,7 @@ export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
);
}
-// 코드 블록 컴포넌트 (디자인 개선)
+// 코드 블록 컴포넌트
function CodeBlock({ language, code }: { language: string; code: string }) {
const [isCopied, setIsCopied] = useState(false);
@@ -249,7 +282,6 @@ function CodeBlock({ language, code }: { language: string; code: string }) {
return (
- {/* Mac OS 스타일 헤더 */}
@@ -257,20 +289,18 @@ function CodeBlock({ language, code }: { language: string; code: string }) {
- {language && (
-
-
- {language}
-
- )}
+
+
+ {language}
+
-
+
-
+