package setup import ( "bubble/setup/ui" "bubble/types" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) 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 } 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, message: msg.Message, buttons: msg.ModalButtons, focus: 0, width: width, height: height, onResult: msg.OnResult, } } func (m *ModalModel) Init() tea.Cmd { return nil } 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": m.focus-- if m.focus < 0 { m.focus = len(m.buttons) - 1 } case "right", "l", "tab": m.focus++ if m.focus >= len(m.buttons) { m.focus = 0 } case "enter", " ": //вытаскиваем значение кнопки result := m.buttons[m.focus].Value var cmd tea.Cmd if m.onResult != nil { //если функция кнопки не пустая, мы передаем в функцию значение кнопки cmd = m.onResult(result) } return m, tea.Batch( //объединяем 2 действия, функцию кнопки и закрытие модального окна cmd, func() tea.Msg { return types.CloseModalMsg{} }, ) } } return m, nil } func (m *ModalModel) View() string { contentWidth := ui.ContentWidth(m.width) modalWidth := min(contentWidth-10, ui.ModalMaxHeight) if modalWidth < 60 { modalWidth = 60 } content := lipgloss.NewStyle(). Width(modalWidth-8). Padding(1, 3). Render(m.message) var buttons []string for i, btn := range m.buttons { style := ui.ModalButtonNormal if i == m.focus { style = ui.ModalButtonFocused } buttons = append(buttons, style.Render(btn.Text)) } buttonRow := lipgloss.JoinHorizontal(lipgloss.Center, buttons...) body := lipgloss.JoinVertical(lipgloss.Center, content, "\n\n", buttonRow) // Бордер и цвет в зависимости от типа var modalStyle lipgloss.Style var titleStyle lipgloss.Style switch m.modalType { case types.ModalError: modalStyle = ui.ModalBorderError titleStyle = ui.ModalTitleError case types.ModalWarning, types.ModalConfirm: modalStyle = ui.ModalBorderWarning titleStyle = ui.ModalTitleWarning default: modalStyle = ui.ModalBorderInfo titleStyle = ui.ModalTitleDefault } modal := lipgloss.NewStyle(). Width(modalWidth). Padding(2, 4). Border(lipgloss.DoubleBorder()). BorderForeground(modalStyle.GetBorderBottomForeground()). Render(body) if m.title != "" { title := titleStyle.Width(modalWidth).Align(lipgloss.Center).Render(m.title) modal = lipgloss.JoinVertical(lipgloss.Center, title, modal) } return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, modal, lipgloss.WithWhitespaceChars("."), lipgloss.WithWhitespaceForeground(ui.ColorGrey)) //modalWidth := min(m.width-20, ui.ModalMaxHeight) //if modalWidth < 60 { // modalWidth = 60 //} //var borderColor lipgloss.Color //var titleStyle lipgloss.Style // //switch m.modalType { //case types.ModalError: // borderColor = ui.ColorRed // titleStyle = lipgloss.NewStyle().Foreground(ui.ColorRed).Bold(true) //case types.ModalWarning, types.ModalConfirm: // borderColor = ui.ColorPurple // titleStyle = lipgloss.NewStyle().Foreground(ui.ColorPurple).Bold(true) //default: // borderColor = ui.ColorBlue // titleStyle = lipgloss.NewStyle().Foreground(ui.ColorBlue).Bold(true) //} //content := lipgloss.NewStyle().Width(m.width-10).Padding(1, 2).Render(m.message) //var buttons []string //for i, btn := range m.buttons { // style := lipgloss.NewStyle(). // Padding(0, 2). // Border(lipgloss.RoundedBorder()). // BorderForeground(ui.ColorGrey) // if i == m.focus { // style = style.Foreground(ui.ColorRed).BorderForeground(ui.ColorRed).Bold(true) // } else { // style = style.Foreground(ui.ColorGreenCyan) // } // buttons = append(buttons, style.Render(btn.Text)) //} //buttonShow := lipgloss.JoinHorizontal(lipgloss.Center, buttons...) //body := lipgloss.JoinVertical(lipgloss.Center, content, "\n", buttonShow) // //modal := lipgloss.NewStyle(). // Width(modalWidth). // Padding(1, 3). // Border(lipgloss.DoubleBorder()). // BorderForeground(borderColor). // Render(body) // //if m.title != "" { // title := titleStyle.Width(modalWidth - 6).Render(m.title) // modal = lipgloss.JoinVertical(lipgloss.Center, title, modal) //} // //return lipgloss.Place(m.width, m.height, // lipgloss.Center, lipgloss.Center, // modal, // lipgloss.WithWhitespaceChars("."), // lipgloss.WithWhitespaceForeground(ui.ColorPurple), //) }