{"version":3,"file":"Todo-Cn2jtMV4.cjs","sources":["../app/components/todo/Todo.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nexport type TodoItem = {\n  id: string;\n  title: string;\n  done: boolean;\n};\n\nfunction createId(): string {\n  return Math.random().toString(36).slice(2, 9);\n}\n\nconst STORAGE_KEY = \"ee.todo.items.v1\";\nconst TTL_MS = 4 * 60 * 60 * 1000; // 4 hours\n\ntype StoredTodo = { items: TodoItem[]; expiresAt: number };\n\nfunction readFromStorage(): TodoItem[] {\n  try {\n    if (typeof window === \"undefined\") return [];\n    const raw = localStorage.getItem(STORAGE_KEY);\n    if (!raw) return [];\n    const parsed = JSON.parse(raw);\n    // Backward compatibility: older versions stored an array directly\n    if (Array.isArray(parsed)) return parsed as TodoItem[];\n    if (\n      parsed &&\n      typeof parsed === \"object\" &&\n      Array.isArray((parsed as StoredTodo).items)\n    ) {\n      const expiresAt = (parsed as StoredTodo).expiresAt;\n      if (typeof expiresAt === \"number\" && expiresAt > Date.now()) {\n        return (parsed as StoredTodo).items;\n      }\n      // Expired\n      localStorage.removeItem(STORAGE_KEY);\n      return [];\n    }\n  } catch {}\n  return [];\n}\n\nfunction writeToStorage(items: TodoItem[]): void {\n  try {\n    if (typeof window === \"undefined\") return;\n    const payload: StoredTodo = {\n      items,\n      // Rolling TTL: extend on each change\n      expiresAt: Date.now() + TTL_MS,\n    };\n    localStorage.setItem(STORAGE_KEY, JSON.stringify(payload));\n  } catch {}\n}\n\nexport default function Todo() {\n  const [items, setItems] = useState<TodoItem[]>(() => readFromStorage());\n  const inputRef = useRef<HTMLInputElement | null>(null);\n\n  // Persist to localStorage with TTL\n  useEffect(() => {\n    writeToStorage(items);\n  }, [items]);\n\n  const visibleItems = useMemo(() => items, [items]);\n\n  function addItem(title: string) {\n    const trimmed = title.trim();\n    if (!trimmed) return;\n    setItems((prev) => [\n      { id: createId(), title: trimmed, done: false },\n      ...prev,\n    ]);\n  }\n\n  function toggleItem(id: string) {\n    setItems((prev) =>\n      prev.map((t) => (t.id === id ? { ...t, done: !t.done } : t))\n    );\n  }\n\n  function removeItem(id: string) {\n    setItems((prev) => prev.filter((t) => t.id !== id));\n  }\n\n  function handleSubmit(e: React.FormEvent) {\n    e.preventDefault();\n    const value = (inputRef.current?.value ?? \"\").trim();\n    if (value) {\n      addItem(value);\n      if (inputRef.current) inputRef.current.value = \"\";\n    }\n  }\n\n  return (\n    <div className=\"flex h-full w-full flex-col gap-3\">\n      <form\n        onSubmit={handleSubmit}\n        className=\"flex flex-col sm:flex-row gap-2\"\n        aria-label=\"Add todo\"\n      >\n        <input\n          ref={inputRef}\n          type=\"text\"\n          placeholder=\"Add a task and press Enter\"\n          className=\"h-10 w-full sm:flex-1 rounded-md border border-[--color-border] bg-background px-3 text-[color:var(--color-foreground)] placeholder-[color:var(--color-muted-foreground)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent]\"\n          aria-label=\"New task\"\n        />\n        <button\n          type=\"submit\"\n          className=\"h-10 w-full sm:w-auto px-3 rounded-md bg-[--color-accent] text-[--color-accent-foreground] hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent]\"\n          aria-label=\"Add task\"\n        >\n          Add\n        </button>\n      </form>\n\n      <ul className=\"flex-1 overflow-auto divide-y divide-[--color-border] rounded-md border border-[--color-border] bg-card\">\n        {visibleItems.length === 0 ? (\n          <li className=\"p-4 text-sm text-[color:var(--color-muted-foreground)]\">\n            No tasks\n          </li>\n        ) : (\n          visibleItems.map((t) => (\n            <li key={t.id} className=\"group flex items-center gap-3 p-2\">\n              <label className=\"flex items-center gap-2 cursor-pointer select-none\">\n                <input\n                  type=\"checkbox\"\n                  checked={t.done}\n                  onChange={() => toggleItem(t.id)}\n                  aria-label={t.title}\n                  className=\"h-4 w-4 accent-[--color-accent]\"\n                />\n                <span\n                  className={t.done ? \"line-through opacity-70\" : undefined}\n                >\n                  {t.title}\n                </span>\n              </label>\n              <button\n                type=\"button\"\n                onClick={() => removeItem(t.id)}\n                className=\"ml-auto h-8 px-2 rounded-md bg-surface hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent] opacity-0 group-hover:opacity-100\"\n                aria-label={`Delete ${t.title}`}\n                title=\"Delete\"\n              >\n                Delete\n              </button>\n            </li>\n          ))\n        )}\n      </ul>\n    </div>\n  );\n}\n"],"names":["createId","STORAGE_KEY","TTL_MS","readFromStorage","raw","parsed","expiresAt","writeToStorage","items","payload","Todo","setItems","useState","inputRef","useRef","useEffect","visibleItems","useMemo","addItem","title","trimmed","prev","toggleItem","id","t","removeItem","handleSubmit","value","jsxs","jsx"],"mappings":"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"}