diff --git a/.gitignore b/.gitignore index 0bb5609..90a48be 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,8 @@ docs/ # Migration state (if using a migration tool that creates state files) migrations/*.state +gh-dash/ + loadtest/run.pid diff --git a/go.mod b/go.mod index 6ea3dde..2d184ab 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,14 @@ module terminalShop -go 1.25.7 +go 1.25.9 require ( - github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 - github.com/charmbracelet/bubbletea v1.3.10 - github.com/charmbracelet/huh v0.8.0 - github.com/charmbracelet/lipgloss v1.1.0 + charm.land/bubbles/v2 v2.1.0 + charm.land/bubbletea/v2 v2.0.6 + charm.land/huh/v2 v2.0.3 + charm.land/lipgloss/v2 v2.0.3 + charm.land/wish/v2 v2.0.1 github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309 - github.com/charmbracelet/wish v1.4.7 github.com/foize/go.sgr v0.0.0-20140220094842-40bdfc98040c github.com/go-chi/chi/v5 v5.2.5 github.com/go-chi/cors v1.2.2 @@ -23,7 +23,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 go.opentelemetry.io/otel/sdk v1.43.0 go.opentelemetry.io/otel/trace v1.43.0 - golang.org/x/crypto v0.49.0 + golang.org/x/crypto v0.50.0 gorm.io/driver/postgres v1.6.0 gorm.io/driver/sqlite v1.6.0 gorm.io/gorm v1.31.1 @@ -32,38 +32,35 @@ require ( ) require ( + charm.land/log/v2 v2.0.0 // indirect github.com/ClickHouse/ch-go v0.61.5 // indirect github.com/ClickHouse/clickhouse-go/v2 v2.30.0 // indirect github.com/andybalholm/brotli v1.1.1 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/atotto/clipboard v0.1.4 // indirect - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/catppuccin/go v0.3.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charmbracelet/colorprofile v0.4.1 // indirect - github.com/charmbracelet/keygen v0.5.3 // indirect - github.com/charmbracelet/log v0.4.1 // indirect - github.com/charmbracelet/x/ansi v0.11.6 // indirect - github.com/charmbracelet/x/cellbuf v0.0.15 // indirect - github.com/charmbracelet/x/conpty v0.1.0 // indirect - github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 // indirect + github.com/charmbracelet/colorprofile v0.4.3 // indirect + github.com/charmbracelet/keygen v0.5.4 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468 // indirect + github.com/charmbracelet/x/ansi v0.11.7 // indirect + github.com/charmbracelet/x/conpty v0.1.1 // indirect + github.com/charmbracelet/x/errors v0.0.0-20251110184232-6ab307057ac7 // indirect + github.com/charmbracelet/x/exp/ordered v0.1.0 // indirect github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect - github.com/charmbracelet/x/input v0.3.4 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect - github.com/charmbracelet/x/windows v0.2.0 // indirect - github.com/clipperhouse/displaywidth v0.9.0 // indirect - github.com/clipperhouse/stringish v0.1.1 // indirect - github.com/clipperhouse/uax29/v2 v2.5.0 // indirect + github.com/charmbracelet/x/windows v0.2.2 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/creack/pty v1.1.24 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/errors v0.7.1 // indirect - github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect @@ -78,15 +75,11 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect - github.com/lucasb-eyer/go-colorful v1.3.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/lucasb-eyer/go-colorful v1.4.0 // indirect + github.com/mattn/go-runewidth v0.0.23 // indirect github.com/mattn/go-sqlite3 v1.14.34 // indirect github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect - github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/paulmach/orb v0.11.1 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect @@ -104,11 +97,11 @@ require ( go.opentelemetry.io/otel/metric v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/net v0.52.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/text v0.35.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/grpc v1.80.0 // indirect diff --git a/go.sum b/go.sum index 2a61dc4..ee37675 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,15 @@ +charm.land/bubbles/v2 v2.1.0 h1:YSnNh5cPYlYjPxRrzs5VEn3vwhtEn3jVGRBT3M7/I0g= +charm.land/bubbles/v2 v2.1.0/go.mod h1:l97h4hym2hvWBVfmJDtrEHHCtkIKeTEb3TTJ4ZOB3wY= +charm.land/bubbletea/v2 v2.0.6 h1:UHN/91OyuhaOFGSrBXQ/hMZD8IO1Uc4BvHlgHXL2WJo= +charm.land/bubbletea/v2 v2.0.6/go.mod h1:MH/D8ZLlN3op37vQvijKuU29g3rqTp+aQapURFonF9g= +charm.land/huh/v2 v2.0.3 h1:2cJsMqEPwSywGHvdlKsJyQKPtSJLVnFKyFbsYZTlLkU= +charm.land/huh/v2 v2.0.3/go.mod h1:93eEveeeqn47MwiC3tf+2atZ2l7Is88rAtmZNZ8x9Wc= +charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= +charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= +charm.land/log/v2 v2.0.0 h1:SY3Cey7ipx86/MBXQHwsguOT6X1exT94mmJRdzTNs+s= +charm.land/log/v2 v2.0.0/go.mod h1:c3cZSRqm20qUVVAR1WmS/7ab8bgha3C6G7DjPcaVZz0= +charm.land/wish/v2 v2.0.1 h1:xYOsvQG/bYNRoKUBt0AEyMiCv9rksmCOG/fD5WifAzg= +charm.land/wish/v2 v2.0.1/go.mod h1:uBWdsKTFk9BE0JsdEv8KKF8/abBfRe/hKEGOBm3OKZA= github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4= github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= github.com/ClickHouse/clickhouse-go/v2 v2.30.0 h1:AG4D/hW39qa58+JHQIFOSnxyL46H6h2lrmGGk17dhFo= @@ -10,10 +22,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= -github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= +github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o= +github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= @@ -22,52 +32,38 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 h1:JFgG/xnwFfbezlUnFMJy0nusZvytYysV4SCS2cYbvws= -github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7/go.mod h1:ISC1gtLcVilLOf23wvTfoQuYbW2q0JevFxPfUzZ9Ybw= -github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= -github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= -github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk= -github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk= -github.com/charmbracelet/huh v0.8.0 h1:Xz/Pm2h64cXQZn/Jvele4J3r7DDiqFCNIVteYukxDvY= -github.com/charmbracelet/huh v0.8.0/go.mod h1:5YVc+SlZ1IhQALxRPpkGwwEKftN/+OlJlnJYlDRFqN4= -github.com/charmbracelet/keygen v0.5.3 h1:2MSDC62OUbDy6VmjIE2jM24LuXUvKywLCmaJDmr/Z/4= -github.com/charmbracelet/keygen v0.5.3/go.mod h1:TcpNoMAO5GSmhx3SgcEMqCrtn8BahKhB8AlwnLjRUpk= -github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= -github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/log v0.4.1 h1:6AYnoHKADkghm/vt4neaNEXkxcXLSV2g1rdyFDOpTyk= -github.com/charmbracelet/log v0.4.1/go.mod h1:pXgyTsqsVu4N9hGdHmQ0xEA4RsXof402LX9ZgiITn2I= +github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= +github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= +github.com/charmbracelet/keygen v0.5.4 h1:XQYgf6UEaTGgQSSmiPpIQ78WfseNQp4Pz8N/c1OsrdA= +github.com/charmbracelet/keygen v0.5.4/go.mod h1:t4oBRr41bvK7FaJsAaAQhhkUuHslzFXVjOBwA55CZNM= github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309 h1:dCVbCRRtg9+tsfiTXTp0WupDlHruAXyp+YoxGVofHHc= github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309/go.mod h1:R9cISUs5kAH4Cq/rguNbSwcR+slE5Dfm8FEs//uoIGE= -github.com/charmbracelet/wish v1.4.7 h1:O+jdLac3s6GaqkOHHSwezejNK04vl6VjO1A+hl8J8Yc= -github.com/charmbracelet/wish v1.4.7/go.mod h1:OBZ8vC62JC5cvbxJLh+bIWtG7Ctmct+ewziuUWK+G14= -github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= -github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= -github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI= -github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q= -github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= -github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= -github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA= -github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468 h1:Q9fO0y1Zo5KB/5Vu8JZoLGm1N3RzF9bNj3Ao3xoR+Ac= +github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468/go.mod h1:bAAz7dh/FTYfC+oiHavL4mX1tOIBZ0ZwYjSi3qE6ivM= +github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= +github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= +github.com/charmbracelet/x/conpty v0.1.1 h1:s1bUxjoi7EpqiXysVtC+a8RrvPPNcNvAjfi4jxsAuEs= +github.com/charmbracelet/x/conpty v0.1.1/go.mod h1:OmtR77VODEFbiTzGE9G1XiRJAga6011PIm4u5fTNZpk= +github.com/charmbracelet/x/errors v0.0.0-20251110184232-6ab307057ac7 h1:4EG8pCHK5fa8dIxv97VHC8hdkJAz6QNm1WB9BuD/WhY= +github.com/charmbracelet/x/errors v0.0.0-20251110184232-6ab307057ac7/go.mod h1:O2BTD/aMVQDmrvqroIO3fB6zXUuU07ZpVt21QTmZjRg= +github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= +github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I= +github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE= +github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8= github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4= github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= -github.com/charmbracelet/x/input v0.3.4 h1:Mujmnv/4DaitU0p+kIsrlfZl/UlmeLKw1wAP3e1fMN0= -github.com/charmbracelet/x/input v0.3.4/go.mod h1:JI8RcvdZWQIhn09VzeK3hdp4lTz7+yhiEdpEQtZN+2c= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= -github.com/charmbracelet/x/windows v0.2.0 h1:ilXA1GJjTNkgOm94CLPeSz7rar54jtFatdmoiONPuEw= -github.com/charmbracelet/x/windows v0.2.0/go.mod h1:ZibNFR49ZFqCXgP76sYanisxRyC+EYrBE7TTknD8s1s= -github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI= -github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4= -github.com/clipperhouse/displaywidth v0.9.0 h1:Qb4KOhYwRiN3viMv1v/3cTBlz3AcAZX3+y9OLhMtAtA= -github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA= -github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= -github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U= -github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= +github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= +github.com/charmbracelet/x/xpty v0.1.3 h1:eGSitii4suhzrISYH50ZfufV3v085BXQwIytcOdFSsw= +github.com/charmbracelet/x/xpty v0.1.3/go.mod h1:poPYpWuLDBFCKmKLDnhBp51ATa0ooD8FhypRwEFtH3Y= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -75,8 +71,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foize/go.sgr v0.0.0-20140220094842-40bdfc98040c h1:NhHTf8Ewd3NS46DylZB75Zi0UeATvDbDwFEmsO5ZVpQ= @@ -91,8 +85,8 @@ github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= -github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= -github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE= +github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -147,25 +141,17 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= -github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4= +github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= +github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk= github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= -github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= @@ -247,10 +233,10 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -273,19 +259,17 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= diff --git a/main.go b/main.go index d88edc0..6d16ac1 100644 --- a/main.go +++ b/main.go @@ -11,11 +11,11 @@ import ( "time" - tea "github.com/charmbracelet/bubbletea" + tea "charm.land/bubbletea/v2" "github.com/charmbracelet/ssh" - "github.com/charmbracelet/wish" - "github.com/charmbracelet/wish/bubbletea" - "github.com/charmbracelet/wish/logging" + "charm.land/wish/v2" + "charm.land/wish/v2/bubbletea" + "charm.land/wish/v2/logging" "terminalShop/pkg/auth" "terminalShop/pkg/config" @@ -36,9 +36,6 @@ var ( ) func teaHandler(s ssh.Session) (tea.Model, []tea.ProgramOption) { - renderer := bubbletea.MakeRenderer(s) - - // Extract SSH public key from session pubKey := s.PublicKey() var fingerprint, pubKeyStr string @@ -47,9 +44,8 @@ func teaHandler(s ssh.Session) (tea.Model, []tea.ProgramOption) { pubKeyStr = auth.FormatSSHPublicKey(pubKey) } - // Create TUI model with user context (no registration screen needed!) - m := tui.NewModelWithAuth(renderer, fingerprint, pubKeyStr, apiURL, authFingerprintKey, stripePublicKey) - return m, []tea.ProgramOption{tea.WithAltScreen()} + m := tui.NewModelWithAuth(fingerprint, pubKeyStr, apiURL, authFingerprintKey, stripePublicKey) + return m, nil } func main() { diff --git a/pkg/tui/account.go b/pkg/tui/account.go index 76a13a1..ec3e60e 100644 --- a/pkg/tui/account.go +++ b/pkg/tui/account.go @@ -1,9 +1,9 @@ package tui import ( - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" "terminalShop/pkg/models" ) @@ -33,12 +33,12 @@ func (m Model) updateAccountViewport() Model { } if !m.account.viewportReady { - m.account.detailViewport = viewport.New(detailWidth, availableHeight) + m.account.detailViewport = viewport.New(viewport.WithWidth(detailWidth), viewport.WithHeight(availableHeight)) m.account.detailViewport.KeyMap = modifiedKeyMap m.account.viewportReady = true } else { - m.account.detailViewport.Width = detailWidth - m.account.detailViewport.Height = availableHeight + m.account.detailViewport.SetWidth(detailWidth) + m.account.detailViewport.SetHeight(availableHeight) } return m @@ -128,8 +128,8 @@ func (m Model) scrollToAccountDetailItem() Model { } targetY := headerOffset + (selectedIndex * itemHeight) - vpH := m.account.detailViewport.Height - offset := m.account.detailViewport.YOffset + vpH := m.account.detailViewport.Height() + offset := m.account.detailViewport.YOffset() // 1-item buffer: scroll when the NEXT item would be off-screen, // not when the current item hits the very edge @@ -336,7 +336,7 @@ func (m Model) AccountUpdate(msg tea.Msg) (Model, tea.Cmd) { {key: "q", value: "quit"}, } case 1: - m.account.orderYOffset = m.account.detailViewport.YOffset + m.account.orderYOffset = m.account.detailViewport.YOffset() m.account.orderViewState = 2 m.account.detailViewport.GotoTop() m.footer = []footerCommand{ diff --git a/pkg/tui/account_orders.go b/pkg/tui/account_orders.go index 69de3dc..12a588c 100644 --- a/pkg/tui/account_orders.go +++ b/pkg/tui/account_orders.go @@ -6,7 +6,7 @@ import ( "terminalShop/pkg/models" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func (m Model) OrdersView(width int) string { diff --git a/pkg/tui/breadcrumbs.go b/pkg/tui/breadcrumbs.go index 189d7f7..c7548e3 100644 --- a/pkg/tui/breadcrumbs.go +++ b/pkg/tui/breadcrumbs.go @@ -1,7 +1,7 @@ package tui import ( - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func (m Model) BuildBreadcrumbs() string { diff --git a/pkg/tui/cart.go b/pkg/tui/cart.go index 082b8f5..018fab8 100644 --- a/pkg/tui/cart.go +++ b/pkg/tui/cart.go @@ -3,9 +3,9 @@ package tui import ( "fmt" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) func (m Model) updateCartViewport() Model { @@ -17,12 +17,12 @@ func (m Model) updateCartViewport() Model { availH = 1 } if !m.cart.viewportReady { - m.cart.viewport = viewport.New(m.widthContent, availH) + m.cart.viewport = viewport.New(viewport.WithWidth(m.widthContent), viewport.WithHeight(availH)) m.cart.viewport.KeyMap = viewport.KeyMap{} m.cart.viewportReady = true } else { - m.cart.viewport.Width = m.widthContent - m.cart.viewport.Height = availH + m.cart.viewport.SetWidth(m.widthContent) + m.cart.viewport.SetHeight(availH) } return m } @@ -116,11 +116,11 @@ func (m Model) CartView() string { } itemHeight := 4 + 2*boxPadding + 1 targetY := m.cart.cursor * itemHeight - if targetY < m.cart.viewport.YOffset { + if targetY < m.cart.viewport.YOffset() { m.cart.viewport.SetYOffset(targetY) } - if targetY+itemHeight > m.cart.viewport.YOffset+m.cart.viewport.Height { - m.cart.viewport.SetYOffset(targetY - m.cart.viewport.Height + itemHeight) + if targetY+itemHeight > m.cart.viewport.YOffset()+m.cart.viewport.Height() { + m.cart.viewport.SetYOffset(targetY - m.cart.viewport.Height() + itemHeight) } } return lipgloss.Place( diff --git a/pkg/tui/confirmation.go b/pkg/tui/confirmation.go index f6c0a8c..1ba431d 100644 --- a/pkg/tui/confirmation.go +++ b/pkg/tui/confirmation.go @@ -5,9 +5,9 @@ import ( "strings" "terminalShop/pkg/models" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) // RenderConfirmation renders the order confirmation view @@ -73,12 +73,12 @@ func (m Model) updateConfirmViewport() Model { availH = 1 } if !m.confirm.viewportReady { - m.confirm.viewport = viewport.New(m.widthContent, availH) + m.confirm.viewport = viewport.New(viewport.WithWidth(m.widthContent), viewport.WithHeight(availH)) m.confirm.viewport.KeyMap = viewport.DefaultKeyMap() m.confirm.viewportReady = true } else { - m.confirm.viewport.Width = m.widthContent - m.confirm.viewport.Height = availH + m.confirm.viewport.SetWidth(m.widthContent) + m.confirm.viewport.SetHeight(availH) } return m } diff --git a/pkg/tui/footer.go b/pkg/tui/footer.go index 9710cd9..5709549 100644 --- a/pkg/tui/footer.go +++ b/pkg/tui/footer.go @@ -3,7 +3,7 @@ package tui import ( "strings" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func (m Model) BuildFooter() string { diff --git a/pkg/tui/header.go b/pkg/tui/header.go index fdf1e15..44a620a 100644 --- a/pkg/tui/header.go +++ b/pkg/tui/header.go @@ -3,8 +3,8 @@ package tui import ( "fmt" - "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/table" + "charm.land/lipgloss/v2" + "charm.land/lipgloss/v2/table" ) func (m Model) BuildHeader() string { @@ -44,7 +44,7 @@ func (m Model) BuildHeader() string { tabs = []string{logo, shop, account, cart} } - tbl := table.New().Border(lipgloss.NormalBorder()).BorderStyle(m.renderer.NewStyle().Foreground(m.theme.Border())).Row(tabs...).Width(m.widthContent).StyleFunc(func(row, col int) lipgloss.Style { + tbl := table.New().Border(lipgloss.NormalBorder()).BorderStyle(lipgloss.NewStyle().Foreground(m.theme.Border())).Row(tabs...).Width(m.widthContent).StyleFunc(func(row, col int) lipgloss.Style { return m.theme.Base().Padding(0, 1).AlignHorizontal(lipgloss.Center) }).Render() diff --git a/pkg/tui/help.go b/pkg/tui/help.go index d93c53b..e4327f4 100644 --- a/pkg/tui/help.go +++ b/pkg/tui/help.go @@ -1,8 +1,8 @@ package tui import ( - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) func (m Model) BuildHelpView() string { diff --git a/pkg/tui/menu.go b/pkg/tui/menu.go index ba748f2..7c97804 100644 --- a/pkg/tui/menu.go +++ b/pkg/tui/menu.go @@ -2,8 +2,8 @@ package tui import ( "fmt" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) func (m Model) BuildMenuView() string { diff --git a/pkg/tui/model.go b/pkg/tui/model.go index 9427eb1..9ec38e0 100644 --- a/pkg/tui/model.go +++ b/pkg/tui/model.go @@ -7,10 +7,9 @@ import ( "sort" "time" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/key" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" "github.com/stripe/stripe-go/v78" stripetoken "github.com/stripe/stripe-go/v78/token" @@ -114,8 +113,7 @@ type Model struct { APIClient *api.Client // Rendering - renderer *lipgloss.Renderer - theme theme.Theme + theme theme.Theme // Checkout flow state (spans multiple pages) CheckingOut bool @@ -240,7 +238,6 @@ func (m Model) CartSwitch() (Model, tea.Cmd) { m = m.SwitchPage(cartPage) m = m.updateCartViewport() if m.IsCartEmpty() { - m.footer = []footerCommand{ {key: "j/k", value: "items"}, {key: "+/-", value: "qty"}, @@ -755,18 +752,12 @@ func (m Model) SavedCardsIsEmpty() bool { return len(m.SavedCards) == 0 } -// NewModel creates a new model using the default renderer. +// NewModel creates a new model. func NewModel(username string) Model { - return newModelWithRenderer(username, lipgloss.DefaultRenderer()) -} - -// newModelWithRenderer creates a new model with the given renderer. -func newModelWithRenderer(username string, renderer *lipgloss.Renderer) Model { m := Model{ Username: username, currentPage: splashPage, - renderer: renderer, - theme: theme.BasicTheme(renderer), + theme: theme.BasicTheme(), Coffees: []models.Coffee{ { Name: "Espresso", @@ -833,8 +824,8 @@ func newModelWithRenderer(username string, renderer *lipgloss.Renderer) Model { } // NewModelWithAuth creates a new model with user authentication context. -func NewModelWithAuth(renderer *lipgloss.Renderer, fingerprint string, pubKeyStr string, apiURL string, clientSecret string, stripePublicKey string) Model { - m := newModelWithRenderer("", renderer) +func NewModelWithAuth(fingerprint string, pubKeyStr string, apiURL string, clientSecret string, stripePublicKey string) Model { + m := NewModel("") m.Fingerprint = fingerprint m.AuthFingerprintKey = clientSecret m.StripePublicKey = stripePublicKey @@ -860,7 +851,7 @@ func NewModelWithAuth(renderer *lipgloss.Renderer, fingerprint string, pubKeyStr } func newViewport(w, h int) viewport.Model { - return viewport.New(w, h) + return viewport.New(viewport.WithWidth(w), viewport.WithHeight(h)) } func (m Model) collectCardCmd() tea.Cmd { @@ -876,8 +867,10 @@ func (m Model) collectCardCmd() tea.Cmd { } } -const ordersPollInterval = 10 * time.Second -const cardPollTimeout = 10 * time.Minute +const ( + ordersPollInterval = 10 * time.Second + cardPollTimeout = 10 * time.Minute +) type OrdersPollTickMsg struct{} diff --git a/pkg/tui/payment_form.go b/pkg/tui/payment_form.go index 64f5a26..724876b 100644 --- a/pkg/tui/payment_form.go +++ b/pkg/tui/payment_form.go @@ -5,10 +5,10 @@ import ( "strings" "time" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/huh" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" + "charm.land/huh/v2" + "charm.land/lipgloss/v2" "terminalShop/pkg/models" "terminalShop/pkg/tui/qrfefe" @@ -280,12 +280,12 @@ func (m Model) updatePaymentViewport() Model { availH = 1 } if !m.payment.viewportReady { - m.payment.viewport = viewport.New(m.widthContent, availH) + m.payment.viewport = viewport.New(viewport.WithWidth(m.widthContent), viewport.WithHeight(availH)) m.payment.viewport.KeyMap = viewport.KeyMap{} m.payment.viewportReady = true } else { - m.payment.viewport.Width = m.widthContent - m.payment.viewport.Height = availH + m.payment.viewport.SetWidth(m.widthContent) + m.payment.viewport.SetHeight(availH) } return m } @@ -301,7 +301,7 @@ func (m Model) PaymentPageView() string { // Bypass viewport — it strips the raw ANSI codes qrfefe emits. return lipgloss.Place( m.widthContainer, - m.payment.viewport.Height, + m.payment.viewport.Height(), lipgloss.Center, lipgloss.Center, m.renderPaymentHttpsView(), ) @@ -310,11 +310,11 @@ func (m Model) PaymentPageView() string { m.payment.viewport.SetContent(content) itemHeight := 3 targetY := m.payment.cardCursor * itemHeight - if targetY < m.payment.viewport.YOffset { + if targetY < m.payment.viewport.YOffset() { m.payment.viewport.SetYOffset(targetY) } - if targetY+itemHeight > m.payment.viewport.YOffset+m.payment.viewport.Height { - m.payment.viewport.SetYOffset(targetY - m.payment.viewport.Height + itemHeight + 1) + if targetY+itemHeight > m.payment.viewport.YOffset()+m.payment.viewport.Height() { + m.payment.viewport.SetYOffset(targetY - m.payment.viewport.Height() + itemHeight + 1) } if m.payment.cardCursor == len(m.SavedCards) { m.payment.viewport.GotoBottom() diff --git a/pkg/tui/shipping_form.go b/pkg/tui/shipping_form.go index db8afdf..63d997a 100644 --- a/pkg/tui/shipping_form.go +++ b/pkg/tui/shipping_form.go @@ -6,10 +6,10 @@ import ( "terminalShop/pkg/models" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/huh" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" + "charm.land/huh/v2" + "charm.land/lipgloss/v2" ) // countries defines the available countries with their dial codes. @@ -262,12 +262,12 @@ func (m Model) updateShippingViewport() Model { availH = 1 } if !m.shipping.viewportReady { - m.shipping.viewport = viewport.New(m.widthContent, availH) + m.shipping.viewport = viewport.New(viewport.WithWidth(m.widthContent), viewport.WithHeight(availH)) m.shipping.viewport.KeyMap = viewport.KeyMap{} m.shipping.viewportReady = true } else { - m.shipping.viewport.Width = m.widthContent - m.shipping.viewport.Height = availH + m.shipping.viewport.SetWidth(m.widthContent) + m.shipping.viewport.SetHeight(availH) } return m } @@ -281,11 +281,11 @@ func (m Model) ShippingPageView() string { m.shipping.viewport.SetContent(content) itemHeight := 4 targetY := m.shipping.addressCursor * itemHeight - if targetY < m.shipping.viewport.YOffset { + if targetY < m.shipping.viewport.YOffset() { m.shipping.viewport.SetYOffset(targetY) } - if targetY+itemHeight > m.shipping.viewport.YOffset+m.shipping.viewport.Height { - m.shipping.viewport.SetYOffset(targetY - m.shipping.viewport.Height + itemHeight + 1) + if targetY+itemHeight > m.shipping.viewport.YOffset()+m.shipping.viewport.Height() { + m.shipping.viewport.SetYOffset(targetY - m.shipping.viewport.Height() + itemHeight + 1) } if m.shipping.addressCursor == len(m.SavedAddresses) { m.shipping.viewport.GotoBottom() diff --git a/pkg/tui/shop.go b/pkg/tui/shop.go index 33c6038..3a7aac8 100644 --- a/pkg/tui/shop.go +++ b/pkg/tui/shop.go @@ -4,9 +4,9 @@ import ( "fmt" "strings" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" "terminalShop/pkg/models" ) @@ -55,10 +55,10 @@ func (m Model) updateShopViewports() Model { m.shop.detailViewport.KeyMap = modifiedKeyMap m.shop.viewportsReady = true } else { - m.shop.menuViewport.Width = menuWidth - m.shop.menuViewport.Height = availableHeight - m.shop.detailViewport.Width = detailWidth - m.shop.detailViewport.Height = availableHeight + m.shop.menuViewport.SetWidth(menuWidth) + m.shop.menuViewport.SetHeight(availableHeight) + m.shop.detailViewport.SetWidth(detailWidth) + m.shop.detailViewport.SetHeight(availableHeight) } return m } @@ -226,7 +226,7 @@ func (m Model) shopMoveSelected(previous bool) Model { if m.shop.viewportsReady { targetY := (m.shop.selected + 2) * 1 - m.shop.menuViewport.SetYOffset(targetY - m.shop.menuViewport.Height/2) + m.shop.menuViewport.SetYOffset(targetY - m.shop.menuViewport.Height()/2) m.shop.detailViewport.GotoTop() } return m diff --git a/pkg/tui/splash.go b/pkg/tui/splash.go index 00a0441..e222ad2 100644 --- a/pkg/tui/splash.go +++ b/pkg/tui/splash.go @@ -5,9 +5,9 @@ import ( "terminalShop/pkg/api" "terminalShop/pkg/models" - tea "github.com/charmbracelet/bubbletea" + tea "charm.land/bubbletea/v2" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) type DelayCompleteMsg struct{} diff --git a/pkg/tui/styles.go b/pkg/tui/styles.go index f5ca40e..c42ad32 100644 --- a/pkg/tui/styles.go +++ b/pkg/tui/styles.go @@ -3,7 +3,7 @@ package tui import ( "strings" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func (m Model) createBoxInner(content string, selected bool, position lipgloss.Position, paddingH int, paddingV int, totalWidth int) string { diff --git a/pkg/tui/theme/huh.go b/pkg/tui/theme/huh.go index 6135e74..22b4e2b 100644 --- a/pkg/tui/theme/huh.go +++ b/pkg/tui/theme/huh.go @@ -1,51 +1,50 @@ package theme import ( - "github.com/charmbracelet/bubbles/help" - "github.com/charmbracelet/huh" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/help" + "charm.land/huh/v2" + "charm.land/lipgloss/v2" ) // HuhTheme creates a huh form theme using this project's color palette. -func HuhTheme(t Theme) *huh.Theme { - var th huh.Theme +func HuhTheme(t Theme) huh.Theme { + var s huh.Styles - th.FieldSeparator = t.renderer.NewStyle().SetString("\n\n") + s.FieldSeparator = lipgloss.NewStyle().SetString("\n\n") - f := &th.Focused - f.Base = t.renderer.NewStyle(). + f := &s.Focused + f.Base = lipgloss.NewStyle(). PaddingLeft(1). BorderStyle(lipgloss.ThickBorder()). BorderLeft(true). BorderForeground(t.accent) - f.Title = t.renderer.NewStyle().Foreground(t.body) - f.Description = t.renderer.NewStyle().Foreground(t.body) - f.TextInput.Cursor = t.renderer.NewStyle().Foreground(t.highlight) - f.TextInput.Placeholder = t.renderer.NewStyle().Foreground(t.dim) - f.TextInput.Prompt = t.renderer.NewStyle().Foreground(t.accent) - f.TextInput.Text = t.renderer.NewStyle().Foreground(t.accent) - f.ErrorIndicator = t.renderer.NewStyle().Foreground(t.error) - f.ErrorMessage = t.renderer.NewStyle().Foreground(t.error) + f.Title = lipgloss.NewStyle().Foreground(t.body) + f.Description = lipgloss.NewStyle().Foreground(t.body) + f.TextInput.Cursor = lipgloss.NewStyle().Foreground(t.highlight) + f.TextInput.Placeholder = lipgloss.NewStyle().Foreground(t.dim) + f.TextInput.Prompt = lipgloss.NewStyle().Foreground(t.accent) + f.TextInput.Text = lipgloss.NewStyle().Foreground(t.accent) + f.ErrorIndicator = lipgloss.NewStyle().Foreground(t.error) + f.ErrorMessage = lipgloss.NewStyle().Foreground(t.error) - f.SelectSelector = t.renderer.NewStyle().Foreground(t.accent).SetString("> ") - f.Option = t.renderer.NewStyle().Foreground(t.body) - f.SelectedOption = t.renderer.NewStyle().Foreground(t.highlight).Bold(true) - f.MultiSelectSelector = t.renderer.NewStyle().Foreground(t.accent).SetString("> ") - f.SelectedPrefix = t.renderer.NewStyle().Foreground(t.highlight).SetString("[x] ") - f.UnselectedPrefix = t.renderer.NewStyle().Foreground(t.dim).SetString("[ ] ") - f.UnselectedOption = t.renderer.NewStyle().Foreground(t.body) + f.SelectSelector = lipgloss.NewStyle().Foreground(t.accent).SetString("> ") + f.Option = lipgloss.NewStyle().Foreground(t.body) + f.SelectedOption = lipgloss.NewStyle().Foreground(t.highlight).Bold(true) + f.MultiSelectSelector = lipgloss.NewStyle().Foreground(t.accent).SetString("> ") + f.SelectedPrefix = lipgloss.NewStyle().Foreground(t.highlight).SetString("[x] ") + f.UnselectedPrefix = lipgloss.NewStyle().Foreground(t.dim).SetString("[ ] ") + f.UnselectedOption = lipgloss.NewStyle().Foreground(t.body) - th.Help = help.New().Styles + s.Help = help.New().Styles - th.Blurred = copyFieldStyles(*f) - th.Blurred.Base = th.Blurred.Base.BorderStyle(lipgloss.HiddenBorder()) - th.Blurred.Title = th.Blurred.Title.Foreground(t.body) - th.Blurred.SelectSelector = t.renderer.NewStyle().SetString(" ") - th.Blurred.SelectedOption = t.renderer.NewStyle().Foreground(t.success).Bold(true) - th.Blurred.Option = t.renderer.NewStyle().Foreground(t.dim) + s.Blurred = copyFieldStyles(*f) + s.Blurred.Base = s.Blurred.Base.BorderStyle(lipgloss.HiddenBorder()) + s.Blurred.Title = s.Blurred.Title.Foreground(t.body) + s.Blurred.SelectSelector = lipgloss.NewStyle().SetString(" ") + s.Blurred.SelectedOption = lipgloss.NewStyle().Foreground(t.success).Bold(true) + s.Blurred.Option = lipgloss.NewStyle().Foreground(t.dim) - return &th + return huh.ThemeFunc(func(bool) *huh.Styles { return &s }) } -// copyFieldStyles returns a copy of FieldStyles (value type, assignment is a copy). func copyFieldStyles(f huh.FieldStyles) huh.FieldStyles { return f } diff --git a/pkg/tui/theme/theme.go b/pkg/tui/theme/theme.go index d1a1539..617dc76 100644 --- a/pkg/tui/theme/theme.go +++ b/pkg/tui/theme/theme.go @@ -1,56 +1,55 @@ package theme import ( - "github.com/charmbracelet/huh" - "github.com/charmbracelet/lipgloss" + "image/color" + + "charm.land/huh/v2" + "charm.land/lipgloss/v2" + "charm.land/lipgloss/v2/compat" ) -// Theme holds all colors and styles for the terminal coffee shop TUI. +// Theme holds all colors and styles for the TUI type Theme struct { - renderer *lipgloss.Renderer - - background lipgloss.TerminalColor - border lipgloss.TerminalColor - body lipgloss.TerminalColor - dim lipgloss.TerminalColor - accent lipgloss.TerminalColor - highlight lipgloss.TerminalColor - brand lipgloss.TerminalColor - label lipgloss.TerminalColor - success lipgloss.TerminalColor - error lipgloss.TerminalColor + background color.Color + border color.Color + body color.Color + dim color.Color + accent color.Color + highlight color.Color + brand color.Color + label color.Color + success color.Color + error color.Color base lipgloss.Style - form *huh.Theme + form huh.Theme } -// BasicTheme constructs the default theme for terminal coffee shop. -func BasicTheme(renderer *lipgloss.Renderer) Theme { - t := Theme{renderer: renderer} +func BasicTheme() Theme { + t := Theme{} - t.background = lipgloss.AdaptiveColor{Dark: "#000000", Light: "#FBFCFD"} - t.border = lipgloss.AdaptiveColor{Dark: "#666666", Light: "#D7DBDF"} + t.background = compat.AdaptiveColor{Dark: lipgloss.Color("#000000"), Light: lipgloss.Color("#FBFCFD")} + t.border = compat.AdaptiveColor{Dark: lipgloss.Color("#666666"), Light: lipgloss.Color("#D7DBDF")} t.body = lipgloss.Color("#AAAAAA") t.dim = lipgloss.Color("#666666") - t.accent = lipgloss.AdaptiveColor{Dark: "#FFFFFF", Light: "#11181C"} + t.accent = compat.AdaptiveColor{Dark: lipgloss.Color("#FFFFFF"), Light: lipgloss.Color("#11181C")} t.highlight = lipgloss.Color("#4682B4") t.brand = lipgloss.Color("#4682B4") t.label = lipgloss.Color("#999999") t.success = lipgloss.Color("#00FF00") t.error = lipgloss.Color("196") - t.base = renderer.NewStyle().Foreground(t.body) + t.base = lipgloss.NewStyle().Foreground(t.body) t.form = HuhTheme(t) return t } -// this should resemble something like catppuccin -func Catppuccin(renderer *lipgloss.Renderer) Theme { - t := Theme{renderer: renderer} +func Catppuccin() Theme { + t := Theme{} - t.background = lipgloss.AdaptiveColor{Dark: "#1e1e2e", Light: "#eff1f5"} - t.border = lipgloss.AdaptiveColor{Dark: "#45475A", Light: "#BCC0CC"} + t.background = compat.AdaptiveColor{Dark: lipgloss.Color("#1e1e2e"), Light: lipgloss.Color("#eff1f5")} + t.border = compat.AdaptiveColor{Dark: lipgloss.Color("#45475A"), Light: lipgloss.Color("#BCC0CC")} t.body = lipgloss.Color("#AAAAAA") t.dim = lipgloss.Color("#6C7086") t.accent = lipgloss.Color("#CBA6F7") @@ -60,25 +59,25 @@ func Catppuccin(renderer *lipgloss.Renderer) Theme { t.success = lipgloss.Color("#A6E3A1") t.error = lipgloss.Color("#F38BA8") - t.base = renderer.NewStyle().Foreground(t.body) + t.base = lipgloss.NewStyle().Foreground(t.body) t.form = HuhTheme(t) + return t } -// Color accessors — use in .Foreground() / .Background() calls. -func (t Theme) Background() lipgloss.TerminalColor { return t.background } -func (t Theme) Border() lipgloss.TerminalColor { return t.border } -func (t Theme) Body() lipgloss.TerminalColor { return t.body } -func (t Theme) Dim() lipgloss.TerminalColor { return t.dim } -func (t Theme) Accent() lipgloss.TerminalColor { return t.accent } -func (t Theme) Highlight() lipgloss.TerminalColor { return t.highlight } -func (t Theme) Brand() lipgloss.TerminalColor { return t.brand } -func (t Theme) Label() lipgloss.TerminalColor { return t.label } -func (t Theme) Success() lipgloss.TerminalColor { return t.success } -func (t Theme) Error() lipgloss.TerminalColor { return t.error } +// Color accessors. +func (t Theme) Background() color.Color { return t.background } +func (t Theme) Border() color.Color { return t.border } +func (t Theme) Body() color.Color { return t.body } +func (t Theme) Dim() color.Color { return t.dim } +func (t Theme) Accent() color.Color { return t.accent } +func (t Theme) Highlight() color.Color { return t.highlight } +func (t Theme) Brand() color.Color { return t.brand } +func (t Theme) Label() color.Color { return t.label } +func (t Theme) Success() color.Color { return t.success } +func (t Theme) Error() color.Color { return t.error } -// Style helpers — return a copy of base with the correct foreground. -// Chain .Bold(), .Width(), .Padding() etc. on the returned style. +// Style helpers. func (t Theme) Base() lipgloss.Style { return t.base } func (t Theme) TextBody() lipgloss.Style { return t.Base().Foreground(t.body) } func (t Theme) TextAccent() lipgloss.Style { return t.Base().Foreground(t.accent) } @@ -90,10 +89,8 @@ func (t Theme) TextSuccess() lipgloss.Style { return t.Base().Foreground(t.suc func (t Theme) TextError() lipgloss.Style { return t.Base().Foreground(t.error) } func (t Theme) TextLoading() lipgloss.Style { return t.Base().Foreground(lipgloss.Color("205")) } -// PanelError returns a style for the error banner: dark red bg, red fg. func (t Theme) PanelError() lipgloss.Style { return t.Base().Background(lipgloss.Color("52")).Foreground(lipgloss.Color("196")) } -// Form returns the huh form theme for shipping and payment forms. -func (t Theme) Form() *huh.Theme { return t.form } +func (t Theme) Form() huh.Theme { return t.form } diff --git a/pkg/tui/update.go b/pkg/tui/update.go index 4f831d9..c333d11 100644 --- a/pkg/tui/update.go +++ b/pkg/tui/update.go @@ -6,7 +6,7 @@ import ( "terminalShop/pkg/models" "time" - tea "github.com/charmbracelet/bubbletea" + tea "charm.land/bubbletea/v2" ) func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { diff --git a/pkg/tui/views.go b/pkg/tui/views.go index 64630d5..9ab5b1e 100644 --- a/pkg/tui/views.go +++ b/pkg/tui/views.go @@ -1,7 +1,8 @@ package tui import ( - "github.com/charmbracelet/lipgloss" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) // ResizeView renders a message when the terminal is too small. @@ -19,7 +20,13 @@ func (m Model) ResizeView() string { ) } -func (m Model) View() string { +func (m Model) View() tea.View { + v := tea.NewView(m.renderString()) + v.AltScreen = true + return v +} + +func (m Model) renderString() string { if m.viewportWidth == 0 { m.updateLayout(120, 30) }