mirror of
https://github.com/anotherhadi/spilltea.git
synced 2026-05-20 01:32:33 +02:00
Init
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
"github.com/anotherhadi/spilltea/internal/style"
|
||||
"github.com/charmbracelet/x/ansi"
|
||||
)
|
||||
|
||||
type Kind string
|
||||
|
||||
const (
|
||||
KindInfo Kind = "info"
|
||||
KindSuccess Kind = "success"
|
||||
KindWarning Kind = "warning"
|
||||
KindError Kind = "error"
|
||||
)
|
||||
|
||||
type NotificationMsg struct {
|
||||
Title string
|
||||
Body string
|
||||
Kind Kind
|
||||
}
|
||||
|
||||
type DismissMsg struct{ ID int }
|
||||
|
||||
type notification struct {
|
||||
id int
|
||||
title string
|
||||
body string
|
||||
kind Kind
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
queue []notification
|
||||
nextID int
|
||||
width int
|
||||
height int
|
||||
}
|
||||
|
||||
func New() Model { return Model{} }
|
||||
|
||||
func (m *Model) SetSize(w, h int) {
|
||||
m.width = w
|
||||
m.height = h
|
||||
}
|
||||
|
||||
func (m Model) HasNotifications() bool {
|
||||
return len(m.queue) > 0
|
||||
}
|
||||
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case NotificationMsg:
|
||||
n := notification{id: m.nextID, title: msg.Title, body: msg.Body, kind: msg.Kind}
|
||||
m.nextID++
|
||||
m.queue = append(m.queue, n)
|
||||
return m, tea.Tick(4*time.Second, func(time.Time) tea.Msg { return DismissMsg{ID: n.id} })
|
||||
case DismissMsg:
|
||||
for i, n := range m.queue {
|
||||
if n.id == msg.ID {
|
||||
m.queue = append(m.queue[:i], m.queue[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m Model) View(background string) string {
|
||||
if len(m.queue) == 0 {
|
||||
return background
|
||||
}
|
||||
|
||||
s := style.S
|
||||
const popupW = 34
|
||||
|
||||
var popups []string
|
||||
start := len(m.queue) - 3
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
for i := start; i < len(m.queue); i++ {
|
||||
n := m.queue[i]
|
||||
var accent color.Color
|
||||
switch n.kind {
|
||||
case KindSuccess:
|
||||
accent = s.Success
|
||||
case KindWarning:
|
||||
accent = s.Warning
|
||||
case KindError:
|
||||
accent = s.Error
|
||||
default:
|
||||
accent = s.Primary
|
||||
}
|
||||
|
||||
titleStr := lipgloss.NewStyle().Foreground(accent).Bold(true).Render(n.title)
|
||||
bodyStr := lipgloss.NewStyle().Foreground(s.Text).Width(popupW).Render(n.body)
|
||||
|
||||
inner := lipgloss.JoinVertical(lipgloss.Left, titleStr, bodyStr)
|
||||
box := lipgloss.NewStyle().
|
||||
Border(lipgloss.RoundedBorder()).
|
||||
BorderForeground(accent).
|
||||
Padding(0, 1).
|
||||
Render(inner)
|
||||
popups = append(popups, box)
|
||||
}
|
||||
|
||||
popup := strings.Join(popups, "\n")
|
||||
return overlayTopRight(background, popup, m.width, m.height)
|
||||
}
|
||||
|
||||
func overlayTopRight(bg, popup string, w, h int) string {
|
||||
bgLines := strings.Split(bg, "\n")
|
||||
|
||||
popupLines := strings.Split(popup, "\n")
|
||||
popupH := len(popupLines)
|
||||
popupW := 0
|
||||
for _, l := range popupLines {
|
||||
if vw := lipgloss.Width(l); vw > popupW {
|
||||
popupW = vw
|
||||
}
|
||||
}
|
||||
|
||||
const marginTop = 1
|
||||
const marginRight = 2
|
||||
startY := marginTop
|
||||
startX := w - popupW - marginRight
|
||||
if startX < 0 {
|
||||
startX = 0
|
||||
}
|
||||
|
||||
result := make([]string, h)
|
||||
for y := 0; y < h; y++ {
|
||||
bgLine := ""
|
||||
if y < len(bgLines) {
|
||||
bgLine = bgLines[y]
|
||||
}
|
||||
|
||||
popupY := y - startY
|
||||
if popupY >= 0 && popupY < popupH {
|
||||
prefix := ansi.Truncate(bgLine, startX, "")
|
||||
suffix := ansi.TruncateLeft(bgLine, startX+popupW, "")
|
||||
result[y] = prefix + popupLines[popupY] + suffix
|
||||
} else {
|
||||
result[y] = bgLine
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(result, "\n")
|
||||
}
|
||||
Reference in New Issue
Block a user