- GuideModal 컴포넌트 신규 생성 (아코디언 방식 가이드 모달 + HelpButton) - 8개 페이지에 (?) 도움말 버튼 및 화면별 사용자 가이드 추가 - 대시보드, 작업 목록, 실행 이력, 실행 상세 - 재수집 이력, 재수집 상세, 스케줄 관리, 타임라인 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
3.1 KiB
TypeScript
93 lines
3.1 KiB
TypeScript
import { useState } from 'react';
|
|
|
|
interface GuideSection {
|
|
title: string;
|
|
content: string;
|
|
}
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
pageTitle: string;
|
|
sections: GuideSection[];
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function GuideModal({ open, pageTitle, sections, onClose }: Props) {
|
|
if (!open) return null;
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-wing-overlay" onClick={onClose}>
|
|
<div
|
|
className="bg-wing-surface rounded-xl shadow-2xl p-6 max-w-2xl w-full mx-4 max-h-[80vh] overflow-y-auto"
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h3 className="text-lg font-semibold text-wing-text">{pageTitle} 사용 가이드</h3>
|
|
<button
|
|
onClick={onClose}
|
|
className="p-1 text-wing-muted hover:text-wing-text transition-colors"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
{sections.map((section, i) => (
|
|
<GuideAccordion key={i} title={section.title} content={section.content} defaultOpen={i === 0} />
|
|
))}
|
|
</div>
|
|
|
|
<div className="flex justify-end mt-6">
|
|
<button
|
|
onClick={onClose}
|
|
className="px-4 py-2 text-sm font-medium text-wing-text bg-wing-card rounded-lg hover:bg-wing-hover transition-colors"
|
|
>
|
|
닫기
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function GuideAccordion({ title, content, defaultOpen }: { title: string; content: string; defaultOpen: boolean }) {
|
|
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
|
|
return (
|
|
<div className="border border-wing-border rounded-lg overflow-hidden">
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="w-full flex items-center justify-between px-4 py-3 text-sm font-medium text-wing-text bg-wing-card hover:bg-wing-hover transition-colors text-left"
|
|
>
|
|
<span>{title}</span>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className={`w-4 h-4 text-wing-muted transition-transform ${isOpen ? 'rotate-180' : ''}`}
|
|
fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}
|
|
>
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</button>
|
|
{isOpen && (
|
|
<div className="px-4 py-3 text-sm text-wing-muted leading-relaxed whitespace-pre-line">
|
|
{content}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function HelpButton({ onClick }: { onClick: () => void }) {
|
|
return (
|
|
<button
|
|
onClick={onClick}
|
|
title="사용 가이드"
|
|
className="inline-flex items-center justify-center w-7 h-7 rounded-full border border-wing-border text-wing-muted hover:text-wing-accent hover:border-wing-accent transition-colors text-sm font-semibold"
|
|
>
|
|
?
|
|
</button>
|
|
);
|
|
}
|