/* 아리 — 알림 트리아지 페이지 "중요한 것만 울려요" — 지금/나중에/아리가 처리 3단 분류 + 집중 보호 + 발신자 규칙 */ const { useState } = React; const I = window.AriShell.Icon; const Topbar = window.AriShell.Topbar; const SubRail = window.AriShell.SubRail; const N = window.AriNotify; /* 페이지 전용 아이콘 (각 JSX는 독립 스코프 — 필요한 path만 로컬 정의) */ const NT_P = { msg: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z", card: "M2 5h20v14H2z|M2 10h20", }; function NI({ d }) { return ( {NT_P[d].split("|").map((s, i) => )} ); } const NT_SRC = { mail: { local: false, d: "mail", tone: "var(--blue)" }, cal: { local: false, d: "cal", tone: "var(--violet)" }, chat: { local: true, d: "msg", tone: "var(--violet)" }, fin: { local: true, d: "card", tone: "var(--green)" }, app: { local: false, d: "grid", tone: "var(--ink-2)" }, }; function SrcIcon({ src }) { const s = NT_SRC[src] || NT_SRC.app; return ( {s.local ? : } ); } function WhyChip({ why, tone }) { const t = tone === "muted" ? "var(--muted)" : "var(--" + tone + ")"; return ( {why} ); } const NT_TABS = [ { id: "now", label: "지금" }, { id: "later", label: "나중에" }, { id: "held", label: "아리가 처리" }, ]; const NT_CAP = { now: "직접 봐야 하는 알림만 남겼어요. 나머지는 아리가 들고 있을게요.", later: "급하지 않은 알림은 묶어서 다이제스트 시간에 전달돼요.", held: "아리가 이미 처리한 알림이에요. 전부 되돌릴 수 있어요.", }; function App() { const [view, setView] = useState("triage"); const [tab, setTab] = useState("now"); const [buckets, setBuckets] = useState({ now: N.buckets.now, later: N.buckets.later, held: N.buckets.held }); const [guardOn, setGuardOn] = useState(N.guard.on); const counts = { now: buckets.now.length, later: buckets.later.length + N.buckets.laterMore, held: buckets.held.length + N.buckets.heldMore, }; const toLater = (it) => setBuckets({ ...buckets, now: buckets.now.filter((x) => x.id !== it.id), later: [{ ...it, why: "내가 미룸", tone: "muted" }, ...buckets.later], }); const undo = (it) => setBuckets({ ...buckets, held: buckets.held.filter((x) => x.id !== it.id), now: [{ ...it, why: "되돌림", tone: "amber" }, ...buckets.now], }); const list = buckets[tab]; const more = tab === "later" ? N.buckets.laterMore : tab === "held" ? N.buckets.heldMore : 0; const NT_RAIL = [ { id: "triage", icon: "bell", label: "트리아지", dot: counts.now > 0 }, { sep: true }, { id: "guard", icon: "shield", label: "집중 보호 · 묶음" }, { id: "senders", icon: "users", label: "발신자 규칙" }, ]; const HEAD = { triage: { title: "알림", em: "중요한 것만 울려요" }, guard: { title: "집중 보호", em: "조용히, 그래도 놓치지 않게" }, senders: { title: "발신자 규칙", em: "누구는 바로, 누구는 모아서" }, }; const h = HEAD[view]; return (
오늘 {N.stats.total}건 도착 직접 본 건 {N.stats.seen}건 {N.stats.filtered}는 아리가 걸렀어요

{h.title} {h.em}

{view === "triage" && (
{/* 트리아지 스트림 */}

트리아지

아리가 분류한 오늘의 알림
{NT_TABS.map((t) => ( ))}
{NT_CAP[tab]}
{list.map((it) => (
{it.app}
{it.title}
{it.sum}
{tab === "now" && (
{it.act && }
)} {tab === "held" && (
)}
{it.time}
))} {list.length === 0 && (
비어 있어요. 오늘은 조용한 날이네요.
)}
{more > 0 &&
비슷한 알림 +{more}건 — 아리가 묶어뒀어요
}
{/* 오늘 요약 */}

오늘의 알림 요약

아리가 정리한 하루
{N.stats.total}도착
{counts.now}지금 볼 것
{N.buckets.held.length + N.buckets.heldMore}아리가 처리
{N.stats.filtered}걸러냄
‘지금 볼 것’만 알림으로 울리고, 나머지는 묶음 배달 시간에 모아서 보여드려요.
)} {view === "guard" && (

집중 보호 · 묶음 배달

조용히, 그래도 놓치지 않게
{guardOn ? (
딥 워크 보호 중 — {N.guard.until}까지
알림 {N.guard.held}건 보류 중 · 끝나면 한 번에 전달해요
) : (
보호 꺼짐
모든 알림이 바로 도착해요 · 집중 모드를 켜면 다시 막아드려요
)}
조용한 시간{N.guard.quiet} 긴급·VIP만 통과
묶음 배달 시간
{N.digests.map((d) => (
{d.time}
{d.name}{d.done ? " — 전달됨" : ""}
{d.desc}
{d.count}건
))}
)} {view === "senders" && (

발신자 규칙

누구는 바로, 누구는 모아서
{N.senders.length}개
{N.senders.map((s) => (
{s.who}{s.from}
{s.rule}
))}
‘나중에’로 미룬 발신자가 쌓이면 아리가 새 규칙을 제안해요. 자동화 페이지에서 언제든 고칠 수 있어요.
)}
); } ReactDOM.createRoot(document.getElementById("root")).render();