From 24d39bf9004c3c492b30dc11718934a7edca6a2f Mon Sep 17 00:00:00 2001 From: sawka Date: Thu, 13 Nov 2025 16:36:01 -0800 Subject: [PATCH 1/2] use AppMeta instead of AppTitle/AppShortDesc --- tsunami/app/defaultclient.go | 10 ++++++++++ tsunami/demo/cpuchart/app.go | 6 ++++-- tsunami/demo/githubaction/app.go | 6 ++++-- tsunami/demo/modaltest/app.go | 6 ++++-- tsunami/demo/pomodoro/app.go | 6 ++++-- tsunami/demo/recharts/app.go | 6 ++++-- tsunami/demo/tabletest/app.go | 6 ++++-- tsunami/demo/todo/app.go | 6 ++++-- tsunami/demo/tsunamiconfig/app.go | 6 ++++-- tsunami/templates/app-main.go.tmpl | 3 +-- 10 files changed, 43 insertions(+), 18 deletions(-) diff --git a/tsunami/app/defaultclient.go b/tsunami/app/defaultclient.go index 7b1c23dec0..4a3a41b581 100644 --- a/tsunami/app/defaultclient.go +++ b/tsunami/app/defaultclient.go @@ -18,6 +18,8 @@ import ( const TsunamiCloseOnStdinEnvVar = "TSUNAMI_CLOSEONSTDIN" const MaxShortDescLen = 120 +type AppMeta engine.AppMeta + func DefineComponent[P any](name string, renderFn func(props P) any) vdom.Component[P] { return engine.DefineComponentEx(engine.GetDefaultClient(), name, renderFn) } @@ -146,6 +148,14 @@ func QueueRefOp(ref *vdom.VDomRef, op vdom.VDomRefOperation) { client.Root.QueueRefOp(op) } +func SetAppMeta(meta AppMeta) { + if len(meta.ShortDesc) > MaxShortDescLen { + meta.ShortDesc = meta.ShortDesc[0:MaxShortDescLen-3] + "..." + } + client := engine.GetDefaultClient() + client.SetAppMeta(engine.AppMeta(meta)) +} + func SetTitle(title string) { client := engine.GetDefaultClient() m := client.GetAppMeta() diff --git a/tsunami/demo/cpuchart/app.go b/tsunami/demo/cpuchart/app.go index 315fcaf0fa..a51e9217ea 100644 --- a/tsunami/demo/cpuchart/app.go +++ b/tsunami/demo/cpuchart/app.go @@ -9,8 +9,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "CPU Usage Monitor" -const AppShortDesc = "Real-time CPU usage monitoring and charting" +var AppMeta = app.AppMeta{ + Title: "CPU Usage Monitor", + ShortDesc: "Real-time CPU usage monitoring and charting", +} // Global atoms for config and data var ( diff --git a/tsunami/demo/githubaction/app.go b/tsunami/demo/githubaction/app.go index 921ff3027b..8839cadfea 100644 --- a/tsunami/demo/githubaction/app.go +++ b/tsunami/demo/githubaction/app.go @@ -15,8 +15,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "GitHub Actions Monitor" -const AppShortDesc = "Real-time GitHub Actions workflow monitoring and status tracking" +var AppMeta = app.AppMeta{ + Title: "GitHub Actions Monitor", + ShortDesc: "Real-time GitHub Actions workflow monitoring and status tracking", +} // Global atoms for config and data var ( diff --git a/tsunami/demo/modaltest/app.go b/tsunami/demo/modaltest/app.go index e2ca335054..ec9df7e64d 100644 --- a/tsunami/demo/modaltest/app.go +++ b/tsunami/demo/modaltest/app.go @@ -5,8 +5,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "Modal Test (Tsunami Demo)" -const AppShortDesc = "Test alert and confirm modals in Tsunami" +var AppMeta = app.AppMeta{ + Title: "Modal Test (Tsunami Demo)", + ShortDesc: "Test alert and confirm modals in Tsunami", +} var App = app.DefineComponent("App", func(_ struct{}) any { // State to track modal results diff --git a/tsunami/demo/pomodoro/app.go b/tsunami/demo/pomodoro/app.go index 179fed5d8e..90c4e86728 100644 --- a/tsunami/demo/pomodoro/app.go +++ b/tsunami/demo/pomodoro/app.go @@ -8,8 +8,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "Pomodoro Timer (Tsunami Demo)" -const AppShortDesc = "Productivity timer with work and break intervals" +var AppMeta = app.AppMeta{ + Title: "Pomodoro Timer (Tsunami Demo)", + ShortDesc: "Productivity timer with work and break intervals", +} type Mode struct { Name string `json:"name"` diff --git a/tsunami/demo/recharts/app.go b/tsunami/demo/recharts/app.go index 95520e6990..72e8d31b5e 100644 --- a/tsunami/demo/recharts/app.go +++ b/tsunami/demo/recharts/app.go @@ -8,8 +8,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "Recharts Demo" -const AppShortDesc = "Interactive charts and data visualization using Recharts" +var AppMeta = app.AppMeta{ + Title: "Recharts Demo", + ShortDesc: "Interactive charts and data visualization using Recharts", +} // Global atoms for config and data var ( diff --git a/tsunami/demo/tabletest/app.go b/tsunami/demo/tabletest/app.go index 83ed4e1c92..c028204e2c 100644 --- a/tsunami/demo/tabletest/app.go +++ b/tsunami/demo/tabletest/app.go @@ -8,8 +8,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "Table Test Demo" -const AppShortDesc = "Testing table component with sortable columns and pagination" +var AppMeta = app.AppMeta{ + Title: "Table Test Demo", + ShortDesc: "Testing table component with sortable columns and pagination", +} // Sample data structure for the table type Person struct { diff --git a/tsunami/demo/todo/app.go b/tsunami/demo/todo/app.go index c4f51e9119..7bb22692c4 100644 --- a/tsunami/demo/todo/app.go +++ b/tsunami/demo/todo/app.go @@ -8,8 +8,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "Todo App (Tsunami Demo)" -const AppShortDesc = "Feature-rich todo list with component composition and state management" +var AppMeta = app.AppMeta{ + Title: "Todo App (Tsunami Demo)", + ShortDesc: "Feature-rich todo list with component composition and state management", +} // Basic domain types with json tags for props type Todo struct { diff --git a/tsunami/demo/tsunamiconfig/app.go b/tsunami/demo/tsunamiconfig/app.go index 78f89f9d66..eea8183b11 100644 --- a/tsunami/demo/tsunamiconfig/app.go +++ b/tsunami/demo/tsunamiconfig/app.go @@ -14,8 +14,10 @@ import ( "github.com/wavetermdev/waveterm/tsunami/vdom" ) -const AppTitle = "Tsunami Config Manager" -const AppShortDesc = "Configuration editor for remote servers with JSON validation" +var AppMeta = app.AppMeta{ + Title: "Tsunami Config Manager", + ShortDesc: "Configuration editor for remote servers with JSON validation", +} // Global atoms for config var ( diff --git a/tsunami/templates/app-main.go.tmpl b/tsunami/templates/app-main.go.tmpl index 5e1f65ec7e..c461995429 100644 --- a/tsunami/templates/app-main.go.tmpl +++ b/tsunami/templates/app-main.go.tmpl @@ -18,8 +18,7 @@ func main() { subDistFS, _ := fs.Sub(distFS, "dist") subStaticFS, _ := fs.Sub(staticFS, "static") app.RegisterEmbeds(subDistFS, subStaticFS, nil) - app.SetTitle(AppTitle) - app.SetShortDesc(AppShortDesc) + app.SetAppMeta(AppMeta) if len(os.Args) == 2 && os.Args[1] == "--manifest" { app.PrintAppManifest() From b66a594a877feac30241b24132f912d1f9d84a01 Mon Sep 17 00:00:00 2001 From: sawka Date: Thu, 13 Nov 2025 16:52:45 -0800 Subject: [PATCH 2/2] rune string truncation --- tsunami/app/defaultclient.go | 9 +++------ tsunami/util/util.go | 10 ++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tsunami/app/defaultclient.go b/tsunami/app/defaultclient.go index 4a3a41b581..ae74b169a8 100644 --- a/tsunami/app/defaultclient.go +++ b/tsunami/app/defaultclient.go @@ -12,6 +12,7 @@ import ( "os" "github.com/wavetermdev/waveterm/tsunami/engine" + "github.com/wavetermdev/waveterm/tsunami/util" "github.com/wavetermdev/waveterm/tsunami/vdom" ) @@ -149,9 +150,7 @@ func QueueRefOp(ref *vdom.VDomRef, op vdom.VDomRefOperation) { } func SetAppMeta(meta AppMeta) { - if len(meta.ShortDesc) > MaxShortDescLen { - meta.ShortDesc = meta.ShortDesc[0:MaxShortDescLen-3] + "..." - } + meta.ShortDesc = util.TruncateString(meta.ShortDesc, MaxShortDescLen) client := engine.GetDefaultClient() client.SetAppMeta(engine.AppMeta(meta)) } @@ -164,9 +163,7 @@ func SetTitle(title string) { } func SetShortDesc(shortDesc string) { - if len(shortDesc) > MaxShortDescLen { - shortDesc = shortDesc[0:MaxShortDescLen-3] + "..." - } + shortDesc = util.TruncateString(shortDesc, MaxShortDescLen) client := engine.GetDefaultClient() m := client.GetAppMeta() m.ShortDesc = shortDesc diff --git a/tsunami/util/util.go b/tsunami/util/util.go index bb3cf39776..561e24930d 100644 --- a/tsunami/util/util.go +++ b/tsunami/util/util.go @@ -283,3 +283,13 @@ func ParseJSONTag(field reflect.StructField) (JsonFieldInfo, bool) { Options: opts, }, true } + +// TruncateString truncates a string to maxLen runes (not bytes). +// If the string is longer than maxLen, it truncates to maxLen-3 and appends "...". +func TruncateString(s string, maxLen int) string { + runes := []rune(s) + if len(runes) <= maxLen { + return s + } + return string(runes[0:maxLen-3]) + "..." +}