Skip to content

Commit

Permalink
Merge pull request #16 from donseba/connector
Browse files Browse the repository at this point in the history
refactor to work with connectors as mentioned in #8
  • Loading branch information
donseba authored Dec 4, 2024
2 parents 4ef3ae4 + f98ad85 commit 8d46012
Show file tree
Hide file tree
Showing 26 changed files with 1,632 additions and 421 deletions.
445 changes: 445 additions & 0 deletions INTEGRATIONS.md

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,20 @@ go get github.com/donseba/go-partial
## Advanced use cases
Advanced usecases are documented in the [ADVANCED.md](ADVANCED.md) file

## Basic Usage
## Integrations
Several integrations are available, detailed information can be found in the [INTEGRATIONS.md](INTEGRATIONS.md) file
- htmx
- Turbo
- Stimulus
- Unpoly
- Alpine.js / Alpine Ajax (not great)
- Vue.js (not great)
- Standalone

## Basic Usage
Here's a simple example of how to use the package to render a template.

### 1. Create a Service

The `Service` holds global configurations and data.

```go
Expand All @@ -44,7 +52,6 @@ service.SetData(map[string]any{
```

## 2. Create a Layout

The `Layout` manages the overall structure of your templates.
```go
layout := service.NewLayout()
Expand All @@ -54,7 +61,6 @@ layout.SetData(map[string]any{
```

### 3. Define Partials

Create `Partial` instances for the content and any other components.

```go
Expand All @@ -81,7 +87,6 @@ func handler(w http.ResponseWriter, r *http.Request) {
```

## Template Files

