/* 아리 — 알림 트리아지 페이지
"중요한 것만 울려요" — 지금/나중에/아리가 처리 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 (
);
}
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.map((s) => (
))}
‘나중에’로 미룬 발신자가 쌓이면 아리가 새 규칙을 제안해요. 자동화 페이지에서 언제든 고칠 수 있어요.
)}
);
}
ReactDOM.createRoot(document.getElementById("root")).render();