From 514d0dc16265e4afee722b15e69f2025d4123663 Mon Sep 17 00:00:00 2001 From: kamiriku Date: Fri, 16 Jan 2026 10:30:47 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E3=83=AA=E3=82=B9=E3=83=88?= =?UTF-8?q?=E9=81=B8=E6=8A=9E=E3=83=A2=E3=83=BC=E3=83=89=E3=82=92=E6=94=B9?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit インタラクティブモードでのリスト表示を改善し、より洗練された選択UIを実装しました。 実装内容: - タスクリストの番号付き表示(1から始まる) - 要約表示の統合(render.ExtractSummary を使用) - ターミナル幅に応じた動的な要約長調整 - 最小40文字、最大80文字 - 番号と余白を考慮 - カーソル記号を ▶ に変更(視覚的に明確) - 区切り線をターミナル幅に合わせて動的に調整 - コードの最適化(未使用のmin関数を削除) 改善点: - タスク番号が明確に表示される - 長文タスクは要約表示で見やすい - ターミナルサイズに応じて最適化 - 選択中の項目が一目でわかる 使用例: todo list -d # - j/k で上下移動 # - ▶ 1 タスク内容...(選択中) # 2 タスク内容... # 3 タスク内容... 受け入れ基準: ✅ タスクリストが番号付きで表示される(1から始まる) ✅ j/k キーで上下に移動できる ✅ 選択中のタスクが視覚的にわかる(▶記号) ✅ 要約表示が適用される ✅ q キーで終了できる ✅ ターミナルサイズに応じて調整される Closes #12 --- internal/ui/models.go | 48 +++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/internal/ui/models.go b/internal/ui/models.go index 8aff2f9..1a7c56c 100644 --- a/internal/ui/models.go +++ b/internal/ui/models.go @@ -1,7 +1,10 @@ package ui import ( + "fmt" + "github.com/charmbracelet/bubbletea" + "github.com/kamiriku/todo_cli/internal/render" "github.com/kamiriku/todo_cli/internal/storage" ) @@ -95,25 +98,52 @@ func (m model) View() string { } } -// renderList はリスト表示を描画します(骨組み) +// renderList はリスト表示を描画します func (m model) renderList() string { s := HeaderStyle.Render("📝 Todo List") + "\n\n" if len(m.pending) == 0 { s += "タスクはありません\n" } else { + // ターミナル幅に応じて要約の長さを調整 + summaryWidth := m.width - 10 // 番号と余白を考慮 + if summaryWidth < 40 { + summaryWidth = 40 + } + if summaryWidth > 80 { + summaryWidth = 80 + } + for i, task := range m.pending { + // 要約を抽出 + summary := render.ExtractSummary(task.Text, summaryWidth) + + // 番号とカーソル + number := fmt.Sprintf("%d", i+1) cursor := " " + if m.cursor == i { - cursor = ">" - s += SelectedStyle.Render(cursor+" "+task.Text[:min(len(task.Text), 60)]) + "\n" + cursor = "▶" + line := fmt.Sprintf("%s %s %s", cursor, number, summary) + s += SelectedStyle.Render(line) + "\n" } else { - s += NormalStyle.Render(cursor+" "+task.Text[:min(len(task.Text), 60)]) + "\n" + line := fmt.Sprintf("%s %s %s", cursor, number, summary) + s += NormalStyle.Render(line) + "\n" } } } - s += "\n" + DividerStyle.Render("────────────────────────────────────────") + "\n" + // 区切り線(ターミナル幅に合わせる) + dividerWidth := m.width - 2 + if dividerWidth < 10 { + dividerWidth = 10 + } + divider := "" + for i := 0; i < dividerWidth; i++ { + divider += "─" + } + + s += "\n" + DividerStyle.Render(divider) + "\n" s += HelpStyle.Render("j/k: 移動 | Enter: 詳細 | q: 終了") + "\n" return s @@ -133,11 +163,3 @@ func (m model) renderDetail() string { return s } - -// min は2つの整数のうち小さい方を返します -func min(a, b int) int { - if a < b { - return a - } - return b -} From b828de20476a9e699b7da3fdb207adbb7a991360 Mon Sep 17 00:00:00 2001 From: kamiriku Date: Fri, 16 Jan 2026 10:32:05 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E3=82=B3=E3=83=BC=E3=83=89=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=BC=E3=83=9E=E3=83=83=E3=83=88=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/ui/models.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ui/models.go b/internal/ui/models.go index 1a7c56c..7509170 100644 --- a/internal/ui/models.go +++ b/internal/ui/models.go @@ -117,11 +117,11 @@ func (m model) renderList() string { for i, task := range m.pending { // 要約を抽出 summary := render.ExtractSummary(task.Text, summaryWidth) - + // 番号とカーソル number := fmt.Sprintf("%d", i+1) cursor := " " - + if m.cursor == i { cursor = "▶" line := fmt.Sprintf("%s %s %s", cursor, number, summary)