ブラウザだけで動く日記アプリ。月カレンダーから日付を選んで書く、データは localStorage に保存 されてサーバには 1 byte も送らない。連続日数 (streak) と総文字数を表示。JSON 形式でのエクスポート / インポートで端末間移行も可能。
npm run serve # python3 -m http.server 8096
# open http://localhost:8096ブラウザの localStorage に保存するので、別のブラウザ / 端末で開くと別のデータになる。共有したいときは JSON エクスポート → 移行先で JSON インポート。
- 月カレンダー UI: 6 行 × 7 列のグリッド、前月末・翌月頭の adjacent 日も描画 (Sunday-first)
- 日付クリック → エディタにその日のエントリをロード
- 入力 → 280 ms debounce → localStorage 保存。空文字列なら削除 (key 自体が消える)
- stat 行 に「記録した日数 / 連続日数 (現在) / 最長連続 / 総文字数」を即時計算で表示
- JSON エクスポート / インポート で端末間移行と backup を可能に
diary.js は DOM 非依存 (localStorage を直接触らず、Storage-like オブジェクトを受け取る形):
formatDate(d)/parseDate(iso)— UTC ベースの ISO 日付変換keyForDate(iso)/isDiaryKey(k)/dateFromKey(k)—diary:YYYY-MM-DDkey のラップmonthGrid(year, month, todayIso?, weekStart?)— 6×7 のセル配列 ({iso, day, inMonth, isToday})characterCount(text)— code-point ベースの文字数 (CJK / emoji 1 字 = 1)daysBetween(a, b)— 符号付き日数差currentStreak(dates, todayIso)/longestStreak(dates)— 連続日数totalCharacters(entries)— 全エントリの合計文字数readEntries(storageLike)— localStorage 互換オブジェクトから iso → text を抽出
script.js は DOM と localStorage の I/O だけを持ち、計算は全部 diary.js 経由。
npm test20 ケース、テストフレームワーク不要 (node --test)。localStorage / DOM は触らず、ピュアロジック側を覆っている:
- 日付変換: Date と
{year, month, day}両対応、UTC ベース、malformed 入力の rejection - monthGrid: 6×7 セル数、in-month 数 (31 日月で 31)、weekStart=0/1、年またぎ
- characterCount: code-point ベース (CJK / emoji)、whitespace の trim/collapse、non-string → 0
- streak: 4 連続が 4 と評価される、today なしで 0、途中の missing day で break
- longestStreak: 複数の run の中で最大、空 / 1 件のエッジケース
- readEntries: Storage-like API、prefix フィルタ、空文字列を除外、malformed input → {}
- 複数行エントリの Markdown レンダリング — 日記は素の text で十分という判断。プレビューが欲しいなら別エントリの仕事
- 画像添付 — localStorage に base64 で保存すると 5 MB のクォータをすぐ食う。IndexedDB に書く形なら可能だが、複雑度が上がる
- タグ付け / 検索 — 一覧性は月カレンダーで足りるという仮定。エントリ数が 1000 を超えたら必要になるかも
- 暗号化 — localStorage は同じドメインの JS から全部読める。完全に保護したいならクライアント側 AES-GCM + ユーザーパスフレーズが要るが、本ツールのスコープ外
MIT — see LICENSE.
