todo mvc
This commit is contained in:
parent
70255ca8de
commit
1aab41bfa9
8 changed files with 122 additions and 16 deletions
|
|
@ -105,7 +105,7 @@ func PartialViewWithHeaders(c echo.Context, headers *Headers, partial *Partial)
|
|||
|
||||
if headers != nil {
|
||||
for s, a := range *headers {
|
||||
c.Set(s, a)
|
||||
c.Response().Header().Set(s, a)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ func PartialView(c echo.Context, partial *Partial) error {
|
|||
c.Set(echo.HeaderContentType, echo.MIMETextHTML)
|
||||
if partial.Headers != nil {
|
||||
for s, a := range *partial.Headers {
|
||||
c.Set(s, a)
|
||||
c.Response().Header().Set(s, a)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
32
framework/h/array.go
Normal file
32
framework/h/array.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package h
|
||||
|
||||
func Unique[T any](slice []T, key func(item T) string) []T {
|
||||
var result []T
|
||||
seen := make(map[string]bool)
|
||||
for _, v := range slice {
|
||||
k := key(v)
|
||||
if _, ok := seen[k]; !ok {
|
||||
seen[k] = true
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Filter[T any](slice []T, predicate func(item T) bool) []T {
|
||||
var result []T
|
||||
for _, v := range slice {
|
||||
if predicate(v) {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Map[T, U any](slice []T, mapper func(item T) U) []U {
|
||||
var result []U
|
||||
for _, v := range slice {
|
||||
result = append(result, mapper(v))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
@ -77,22 +77,27 @@ type JsCommand struct {
|
|||
}
|
||||
|
||||
func SetText(text string) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.innerText = '%s'", text)}
|
||||
}
|
||||
|
||||
func Increment(amount int) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.innerText = parseInt(this.innerText) + %d", amount)}
|
||||
}
|
||||
|
||||
func SetInnerHtml(r Renderable) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.innerHTML = `%s`", Render(r.Render()))}
|
||||
}
|
||||
|
||||
func SetOuterHtml(r Renderable) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.outerHTML = `%s`", Render(r.Render()))}
|
||||
}
|
||||
|
||||
func AddAttribute(name, value string) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.setAttribute('%s', '%s')", name, value)}
|
||||
}
|
||||
|
||||
|
|
@ -105,18 +110,22 @@ func SetDisabled(disabled bool) JsCommand {
|
|||
}
|
||||
|
||||
func RemoveAttribute(name string) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.removeAttribute('%s')", name)}
|
||||
}
|
||||
|
||||
func AddClass(class string) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.classList.add('%s')", class)}
|
||||
}
|
||||
|
||||
func RemoveClass(class string) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("this.classList.remove('%s')", class)}
|
||||
}
|
||||
|
||||
func Alert(text string) JsCommand {
|
||||
// language=JavaScript
|
||||
return JsCommand{Command: fmt.Sprintf("alert('%s')", text)}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,17 @@ func Class(value ...string) Renderable {
|
|||
}
|
||||
}
|
||||
|
||||
func ClassX(value string, m map[string]bool) Renderable {
|
||||
builder := strings.Builder{}
|
||||
builder.WriteString(value + " ")
|
||||
for k, v := range m {
|
||||
if v {
|
||||
builder.WriteString(k + " ")
|
||||
}
|
||||
}
|
||||
return Class(builder.String())
|
||||
}
|
||||
|
||||
func MergeClasses(classes ...string) string {
|
||||
builder := ""
|
||||
for _, s := range classes {
|
||||
|
|
@ -151,10 +162,26 @@ func Post(url string) Renderable {
|
|||
return Attribute("hx-post", url)
|
||||
}
|
||||
|
||||
func PostOnClick(url string) Renderable {
|
||||
return AttributeList(Attribute("hx-post", url), Trigger("click"))
|
||||
}
|
||||
|
||||
func PostPartialOnClick(partial func(ctx *RequestContext) *Partial) Renderable {
|
||||
return PostOnClick(GetPartialPath(partial))
|
||||
}
|
||||
|
||||
func PostPartialOnClickQs(partial func(ctx *RequestContext) *Partial, qs string) Renderable {
|
||||
return PostOnClick(GetPartialPathWithQs(partial, qs))
|
||||
}
|
||||
|
||||
func Trigger(trigger string) Renderable {
|
||||
return Attribute("hx-trigger", trigger)
|
||||
}
|
||||
|
||||
func TextF(format string, args ...interface{}) Renderable {
|
||||
return Text(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func Text(text string) Renderable {
|
||||
return &Node{
|
||||
tag: "text",
|
||||
|
|
@ -542,11 +569,11 @@ func NewSwap(selector string, content *Node) SwapArg {
|
|||
}
|
||||
}
|
||||
|
||||
func Swap(ctx *RequestContext, content Renderable) Renderable {
|
||||
return SwapWithSelector(ctx, "", content)
|
||||
func OobSwap(ctx *RequestContext, content Renderable) Renderable {
|
||||
return OobSwapWithSelector(ctx, "", content)
|
||||
}
|
||||
|
||||
func SwapWithSelector(ctx *RequestContext, selector string, content Renderable) Renderable {
|
||||
func OobSwapWithSelector(ctx *RequestContext, selector string, content Renderable) Renderable {
|
||||
if ctx == nil || ctx.Get("HX-Request") == "" {
|
||||
return Empty()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,6 @@ func Ternary[T any](value bool, a T, b T) T {
|
|||
return b
|
||||
}
|
||||
|
||||
func Map[T any, U any](items []T, fn func(T) U) []U {
|
||||
var result []U
|
||||
for _, item := range items {
|
||||
result = append(result, fn(item))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func JsonSerialize(data any) string {
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ func NewsSheet(ctx echo.Context) *h.Partial {
|
|||
},
|
||||
SheetWrapper(
|
||||
h.IfElseLazy(open, SheetOpen, SheetClosed),
|
||||
h.Swap(ctx, OpenSheetButton(open)),
|
||||
h.Swap(ctx, NewsSheetOpenCount(ctx).Root),
|
||||
h.OobSwap(ctx, OpenSheetButton(open)),
|
||||
h.OobSwap(ctx, NewsSheetOpenCount(ctx).Root),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func Closed() h.Renderable {
|
|||
func Close(ctx echo.Context) *h.Partial {
|
||||
return h.NewPartialWithHeaders(
|
||||
h.Ternary(ctx.Query("path") != "", h.ReplaceUrlHeader(ctx.Query("path")), h.NewHeaders()),
|
||||
h.Swap(ctx, Closed()),
|
||||
h.OobSwap(ctx, Closed()),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
46
tailwind-lsp-config.json
Normal file
46
tailwind-lsp-config.json
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"includeLanguages": {
|
||||
"ftl": "html",
|
||||
"jinja": "html",
|
||||
"jinja2": "html",
|
||||
"smarty": "html",
|
||||
"tmpl": "gohtml",
|
||||
"cshtml": "html",
|
||||
"vbhtml": "html",
|
||||
"razor": "html",
|
||||
"go": "html"
|
||||
},
|
||||
"files": {
|
||||
"exclude": [
|
||||
"**/.git/**",
|
||||
"**/node_modules/**",
|
||||
"**/.hg/**",
|
||||
"**/.svn/**"
|
||||
]
|
||||
},
|
||||
"emmetCompletions": false,
|
||||
"classAttributes": ["class", "className", "ngClass"],
|
||||
"colorDecorators": false,
|
||||
"showPixelEquivalents": true,
|
||||
"rootFontSize": 16,
|
||||
"hovers": true,
|
||||
"suggestions": true,
|
||||
"codeActions": true,
|
||||
"validate": true,
|
||||
"lint": {
|
||||
"invalidScreen": "error",
|
||||
"invalidVariant": "error",
|
||||
"invalidTailwindDirective": "error",
|
||||
"invalidApply": "error",
|
||||
"invalidConfigPath": "error",
|
||||
"cssConflict": "warning",
|
||||
"recommendedVariantOrder": "warning"
|
||||
},
|
||||
"experimental": {
|
||||
"configFile": null,
|
||||
"classRegex": [[
|
||||
"tailwind|Class|h.Class\\(([^)]*)\\)",
|
||||
"[\"'`]([^\"'`]*).*?[\"'`]"
|
||||
]]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue