Merge pull request #73 from LazyBachelor/LPM-138

LPM-138 Refactor Tui with composable modals and use canvas

Refactors the TUI (dashboard + kanban) to use a shared, composable modal system with canvas-based overlay rendering, while consolidating styling into internal/style and expanding issue interactions (e.g., comments).

Changes:

Introduces a new pkg/tui/modal system (manager/stack + multiple modal types) and overlays modals using Lipgloss compositor layers.
Refactors dashboard/kanban views and input handling to use the modal manager + focus manager instead of per-modal boolean state.
Consolidates TUI styling by moving from pkg/tui/styles to internal/style and updates components to use the new style package; adds a shared footer renderer.
This commit is contained in:
Robin Olsen
2026-03-20 08:28:10 -07:00
committed by GitHub
parent 9a47acc49a
commit 7facfb6afe
27 changed files with 2469 additions and 1752 deletions

View File

@@ -0,0 +1,43 @@
package truncate
import "charm.land/lipgloss/v2"
// TruncateToWidth trims the given text so that its rendered width does not
// exceed maxWidth. If truncation occurs and there is room, an ellipsis is
// appended to indicate that the text was shortened.
func TruncateToWidth(text string, maxWidth int) string {
if maxWidth <= 0 {
return ""
}
if lipgloss.Width(text) <= maxWidth {
return text
}
const ellipsis = "…"
ellipsisWidth := lipgloss.Width(ellipsis)
if ellipsisWidth > maxWidth {
runes := []rune(text)
if len(runes) > 0 {
firstChar := string(runes[0])
if lipgloss.Width(firstChar) <= maxWidth {
return firstChar
}
}
return ""
}
runes := []rune(text)
lastSafe := 0
for i := range runes {
candidate := string(runes[:i+1])
if lipgloss.Width(candidate)+ellipsisWidth > maxWidth {
break
}
lastSafe = i + 1
}
current := string(runes[:lastSafe])
return current + ellipsis
}

View File

@@ -0,0 +1,19 @@
package user
import (
"os"
"os/user"
)
func GetOsUsername() string {
if u, err := user.Current(); err == nil && u.Username != "" {
return u.Username
}
if s := os.Getenv("USER"); s != "" {
return s
}
if s := os.Getenv("USERNAME"); s != "" {
return s
}
return "user"
}