- ① 매칭 점수가 모든 화면의 주인공
- ② 다양성이 곧 가치 — 전공 컬러 코딩
- ③ 차분한 베이스 + 한 곳의 강렬한 포인트
- ④ 학생 톤 — 반말 살짝, 신뢰감 있게
- ⑤ 결과물(포트폴리오)에 자부심을
// App shell: tabs + side-by-side desktop + mobile preview
const Atoms = window.MajorAtoms;
const S1 = window.MajorScreens;
const S2 = window.MajorScreens2;
const S3 = window.MajorScreens3;
const Li = window.lucideReact || {};
const { useState: useApp, useEffect: useAppE } = React;
const TABS = [
{ k: 'landing', label: '랜딩', url: '', desktop: 'web', mobile: 'web' },
{ k: 'explore', label: '탐색', url: 'explore', desktop: 'web', mobile: 'web' },
{ k: 'detail', label: '상세', url: 'projects/lost-and-found', desktop: 'web', mobile: 'web' },
{ k: 'compare', label: '매칭 비교', url: 'projects/.../applicants', desktop: 'web', mobile: 'web' },
{ k: 'dashboard', label: '대시보드', url: 'workspace/lost-and-found', desktop: 'web', mobile: 'web' },
{ k: 'portfolio', label: '포트폴리오', url: 'me/portfolio/892', desktop: 'web', mobile: 'web' },
{ k: 'notif', label: '모바일 알림', url: 'notifications', desktop: 'fallback', mobile: 'web' },
{ k: 'mypage', label: '마이페이지', url: 'me', desktop: 'web', mobile: 'web' },
{ k: 'pricing', label: '요금제', url: 'pricing', desktop: 'web', mobile: 'web' },
];
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"wRole": 30,
"wSkill": 25,
"wPeriod": 20,
"wInterest": 15,
"wFolio": 10,
"showConfetti": true
}/*EDITMODE-END*/;
function App() {
const [tab, setTab] = useApp('landing');
const [animKey, setAnimKey] = useApp(0);
const [projectId, setProjectId] = useApp(1);
const [activeApplicant, setActiveApplicant] = useApp(null);
const [activeTask, setActiveTask] = useApp(null);
const [showCreate, setShowCreate] = useApp(false);
const [peerTeammate, setPeerTeammate] = useApp(null);
const [showAwardSubmit, setShowAwardSubmit] = useApp(false);
const [approval, setApproval] = useApp(null);
const [, setAwardVersion] = useApp(0);
const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
// Expose nav globally so cards/buttons can navigate
useAppE(() => {
window.__nav = {
go(target, args = {}) {
if (args.projectId) setProjectId(args.projectId);
setTab(target);
},
};
window.__openApplicant = (a) => setActiveApplicant(a);
window.__openTask = (t) => setActiveTask(t);
window.__openCreate = () => setShowCreate(true);
window.__openPeerEval = (m) => setPeerTeammate(m);
window.__openAwardSubmit = () => setShowAwardSubmit(true);
window.__openAwardApproval = (submission, applicantName) => setApproval({ submission, applicantName });
}, []);
// Push weights into BREAKDOWN_LABELS so ScoreBars + demo reflect them
useAppE(() => {
const max = { role: t.wRole, skill: t.wSkill, period: t.wPeriod, interest: t.wInterest, folio: t.wFolio };
Atoms.BREAKDOWN_LABELS.forEach(r => { r.max = max[r.key]; });
setAnimKey(k => k + 1);
}, [t.wRole, t.wSkill, t.wPeriod, t.wInterest, t.wFolio]);
useAppE(() => {
window.__ML_SHOW_CONFETTI = t.showConfetti;
setAnimKey(k => k + 1);
}, [t.showConfetti]);
useAppE(() => { setAnimKey(k => k + 1); }, [tab]);
const total = t.wRole + t.wSkill + t.wPeriod + t.wInterest + t.wFolio;
const renderDesktop = () => {
if (tab === 'notif') return