admin 8dc496b626
Some checks failed
CI / test (push) Has been cancelled
Release / release (push) Failing after 4m36s
first commit
2026-03-08 15:40:34 +07:00

122 lines
2.9 KiB
Go

package tui
import (
"strings"
"time"
tea "charm.land/bubbletea/v2"
"charm.land/lipgloss/v2"
"github.com/charmbracelet/harmonica"
)
const (
LogoPhaseHidden = iota
LogoPhaseAnimating
LogoPhaseVisible
LogoPhaseDone
)
type LogoTickMsg struct{}
type LogoModel struct {
phase int
alpha float64
vel float64
spring harmonica.Spring
isDark bool
frame int
displayLogo bool
}
func logoLines() []string {
return []string{
``,
` ╔═╗╦ ╔═╗╔═╗╔═╗╔╗╔╔╦╗`,
` ╠═╣║ ╠═╣║ ╦║╣ ║║║ ║ `,
` ╩ ╩╩ ╩ ╩╚═╝╚═╝╝╚╝ ╩ `,
``,
` 100% local · Your data never leaves`,
``,
}
}
func NewLogoModel(isDark bool) LogoModel {
return LogoModel{
spring: harmonica.NewSpring(harmonica.FPS(60), 4.0, 0.9),
isDark: isDark,
phase: LogoPhaseHidden,
}
}
func (m *LogoModel) Start() {
m.phase = LogoPhaseAnimating
m.alpha = 0
m.vel = 0
m.frame = 0
}
func (m LogoModel) Init() tea.Cmd {
return tea.Tick(16*time.Millisecond, func(time.Time) tea.Msg {
return LogoTickMsg{}
})
}
func (m LogoModel) Update(msg tea.Msg) (LogoModel, tea.Cmd) {
if _, ok := msg.(LogoTickMsg); ok {
m.frame++
if m.phase == LogoPhaseAnimating {
target := 1.0
m.alpha, m.vel = m.spring.Update(m.alpha, m.vel, target)
if m.alpha >= 0.95 && m.frame > 60 {
m.phase = LogoPhaseVisible
m.displayLogo = true
}
if m.phase == LogoPhaseVisible && m.frame > 180 {
m.phase = LogoPhaseDone
m.displayLogo = false
}
}
if m.phase < LogoPhaseDone {
return m, tea.Tick(16*time.Millisecond, func(time.Time) tea.Msg {
return LogoTickMsg{}
})
}
}
return m, nil
}
func (m LogoModel) View() string {
if m.phase == LogoPhaseHidden || m.phase == LogoPhaseDone || !m.displayLogo {
return ""
}
lines := logoLines()
var b strings.Builder
for _, line := range lines {
if m.alpha < 0.1 {
b.WriteString(lipgloss.NewStyle().
Foreground(lipgloss.Color("#4c566a")).
Render(line))
} else if m.alpha < 0.5 {
b.WriteString(lipgloss.NewStyle().
Foreground(lipgloss.Color("#81a1c1")).
Render(line))
} else {
b.WriteString(lipgloss.NewStyle().
Foreground(lipgloss.Color("#88c0d0")).
Bold(true).
Render(line))
}
b.WriteString("\n")
}
return b.String()
}
func (m LogoModel) IsDone() bool {
return m.phase == LogoPhaseDone
}
func (m LogoModel) ShouldShow() bool {
return m.displayLogo && m.phase < LogoPhaseDone
}