// home.jsx — Home screen with state variants
const { useState: useStateH } = React;
function HomeHeader({ data, go }) {
return (
} label={data.streak}/>
go('energy')}/>
);
}
function QuickActions({ go }) {
const acts = [
{ id: 'notime', label: '시간 없음', icon: 'clock' },
{ id: 'tired', label: '피곤해요', icon: 'moon' },
{ id: 'nospace', label: '공간 없음', icon: 'seat' },
{ id: 'swap', label: 'Quest 바꾸기', icon: 'quest' },
];
return (
{acts.map(a => (
))}
);
}
function AcademyTeaser({ go }) {
return (
go('academy')} style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 14 }}>
);
}
function Home({ data, go, startQuest }) {
const v = data.homeVariant || 'default';
// big quest card per variant
const variants = {
default: {
ava: <>오늘은 오래 앉아 있었어요. 30초만 어깨를 풀고 시작해요.>,
tag: "TODAY'S QUEST", title: '어깨 리셋 30초', desc: '목·어깨 긴장 완화', tone: T.coral,
meta: [{ icon: 'clock', label: '30초' }, { icon: 'seat', label: '앉아서 가능' }, { icon: 'camera_off', label: '카메라 없음' }],
primary: { label: '지금 30초 시작', onClick: () => startQuest({ title: '어깨 리셋', seconds: 30, steps: ['어깨를 귀 쪽으로 올려요', '뒤로 천천히 크게 돌려요', '숨을 길게 내쉬어요'], avaLine: '속도보다 부드러움이 중요해요', xp: 10 }, true) },
secondary: { label: '10초만 할래요', onClick: () => startQuest({ title: '어깨 리셋', seconds: 10, steps: ['어깨를 올려요', '뒤로 돌려요', '숨을 내쉬어요'], avaLine: '짧아도 충분해요', xp: 5 }, true) },
},
streakRisk: {
ava: <>오늘 기록이 아직 비어 있어요. 10초 Recovery로 Streak를 지킬 수 있어요.>,
tag: 'STREAK SAVE QUEST', title: '누워서 호흡 10초', desc: '오늘의 연결을 지켜요', tone: T.calm,
meta: [{ icon: 'clock', label: '10초' }, { icon: 'moon', label: '침대에서' }, { icon: 'wind', label: '회복 모드' }],
primary: { label: 'Streak 지키기', onClick: () => startQuest({ title: '회복 호흡', seconds: 10, tone: T.calm, steps: ['편하게 누워요', '천천히 들이마셔요', '길게 내쉬어요'], avaLine: '완벽한 운동은 필요 없어요', xp: 5 }, true), variant: 'calm' },
secondary: { label: '오늘은 쉴래요', onClick: () => go('flow', { flow: 'skip' }) },
},
completed: {
ava: <>오늘 Quest 완료했어요. 원하면 1분 보너스로 XP를 더 받을 수 있어요.>,
tag: 'COMPLETED TODAY', title: '어깨 리셋 30초', desc: '+10 XP · Streak 유지', tone: T.good, done: true,
meta: [],
primary: { label: '1분 보너스 Quest', onClick: () => startQuest({ title: '전신 깨우기', seconds: 60, steps: ['팔을 크게 돌려요', '가볍게 스쿼트해요', '깊게 호흡해요'], avaLine: '여유가 있다면 조금만 더', xp: 20 }) },
secondary: { label: 'Progress 보기', onClick: () => go('progress') },
},
return7: {
ava: <>다시 온 것만으로 충분해요. 오늘은 10초로 재시작해요.>,
tag: 'RESTART QUEST', title: '목 긴장 풀기 10초', desc: '7일 만의 복귀를 환영해요', tone: T.coral,
meta: [{ icon: 'clock', label: '10초' }, { icon: 'seat', label: '앉아서' }, { icon: 'camera_off', label: '카메라 없음' }],
primary: { label: '다시 시작', onClick: () => startQuest({ title: '목 긴장 풀기', seconds: 10, steps: ['목을 좌우로 기울여요', '천천히 돌려요', '숨을 내쉬어요'], avaLine: '돌아온 게 가장 중요해요', xp: 10 }, true) },
secondary: null,
},
};
if (data.todayQuest) {
const q = data.todayQuest;
const sec = q.seconds || 30;
variants.default = {
ava: <>Ava가 오늘 가능한 {sec}초 건강 행동을 골랐어요.>,
tag: "TODAY'S QUEST", title: q.title, desc: q.meta || '오늘의 건강 행동', tone: q.tone || T.coral,
meta: [{ icon: 'clock', label: `${sec}초` }, { icon: q.icon || 'seat', label: q.meta || '바로 가능' }, { icon: 'camera_off', label: '카메라 없음' }],
primary: { label: `지금 ${sec}초 시작`, onClick: () => startQuest(q, true) },
secondary: { label: '더 쉬운 Quest', onClick: () => go('flow', { flow: 'swap' }) },
};
variants.completed = {
...variants.completed,
title: q.title,
desc: `+${q.xp || 10} XP · Streak 유지`,
};
}
const c = variants[v];
return (
{c.ava}
{/* big quest card */}
{c.done &&
}
{c.tag}
{c.title}
{c.desc}
{c.meta.length > 0 &&
}
: null}>{c.primary.label}
{c.secondary && {c.secondary.label}}
{/* daily goal */}
DAILY GOAL
{data.completedToday ? '오늘 목표 달성!' : '오늘 1개 Quest'}
Lv.{data.level} · {data.xp} / 200 XP
{/* streak risk extra info */}
{v === 'streakRisk' && (
현재 {data.streak}일 연속 · 오늘 10초만 하면 유지돼요
)}
Quick Actions
);
}
function BodyCheckTeaser({ go }) {
return (
go('bodycheck')} style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 14, background: `linear-gradient(150deg, ${T.tealSoft}, ${T.bg})` }}>
);
}
Object.assign(window, { Home, QuickActions, AcademyTeaser, HomeHeader });