Работа над стилями, работа над модальными окнами, изменение списка приложений, работа с размерами окон
This commit is contained in:
parent
5203032b83
commit
ada7db46cf
12 changed files with 1161 additions and 130 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
||||||
*.tmp
|
*.tmp
|
||||||
*.log
|
*.log
|
||||||
|
*.txt
|
||||||
|
|
||||||
/vendor/
|
/vendor/
|
||||||
/bin/
|
/bin/
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -8,6 +8,7 @@ require (
|
||||||
github.com/charmbracelet/glamour v0.10.0
|
github.com/charmbracelet/glamour v0.10.0
|
||||||
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
|
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
|
||||||
github.com/expr-lang/expr v1.17.7
|
github.com/expr-lang/expr v1.17.7
|
||||||
|
github.com/muesli/reflow v0.3.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|
@ -36,7 +37,6 @@ require (
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
|
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/reflow v0.3.0 // indirect
|
|
||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/sahilm/fuzzy v0.1.1 // indirect
|
github.com/sahilm/fuzzy v0.1.1 // indirect
|
||||||
|
|
|
||||||
436
log.txt
436
log.txt
|
|
@ -0,0 +1,436 @@
|
||||||
|
time=13:34:29 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=13:34:29 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=13:34:30 29-12-2025 level=info msg=sections user, focus 0, fields len 2
|
||||||
|
time=13:34:30 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:34:30 29-12-2025 level=info msg=field choose_user, capture keys true
|
||||||
|
time=13:34:30 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:34:30 29-12-2025 level=info msg=field choose_user, capture keys true
|
||||||
|
time=13:34:31 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:34:31 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=13:34:32 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=13:34:32 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=13:34:32 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=13:34:32 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:34:32 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=13:34:32 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=13:34:32 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=13:34:33 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=13:34:33 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=13:34:33 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=13:34:33 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=13:34:33 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=13:34:33 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=13:34:34 29-12-2025 level=info msg=sections domain, focus 5, fields len 5
|
||||||
|
time=13:34:34 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:34:34 29-12-2025 level=info msg=field database_type, capture keys false
|
||||||
|
time=13:34:35 29-12-2025 level=info msg=sections database, focus 1, fields len 1
|
||||||
|
time=13:34:36 29-12-2025 level=info msg=sections paths, focus 0, fields len 1
|
||||||
|
time=13:34:37 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:34:37 29-12-2025 level=info msg=field debian_root, capture keys true
|
||||||
|
time=13:34:37 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:34:37 29-12-2025 level=info msg=field debian_root, capture keys true
|
||||||
|
time=13:34:37 29-12-2025 level=info msg=sections paths, focus 0, fields len 1
|
||||||
|
time=13:54:35 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=13:54:37 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=13:54:38 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:54:38 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=13:54:38 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=13:54:38 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=13:54:39 29-12-2025 level=info msg=2
|
||||||
|
time=13:54:39 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=13:54:39 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=13:54:40 29-12-2025 level=info msg=sections user, focus 0, fields len 2
|
||||||
|
time=13:54:40 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:54:40 29-12-2025 level=info msg=field choose_user, capture keys true
|
||||||
|
time=13:54:41 29-12-2025 level=info msg=sections user, focus 0, fields len 2
|
||||||
|
time=13:54:41 29-12-2025 level=info msg=chose {FieldIndex:1 Value:Existing}
|
||||||
|
time=13:54:42 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:54:42 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=13:54:42 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=13:54:42 29-12-2025 level=info msg=field select_user, capture keys false
|
||||||
|
time=13:54:42 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=13:54:42 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:54:42 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=13:54:43 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=13:54:44 29-12-2025 level=info msg=sections domain, focus 5, fields len 5
|
||||||
|
time=13:54:44 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:54:44 29-12-2025 level=info msg=field database_type, capture keys false
|
||||||
|
time=13:54:44 29-12-2025 level=info msg=sections database, focus 1, fields len 1
|
||||||
|
time=13:54:45 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=13:54:45 29-12-2025 level=info msg=field debian_root, capture keys false
|
||||||
|
time=13:54:45 29-12-2025 level=info msg=sections paths, focus 1, fields len 1
|
||||||
|
time=13:57:35 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:00:04 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:08:24 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:08:25 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:08:25 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:08:25 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:08:26 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:08:26 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:08:26 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=14:08:28 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:08:28 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:28:24 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:28:25 29-12-2025 level=info msg=2
|
||||||
|
time=14:28:25 29-12-2025 level=info msg=2
|
||||||
|
time=14:28:25 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:28:26 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:28:26 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:28:26 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:28:26 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:28:27 29-12-2025 level=info msg=2
|
||||||
|
time=14:28:27 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:28:27 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:28:28 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:28:28 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:28:29 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:28:29 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:28:29 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:28:29 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:28:29 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:28:29 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:28:49 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:28:50 29-12-2025 level=info msg=2
|
||||||
|
time=14:28:50 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:28:50 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:28:50 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:28:51 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:28:51 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:28:52 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=14:28:52 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:28:52 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:28:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:28:53 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:28:53 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:28:53 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=2
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:29:53 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:29:54 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:54 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:29:54 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:29:54 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:29:54 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:29:54 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:30:06 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:30:08 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:31:23 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:31:23 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:31:23 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:31:23 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:31:24 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=14:32:32 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:38:03 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:38:04 29-12-2025 level=info msg=2
|
||||||
|
time=14:38:04 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:38:05 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:38:05 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:38:05 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:38:05 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:38:06 29-12-2025 level=info msg=2
|
||||||
|
time=14:38:06 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:38:06 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:38:07 29-12-2025 level=info msg=2
|
||||||
|
time=14:38:07 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:38:07 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:38:08 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=14:38:08 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:38:08 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:38:09 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:38:09 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:38:09 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:38:09 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:38:09 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:38:09 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:38:10 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:38:10 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:39:11 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:39:11 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:39:52 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:40:10 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:40:12 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:40:31 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=14:40:32 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=14:40:32 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:40:32 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=14:40:32 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:40:32 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=14:40:33 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=14:40:33 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:40:33 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:40:33 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:40:33 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:40:34 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:40:34 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:40:34 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:40:34 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:40:34 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:40:34 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:40:34 29-12-2025 level=info msg=2
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:41:48 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:41:49 29-12-2025 level=info msg=sections domain, focus 3, fields len 5
|
||||||
|
time=14:41:49 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=14:41:49 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=14:41:49 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=14:41:49 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=14:41:49 29-12-2025 level=info msg=sections domain, focus 5, fields len 5
|
||||||
|
time=14:41:52 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=14:41:52 29-12-2025 level=info msg=field ssl_type, capture keys false
|
||||||
|
time=14:41:53 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:41:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:41:53 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:41:53 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:41:53 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:41:54 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:41:54 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:41:54 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:41:55 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:41:56 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:41:57 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:41:58 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:41:58 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:41:58 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:41:58 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:41:59 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:41:59 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:41:59 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:00 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:01 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:02 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:02 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:02 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:03 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:04 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:04 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:04 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:04 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:04 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:04 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:05 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:42:05 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:05 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:05 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:05 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:05 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:05 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:06 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:07 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:07 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:07 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:07 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:07 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:08 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:09 29-12-2025 level=info msg=sections ssl, focus 1, fields len 3
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:10 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:11 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=14:42:12 29-12-2025 level=info msg=field ssl_cert_path, capture keys true
|
||||||
|
time=14:42:16 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=15:05:11 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=15:05:12 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=15:17:37 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=15:24:20 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=16:26:13 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=16:26:13 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=16:26:14 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=16:26:14 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=16:26:14 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=16:26:14 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=16:26:58 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=16:49:25 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=17:01:58 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=17:04:53 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=17:04:54 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:04:54 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=17:04:54 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=17:04:54 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=17:04:54 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:04:55 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=17:04:56 29-12-2025 level=info msg=sections domain, focus 5, fields len 5
|
||||||
|
time=17:04:56 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:04:56 29-12-2025 level=info msg=field database_type, capture keys false
|
||||||
|
time=17:04:57 29-12-2025 level=info msg=sections database, focus 1, fields len 1
|
||||||
|
time=17:04:57 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:04:57 29-12-2025 level=info msg=field debian_root, capture keys false
|
||||||
|
time=17:04:57 29-12-2025 level=info msg=sections paths, focus 1, fields len 1
|
||||||
|
time=17:43:36 29-12-2025 level=info msg=modal close msg get
|
||||||
|
time=17:43:37 29-12-2025 level=info msg=sections Repko about, focus 0, fields len 0
|
||||||
|
time=17:43:38 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:43:38 29-12-2025 level=info msg=field choose_user, capture keys false
|
||||||
|
time=17:43:38 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=17:43:38 29-12-2025 level=info msg=field new_user, capture keys false
|
||||||
|
time=17:43:39 29-12-2025 level=info msg=sections user, focus 2, fields len 2
|
||||||
|
time=17:43:39 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:43:39 29-12-2025 level=info msg=field api_domain, capture keys false
|
||||||
|
time=17:43:39 29-12-2025 level=info msg=1, focus is 1
|
||||||
|
time=17:43:39 29-12-2025 level=info msg=field panel_domain, capture keys false
|
||||||
|
time=17:43:39 29-12-2025 level=info msg=1, focus is 2
|
||||||
|
time=17:43:39 29-12-2025 level=info msg=field cookie_domain, capture keys false
|
||||||
|
time=17:43:40 29-12-2025 level=info msg=1, focus is 3
|
||||||
|
time=17:43:40 29-12-2025 level=info msg=field is_secure, capture keys false
|
||||||
|
time=17:43:40 29-12-2025 level=info msg=1, focus is 4
|
||||||
|
time=17:43:40 29-12-2025 level=info msg=field server_address, capture keys false
|
||||||
|
time=17:43:40 29-12-2025 level=info msg=sections domain, focus 5, fields len 5
|
||||||
|
time=17:43:40 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:43:40 29-12-2025 level=info msg=field database_type, capture keys false
|
||||||
|
time=17:43:41 29-12-2025 level=info msg=sections database, focus 1, fields len 1
|
||||||
|
time=17:43:41 29-12-2025 level=info msg=1, focus is 0
|
||||||
|
time=17:43:41 29-12-2025 level=info msg=field debian_root, capture keys false
|
||||||
|
time=17:43:41 29-12-2025 level=info msg=sections paths, focus 1, fields len 1
|
||||||
108
setup/final.go
108
setup/final.go
|
|
@ -37,9 +37,9 @@ func (m *FinalModel) Init() tea.Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FinalModel) initViewport(width, height int) {
|
func (m *FinalModel) initViewport(width, height int) {
|
||||||
m.viewport = viewport.New(width, height-4)
|
m.viewport = viewport.New(width, height-8)
|
||||||
m.viewport.Width = width - 4
|
m.viewport.Width = width
|
||||||
m.viewport.Height = height - 6
|
m.viewport.Height = height - 10
|
||||||
m.ready = true
|
m.ready = true
|
||||||
m.rebuildTable(m.viewport.Width)
|
m.rebuildTable(m.viewport.Width)
|
||||||
m.viewport.SetContent(m.table.Render())
|
m.viewport.SetContent(m.table.Render())
|
||||||
|
|
@ -50,22 +50,22 @@ func (m *FinalModel) rebuildTable(width int) {
|
||||||
m.table = table.New().Headers("Нет переменных")
|
m.table = table.New().Headers("Нет переменных")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
availableWidth := width - 8 // примерно: 2 (отступы) + 4 (бордер) + запас
|
availableWidth := width - 12 // примерно: 2 (отступы) + 4 (бордер) + запас
|
||||||
if availableWidth < 60 {
|
if availableWidth < 70 {
|
||||||
availableWidth = 60
|
availableWidth = 70
|
||||||
}
|
}
|
||||||
t := table.New().
|
t := table.New().
|
||||||
Border(lipgloss.ThickBorder()).
|
Border(lipgloss.RoundedBorder()).
|
||||||
BorderStyle(ui.TableBorderStyle).
|
BorderStyle(ui.TableBorder).
|
||||||
StyleFunc(func(row, col int) lipgloss.Style {
|
StyleFunc(func(row, col int) lipgloss.Style {
|
||||||
var style lipgloss.Style
|
var style lipgloss.Style
|
||||||
switch {
|
switch {
|
||||||
case row == table.HeaderRow:
|
case row == table.HeaderRow:
|
||||||
return ui.TableHeaderStyle
|
return ui.TableHeader
|
||||||
case row%2 == 0:
|
case row%2 == 0:
|
||||||
style = ui.TableEvenRowStyle
|
style = ui.TableRowEven.Padding(0, 2)
|
||||||
default:
|
default:
|
||||||
style = ui.TableOddRowStyle
|
style = ui.TableRowOdd.Padding(0, 2)
|
||||||
}
|
}
|
||||||
switch col {
|
switch col {
|
||||||
case 0, 1:
|
case 0, 1:
|
||||||
|
|
@ -125,26 +125,76 @@ func (m *FinalModel) View() string {
|
||||||
if !m.ready {
|
if !m.ready {
|
||||||
return "Загрузка таблицы"
|
return "Загрузка таблицы"
|
||||||
}
|
}
|
||||||
header := lipgloss.NewStyle().
|
|
||||||
Width(m.viewport.Width).
|
|
||||||
Align(lipgloss.Center).
|
|
||||||
Bold(true).
|
|
||||||
Background(ui.ColorPurple).
|
|
||||||
Foreground(ui.ColorWhite).
|
|
||||||
Padding(1).
|
|
||||||
Render("Итоговые значения переменных")
|
|
||||||
|
|
||||||
footer := lipgloss.NewStyle().
|
contentWidth := ui.ContentWidth(m.width)
|
||||||
Width(m.viewport.Width).
|
m.rebuildTable(contentWidth)
|
||||||
Align(lipgloss.Center).
|
|
||||||
Foreground(ui.ColorGrey).
|
header := ui.HeaderStyle.Width(contentWidth).Render("Итоговые значения переменных")
|
||||||
Padding(0, 1).
|
footer := ui.FooterStyle.Width(contentWidth).Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
||||||
Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
|
||||||
|
m.viewport.Width = contentWidth - 8
|
||||||
|
m.viewport.Height = m.height - 12
|
||||||
|
m.viewport.SetContent(m.table.Render())
|
||||||
|
|
||||||
body := m.viewport.View()
|
body := m.viewport.View()
|
||||||
return lipgloss.JoinVertical(lipgloss.Center,
|
|
||||||
header,
|
content := lipgloss.JoinVertical(lipgloss.Left, header, body, footer)
|
||||||
body,
|
container := ui.AppContainer.Width(contentWidth).Render(content)
|
||||||
footer,
|
|
||||||
|
return lipgloss.Place(m.width, m.height,
|
||||||
|
lipgloss.Center, lipgloss.Center,
|
||||||
|
container,
|
||||||
|
lipgloss.WithWhitespaceChars("░"),
|
||||||
|
lipgloss.WithWhitespaceForeground(ui.ColorGrey),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//contentWidth := ui.AppContentWidth(m.width)
|
||||||
|
//m.viewport.Width = contentWidth - 6
|
||||||
|
//m.viewport.Height = m.height - 12
|
||||||
|
//m.rebuildTable(contentWidth)
|
||||||
|
//
|
||||||
|
//header := ui.AppHeaderStyle.
|
||||||
|
// Width(contentWidth).
|
||||||
|
// Render("Итоговые значения переменных")
|
||||||
|
//
|
||||||
|
//footer := ui.AppFooterStyle.
|
||||||
|
// Width(contentWidth).
|
||||||
|
// Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
||||||
|
//
|
||||||
|
//body := m.viewport.View()
|
||||||
|
//content := lipgloss.JoinVertical(lipgloss.Left, header, body, footer)
|
||||||
|
//
|
||||||
|
//container := ui.AppContainerStyle.
|
||||||
|
// Width(contentWidth).
|
||||||
|
// Render(content)
|
||||||
|
//
|
||||||
|
//return lipgloss.Place(m.width, m.height,
|
||||||
|
// lipgloss.Center, lipgloss.Center,
|
||||||
|
// container,
|
||||||
|
// lipgloss.WithWhitespaceChars("░"),
|
||||||
|
// lipgloss.WithWhitespaceForeground(ui.ColorGrey),
|
||||||
|
//)
|
||||||
|
|
||||||
|
//header := lipgloss.NewStyle().
|
||||||
|
// Width(m.viewport.Width).
|
||||||
|
// Align(lipgloss.Center).
|
||||||
|
// Bold(true).
|
||||||
|
// Background(ui.ColorPurple).
|
||||||
|
// Foreground(ui.ColorWhite).
|
||||||
|
// Padding(1).
|
||||||
|
// Render("Итоговые значения переменных")
|
||||||
|
//
|
||||||
|
//footer := lipgloss.NewStyle().
|
||||||
|
// Width(m.viewport.Width).
|
||||||
|
// Align(lipgloss.Center).
|
||||||
|
// Foreground(ui.ColorGrey).
|
||||||
|
// Padding(0, 1).
|
||||||
|
// Render(fmt.Sprintf("Строк: %d • q — выход • ↑↓ / jk — скролл", len(m.variables)))
|
||||||
|
//
|
||||||
|
//body := m.viewport.View()
|
||||||
|
//return lipgloss.JoinVertical(lipgloss.Center,
|
||||||
|
// header,
|
||||||
|
// body,
|
||||||
|
// footer,
|
||||||
|
//)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
120
setup/form.go
120
setup/form.go
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/glamour"
|
"github.com/charmbracelet/glamour"
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
"github.com/muesli/reflow/wordwrap"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -16,9 +18,11 @@ type FormModel struct {
|
||||||
FieldModels []fields.FieldModel
|
FieldModels []fields.FieldModel
|
||||||
focus int
|
focus int
|
||||||
renderedContent string
|
renderedContent string
|
||||||
|
width int
|
||||||
|
height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFormModel(application *types.PackageApplication, sectionIdx, focus int) *FormModel {
|
func NewFormModel(application *types.PackageApplication, sectionIdx, focus, width, height int) *FormModel {
|
||||||
currentSection := &application.Sections[sectionIdx]
|
currentSection := &application.Sections[sectionIdx]
|
||||||
var fieldModels []fields.FieldModel
|
var fieldModels []fields.FieldModel
|
||||||
for _, sectionField := range currentSection.Fields {
|
for _, sectionField := range currentSection.Fields {
|
||||||
|
|
@ -69,12 +73,14 @@ func NewFormModel(application *types.PackageApplication, sectionIdx, focus int)
|
||||||
FieldModels: fieldModels,
|
FieldModels: fieldModels,
|
||||||
focus: focus,
|
focus: focus,
|
||||||
CurrentSection: currentSection,
|
CurrentSection: currentSection,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
}
|
}
|
||||||
if currentSection.Type == "abouta" { //"about" {
|
if currentSection.Type == types.SectionAbout {
|
||||||
md := strings.Join(currentSection.Paragraphs, "\n\n")
|
md := strings.Join(currentSection.Paragraphs, "\n\n")
|
||||||
renderer, _ := glamour.NewTermRenderer(
|
renderer, _ := glamour.NewTermRenderer(
|
||||||
glamour.WithAutoStyle(),
|
glamour.WithAutoStyle(),
|
||||||
glamour.WithWordWrap(80))
|
glamour.WithWordWrap(width-10))
|
||||||
rendered, _ := renderer.Render(md)
|
rendered, _ := renderer.Render(md)
|
||||||
m.renderedContent = rendered
|
m.renderedContent = rendered
|
||||||
m.focus = 0
|
m.focus = 0
|
||||||
|
|
@ -88,23 +94,61 @@ 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:
|
||||||
|
m.width = msg.Width
|
||||||
|
m.height = msg.Height
|
||||||
|
if m.CurrentSection.Type == types.SectionAbout {
|
||||||
|
md := strings.Join(m.CurrentSection.Paragraphs, "\n\n")
|
||||||
|
renderer, _ := glamour.NewTermRenderer(
|
||||||
|
glamour.WithAutoStyle(),
|
||||||
|
glamour.WithWordWrap(m.width-10),
|
||||||
|
)
|
||||||
|
rendered, _ := renderer.Render(md)
|
||||||
|
m.renderedContent = rendered
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c", "q":
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
case "esc":
|
case "esc":
|
||||||
|
for _, field := range m.FieldModels {
|
||||||
|
if field.CaptureKeys() {
|
||||||
|
return m, m.updateFields(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, func() tea.Msg {
|
||||||
|
return types.ShowModalMsg{
|
||||||
|
Type: types.ModalWarning,
|
||||||
|
Title: "Прервать настройку",
|
||||||
|
Message: "Вы уверены, что хотите прервать настройку?\nВсе введенные данные будут потеряны.",
|
||||||
|
ModalButtons: []types.ModalButton{
|
||||||
|
{Text: "Да, выйти", Value: true},
|
||||||
|
{Text: "Продолжить настройку", Value: false},
|
||||||
|
},
|
||||||
|
OnResult: func(result any) tea.Cmd {
|
||||||
|
if result == true {
|
||||||
|
return func() tea.Msg { return types.BackToListMsg{} }
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
//вернуться к списку приложений, чтобы выбрать другое приложение.
|
//вернуться к списку приложений, чтобы выбрать другое приложение.
|
||||||
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 {
|
||||||
|
m.focus = 0
|
||||||
return m, func() tea.Msg {
|
return m, func() tea.Msg {
|
||||||
return types.NextSectionMsg{}
|
return types.NextSectionMsg{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "tab", "down", "shift+tab", "up":
|
case "tab", "down", "shift+tab", "up":
|
||||||
|
//Итак, тут надо учесть динамические поля.
|
||||||
|
//
|
||||||
key := msg.String()
|
key := msg.String()
|
||||||
if m.focus != len(m.FieldModels) {
|
if m.focus != len(m.FieldModels) {
|
||||||
logrus.Infof("1")
|
logrus.Infof("1, focus is %d", m.focus)
|
||||||
//todo исправить фокус
|
//todo исправить фокус
|
||||||
field := m.FieldModels[m.focus]
|
field := m.FieldModels[m.focus]
|
||||||
logrus.Infof("field %s, capture keys %t", field.GetLabel(), field.CaptureKeys())
|
logrus.Infof("field %s, capture keys %t", field.GetLabel(), field.CaptureKeys())
|
||||||
|
|
@ -137,30 +181,66 @@ func (m *FormModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FormModel) View() string {
|
func (m *FormModel) View() string {
|
||||||
res := ""
|
contentWidth := ui.ContentWidth(m.width)
|
||||||
|
|
||||||
if len(m.FieldModels) > 0 {
|
var res strings.Builder
|
||||||
for i := range m.FieldModels {
|
|
||||||
inputView := m.FieldModels[i].View()
|
for i, field := range m.FieldModels {
|
||||||
if m.focus == i {
|
fieldStr := wordwrap.String(field.View(), contentWidth-10)
|
||||||
res += ui.FormFocusedStyle.Render(inputView)
|
if i == m.focus {
|
||||||
} else {
|
res.WriteString(ui.FormFieldFocused.Render(fieldStr))
|
||||||
res += ui.FormUnfocusedStyle.Render(inputView)
|
} else {
|
||||||
}
|
res.WriteString(ui.FormFieldUnfocused.Render(fieldStr))
|
||||||
res += "\n"
|
|
||||||
}
|
}
|
||||||
|
res.WriteString("\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
button := "\n[ next section ]"
|
if m.CurrentSection.Type == types.SectionAbout {
|
||||||
if m.CurrentSection.Type == "about" {
|
res.WriteString(m.renderedContent)
|
||||||
res += m.renderedContent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextBtn := "[ next section ]"
|
||||||
if m.focus == len(m.FieldModels) {
|
if m.focus == len(m.FieldModels) {
|
||||||
res += ui.FormFocusedStyle.Render(button)
|
res.WriteString(ui.FormNextButton.Render(nextBtn))
|
||||||
} else {
|
} else {
|
||||||
res += ui.FormUnfocusedStyle.Render(button)
|
res.WriteString(ui.FormFieldUnfocused.Render(nextBtn))
|
||||||
}
|
}
|
||||||
return ui.FormStyle.Render(res)
|
|
||||||
|
container := ui.FormContainer.Width(contentWidth).Render(res.String())
|
||||||
|
return lipgloss.Place(m.width, m.height,
|
||||||
|
lipgloss.Center, lipgloss.Center,
|
||||||
|
container,
|
||||||
|
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 {
|
||||||
|
|
|
||||||
139
setup/list.go
139
setup/list.go
|
|
@ -3,67 +3,138 @@ package setup
|
||||||
import (
|
import (
|
||||||
"bubble/setup/ui"
|
"bubble/setup/ui"
|
||||||
"bubble/types"
|
"bubble/types"
|
||||||
|
"fmt"
|
||||||
|
"github.com/charmbracelet/bubbles/list"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListModel struct {
|
type ListApplicationItem struct {
|
||||||
options []string
|
Application types.PackageApplication
|
||||||
focus int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewListModel(applications []types.PackageApplication) *ListModel {
|
func (i ListApplicationItem) Title() string {
|
||||||
options := make([]string, len(applications))
|
return fmt.Sprintf("%s, v%s", i.Application.Name, i.Application.Version)
|
||||||
|
}
|
||||||
|
func (i ListApplicationItem) Description() string {
|
||||||
|
return fmt.Sprintf("%s", i.Application.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i ListApplicationItem) FilterValue() string {
|
||||||
|
return i.Application.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListApplicationsModel struct {
|
||||||
|
List list.Model
|
||||||
|
width int
|
||||||
|
height int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListApplicationsModel(applications []types.PackageApplication, width, height int) *ListApplicationsModel {
|
||||||
|
|
||||||
|
items := make([]list.Item, len(applications))
|
||||||
for i, app := range applications {
|
for i, app := range applications {
|
||||||
options[i] = app.Name
|
items[i] = ListApplicationItem{app}
|
||||||
}
|
}
|
||||||
return &ListModel{
|
|
||||||
options: options,
|
delegate := list.NewDefaultDelegate()
|
||||||
|
delegate.Styles.SelectedTitle = ui.ListSelectedStyle
|
||||||
|
delegate.Styles.SelectedDesc = ui.ListSelectedStyle
|
||||||
|
delegate.ShowDescription = false
|
||||||
|
l := list.New(items, delegate, width, height)
|
||||||
|
l.Title = "Выберите приложение для настройки"
|
||||||
|
l.Styles.Title = ui.ListTitleStyle
|
||||||
|
|
||||||
|
return &ListApplicationsModel{
|
||||||
|
List: l,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ListModel) Init() tea.Cmd {
|
func (m *ListApplicationsModel) Init() tea.Cmd {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ListModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m *ListApplicationsModel) 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.WindowSizeMsg:
|
||||||
|
m.width = msg.Width
|
||||||
|
m.height = msg.Height
|
||||||
|
return m, nil
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c", "q":
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
case "up", "w", "shift+tab":
|
|
||||||
m.focus--
|
|
||||||
if m.focus < 0 {
|
|
||||||
m.focus = len(m.options) - 1
|
|
||||||
}
|
|
||||||
case "down", "s", "tab":
|
|
||||||
m.focus++
|
|
||||||
if m.focus == len(m.options) {
|
|
||||||
m.focus = 0
|
|
||||||
}
|
|
||||||
case "enter":
|
case "enter":
|
||||||
|
selected := m.List.SelectedItem().(ListApplicationItem)
|
||||||
return m, func() tea.Msg {
|
return m, func() tea.Msg {
|
||||||
return types.SelectedAppMsg{Index: m.focus}
|
return types.ShowModalMsg{
|
||||||
|
Type: types.ModalConfirm,
|
||||||
|
Title: "Начать установку",
|
||||||
|
Message: fmt.Sprintf("Вы хотит настроить приложение:\n\n%s\n\nПродолжить?", selected.Title()),
|
||||||
|
ModalButtons: []types.ModalButton{
|
||||||
|
{Text: "Да", Value: true},
|
||||||
|
{Text: "Нет", Value: false},
|
||||||
|
},
|
||||||
|
OnResult: func(result any) tea.Cmd {
|
||||||
|
if result == true {
|
||||||
|
return func() tea.Msg {
|
||||||
|
return types.SelectedAppMsg{App: selected.Application}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m.List, cmd = m.List.Update(msg)
|
||||||
return m, cmd
|
return m, cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ListModel) View() string {
|
func (m *ListApplicationsModel) View() string {
|
||||||
res := ""
|
contentWidth := ui.ContentWidth(m.width)
|
||||||
listStyle := lipgloss.NewStyle().Padding(1, 1).Foreground(ui.ColorPurple)
|
listWidth := int(float64(contentWidth) * ui.ListWithRatio)
|
||||||
for i := range m.options {
|
m.List.SetSize(listWidth-6, m.height-10)
|
||||||
if i == m.focus {
|
|
||||||
res += "[x] " + m.options[i]
|
listView := m.List.View()
|
||||||
} else {
|
|
||||||
res += "[ ] " + m.options[i]
|
var desc string
|
||||||
}
|
if sel := m.List.SelectedItem(); sel != nil {
|
||||||
if i != len(m.options)-1 {
|
desc = sel.(ListApplicationItem).Description()
|
||||||
res += "\n"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return listStyle.Render(res)
|
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,
|
||||||
|
lipgloss.Center, lipgloss.Center,
|
||||||
|
container,
|
||||||
|
lipgloss.WithWhitespaceChars("░"),
|
||||||
|
lipgloss.WithWhitespaceForeground(ui.ColorGrey),
|
||||||
|
)
|
||||||
|
|
||||||
|
//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),
|
||||||
|
//)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,34 +17,54 @@ func Start() {
|
||||||
|
|
||||||
type Main struct {
|
type Main struct {
|
||||||
current tea.Model
|
current tea.Model
|
||||||
|
overlay tea.Model
|
||||||
Applications []types.PackageApplication
|
Applications []types.PackageApplication
|
||||||
CurrentApplication *types.PackageApplication
|
CurrentApplication *types.PackageApplication
|
||||||
CurrentSection *types.Section
|
CurrentSection *types.Section
|
||||||
CurrentSectionIdx int
|
CurrentSectionIdx int
|
||||||
width int
|
Width int
|
||||||
height int
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMain() *Main {
|
func NewMain() *Main {
|
||||||
apps := bootstrap.LoadApplications()
|
apps := bootstrap.LoadApplications()
|
||||||
return &Main{
|
m := &Main{
|
||||||
Applications: apps,
|
Applications: apps,
|
||||||
current: NewListModel(apps),
|
|
||||||
CurrentSectionIdx: 0,
|
CurrentSectionIdx: 0,
|
||||||
}
|
}
|
||||||
|
m.current = NewListApplicationsModel(m.Applications, m.Width, m.Height)
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Main) Init() tea.Cmd {
|
func (m *Main) Init() tea.Cmd {
|
||||||
return m.current.Init()
|
return m.current.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
var cmd tea.Cmd
|
var cmds []tea.Cmd
|
||||||
m.current, cmd = m.current.Update(msg)
|
if m.overlay != nil {
|
||||||
|
var cmd tea.Cmd
|
||||||
|
m.overlay, cmd = m.overlay.Update(msg)
|
||||||
|
if cmd != nil {
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var cmd tea.Cmd
|
||||||
|
m.current, cmd = m.current.Update(msg)
|
||||||
|
if cmd != nil {
|
||||||
|
cmds = append(cmds, 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
|
||||||
m.current, cmd = m.current.Update(msg)
|
if m.current != nil {
|
||||||
|
m.current, _ = m.current.Update(msg)
|
||||||
|
}
|
||||||
|
if m.overlay != nil {
|
||||||
|
m.overlay, _ = m.overlay.Update(msg)
|
||||||
|
}
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c", "q":
|
||||||
|
|
@ -65,21 +85,31 @@ func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if m.CurrentSection == nil {
|
if m.CurrentSection == nil {
|
||||||
logrus.Infof("next section, eq nil, out, idx %d", m.CurrentSectionIdx)
|
return m, func() tea.Msg {
|
||||||
return m, tea.Quit
|
return types.ShowModalMsg{
|
||||||
|
Type: types.ModalError,
|
||||||
|
Title: "Ошибка конфигурации",
|
||||||
|
Message: "Это приложение не имеет доступных секций для настройки\n" +
|
||||||
|
"Возможно оно повреждено или не поддерживается",
|
||||||
|
ModalButtons: []types.ModalButton{{Text: "Выйти", Value: true}},
|
||||||
|
OnResult: func(result any) tea.Cmd {
|
||||||
|
return tea.Quit
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//todo переделать. Учесть динамические индексы.
|
//todo переделать. Учесть динамические индексы.
|
||||||
if m.CurrentSectionIdx == len(m.CurrentApplication.Sections)-1 && m.CurrentSection.Type == "final" {
|
if m.CurrentSectionIdx == len(m.CurrentApplication.Sections)-1 && m.CurrentSection.Type == types.SectionFinal {
|
||||||
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.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 = &m.Applications[msg.Index]
|
m.CurrentApplication = &msg.App
|
||||||
|
|
||||||
//ищем доступную секцию
|
//ищем доступную секцию
|
||||||
for sectionIdx := 0; sectionIdx < len(m.CurrentApplication.Sections); sectionIdx++ {
|
for sectionIdx := 0; sectionIdx < len(m.CurrentApplication.Sections); sectionIdx++ {
|
||||||
|
|
@ -96,13 +126,29 @@ func (m *Main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
//создаем новую форму
|
//создаем новую форму
|
||||||
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, 0)
|
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, 0, m.Width, m.Height)
|
||||||
|
case types.BackToListMsg:
|
||||||
|
m.CurrentApplication = nil
|
||||||
|
m.CurrentSection = nil
|
||||||
|
m.CurrentSectionIdx = 0
|
||||||
|
m.current = NewListApplicationsModel(m.Applications, m.Width, m.Height)
|
||||||
|
case types.ShowModalMsg:
|
||||||
|
m.overlay = NewModalModel(msg, m.Width, m.Height)
|
||||||
|
return m, nil
|
||||||
|
case types.CloseModalMsg:
|
||||||
|
logrus.Infof("modal close msg get")
|
||||||
|
m.overlay = nil
|
||||||
|
return m, tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
return m, cmd
|
return m, tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Main) View() string {
|
func (m *Main) View() string {
|
||||||
return m.current.View()
|
view := m.current.View()
|
||||||
|
if m.overlay != nil {
|
||||||
|
view = m.overlay.View()
|
||||||
|
}
|
||||||
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Main) Sugar(sugar types.SugarMsg) {
|
func (m *Main) Sugar(sugar types.SugarMsg) {
|
||||||
|
|
@ -113,7 +159,7 @@ func (m *Main) Sugar(sugar types.SugarMsg) {
|
||||||
if sugar.Compute != "" {
|
if sugar.Compute != "" {
|
||||||
Recompute(m.CurrentApplication)
|
Recompute(m.CurrentApplication)
|
||||||
}
|
}
|
||||||
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, sugar.Focus)
|
m.current = NewFormModel(m.CurrentApplication, m.CurrentSectionIdx, sugar.Focus, m.Width, m.Height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
185
setup/modal.go
Normal file
185
setup/modal.go
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
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),
|
||||||
|
//)
|
||||||
|
}
|
||||||
|
|
@ -2,35 +2,164 @@ 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 {
|
||||||
|
w := screenWidth - 2*AppSidePadding
|
||||||
|
if w > AppMaxWidth {
|
||||||
|
return AppMaxWidth
|
||||||
|
}
|
||||||
|
if w < AppMinWidth {
|
||||||
|
return AppMinWidth
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ColorWhite = lipgloss.Color("#ffffff")
|
ColorFg = lipgloss.Color("#eeeeee")
|
||||||
ColorGrey = lipgloss.Color("#626262")
|
ColorBg = lipgloss.Color("#0d1117")
|
||||||
ColorBlack = lipgloss.Color("#000000")
|
ColorAccent = lipgloss.Color("#a6e3a1")
|
||||||
ColorRed = lipgloss.Color("#FF0000")
|
ColorAccent2 = lipgloss.Color("#747cec")
|
||||||
ColorGreen = lipgloss.Color("#00FF00")
|
ColorWarning = lipgloss.Color("#f9e2af")
|
||||||
ColorBlue = lipgloss.Color("#0000FF")
|
ColorError = lipgloss.Color("#f38ba8")
|
||||||
ColorPurple = lipgloss.Color("#6f03fc")
|
ColorPurple = lipgloss.Color("#cba6f7")
|
||||||
ColorGreenCyan = lipgloss.Color("#11CAAA")
|
ColorGrey = lipgloss.Color("#585b70")
|
||||||
|
ColorDarkGrey = lipgloss.Color("#313244")
|
||||||
|
|
||||||
TableHeaderStyle = lipgloss.NewStyle().Foreground(ColorPurple).Bold(true).Align(lipgloss.Center)
|
AppContainer = lipgloss.NewStyle().
|
||||||
TableCellStyle = lipgloss.NewStyle().Padding(0, 1).Width(14)
|
Padding(2, 4).
|
||||||
TableOddRowStyle = TableCellStyle.Foreground(ColorWhite).Background(ColorGrey)
|
Border(lipgloss.RoundedBorder()).
|
||||||
TableEvenRowStyle = TableCellStyle.Foreground(ColorWhite)
|
BorderForeground(ColorPurple)
|
||||||
TableBorderStyle = lipgloss.NewStyle().Foreground(ColorPurple)
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
ListTitleStyle = lipgloss.NewStyle().Foreground(ColorPurple).Italic(true).Bold(true)
|
||||||
|
ListSelectedStyle = lipgloss.NewStyle().Foreground(ColorError).Bold(true)
|
||||||
|
ListDescriptionStyle = lipgloss.NewStyle().Foreground(ColorAccent2).MarginTop(1)
|
||||||
|
|
||||||
|
ModalBorderError = lipgloss.NewStyle().BorderForeground(ColorError)
|
||||||
|
ModalBorderWarning = lipgloss.NewStyle().BorderForeground(ColorWarning)
|
||||||
|
ModalBorderConfirm = lipgloss.NewStyle().BorderForeground(ColorPurple)
|
||||||
|
ModalBorderInfo = lipgloss.NewStyle().BorderForeground(ColorAccent)
|
||||||
|
|
||||||
|
ModalTitleError = lipgloss.NewStyle().BorderForeground(ColorError).Bold(true)
|
||||||
|
ModalTitleWarning = lipgloss.NewStyle().BorderForeground(ColorWarning).Bold(true)
|
||||||
|
ModalTitleDefault = lipgloss.NewStyle().BorderForeground(ColorPurple).Bold(true)
|
||||||
|
|
||||||
|
ModalButtonNormal = lipgloss.NewStyle().
|
||||||
|
Padding(0, 3).
|
||||||
|
Border(lipgloss.RoundedBorder()).
|
||||||
|
BorderForeground(ColorGrey).
|
||||||
|
Foreground(ColorAccent2)
|
||||||
|
|
||||||
|
ModalButtonFocused = lipgloss.NewStyle().
|
||||||
|
Padding(0, 3).
|
||||||
|
Border(lipgloss.RoundedBorder()).
|
||||||
|
BorderForeground(ColorError).
|
||||||
|
Foreground(ColorError).
|
||||||
|
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)
|
SelectFileDirDeniedStyle = lipgloss.NewStyle().Foreground(ColorGrey)
|
||||||
SelectFileDirParentStyle = lipgloss.NewStyle().Foreground(ColorPurple)
|
SelectFileDirParentStyle = lipgloss.NewStyle().Foreground(ColorPurple)
|
||||||
SelectFileStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
SelectFileStyle = lipgloss.NewStyle().Foreground(ColorAccent)
|
||||||
SelectDirStyle = lipgloss.NewStyle().Foreground(ColorBlue)
|
SelectDirStyle = lipgloss.NewStyle().Foreground(ColorAccent2)
|
||||||
|
//
|
||||||
SelectStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
//SelectStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
InputStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
//InputStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
ComputeStyle = lipgloss.NewStyle().Foreground(ColorGrey)
|
//ComputeStyle = lipgloss.NewStyle().Foreground(ColorGrey)
|
||||||
CheckboxStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
//CheckboxStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
|
//
|
||||||
FormFocusedStyle = lipgloss.NewStyle().Foreground(ColorRed).Bold(true).
|
//FormFocusedStyle = lipgloss.NewStyle().Foreground(ColorRed).Bold(true).
|
||||||
Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(ColorRed)
|
// Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(ColorRed)
|
||||||
FormUnfocusedStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
//FormUnfocusedStyle = lipgloss.NewStyle().Foreground(ColorGreenCyan)
|
||||||
FormStyle = lipgloss.NewStyle().Padding(1, 2).Foreground(ColorBlack).
|
//FormStyle = lipgloss.NewStyle().Padding(1, 2).Foreground(ColorBlack).
|
||||||
Border(lipgloss.RoundedBorder()).BorderForeground(ColorRed)
|
// 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
|
||||||
|
if w > AppMaxWidth {
|
||||||
|
return AppMaxWidth
|
||||||
|
}
|
||||||
|
if w < AppMinWidth {
|
||||||
|
return AppMinWidth
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
|
||||||
10
types/modal.go
Normal file
10
types/modal.go
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
type ModalType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModalInfo ModalType = "info"
|
||||||
|
ModalWarning ModalType = "warning"
|
||||||
|
ModalError ModalType = "error"
|
||||||
|
ModalConfirm ModalType = "confirm"
|
||||||
|
)
|
||||||
21
types/msg.go
21
types/msg.go
|
|
@ -1,9 +1,13 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
import tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
||||||
type SelectedAppMsg struct {
|
type SelectedAppMsg struct {
|
||||||
Index int
|
App PackageApplication
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BackToListMsg struct{}
|
||||||
|
|
||||||
type SelectedOptionMsg struct {
|
type SelectedOptionMsg struct {
|
||||||
FieldIndex int
|
FieldIndex int
|
||||||
Value string
|
Value string
|
||||||
|
|
@ -27,3 +31,18 @@ type SelectedFileMsg struct {
|
||||||
Filename string
|
Filename string
|
||||||
Index int
|
Index int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ShowModalMsg struct {
|
||||||
|
Type ModalType
|
||||||
|
Title string
|
||||||
|
Message string
|
||||||
|
ModalButtons []ModalButton
|
||||||
|
OnResult func(result any) tea.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModalButton struct {
|
||||||
|
Text string
|
||||||
|
Value any
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloseModalMsg struct{}
|
||||||
|
|
|
||||||
4
types/names.go
Normal file
4
types/names.go
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
const SectionAbout = "abouta"
|
||||||
|
const SectionFinal = "final"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue