Skip to content

Commit 131a3ee

Browse files
committed
remove AppOpts, move title to hook, derrive GlobalKeyboardHandler... update prompt, etc...
1 parent 384699a commit 131a3ee

13 files changed

Lines changed: 76 additions & 83 deletions

File tree

tsunami/app/defaultclient.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/wavetermdev/waveterm/tsunami/vdom"
1212
)
1313

14-
var defaultClient = MakeClient(AppOpts{})
14+
var defaultClient = MakeClient()
1515
var assetsFS fs.FS
1616
var staticFS fs.FS
1717
var manifestFile *FileHandlerOption
@@ -26,9 +26,6 @@ func SetGlobalEventHandler(handler func(client *Client, event vdom.VDomEvent)) {
2626
defaultClient.SetGlobalEventHandler(handler)
2727
}
2828

29-
func SetAppOpts(appOpts AppOpts) {
30-
defaultClient.SetAppOpts(appOpts)
31-
}
3229

3330
func AddSetupFn(fn func()) {
3431
defaultClient.AddSetupFn(fn)

tsunami/app/serverhandlers.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (h *HTTPHandlers) RegisterHandlers(mux *http.ServeMux, opts HandlerOpts) {
4949
mux.HandleFunc("/api/data", h.handleData)
5050
mux.HandleFunc("/api/config", h.handleConfig)
5151
mux.HandleFunc("/api/manifest", h.handleManifest(opts.ManifestFile))
52-
mux.HandleFunc("/files/", h.handleAssetsUrl)
52+
mux.HandleFunc("/dyn/", h.handleDynContent)
5353

5454
// Add handler for static files at /static/ path
5555
if opts.StaticFS != nil {
@@ -235,24 +235,20 @@ func (h *HTTPHandlers) handleConfigPost(w http.ResponseWriter, r *http.Request)
235235
w.WriteHeader(http.StatusOK)
236236
}
237237

238-
func (h *HTTPHandlers) handleAssetsUrl(w http.ResponseWriter, r *http.Request) {
238+
func (h *HTTPHandlers) handleDynContent(w http.ResponseWriter, r *http.Request) {
239239
defer func() {
240-
panicErr := util.PanicHandler("handleAssetsUrl", recover())
240+
panicErr := util.PanicHandler("handleDynContent", recover())
241241
if panicErr != nil {
242242
http.Error(w, fmt.Sprintf("internal server error: %v", panicErr), http.StatusInternalServerError)
243243
}
244244
}()
245245

246246
// Strip /assets prefix and update the request URL
247-
r.URL.Path = strings.TrimPrefix(r.URL.Path, "/assets")
247+
r.URL.Path = strings.TrimPrefix(r.URL.Path, "/dyn")
248248
if r.URL.Path == "" {
249249
r.URL.Path = "/"
250250
}
251251

252-
if r.URL.Path == "/global.css" && h.Client.GlobalStylesOption != nil {
253-
ServeFileOption(w, r, *h.Client.GlobalStylesOption)
254-
return
255-
}
256252
h.Client.UrlHandlerMux.ServeHTTP(w, r)
257253
}
258254

tsunami/app/tsunamiapp.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,8 @@ type SSEvent struct {
3434
Data []byte
3535
}
3636

37-
type AppOpts struct {
38-
Title string // window title
39-
GlobalKeyboardEvents bool
40-
}
41-
4237
type Client struct {
4338
Lock *sync.Mutex
44-
AppOpts AppOpts
4539
Root *comp.RootElem
4640
RootElem *vdom.VDomElem
4741
CurrentClientId string
@@ -56,7 +50,7 @@ type Client struct {
5650
SetupFn func()
5751
}
5852

59-
func MakeClient(appOpts AppOpts) *Client {
53+
func MakeClient() *Client {
6054
client := &Client{
6155
Lock: &sync.Mutex{},
6256
Root: comp.MakeRoot(),
@@ -66,7 +60,6 @@ func MakeClient(appOpts AppOpts) *Client {
6660
ServerId: uuid.New().String(),
6761
RootElem: vdom.E(DefaultComponentName),
6862
}
69-
client.SetAppOpts(appOpts)
7063
return client
7164
}
7265

@@ -110,12 +103,6 @@ func (c *Client) SetGlobalEventHandler(handler func(client *Client, event vdom.V
110103
c.GlobalEventHandler = handler
111104
}
112105

113-
func (c *Client) SetAppOpts(appOpts AppOpts) {
114-
c.Lock.Lock()
115-
defer c.Lock.Unlock()
116-
117-
c.AppOpts = appOpts
118-
}
119106

120107
func getFaviconPath() string {
121108
if staticFS != nil {
@@ -131,8 +118,8 @@ func getFaviconPath() string {
131118

132119
func (c *Client) makeBackendOpts() *rpctypes.VDomBackendOpts {
133120
return &rpctypes.VDomBackendOpts{
134-
Title: c.AppOpts.Title,
135-
GlobalKeyboardEvents: c.AppOpts.GlobalKeyboardEvents,
121+
Title: c.Root.AppTitle,
122+
GlobalKeyboardEvents: c.GlobalEventHandler != nil,
136123
FaviconPath: getFaviconPath(),
137124
}
138125
}
@@ -298,6 +285,7 @@ func (c *Client) incrementalRender() (*rpctypes.VDomBackendUpdate, error) {
298285
Type: "backendupdate",
299286
Ts: time.Now().UnixMilli(),
300287
ServerId: c.ServerId,
288+
Opts: c.makeBackendOpts(),
301289
RenderUpdates: []rpctypes.VDomRenderUpdate{
302290
{UpdateType: "root", VDom: renderedVDom},
303291
},

tsunami/build/build.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"golang.org/x/mod/modfile"
2121
)
2222

23+
const MinSupportedGoMinorVersion = 22
24+
2325
type BuildOpts struct {
2426
Dir string
2527
Verbose bool
@@ -50,13 +52,13 @@ func verifyEnvironment(verbose bool) (*BuildEnv, error) {
5052
return nil, fmt.Errorf("failed to run 'go version': %w", err)
5153
}
5254

53-
// Parse go version output and check for 1.21+
55+
// Parse go version output and check for 1.22+
5456
versionStr := strings.TrimSpace(string(output))
5557
if verbose {
5658
log.Printf("Found %s", versionStr)
5759
}
5860

59-
// Extract version like "go1.21.0" from output
61+
// Extract version like "go1.22.0" from output
6062
versionRegex := regexp.MustCompile(`go(1\.\d+)`)
6163
matches := versionRegex.FindStringSubmatch(versionStr)
6264
if len(matches) < 2 {
@@ -65,16 +67,16 @@ func verifyEnvironment(verbose bool) (*BuildEnv, error) {
6567

6668
goVersion := matches[1]
6769

68-
// Check if version is 1.21+
70+
// Check if version is 1.22+
6971
minorRegex := regexp.MustCompile(`1\.(\d+)`)
7072
minorMatches := minorRegex.FindStringSubmatch(goVersion)
7173
if len(minorMatches) < 2 {
7274
return nil, fmt.Errorf("unable to parse minor version from: %s", goVersion)
7375
}
7476

7577
minor, err := strconv.Atoi(minorMatches[1])
76-
if err != nil || minor < 21 {
77-
return nil, fmt.Errorf("go version 1.21 or higher required, found: %s", versionStr)
78+
if err != nil || minor < MinSupportedGoMinorVersion {
79+
return nil, fmt.Errorf("go version 1.%d or higher required, found: %s", MinSupportedGoMinorVersion, versionStr)
7880
}
7981

8082
// Check if npx is in PATH

tsunami/comp/rootelem.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type RootElem struct {
2626
OuterCtx context.Context
2727
Root *ComponentImpl
2828
RenderTs int64
29+
AppTitle string
2930
CFuncs map[string]any
3031
CompMap map[string]*ComponentImpl // component waveid -> component
3132
EffectWorkQueue []*vdom.EffectWorkElem

tsunami/comp/vdomcontext.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,14 @@ func (vc *VDomContextVal) IsResync() bool {
7272
}
7373
return vc.RenderOpts.Resync
7474
}
75+
76+
func (vc *VDomContextVal) GetCompName() string {
77+
if vc.Comp == nil || vc.Comp.Elem == nil {
78+
return ""
79+
}
80+
return vc.Comp.Elem.Tag
81+
}
82+
83+
func (vc *VDomContextVal) SetAppTitle(title string) {
84+
vc.Root.AppTitle = title
85+
}

tsunami/demo/pomodoro/app.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ import (
99
"github.com/wavetermdev/waveterm/tsunami/vdom"
1010
)
1111

12-
func init() {
13-
app.SetAppOpts(app.AppOpts{
14-
Title: "Pomodoro Timer (Tsunami Demo)",
15-
})
16-
}
1712

1813
type Mode struct {
1914
Name string `json:"name"`
@@ -103,6 +98,8 @@ var ControlButtons = app.DefineComponent("ControlButtons",
10398

10499
var App = app.DefineComponent("App",
105100
func(ctx context.Context, _ any) any {
101+
vdom.UseSetAppTitle(ctx, "Pomodoro Timer (Tsunami Demo)")
102+
106103
isRunning, setIsRunning, _ := vdom.UseState(ctx, false)
107104
minutes, setMinutes, _ := vdom.UseState(ctx, WorkMode.Duration)
108105
seconds, setSeconds, _ := vdom.UseState(ctx, 0)

tsunami/demo/todo/app.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ import (
99
"github.com/wavetermdev/waveterm/tsunami/vdom"
1010
)
1111

12-
func init() {
13-
// Set up the default client with embedded Tailwind styles
14-
app.SetAppOpts(app.AppOpts{
15-
Title: "Todo App (Tsunami Demo)",
16-
})
17-
}
1812

1913
// Basic domain types with json tags for props
2014
type Todo struct {
@@ -108,6 +102,8 @@ var TodoList = app.DefineComponent("TodoList",
108102
// Root component showing state management and composition
109103
var App = app.DefineComponent("App",
110104
func(ctx context.Context, _ any) any {
105+
vdom.UseSetAppTitle(ctx, "Todo App (Tsunami Demo)")
106+
111107
// Multiple state hooks example
112108
todos, setTodos, _ := vdom.UseState(ctx, []Todo{
113109
{Id: 1, Text: "Learn VDOM", Completed: false},

tsunami/prompt.md

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,26 @@ The included todo-main.go provides a complete example application showing these
1616

1717
## App Setup and Registration
1818

19-
Tsunami applications use a default client configured through `app.SetAppOpts()` in an `init()` function:
19+
Tsunami applications define components using the default client:
2020

2121
```go
22-
func init() {
23-
// Set up the default client with options
24-
app.SetAppOpts(app.AppOpts{
25-
Title: "My Tsunami App",
26-
})
27-
}
28-
2922
// Components are defined using the default client
3023
var MyComponent = app.DefineComponent("MyComponent",
3124
func(ctx context.Context, props MyProps) any {
3225
// component logic
3326
},
3427
)
28+
29+
// The main "App" component can set the app title
30+
var App = app.DefineComponent("App",
31+
func(ctx context.Context, _ struct{}) any {
32+
vdom.UseSetAppTitle(ctx, "My Tsunami App") // Only works in top-level App component
33+
34+
return vdom.H("div", nil,
35+
// app content
36+
)
37+
},
38+
)
3539
```
3640

3741
## Building Elements with vdom.H()
@@ -183,7 +187,7 @@ Helper functions:
183187

184188
## Style Handling
185189

186-
Tsunami applications use Tailwind v4 CSS by default for styling. You can also define inline styles using a map[string]any in the props:
190+
Tsunami applications use Tailwind v4 CSS by default for styling (className prop). You can also define inline styles using a map[string]any in the props:
187191

188192
```go
189193
vdom.H("div", map[string]any{
@@ -385,7 +389,7 @@ func MyComponent(ctx context.Context, props MyProps) any {
385389
vdom.UseEffect(ctx, func() func() {
386390
// Example: set counter to 10 on mount
387391
setCounter(10)
388-
392+
389393
return func() {
390394
// cleanup
391395
}
@@ -587,15 +591,9 @@ vdom.H("div", map[string]any{
587591
2. Global keyboard event handling:
588592

589593
```go
594+
// Global keyboard events are automatically enabled when you set a global event handler
590595
func init() {
591-
app.SetAppOpts(app.AppOpts{
592-
GlobalKeyboardEvents: true, // Enable global keyboard events
593-
Title: "My Tsunami App",
594-
})
595-
}
596-
597-
// In main() or an effect:
598-
app.SetGlobalEventHandler(func(event vdom.VDomEvent) {
596+
app.SetGlobalEventHandler(func(event vdom.VDomEvent) {
599597
if event.EventType != "onKeyDown" || event.KeyData == nil {
600598
return
601599
}
@@ -645,10 +643,9 @@ type WaveKeyboardEvent struct {
645643
}
646644
```
647645
648-
When using global keyboard events, remember to:
646+
When using global keyboard events:
649647
650-
1. Enable GlobalKeyboardEvents in AppOpts
651-
2. Set up the handler in a place where you have access to necessary state updates
648+
Global keyboard events are automatically enabled when you set a global event handler. Set up the handler in a place where you have access to necessary state updates.
652649
653650
## File Handling
654651
@@ -712,12 +709,8 @@ import (
712709
"github.com/wavetermdev/waveterm/tsunami/vdom"
713710
)
714711
715-
func init() {
716-
// Set up the default client with Tailwind styles
717-
app.SetAppOpts(app.AppOpts{
718-
Title: "My Tsunami App",
719-
})
720-
}
712+
// Tsunami applications automatically include Tailwind v4 CSS
713+
// No setup required - just use Tailwind classes in your components
721714
722715
// Basic domain types with json tags for props
723716
type Todo struct {
@@ -843,17 +836,10 @@ var App = app.DefineComponent("App",
843836
Key points:
844837
845838
1. Root component must be named "App"
846-
2. Use `init()` function to configure app options
847-
3. No main() function is needed - the framework handles app lifecycle
839+
2. Use `vdom.UseSetAppTitle()` in the main App component to set the window title
840+
3. Do NOT write a main() function - the framework handles app lifecycle
848841
4. File handlers can be registered in init() if needed
849842
850-
```
851-
type AppOpts struct {
852-
Title string // window title
853-
GlobalKeyboardEvents bool
854-
}
855-
```
856-
857843
## Important Technical Details
858844
859845
- Props must be defined as Go structs with json tags
@@ -863,7 +849,7 @@ type AppOpts struct {
863849
- Provide keys when using ForEach() with lists (using WithKey() method)
864850
- Use Classes() with If() for combining static and conditional class names
865851
- Consider cleanup functions in UseEffect() for async operations
866-
- <script> tags are not supported
852+
- <script> tags are NOT supported
867853
- Applications consist of a single file: app.go containing all Go code and component definitions
868854
- Styling is handled through Tailwind v4 CSS classes
869855
- No main() function is needed - use init() for configuration

0 commit comments

Comments
 (0)