Walrus blob · mainnet
On-chain registration not yet visible.
The aggregator served this blob, but we couldn't locate a matching BlobRegistered event in our scan window. It may not be certified yet, or live further back than we paged.
Lifecycle data is unavailable until the blob registration is visible on-chain.
import { r as y, j as e, L as Y } from "./react-vendor-D_egQ_JM.js";
import { u as F } from "./index-42b27eoT.js";
import { ag as P, h as E, t as M, S as J, M as V, z as w, k as X, l as B, aj as G, x as H, ak as K, X as q } from "./icons-kgsOGgkz.js";
import "./vendor-ClTrYn-B.js";
import "./sui-dapp-DSEyQPYQ.js";
import "./sui-core-CYDB34vH.js";
import "./tanstack-mi_hh22G.js";
import "./supabase-C9TepEwE.js";
import "./sui-walrus-DUKqLMf8.js";
import "./dexie-QiWxkoOr.js";
const R = "toolhub_elapsed_tracker_v1";
function Q() {
try {
if (typeof crypto < "u" && crypto.randomUUID) return crypto.randomUUID();
} catch {
}
return "ev_" + Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
}
function f() {
const n = /* @__PURE__ */ new Date(), a = n.getFullYear(), s = String(n.getMonth() + 1).padStart(2, "0"), g = String(n.getDate()).padStart(2, "0");
return `${a}-${s}-${g}`;
}
function I(n) {
const [a, s, g] = n.split("-").map(Number);
if (!a || !s || !g) return 0;
const l = new Date(a, s - 1, g), c = /* @__PURE__ */ new Date(), j = new Date(c.getFullYear(), c.getMonth(), c.getDate()).getTime() - l.getTime();
return Math.max(0, Math.round(j / 864e5));
}
function b(n) {
const a = /* @__PURE__ */ new Date();
a.setDate(a.getDate() - n);
const s = a.getFullYear(), g = String(a.getMonth() + 1).padStart(2, "0"), l = String(a.getDate()).padStart(2, "0");
return `${s}-${g}-${l}`;
}
const W = [{ id: "exA", name: "\u611B\u72AC\u306E\u30B7\u30E3\u30F3\u30D7\u30FC", targetCycleDays: 21, lastDone: b(9), history: [b(9)], createdAt: "", updatedAt: "" }, { id: "exB", name: "\u30A8\u30A2\u30B3\u30F3\u6383\u9664", targetCycleDays: 90, lastDone: b(75), history: [b(75)], createdAt: "", updatedAt: "" }, { id: "exC", name: "\u30D1\u30B9\u30EF\u30FC\u30C9\u5909\u66F4", targetCycleDays: 180, lastDone: b(200), history: [b(200)], createdAt: "", updatedAt: "" }];
function Z() {
try {
const n = localStorage.getItem(R);
if (n === null) return [];
const a = JSON.parse(n);
return Array.isArray(a) ? a.filter((s) => s && typeof s.id == "string" && typeof s.name == "string" && typeof s.lastDone == "string") : [];
} catch {
return [];
}
}
function ee(n) {
try {
localStorage.setItem(R, JSON.stringify(n));
} catch (a) {
console.error("[elapsed-tracker] save failed", a);
}
}
function u(n) {
const a = I(n.lastDone);
if (!n.targetCycleDays || n.targetCycleDays <= 0) return { level: "none", ratio: 0, elapsed: a };
const s = a / n.targetCycleDays;
return { level: s >= 1 ? "over" : s >= 0.7 ? "warn" : "ok", ratio: s, elapsed: a };
}
const A = { none: { bar: "bg-gray-400", ring: "border-gray-200 dark:border-gray-800", text: "text-gray-500", label: "" }, ok: { bar: "bg-emerald-500", ring: "border-emerald-300/60 dark:border-emerald-700/50", text: "text-emerald-600 dark:text-emerald-400", label: "\u4F59\u88D5" }, warn: { bar: "bg-amber-500", ring: "border-amber-300/70 dark:border-amber-600/50", text: "text-amber-600 dark:text-amber-400", label: "\u305D\u308D\u305D\u308D" }, over: { bar: "bg-red-500", ring: "border-red-300 dark:border-red-700/60", text: "text-red-600 dark:text-red-400", label: "\u8D85\u904E" } }, T = () => ({ id: null, name: "", cycleRaw: "", lastDone: f() });
function xe() {
const { theme: n, toggleTheme: a } = F(), [s, g] = y.useState(() => Z()), [l, c] = y.useState(null), [v, j] = y.useState(/* @__PURE__ */ new Set()), [D, C] = y.useState(null), k = y.useRef(null);
y.useEffect(() => {
ee(s);
}, [s]);
const h = (t) => {
C(t), k.current && window.clearTimeout(k.current), k.current = window.setTimeout(() => C(null), 1400);
}, S = y.useMemo(() => [...s].sort((t, d) => {
const r = u(t), o = u(d), i = t.targetCycleDays ? r.ratio : -1;
return (d.targetCycleDays ? o.ratio : -1) - i;
}), [s]), L = (t) => {
const d = f();
g((r) => r.map((o) => {
if (o.id !== t) return o;
const i = o.history[0] === d ? o.history : [d, ...o.history].slice(0, 50);
return { ...o, lastDone: d, history: i, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
})), h("\u5B8C\u4E86\u3092\u8A18\u9332\u3057\u307E\u3057\u305F");
}, _ = (t) => {
g((d) => d.filter((r) => r.id !== t)), h("\u524A\u9664\u3057\u307E\u3057\u305F");
}, O = (t) => {
j((d) => {
const r = new Set(d);
return r.has(t) ? r.delete(t) : r.add(t), r;
});
}, U = () => {
if (!l) return;
const t = l.name.trim();
if (!t) {
h("\u30A4\u30D9\u30F3\u30C8\u540D\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044");
return;
}
const d = l.cycleRaw.trim() === "" ? null : Math.max(1, Math.round(Number(l.cycleRaw))), r = l.lastDone || f(), o = (/* @__PURE__ */ new Date()).toISOString();
if (l.id) g((i) => i.map((x) => {
if (x.id !== l.id) return x;
const p = x.lastDone === r ? x.history : [r, ...x.history.filter((m) => m !== r)].slice(0, 50);
return { ...x, name: t, targetCycleDays: d, lastDone: r, history: p, updatedAt: o };
})), h("\u66F4\u65B0\u3057\u307E\u3057\u305F");
else {
const i = { id: Q(), name: t, targetCycleDays: d, lastDone: r, history: [r], createdAt: o, updatedAt: o };
g((x) => [i, ...x]), h("\u8FFD\u52A0\u3057\u307E\u3057\u305F");
}
c(null);
}, $ = (t) => {
const [d, r, o] = t.split("-");
return `${d}/${r}/${o}`;
};
return e.jsxs("div", { className: "min-h-screen bg-gray-50 dark:bg-[#0b0b0d] text-gray-900 dark:text-gray-100", children: [e.jsx("header", { className: "sticky top-0 z-20 backdrop-blur bg-gray-50/80 dark:bg-[#0b0b0d]/80 border-b border-gray-200 dark:border-gray-800", children: e.jsxs("div", { className: "max-w-3xl mx-auto px-4 py-3 flex items-center gap-3", children: [e.jsx(Y, { to: "/", className: "p-2 -ml-2 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-800 transition-colors", title: "\u30CF\u30D6\u3078\u623B\u308B", children: e.jsx(P, { size: 18 }) }), e.jsxs("div", { className: "flex items-center gap-2 flex-1", children: [e.jsx(E, { size: 20, className: "text-sky-500" }), e.jsx("h1", { className: "font-bold tracking-tight", children: "\u7D4C\u904E\u65E5\u6570\u30C8\u30E9\u30C3\u30AB\u30FC" })] }), e.jsxs("button", { onClick: () => c(T()), className: "flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-gray-900 dark:bg-white text-white dark:text-gray-900 text-sm font-bold hover:opacity-90 transition-opacity", children: [e.jsx(M, { size: 16 }), " \u8FFD\u52A0"] }), e.jsx("button", { onClick: a, className: "p-2 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-800 transition-colors", title: "\u30C6\u30FC\u30DE\u5207\u66FF", children: n === "dark" ? e.jsx(J, { size: 18 }) : e.jsx(V, { size: 18 }) })] }) }), e.jsx("main", { className: "max-w-3xl mx-auto px-4 py-5", children: S.length === 0 ? e.jsxs("div", { children: [e.jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500 mb-3 bg-gray-100/70 dark:bg-gray-800/50 rounded-lg px-3 py-2", children: [e.jsx(E, { size: 14, className: "opacity-60" }), e.jsxs("span", { children: ["\u3053\u308C\u306F\u4F7F\u3044\u65B9\u306E", e.jsx("span", { className: "font-bold", children: "\u4F8B" }), "\u3067\u3059\uFF08\u4FDD\u5B58\u3055\u308C\u3066\u3044\u307E\u305B\u3093\uFF09\u3002\u300C", e.jsx("span", { className: "font-bold", children: "\u8FFD\u52A0" }), "\u300D\u3067\u81EA\u5206\u306E\u30A4\u30D9\u30F3\u30C8\u3092\u767B\u9332\u3059\u308B\u3068\u3001\u3053\u306E\u898B\u672C\u306F\u6D88\u3048\u307E\u3059\u3002"] })] }), e.jsx("div", { className: "space-y-3 select-none", children: W.map((t) => {
const { level: d, ratio: r, elapsed: o } = u(t), i = A[d], x = Math.min(100, Math.round(r * 100));
return e.jsxs("div", { className: `relative rounded-xl bg-white dark:bg-gray-900 border border-dashed ${i.ring} p-4 opacity-60`, children: [e.jsx("span", { className: "absolute top-2 right-2 text-[10px] font-bold text-gray-400 border border-gray-300 dark:border-gray-600 rounded px-1.5 py-0.5", children: "\u4F8B" }), e.jsxs("div", { className: "flex items-start justify-between gap-3 pr-8", children: [e.jsxs("div", { className: "min-w-0", children: [e.jsx("h3", { className: "font-bold text-[15px] truncate", children: t.name }), e.jsxs("p", { className: "text-xs text-gray-500 mt-0.5", children: ["\u76EE\u6A19 ", t.targetCycleDays, "\u65E5\u3054\u3068"] })] }), e.jsxs("div", { className: "text-right shrink-0", children: [e.jsx("div", { className: `text-3xl font-extrabold leading-none ${i.text}`, children: o }), e.jsx("div", { className: "text-[10px] text-gray-400 mt-0.5", children: "\u65E5\u7D4C\u904E" })] })] }), e.jsx("div", { className: "mt-3 h-2 rounded-full bg-gray-100 dark:bg-gray-800 overflow-hidden", children: e.jsx("div", { className: `h-full ${i.bar}`, style: { width: `${x}%` } }) })] }, t.id);
}) }), e.jsx("div", { className: "text-center mt-6", children: e.jsxs("button", { onClick: () => c(T()), className: "inline-flex items-center gap-1.5 px-4 py-2 rounded-lg bg-gray-900 dark:bg-white text-white dark:text-gray-900 text-sm font-bold hover:opacity-90", children: [e.jsx(M, { size: 16 }), " \u81EA\u5206\u306E\u30A4\u30D9\u30F3\u30C8\u3092\u8FFD\u52A0"] }) })] }) : e.jsx("div", { className: "space-y-3", children: S.map((t) => {
const { level: d, ratio: r, elapsed: o } = u(t), i = A[d], x = v.has(t.id), p = Math.min(100, Math.round(r * 100)), m = t.targetCycleDays ? t.targetCycleDays - o : null;
return e.jsxs("div", { className: `rounded-xl bg-white dark:bg-gray-900 border ${i.ring} overflow-hidden`, children: [e.jsxs("div", { className: "p-4", children: [e.jsxs("div", { className: "flex items-start justify-between gap-3", children: [e.jsxs("div", { className: "min-w-0 flex-1", children: [e.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [e.jsx("h3", { className: "font-bold text-[15px] truncate", children: t.name }), i.label && e.jsx("span", { className: `text-[10px] font-bold px-1.5 py-0.5 rounded ${i.text} bg-current/10`, children: e.jsx("span", { className: i.text, children: i.label }) })] }), e.jsxs("p", { className: "text-xs text-gray-500 mt-0.5", children: ["\u524D\u56DE ", $(t.lastDone), t.targetCycleDays ? ` \u30FB \u76EE\u6A19 ${t.targetCycleDays}\u65E5\u3054\u3068` : " \u30FB \u76EE\u6A19\u306A\u3057"] })] }), e.jsxs("div", { className: "text-right shrink-0", children: [e.jsx("div", { className: `text-3xl font-extrabold leading-none ${i.text}`, children: o }), e.jsx("div", { className: "text-[10px] text-gray-400 mt-0.5", children: "\u65E5\u7D4C\u904E" })] })] }), t.targetCycleDays && e.jsxs("div", { className: "mt-3", children: [e.jsx("div", { className: "h-2 rounded-full bg-gray-100 dark:bg-gray-800 overflow-hidden", children: e.jsx("div", { className: `h-full ${i.bar} transition-all`, style: { width: `${p}%` } }) }), e.jsxs("div", { className: "flex justify-between text-[10px] text-gray-400 mt-1", children: [e.jsxs("span", { children: [p, "%"] }), e.jsx("span", { children: m !== null && m >= 0 ? `\u3042\u3068 ${m} \u65E5` : `${Math.abs(m ?? 0)} \u65E5 \u8D85\u904E` })] })] }), e.jsxs("div", { className: "mt-3 flex items-center gap-2", children: [e.jsxs("button", { onClick: () => L(t.id), className: "flex-1 flex items-center justify-center gap-1.5 py-2.5 rounded-lg bg-gray-900 dark:bg-white text-white dark:text-gray-900 text-sm font-bold hover:opacity-90 active:scale-[0.99] transition-all", children: [e.jsx(w, { size: 16 }), " \u4ECA\u3084\u3063\u305F\uFF01"] }), e.jsx("button", { onClick: () => O(t.id), className: "p-2.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-500 hover:bg-gray-50 dark:hover:bg-gray-800", title: "\u5C65\u6B74", children: x ? e.jsx(X, { size: 16 }) : e.jsx(B, { size: 16 }) }), e.jsx("button", { onClick: () => {
var _a;
return c({ id: t.id, name: t.name, cycleRaw: ((_a = t.targetCycleDays) == null ? void 0 : _a.toString()) ?? "", lastDone: t.lastDone });
}, className: "p-2.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-500 hover:bg-gray-50 dark:hover:bg-gray-800", title: "\u7DE8\u96C6", children: e.jsx(G, { size: 16 }) }), e.jsx("button", { onClick: () => _(t.id), className: "p-2.5 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-500 hover:text-red-500 hover:border-red-300", title: "\u524A\u9664", children: e.jsx(H, { size: 16 }) })] })] }), x && e.jsxs("div", { className: "px-4 pb-4 pt-1 border-t border-gray-100 dark:border-gray-800", children: [e.jsxs("div", { className: "flex items-center gap-1.5 text-xs font-bold text-gray-500 mt-3 mb-2", children: [e.jsx(K, { size: 13 }), " \u5B9F\u884C\u5C65\u6B74"] }), t.history.length === 0 ? e.jsx("p", { className: "text-xs text-gray-400", children: "\u5C65\u6B74\u306F\u3042\u308A\u307E\u305B\u3093\u3002" }) : e.jsx("ul", { className: "space-y-1.5", children: t.history.slice(0, 8).map((N, z) => e.jsxs("li", { className: "flex items-center gap-2 text-sm", children: [e.jsx("span", { className: `w-1.5 h-1.5 rounded-full ${z === 0 ? "bg-sky-500" : "bg-gray-300 dark:bg-gray-600"}` }), e.jsx("span", { className: "text-gray-700 dark:text-gray-300", children: $(N) }), e.jsxs("span", { className: "text-xs text-gray-400", children: ["\uFF08", I(N), "\u65E5\u524D\uFF09"] })] }, N + z)) })] })] }, t.id);
}) }) }), l && e.jsx("div", { className: "fixed inset-0 z-40 flex items-end sm:items-center justify-center bg-black/50 backdrop-blur-sm p-0 sm:p-4", onClick: () => c(null), children: e.jsxs("div", { className: "w-full sm:max-w-md bg-white dark:bg-gray-900 rounded-t-2xl sm:rounded-2xl border border-gray-200 dark:border-gray-800 shadow-2xl", onClick: (t) => t.stopPropagation(), children: [e.jsxs("div", { className: "flex items-center justify-between px-5 py-3 border-b border-gray-200 dark:border-gray-800", children: [e.jsx("h2", { className: "font-bold", children: l.id ? "\u30A4\u30D9\u30F3\u30C8\u3092\u7DE8\u96C6" : "\u30A4\u30D9\u30F3\u30C8\u3092\u8FFD\u52A0" }), e.jsx("button", { onClick: () => c(null), className: "p-1.5 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-500", children: e.jsx(q, { size: 18 }) })] }), e.jsxs("div", { className: "p-5 space-y-3", children: [e.jsxs("div", { children: [e.jsx("label", { className: "block text-xs font-bold text-gray-500 mb-1", children: "\u30A4\u30D9\u30F3\u30C8\u540D" }), e.jsx("input", { autoFocus: true, value: l.name, onChange: (t) => c({ ...l, name: t.target.value }), placeholder: "\u4F8B\uFF1A\u611B\u72AC\u306E\u30B7\u30E3\u30F3\u30D7\u30FC", className: "w-full px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 outline-none focus:border-gray-400 text-sm" })] }), e.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [e.jsxs("div", { children: [e.jsxs("label", { className: "block text-xs font-bold text-gray-500 mb-1", children: ["\u76EE\u6A19\u5468\u671F\uFF08\u65E5\uFF09", e.jsx("span", { className: "font-normal text-gray-400", children: "\u4EFB\u610F" })] }), e.jsx("input", { type: "number", min: "1", value: l.cycleRaw, onChange: (t) => c({ ...l, cycleRaw: t.target.value }), placeholder: "\u4F8B\uFF1A30", className: "w-full px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 outline-none focus:border-gray-400 text-sm" })] }), e.jsxs("div", { children: [e.jsx("label", { className: "block text-xs font-bold text-gray-500 mb-1", children: "\u524D\u56DE\u5B9F\u884C\u65E5" }), e.jsx("input", { type: "date", value: l.lastDone, max: f(), onChange: (t) => c({ ...l, lastDone: t.target.value }), className: "w-full px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 outline-none focus:border-gray-400 text-sm" })] })] })] }), e.jsxs("div", { className: "flex items-center justify-end gap-2 px-5 py-3 border-t border-gray-200 dark:border-gray-800", children: [e.jsx("button", { onClick: () => c(null), className: "px-4 py-2 rounded-lg text-sm font-bold text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800", children: "\u30AD\u30E3\u30F3\u30BB\u30EB" }), e.jsxs("button", { onClick: U, className: "flex items-center gap-1.5 px-4 py-2 rounded-lg bg-gray-900 dark:bg-white text-white dark:text-gray-900 text-sm font-bold hover:opacity-90", children: [e.jsx(w, { size: 16 }), " \u4FDD\u5B58"] })] })] }) }), D && e.jsxs("div", { className: "fixed bottom-6 left-1/2 -translate-x-1/2 z-50 flex items-center gap-2 bg-gray-900 dark:bg-white text-white dark:text-gray-900 px-4 py-2 rounded-full shadow-lg text-sm font-bold", children: [e.jsx(w, { size: 16, className: "text-green-400 dark:text-green-600" }), " ", D] })] });
}
export {
xe as default
};