mirror of
https://github.com/RWejlgaard/org.git
synced 2026-05-06 04:34:45 +00:00
readme and keybindings improvements
This commit is contained in:
parent
097703beda
commit
8f6ec4a79f
5 changed files with 180 additions and 17 deletions
BIN
.imgs/priority_prompt.png
Normal file
BIN
.imgs/priority_prompt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
|
|
@ -70,7 +70,7 @@ org # Opens ./todo.org by default
|
|||
| `p` | Set priority |
|
||||
| `e` | Set effort |
|
||||
| `r` | Toggle reorder mode |
|
||||
| `shift+↑/↓` | Move item up/down (in reorder mode) |
|
||||
| `shift+↑/↓` | Move item up/down |
|
||||
| `ctrl+s` | Save |
|
||||
| `?` | Toggle help |
|
||||
| `q` or `ctrl+c` | Quit |
|
||||
|
|
@ -89,6 +89,7 @@ Changes are automatically saved when you quit the application.
|
|||
### Prompts
|
||||

|
||||

|
||||

|
||||
|
||||
## File Format
|
||||
|
||||
|
|
|
|||
|
|
@ -22,24 +22,26 @@ const (
|
|||
modeSetDeadline
|
||||
modeSetPriority
|
||||
modeSetEffort
|
||||
modeHelp
|
||||
)
|
||||
|
||||
type uiModel struct {
|
||||
orgFile *model.OrgFile
|
||||
cursor int
|
||||
scrollOffset int // Track the scroll position
|
||||
mode viewMode
|
||||
help help.Model
|
||||
keys keyMap
|
||||
width int
|
||||
height int
|
||||
statusMsg string
|
||||
statusExpiry time.Time
|
||||
editingItem *model.Item
|
||||
textarea textarea.Model
|
||||
textinput textinput.Model
|
||||
itemToDelete *model.Item
|
||||
reorderMode bool
|
||||
orgFile *model.OrgFile
|
||||
cursor int
|
||||
scrollOffset int // Track the scroll position
|
||||
helpScroll int // Track scroll position in help mode
|
||||
mode viewMode
|
||||
help help.Model
|
||||
keys keyMap
|
||||
width int
|
||||
height int
|
||||
statusMsg string
|
||||
statusExpiry time.Time
|
||||
editingItem *model.Item
|
||||
textarea textarea.Model
|
||||
textinput textinput.Model
|
||||
itemToDelete *model.Item
|
||||
reorderMode bool
|
||||
}
|
||||
|
||||
func initialModel(orgFile *model.OrgFile) uiModel {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
return m.updateSetPriority(msg)
|
||||
case modeSetEffort:
|
||||
return m.updateSetEffort(msg)
|
||||
case modeHelp:
|
||||
return m.updateHelp(msg)
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
|
|
@ -48,7 +50,8 @@ func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
return m, tea.Quit
|
||||
|
||||
case key.Matches(msg, m.keys.Help):
|
||||
m.help.ShowAll = !m.help.ShowAll
|
||||
m.mode = modeHelp
|
||||
m.helpScroll = 0 // Reset scroll when entering help
|
||||
return m, nil
|
||||
|
||||
case key.Matches(msg, m.keys.Up):
|
||||
|
|
@ -733,3 +736,41 @@ func (m *uiModel) swapItems(item1, item2 *model.Item) {
|
|||
}
|
||||
swapInList(m.orgFile.Items)
|
||||
}
|
||||
|
||||
func (m uiModel) updateHelp(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
m.height = msg.Height
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "?", "esc", "q":
|
||||
m.mode = modeList
|
||||
m.helpScroll = 0 // Reset scroll when exiting
|
||||
return m, nil
|
||||
case "up", "k":
|
||||
if m.helpScroll > 0 {
|
||||
m.helpScroll--
|
||||
}
|
||||
return m, nil
|
||||
case "down", "j":
|
||||
m.helpScroll++
|
||||
// The view will handle clamping to max scroll
|
||||
return m, nil
|
||||
case "pageup":
|
||||
m.helpScroll -= 10
|
||||
if m.helpScroll < 0 {
|
||||
m.helpScroll = 0
|
||||
}
|
||||
return m, nil
|
||||
case "pagedown":
|
||||
m.helpScroll += 10
|
||||
return m, nil
|
||||
case "home", "g":
|
||||
m.helpScroll = 0
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ func (m uiModel) View() string {
|
|||
return m.viewSetPriority()
|
||||
case modeSetEffort:
|
||||
return m.viewSetEffort()
|
||||
case modeHelp:
|
||||
return m.viewHelp()
|
||||
}
|
||||
|
||||
// Build footer (status + help)
|
||||
|
|
@ -421,6 +423,123 @@ func (m uiModel) viewSetEffort() string {
|
|||
return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, dialog)
|
||||
}
|
||||
|
||||
func (m uiModel) viewHelp() string {
|
||||
// Build the full help content first
|
||||
var lines []string
|
||||
|
||||
// Title
|
||||
lines = append(lines, titleStyle.Render("Keybindings Help"))
|
||||
lines = append(lines, "")
|
||||
|
||||
// Group bindings by category
|
||||
navigationBindings := []key.Binding{m.keys.Up, m.keys.Down, m.keys.Left, m.keys.Right}
|
||||
itemBindings := []key.Binding{m.keys.ToggleFold, m.keys.EditNotes, m.keys.CycleState}
|
||||
taskBindings := []key.Binding{m.keys.Capture, m.keys.AddSubTask, m.keys.Delete}
|
||||
timeBindings := []key.Binding{m.keys.ClockIn, m.keys.ClockOut, m.keys.SetDeadline, m.keys.SetEffort}
|
||||
organizationBindings := []key.Binding{m.keys.SetPriority, m.keys.ShiftUp, m.keys.ShiftDown, m.keys.ToggleReorder}
|
||||
viewBindings := []key.Binding{m.keys.ToggleView, m.keys.Save, m.keys.Help, m.keys.Quit}
|
||||
|
||||
// Helper function to render a binding
|
||||
renderBinding := func(b key.Binding) string {
|
||||
keyStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).Bold(true)
|
||||
descStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("245"))
|
||||
help := b.Help()
|
||||
return fmt.Sprintf(" %s %s", keyStyle.Render(help.Key), descStyle.Render(help.Desc))
|
||||
}
|
||||
|
||||
// Render categories
|
||||
categoryStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("214")).Bold(true)
|
||||
|
||||
lines = append(lines, categoryStyle.Render("Navigation"))
|
||||
for _, binding := range navigationBindings {
|
||||
lines = append(lines, renderBinding(binding))
|
||||
}
|
||||
lines = append(lines, "")
|
||||
|
||||
lines = append(lines, categoryStyle.Render("Item Actions"))
|
||||
for _, binding := range itemBindings {
|
||||
lines = append(lines, renderBinding(binding))
|
||||
}
|
||||
lines = append(lines, "")
|
||||
|
||||
lines = append(lines, categoryStyle.Render("Task Management"))
|
||||
for _, binding := range taskBindings {
|
||||
lines = append(lines, renderBinding(binding))
|
||||
}
|
||||
lines = append(lines, "")
|
||||
|
||||
lines = append(lines, categoryStyle.Render("Time Tracking"))
|
||||
for _, binding := range timeBindings {
|
||||
lines = append(lines, renderBinding(binding))
|
||||
}
|
||||
lines = append(lines, "")
|
||||
|
||||
lines = append(lines, categoryStyle.Render("Organization"))
|
||||
for _, binding := range organizationBindings {
|
||||
lines = append(lines, renderBinding(binding))
|
||||
}
|
||||
lines = append(lines, "")
|
||||
|
||||
lines = append(lines, categoryStyle.Render("View & System"))
|
||||
for _, binding := range viewBindings {
|
||||
lines = append(lines, renderBinding(binding))
|
||||
}
|
||||
lines = append(lines, "")
|
||||
|
||||
// Calculate visible area
|
||||
footerLines := 2 // Footer text
|
||||
availableHeight := m.height - footerLines
|
||||
if availableHeight < 5 {
|
||||
availableHeight = 5
|
||||
}
|
||||
|
||||
totalLines := len(lines)
|
||||
|
||||
// Determine which lines to show based on scroll offset
|
||||
startLine := m.helpScroll
|
||||
endLine := startLine + availableHeight
|
||||
if endLine > totalLines {
|
||||
endLine = totalLines
|
||||
}
|
||||
if startLine >= totalLines {
|
||||
startLine = totalLines - 1
|
||||
if startLine < 0 {
|
||||
startLine = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Build visible content
|
||||
var content strings.Builder
|
||||
for i := startLine; i < endLine && i < len(lines); i++ {
|
||||
content.WriteString(lines[i])
|
||||
content.WriteString("\n")
|
||||
}
|
||||
|
||||
// Add scroll indicators and footer
|
||||
var footer strings.Builder
|
||||
if startLine > 0 || endLine < totalLines {
|
||||
scrollInfo := fmt.Sprintf("(Scroll: %d-%d of %d lines)", startLine+1, endLine, totalLines)
|
||||
footer.WriteString(statusStyle.Render(scrollInfo))
|
||||
footer.WriteString(" ")
|
||||
}
|
||||
footer.WriteString(statusStyle.Render("↑/↓ scroll • ? or ESC to close"))
|
||||
|
||||
// Combine content and footer
|
||||
var result strings.Builder
|
||||
result.WriteString(content.String())
|
||||
|
||||
// Add padding if needed
|
||||
currentHeight := lipgloss.Height(content.String())
|
||||
paddingNeeded := availableHeight - currentHeight
|
||||
if paddingNeeded > 0 {
|
||||
result.WriteString(strings.Repeat("\n", paddingNeeded))
|
||||
}
|
||||
|
||||
result.WriteString(footer.String())
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func (m uiModel) viewEditMode() string {
|
||||
var b strings.Builder
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue