mirror of
https://github.com/theniceboy/.config.git
synced 2026-07-16 22:01:21 +08:00
feat: improve ui with text wrapping, better list styling and scope tags
This commit is contained in:
parent
486f31675e
commit
879aa9eb8f
1 changed files with 122 additions and 22 deletions
|
|
@ -963,7 +963,7 @@ func runUI(args []string) error {
|
||||||
|
|
||||||
// Line 1: Indicator + Summary + Right-aligned Duration
|
// Line 1: Indicator + Summary + Right-aligned Duration
|
||||||
dur := liveDuration(t, now)
|
dur := liveDuration(t, now)
|
||||||
availWidth := width - len(indicator) - 1 - len(dur) - 1
|
availWidth := width - len(indicator) - 1 - len(dur) - 3
|
||||||
if availWidth < 0 {
|
if availWidth < 0 {
|
||||||
availWidth = 0
|
availWidth = 0
|
||||||
}
|
}
|
||||||
|
|
@ -1032,7 +1032,39 @@ func runUI(args []string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wrapText := func(text string, maxWidth int) []string {
|
||||||
|
if maxWidth <= 0 {
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
|
runes := []rune(text)
|
||||||
|
if len(runes) <= maxWidth {
|
||||||
|
return []string{text}
|
||||||
|
}
|
||||||
|
var lines []string
|
||||||
|
for len(runes) > maxWidth {
|
||||||
|
split := maxWidth
|
||||||
|
found := false
|
||||||
|
for i := maxWidth; i > 0; i-- {
|
||||||
|
if unicode.IsSpace(runes[i]) {
|
||||||
|
split = i
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
split = maxWidth
|
||||||
|
}
|
||||||
|
lines = append(lines, string(runes[:split]))
|
||||||
|
runes = runes[split:]
|
||||||
|
for len(runes) > 0 && unicode.IsSpace(runes[0]) {
|
||||||
|
runes = runes[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(runes) > 0 {
|
||||||
|
lines = append(lines, string(runes))
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
renderNotes := func(list []ipc.Note, state *listState, archived bool) {
|
renderNotes := func(list []ipc.Note, state *listState, archived bool) {
|
||||||
clampList(state, len(list), 3, visibleRows)
|
clampList(state, len(list), 3, visibleRows)
|
||||||
|
|
@ -1053,6 +1085,8 @@ func runUI(args []string) error {
|
||||||
if n.Completed {
|
if n.Completed {
|
||||||
textStyle = tcell.StyleDefault.Foreground(tcell.ColorDarkGray)
|
textStyle = tcell.StyleDefault.Foreground(tcell.ColorDarkGray)
|
||||||
scopeSt = tcell.StyleDefault.Foreground(tcell.ColorDarkGray)
|
scopeSt = tcell.StyleDefault.Foreground(tcell.ColorDarkGray)
|
||||||
|
metaStyle = tcell.StyleDefault.Foreground(tcell.ColorDarkGray)
|
||||||
|
timeStyle = tcell.StyleDefault.Foreground(tcell.ColorDarkGray)
|
||||||
}
|
}
|
||||||
|
|
||||||
if idx == state.selected {
|
if idx == state.selected {
|
||||||
|
|
@ -1063,7 +1097,7 @@ func runUI(args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag Logic
|
// Tag Logic
|
||||||
tagText := " " + scopeTag(ns) + " " // e.g. " [W] "
|
tagText := " " + scopeTag(ns) + " "
|
||||||
|
|
||||||
// Timestamp Logic
|
// Timestamp Logic
|
||||||
tsStr := ""
|
tsStr := ""
|
||||||
|
|
@ -1081,27 +1115,54 @@ func runUI(args []string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line 1 Construction
|
|
||||||
// [TAG] Summary ...................... Time
|
|
||||||
availWidth := width - len(tagText) - len(tsStr)
|
|
||||||
if availWidth < 0 {
|
|
||||||
availWidth = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
summary := n.Summary
|
summary := n.Summary
|
||||||
if n.Completed {
|
if n.Completed {
|
||||||
summary = "✓ " + summary
|
summary = "✓ " + summary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Line 1 Rendering ---
|
||||||
|
availWidth1 := width - len(tagText) - len(tsStr) - 2
|
||||||
|
if availWidth1 < 5 {
|
||||||
|
availWidth1 = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split summary for first line
|
||||||
|
line1Text := summary
|
||||||
|
remText := ""
|
||||||
|
runes := []rune(summary)
|
||||||
|
if len(runes) > availWidth1 {
|
||||||
|
split := availWidth1
|
||||||
|
found := false
|
||||||
|
for i := availWidth1; i > 0; i-- {
|
||||||
|
if unicode.IsSpace(runes[i]) {
|
||||||
|
split = i
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
split = availWidth1
|
||||||
|
}
|
||||||
|
|
||||||
|
line1Text = string(runes[:split])
|
||||||
|
remText = string(runes[split:])
|
||||||
|
// trim leading space from remainder
|
||||||
|
trimRunes := []rune(remText)
|
||||||
|
for len(trimRunes) > 0 && unicode.IsSpace(trimRunes[0]) {
|
||||||
|
trimRunes = trimRunes[1:]
|
||||||
|
}
|
||||||
|
remText = string(trimRunes)
|
||||||
|
}
|
||||||
|
|
||||||
segs := []struct {
|
segs := []struct {
|
||||||
text string
|
text string
|
||||||
style tcell.Style
|
style tcell.Style
|
||||||
}{
|
}{
|
||||||
{text: tagText, style: scopeSt},
|
{text: tagText, style: scopeSt},
|
||||||
{text: truncate(summary, availWidth), style: textStyle},
|
{text: line1Text, style: textStyle},
|
||||||
}
|
}
|
||||||
|
|
||||||
usedLen := len(tagText) + len([]rune(truncate(summary, availWidth)))
|
usedLen := len(tagText) + len([]rune(line1Text))
|
||||||
padding := width - usedLen - len(tsStr)
|
padding := width - usedLen - len(tsStr)
|
||||||
if padding > 0 {
|
if padding > 0 {
|
||||||
segs = append(segs, struct {
|
segs = append(segs, struct {
|
||||||
|
|
@ -1126,14 +1187,48 @@ func runUI(args []string) error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line 2: Context Metadata
|
// --- Wrapped Lines Rendering ---
|
||||||
// Session / Window
|
if remText != "" {
|
||||||
|
indent := len(tagText)
|
||||||
|
availWidthN := width - indent
|
||||||
|
if availWidthN < 5 {
|
||||||
|
availWidthN = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
wrappedRem := wrapText(remText, availWidthN)
|
||||||
|
for _, wLine := range wrappedRem {
|
||||||
|
segs := []struct {
|
||||||
|
text string
|
||||||
|
style tcell.Style
|
||||||
|
}{
|
||||||
|
{text: strings.Repeat(" ", indent), style: scopeSt},
|
||||||
|
{text: wLine, style: textStyle},
|
||||||
|
}
|
||||||
|
used := indent + len([]rune(wLine))
|
||||||
|
if width > used {
|
||||||
|
segs = append(segs, struct {
|
||||||
|
text string
|
||||||
|
style tcell.Style
|
||||||
|
}{
|
||||||
|
text: strings.Repeat(" ", width-used),
|
||||||
|
style: textStyle,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
writeStyledSegments(screen, row, segs...)
|
||||||
|
row++
|
||||||
|
if row >= height {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if row >= height {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Meta Line Rendering ---
|
||||||
prefix := " "
|
prefix := " "
|
||||||
metaText := fmt.Sprintf("%s / %s", n.Session, n.Window)
|
metaText := fmt.Sprintf("%s / %s", n.Session, n.Window)
|
||||||
|
|
||||||
// If visual space allows, maybe include date if it's old?
|
|
||||||
// For now keeping it simple as per request.
|
|
||||||
|
|
||||||
metaSegs := []struct {
|
metaSegs := []struct {
|
||||||
text string
|
text string
|
||||||
style tcell.Style
|
style tcell.Style
|
||||||
|
|
@ -1141,7 +1236,6 @@ func runUI(args []string) error {
|
||||||
{text: prefix, style: metaStyle},
|
{text: prefix, style: metaStyle},
|
||||||
{text: truncate(metaText, width-len(prefix)), style: metaStyle},
|
{text: truncate(metaText, width-len(prefix)), style: metaStyle},
|
||||||
}
|
}
|
||||||
// Pad the rest of the line to ensure background color extends if selected
|
|
||||||
metaUsed := len(prefix) + len([]rune(truncate(metaText, width-len(prefix))))
|
metaUsed := len(prefix) + len([]rune(truncate(metaText, width-len(prefix))))
|
||||||
if width > metaUsed {
|
if width > metaUsed {
|
||||||
metaSegs = append(metaSegs, struct {
|
metaSegs = append(metaSegs, struct {
|
||||||
|
|
@ -1155,11 +1249,17 @@ func runUI(args []string) error {
|
||||||
|
|
||||||
writeStyledSegments(screen, row, metaSegs...)
|
writeStyledSegments(screen, row, metaSegs...)
|
||||||
row++
|
row++
|
||||||
|
if row >= height {
|
||||||
// Spacer line
|
break
|
||||||
if row < height {
|
|
||||||
row++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Spacer Rendering ---
|
||||||
|
spacerStyle := tcell.StyleDefault
|
||||||
|
if idx == state.selected {
|
||||||
|
spacerStyle = spacerStyle.Background(tcell.ColorDarkSlateGray)
|
||||||
|
}
|
||||||
|
writeStyledLine(screen, 0, row, strings.Repeat(" ", width), spacerStyle)
|
||||||
|
row++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue