Работа над отображением объектов, работа со стилями, работа с позиционированиме, изменение таблицы переменных
This commit is contained in:
parent
ada7db46cf
commit
2e8eee135e
7 changed files with 477 additions and 431 deletions
221
setup/final.go
221
setup/final.go
|
|
@ -36,67 +36,19 @@ func (m *FinalModel) Init() tea.Cmd {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FinalModel) initViewport(width, height int) {
|
|
||||||
m.viewport = viewport.New(width, height-8)
|
|
||||||
m.viewport.Width = width
|
|
||||||
m.viewport.Height = height - 10
|
|
||||||
m.ready = true
|
|
||||||
m.rebuildTable(m.viewport.Width)
|
|
||||||
m.viewport.SetContent(m.table.Render())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *FinalModel) rebuildTable(width int) {
|
|
||||||
if len(m.variables) == 0 {
|
|
||||||
m.table = table.New().Headers("Нет переменных")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
availableWidth := width - 12 // примерно: 2 (отступы) + 4 (бордер) + запас
|
|
||||||
if availableWidth < 70 {
|
|
||||||
availableWidth = 70
|
|
||||||
}
|
|
||||||
t := table.New().
|
|
||||||
Border(lipgloss.RoundedBorder()).
|
|
||||||
BorderStyle(ui.TableBorder).
|
|
||||||
StyleFunc(func(row, col int) lipgloss.Style {
|
|
||||||
var style lipgloss.Style
|
|
||||||
switch {
|
|
||||||
case row == table.HeaderRow:
|
|
||||||
return ui.TableHeader
|
|
||||||
case row%2 == 0:
|
|
||||||
style = ui.TableRowEven.Padding(0, 2)
|
|
||||||
default:
|
|
||||||
style = ui.TableRowOdd.Padding(0, 2)
|
|
||||||
}
|
|
||||||
switch col {
|
|
||||||
case 0, 1:
|
|
||||||
style = style.Width(25)
|
|
||||||
case 2:
|
|
||||||
style = style.Width(availableWidth - 50 - 10)
|
|
||||||
}
|
|
||||||
return style
|
|
||||||
}).
|
|
||||||
Headers("Variable name", "Default value", "Used value")
|
|
||||||
for _, v := range m.variables {
|
|
||||||
used := fmt.Sprintf("%v", v.Value)
|
|
||||||
if used == "" {
|
|
||||||
used = "<пусто>"
|
|
||||||
}
|
|
||||||
t.Row(v.Name, v.Default, used)
|
|
||||||
}
|
|
||||||
m.table = t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *FinalModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m *FinalModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
|
||||||
return m, tea.Quit
|
|
||||||
case "up":
|
case "up":
|
||||||
m.viewport.ScrollUp(1)
|
m.viewport.ScrollUp(1)
|
||||||
case "down":
|
case "down":
|
||||||
m.viewport.ScrollDown(1)
|
m.viewport.ScrollDown(1)
|
||||||
|
case "left":
|
||||||
|
m.viewport.ScrollLeft(1)
|
||||||
|
case "right":
|
||||||
|
m.viewport.ScrollRight(1)
|
||||||
case "pageup":
|
case "pageup":
|
||||||
m.viewport.HalfPageUp()
|
m.viewport.HalfPageUp()
|
||||||
case "pagedown":
|
case "pagedown":
|
||||||
|
|
@ -107,15 +59,9 @@ func (m *FinalModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
m.viewport.GotoBottom()
|
m.viewport.GotoBottom()
|
||||||
}
|
}
|
||||||
case tea.WindowSizeMsg:
|
case tea.WindowSizeMsg:
|
||||||
if !m.ready {
|
m.height = msg.Height
|
||||||
m.initViewport(msg.Width, msg.Height)
|
m.width = msg.Width
|
||||||
} else {
|
m.initViewport(msg.Width, msg.Height)
|
||||||
m.viewport.Width = msg.Width - 4
|
|
||||||
m.viewport.Height = msg.Height - 6
|
|
||||||
}
|
|
||||||
m.rebuildTable(m.viewport.Width)
|
|
||||||
rendered := m.table.Render()
|
|
||||||
m.viewport.SetContent(rendered)
|
|
||||||
}
|
}
|
||||||
m.viewport, cmd = m.viewport.Update(msg)
|
m.viewport, cmd = m.viewport.Update(msg)
|
||||||
return m, cmd
|
return m, cmd
|
||||||
|
|
@ -125,76 +71,103 @@ func (m *FinalModel) View() string {
|
||||||
if !m.ready {
|
if !m.ready {
|
||||||
return "Загрузка таблицы"
|
return "Загрузка таблицы"
|
||||||
}
|
}
|
||||||
|
containerWidth, containerHeight, contentWidth, _ := ui.ContentSizes(m.width, m.height)
|
||||||
|
|
||||||
contentWidth := ui.ContentWidth(m.width)
|
|
||||||
m.rebuildTable(contentWidth)
|
m.rebuildTable(contentWidth)
|
||||||
|
|
||||||
header := ui.HeaderStyle.Width(contentWidth).Render("Итоговые значения переменных")
|
header := ui.FinalHeader.
|
||||||
footer := ui.FooterStyle.Width(contentWidth).Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
Width(contentWidth).
|
||||||
|
Render("Итоговые значения переменных")
|
||||||
m.viewport.Width = contentWidth - 8
|
footer := ui.FinalFooter.
|
||||||
m.viewport.Height = m.height - 12
|
Width(contentWidth).
|
||||||
m.viewport.SetContent(m.table.Render())
|
Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
||||||
|
|
||||||
|
renderedTable := m.table.Render()
|
||||||
|
content := lipgloss.NewStyle().
|
||||||
|
Align(lipgloss.Center).
|
||||||
|
Render(renderedTable)
|
||||||
|
m.viewport.SetContent(content)
|
||||||
body := m.viewport.View()
|
body := m.viewport.View()
|
||||||
|
fullContent := lipgloss.JoinVertical(lipgloss.Top, header, body, footer)
|
||||||
|
|
||||||
content := lipgloss.JoinVertical(lipgloss.Left, header, body, footer)
|
container := ui.AppContainer.
|
||||||
container := ui.AppContainer.Width(contentWidth).Render(content)
|
Width(containerWidth).
|
||||||
|
Height(containerHeight).
|
||||||
return lipgloss.Place(m.width, m.height,
|
Render(fullContent)
|
||||||
|
return lipgloss.Place(
|
||||||
|
m.width, m.height,
|
||||||
lipgloss.Center, lipgloss.Center,
|
lipgloss.Center, lipgloss.Center,
|
||||||
container,
|
container,
|
||||||
lipgloss.WithWhitespaceChars("░"),
|
lipgloss.WithWhitespaceChars("+"),
|
||||||
lipgloss.WithWhitespaceForeground(ui.ColorGrey),
|
lipgloss.WithWhitespaceForeground(ui.ColorError),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
//contentWidth := ui.AppContentWidth(m.width)
|
|
||||||
//m.viewport.Width = contentWidth - 6
|
func (m *FinalModel) initViewport(width, height int) {
|
||||||
//m.viewport.Height = m.height - 12
|
|
||||||
//m.rebuildTable(contentWidth)
|
_, _, contentWidth, contentHeight := ui.ContentSizes(width, height)
|
||||||
//
|
|
||||||
//header := ui.AppHeaderStyle.
|
tableWidth := contentWidth - 2*1
|
||||||
// Width(contentWidth).
|
tableHeight := int(float64(contentHeight)*ui.TableWithRatio) - 2*1
|
||||||
// Render("Итоговые значения переменных")
|
|
||||||
//
|
m.viewport = viewport.New(contentWidth, tableHeight)
|
||||||
//footer := ui.AppFooterStyle.
|
//размеры для viewport в нем будет находиться таблица и перемещаться в зависимости от команд
|
||||||
// Width(contentWidth).
|
|
||||||
// Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
m.ready = true
|
||||||
//
|
m.rebuildTable(tableWidth)
|
||||||
//body := m.viewport.View()
|
m.viewport.SetContent(m.table.Render())
|
||||||
//content := lipgloss.JoinVertical(lipgloss.Left, header, body, footer)
|
}
|
||||||
//
|
|
||||||
//container := ui.AppContainerStyle.
|
func (m *FinalModel) rebuildTable(width int) {
|
||||||
// Width(contentWidth).
|
if len(m.variables) == 0 {
|
||||||
// Render(content)
|
m.table = table.New().
|
||||||
//
|
Border(lipgloss.RoundedBorder()).
|
||||||
//return lipgloss.Place(m.width, m.height,
|
BorderStyle(ui.FinalTableBorder).
|
||||||
// lipgloss.Center, lipgloss.Center,
|
StyleFunc(func(row, col int) lipgloss.Style {
|
||||||
// container,
|
return ui.FinalTableHeader
|
||||||
// lipgloss.WithWhitespaceChars("░"),
|
}).Headers("Нет переменных")
|
||||||
// lipgloss.WithWhitespaceForeground(ui.ColorGrey),
|
return
|
||||||
//)
|
}
|
||||||
|
variableNameColWidth := 15
|
||||||
//header := lipgloss.NewStyle().
|
defaultValueColWidth := 25
|
||||||
// Width(m.viewport.Width).
|
usedValueColWidth := width - variableNameColWidth - defaultValueColWidth - 4*1
|
||||||
// Align(lipgloss.Center).
|
//ширина таблицы - ширина первой колонки - ширина второй колонки - 4 границы (2 крайние, 2 между колонками)
|
||||||
// Bold(true).
|
if usedValueColWidth < 30 { //если значение сильно меньше
|
||||||
// Background(ui.ColorPurple).
|
usedValueColWidth = 30
|
||||||
// Foreground(ui.ColorWhite).
|
}
|
||||||
// Padding(1).
|
|
||||||
// Render("Итоговые значения переменных")
|
t := table.New().
|
||||||
//
|
Width(variableNameColWidth+defaultValueColWidth+usedValueColWidth+4).
|
||||||
//footer := lipgloss.NewStyle().
|
Border(lipgloss.RoundedBorder()).
|
||||||
// Width(m.viewport.Width).
|
BorderStyle(ui.FinalTableBorder).
|
||||||
// Align(lipgloss.Center).
|
StyleFunc(func(row, col int) lipgloss.Style {
|
||||||
// Foreground(ui.ColorGrey).
|
var style lipgloss.Style
|
||||||
// Padding(0, 1).
|
if row == table.HeaderRow {
|
||||||
// Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
return ui.FinalTableHeader
|
||||||
//
|
}
|
||||||
//body := m.viewport.View()
|
if row%2 == 0 {
|
||||||
//return lipgloss.JoinVertical(lipgloss.Center,
|
style = ui.FinalTableEvenRow
|
||||||
// header,
|
} else {
|
||||||
// body,
|
style = ui.FinalTableOddRow
|
||||||
// footer,
|
}
|
||||||
//)
|
switch col {
|
||||||
|
case 0:
|
||||||
|
return style.Width(variableNameColWidth).Align(lipgloss.Left)
|
||||||
|
case 1:
|
||||||
|
return style.Width(defaultValueColWidth).Align(lipgloss.Left)
|
||||||
|
case 2:
|
||||||
|
return style.Width(usedValueColWidth).Align(lipgloss.Left)
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
}).
|
||||||
|
Headers("Variable name", "Default value", "Used value")
|
||||||
|
|
||||||
|
for _, v := range m.variables {
|
||||||
|
used := fmt.Sprintf("%v", v.Value)
|
||||||
|
if used == "" {
|
||||||
|
used = "<Пусто>"
|
||||||
|
}
|
||||||
|
t.Row(v.Name, v.Default, used)
|
||||||
|
}
|
||||||
|
m.table = t
|
||||||
}
|
}
|
||||||
|
|
|
||||||
118
setup/form.go
118
setup/form.go
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"bubble/types"
|
"bubble/types"
|
||||||
"fmt"
|
"fmt"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/glamour"
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/muesli/reflow/wordwrap"
|
"github.com/muesli/reflow/wordwrap"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FormModel struct {
|
type FormModel struct {
|
||||||
|
|
@ -77,12 +77,7 @@ func NewFormModel(application *types.PackageApplication, sectionIdx, focus, widt
|
||||||
height: height,
|
height: height,
|
||||||
}
|
}
|
||||||
if currentSection.Type == types.SectionAbout {
|
if currentSection.Type == types.SectionAbout {
|
||||||
md := strings.Join(currentSection.Paragraphs, "\n\n")
|
m.renderedContent = simpleAboutRender(currentSection.Paragraphs, width)
|
||||||
renderer, _ := glamour.NewTermRenderer(
|
|
||||||
glamour.WithAutoStyle(),
|
|
||||||
glamour.WithWordWrap(width-10))
|
|
||||||
rendered, _ := renderer.Render(md)
|
|
||||||
m.renderedContent = rendered
|
|
||||||
m.focus = 0
|
m.focus = 0
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
|
|
@ -93,24 +88,17 @@ func (m *FormModel) Init() tea.Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FormModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m *FormModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.WindowSizeMsg:
|
case tea.WindowSizeMsg:
|
||||||
m.width = msg.Width
|
m.width = msg.Width
|
||||||
m.height = msg.Height
|
m.height = msg.Height
|
||||||
if m.CurrentSection.Type == types.SectionAbout {
|
if m.CurrentSection.Type == types.SectionAbout {
|
||||||
md := strings.Join(m.CurrentSection.Paragraphs, "\n\n")
|
m.renderedContent = simpleAboutRender(m.CurrentSection.Paragraphs, m.width)
|
||||||
renderer, _ := glamour.NewTermRenderer(
|
|
||||||
glamour.WithAutoStyle(),
|
|
||||||
glamour.WithWordWrap(m.width-10),
|
|
||||||
)
|
|
||||||
rendered, _ := renderer.Render(md)
|
|
||||||
m.renderedContent = rendered
|
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
|
||||||
return m, tea.Quit
|
|
||||||
case "esc":
|
case "esc":
|
||||||
for _, field := range m.FieldModels {
|
for _, field := range m.FieldModels {
|
||||||
if field.CaptureKeys() {
|
if field.CaptureKeys() {
|
||||||
|
|
@ -134,7 +122,6 @@ func (m *FormModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//вернуться к списку приложений, чтобы выбрать другое приложение.
|
|
||||||
case "enter":
|
case "enter":
|
||||||
logrus.Infof("sections %s, focus %d, fields len %d", m.CurrentSection.Name, m.focus, len(m.FieldModels))
|
logrus.Infof("sections %s, focus %d, fields len %d", m.CurrentSection.Name, m.focus, len(m.FieldModels))
|
||||||
if len(m.FieldModels) == m.focus {
|
if len(m.FieldModels) == m.focus {
|
||||||
|
|
@ -176,71 +163,45 @@ func (m *FormModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
case types.SelectedOptionMsg:
|
case types.SelectedOptionMsg:
|
||||||
logrus.Infof("chose %+v", msg)
|
logrus.Infof("chose %+v", msg)
|
||||||
}
|
}
|
||||||
cmd := m.updateFields(msg)
|
return m, m.updateFields(msg)
|
||||||
return m, cmd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FormModel) View() string {
|
func (m *FormModel) View() string {
|
||||||
contentWidth := ui.ContentWidth(m.width)
|
|
||||||
|
|
||||||
var res strings.Builder
|
containerWidth, containerHeight, contentWidth, _ := ui.ContentSizes(m.width, m.height)
|
||||||
|
|
||||||
|
formWidth := contentWidth - 2*1
|
||||||
|
var strokes []string
|
||||||
for i, field := range m.FieldModels {
|
for i, field := range m.FieldModels {
|
||||||
fieldStr := wordwrap.String(field.View(), contentWidth-10)
|
fieldStroke := wordwrap.String(field.View(), formWidth)
|
||||||
if i == m.focus {
|
if i == m.focus {
|
||||||
res.WriteString(ui.FormFieldFocused.Render(fieldStr))
|
strokes = append(strokes, ui.FormFieldFocused.Render(fieldStroke))
|
||||||
} else {
|
} else {
|
||||||
res.WriteString(ui.FormFieldUnfocused.Render(fieldStr))
|
strokes = append(strokes, ui.FormFieldUnfocused.Render(fieldStroke))
|
||||||
}
|
}
|
||||||
res.WriteString("\n\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.CurrentSection.Type == types.SectionAbout {
|
if m.CurrentSection.Type == types.SectionAbout {
|
||||||
res.WriteString(m.renderedContent)
|
strokes = append([]string{}, m.renderedContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextBtn := "[ next section ]"
|
nextBtn := "[ next section ]"
|
||||||
if m.focus == len(m.FieldModels) {
|
if m.focus == len(m.FieldModels) {
|
||||||
res.WriteString(ui.FormNextButton.Render(nextBtn))
|
strokes = append(strokes, ui.FormNextButton.Render(nextBtn))
|
||||||
} else {
|
} else {
|
||||||
res.WriteString(ui.FormFieldUnfocused.Render(nextBtn))
|
strokes = append(strokes, ui.FormFieldUnfocused.Render(nextBtn))
|
||||||
}
|
}
|
||||||
|
|
||||||
container := ui.FormContainer.Width(contentWidth).Render(res.String())
|
container := ui.AppContainer.
|
||||||
return lipgloss.Place(m.width, m.height,
|
Width(containerWidth).
|
||||||
|
Height(containerHeight).
|
||||||
|
Render(strings.Join(strokes, "\n\n"))
|
||||||
|
return lipgloss.Place(
|
||||||
|
m.width, m.height,
|
||||||
lipgloss.Center, lipgloss.Center,
|
lipgloss.Center, lipgloss.Center,
|
||||||
container,
|
container,
|
||||||
lipgloss.WithWhitespaceChars(" "),
|
lipgloss.WithWhitespaceChars(" "),
|
||||||
)
|
)
|
||||||
|
|
||||||
//for i, field := range m.FieldModels {
|
|
||||||
// fieldStr := wordwrap.String(field.View(), contentWidth-8)
|
|
||||||
// if i == m.focus {
|
|
||||||
// res.WriteString(ui.FormFocusedStyle.Render(fieldStr))
|
|
||||||
// } else {
|
|
||||||
// res.WriteString(ui.FormUnfocusedStyle.Render(fieldStr))
|
|
||||||
// }
|
|
||||||
// res.WriteString("\n\n")
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//if m.CurrentSection.Type == types.SectionAbout {
|
|
||||||
// res.WriteString("\n\n" + m.renderedContent)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//button := "[ next section ]"
|
|
||||||
//if m.focus == len(m.FieldModels) {
|
|
||||||
// res.WriteString(ui.FormFocusedStyle.Render(button))
|
|
||||||
//} else {
|
|
||||||
// res.WriteString(ui.FormUnfocusedStyle.Render(button))
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//container := ui.FormStyle.Width(contentWidth).Render(res.String())
|
|
||||||
//
|
|
||||||
//return lipgloss.Place(m.width, m.height,
|
|
||||||
// lipgloss.Center, lipgloss.Top,
|
|
||||||
// container,
|
|
||||||
// lipgloss.WithWhitespaceChars(" "),
|
|
||||||
//)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FormModel) updateFields(msg tea.Msg) tea.Cmd {
|
func (m *FormModel) updateFields(msg tea.Msg) tea.Cmd {
|
||||||
|
|
@ -283,3 +244,42 @@ func (m *FormModel) updateFields(msg tea.Msg) tea.Cmd {
|
||||||
}
|
}
|
||||||
return tea.Batch(cmds...)
|
return tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func simpleAboutRender(paragraphs []string, width int) string {
|
||||||
|
var sb strings.Builder
|
||||||
|
for _, p := range paragraphs {
|
||||||
|
p = strings.TrimSpace(p)
|
||||||
|
if p == "" {
|
||||||
|
sb.WriteString("\n")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(p, "# "):
|
||||||
|
// Заголовок 1 уровня
|
||||||
|
h1Len := utf8.RuneCountInString(p[2:])
|
||||||
|
h1Offset := strings.Repeat(" ", (width-h1Len)/2)
|
||||||
|
sb.WriteString(ui.AboutTitle.Render(h1Offset+p[2:]) + "\n\n")
|
||||||
|
case strings.HasPrefix(p, "## "):
|
||||||
|
// Заголовок 2 уровня
|
||||||
|
sb.WriteString(ui.AboutH2.Render(p[3:]) + "\n\n")
|
||||||
|
case strings.HasPrefix(p, "### "):
|
||||||
|
// Заголовок 3 уровня
|
||||||
|
sb.WriteString(" " + ui.AboutH3.Render(p[4:]) + "\n\n")
|
||||||
|
case strings.HasPrefix(p, "- "), strings.HasPrefix(p, "* "):
|
||||||
|
// Список простой
|
||||||
|
text := strings.TrimLeft(p[2:], " ")
|
||||||
|
wrapped := wordwrap.String(text, width-10)
|
||||||
|
sb.WriteString(" " + ui.AboutBullet.Render("• ") + ui.AboutNormal.Render(wrapped) + "\n")
|
||||||
|
case strings.HasPrefix(p, "> "):
|
||||||
|
// Цитаты
|
||||||
|
text := strings.TrimPrefix(p, "> ")
|
||||||
|
wrapped := wordwrap.String(text, width-12)
|
||||||
|
sb.WriteString(" " + ui.AboutNormal.Foreground(ui.ColorGrey).Render("│ "+wrapped) + "\n")
|
||||||
|
default:
|
||||||
|
// Обычный текст
|
||||||
|
wrapped := wordwrap.String(p, width-8)
|
||||||
|
sb.WriteString(" " + ui.AboutNormal.Render(wrapped) + "\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/charmbracelet/bubbles/list"
|
"github.com/charmbracelet/bubbles/list"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListApplicationItem struct {
|
type ListApplicationItem struct {
|
||||||
|
|
@ -42,9 +43,9 @@ func NewListApplicationsModel(applications []types.PackageApplication, width, he
|
||||||
delegate.Styles.SelectedDesc = ui.ListSelectedStyle
|
delegate.Styles.SelectedDesc = ui.ListSelectedStyle
|
||||||
delegate.ShowDescription = false
|
delegate.ShowDescription = false
|
||||||
l := list.New(items, delegate, width, height)
|
l := list.New(items, delegate, width, height)
|
||||||
l.Title = "Выберите приложение для настройки"
|
l.Title = "Приложения"
|
||||||
l.Styles.Title = ui.ListTitleStyle
|
l.Styles.Title = ui.ListTitleStyle
|
||||||
|
l.SetShowHelp(false)
|
||||||
return &ListApplicationsModel{
|
return &ListApplicationsModel{
|
||||||
List: l,
|
List: l,
|
||||||
width: width,
|
width: width,
|
||||||
|
|
@ -65,15 +66,13 @@ func (m *ListApplicationsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
return m, nil
|
return m, nil
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
|
||||||
return m, tea.Quit
|
|
||||||
case "enter":
|
case "enter":
|
||||||
selected := m.List.SelectedItem().(ListApplicationItem)
|
selected := m.List.SelectedItem().(ListApplicationItem)
|
||||||
return m, func() tea.Msg {
|
return m, func() tea.Msg {
|
||||||
return types.ShowModalMsg{
|
return types.ShowModalMsg{
|
||||||
Type: types.ModalConfirm,
|
Type: types.ModalConfirm,
|
||||||
Title: "Начать установку",
|
Title: "Начать установку",
|
||||||
Message: fmt.Sprintf("Вы хотит настроить приложение:\n\n%s\n\nПродолжить?", selected.Title()),
|
Message: fmt.Sprintf("Вы хотите настроить приложение:\n\n%s\n\nПродолжить?", selected.Title()),
|
||||||
ModalButtons: []types.ModalButton{
|
ModalButtons: []types.ModalButton{
|
||||||
{Text: "Да", Value: true},
|
{Text: "Да", Value: true},
|
||||||
{Text: "Нет", Value: false},
|
{Text: "Нет", Value: false},
|
||||||
|
|
@ -95,46 +94,63 @@ func (m *ListApplicationsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ListApplicationsModel) View() string {
|
func (m *ListApplicationsModel) View() string {
|
||||||
contentWidth := ui.ContentWidth(m.width)
|
gapStroke := " "
|
||||||
listWidth := int(float64(contentWidth) * ui.ListWithRatio)
|
containerWidth, containerHeight, contentWidth, contentHeight := ui.ContentSizes(m.width, m.height)
|
||||||
m.List.SetSize(listWidth-6, m.height-10)
|
|
||||||
|
|
||||||
listView := m.List.View()
|
listWidth := int(float64(contentWidth)*ui.ListWithRatio) - 2*1
|
||||||
|
//ширина листа = пропорция от ширины контента - границы для контейнера листа
|
||||||
|
listHeight := contentHeight - 2*1
|
||||||
|
//высота листа = высота контента - границы для контейнера листа
|
||||||
|
descWidth := int(float64(contentWidth)*(1-ui.ListWithRatio)) - 2*1 - len(gapStroke)
|
||||||
|
//ширина описания = обратная пропорция листа от ширины контента - границы для контейнера описания - отступ от контейнера листа
|
||||||
|
descHeight := contentHeight - 2*1
|
||||||
|
//высота листа = высота контента - границы для контейнера описания
|
||||||
|
|
||||||
|
m.List.SetSize(listWidth, listHeight)
|
||||||
|
|
||||||
|
//logs.go logrus.DebugLevel set
|
||||||
|
logrus.Debugf(
|
||||||
|
"window: width %d, height %d\ncontainer: width %d, height %d\ncontent: width %d, height %d\nlist: width %d, height %d\ndesc: width %d, height %d\n\n",
|
||||||
|
m.width, m.height,
|
||||||
|
containerWidth, containerHeight,
|
||||||
|
contentWidth, contentHeight,
|
||||||
|
listWidth, listHeight,
|
||||||
|
descWidth, descHeight,
|
||||||
|
)
|
||||||
|
|
||||||
|
listView := lipgloss.NewStyle().
|
||||||
|
Width(listWidth).
|
||||||
|
Height(listHeight).
|
||||||
|
Border(lipgloss.RoundedBorder()).
|
||||||
|
BorderForeground(ui.ColorPurple).
|
||||||
|
AlignVertical(lipgloss.Top).
|
||||||
|
Render(m.List.View())
|
||||||
|
|
||||||
var desc string
|
var desc string
|
||||||
if sel := m.List.SelectedItem(); sel != nil {
|
if sel := m.List.SelectedItem(); sel != nil {
|
||||||
desc = sel.(ListApplicationItem).Description()
|
desc = sel.(ListApplicationItem).Description()
|
||||||
}
|
}
|
||||||
descView := ui.ListDescriptionStyle.Width(contentWidth - listWidth - 10).Render(desc)
|
|
||||||
body := lipgloss.JoinHorizontal(lipgloss.Top, listView, " ", descView)
|
|
||||||
container := ui.ListContainer.Width(contentWidth).Render(body)
|
|
||||||
|
|
||||||
return lipgloss.Place(m.width, m.height,
|
descView := ui.ListDescriptionStyle.
|
||||||
|
Width(descWidth).
|
||||||
|
Height(descHeight).
|
||||||
|
Border(lipgloss.RoundedBorder()).
|
||||||
|
BorderForeground(ui.ColorError).
|
||||||
|
AlignVertical(lipgloss.Top).
|
||||||
|
Render(
|
||||||
|
desc,
|
||||||
|
)
|
||||||
|
|
||||||
|
body := lipgloss.JoinHorizontal(lipgloss.Center, listView, gapStroke, descView)
|
||||||
|
container := ui.AppContainer.
|
||||||
|
Width(containerWidth).
|
||||||
|
Height(containerHeight).
|
||||||
|
Render(body)
|
||||||
|
return lipgloss.Place(
|
||||||
|
m.width, m.height,
|
||||||
lipgloss.Center, lipgloss.Center,
|
lipgloss.Center, lipgloss.Center,
|
||||||
container,
|
container,
|
||||||
lipgloss.WithWhitespaceChars("░"),
|
lipgloss.WithWhitespaceChars("░"),
|
||||||
lipgloss.WithWhitespaceForeground(ui.ColorGrey),
|
lipgloss.WithWhitespaceForeground(ui.ColorWarning),
|
||||||
)
|
)
|
||||||
|
|
||||||
//var desc string
|
|
||||||
//if selected := m.List.SelectedItem(); selected != nil {
|
|
||||||
// desc = selected.(ListApplicationItem).Description()
|
|
||||||
//}
|
|
||||||
//descView := ui.ListDescriptionStyle.
|
|
||||||
// Width(contentWidth/2 - 4).
|
|
||||||
// Render(desc)
|
|
||||||
//
|
|
||||||
//body := lipgloss.JoinHorizontal(lipgloss.Top, listView, " ", descView)
|
|
||||||
//
|
|
||||||
//container := ui.ListStyle.
|
|
||||||
// Width(contentWidth).
|
|
||||||
// Render(body)
|
|
||||||
//
|
|
||||||
//return lipgloss.Place(m.width, m.height,
|
|
||||||
// lipgloss.Center, lipgloss.Center,
|
|
||||||
// container,
|
|
||||||
// lipgloss.WithWhitespaceChars("░"),
|
|
||||||
// lipgloss.WithWhitespaceForeground(ui.ColorGrey),
|
|
||||||
//)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,24 @@ func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
}
|
}
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c":
|
||||||
return m, tea.Quit
|
return m, func() tea.Msg {
|
||||||
|
return types.ShowModalMsg{
|
||||||
|
Type: types.ModalWarning,
|
||||||
|
Title: "Закрытие приложения",
|
||||||
|
Message: "Вы нажали ctrl+c, вы желаете закрыть приложение?",
|
||||||
|
ModalButtons: []types.ModalButton{
|
||||||
|
{Text: "Закрыть приложение", Value: true},
|
||||||
|
{Text: "Не закрывать", Value: false},
|
||||||
|
},
|
||||||
|
OnResult: func(result any) tea.Cmd {
|
||||||
|
if result == true {
|
||||||
|
return tea.Quit
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case types.NextSectionMsg:
|
case types.NextSectionMsg:
|
||||||
m.CurrentSectionIdx++
|
m.CurrentSectionIdx++
|
||||||
|
|
@ -103,14 +119,12 @@ func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
m.current = NewFinalModel(m.CurrentApplication.Variables, m.Width, m.Height)
|
m.current = NewFinalModel(m.CurrentApplication.Variables, m.Width, m.Height)
|
||||||
} else {
|
} else {
|
||||||
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, 0, m.Width, m.Height)
|
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, 0, m.Width, m.Height)
|
||||||
|
|
||||||
}
|
}
|
||||||
case types.SugarMsg:
|
case types.SugarMsg:
|
||||||
m.Sugar(msg)
|
m.Sugar(msg)
|
||||||
case types.SelectedAppMsg:
|
case types.SelectedAppMsg:
|
||||||
//получаем сообщение о выборе приложения
|
//получаем сообщение о выборе приложения
|
||||||
m.CurrentApplication = &msg.App
|
m.CurrentApplication = &msg.App
|
||||||
|
|
||||||
//ищем доступную секцию
|
//ищем доступную секцию
|
||||||
for sectionIdx := 0; sectionIdx < len(m.CurrentApplication.Sections); sectionIdx++ {
|
for sectionIdx := 0; sectionIdx < len(m.CurrentApplication.Sections); sectionIdx++ {
|
||||||
section := m.CurrentApplication.Sections[sectionIdx]
|
section := m.CurrentApplication.Sections[sectionIdx]
|
||||||
|
|
@ -136,7 +150,6 @@ func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
m.overlay = NewModalModel(msg, m.Width, m.Height)
|
m.overlay = NewModalModel(msg, m.Width, m.Height)
|
||||||
return m, nil
|
return m, nil
|
||||||
case types.CloseModalMsg:
|
case types.CloseModalMsg:
|
||||||
logrus.Infof("modal close msg get")
|
|
||||||
m.overlay = nil
|
m.overlay = nil
|
||||||
return m, tea.Batch(cmds...)
|
return m, tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
150
setup/modal.go
150
setup/modal.go
|
|
@ -73,113 +73,89 @@ func (m *ModalModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ModalModel) View() string {
|
func (m *ModalModel) View() string {
|
||||||
contentWidth := ui.ContentWidth(m.width)
|
|
||||||
modalWidth := min(contentWidth-10, ui.ModalMaxHeight)
|
|
||||||
if modalWidth < 60 {
|
|
||||||
modalWidth = 60
|
|
||||||
}
|
|
||||||
|
|
||||||
content := lipgloss.NewStyle().
|
containerWidth, containerHeight, _, _ := ui.ContentSizes(m.width, m.height)
|
||||||
Width(modalWidth-8).
|
|
||||||
Padding(1, 3).
|
|
||||||
Render(m.message)
|
|
||||||
|
|
||||||
|
modalWidth := min(containerWidth, ui.ModalMaxWidth)
|
||||||
|
modalHeight := min(containerHeight, ui.ModalMaxHeight)
|
||||||
|
|
||||||
|
message := lipgloss.NewStyle().Render(m.message)
|
||||||
var buttons []string
|
var buttons []string
|
||||||
|
for i, button := range m.buttons {
|
||||||
for i, btn := range m.buttons {
|
|
||||||
style := ui.ModalButtonNormal
|
style := ui.ModalButtonNormal
|
||||||
if i == m.focus {
|
if i == m.focus {
|
||||||
style = ui.ModalButtonFocused
|
style = ui.ModalButtonFocused
|
||||||
}
|
}
|
||||||
buttons = append(buttons, style.Render(btn.Text))
|
buttons = append(buttons, style.Render(button.Text))
|
||||||
}
|
}
|
||||||
buttonRow := lipgloss.JoinHorizontal(lipgloss.Center, buttons...)
|
buttonRow := lipgloss.JoinHorizontal(lipgloss.Center, buttons...)
|
||||||
|
modalBody := lipgloss.JoinVertical(lipgloss.Center, message, "", buttonRow)
|
||||||
|
|
||||||
body := lipgloss.JoinVertical(lipgloss.Center, content, "\n\n", buttonRow)
|
var borderColor lipgloss.Color
|
||||||
|
var modalTitleStyle lipgloss.Style
|
||||||
|
|
||||||
// Бордер и цвет в зависимости от типа
|
|
||||||
var modalStyle lipgloss.Style
|
|
||||||
var titleStyle lipgloss.Style
|
|
||||||
switch m.modalType {
|
switch m.modalType {
|
||||||
case types.ModalError:
|
case types.ModalError:
|
||||||
modalStyle = ui.ModalBorderError
|
borderColor = ui.ColorError
|
||||||
titleStyle = ui.ModalTitleError
|
modalTitleStyle = ui.ModalTitleError
|
||||||
case types.ModalWarning, types.ModalConfirm:
|
case types.ModalWarning, types.ModalConfirm:
|
||||||
modalStyle = ui.ModalBorderWarning
|
borderColor = ui.ColorWarning
|
||||||
titleStyle = ui.ModalTitleWarning
|
modalTitleStyle = ui.ModalTitleWarning
|
||||||
default:
|
default:
|
||||||
modalStyle = ui.ModalBorderInfo
|
borderColor = ui.ColorAccent
|
||||||
titleStyle = ui.ModalTitleDefault
|
modalTitleStyle = 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 {
|
//switch m.modalType {
|
||||||
//case types.ModalError:
|
//case types.ModalError:
|
||||||
// borderColor = ui.ColorRed
|
// modalStyle = ui.ModalBorderError
|
||||||
// titleStyle = lipgloss.NewStyle().Foreground(ui.ColorRed).Bold(true)
|
// modalTitleStyle = ui.ModalTitleError
|
||||||
//case types.ModalWarning, types.ModalConfirm:
|
//case types.ModalWarning, types.ModalConfirm:
|
||||||
// borderColor = ui.ColorPurple
|
// modalStyle = ui.ModalBorderWarning
|
||||||
// titleStyle = lipgloss.NewStyle().Foreground(ui.ColorPurple).Bold(true)
|
// modalTitleStyle = ui.ModalTitleWarning
|
||||||
//default:
|
//default:
|
||||||
// borderColor = ui.ColorBlue
|
// modalStyle = ui.ModalBorderInfo
|
||||||
// titleStyle = lipgloss.NewStyle().Foreground(ui.ColorBlue).Bold(true)
|
// modalTitleStyle = ui.ModalTitleDefault
|
||||||
//}
|
//}
|
||||||
//content := lipgloss.NewStyle().Width(m.width-10).Padding(1, 2).Render(m.message)
|
var modalView string
|
||||||
//var buttons []string
|
symbolToRepeat := "*"
|
||||||
//for i, btn := range m.buttons {
|
if m.title != "" {
|
||||||
// style := lipgloss.NewStyle().
|
modalView = ui.ModalContainer.
|
||||||
// Padding(0, 2).
|
Width(modalWidth).
|
||||||
// Border(lipgloss.RoundedBorder()).
|
Height(modalHeight).
|
||||||
// BorderForeground(ui.ColorGrey)
|
Align(lipgloss.Center, lipgloss.Center).
|
||||||
// if i == m.focus {
|
Border(lipgloss.DoubleBorder()).
|
||||||
// style = style.Foreground(ui.ColorRed).BorderForeground(ui.ColorRed).Bold(true)
|
BorderForeground(borderColor).
|
||||||
// } else {
|
Render(modalBody)
|
||||||
// style = style.Foreground(ui.ColorGreenCyan)
|
//modalView = ui.ModalContainer.
|
||||||
// }
|
// Width(modalWidth).
|
||||||
// buttons = append(buttons, style.Render(btn.Text))
|
// Height(modalHeight).
|
||||||
//}
|
// BorderForeground(borderColor).
|
||||||
//buttonShow := lipgloss.JoinHorizontal(lipgloss.Center, buttons...)
|
// Render(modalBody)
|
||||||
//body := lipgloss.JoinVertical(lipgloss.Center, content, "\n", buttonShow)
|
//repeatCount := modalWidth - utf8.RuneCountInString(m.title)
|
||||||
//
|
//if repeatCount < 0 {
|
||||||
//modal := lipgloss.NewStyle().
|
// repeatCount = 0
|
||||||
// Width(modalWidth).
|
//}
|
||||||
// Padding(1, 3).
|
//symbolFill := strings.Repeat(symbolToRepeat, repeatCount/2)
|
||||||
// Border(lipgloss.DoubleBorder()).
|
//modalView = lipgloss.JoinVertical(lipgloss.Center, modalTitleStyle.Render(symbolFill+m.title+symbolFill), modalView)
|
||||||
// BorderForeground(borderColor).
|
modalView = lipgloss.JoinVertical(lipgloss.Center, modalTitleStyle.Render(m.title), modalView)
|
||||||
// Render(body)
|
} else {
|
||||||
//
|
modalView = ui.ModalContainer.
|
||||||
//if m.title != "" {
|
Width(modalWidth).
|
||||||
// title := titleStyle.Width(modalWidth - 6).Render(m.title)
|
Height(modalHeight).
|
||||||
// modal = lipgloss.JoinVertical(lipgloss.Center, title, modal)
|
BorderStyle(lipgloss.ASCIIBorder()).
|
||||||
//}
|
BorderForeground(borderColor).
|
||||||
//
|
Render(modalBody)
|
||||||
//return lipgloss.Place(m.width, m.height,
|
//modalView = modalStyle.
|
||||||
// lipgloss.Center, lipgloss.Center,
|
// Width(modalWidth).
|
||||||
// modal,
|
// Height(modalHeight).
|
||||||
// lipgloss.WithWhitespaceChars("."),
|
// Padding(1, 3).
|
||||||
// lipgloss.WithWhitespaceForeground(ui.ColorPurple),
|
// Border(lipgloss.DoubleBorder()).
|
||||||
//)
|
// Render(modalBody)
|
||||||
|
}
|
||||||
|
return lipgloss.Place(m.width, m.height,
|
||||||
|
lipgloss.Center, lipgloss.Center,
|
||||||
|
modalView,
|
||||||
|
lipgloss.WithWhitespaceChars(symbolToRepeat),
|
||||||
|
lipgloss.WithWhitespaceForeground(ui.ColorGrey))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,63 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import "github.com/charmbracelet/lipgloss"
|
import (
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
const (
|
|
||||||
AppMaxWidth = 110
|
|
||||||
AppMinWidth = 80
|
|
||||||
AppSidePadding = 4
|
|
||||||
ModalMaxWidth = 80
|
|
||||||
ModalMaxHeight = 30
|
|
||||||
ListWithRatio = 0.4
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func AppContentWidth(screenWidth int) int {
|
const (
|
||||||
w := screenWidth - 2*AppSidePadding
|
ApplicationMinWidth = 60
|
||||||
if w > AppMaxWidth {
|
ApplicationMaxHeight = 40
|
||||||
return AppMaxWidth
|
ApplicationMinHeight = 20
|
||||||
|
ApplicationHorizontalOffset = 3
|
||||||
|
ApplicationVerticalOffset = 1
|
||||||
|
ApplicationContainerPadding = 4
|
||||||
|
|
||||||
|
ModalMaxWidth = 50
|
||||||
|
ModalMaxHeight = 15
|
||||||
|
ListWithRatio = 0.4
|
||||||
|
TableWithRatio = 0.8
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContentSizes вычисляет размеры для контейнера внутри окна и контента внутри контейнера.
|
||||||
|
//
|
||||||
|
// Принимает 2 параметра типа int, screenWidth и screenHeight ширина и высота окна.
|
||||||
|
//
|
||||||
|
// Возвращает 4 значения типа int.
|
||||||
|
//
|
||||||
|
// containerWidth это ширина контейнера внутри окна с отступами от левого и правого краёв, и с учетом границ
|
||||||
|
//
|
||||||
|
// containerHeight это высота контейнера внутри окна с отступами от верхнего и нижнего краёв, и с учетом границ
|
||||||
|
//
|
||||||
|
// contentWidth это ширина контента внутри контейнера с отступами от левого и правого краёв контейнера
|
||||||
|
//
|
||||||
|
// contentHeight это высота контента внутри контейнера с отступами от верхнего и нижнего краёв контейнера
|
||||||
|
func ContentSizes(screenWidth, screenHeight int) (containerWidth, containerHeight, contentWidth, contentHeight int) {
|
||||||
|
containerWidth = screenWidth - 2*ApplicationHorizontalOffset
|
||||||
|
if containerWidth < ApplicationMinWidth {
|
||||||
|
//если ширина слишком маленькая ставим минимальную поддерживаемую
|
||||||
|
containerWidth = ApplicationMinWidth
|
||||||
}
|
}
|
||||||
if w < AppMinWidth {
|
containerWidth = containerWidth - 2*1
|
||||||
return AppMinWidth
|
//Вычитаем из ширины контейнера 2 условных единицы для границ
|
||||||
|
//Пример, окно 70, контейнер будет 64, места для контента тогда 62
|
||||||
|
|
||||||
|
containerHeight = screenHeight - 2*ApplicationVerticalOffset
|
||||||
|
if containerHeight < ApplicationMinHeight {
|
||||||
|
//если высота слишком маленькая ставим минимально поддерживаемую
|
||||||
|
containerHeight = ApplicationMinHeight
|
||||||
}
|
}
|
||||||
return w
|
containerHeight = containerHeight - 2*1
|
||||||
|
//Вычитаем из высоты контейнера 2 условных единицы для границ
|
||||||
|
//Пример, окно 30, контейнер будет 28, места для контента тогда 26
|
||||||
|
|
||||||
|
contentWidth = containerWidth - 2*ApplicationHorizontalOffset
|
||||||
|
//Вычитаем из ширины контейнера отступы для контента внутри
|
||||||
|
contentHeight = containerHeight - 2*ApplicationVerticalOffset
|
||||||
|
//Вычитаем из высоты контейнера отступы для контента внутри
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Используемые цвета
|
||||||
var (
|
var (
|
||||||
ColorFg = lipgloss.Color("#eeeeee")
|
ColorFg = lipgloss.Color("#eeeeee")
|
||||||
ColorBg = lipgloss.Color("#0d1117")
|
ColorBg = lipgloss.Color("#0d1117")
|
||||||
|
|
@ -32,34 +68,93 @@ var (
|
||||||
ColorPurple = lipgloss.Color("#cba6f7")
|
ColorPurple = lipgloss.Color("#cba6f7")
|
||||||
ColorGrey = lipgloss.Color("#585b70")
|
ColorGrey = lipgloss.Color("#585b70")
|
||||||
ColorDarkGrey = lipgloss.Color("#313244")
|
ColorDarkGrey = lipgloss.Color("#313244")
|
||||||
|
)
|
||||||
|
|
||||||
AppContainer = lipgloss.NewStyle().
|
var AppContainer = lipgloss.NewStyle().
|
||||||
Padding(2, 4).
|
Padding(ApplicationVerticalOffset, ApplicationHorizontalOffset).
|
||||||
Border(lipgloss.RoundedBorder()).
|
Border(lipgloss.RoundedBorder()).
|
||||||
BorderForeground(ColorPurple)
|
BorderForeground(ColorAccent)
|
||||||
|
|
||||||
HeaderStyle = lipgloss.NewStyle().
|
|
||||||
Bold(true).
|
|
||||||
Foreground(ColorPurple).
|
|
||||||
Background(ColorDarkGrey).
|
|
||||||
Padding(1, 2).
|
|
||||||
MarginBottom(1).
|
|
||||||
Align(lipgloss.Center)
|
|
||||||
|
|
||||||
FooterStyle = lipgloss.NewStyle().
|
|
||||||
Foreground(ColorGrey).
|
|
||||||
Padding(0, 2).
|
|
||||||
MarginTop(1).
|
|
||||||
Align(lipgloss.Center)
|
|
||||||
|
|
||||||
ListContainer = lipgloss.NewStyle().
|
|
||||||
Padding(1, 3).
|
|
||||||
Border(lipgloss.RoundedBorder()).
|
|
||||||
BorderForeground(ColorAccent)
|
|
||||||
|
|
||||||
|
// Стили для списка приложений
|
||||||
|
var (
|
||||||
ListTitleStyle = lipgloss.NewStyle().Foreground(ColorPurple).Italic(true).Bold(true)
|
ListTitleStyle = lipgloss.NewStyle().Foreground(ColorPurple).Italic(true).Bold(true)
|
||||||
ListSelectedStyle = lipgloss.NewStyle().Foreground(ColorError).Bold(true)
|
ListSelectedStyle = lipgloss.NewStyle().Foreground(ColorError).Bold(true)
|
||||||
ListDescriptionStyle = lipgloss.NewStyle().Foreground(ColorAccent2).MarginTop(1)
|
ListDescriptionStyle = lipgloss.NewStyle().Foreground(ColorAccent2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Стили для about
|
||||||
|
var (
|
||||||
|
AboutTitle = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorAccent).
|
||||||
|
Bold(true).
|
||||||
|
AlignHorizontal(lipgloss.Center)
|
||||||
|
|
||||||
|
AboutH2 = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorAccent).
|
||||||
|
Bold(true)
|
||||||
|
|
||||||
|
AboutH3 = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorAccent).
|
||||||
|
Bold(true)
|
||||||
|
|
||||||
|
AboutBullet = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorGrey)
|
||||||
|
|
||||||
|
AboutNormal = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorFg)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Стили для форм и полей ввода
|
||||||
|
var (
|
||||||
|
FormFieldFocused = lipgloss.NewStyle().Foreground(ColorError).Bold(true)
|
||||||
|
FormFieldUnfocused = lipgloss.NewStyle().Foreground(ColorAccent2)
|
||||||
|
FormNextButton = lipgloss.NewStyle().Foreground(ColorPurple).Bold(true)
|
||||||
|
|
||||||
|
SelectFileDirDeniedStyle = lipgloss.NewStyle().Foreground(ColorGrey)
|
||||||
|
SelectFileDirParentStyle = lipgloss.NewStyle().Foreground(ColorPurple)
|
||||||
|
SelectFileStyle = lipgloss.NewStyle().Foreground(ColorAccent)
|
||||||
|
SelectDirStyle = lipgloss.NewStyle().Foreground(ColorAccent2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Стили для таблицы переменных Final
|
||||||
|
var (
|
||||||
|
FinalHeader = lipgloss.NewStyle().
|
||||||
|
Background(ColorDarkGrey).
|
||||||
|
Foreground(ColorPurple).
|
||||||
|
Bold(true).
|
||||||
|
Align(lipgloss.Center).
|
||||||
|
MarginBottom(1).
|
||||||
|
Padding(1, 2)
|
||||||
|
|
||||||
|
FinalFooter = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorGrey).
|
||||||
|
MarginTop(1).
|
||||||
|
Padding(1, 0).
|
||||||
|
Align(lipgloss.Center)
|
||||||
|
|
||||||
|
FinalTableBorder = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorPurple)
|
||||||
|
|
||||||
|
FinalTableHeader = lipgloss.NewStyle().
|
||||||
|
Foreground(ColorPurple).
|
||||||
|
Bold(true).
|
||||||
|
Align(lipgloss.Center).
|
||||||
|
Padding(0, 1)
|
||||||
|
|
||||||
|
FinalTableEvenRow = lipgloss.NewStyle().
|
||||||
|
Background(ColorDarkGrey).
|
||||||
|
Padding(0, 2)
|
||||||
|
|
||||||
|
FinalTableOddRow = lipgloss.NewStyle().
|
||||||
|
Padding(0, 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Стили для модальных окон
|
||||||
|
var (
|
||||||
|
ModalContainer = lipgloss.NewStyle().
|
||||||
|
Border(lipgloss.DoubleBorder()).
|
||||||
|
Align(lipgloss.Center, lipgloss.Center)
|
||||||
|
//Padding(ApplicationVerticalOffset, ApplicationHorizontalOffset)
|
||||||
|
|
||||||
ModalBorderError = lipgloss.NewStyle().BorderForeground(ColorError)
|
ModalBorderError = lipgloss.NewStyle().BorderForeground(ColorError)
|
||||||
ModalBorderWarning = lipgloss.NewStyle().BorderForeground(ColorWarning)
|
ModalBorderWarning = lipgloss.NewStyle().BorderForeground(ColorWarning)
|
||||||
|
|
@ -82,84 +177,57 @@ var (
|
||||||
BorderForeground(ColorError).
|
BorderForeground(ColorError).
|
||||||
Foreground(ColorError).
|
Foreground(ColorError).
|
||||||
Bold(true)
|
Bold(true)
|
||||||
|
|
||||||
FormContainer = lipgloss.NewStyle().
|
|
||||||
Padding(2, 4).
|
|
||||||
Border(lipgloss.RoundedBorder()).
|
|
||||||
BorderForeground(ColorAccent)
|
|
||||||
|
|
||||||
FormFieldFocused = lipgloss.NewStyle().Foreground(ColorError).Bold(true)
|
|
||||||
FormFieldUnfocused = lipgloss.NewStyle().Foreground(ColorAccent2)
|
|
||||||
FormNextButton = lipgloss.NewStyle().Foreground(ColorPurple).Bold(true)
|
|
||||||
|
|
||||||
TableBorder = lipgloss.NewStyle().Foreground(ColorPurple)
|
|
||||||
TableHeader = lipgloss.NewStyle().Foreground(ColorPurple).Bold(true).Align(lipgloss.Center)
|
|
||||||
TableRowEven = lipgloss.NewStyle().Foreground(ColorFg).Background(ColorDarkGrey)
|
|
||||||
TableRowOdd = lipgloss.NewStyle().Foreground(ColorFg)
|
|
||||||
TableCell = lipgloss.NewStyle().Padding(0, 2)
|
|
||||||
|
|
||||||
//ColorWhite = lipgloss.Color("#ffffff")
|
|
||||||
//ColorGrey = lipgloss.Color("#626262")
|
|
||||||
//ColorBlack = lipgloss.Color("#000000")
|
|
||||||
//ColorRed = lipgloss.Color("#FF0000")
|
|
||||||
//ColorGreen = lipgloss.Color("#00FF00")
|
|
||||||
//ColorBlue = lipgloss.Color("#0000FF")
|
|
||||||
//ColorPurple = lipgloss.Color("#6f03fc")
|
|
||||||
//ColorGreenCyan = lipgloss.Color("#11CAAA")
|
|
||||||
//
|
|
||||||
//AppContainerStyle = lipgloss.NewStyle().
|
|
||||||
// Padding(1, 3).
|
|
||||||
// Border(lipgloss.RoundedBorder()).
|
|
||||||
// BorderForeground(ColorPurple)
|
|
||||||
//
|
|
||||||
//AppHeaderStyle = lipgloss.NewStyle().
|
|
||||||
// Bold(true).
|
|
||||||
// Foreground(ColorPurple).
|
|
||||||
// Align(lipgloss.Center).
|
|
||||||
// Padding(1, 0).
|
|
||||||
// Background(ColorWhite).
|
|
||||||
// Foreground(ColorBlack)
|
|
||||||
//
|
|
||||||
//AppFooterStyle = lipgloss.NewStyle().
|
|
||||||
// Foreground(ColorGrey).
|
|
||||||
// Align(lipgloss.Center).
|
|
||||||
// Padding(0, 1)
|
|
||||||
//
|
|
||||||
//TableHeaderStyle = lipgloss.NewStyle().Foreground(ColorPurple).Bold(true).Align(lipgloss.Center)
|
|
||||||
//TableCellStyle = lipgloss.NewStyle().Padding(0, 1).Width(14)
|
|
||||||
//TableOddRowStyle = TableCellStyle.Foreground(ColorWhite).Background(ColorGrey)
|
|
||||||
//TableEvenRowStyle = TableCellStyle.Foreground(ColorWhite)
|
|
||||||
//TableBorderStyle = lipgloss.NewStyle().Foreground(ColorPurple)
|
|
||||||
//
|
|
||||||
SelectFileDirDeniedStyle = lipgloss.NewStyle().Foreground(ColorGrey)
|
|
||||||
SelectFileDirParentStyle = lipgloss.NewStyle().Foreground(ColorPurple)
|
|
||||||
SelectFileStyle = lipgloss.NewStyle().Foreground(ColorAccent)
|
|
||||||
SelectDirStyle = lipgloss.NewStyle().Foreground(ColorAccent2)
|
|
||||||
//
|
|
||||||
//SelectStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
|
||||||
//InputStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
|
||||||
//ComputeStyle = lipgloss.NewStyle().Foreground(ColorGrey)
|
|
||||||
//CheckboxStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
|
||||||
//
|
|
||||||
//FormFocusedStyle = lipgloss.NewStyle().Foreground(ColorRed).Bold(true).
|
|
||||||
// Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(ColorRed)
|
|
||||||
//FormUnfocusedStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
|
||||||
//FormStyle = lipgloss.NewStyle().Padding(1, 2).Foreground(ColorBlack).
|
|
||||||
// Border(lipgloss.RoundedBorder()).BorderForeground(ColorRed)
|
|
||||||
//
|
|
||||||
//ListStyle = lipgloss.NewStyle().Padding(1, 3).Border(lipgloss.RoundedBorder()).BorderForeground(ColorRed)
|
|
||||||
//ListSelectedItemStyle = lipgloss.NewStyle().Foreground(ColorRed).Bold(true)
|
|
||||||
//ListTitleStyle = lipgloss.NewStyle().Foreground(ColorPurple).Italic(true)
|
|
||||||
//ListDescriptionStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan).MarginTop(1)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ContentWidth(screenWidth int) int {
|
//Старые стили
|
||||||
w := screenWidth - 2*AppSidePadding
|
//var (
|
||||||
if w > AppMaxWidth {
|
//ColorWhite = lipgloss.Color("#ffffff")
|
||||||
return AppMaxWidth
|
//ColorGrey = lipgloss.Color("#626262")
|
||||||
}
|
//ColorBlack = lipgloss.Color("#000000")
|
||||||
if w < AppMinWidth {
|
//ColorRed = lipgloss.Color("#FF0000")
|
||||||
return AppMinWidth
|
//ColorGreen = lipgloss.Color("#00FF00")
|
||||||
}
|
//ColorBlue = lipgloss.Color("#0000FF")
|
||||||
return w
|
//ColorPurple = lipgloss.Color("#6f03fc")
|
||||||
}
|
//ColorGreenCyan = lipgloss.Color("#11CAAA")
|
||||||
|
//
|
||||||
|
//AppContainerStyle = lipgloss.NewStyle().
|
||||||
|
// Padding(1, 3).
|
||||||
|
// Border(lipgloss.RoundedBorder()).
|
||||||
|
// BorderForeground(ColorPurple)
|
||||||
|
//
|
||||||
|
//AppHeaderStyle = lipgloss.NewStyle().
|
||||||
|
// Bold(true).
|
||||||
|
// Foreground(ColorPurple).
|
||||||
|
// Align(lipgloss.Center).
|
||||||
|
// Padding(1, 0).
|
||||||
|
// Background(ColorWhite).
|
||||||
|
// Foreground(ColorBlack)
|
||||||
|
//
|
||||||
|
//AppFooterStyle = lipgloss.NewStyle().
|
||||||
|
// Foreground(ColorGrey).
|
||||||
|
// Align(lipgloss.Center).
|
||||||
|
// Padding(0, 1)
|
||||||
|
//
|
||||||
|
//TableHeaderStyle = lipgloss.NewStyle().Foreground(ColorPurple).Bold(true).Align(lipgloss.Center)
|
||||||
|
//TableCellStyle = lipgloss.NewStyle().Padding(0, 1).Width(14)
|
||||||
|
//TableOddRowStyle = TableCellStyle.Foreground(ColorWhite).Background(ColorGrey)
|
||||||
|
//TableEvenRowStyle = TableCellStyle.Foreground(ColorWhite)
|
||||||
|
//TableBorderStyle = lipgloss.NewStyle().Foreground(ColorPurple)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//SelectStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
|
//InputStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
|
//ComputeStyle = lipgloss.NewStyle().Foreground(ColorGrey)
|
||||||
|
//CheckboxStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
|
//
|
||||||
|
//FormFocusedStyle = lipgloss.NewStyle().Foreground(ColorRed).Bold(true).
|
||||||
|
// Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(ColorRed)
|
||||||
|
//FormUnfocusedStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
|
//FormStyle = lipgloss.NewStyle().Padding(1, 2).Foreground(ColorBlack).
|
||||||
|
// Border(lipgloss.RoundedBorder()).BorderForeground(ColorRed)
|
||||||
|
//
|
||||||
|
//ListStyle = lipgloss.NewStyle().Padding(1, 3).Border(lipgloss.RoundedBorder()).BorderForeground(ColorRed)
|
||||||
|
//ListSelectedItemStyle = lipgloss.NewStyle().Foreground(ColorRed).Bold(true)
|
||||||
|
//ListTitleStyle = lipgloss.NewStyle().Foreground(ColorPurple).Italic(true)
|
||||||
|
//ListDescriptionStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan).MarginTop(1)
|
||||||
|
//)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
const SectionAbout = "abouta"
|
const SectionAbout = "about"
|
||||||
const SectionFinal = "final"
|
const SectionFinal = "final"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue