Skip to content

Commit

Permalink
sse demo
Browse files Browse the repository at this point in the history
  • Loading branch information
will-wow committed May 20, 2024
1 parent e1a5fed commit 4571700
Show file tree
Hide file tree
Showing 17 changed files with 580 additions and 20 deletions.
13 changes: 6 additions & 7 deletions .vscode/examples.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,35 @@
"scope": "templ",
"prefix": "page",
"body": [
"package \"extempl\"",
"package ${TM_DIRECTORY/.*\\/(.*)$/$1/}",
"",
"import (",
" \"embed\"",
"",
" \"github.com/will-wow/typed-htmx-go/examples/web/layout/templ/layout\"",
" \"github.com/will-wow/typed-htmx-go/examples/web/${TM_DIRECTORY/.*\\/(.*)$/$1/}/shared\"",
" \"github.com/will-wow/typed-htmx-go/examples/web/exprint\"",
" \"github.com/will-wow/typed-htmx-go/htmx\"",
")",
"",
"var hx = htmx.NewTempl()",
"",
"//go:embed ${TM_DIRECTORY/.*\\/(.*)$/$1/}.templ",
"//go:embed $TM_FILENAME",
"var fs embed.FS",
"var ex = exprint.New(fs, \"//\", \"\")",
"",
"templ Page() {",
" @layout.Base(\"$1\") {",
" <h1>$1</h1>",
" @layout.Wrapper(\"$2\", \"$3\") {",
" <h1>$2</h1>",
" <p>",
" Desc",
" </p>",
" <pre>",
" <code class=\"language-go\">",
" { ex.PrintOrErr(\"${TM_DIRECTORY/.*\\/(.*)$/$1/}.templ\", \"demo\") }",
" { ex.PrintOrErr(\"$TM_FILENAME\") }",
" </code>",
" </pre>",
" <h2>Demo</h2>",
" { demo() }",
" @demo()",
" }",
"}",
"",
Expand Down
2 changes: 1 addition & 1 deletion examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/angelofallars/htmx-go v0.5.0
github.com/lithammer/dedent v1.1.0
github.com/maragudk/gomponents v0.20.2
github.com/will-wow/typed-htmx-go v0.1.2
github.com/will-wow/typed-htmx-go v0.2.0
)

