package tui import ( "strings" "github.com/charmbracelet/lipgloss" ) // eecoLogo is the home-view banner. Heavy box-drawing glyphs trace // the lowercase outline wordmark used in assets/eeco_logo_{dark,light}.png; // the rendering pipeline splits the first 'e' from the rest so the two // halves can be coloured independently (mirrors the dark/indigo split // in the PNG marks). const eecoLogo = `┏━━━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━ ┏━━━━━━━┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣━━━━━━━┛ ┣━━━━━━━┛ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗━━━━━━━ ┗━━━━━━━ ┗━━━━━━━━ ┗━━━━━━━┛` // logoSplit is the rune offset that separates the leading "e" glyph // from the "eco" remainder on every row of eecoLogo. Each glyph is 9 // cells wide with a 1-cell gap; the leading glyph therefore ends at // rune 9. const logoSplit = 9 // hintLine is the dim affordance at the foot of the home view. Names no // external tool and uses no first person (Constraint 4). const hintLine = "type /" // renderHome builds the first-impression home view: the centred logo, a // dim version line, one rotating usage tip, and the hint, stacked with // generous breathing room. Command discovery lives in the `/` palette and // the `?` overlay, so the home no longer lists commands. The caller // concatenates the prompt input and dim footer below. func renderHome(width int, st styles, version, tip string) string { var b strings.Builder b.WriteString(renderLogo(width, st)) b.WriteByte('\n') b.WriteByte('\n') b.WriteString(renderVersion(width, st, version)) b.WriteByte('\n') b.WriteByte('\n') b.WriteByte('\n') b.WriteString(renderTip(width, st, tip)) b.WriteByte('\n') b.WriteByte('\n') b.WriteByte('\n') b.WriteString(renderHint(width, st)) b.WriteByte('\n') return b.String() } // renderLogo centres each line of eecoLogo on width and applies the // two-tone colouring: the leading "e" is rendered in the muted style // (the dark half of the README mark), the rest in brand. With width <= // 0 (no WindowSizeMsg yet) the logo renders left-flush, which is the // pass-through behaviour the rest of the View already uses. func renderLogo(width int, st styles) string { lines := strings.Split(eecoLogo, "\n") for i, ln := range lines { runes := []rune(ln) var head, tail string if len(runes) >= logoSplit { head = string(runes[:logoSplit]) tail = string(runes[logoSplit:]) } else { tail = ln } out := st.logoMuted.Render(head) + st.brand.Render(tail) if width > 0 { out = lipgloss.PlaceHorizontal(width, lipgloss.Center, out) } lines[i] = out } return strings.Join(lines, "\n") } // renderVersion is the dim, centred version line shown once below the // logo on the home view. It is the only place the running version is // surfaced: the status footer (barLine) elides it deliberately, so the // banner carries it. func renderVersion(width int, st styles, version string) string { out := st.dim.Render(version) if width > 0 { out = lipgloss.PlaceHorizontal(width, lipgloss.Center, out) } return out } // renderTip formats one rotating usage hint: a `tip` label in the key // style and the hint body in dim, centred as a whole at width. The hint // is chosen once per session (pickTip); discovery of the commands // themselves lives in the `/` palette and the `?` overlay. func renderTip(width int, st styles, tip string) string { out := st.key.Render("tip") + st.dim.Render(" · "+tip) if width > 0 { out = lipgloss.PlaceHorizontal(width, lipgloss.Center, out) } return out } // renderHint is the dim one-liner at the foot of the home view. func renderHint(width int, st styles) string { out := st.dim.Render(hintLine) if width > 0 { out = lipgloss.PlaceHorizontal(width, lipgloss.Center, out) } return out }