cleanup, get starter template working

This commit is contained in:
maddalax 2024-09-23 10:57:59 -05:00
parent 939e80968f
commit 52786613dc
30 changed files with 277 additions and 4169 deletions

View file

@ -3,12 +3,20 @@ package dirutil
import (
"errors"
"fmt"
"github.com/maddalax/htmgo/cli/htmgo/tasks/process"
"io"
"log/slog"
"os"
"path/filepath"
)
func HasFileFromRoot(file string) bool {
cwd := process.GetWorkingDir()
path := filepath.Join(cwd, file)
_, err := os.Stat(path)
return err == nil
}
func CopyDir(srcDir, dstDir string, predicate func(path string, exists bool) bool) error {
// Walk the source directory tree.
return filepath.Walk(srcDir, func(srcPath string, info os.FileInfo, err error) error {

View file

@ -20,7 +20,7 @@ func main() {
done := RegisterSignals()
commandMap := make(map[string]*flag.FlagSet)
commands := []string{"template", "run", "watch", "build", "setup", "css", "schema", "generate", "tailwind-cli"}
commands := []string{"template", "run", "watch", "build", "setup", "css", "schema", "generate"}
for _, command := range commands {
commandMap[command] = flag.NewFlagSet(command, flag.ExitOnError)
@ -69,9 +69,7 @@ func main() {
}()
startWatcher(reloader.OnFileChange)
} else {
if taskName == "tailwind-cli" {
css.DownloadTailwindCli()
} else if taskName == "schema" {
if taskName == "schema" {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter entity name:")
text, _ := reader.ReadString('\n')

View file

@ -7,8 +7,8 @@ import (
"github.com/maddalax/htmgo/cli/htmgo/tasks/process"
"golang.org/x/mod/modfile"
"log"
"log/slog"
"os"
"path/filepath"
"strings"
)
@ -67,8 +67,13 @@ func CopyAssets() {
err := dirutil.CopyDir(assetDistDir, destDirDist, func(path string, exists bool) bool {
return true
})
if err != nil {
log.Fatalf("Error: %v", err)
}
err = dirutil.CopyDir(assetCssDir, destDirCss, func(path string, exists bool) bool {
if exists {
if strings.HasSuffix(path, "tailwind.config.js") {
return false
}
return true
@ -78,5 +83,14 @@ func CopyAssets() {
log.Fatalf("Error: %v", err)
}
slog.Debug("successfully copied assets to %s\n", destDir)
err = dirutil.CopyFile(
filepath.Join(assetCssDir, "tailwind.config.js"),
filepath.Join(process.GetWorkingDir(), "tailwind.config.js"),
)
if err != nil {
log.Fatalf("Error: %v", err)
}
process.Run(fmt.Sprintf("cd %s && git add .", destDirCss))
}

View file

@ -2,25 +2,61 @@ package css
import (
"fmt"
"github.com/maddalax/htmgo/cli/htmgo/internal/dirutil"
"github.com/maddalax/htmgo/cli/htmgo/tasks/copyassets"
"github.com/maddalax/htmgo/cli/htmgo/tasks/process"
"log"
"log/slog"
"runtime"
)
func IsTailwindEnabled() bool {
return dirutil.HasFileFromRoot("tailwind.config.js")
}
func Setup() bool {
if !IsTailwindEnabled() {
slog.Debug("Tailwind is not enabled. Skipping CSS generation.")
return false
}
downloadTailwindCli()
if dirutil.HasFileFromRoot("assets/css/input.css") {
copyassets.CopyAssets()
}
return true
}
func GenerateCss(flags ...process.RunFlag) error {
if !Setup() {
return nil
}
return process.RunMany([]string{
"./assets/css/tailwindcss -i ./assets/css/input.css -o ./assets/dist/main.css -c ./assets/css/tailwind.config.js",
"./__htmgo/tailwind -i ./assets/css/input.css -o ./assets/dist/main.css -c ./tailwind.config.js",
}, append(flags, process.Silent)...)
}
func GenerateCssWatch(flags ...process.RunFlag) error {
if !Setup() {
return nil
}
return process.RunMany([]string{
"./assets/css/tailwindcss -i ./assets/css/input.css -o ./assets/dist/main.css -c ./assets/css/tailwind.config.js --watch=always",
"./__htmgo/tailwind -i ./assets/css/input.css -o ./assets/dist/main.css -c ./tailwind.config.js --watch=always",
}, append(flags, process.KillOnlyOnExit, process.Silent)...)
}
func DownloadTailwindCli() {
func downloadTailwindCli() {
if dirutil.HasFileFromRoot("__htmgo/tailwind") {
slog.Debug("Tailwind CLI already exists. Skipping download.")
return
}
if !IsTailwindEnabled() {
slog.Debug("Tailwind is not enabled. Skipping tailwind cli download.")
return
}
distro := ""
os := runtime.GOOS
arch := runtime.GOARCH
@ -41,7 +77,7 @@ func DownloadTailwindCli() {
process.RunMany([]string{
fmt.Sprintf(`curl -LO %s`, url),
fmt.Sprintf(`chmod +x %s`, fileName),
fmt.Sprintf(`mv %s ./assets/css/tailwindcss`, fileName),
fmt.Sprintf(`mv %s ./__htmgo/tailwind`, fileName),
}, process.ExitOnError)
slog.Debug("Successfully downloaded Tailwind CLI", slog.String("url", url))

View file

@ -53,6 +53,7 @@ func DownloadTemplate(outPath string) {
}
templateName := "starter-template"
templatePath := filepath.Join("templates", "starter")
re := regexp.MustCompile(`[^a-zA-Z]+`)
// Replace all non-alphabetic characters with an empty string
@ -68,7 +69,7 @@ func DownloadTemplate(outPath string) {
return
}
deleteAllExceptTemplate(outPath, templateName)
deleteAllExceptTemplate(outPath, templatePath)
newDir := filepath.Join(cwd, outPath)

View file

@ -6,26 +6,20 @@ import (
"github.com/maddalax/htmgo/cli/htmgo/tasks/copyassets"
"github.com/maddalax/htmgo/cli/htmgo/tasks/css"
"github.com/maddalax/htmgo/cli/htmgo/tasks/process"
"os"
)
func Build() {
css.DownloadTailwindCli()
copyassets.CopyAssets()
astgen.GenAst(process.ExitOnError)
css.GenerateCss(process.ExitOnError)
copyassets.CopyAssets()
process.RunOrExit("rm -rf ./dist")
process.RunOrExit("mkdir -p ./dist")
//flags := ""
//if os.Getenv("CGO_ENABLED") == "1" {
// flags = `-a -ldflags '-linkmode external -extldflags "-static"' `
//}
//
//process.RunOrExit(fmt.Sprintf("go build -o ./dist %s.", flags))
//process.RunOrExit(fmt.Sprintf("go build -o ./dist/app %s .", flags))
if os.Getenv("SKIP_GO_BUILD") != "1" {
process.RunOrExit(fmt.Sprintf("go build -o ./dist"))
}
fmt.Printf("Executable built at %s\n", process.GetPathRelativeToCwd("dist"))
}

View file

@ -1,6 +1,7 @@
package run
import (
"github.com/maddalax/htmgo/cli/htmgo/internal/dirutil"
"github.com/maddalax/htmgo/cli/htmgo/tasks/astgen"
"github.com/maddalax/htmgo/cli/htmgo/tasks/copyassets"
"github.com/maddalax/htmgo/cli/htmgo/tasks/css"
@ -10,8 +11,12 @@ import (
func Setup() {
process.RunOrExit("go mod download")
process.RunOrExit("go mod tidy")
copyassets.CopyAssets()
_ = astgen.GenAst(process.ExitOnError)
_ = css.GenerateCss(process.ExitOnError)
EntGenerate()
astgen.GenAst(process.ExitOnError)
css.GenerateCss(process.ExitOnError)
if dirutil.HasFileFromRoot("ent/schema") {
EntGenerate()
}
}

View file

@ -1,16 +0,0 @@
version: '3'
tasks:
run:
cmds:
- go run github.com/maddalax/htmgo/cli@latest run
silent: true
build:
cmds:
- go run github.com/maddalax/htmgo/cli@latest build
watch:
cmds:
- go run github.com/maddalax/htmgo/cli@latest watch
silent: true

View file

@ -1,3 +0,0 @@
package ent
//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema

View file

@ -1,42 +0,0 @@
package schema
import (
"entgo.io/ent"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema/field"
"time"
)
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age").
Positive(),
field.String("name").
Default("unknown"),
field.String("occupation").Optional(),
field.String("email").Optional(),
field.String("password").Sensitive().Optional(),
field.String("test").Optional(),
field.String("test2").Optional(),
field.String("test4").Optional(),
field.Time("created_at").
Default(time.Now).Annotations(
entsql.Default("CURRENT_TIMESTAMP"),
),
field.Time("updated_at").
Default(time.Now).Annotations(
entsql.Default("CURRENT_TIMESTAMP"),
),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return nil
}

View file

@ -1,39 +0,0 @@
module starter-template
go 1.23.0
require (
entgo.io/ent v0.14.1
github.com/maddalax/htmgo/framework v0.0.0-20240916224719-9e5d8edada65
)
require (
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect
github.com/agext/levenshtein v1.2.1 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl/v2 v2.13.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
github.com/zclconf/go-cty v1.8.0 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)

View file

@ -1,26 +0,0 @@
package main
import (
"github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
_ "github.com/mattn/go-sqlite3"
"log"
"starter-template/pages"
"starter-template/partials/load"
"time"
)
func main() {
var startTime = time.Now()
f := echo.New()
f.Static("/public", "./assets/dist")
load.RegisterPartials(f)
pages.RegisterPages(f)
log.Printf("main() ready in %s", time.Since(startTime))
h.Start(f, h.App{
LiveReload: true,
})
}

View file

@ -1,40 +0,0 @@
package pages
import (
"github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
"starter-template/pages/base"
"starter-template/partials"
)
func IndexPage(c echo.Context) *h.Page {
return h.NewPage(h.Html(
h.HxExtension(base.Extensions()),
h.Class("bg-red-200 flex flex-col items-center h-full w-full"),
h.Head(
h.Link("/public/main.css", "stylesheet"),
h.Script("/public/htmgo.js"),
),
h.Body(
h.Class("flex flex-col gap-4"),
h.Div(h.Class("flex gap-2 mt-6"),
Button(),
Button(),
Button(),
Button(),
),
),
))
}
func Button() h.Ren {
return h.Button(h.Class("btn bg-green-500 p-4 rounded text-white"),
h.Text("my button"),
h.HxAfterRequest(
h.SetDisabled(true),
h.RemoveClass("bg-red-600"),
h.AddClass("bg-gray-500"),
),
h.GetPartial(partials.SamplePartial),
)
}

View file

@ -1,18 +0,0 @@
package partials
import (
"github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
)
func SamplePartial(ctx echo.Context) *h.Partial {
return h.NewPartial(h.Div(h.P(h.Text(" asdasasds"))))
}
func NewPartial(ctx echo.Context) *h.Partial {
return h.NewPartial(h.Div(h.P(h.Text("This sadsl."))))
}
func NewPartial2(ctx echo.Context) *h.Partial {
return h.NewPartial(h.Div(h.P(h.Text("This sasdsadasdwl."))))
}

View file

@ -1,36 +1,5 @@
const {join} = require("node:path");
/** @type {import('tailwindcss').Config} */
const root = join(__dirname, "../../");
const contentGo = join(root, "**/*.go");
const contentJs = join(root, "**/pages/**/*.js");
module.exports = {
content: [contentGo, contentJs],
theme: {
extend: {
colors: {
background: 'hsl(224, 71.4%, 4.1%)',
foreground: 'hsl(0, 0%, 89%)',
card: 'hsl(224, 71.4%, 4.1%)',
cardForeground: 'hsl(0, 0%, 89%)',
popover: 'hsl(224, 71.4%, 4.1%)',
popoverForeground: 'hsl(0, 0%, 89%)',
primary: 'hsl(0, 0%, 89%)',
primaryForeground: 'hsl(220.9, 39.3%, 11%)',
secondary: 'hsl(215, 27.9%, 16.9%)',
secondaryForeground: 'hsl(0, 0%, 89%)',
muted: 'hsl(215, 27.9%, 16.9%)',
mutedForeground: 'hsl(217.9, 10.6%, 64.9%)',
accent: 'hsl(215, 27.9%, 16.9%)',
accentForeground: 'hsl(0, 0%, 89%)',
destructive: 'hsl(0, 62.8%, 30.6%)',
destructiveForeground: 'hsl(0, 0%, 89%)',
border: 'hsl(215, 27.9%, 16.9%)',
input: 'hsl(215, 27.9%, 16.9%)',
ring: 'hsl(216, 12.2%, 83.9%)',
},
},
},
content: ["**/*.go", "**/*.js"],
plugins: [],
};

File diff suppressed because one or more lines are too long

View file

@ -16,7 +16,7 @@ export default defineConfig({
js: ".js",
};
},
minify: false,
minify: true,
bundle: true,
splitting: true,
// https://github.com/egoist/tsup/issues/619

View file

@ -12,6 +12,14 @@ func Ternary[T any](value bool, a T, b T) T {
return IfElse(value, a, b)
}
func ElementIf(condition bool, element *Element) *Element {
if condition {
return element
} else {
return Empty()
}
}
func IfElse[T any](condition bool, node T, node2 T) T {
if condition {
return node

View file

@ -2,6 +2,7 @@ package h
import (
"fmt"
"strconv"
)
type ClassMap map[string]bool
@ -117,6 +118,17 @@ func Checkbox(children ...Ren) Ren {
return Input("checkbox", children...)
}
func Value(value any) Ren {
switch v := value.(type) {
case string:
return Attribute("value", v)
case int:
return Attribute("value", strconv.Itoa(v))
default:
return Attribute("value", fmt.Sprintf("%v", v))
}
}
func Input(inputType string, children ...Ren) Ren {
attributeMap := AttributeMap{
"type": inputType,

View file

@ -0,0 +1,16 @@
version: '3'
tasks:
run:
cmds:
- go run github.com/maddalax/htmgo/cli/htmgo@latest run
silent: true
build:
cmds:
- go run github.com/maddalax/htmgo/cli/htmgo@latest build
watch:
cmds:
- go run github.com/maddalax/htmgo/cli/htmgo@latest watch
silent: true

View file

@ -1,12 +1,13 @@
// Package pages THIS FILE IS GENERATED. DO NOT EDIT.
package pages
// Package __htmgo THIS FILE IS GENERATED. DO NOT EDIT.
package __htmgo
import "github.com/labstack/echo/v4"
import "github.com/maddalax/htmgo/framework/h"
import "starter-template/pages"
func RegisterPages(f *echo.Echo) {
f.GET("/", func(ctx echo.Context) error {
cc := ctx.(*h.RequestContext)
return h.HtmlView(ctx, IndexPage(cc))
return h.HtmlView(ctx, pages.IndexPage(cc))
})
}

View file

@ -1,5 +1,5 @@
// Package partials THIS FILE IS GENERATED. DO NOT EDIT.
package load
// Package __htmgo THIS FILE IS GENERATED. DO NOT EDIT.
package __htmgo
import "github.com/maddalax/htmgo/framework/h"
import "github.com/labstack/echo/v4"
@ -7,17 +7,9 @@ import "starter-template/partials"
func GetPartialFromContext(ctx echo.Context) *h.Partial {
path := ctx.Request().URL.Path
if path == "SamplePartial" || path == "/starter-template/partials.SamplePartial" {
if path == "CounterPartial" || path == "/starter-template/partials.CounterPartial" {
cc := ctx.(*h.RequestContext)
return partials.SamplePartial(cc)
}
if path == "NewPartial" || path == "/starter-template/partials.NewPartial" {
cc := ctx.(*h.RequestContext)
return partials.NewPartial(cc)
}
if path == "NewPartial2" || path == "/starter-template/partials.NewPartial2" {
cc := ctx.(*h.RequestContext)
return partials.NewPartial2(cc)
return partials.CounterPartial(cc)
}
return nil
}

View file

@ -0,0 +1,11 @@
// Package __htmgo THIS FILE IS GENERATED. DO NOT EDIT.
package __htmgo
import (
"github.com/labstack/echo/v4"
)
func Register(e *echo.Echo) {
RegisterPartials(e)
RegisterPages(e)
}

22
templates/starter/go.mod Normal file
View file

@ -0,0 +1,22 @@
module starter-template
go 1.23.0
require (
github.com/labstack/echo/v4 v4.12.0
github.com/maddalax/htmgo/framework v0.0.0-20240923041212-939e80968f38
github.com/mattn/go-sqlite3 v1.14.16
)
require (
github.com/google/uuid v1.6.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
)

33
templates/starter/main.go Normal file
View file

@ -0,0 +1,33 @@
package main
import (
"embed"
"github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
"github.com/maddalax/htmgo/framework/service"
_ "github.com/mattn/go-sqlite3"
"io/fs"
"starter-template/__htmgo"
)
//go:embed assets/dist/*
var StaticAssets embed.FS
func main() {
locator := service.NewLocator()
sub, err := fs.Sub(StaticAssets, "assets/dist")
if err != nil {
panic(err)
}
h.Start(h.AppOpts{
ServiceLocator: locator,
LiveReload: true,
Register: func(e *echo.Echo) {
e.StaticFS("/public", sub)
__htmgo.Register(e)
},
})
}

View file

@ -0,0 +1,21 @@
package pages
import (
"github.com/maddalax/htmgo/framework/h"
"starter-template/partials"
)
func IndexPage(ctx *h.RequestContext) *h.Page {
return h.NewPage(
RootPage(
h.Div(
h.Class("flex flex-col gap-4 items-center pt-24 min-h-screen bg-neutral-100"),
h.H3(h.Id("intro-text"), h.Text("hello htmgo"), h.Class("text-5xl")),
h.Div(
h.Class("mt-3"),
partials.CounterForm(0),
),
),
),
)
}

View file

@ -1,21 +1,12 @@
package base
package pages
import (
"github.com/maddalax/htmgo/framework/h"
"strings"
)
func Extensions() string {
extensions := []string{"path-deps", "response-targets", "mutation-error"}
if h.IsDevelopment() {
extensions = append(extensions, "livereload")
}
return strings.Join(extensions, ", ")
}
func RootPage(children ...h.Ren) h.Ren {
return h.Html(
h.HxExtension(Extensions()),
h.HxExtension(h.BaseExtensions()),
h.Head(
h.Link("/public/main.css", "stylesheet"),
h.Script("/public/htmgo.js"),

View file

@ -0,0 +1,54 @@
package partials
import (
"github.com/maddalax/htmgo/framework/h"
"strconv"
)
func CounterPartial(ctx *h.RequestContext) *h.Partial {
count, err := strconv.ParseInt(ctx.FormValue("count"), 10, 64)
if err != nil {
count = 0
}
count++
return h.SwapManyPartial(
ctx,
CounterForm(int(count)),
h.ElementIf(count > 10, SubmitButton("New record!")),
)
}
func CounterForm(count int) *h.Element {
return h.Form(
h.Class("flex flex-col gap-3 items-center"),
h.Id("counter-form"),
h.PostPartial(CounterPartial),
h.Input("text",
h.Class("hidden"),
h.Value(count),
h.Name("count"),
),
h.P(
h.AttributePairs(
"id", "counter",
"class", "text-xl",
"name", "count",
"text", "count",
),
h.TextF("Count: %d", count),
),
SubmitButton("Increment"),
)
}
func SubmitButton(text string) *h.Element {
return h.Button(
h.Class("bg-rose-400 hover:bg-rose-500 text-white font-bold py-2 px-4 rounded"),
h.Id("swap-text"),
h.Type("submit"),
h.Text(text),
)
}

View file

@ -0,0 +1,5 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["**/*.go", "**/*.js"],
plugins: [],
};