Комментирование, правки кода, исправление модальных окон

This commit is contained in:
XeRo 2026-01-15 17:55:52 +05:00
parent 2e8eee135e
commit 300afb5d26
8 changed files with 299 additions and 618 deletions

View file

@ -7,21 +7,20 @@ import (
"github.com/charmbracelet/lipgloss"
)
// ModalModel структура описывающая модель отрисовки модального окна
type ModalModel struct {
modalType types.ModalType
title string
message string
buttons []types.ModalButton
focus int
width int
height int
onResult func(result any) tea.Cmd
modalType types.ModalType //Тип модального окна
title string //Заголовок модального окна
message string //Сообщение модального окна
buttons []types.ModalButton //Кнопки модального окна
focus int //Фокус для отслеживания с каким объектом надо работать
width int //Ширина окна
height int //Высота окна
onResult func(result any) tea.Cmd //Какое действие надо выполнить при нажатии
}
// NewModalModel создает новую модель модального окна на основе переданного сообщения
func NewModalModel(msg types.ShowModalMsg, width, height int) *ModalModel {
if len(msg.ModalButtons) == 0 {
msg.ModalButtons = []types.ModalButton{{Text: "Ok", Value: true}}
}
return &ModalModel{
modalType: msg.Type,
title: msg.Title,
@ -38,32 +37,46 @@ func (m *ModalModel) Init() tea.Cmd {
return nil
}
// Update отслеживает действия с модальным окном
func (m *ModalModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
//Отслеживаем и записываем новые размеры окна
m.width = msg.Width
m.height = msg.Height
return m, nil
case tea.KeyMsg:
//Отслеживаем нажатие клавиш модального окна
switch msg.String() {
case "left", "h", "shift+tab":
case "left", "shift+tab":
//Обработчик нажатия клавиш left и shift+tab нужен для перевода фокуса на прошлую кнопку.
//Уменьшаем фокус, если фокус стал меньше 0, значит он вышел за пределы кнопок,
//переводим его на последнюю кнопку.
m.focus--
if m.focus < 0 {
m.focus = len(m.buttons) - 1
}
case "right", "l", "tab":
case "right", "tab":
//Обработчик нажатия клавиш right и tab нужен для перевода фокуса на следующую кнопку.
//Увеличиваем фокус, если фокус стал равен количество кнопок, значит он вышел за их пределы,
//переводим его на первую позицию, то есть на 0
m.focus++
if m.focus >= len(m.buttons) {
m.focus = 0
}
case "enter", " ":
//вытаскиваем значение кнопки
//Обработчик клавиши enter нужен для подтверждения кнопки.
//Получаем значение кнопки, а после если у модального окна прописана функция,
//то передаем значение кнопки в функцию модального окна.
result := m.buttons[m.focus].Value
var cmd tea.Cmd
if m.onResult != nil { //если функция кнопки не пустая, мы передаем в функцию значение кнопки
if m.onResult != nil {
cmd = m.onResult(result)
}
return m, tea.Batch( //объединяем 2 действия, функцию кнопки и закрытие модального окна
//Возвращаем единую команду составленную из двух,
//результата выполнения функции модального окна,
//функцию возвращения сообщения о закрытии модального окна.
return m, tea.Batch(
cmd,
func() tea.Msg { return types.CloseModalMsg{} },
)
@ -72,13 +85,14 @@ func (m *ModalModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
// View формирует строку для вывода модального окна и её контента
func (m *ModalModel) View() string {
//Данные о размерах контейнера
containerWidth, containerHeight, _, _ := ui.ContentSizes(m.width, m.height)
//Модальное окно не должно занимать все пространство, поэтому получаем минимально допустимые размеры
modalWidth := min(containerWidth, ui.ModalMaxWidth)
modalHeight := min(containerHeight, ui.ModalMaxHeight)
//Формируем просто сообщение и кнопки с учетом фокуса
message := lipgloss.NewStyle().Render(m.message)
var buttons []string
for i, button := range m.buttons {
@ -88,12 +102,14 @@ func (m *ModalModel) View() string {
}
buttons = append(buttons, style.Render(button.Text))
}
//Строка кнопок
buttonRow := lipgloss.JoinHorizontal(lipgloss.Center, buttons...)
//Тело контента модального окна
modalBody := lipgloss.JoinVertical(lipgloss.Center, message, "", buttonRow)
//В зависимости от типа модального окна разные цвета
var borderColor lipgloss.Color
var modalTitleStyle lipgloss.Style
switch m.modalType {
case types.ModalError:
borderColor = ui.ColorError
@ -105,33 +121,19 @@ func (m *ModalModel) View() string {
borderColor = ui.ColorAccent
modalTitleStyle = ui.ModalTitleDefault
}
//
//switch m.modalType {
//case types.ModalError:
// modalStyle = ui.ModalBorderError
// modalTitleStyle = ui.ModalTitleError
//case types.ModalWarning, types.ModalConfirm:
// modalStyle = ui.ModalBorderWarning
// modalTitleStyle = ui.ModalTitleWarning
//default:
// modalStyle = ui.ModalBorderInfo
// modalTitleStyle = ui.ModalTitleDefault
//}
var modalView string
//Формируем модальный контейнер с контентом внутри и указанным цветом границ.
modalView := ui.ModalContainer.
Width(modalWidth).
Height(modalHeight).
Align(lipgloss.Center).
Border(lipgloss.DoubleBorder()).
BorderForeground(borderColor).
Render(modalBody)
symbolToRepeat := "*"
//Если у модального окна есть заголовок, то в modalView записываем новое значение,
//ставя заголовок сверху модального контейнера
if m.title != "" {
modalView = ui.ModalContainer.
Width(modalWidth).
Height(modalHeight).
Align(lipgloss.Center, lipgloss.Center).
Border(lipgloss.DoubleBorder()).
BorderForeground(borderColor).
Render(modalBody)
//modalView = ui.ModalContainer.
// Width(modalWidth).
// Height(modalHeight).
// BorderForeground(borderColor).
// Render(modalBody)
//repeatCount := modalWidth - utf8.RuneCountInString(m.title)
//if repeatCount < 0 {
// repeatCount = 0
@ -139,19 +141,6 @@ func (m *ModalModel) View() string {
//symbolFill := strings.Repeat(symbolToRepeat, repeatCount/2)
//modalView = lipgloss.JoinVertical(lipgloss.Center, modalTitleStyle.Render(symbolFill+m.title+symbolFill), modalView)
modalView = lipgloss.JoinVertical(lipgloss.Center, modalTitleStyle.Render(m.title), modalView)
} else {
modalView = ui.ModalContainer.
Width(modalWidth).
Height(modalHeight).
BorderStyle(lipgloss.ASCIIBorder()).
BorderForeground(borderColor).
Render(modalBody)
//modalView = modalStyle.
// Width(modalWidth).
// Height(modalHeight).
// Padding(1, 3).
// Border(lipgloss.DoubleBorder()).
// Render(modalBody)
}
return lipgloss.Place(m.width, m.height,
lipgloss.Center, lipgloss.Center,