|
|
/* 아리 — '오늘의 여정' 대시보드 (RON 디자인 언어) */
|
|
|
const { useState, useEffect, useRef } = React;
|
|
|
|
|
|
/* ---------- 아이콘 ---------- */
|
|
|
const P = {
|
|
|
spark: "M12 3l1.9 5.2L19 10l-5.1 1.8L12 17l-1.9-5.2L5 10l5.1-1.8z|M19 4v3|M5 17v3",
|
|
|
grid: "M3 3h7v7H3z|M14 3h7v7h-7z|M14 14h7v7h-7z|M3 14h7v7H3z",
|
|
|
route: "M6 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6z|M18 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z|M9 16h6a3 3 0 0 0 3-3V11",
|
|
|
cal: "M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z",
|
|
|
check: "M9 11l3 3L22 4|M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11",
|
|
|
tick: "M20 6 9 17l-5-5",
|
|
|
mail: "M22 7 13.03 12.7a1.94 1.94 0 0 1-2.06 0L2 7|M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z",
|
|
|
target: "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20z|M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z|M12 12h.01",
|
|
|
heart: "M19 14c1.5-1.5 3-3.4 3-5.5A4.5 4.5 0 0 0 12 5.5 4.5 4.5 0 0 0 2 8.5c0 2.1 1.5 4 3 5.5l7 7z",
|
|
|
wallet: "M19 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0 0 4h15a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5|M16 12h.01",
|
|
|
brain: "M12 5a3 3 0 1 0-5.9.8A3 3 0 0 0 4 9.5 3 3 0 0 0 6 14a3 3 0 0 0 6 1zM12 5a3 3 0 1 1 5.9.8A3 3 0 0 1 20 9.5 3 3 0 0 1 18 14a3 3 0 0 1-6 1z|M12 5v14",
|
|
|
zap: "M13 2 3 14h9l-1 8 10-12h-9z",
|
|
|
bell: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9|M10.3 21a1.94 1.94 0 0 0 3.4 0",
|
|
|
search: "M21 21l-4.34-4.34|M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z",
|
|
|
send: "M22 2 11 13|M22 2 15 22l-4-9-9-4z",
|
|
|
sun: "M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10z|M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4",
|
|
|
moon: "M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z",
|
|
|
video: "M23 7l-7 5 7 5zM1 5h15a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H1a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2z",
|
|
|
pen: "M12 20h9|M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z",
|
|
|
file: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z|M14 2v6h6",
|
|
|
drop: "M12 2.7S5 10 5 14a7 7 0 0 0 14 0c0-4-7-11.3-7-11.3z",
|
|
|
foot: "M4 16c0-2 .5-4 2-4s2 1 2 3 .5 4-1 4-3-1-3-3z|M8 7c0-2 .5-3 1.5-3S11 5 11 7s0 3-1.5 3S8 9 8 7z|M14 16c0-2-.5-4-2-4s-2 1-2 3-.5 4 1 4 3-1 3-3z|M16 7c0-2-.5-3-1.5-3S13 5 13 7s0 3 1.5 3S16 9 16 7z",
|
|
|
more: "M5 12a1 1 0 1 0 2 0 1 1 0 0 0-2 0zM11 12a1 1 0 1 0 2 0 1 1 0 0 0-2 0zM17 12a1 1 0 1 0 2 0 1 1 0 0 0-2 0z",
|
|
|
plus: "M12 5v14|M5 12h14",
|
|
|
share: "M4 12v7a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7|M16 6l-4-4-4 4|M12 2v13",
|
|
|
back: "M19 12H5|M12 19l-7-7 7-7",
|
|
|
star: "M12 2l2.9 6.3 6.9.8-5.1 4.7 1.4 6.8L12 18l-6 3.4 1.4-6.8L2.3 9.9l6.9-.8z",
|
|
|
arrow: "M5 12h14|M13 6l6 6-6 6",
|
|
|
clock: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z|M12 7v5l3 2",
|
|
|
};
|
|
|
function I({ d, w }) {
|
|
|
return (
|
|
|
<svg className="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
|
strokeWidth={w || 1.9} strokeLinecap="round" strokeLinejoin="round">
|
|
|
{P[d].split("|").map((s, i) => <path key={i} d={s} />)}
|
|
|
</svg>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/* ---------- 색 ---------- */
|
|
|
const C = { blue: "#83a2db", blueD: "#6286c9", red: "#ce6969", navy: "#10141a", teal: "#5fa6a0", mauve: "#9c8bcb" };
|
|
|
|
|
|
/* ---------- 상단 메뉴 ---------- */
|
|
|
const NAV = [
|
|
|
{ id: "dash", label: "대시보드", icon: "grid", href: "아리 대시보드 (RON).html" },
|
|
|
{ id: "journey", label: "여정", icon: "route", href: "아리 대시보드 (RON v2).html" },
|
|
|
{ id: "cal", label: "일정", icon: "cal", href: "#" },
|
|
|
{ id: "task", label: "작업", icon: "check", badge: "4", href: "#" },
|
|
|
{ id: "mail", label: "메일", icon: "mail", href: "#" },
|
|
|
{ id: "life", label: "라이프", icon: "heart", href: "#" },
|
|
|
];
|
|
|
const RAIL = [
|
|
|
{ icon: "back", label: "뒤로" }, { sep: true },
|
|
|
{ icon: "grid", label: "오늘 개요", active: true },
|
|
|
{ icon: "cal", label: "일정" },
|
|
|
{ icon: "check", label: "할 일" },
|
|
|
{ icon: "target", label: "목표" },
|
|
|
{ icon: "heart", label: "건강" },
|
|
|
{ icon: "wallet", label: "지출" },
|
|
|
{ sep: true },
|
|
|
{ icon: "plus", label: "추가" },
|
|
|
];
|
|
|
|
|
|
/* ---------- 흐름 보드 데이터 ---------- */
|
|
|
const COL_MORNING = [
|
|
|
{ ic: "moon", title: "수면 7시간 12분", meta: "평소만큼 푹 잔 밤", tag: "컨디션 좋음", tool: "tick", toolC: "b" },
|
|
|
{ ic: "sun", title: "아침 브리핑 확인", meta: "맑음 24° · 출근 23분", tag: "4분 빠름", tool: "cal" },
|
|
|
];
|
|
|
const COL_FOCUS = [
|
|
|
{ id: "t1", title: "분기 리포트 초안 마무리", meta: "경영 · 우선", done: false },
|
|
|
{ id: "t2", title: "온보딩 와이어프레임 피드백", meta: "디자인 · 우선", done: false },
|
|
|
{ id: "t3", title: "신규 입사자 환영 메일 회신", meta: "팀", done: true },
|
|
|
{ id: "t4", title: "구독 결제 카드 갱신", meta: "개인", done: false },
|
|
|
];
|
|
|
const COL_MEET = [
|
|
|
{ time: "09:30", title: "팀 데일리 스탠드업", meta: "프로덕트 · 15분", av: C.blue, ini: "팀" },
|
|
|
{ time: "11:00", title: "디자인 리뷰", meta: "온보딩 · 45분", av: C.red, ini: "현" },
|
|
|
{ time: "14:00", title: "분기 전략 미팅", meta: "경영진 · 60분", av: C.navy, ini: "대", soon: true },
|
|
|
{ time: "16:30", title: "1:1 — 민서님", meta: "팀 · 30분", av: C.mauve, ini: "민" },
|
|
|
];
|
|
|
const COL_WRAP = [
|
|
|
{ hi: true, ic: "target", tt: "지금 집중", ts: "분기 리포트" },
|
|
|
{ ic: "heart", tt: "운동 30분", ts: "주 3/4회" },
|
|
|
{ ic: "brain", tt: "독서 2장", ts: "‘몰입’" },
|
|
|
{ ic: "wallet", tt: "가계부 정산", ts: "8% 절약" },
|
|
|
{ ic: "cal", tt: "내일 준비", ts: "일정 4건" },
|
|
|
{ ic: "moon", tt: "수면 모드", ts: "23:00" },
|
|
|
];
|
|
|
const COL_LABELS = [
|
|
|
{ t: "아침 루틴", s: "06:40 – 09:00", c: C.blue },
|
|
|
{ t: "오전 집중", s: "09:00 – 13:00", c: C.red },
|
|
|
{ t: "오후 미팅", s: "13:00 – 17:00", c: C.blue },
|
|
|
{ t: "마무리 & 내일", s: "17:00 – 23:00", c: C.navy },
|
|
|
];
|
|
|
|
|
|
/* 겹친 아바타 */
|
|
|
const STACK = [
|
|
|
{ ini: "대", c: C.navy, cnt: "2", cc: "b" },
|
|
|
{ ini: "현", c: C.red, cnt: "3", cc: "b" },
|
|
|
{ ini: "민", c: C.blue, cnt: "2", cc: "r" },
|
|
|
{ ini: "재", c: C.mauve, cnt: "1", cc: "r" },
|
|
|
{ ini: "수", c: C.teal },
|
|
|
];
|
|
|
|
|
|
/* 커넥터 라인 (gap center, y1, y2, color, dash) */
|
|
|
const CONN = [
|
|
|
{ c: 245, y1: 150, y2: 124, col: C.blue }, { c: 245, y1: 252, y2: 286, col: C.red, dash: true }, { c: 245, y1: 360, y2: 338, col: C.blue },
|
|
|
{ c: 499, y1: 160, y2: 138, col: C.blue }, { c: 499, y1: 270, y2: 300, col: C.red, dash: true }, { c: 499, y1: 378, y2: 356, col: C.blue, dash: true },
|
|
|
{ c: 753, y1: 150, y2: 172, col: C.red, dash: true }, { c: 753, y1: 262, y2: 238, col: C.blue }, { c: 753, y1: 360, y2: 384, col: C.red },
|
|
|
];
|
|
|
|
|
|
/* ---------- 데이터 테이블 ---------- */
|
|
|
const ROWS = [
|
|
|
{ star: true, nm: "분기 리포트 초안", st: "prog", stt: "진행중", date: "09:00", un: "지우", uc: C.navy },
|
|
|
{ nm: "온보딩 와이어프레임 피드백", st: "sched", stt: "예정", date: "11:00", un: "현우", uc: C.red },
|
|
|
{ star: true, nm: "신규 입사자 환영 메일", st: "done", stt: "완료", date: "08:30", un: "민서", uc: C.blue },
|
|
|
{ nm: "구독 결제 카드 갱신", st: "sched", stt: "예정", date: "18:00", un: "지우", uc: C.navy },
|
|
|
{ nm: "독서모임 책 2장 읽기", st: "sched", stt: "예정", date: "21:00", un: "지우", uc: C.navy },
|
|
|
];
|
|
|
|
|
|
/* ---------- 반원 게이지 ---------- */
|
|
|
const LEN = Math.PI * 64;
|
|
|
function Gauge({ pct, color, val, unit, label, sub }) {
|
|
|
return (
|
|
|
<div className="gauge">
|
|
|
<svg viewBox="0 0 160 104">
|
|
|
<path d="M16 88 A64 64 0 0 1 144 88" fill="none" stroke="var(--card-2)" strokeWidth="13" strokeLinecap="round" />
|
|
|
<path d="M16 88 A64 64 0 0 1 144 88" fill="none" stroke={color} strokeWidth="13" strokeLinecap="round"
|
|
|
strokeDasharray={`${(LEN * pct) / 100} ${LEN}`} />
|
|
|
</svg>
|
|
|
<div style={{ marginTop: "-50px", display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
|
<div className="gval">{val}</div>
|
|
|
<div className="gunit">{unit}</div>
|
|
|
</div>
|
|
|
<div className="glabel">{label}</div>
|
|
|
<div className="gsub">{sub}</div>
|
|
|
</div>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
function App() {
|
|
|
const [theme, setTheme] = useState("light");
|
|
|
const [tasks, setTasks] = useState(COL_FOCUS);
|
|
|
const ref = useRef(null);
|
|
|
|
|
|
useEffect(() => { document.documentElement.setAttribute("data-theme", theme); }, [theme]);
|
|
|
useEffect(() => {
|
|
|
const el = ref.current;
|
|
|
const id = requestAnimationFrame(() => el && el.classList.add("enter"));
|
|
|
return () => cancelAnimationFrame(id);
|
|
|
}, []);
|
|
|
|
|
|
const toggle = (id) => setTasks((t) => t.map((x) => (x.id === id ? { ...x, done: !x.done } : x)));
|
|
|
const openCount = tasks.filter((t) => !t.done).length;
|
|
|
|
|
|
return (
|
|
|
<div className="app" ref={ref}>
|
|
|
{/* ===== 상단바 ===== */}
|
|
|
<header className="top">
|
|
|
<div className="brand">
|
|
|
<div className="brand-mark"><I d="spark" /></div>
|
|
|
<span className="brand-name">아리</span>
|
|
|
</div>
|
|
|
<nav className="nav">
|
|
|
{NAV.map((m) => (
|
|
|
<a key={m.id} href={m.href} className={m.id === "journey" ? "active" : ""}>
|
|
|
<I d={m.icon} />{m.label}
|
|
|
{m.badge && <span className="badge">{m.badge}</span>}
|
|
|
</a>
|
|
|
))}
|
|
|
</nav>
|
|
|
<div className="top-actions">
|
|
|
<button className="circ" aria-label="검색"><I d="search" /></button>
|
|
|
<button className="circ dot" aria-label="메일"><I d="mail" /></button>
|
|
|
<button className="circ dot" aria-label="알림"><I d="bell" /></button>
|
|
|
<button className="circ" aria-label="테마" onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
|
|
|
<I d={theme === "light" ? "moon" : "sun"} />
|
|
|
</button>
|
|
|
<div className="avatar">지</div>
|
|
|
</div>
|
|
|
</header>
|
|
|
|
|
|
{/* ===== 무대 ===== */}
|
|
|
<div className="stage">
|
|
|
{/* 좌측 레일 */}
|
|
|
<aside className="rail">
|
|
|
{RAIL.map((r, i) =>
|
|
|
r.sep ? <span className="sep" key={i} /> : (
|
|
|
<button key={i} className={r.active ? "active" : ""} aria-label={r.label}>
|
|
|
<I d={r.icon} /><span className="tip">{r.label}</span>
|
|
|
</button>
|
|
|
)
|
|
|
)}
|
|
|
</aside>
|
|
|
|
|
|
{/* 메인 */}
|
|
|
<main className="main">
|
|
|
{/* 페이지 헤더 */}
|
|
|
<div className="pagehead">
|
|
|
<div className="ph-titles">
|
|
|
<h1 className="ph-title">오늘의 여정</h1>
|
|
|
<p className="ph-sub">좋은 아침이에요, <b>지우님</b> · 6월 7일 일요일 · 일정 <b>4건</b>, 할 일 <b>{openCount}개</b></p>
|
|
|
</div>
|
|
|
<div className="ph-right">
|
|
|
<div className="ph-weather"><I d="sun" /><b>24°</b> 맑음 · 한낮 28°</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/* 흐름 보드 패널 */}
|
|
|
<section className="panel journey">
|
|
|
<div className="journey-top">
|
|
|
<div className="journey-label">오늘의 흐름 <span>· 4단계 · 12개 항목</span></div>
|
|
|
<div className="stack">
|
|
|
{STACK.map((s, i) => (
|
|
|
<div className="av" key={i} style={{ background: s.c }}>
|
|
|
{s.ini}
|
|
|
{s.cnt && <span className={"cnt " + s.cc}>{s.cnt}</span>}
|
|
|
</div>
|
|
|
))}
|
|
|
<div className="more">+3</div>
|
|
|
</div>
|
|
|
<div className="journey-actions">
|
|
|
<button className="act"><I d="plus" /></button>
|
|
|
<button className="act"><I d="share" /></button>
|
|
|
<button className="act fill"><I d="cal" /></button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div className="board">
|
|
|
{/* 커넥터 */}
|
|
|
<svg className="connectors" viewBox="0 0 1000 460" preserveAspectRatio="none">
|
|
|
{CONN.map((k, i) => (
|
|
|
<g key={i}>
|
|
|
<path d={`M${k.c - 34} ${k.y1} C ${k.c - 6} ${k.y1}, ${k.c + 6} ${k.y2}, ${k.c + 34} ${k.y2}`}
|
|
|
fill="none" stroke={k.col} strokeWidth="1.8" strokeLinecap="round"
|
|
|
vectorEffect="non-scaling-stroke" opacity="0.6"
|
|
|
strokeDasharray={k.dash ? "1 6" : "none"} />
|
|
|
<circle cx={k.c - 34} cy={k.y1} r="3" fill={k.col} opacity="0.7" vectorEffect="non-scaling-stroke" />
|
|
|
<circle cx={k.c + 34} cy={k.y2} r="3" fill={k.col} opacity="0.7" vectorEffect="non-scaling-stroke" />
|
|
|
</g>
|
|
|
))}
|
|
|
</svg>
|
|
|
|
|
|
{/* 컬럼 1 — 아침 루틴 */}
|
|
|
<div className="col">
|
|
|
<div className="col-head"><span className="dot" style={{ background: C.blue }} /><span className="t">아침 루틴</span><span className="n">2</span></div>
|
|
|
<div className="col-body">
|
|
|
{COL_MORNING.map((c, i) => (
|
|
|
<div className="fcard" key={i}>
|
|
|
<div className="fcard-row">
|
|
|
<div className="fc-ic"><I d={c.ic} /></div>
|
|
|
<div className="fc-main"><div className="fc-title">{c.title}</div><div className="fc-meta">{c.meta}</div></div>
|
|
|
<div className={"mini " + (c.toolC || "")}><I d={c.tool} w="2.4" /></div>
|
|
|
</div>
|
|
|
<div className="fcard-foot"><span className="tag">{c.tag}</span></div>
|
|
|
</div>
|
|
|
))}
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/* 컬럼 2 — 오전 집중 (할 일) */}
|
|
|
<div className="col">
|
|
|
<div className="col-head"><span className="dot" style={{ background: C.red }} /><span className="t">오전 집중</span><span className="n">{openCount}/4</span></div>
|
|
|
<div className="col-body">
|
|
|
{tasks.map((t) => (
|
|
|
<div className={"fcard task" + (t.done ? " done" : "")} key={t.id} onClick={() => toggle(t.id)}>
|
|
|
<div className="fcard-row">
|
|
|
<div className="fcheck"><I d="tick" w="3" /></div>
|
|
|
<div className="fc-main"><div className="fc-title">{t.title}</div><div className="fc-meta">{t.meta}</div></div>
|
|
|
<div className="mini"><I d="cal" /></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
))}
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/* 컬럼 3 — 오후 미팅 */}
|
|
|
<div className="col">
|
|
|
<div className="col-head"><span className="dot" style={{ background: C.blue }} /><span className="t">오후 미팅</span><span className="n">4</span></div>
|
|
|
<div className="col-body">
|
|
|
{COL_MEET.map((e, i) => (
|
|
|
<div className="fcard" key={i}>
|
|
|
<div className="fcard-row">
|
|
|
<div className="fc-av" style={{ background: e.av }}>{e.ini}</div>
|
|
|
<div className="fc-main"><div className="fc-title">{e.title}</div><div className="fc-meta">{e.meta}</div></div>
|
|
|
{e.soon ? <span className="mini r" style={{ width: "auto", padding: "0 9px", fontSize: "11px", fontWeight: 700 }}>곧</span> : <div className="fc-time">{e.time}</div>}
|
|
|
</div>
|
|
|
</div>
|
|
|
))}
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/* 컬럼 4 — 마무리 & 내일 */}
|
|
|
<div className="col">
|
|
|
<div className="col-head"><span className="dot" style={{ background: C.navy }} /><span className="t">마무리 & 내일</span><span className="n">6</span></div>
|
|
|
<div className="col-body">
|
|
|
<div className="tiles">
|
|
|
{COL_WRAP.map((t, i) => (
|
|
|
<div className={"tile" + (t.hi ? " hi" : "")} key={i}>
|
|
|
<div className="tic"><I d={t.ic} /></div>
|
|
|
<div className="tt">{t.tt}</div>
|
|
|
<div className="ts">{t.ts}</div>
|
|
|
</div>
|
|
|
))}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/* 말풍선 */}
|
|
|
<div className="bubble" style={{ top: "150px", left: "62%" }}>
|
|
|
<span className="bsm">다음 집중</span>
|
|
|
<b>분기 리포트</b> 오전을 비워 마무리하세요
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/* 컬럼 라벨 */}
|
|
|
<div className="col-labels">
|
|
|
{COL_LABELS.map((l, i) => (
|
|
|
<div className="cl" key={i} style={{ color: l.c === C.navy ? "var(--ink)" : l.c }}>{l.t}<span>{l.s}</span></div>
|
|
|
))}
|
|
|
</div>
|
|
|
</section>
|
|
|
|
|
|
{/* 하단 2열 */}
|
|
|
<section className="bottom">
|
|
|
{/* 데이터 테이블 */}
|
|
|
<div className="panel">
|
|
|
<div className="panel-head">
|
|
|
<div><div className="pt">오늘의 작업</div><div className="ps">5건 · 진행중 1 · 예정 3 · 완료 1</div></div>
|
|
|
<div className="pa">
|
|
|
<button className="act"><I d="plus" /></button>
|
|
|
<button className="act"><I d="share" /></button>
|
|
|
<button className="act"><I d="cal" /></button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<table className="table">
|
|
|
<thead>
|
|
|
<tr><th>작업</th><th>상태</th><th>시작</th><th>담당</th></tr>
|
|
|
</thead>
|
|
|
<tbody>
|
|
|
{ROWS.map((r, i) => (
|
|
|
<tr key={i}>
|
|
|
<td>
|
|
|
<div className="t-subj">
|
|
|
<svg className={"ic star" + (r.star ? " on" : "")} viewBox="0 0 24 24" fill={r.star ? "currentColor" : "none"} stroke="currentColor" strokeWidth="1.7"><path d={P.star} /></svg>
|
|
|
<span className="nm">{r.nm}</span>
|
|
|
</div>
|
|
|
</td>
|
|
|
<td><span className={"chip " + r.st}>{r.stt}</span></td>
|
|
|
<td><span className="t-date">{r.date}</span></td>
|
|
|
<td>
|
|
|
<div className="t-user"><div className="ua" style={{ background: r.uc }}>{r.un[0]}</div><span className="un">{r.un}</span></div>
|
|
|
</td>
|
|
|
</tr>
|
|
|
))}
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
|
|
|
{/* 게이지 */}
|
|
|
<div className="panel">
|
|
|
<div className="panel-head">
|
|
|
<div><div className="pt">오늘의 지표</div><div className="ps">집중 · 활동</div></div>
|
|
|
<div className="pa"><button className="act"><I d="more" /></button></div>
|
|
|
</div>
|
|
|
<div className="gauges">
|
|
|
<Gauge pct={87} color={C.blue} val="5.2" unit="시간" label="딥 워크" sub="목표 6시간" />
|
|
|
<Gauge pct={72} color={C.red} val="72" unit="%" label="활동 링" sub="7.2천 걸음" />
|
|
|
</div>
|
|
|
<div className="gauge-foot"><I d="drop" />오후 3시예요 — 물 한 잔, 5분 스트레칭 어때요?</div>
|
|
|
</div>
|
|
|
</section>
|
|
|
</main>
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
|