Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 95 additions & 17 deletions internal/ui/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,46 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

// handleKeyPress はキー入力を処理します
func (m model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
// 詳細表示モード時の特別なキーバインド
if m.currentMode == modeDetail {
switch msg.String() {
case "ctrl+c":
m.quitting = true
return m, tea.Quit
case "q", "esc":
// リスト選択モードに戻る
m.currentMode = modeList
m.updatePreview()
return m, nil
case "g":
// 先頭へジャンプ
m.viewport.GotoTop()
return m, nil
case "G":
// 末尾へジャンプ
m.viewport.GotoBottom()
return m, nil
case "j", "down":
// 下にスクロール
m.viewport.LineDown(1)
return m, nil
case "k", "up":
// 上にスクロール
m.viewport.LineUp(1)
return m, nil
case "d":
// 半ページ下にスクロール
m.viewport.HalfViewDown()
return m, nil
case "u":
// 半ページ上にスクロール
m.viewport.HalfViewUp()
return m, nil
}
return m, nil
}

// リスト選択モード時のキーバインド
switch msg.String() {
case "ctrl+c", "q":
m.quitting = true
Expand All @@ -98,17 +138,9 @@ func (m model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
m.updatePreview() // プレビューを更新
}
case "enter":
// 詳細表示への切り替え(後で実装)
if m.currentMode == modeList {
m.currentMode = modeDetail
} else {
m.currentMode = modeList
}
case "esc":
// リスト表示に戻る
if m.currentMode == modeDetail {
m.currentMode = modeList
}
// 詳細表示への切り替え
m.currentMode = modeDetail
m.updateDetailView()
}
return m, nil
}
Expand Down Expand Up @@ -151,6 +183,36 @@ func (m *model) updatePreview() {
m.viewport.SetContent(rendered)
}

// updateDetailView は詳細表示モードのビューを更新します
func (m *model) updateDetailView() {
if !m.ready || len(m.pending) == 0 || m.cursor >= len(m.pending) {
m.viewport.SetContent("タスクが見つかりません")
return
}

task := m.pending[m.cursor]

// 詳細表示用のviewportサイズを調整(全画面に近い)
detailHeight := m.height - 6 // ヘッダーとヘルプを考慮
if detailHeight < 10 {
detailHeight = 10
}
m.viewport.Width = m.width - 4
m.viewport.Height = detailHeight

// Markdownをレンダリング(全画面用)
rendered, err := render.RenderMarkdown(task.Text, m.width-4)
if err != nil {
// エラー時は生テキストを表示
m.viewport.SetContent(task.Text)
} else {
m.viewport.SetContent(rendered)
}

// 先頭にジャンプ
m.viewport.GotoTop()
}

// renderList はリスト表示を描画します(プレビュー付き2ペイン表示)
func (m model) renderList() string {
var s strings.Builder
Expand Down Expand Up @@ -237,17 +299,33 @@ func (m model) renderList() string {
return s.String()
}

// renderDetail は詳細表示を描画します(骨組み)
// renderDetail は詳細表示を描画します(全画面表示)
func (m model) renderDetail() string {
if m.cursor >= len(m.pending) {
return "タスクが見つかりません\n"
}

task := m.pending[m.cursor]
var s strings.Builder

// ヘッダー(タスク番号と情報)
taskNum := fmt.Sprintf("Task #%d/%d", m.cursor+1, len(m.pending))
s.WriteString(DetailHeaderStyle.Render(taskNum) + "\n\n")

// viewport で全画面表示
if m.ready {
s.WriteString(m.viewport.View() + "\n")
}

s := HeaderStyle.Render("📄 Task Detail") + "\n\n"
s += DetailStyle.Render(task.Text) + "\n\n"
s += HelpStyle.Render("Esc/Enter: 戻る | q: 終了") + "\n"
// 区切り線
dividerWidth := m.width - 2
if dividerWidth < 10 {
dividerWidth = 10
}
divider := strings.Repeat("─", dividerWidth)
s.WriteString("\n" + DividerStyle.Render(divider) + "\n")

return s
// ヘルプ
s.WriteString(HelpStyle.Render("j/k: スクロール | g/G: 先頭/末尾 | d/u: 半ページ | q/Esc: 戻る") + "\n")

return s.String()
}
7 changes: 7 additions & 0 deletions internal/ui/styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,11 @@ var (
Foreground(lipgloss.Color("15")).
Background(lipgloss.Color("99")).
Padding(0, 1)

// DetailHeaderStyle は詳細表示ヘッダー用のスタイル
DetailHeaderStyle = lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("15")).
Background(lipgloss.Color("33")).
Padding(0, 1)
)
Loading