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 {
|
if headers != nil {
|
||||||
for s, a := range *headers {
|
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)
|
c.Set(echo.HeaderContentType, echo.MIMETextHTML)
|
||||||
if partial.Headers != nil {
|
if partial.Headers != nil {
|
||||||
for s, a := range *partial.Headers {
|
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 {
|
func SetText(text string) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.innerText = '%s'", text)}
|
return JsCommand{Command: fmt.Sprintf("this.innerText = '%s'", text)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Increment(amount int) JsCommand {
|
func Increment(amount int) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.innerText = parseInt(this.innerText) + %d", amount)}
|
return JsCommand{Command: fmt.Sprintf("this.innerText = parseInt(this.innerText) + %d", amount)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetInnerHtml(r Renderable) JsCommand {
|
func SetInnerHtml(r Renderable) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.innerHTML = `%s`", Render(r.Render()))}
|
return JsCommand{Command: fmt.Sprintf("this.innerHTML = `%s`", Render(r.Render()))}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetOuterHtml(r Renderable) JsCommand {
|
func SetOuterHtml(r Renderable) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.outerHTML = `%s`", Render(r.Render()))}
|
return JsCommand{Command: fmt.Sprintf("this.outerHTML = `%s`", Render(r.Render()))}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddAttribute(name, value string) JsCommand {
|
func AddAttribute(name, value string) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.setAttribute('%s', '%s')", name, value)}
|
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 {
|
func RemoveAttribute(name string) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.removeAttribute('%s')", name)}
|
return JsCommand{Command: fmt.Sprintf("this.removeAttribute('%s')", name)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddClass(class string) JsCommand {
|
func AddClass(class string) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.classList.add('%s')", class)}
|
return JsCommand{Command: fmt.Sprintf("this.classList.add('%s')", class)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveClass(class string) JsCommand {
|
func RemoveClass(class string) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("this.classList.remove('%s')", class)}
|
return JsCommand{Command: fmt.Sprintf("this.classList.remove('%s')", class)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Alert(text string) JsCommand {
|
func Alert(text string) JsCommand {
|
||||||
|
// language=JavaScript
|
||||||
return JsCommand{Command: fmt.Sprintf("alert('%s')", text)}
|
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 {
|
func MergeClasses(classes ...string) string {
|
||||||
builder := ""
|
builder := ""
|
||||||
for _, s := range classes {
|
for _, s := range classes {
|
||||||
|
|
@ -151,10 +162,26 @@ func Post(url string) Renderable {
|
||||||
return Attribute("hx-post", url)
|
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 {
|
func Trigger(trigger string) Renderable {
|
||||||
return Attribute("hx-trigger", trigger)
|
return Attribute("hx-trigger", trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TextF(format string, args ...interface{}) Renderable {
|
||||||
|
return Text(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
func Text(text string) Renderable {
|
func Text(text string) Renderable {
|
||||||
return &Node{
|
return &Node{
|
||||||
tag: "text",
|
tag: "text",
|
||||||
|
|
@ -542,11 +569,11 @@ func NewSwap(selector string, content *Node) SwapArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Swap(ctx *RequestContext, content Renderable) Renderable {
|
func OobSwap(ctx *RequestContext, content Renderable) Renderable {
|
||||||
return SwapWithSelector(ctx, "", content)
|
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") == "" {
|
if ctx == nil || ctx.Get("HX-Request") == "" {
|
||||||
return Empty()
|
return Empty()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,6 @@ func Ternary[T any](value bool, a T, b T) T {
|
||||||
return b
|
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 {
|
func JsonSerialize(data any) string {
|
||||||
serialized, err := json.Marshal(data)
|
serialized, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ func NewsSheet(ctx echo.Context) *h.Partial {
|
||||||
},
|
},
|
||||||
SheetWrapper(
|
SheetWrapper(
|
||||||
h.IfElseLazy(open, SheetOpen, SheetClosed),
|
h.IfElseLazy(open, SheetOpen, SheetClosed),
|
||||||
h.Swap(ctx, OpenSheetButton(open)),
|
h.OobSwap(ctx, OpenSheetButton(open)),
|
||||||
h.Swap(ctx, NewsSheetOpenCount(ctx).Root),
|
h.OobSwap(ctx, NewsSheetOpenCount(ctx).Root),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ func Closed() h.Renderable {
|
||||||
func Close(ctx echo.Context) *h.Partial {
|
func Close(ctx echo.Context) *h.Partial {
|
||||||
return h.NewPartialWithHeaders(
|
return h.NewPartialWithHeaders(
|
||||||
h.Ternary(ctx.Query("path") != "", h.ReplaceUrlHeader(ctx.Query("path")), h.NewHeaders()),
|
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