Skip to content

Commit

Permalink
Merge pull request #14 from donseba/examples
Browse files Browse the repository at this point in the history
Additional examples
  • Loading branch information
donseba authored Nov 25, 2024
2 parents 485341f + 75db38c commit 568e4d5
Show file tree
Hide file tree
Showing 23 changed files with 1,136 additions and 297 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The `Service` holds global configurations and data.

```go
cfg := &partial.Config{
PartialHeader: "X-Partial", // Optional: Header to determine which partial to render
PartialHeader: "X-Target", // Optional: Header to determine which partial to render
UseCache: true, // Enable template caching
FuncMap: template.FuncMap{}, // Global template functions
Logger: myLogger, // Implement the Logger interface or use nil
Expand Down Expand Up @@ -279,7 +279,7 @@ cfg := &partial.Config{
```

## Handling Partial Rendering via HTTP Headers
You can render specific partials based on the X-Partial header (or your custom header).
You can render specific partials based on the X-Target header (or your custom header).

Example:
```go
Expand All @@ -295,7 +295,7 @@ func handler(w http.ResponseWriter, r *http.Request) {

To request a specific partial:
```bash
curl -H "X-Partial: sidebar" http://localhost:8080
curl -H "X-Target: sidebar" http://localhost:8080
```

## Useless benchmark results
Expand Down
77 changes: 77 additions & 0 deletions examples/form/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"context"
"encoding/json"
"fmt"
"github.com/donseba/go-partial"
"log/slog"
"net/http"
"path/filepath"
)

type (
App struct {
PartialService *partial.Service
}

FormData struct {
Username string `json:"username"`
Password string `json:"password"`
}
)

func main() {
logger := slog.Default()

app := &App{
PartialService: partial.NewService(&partial.Config{
Logger: logger,
}),
}

mux := http.NewServeMux()

mux.Handle("GET /js/", http.StripPrefix("/js/", http.FileServer(http.Dir("../../js"))))
mux.HandleFunc("GET /", app.home)
mux.HandleFunc("POST /", app.home)

server := &http.Server{
Addr: ":8080",
Handler: mux,
}

logger.Info("starting server on :8080")
err := server.ListenAndServe()
if err != nil {
logger.Error("error starting server", "error", err)
}
}

func (a *App) home(w http.ResponseWriter, r *http.Request) {
layout := a.PartialService.NewLayout()
footer := partial.NewID("footer", filepath.Join("templates", "footer.gohtml"))
index := partial.NewID("index", filepath.Join("templates", "index.gohtml")).WithOOB(footer)
content := partial.NewID("form", filepath.Join("templates", "form.gohtml")).WithAction(func(ctx context.Context, p *partial.Partial, data *partial.Data) (*partial.Partial, error) {
switch p.GetRequestedAction() {
case "submit":
formData := &FormData{}
err := json.NewDecoder(r.Body).Decode(formData)
if err != nil {
return nil, fmt.Errorf("error decoding form data: %w", err)
}

w.Header().Set("X-Event-Notify", `{"type": "success", "message": "Form submitted successfully"}`)
p = p.Templates(filepath.Join("templates", "submitted.gohtml")).AddData("formData", formData)
}

return p, nil
})

layout.Set(content).Wrap(index)

err := layout.WriteWithRequest(r.Context(), w, r)
if err != nil {
http.Error(w, fmt.Errorf("error rendering layout: %w", err).Error(), http.StatusInternalServerError)
}
}
1 change: 1 addition & 0 deletions examples/form/templates/footer.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div id="footer" {{ if swapOOB }}x-swap-oob="outerHTML"{{end}} class="container">footer time : {{ formatDate now "15:04:05" }} - {{ if swapOOB }}swapped with OOB{{else}}rendered on load{{end}}</div>
8 changes: 8 additions & 0 deletions examples/form/templates/form.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="container mt-5">
<!-- Example Form with JSON Serialization -->
<form x-post="/submit" x-serialize="json" x-target="#form" x-action="submit">
<input type="text" name="username" />
<input type="password" name="password" />
<button type="submit">Submit</button>
</form>
</div>
71 changes: 71 additions & 0 deletions examples/form/templates/index.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Form Example</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script type="application/javascript" src="/js/partial.js"></script>
</head>

<body>
<div id="form">
{{ child "form" }}
</div>

<div class="mt-3 container">
<div>(rendered on load at : {{ formatDate now "15:04:05" }})</div>
<div class="mt-3">What the handler looks like: </div>
<pre class="mt-1 p-1" style="background-color: gray"><small>func (a *App) home(w http.ResponseWriter, r *http.Request) {
layout := a.PartialService.NewLayout()
footer := partial.NewID("footer", filepath.Join("templates", "footer.gohtml"))
index := partial.NewID("index", filepath.Join("templates", "index.gohtml")).WithOOB(footer)
content := partial.NewID("form", filepath.Join("templates", "form.gohtml")).WithAction(func(ctx context.Context, p *partial.Partial, data *partial.Data) (*partial.Partial, error) {
switch p.GetRequestedAction() {
case "submit":
formData := &FormData{}
err := json.NewDecoder(r.Body).Decode(formData)
if err != nil {
return nil, fmt.Errorf("error decoding form data: %w", err)
}

w.Header().Set("X-Event-Notify", `{"type": "success", "message": "Form submitted successfully"}`)
p = p.Templates(filepath.Join("templates", "submitted.gohtml")).AddData("formData", formData)
}

return p, nil
})

layout.Set(content).Wrap(index)

err := layout.WriteWithRequest(r.Context(), w, r)
if err != nil {
http.Error(w, fmt.Errorf("error rendering layout: %w", err).Error(), http.StatusInternalServerError)
}
}</small></pre>

<div class="mt-3">What the form looks like: </div>
<pre class="mt-1 p-1" style="background-color: gray"><small>&lt;div class=&quot;container mt-5&quot;&gt;
&lt;!-- Example Form with JSON Serialization --&gt;
&lt;form x-post=&quot;/submit&quot; x-serialize=&quot;json&quot; x-target=&quot;#form&quot; x-action=&quot;submit&quot;&gt;
&lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;
&lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;
&lt;button type=&quot;submit&quot;&gt;Submit&lt;/button&gt;
&lt;/form&gt;
&lt;/div&gt;</small></pre>
</div>



{{ child "footer" }}

<script>
// Initialize the handler with optional configuration
const partial = new Partial({
defaultSwapOption: "innerHTML",
});

partial.event('notify', (event) => {
alert('Form submitted successfully');
}, { once: true });
</script>
</body>
</html>
8 changes: 8 additions & 0 deletions examples/form/templates/submitted.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="container mt-5">
<div>Form Submitted</div>

<div>Received</div>
<pre>
{{ debug .Data.formData }}
</pre>
</div>
2 changes: 1 addition & 1 deletion examples/tabs-htmx/index.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<title>Tab Example</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script src="https://unpkg.com/[email protected]"></script>
<script src="/js/htmx.partial.js"></script>
<script src="/js/partial.htmx.js"></script>
</head>

<body>
Expand Down
2 changes: 1 addition & 1 deletion examples/tabs/index.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

<script>
// Initialize the handler with optional configuration
const xP = new XPartial({
const partial = new Partial({
enableUrlParam: true, // Enable URL parameter setting
urlParamName: 'x-select', // Name of the query parameter (e.g., 'selected', 'tab')
replaceState: false // Use pushState (false) or replaceState (true) when updating the URL
Expand Down
13 changes: 7 additions & 6 deletions examples/tabs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/donseba/go-partial"
"log/slog"
"net/http"
"path/filepath"
)

type (
Expand Down Expand Up @@ -44,17 +45,17 @@ func main() {
func (a *App) home(w http.ResponseWriter, r *http.Request) {
// the tabs for this page.
selectMap := map[string]*partial.Partial{
"tab1": partial.New("tab1.gohtml"),
"tab2": partial.New("tab2.gohtml"),
"tab3": partial.New("tab3.gohtml"),
"tab1": partial.New(filepath.Join("templates", "tab1.gohtml")),
"tab2": partial.New(filepath.Join("templates", "tab2.gohtml")),
"tab3": partial.New(filepath.Join("templates", "tab3.gohtml")),
}

// layout, footer, index could be abstracted away and shared over multiple handlers within the same module, for instance.
layout := a.PartialService.NewLayout()
footer := partial.NewID("footer", "footer.gohtml")
index := partial.NewID("index", "index.gohtml").WithOOB(footer)
footer := partial.NewID("footer", filepath.Join("templates", "footer.gohtml"))
index := partial.NewID("index", filepath.Join("templates", "index.gohtml")).WithOOB(footer)

content := partial.NewID("content", "content.gohtml").WithSelectMap("tab1", selectMap)
content := partial.NewID("content", filepath.Join("templates", "content.gohtml")).WithSelectMap("tab1", selectMap)

// set the layout content and wrap it with the main template
layout.Set(content).Wrap(index)
Expand Down
18 changes: 18 additions & 0 deletions examples/tabs/templates/content.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="container mt-5">
<!-- Tab Navigation -->
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<span class="nav-link {{ ifRequestedSelect "active" "tab1" ""}}" style="cursor:pointer;" x-get="/" x-target="#content" x-select="tab1">Tab 1</span>
</li>
<li class="nav-item">
<span class="nav-link {{ ifRequestedSelect "active" "tab2"}}" style="cursor:pointer;" x-get="/" x-target="#content" x-select="tab2">Tab 2</span>
</li>
<li class="nav-item">
<span class="nav-link {{ ifRequestedSelect "active" "tab3"}}" style="cursor:pointer;" x-get="/" x-target="#content" x-select="tab3" x-debounce="1000">Tab 3 (debounce 1000ms)</span>
</li>
</ul>

<div class="mt-3">
{{ selection }}
</div>
</div>
1 change: 1 addition & 0 deletions examples/tabs/templates/footer.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div id="footer" {{ if swapOOB }}x-swap-oob="outerHTML"{{end}} class="container">footer time : {{ formatDate now "15:04:05" }} - {{ if swapOOB }}swapped with OOB{{else}}rendered on load{{end}}</div>
50 changes: 50 additions & 0 deletions examples/tabs/templates/index.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tab Example</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script type="application/javascript" src="/js/partial.js"></script>
</head>

<body>
<div id="content">
{{ child "content" }}
</div>

<div class="mt-3 container">
<div>(rendered on load at : {{ formatDate now "15:04:05" }})</div>
<div class="mt-3">What the handler looks like: </div>

<pre class="mt-3 p-1" style="background-color: gray"><small>func (a *App) home(w http.ResponseWriter, r *http.Request) {
// the tabs for this page.
selectMap := map[string]*partial.Partial{
"tab1": partial.New("tab1.gohtml"),
"tab2": partial.New("tab2.gohtml"),
"tab3": partial.New("tab3.gohtml"),
}

// layout, footer, index could be abstracted away and shared over multiple handlers within the same module, for instance.
layout := a.PartialService.NewLayout()
footer := partial.NewID("footer", "footer.gohtml")
index := partial.NewID("index", "index.gohtml").WithOOB(footer)

content := partial.NewID("content", "content.gohtml").WithSelectMap("tab1", selectMap)

// set the layout content and wrap it with the main template
layout.Set(content).Wrap(index)

err := layout.WriteWithRequest(r.Context(), w, r)
if err != nil {
http.Error(w, fmt.Errorf("error rendering layout: %w", err).Error(), http.StatusInternalServerError)
}
}</small></pre>
</div>

{{ child "footer" }}

<script>
// Initialize the handler with optional configuration
const partial = new Partial();
</script>
</body>
</html>
1 change: 1 addition & 0 deletions examples/tabs/templates/tab1.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque pulvinar massa pulvinar eros molestie pellentesque. Mauris facilisis libero leo, non cursus ex facilisis a. Donec tempor metus non ex efficitur, in vestibulum nunc dapibus. Etiam pretium tortor magna, eget tempus lacus varius et. Sed vestibulum velit sed odio facilisis dignissim. Fusce in dolor ac enim consequat cursus et id lorem. Donec convallis lorem dignissim tristique pellentesque. Etiam ultricies sed mauris vitae hendrerit. Maecenas accumsan ligula vel libero faucibus, in lacinia justo ullamcorper. Etiam pulvinar ex ac odio posuere bibendum. Pellentesque ipsum justo, finibus in egestas ac, dignissim varius neque. Fusce laoreet consequat diam, ut imperdiet libero laoreet quis. Aenean tincidunt a tellus vel posuere. Aenean vel elementum mauris. Pellentesque erat tortor, lobortis ac ullamcorper vitae, sagittis vel arcu. Morbi malesuada, justo ut dignissim mollis, diam nunc consequat enim, nec facilisis ex felis ac dui.
1 change: 1 addition & 0 deletions examples/tabs/templates/tab2.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Suspendisse blandit, nisl ac porta auctor, mauris nisi elementum enim, non laoreet mauris justo eu sem. Cras eget urna id libero posuere luctus vitae ac lacus. Nunc varius iaculis leo, eu ultrices ligula aliquam non. Suspendisse lacinia magna enim, a ornare leo placerat in. Sed accumsan sapien ligula, sed maximus enim rutrum ut. Fusce leo purus, vestibulum nec dui accumsan, ullamcorper viverra risus. Duis fermentum orci augue, non sagittis orci tempor at. Praesent quis ipsum fermentum, consequat massa at, finibus eros. Praesent nec massa nisi. Proin sed feugiat eros.
1 change: 1 addition & 0 deletions examples/tabs/templates/tab3.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Morbi elementum varius suscipit. Phasellus congue feugiat sem, vel sodales odio varius eu. Fusce non ex nisi. Aenean nisi dui, tincidunt nec est quis, mollis tempus libero. Fusce placerat pharetra diam, ac mollis turpis bibendum ac. Nullam pulvinar venenatis lacinia. Nam vel quam non ante dignissim bibendum id et ex. Suspendisse potenti.
Loading

0 comments on commit 568e4d5

Please sign in to comment.