mirror of
https://github.com/anotherhadi/ilovetui.git
synced 2026-08-21 20:15:49 +02:00
5f99fa7521
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
108 lines
3.5 KiB
Go
108 lines
3.5 KiB
Go
package notification
|
|
|
|
import (
|
|
"time"
|
|
|
|
tea "charm.land/bubbletea/v2"
|
|
)
|
|
|
|
// Kind picks which of Styles' presets a toast renders with, unless
|
|
// overridden per-toast via WithToastStyle.
|
|
type Kind int
|
|
|
|
const (
|
|
Info Kind = iota
|
|
Success
|
|
Warning
|
|
Error
|
|
)
|
|
|
|
// DefaultDuration is how long a toast stays visible when WithDuration isn't
|
|
// used. Show has no reference to a Model (see ShowMsg's doc comment), so this
|
|
// lives as a package constant rather than a Model-level default.
|
|
const DefaultDuration = 3 * time.Second
|
|
|
|
// Toast is one notification. Build it via Show's opts rather than a literal:
|
|
// ID and Duration both get defaults (see WithID, DefaultDuration) that a bare
|
|
// literal would silently skip.
|
|
type Toast struct {
|
|
ID string
|
|
Title string
|
|
Message string
|
|
Kind Kind
|
|
// Duration is how long the toast stays up before auto-dismissing. 0
|
|
// means sticky: it stays until DismissMsg/Dismiss(ID) removes it.
|
|
Duration time.Duration
|
|
// Style, if non-nil, overrides the Model's Kind-based preset for this
|
|
// toast alone.
|
|
Style *KindStyle
|
|
}
|
|
|
|
// ToastOption configures a Toast built by Show.
|
|
type ToastOption func(*Toast)
|
|
|
|
// WithID gives the toast a stable id, so a later Show reusing the same id
|
|
// replaces it in place (resetting its position and timer) instead of
|
|
// stacking a duplicate, and so it can be targeted by Dismiss.
|
|
func WithID(id string) ToastOption {
|
|
return func(t *Toast) { t.ID = id }
|
|
}
|
|
|
|
// WithDuration overrides DefaultDuration. 0 makes the toast sticky: it never
|
|
// auto-dismisses, only Dismiss(ID) removes it.
|
|
func WithDuration(d time.Duration) ToastOption {
|
|
return func(t *Toast) { t.Duration = d }
|
|
}
|
|
|
|
// WithToastStyle overrides the Model's Kind-based preset for this toast
|
|
// alone, for a one-off custom look instead of the type-based theme.
|
|
func WithToastStyle(s KindStyle) ToastOption {
|
|
return func(t *Toast) { t.Style = &s }
|
|
}
|
|
|
|
func newToast(title, message string, kind Kind, opts ...ToastOption) Toast {
|
|
t := Toast{
|
|
Title: title,
|
|
Message: message,
|
|
Kind: kind,
|
|
Duration: DefaultDuration,
|
|
}
|
|
for _, opt := range opts {
|
|
opt(&t)
|
|
}
|
|
return t
|
|
}
|
|
|
|
// ShowMsg tells a notification.Model to display Toast. Any component in the
|
|
// same bubbletea program can trigger one via Show, without holding a
|
|
// reference to the notification.Model that will actually render it - that
|
|
// Model just needs to see every tea.Msg the program produces, same as any
|
|
// other child model.
|
|
type ShowMsg struct{ Toast Toast }
|
|
|
|
// Show returns a tea.Cmd that shows a new toast of the given kind. Call it
|
|
// from any component's Update:
|
|
//
|
|
// return m, notification.Show("Saved", "Config written to disk", notification.Success)
|
|
func Show(title, message string, kind Kind, opts ...ToastOption) tea.Cmd {
|
|
t := newToast(title, message, kind, opts...)
|
|
return func() tea.Msg { return ShowMsg{Toast: t} }
|
|
}
|
|
|
|
// DismissMsg removes the toast identified by ID, whether it's sticky or
|
|
// mid-countdown. A no-op if ID isn't currently shown (already expired, or
|
|
// never had an explicit id in the first place - see WithID).
|
|
type DismissMsg struct{ ID string }
|
|
|
|
// Dismiss returns a tea.Cmd that removes the toast identified by id. Only
|
|
// useful for toasts shown with WithID, since an auto-generated id is never
|
|
// exposed back to the caller.
|
|
func Dismiss(id string) tea.Cmd {
|
|
return func() tea.Msg { return DismissMsg{ID: id} }
|
|
}
|
|
|
|
// expireMsg fires once a toast's Duration has elapsed, scheduled by
|
|
// Model.show via tea.Tick. Unexported: nothing outside the package should
|
|
// construct or match on it directly, that's what DismissMsg is for.
|
|
type expireMsg struct{ id string }
|