@@ -10,8 +10,7 @@ import (
1010 "github.com/charmbracelet/lipgloss/v2"
1111 "github.com/charmbracelet/x/ansi"
1212 "github.com/charmbracelet/x/exp/slice"
13- "github.com/lucasb-eyer/go-colorful"
14- "github.com/rivo/uniseg"
13+ "github.com/opencode-ai/opencode/internal/tui/styles"
1514)
1615
1716// letterform represents a letterform. It can be stretched horizontally by
@@ -46,7 +45,7 @@ func Render(version string, compact bool, o Opts) string {
4645 crushWidth := lipgloss .Width (crush )
4746 b := new (strings.Builder )
4847 for r := range strings .SplitSeq (crush , "\n " ) {
49- fmt .Fprintln (b , applyForegroundGrad (r , o .TitleColorA , o .TitleColorB ))
48+ fmt .Fprintln (b , styles . ApplyForegroundGrad (r , o .TitleColorA , o .TitleColorB ))
5049 }
5150 crush = b .String ()
5251
@@ -312,76 +311,3 @@ func stretchLetterformPart(s string, p letterformProps) string {
312311 }
313312 return lipgloss .JoinHorizontal (lipgloss .Top , parts ... )
314313}
315-
316- // applyForegroundGrad renders a given string with a horizontal gradient
317- // foreground.
318- func applyForegroundGrad (input string , color1 , color2 color.Color ) string {
319- if input == "" {
320- return ""
321- }
322-
323- var o strings.Builder
324- if len (input ) == 1 {
325- return lipgloss .NewStyle ().Foreground (color1 ).Render (input )
326- }
327-
328- var clusters []string
329- gr := uniseg .NewGraphemes (input )
330- for gr .Next () {
331- clusters = append (clusters , string (gr .Runes ()))
332- }
333-
334- ramp := blendColors (len (clusters ), color1 , color2 )
335- for i , c := range ramp {
336- fmt .Fprint (& o , lipgloss .NewStyle ().Foreground (c ).Render (clusters [i ]))
337- }
338-
339- return o .String ()
340- }
341-
342- // blendColors returns a slice of colors blended between the given keys.
343- // Blending is done in Hcl to stay in gamut.
344- func blendColors (size int , stops ... color.Color ) []color.Color {
345- if len (stops ) < 2 {
346- return nil
347- }
348-
349- stopsPrime := make ([]colorful.Color , len (stops ))
350- for i , k := range stops {
351- stopsPrime [i ], _ = colorful .MakeColor (k )
352- }
353-
354- numSegments := len (stopsPrime ) - 1
355- blended := make ([]color.Color , 0 , size )
356-
357- // Calculate how many colors each segment should have.
358- segmentSizes := make ([]int , numSegments )
359- baseSize := size / numSegments
360- remainder := size % numSegments
361-
362- // Distribute the remainder across segments.
363- for i := range numSegments {
364- segmentSizes [i ] = baseSize
365- if i < remainder {
366- segmentSizes [i ]++
367- }
368- }
369-
370- // Generate colors for each segment.
371- for i := range numSegments {
372- c1 := stopsPrime [i ]
373- c2 := stopsPrime [i + 1 ]
374- segmentSize := segmentSizes [i ]
375-
376- for j := range segmentSize {
377- var t float64
378- if segmentSize > 1 {
379- t = float64 (j ) / float64 (segmentSize - 1 )
380- }
381- c := c1 .BlendHcl (c2 , t )
382- blended = append (blended , c )
383- }
384- }
385-
386- return blended
387- }
0 commit comments