文書バージョン: 1.0
作成日: 2026-03-26
対象: ローカル動作のシングルページWebアプリケーション
本アプリは、「積読(読んでいない本)」を視覚的に管理するためのパーソナル用ローカルWebアプリである。複数の「積読の山(スタック)」をカラムとして横並びに表示し、本をスタック構造で管理する。ブラウザ上で完結し、外部サーバーへの依存はない。
| 用語 | 定義 |
|---|---|
| 山 (Stack) | 本を積み重ねて管理するカラム単位の構造体 |
| 本 (Book) | 積読の管理対象となる1件のエントリ |
| Push | 山の一番上に本を追加する操作 |
| Peek | 山の一番上の本の詳細を参照する操作(データは変化しない) |
| Pop | 山の一番上の本を削除(読了・破棄)する操作 |
全データはブラウザの localStorage に保存する。ページを開くたびに localStorage から読み込み、操作のたびに即時書き込みを行う。外部ファイルへの入出力は行わない。
localStorage のキー名は tsundoku-data とする。
{
"stacks": [
{
"id": "string(UUID)",
"title": "string(山の表題)",
"books": [
{
"id": "string(UUID)",
"title": "string(本のタイトル)",
"estimatedMinutes": "number(必要時間、分単位)",
"link": "string(URL、空文字可)",
"isImportant": "boolean(重要フラグ)",
"addedAt": "string(ISO 8601形式の日時)"
}
]
}
]
}本 (Book) の項目:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
id |
string | ✓ | アプリ内で一意のUUID |
title |
string | ✓ | 本のタイトル(最大200文字) |
estimatedMinutes |
number | ✓ | 読了に要する時間(分単位、0以上の整数) |
link |
string | — | 参考URL(Amazon、書評ページ等)。未入力の場合は空文字 |
isImportant |
boolean | ✓ | 重要フラグ。true の場合にバッジを表示 |
addedAt |
string | ✓ | 追加日時(ISO 8601) |
山 (Stack) の項目:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
id |
string | ✓ | アプリ内で一意のUUID |
title |
string | ✓ | 山の分類名(最大50文字) |
books |
array | ✓ | 本の配列。インデックス0が「一番上」 |
スタックに対して許可される操作は以下の3種類のみとする。任意の位置への挿入・並び替えは行わない。
山のヘッダにある「+」ボタンを押すと、本の追加フォームをモーダルで表示する。フォームには以下の入力欄を設ける。
- タイトル(テキスト、必須)
- 必要時間(数値入力、分単位、必須)
- リンク(URL、任意)
- 重要フラグ(チェックボックス)
送信後、入力した本を books 配列の先頭(インデックス0)に追加し、localStorage を即時更新する。
山の一番上(books[0])のカードに表示された「詳細」ボタン、または山のヘッダにある「Peek」ボタンを押すと、その本の全フィールドをモーダルで表示する。link が設定されている場合は外部リンクとして表示する。データへの変更は発生しない。
山のヘッダにある「Pop」ボタンを押すと、確認ダイアログを表示する。ユーザーが確認した場合のみ books[0] を削除し、localStorage を即時更新する。山が空の場合、Pop ボタンは無効化(グレーアウト)する。
- 山の追加: 画面右端に「+ 新しい山を追加」ボタンを常時表示する。クリックするとタイトル入力を求めるインラインフォームまたはモーダルを表示し、空のスタックを追加する。
- 山の削除: 山が空の場合にのみ削除ボタンを表示する。本が1冊以上存在する山は削除不可とする。
- 山のタイトル変更: 山のヘッダのタイトルをダブルクリックするとインライン編集が可能になる。
各山のヘッダには以下の情報を表示する。
- 山のタイトル(分類名)
- 積冊数(例:
3 冊) - 合計必要時間(例:
計 5h 30m)。合計が60分未満の場合は分のみで表示(例:計 45m) - Push / Peek / Pop の操作ボタン
一番上の本(books[0])を「トップカード」として他のカードより目立つ形でレンダリングする。2枚目以降のカードは簡略表示(タイトルのみ)で積み重ね表現を行う。
各カードには以下を表示する。
- タイトル
- 必要時間(例:
2h 00m) isImportant: trueの場合: 「重要」バッジ(目立つ色のラベル)linkが設定されている場合: リンクアイコン
- 画面全体は横スクロールのレイアウトとする。
- 各山はカラムとして横並びに表示し、最小幅は280px、最大幅は320pxを基準とする。
- カラム間の余白は20px程度とする。
「落ち着いた・静謐な」トーンを目指す。具体的には以下を基準とする。
| 役割 | 方針 |
|---|---|
| 背景 | 温かみのあるオフホワイト、あるいはダークモードに対応したダークグレー |
| カラムヘッダ | 淡いセージグリーン、スレートブルーなどのアースカラー |
| 本カード(トップ) | 白またはライトクリーム、ほのかな影付き |
| 本カード(2枚目以降) | やや暗め・小さめで奥行き表現 |
| 「重要」バッジ | テラコッタ・深紅などの落ち着いたアクセントカラー |
| ボタン類 | モノトーン系のシンプルなアウトラインスタイル |
- 全モーダルはオーバーレイ背景付きで表示し、背景クリックまたは「✕」ボタンで閉じる。
- Pop の確認ダイアログは誤操作防止のため必ず表示する。
- localStorage への保存は各操作の直後に同期的に行い、ページリロード後も状態が維持されることを保証する。
| 項目 | 内容 |
|---|---|
| 実装形式 | シングルHTMLファイル(HTML / CSS / JavaScript をインライン統合) |
| フレームワーク | Vanilla JS(フレームワーク不使用)または軽量ライブラリ |
| データ保存 | window.localStorage(キー: tsundoku-data) |
| ID生成 | crypto.randomUUID() を使用 |
| ブラウザ互換 | モダンブラウザ(Chrome / Firefox / Safari 最新版)を対象とする |
| サーバー不要 | HTMLファイルをローカルでダブルクリック起動で動作すること |
localStorageの読み込み時にパースエラーが発生した場合、データを初期化してから起動する。- Push フォームで必須項目が未入力の場合、バリデーションエラーをフォーム内にインライン表示する。
linkフィールドに不正なURL形式が入力された場合、警告を表示するが保存は許可する(ユーザーの柔軟性を優先)。
以下は現バージョンでは実装しないが、今後の検討候補として記録する。
- JSONファイルへのエクスポート・インポート機能
- 山間での本の移動機能
- 読了済みアーカイブ機能
- タグ・メモフィールドの追加
- ダークモード切り替えトグル