templates/layout.html
```html
<!DOCTYPE html>
Expand All @@ -103,7 +108,6 @@ Note: In the layout template, we use {{ child "content" }} to render the content


### Using Global and Layout Data

- **Global Data (ServiceData)**: Set on the Service, accessible via {{.Service}} in templates.
- **Layout Data (LayoutData)**: Set on the Layout, accessible via {{.Layout}} in templates.
- **Partial Data (Data)**: Set on individual Partial instances, accessible via {{.Data}} in templates.
Expand Down
22 changes: 22 additions & 0 deletions connector/alpine-ajax.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package connector

import "net/http"

type AlpineAjax struct {
base
}

func NewAlpineAjax(c *Config) Connector {
return &AlpineAjax{
base: base{
config: c,
targetHeader: "X-Alpine-Target",
selectHeader: "X-Alpine-Select",
actionHeader: "X-Alpine-Action",
},
}
}

func (a *AlpineAjax) RenderPartial(r *http.Request) bool {
return r.Header.Get(a.targetHeader) != ""
}
22 changes: 22 additions & 0 deletions connector/alpine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package connector

import "net/http"

type Alpine struct {
base
}

func NewAlpine(c *Config) Connector {
return &Alpine{
base: base{
config: c,
targetHeader: "X-Alpine-Target",
selectHeader: "X-Alpine-Select",
actionHeader: "X-Alpine-Action",
},
}
}

func (a *Alpine) RenderPartial(r *http.Request) bool {
return r.Header.Get(a.targetHeader) != ""
}
87 changes: 87 additions & 0 deletions connector/connector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package connector

import "net/http"

type (
Connector interface {
RenderPartial(r *http.Request) bool
GetTargetValue(r *http.Request) string
GetSelectValue(r *http.Request) string
GetActionValue(r *http.Request) string

GetTargetHeader() string
GetSelectHeader() string
GetActionHeader() string
}

Config struct {
UseURLQuery bool
}

base struct {
config *Config
targetHeader string
selectHeader string
actionHeader string
}
)

func (x *base) RenderPartial(r *http.Request) bool {
return r.Header.Get(x.targetHeader) != ""
}

func (x *base) GetTargetHeader() string {
return x.targetHeader
}

func (x *base) GetSelectHeader() string {
return x.selectHeader
}

func (x *base) GetActionHeader() string {
return x.actionHeader
}

func (x *base) GetTargetValue(r *http.Request) string {
if targetValue := r.Header.Get(x.targetHeader); targetValue != "" {
return targetValue
}

if x.config.useURLQuery() {
return r.URL.Query().Get("target")
}

return ""
}

func (x *base) GetSelectValue(r *http.Request) string {
if selectValue := r.Header.Get(x.selectHeader); selectValue != "" {
return selectValue
}

if x.config.useURLQuery() {
return r.URL.Query().Get("select")
}

return ""
}

func (x *base) GetActionValue(r *http.Request) string {
if actionValue := r.Header.Get(x.actionHeader); actionValue != "" {
return actionValue
}

if x.config.useURLQuery() {
return r.URL.Query().Get("action")
}

return ""
}

func (c *Config) useURLQuery() bool {
if c == nil {
return false
}

return c.UseURLQuery
}
35 changes: 35 additions & 0 deletions connector/htmx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package connector

import (
"net/http"
)

type HTMX struct {
base

requestHeader string
boostedHeader string
historyRestoreRequestHeader string
}

func NewHTMX(c *Config) Connector {
return &HTMX{
base: base{
config: c,
targetHeader: "HX-Target",
selectHeader: "X-Select",
actionHeader: "X-Action",
},
requestHeader: "HX-Request",
boostedHeader: "HX-Boosted",
historyRestoreRequestHeader: "HX-History-Restore-Request",
}
}

func (h *HTMX) RenderPartial(r *http.Request) bool {
hxRequest := r.Header.Get(h.requestHeader)
hxBoosted := r.Header.Get(h.boostedHeader)
hxHistoryRestoreRequest := r.Header.Get(h.historyRestoreRequestHeader)

return (hxRequest == "true" || hxBoosted == "true") && hxHistoryRestoreRequest != "true"
}
16 changes: 16 additions & 0 deletions connector/partial.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package connector

type Partial struct {
base
}

func NewPartial(c *Config) Connector {
return &Partial{
base: base{
config: c,
targetHeader: "X-Target",
selectHeader: "X-Select",
actionHeader: "X-Action",
},
}
}
22 changes: 22 additions & 0 deletions connector/stimulus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package connector

import "net/http"

type Stimulus struct {
base
}

func NewStimulus(c *Config) Connector {
return &Stimulus{
base: base{
config: c,
targetHeader: "X-Stimulus-Target",
selectHeader: "X-Stimulus-Select",
actionHeader: "X-Stimulus-Action",
},
}
}

func (s *Stimulus) RenderPartial(r *http.Request) bool {
return r.Header.Get(s.targetHeader) != ""
}
16 changes: 16 additions & 0 deletions connector/turbo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package connector

type Turbo struct {
base
}

func NewTurbo(c *Config) Connector {
return &Turbo{
base: base{
config: c,
targetHeader: "Turbo-Frame",
selectHeader: "Turbo-Select",
actionHeader: "Turbo-Action",
},
}
}
22 changes: 22 additions & 0 deletions connector/unpoly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package connector

import "net/http"

type Unpoly struct {
base
}

func NewUnpoly(c *Config) Connector {
return &Unpoly{
base: base{
config: c,
targetHeader: "X-Up-Target",
selectHeader: "X-Up-Select",
actionHeader: "X-Up-Action",
},
}
}

func (u *Unpoly) RenderPartial(r *http.Request) bool {
return r.Header.Get(u.targetHeader) != ""
}
22 changes: 22 additions & 0 deletions connector/vuejs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package connector

import "net/http"

type Vue struct {
base
}

func NewVue(c *Config) Connector {
return &Vue{
base: base{
config: c,
targetHeader: "X-Vue-Target",
selectHeader: "X-Vue-Select",
actionHeader: "X-Vue-Action",
},
}
}

func (v *Vue) RenderPartial(r *http.Request) bool {
return r.Header.Get(v.targetHeader) != ""
}
Loading

0 comments on commit 8d46012

Please sign in to comment.