require (
Expand Down
4 changes: 2 additions & 2 deletions examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffkt
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
github.com/maragudk/gomponents v0.20.2 h1:39FhnBNNCJzqNcD9Hmvp/5xj0otweFoyvVgFG6kXoy0=
github.com/maragudk/gomponents v0.20.2/go.mod h1:nHkNnZL6ODgMBeJhrZjkMHVvNdoYsfmpKB2/hjdQ0Hg=
github.com/will-wow/typed-htmx-go v0.1.2 h1:b9ZbWL/mXzEoed4sHNZeU9Q2L+I0aXjZZHGV8YQWmDU=
github.com/will-wow/typed-htmx-go v0.1.2/go.mod h1:4kTdRyJEy/oSURNcUAUvSiJ90Mf19W0dEhe/ouK7530=
github.com/will-wow/typed-htmx-go v0.2.0 h1:MGaL4XqdP6AC49hAgApRh/IdhmkyOQ0FVNmo2h8YkMo=
github.com/will-wow/typed-htmx-go v0.2.0/go.mod h1:4kTdRyJEy/oSURNcUAUvSiJ90Mf19W0dEhe/ouK7530=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
Expand Down
7 changes: 6 additions & 1 deletion examples/vercel.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"routes": [{ "src": "/(.*)", "dest": "/api" }]
"routes": [{ "src": "/(.*)", "dest": "/api" }],
"functions": {
"api/index.go": {
"maxDuration": "30"
}
}
}
1 change: 0 additions & 1 deletion examples/web/activesearch/extempl/activesearch_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion examples/web/bulkupdate/extempl/bulkupdate_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion examples/web/classtools_ex/extempl/classtools_ex_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion examples/web/clicktoedit/extempl/clicktoedit_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/web/layout/templ/layout/layout.templ
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ templ Wrapper(title string, className ...string) {
/>
<script src="https://unpkg.com/[email protected]"></script>
<script src="https://unpkg.com/[email protected]/dist/ext/class-tools.js"></script>
<script src="https://unpkg.com/[email protected]/dist/ext/sse.js"></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
Expand Down
3 changes: 1 addition & 2 deletions examples/web/layout/templ/layout/layout_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion examples/web/progressbar/extempl/progressbar_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 84 additions & 0 deletions examples/web/sse_ex/chatroom/chatroom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package chatroom

import (
"context"
"fmt"
"slices"
)

const EndEvent = "end"
const ChatEvent = "chat"

type Chat struct {
Message string
}

type Chatroom struct {
source chan Chat
listeners []chan Chat
addListener chan chan Chat
removeListener chan (<-chan Chat)
}

func New(ctx context.Context) *Chatroom {
c := &Chatroom{
source: make(chan Chat),
listeners: []chan Chat{},
addListener: make(chan chan Chat),
removeListener: make(chan (<-chan Chat)),
}

go c.run(ctx)

return c
}

func (c *Chatroom) Join() <-chan Chat {
newListener := make(chan Chat)
c.addListener <- newListener
return newListener
}

func (c *Chatroom) Leave(channel <-chan Chat) {
fmt.Println("removing listener")
c.removeListener <- channel
}

func (c *Chatroom) Send(message string) {
c.source <- Chat{Message: message}
}

func (c *Chatroom) run(ctx context.Context) {
defer func() {
for _, listener := range c.listeners {
if listener != nil {
close(listener)
}
}
}()

for {
select {
case <-ctx.Done():
fmt.Println("closing chatroom")
return
case newListener := <-c.addListener:
c.listeners = append(c.listeners, newListener)
case toRemove := <-c.removeListener:
c.listeners = slices.DeleteFunc(c.listeners, func(l chan Chat) bool {
if l == toRemove {
fmt.Println("removed listener")
return true
}
return false
})
case chat, ok := <-c.source:
if !ok {
return
}
for _, listener := range c.listeners {
listener <- chat
}
}
}
}
108 changes: 108 additions & 0 deletions examples/web/sse_ex/extempl/sse.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package extempl

import (
"embed"

"github.com/will-wow/typed-htmx-go/examples/web/layout/templ/layout"
"github.com/will-wow/typed-htmx-go/examples/web/exprint"
"github.com/will-wow/typed-htmx-go/htmx/ext/sse"
"github.com/will-wow/typed-htmx-go/htmx"
"github.com/will-wow/typed-htmx-go/htmx/swap"
"github.com/will-wow/typed-htmx-go/examples/web/sse_ex/chatroom"
"github.com/will-wow/typed-htmx-go/htmx/on"
)

var hx = htmx.NewTempl()

//go:embed sse.templ
var fs embed.FS
var ex = exprint.New(fs, "//", "")

templ Page() {
@layout.Wrapper("Server-Side Events") {
<h1>Server-Side Events</h1>
<p>
A demo of Server-Side Events using htmx and typed-htmx-go.
</p>
<p>
When you click the button below, that fetches a new element that uses the sse extension to start a live feed.
</p>
<pre>
<code class="language-go">
{ ex.PrintOrErr("sse.templ", "entry") }
</code>
</pre>
<p>
The new elements uses the sse.Connect attribute to connect to a server-side event stream, and allows you to POST messages to the stream.
</p>
<pre>
<code class="language-go">
{ ex.PrintOrErr("sse.templ", "chatroom") }
</code>
</pre>
<p>
When you or another user posts a message, it will be sent to the server and broadcast to all connected clients as a simple div.
</p>
<pre>
<code class="language-go">
{ ex.PrintOrErr("sse.templ", "message") }
</code>
</pre>
<p>
After 25 seconds, the server will send the EndEvent, that closes removes the sse connection by replacing the sse.Connect element with the initial button using <code>hx.Swap(swap.OuterHTML)</code>.
</p>
<h2>Demo</h2>
@Entry()
}
}

templ Entry() {
//ex:start:entry
<button
{ hx.Get("/examples/templ/sse/chatroom/")... }
{ hx.Target(htmx.TargetThis)... }
{ hx.Swap(swap.OuterHTML)... }
>
Enter Chat
</button>
//ex:end:entry
}

templ Chatroom() {
//ex:start:chatroom
<div
{ hx.Ext(sse.Extension)... }
{ sse.Connect(hx, "/examples/templ/sse/chatroom/feed/")... }
{ sse.Swap(hx, chatroom.EndEvent)... }
{ hx.Swap(swap.OuterHTML)... }
>
<form
id="form"
method="POST"
action="/examples/templ/sse/chatroom/post/"
{ hx.On(on.AfterRequest, "this.querySelector('#message').value = ''")... }
>
<label>
Send a message
<input
id="message"
type="text"
name="message"
/>
</label>
<button type="submit">Send</button>
</form>
<div
{ sse.Swap(hx, chatroom.ChatEvent)... }
{ hx.Swap(swap.BeforeEnd)... }
></div>
</div>
//ex:end:chatroom
}

//ex:start:message
templ ChatMessage(msg string) {
<div>{ msg }</div>
}

//ex:end:message
Loading

0 comments on commit 4571700

Please sign in to comment.