Spaces:
Running
Running
| /** | |
| * @license | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { Loader2, AlertCircle } from 'lucide-react'; | |
| export function LoadingOverlay({ message = "분석 중입니다..." }: { message?: string }) { | |
| return ( | |
| <div className="fixed inset-0 bg-white/80 backdrop-blur-sm z-50 flex flex-col items-center justify-center"> | |
| <Loader2 className="w-12 h-12 text-cyan-500 animate-spin mb-4" /> | |
| <p className="text-lg font-bold text-slate-700">{message}</p> | |
| </div> | |
| ); | |
| } | |
| export function ErrorMessage({ message, onRetry }: { message: string; onRetry?: () => void }) { | |
| return ( | |
| <div className="p-6 bg-red-50 border border-red-200 rounded-2xl flex flex-col items-center text-center"> | |
| <AlertCircle className="w-10 h-10 text-red-500 mb-2" /> | |
| <p className="text-red-700 font-medium mb-4">{message}</p> | |
| {onRetry && ( | |
| <button | |
| onClick={onRetry} | |
| className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors" | |
| > | |
| 다시 시도 | |
| </button> | |
| )} | |
| </div> | |
| ); | |
| } | |
| import Link from 'next/link'; | |
| export function Header() { | |
| return ( | |
| <header className="min-h-16 border-b border-slate-100 bg-white sticky top-0 z-40 px-4 sm:px-6 py-3 flex items-center justify-between gap-3"> | |
| <Link href="/" className="flex min-w-0 items-center space-x-2 hover:opacity-80 transition-opacity"> | |
| <div className="w-8 h-8 bg-cyan-500 rounded-lg flex items-center justify-center"> | |
| <div className="w-4 h-4 bg-white rounded-sm rotate-45" /> | |
| </div> | |
| <h1 className="text-xl font-bold text-slate-900 tracking-tight">IT 커리어밸류체크</h1> | |
| </Link> | |
| <div className="hidden md:flex shrink-0 items-center space-x-6 text-sm font-medium text-slate-500"> | |
| <span className="text-cyan-600">2025 IT산업 임금체계 개선 길라잡이 연계</span> | |
| </div> | |
| </header> | |
| ); | |
| } | |
| import { motion } from 'framer-motion'; | |
| export function SurveyHeader({ current, total }: { current: number; total: number }) { | |
| const progress = (current / total) * 100; | |
| return ( | |
| <header className="h-16 border-b border-slate-100 bg-white sticky top-0 z-40 flex flex-col justify-end"> | |
| <div className="px-4 sm:px-6 flex items-center justify-between h-full gap-3"> | |
| <div className="flex items-center space-x-2"> | |
| <span className="text-xs font-bold text-cyan-600 tracking-widest">Step {current} of {total}</span> | |
| </div> | |
| <div className="text-right"> | |
| <span className="text-sm font-bold text-slate-900">{Math.round(progress)}%</span> | |
| </div> | |
| </div> | |
| <div className="w-full h-1 bg-slate-100 overflow-hidden"> | |
| <motion.div | |
| initial={{ width: 0 }} | |
| animate={{ width: `${progress}%` }} | |
| className="h-full bg-cyan-500" | |
| /> | |
| </div> | |
| </header> | |
| ); | |
| } | |