11package views
22
33import (
4+ "fmt"
5+
46 tea "github.com/charmbracelet/bubbletea"
57 "skene/internal/constants"
68 "skene/internal/tui/components"
@@ -15,6 +17,11 @@ type WelcomeView struct {
1517 height int
1618 time float64
1719 anim components.ASCIIMotionModel
20+
21+ // Update notification (set asynchronously)
22+ newVersion string
23+ updateCmd string
24+ copied bool
1825}
1926
2027// NewWelcomeView creates a new welcome view
@@ -49,6 +56,27 @@ func (v *WelcomeView) InitAnimation() tea.Cmd {
4956 return v .anim .Init ()
5057}
5158
59+ // SetUpdateAvailable sets the update notification info
60+ func (v * WelcomeView ) SetUpdateAvailable (newVersion , updateCmd string ) {
61+ v .newVersion = newVersion
62+ v .updateCmd = updateCmd
63+ }
64+
65+ // HasUpdate returns true if an update notification is present.
66+ func (v * WelcomeView ) HasUpdate () bool {
67+ return v .newVersion != ""
68+ }
69+
70+ // GetUpdateCmd returns the update command string.
71+ func (v * WelcomeView ) GetUpdateCmd () string {
72+ return v .updateCmd
73+ }
74+
75+ // SetCopied marks the update command as copied to clipboard.
76+ func (v * WelcomeView ) SetCopied () {
77+ v .copied = true
78+ }
79+
5280// ResetAnimation recreates the animation so it plays from the start
5381func (v * WelcomeView ) ResetAnimation () tea.Cmd {
5482 v .anim = components .NewASCIIMotion (styles .IsDarkBackground )
@@ -79,15 +107,37 @@ func (v *WelcomeView) Render() string {
79107 // Version info
80108 version := center .Render (styles .Muted .Render (constants .Version + " • " + constants .Repository ))
81109
110+ // Update notification — bordered block with update + hint
111+ var updateNotice string
112+ if v .newVersion != "" {
113+ notice := fmt .Sprintf (constants .UpdateNoticeFormat , v .newVersion , constants .Version )
114+ hintRaw := constants .UpdateNoticeHintCopy
115+ if v .copied {
116+ hintRaw = constants .UpdateNoticeCopied
117+ }
118+ hint := styles .Muted .Render (hintRaw )
119+ blockWidth := lipgloss .Width (notice )
120+ if w := lipgloss .Width (hintRaw ); w > blockWidth {
121+ blockWidth = w
122+ }
123+ blockWidth += 4 // padding
124+ content := styles .UpdateNoticeText .Render (notice ) + "\n " + hint
125+ block := styles .UpdateNotice .Width (blockWidth ).Render (content )
126+ updateNotice = center .Render (block )
127+ }
128+
82129 // Footer help
83- footer := components . FooterHelp ( []components.HelpItem {
130+ helpItems := []components.HelpItem {
84131 {Key : constants .HelpKeyEnter , Desc : constants .HelpDescStart },
85132 {Key : constants .HelpKeyCtrlC , Desc : constants .HelpDescQuit },
86- })
133+ }
134+ if v .newVersion != "" {
135+ helpItems = append (helpItems , components.HelpItem {Key : constants .HelpKeyC , Desc : constants .HelpDescCopyUpdateCmd })
136+ }
137+ footer := components .FooterHelp (helpItems )
87138
88139 // Combine elements
89- content := lipgloss .JoinVertical (
90- lipgloss .Center ,
140+ elements := []string {
91141 logo ,
92142 "" ,
93143 "" ,
@@ -96,6 +146,13 @@ func (v *WelcomeView) Render() string {
96146 subtitle ,
97147 "" ,
98148 version ,
149+ }
150+ if updateNotice != "" {
151+ elements = append (elements , "" , updateNotice )
152+ }
153+ content := lipgloss .JoinVertical (
154+ lipgloss .Center ,
155+ elements ... ,
99156 )
100157
101158 centered := lipgloss .Place (
@@ -118,8 +175,12 @@ func (v *WelcomeView) Render() string {
118175
119176// GetHelpItems returns context-specific help
120177func (v * WelcomeView ) GetHelpItems () []components.HelpItem {
121- return []components.HelpItem {
178+ items := []components.HelpItem {
122179 {Key : constants .HelpKeyEnter , Desc : constants .HelpDescStart },
123180 {Key : constants .HelpKeyCtrlC , Desc : constants .HelpDescQuit },
124181 }
182+ if v .newVersion != "" {
183+ items = append (items , components.HelpItem {Key : constants .HelpKeyC , Desc : constants .HelpDescCopyUpdateCmd })
184+ }
185+ return items
125186}
0 commit comments