diff --git a/Makefile b/Makefile
index 1e92b18..e067824 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,10 @@
.PHONY: build
build:
- go build bin/shelves.go
+ go build cmd/shelves/main.go
run:
- go run bin/shelves.go
+ go run cmd/shelves/main.go
watch:
fd | entr -cr make run
diff --git a/bin/shelves.go b/bin/shelves.go
deleted file mode 100644
index 3ec7a14..0000000
--- a/bin/shelves.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package main
-
-import (
- "fmt"
- "log"
- "net/http"
-
- _ "github.com/mattn/go-sqlite3"
-
- "shelves/db"
- "shelves/httpx"
- "shelves/routes"
-)
-
-func main() {
- db, migrateResult, err := db.Open("./shelves.db")
- if err != nil {
- log.Fatalf("Failed to open DB: %v", err)
- }
- if migrateResult.MigrationError != nil {
- log.Printf("An error was encountered while upgrading the database schema. You are on version %v, but the latest is %v. The error was: %v", migrateResult.SchemaVerNew, migrateResult.SchemaVerLatest, migrateResult.MigrationError)
- }
- schemaNeedsUpdating := migrateResult.SchemaVerNew != migrateResult.SchemaVerLatest
- if schemaNeedsUpdating {
- log.Printf("Your database schema needs to be updated. The application will continue to run, but you may encounter errors.\n")
- }
- _ = db
-
- routes := routes.Routes()
- fmt.Println("Listening on localhost:8999")
- http.ListenAndServe("localhost:8999", httpx.Log(httpx.WithCtx(db, routes)))
-}
diff --git a/embeds.go b/embeds.go
new file mode 100644
index 0000000..4dff149
--- /dev/null
+++ b/embeds.go
@@ -0,0 +1,28 @@
+package shelves
+
+import (
+ "embed"
+ "fmt"
+ "io/fs"
+)
+
+//go:embed frontend/*
+var fe embed.FS
+
+var Frontend, _ = fs.Sub(fe, "frontend")
+
+//go:embed internal/templates/views/*.tmpl.* internal/templates/components/*.tmpl.*
+var templates embed.FS
+var Templates, _ = fs.Sub(templates, "internal/templates")
+
+func printEmbeddedFiles(efs fs.FS) error {
+ return fs.WalkDir(efs, ".", func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ if !d.IsDir() {
+ fmt.Println(path)
+ }
+ return nil
+ })
+}
diff --git a/frontend.go b/frontend.go
deleted file mode 100644
index 2f7c500..0000000
--- a/frontend.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package shelves
-
-import (
- "embed"
- "io/fs"
-)
-
-//go:embed frontend/*
-var fe embed.FS
-
-var Frontend, _ = fs.Sub(fe, "frontend")
diff --git a/go.mod b/go.mod
index fba7ffa..1a400b7 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module shelves
+module git.soup.land/soup/shelves
go 1.23
diff --git a/auth/auth.go b/internal/auth/auth.go
similarity index 100%
rename from auth/auth.go
rename to internal/auth/auth.go
diff --git a/db/db.go b/internal/db/db.go
similarity index 100%
rename from db/db.go
rename to internal/db/db.go
diff --git a/errorsx/errorsx.go b/internal/errorsx/errorsx.go
similarity index 100%
rename from errorsx/errorsx.go
rename to internal/errorsx/errorsx.go
diff --git a/forms/forms.go b/internal/forms/forms.go
similarity index 100%
rename from forms/forms.go
rename to internal/forms/forms.go
diff --git a/httpx/httpx.go b/internal/httpx/httpx.go
similarity index 90%
rename from httpx/httpx.go
rename to internal/httpx/httpx.go
index e275cd2..a829a65 100644
--- a/httpx/httpx.go
+++ b/internal/httpx/httpx.go
@@ -1,11 +1,11 @@
package httpx
import (
+ "git.soup.land/soup/shelves/internal/errorsx"
+ "git.soup.land/soup/shelves/internal/urls"
"log"
"net/http"
"net/url"
- "shelves/errorsx"
- "shelves/urls"
)
func SeeOther(w http.ResponseWriter, location string) {
diff --git a/httpx/hx.go b/internal/httpx/hx.go
similarity index 100%
rename from httpx/hx.go
rename to internal/httpx/hx.go
diff --git a/httpx/middleware.go b/internal/httpx/middleware.go
similarity index 97%
rename from httpx/middleware.go
rename to internal/httpx/middleware.go
index 1fe7b63..7e6ae34 100644
--- a/httpx/middleware.go
+++ b/internal/httpx/middleware.go
@@ -3,9 +3,9 @@ package httpx
import (
"context"
"database/sql"
+ "git.soup.land/soup/shelves/internal/auth"
"log"
"net/http"
- "shelves/auth"
"time"
)
diff --git a/internal/routes/home.go b/internal/routes/home.go
new file mode 100644
index 0000000..3c5d652
--- /dev/null
+++ b/internal/routes/home.go
@@ -0,0 +1,26 @@
+package routes
+
+import (
+ "net/http"
+
+ "git.soup.land/soup/shelves/internal/httpx"
+ "git.soup.land/soup/shelves/internal/templates"
+ "git.soup.land/soup/shelves/internal/templates/components"
+)
+
+type homeTemplate struct {
+ components.Page
+}
+
+var homeTmpl = templates.MustParseEmbed("views/home.tmpl.html")
+
+func HomeGet(w http.ResponseWriter, req *http.Request) {
+ ctx := httpx.GetCtx(req)
+
+ h := components.Page{
+ Title: "Home",
+ SessionInfo: ctx.SessionInfo,
+ }.HTML()
+
+ html(w, h)
+}
diff --git a/routes/login.go b/internal/routes/login.go
similarity index 79%
rename from routes/login.go
rename to internal/routes/login.go
index 32ab6d8..f762736 100644
--- a/routes/login.go
+++ b/internal/routes/login.go
@@ -5,11 +5,12 @@ import (
"html/template"
"net/http"
"net/url"
- "shelves/auth"
- "shelves/errorsx"
- "shelves/forms"
- "shelves/httpx"
- "shelves/templates"
+
+ "git.soup.land/soup/shelves/internal/auth"
+ "git.soup.land/soup/shelves/internal/errorsx"
+ "git.soup.land/soup/shelves/internal/forms"
+ "git.soup.land/soup/shelves/internal/httpx"
+ "git.soup.land/soup/shelves/internal/templates/components"
)
type loginForm struct {
@@ -21,26 +22,32 @@ type loginFormErrors struct {
password error
}
-func loginRenderView(f loginForm, e loginFormErrors) template.HTML {
- body := templates.Form{
+func loginRenderView(f loginForm, e loginFormErrors, ctx httpx.Ctx) template.HTML {
+ formHtml := components.Form{
Action: "/login",
- Fields: []templates.Field{
- templates.Field{
+ Fields: []components.Field{
+ components.Field{
Label: "Password",
Type: "password",
Placeholder: "Password",
Name: "password",
Error: errorsx.String(e.password),
},
- templates.Field{
+ components.Field{
Type: "hidden",
Name: "redirectTo",
Value: f.redirectTo,
},
},
+ }.HTML()
+
+ page := components.Page{
+ Title: "Login",
+ SessionInfo: ctx.SessionInfo,
+ Body: formHtml,
}
- return templates.Page{Title: "Login", Body: body.HTML()}.HTML()
+ return page.HTML()
}
func getRedirectTo(r *http.Request) string {
@@ -66,7 +73,7 @@ func LoginGet(w http.ResponseWriter, r *http.Request) {
return
}
- html(w, loginRenderView(loginForm{redirectTo: redirectTo}, loginFormErrors{}))
+ html(w, loginRenderView(loginForm{redirectTo: redirectTo}, loginFormErrors{}, ctx))
}
func loginParseForm(f *loginForm, e *loginFormErrors, vs url.Values, v *forms.Validator) {
@@ -84,7 +91,7 @@ func LoginPost(w http.ResponseWriter, r *http.Request) {
})
if failed {
httpx.BadRequest(w)
- html(w, loginRenderView(form, errs))
+ html(w, loginRenderView(form, errs, ctx))
return
}
@@ -102,7 +109,7 @@ func LoginPost(w http.ResponseWriter, r *http.Request) {
httpx.BadRequest(w)
errs.password = errors.New("Incorrect password")
- html(w, loginRenderView(form, errs))
+ html(w, loginRenderView(form, errs, ctx))
return
}
diff --git a/routes/routes.go b/internal/routes/routes.go
similarity index 95%
rename from routes/routes.go
rename to internal/routes/routes.go
index c824b6e..41cc9fd 100644
--- a/routes/routes.go
+++ b/internal/routes/routes.go
@@ -1,13 +1,12 @@
package routes
import (
+ "git.soup.land/soup/shelves"
+ "git.soup.land/soup/shelves/internal/httpx"
"html/template"
"net/http"
- "shelves/httpx"
"strings"
"time"
-
- "shelves"
)
func html(w http.ResponseWriter, s template.HTML) {
diff --git a/routes/settings.go b/internal/routes/settings.go
similarity index 87%
rename from routes/settings.go
rename to internal/routes/settings.go
index a53f3a7..cf2c1e1 100644
--- a/routes/settings.go
+++ b/internal/routes/settings.go
@@ -6,41 +6,42 @@ import (
"html/template"
"net/http"
"net/url"
- "shelves/auth"
- "shelves/errorsx"
- "shelves/forms"
- "shelves/httpx"
- "shelves/templates"
+
+ "git.soup.land/soup/shelves/internal/auth"
+ "git.soup.land/soup/shelves/internal/errorsx"
+ "git.soup.land/soup/shelves/internal/forms"
+ "git.soup.land/soup/shelves/internal/httpx"
+ "git.soup.land/soup/shelves/internal/templates/components"
)
func settingsRenderView(f settingsForm, e settingsFormErrors) template.HTML {
- body := templates.Form{
+ body := components.Form{
Action: "/settings",
- Fields: []templates.Field{
- templates.Field{
+ Fields: []components.Field{
+ components.Field{
Label: "Display name",
Name: "displayName",
Placeholder: "Jane Doe",
Value: f.displayName,
Error: errorsx.String(e.displayName),
},
- templates.Field{
+ components.Field{
Label: "Password",
Type: "password",
Placeholder: "Password",
Name: "password",
Error: errorsx.String(e.password),
},
- templates.Field{
+ components.Field{
Label: "Confirm password",
Placeholder: "Confirm Password",
Type: "password",
Name: "passwordConfirmation",
},
},
- }
+ }.HTML()
- return templates.PageBase{Title: "Set up", Body: body.HTML()}.HTML()
+ return components.Page{Title: "Set up", Body: body}.HTML()
}
func queryGetOwnerSettings(db *sql.DB) (settingsForm, error) {
diff --git a/internal/templates/components/component.go b/internal/templates/components/component.go
new file mode 100644
index 0000000..bc820f5
--- /dev/null
+++ b/internal/templates/components/component.go
@@ -0,0 +1 @@
+package components
diff --git a/templates/form.go b/internal/templates/components/form.go
similarity index 73%
rename from templates/form.go
rename to internal/templates/components/form.go
index 34c47ed..41b9a7b 100644
--- a/templates/form.go
+++ b/internal/templates/components/form.go
@@ -1,6 +1,7 @@
-package templates
+package components
import (
+ "git.soup.land/soup/shelves/internal/templates"
"html/template"
)
@@ -28,6 +29,8 @@ type Form struct {
Fields []Field
}
+var formTmpl = templates.MustParseEmbed("components/form.tmpl.html")
+
func (f Form) HTML() template.HTML {
if f.Method == "" {
f.Method = "POST"
@@ -37,5 +40,5 @@ func (f Form) HTML() template.HTML {
f.Fields[i].init()
}
- return Tmpls.HTML("form.tmpl.html", f)
+ return templates.HTML(formTmpl, "form", f)
}
diff --git a/internal/templates/components/form.tmpl.html b/internal/templates/components/form.tmpl.html
new file mode 100644
index 0000000..2576d30
--- /dev/null
+++ b/internal/templates/components/form.tmpl.html
@@ -0,0 +1,5 @@
+{{define "field"}}
+{{end}}
+
+{{define "form"}}
+{{end}}
diff --git a/internal/templates/components/page.go b/internal/templates/components/page.go
new file mode 100644
index 0000000..423152c
--- /dev/null
+++ b/internal/templates/components/page.go
@@ -0,0 +1,23 @@
+package components
+
+import (
+ "git.soup.land/soup/shelves/internal/auth"
+ "git.soup.land/soup/shelves/internal/templates"
+ "html/template"
+)
+
+type Page struct {
+ SessionInfo auth.SessionInfo
+
+ Title string
+ Head template.HTML
+ Body template.HTML
+ BodyBefore template.HTML
+ BodyAfter template.HTML
+}
+
+var pageTmpl = templates.MustParseEmbed("components/page.tmpl.html")
+
+func (p Page) HTML() template.HTML {
+ return templates.HTML(pageTmpl, "page", p)
+}
diff --git a/templates/tmpls/page.tmpl.html b/internal/templates/components/page.tmpl.html
similarity index 100%
rename from templates/tmpls/page.tmpl.html
rename to internal/templates/components/page.tmpl.html
diff --git a/internal/templates/templates.go b/internal/templates/templates.go
new file mode 100644
index 0000000..a74b8a8
--- /dev/null
+++ b/internal/templates/templates.go
@@ -0,0 +1,22 @@
+package templates
+
+import (
+ "git.soup.land/soup/shelves"
+ "git.soup.land/soup/shelves/internal/errorsx"
+ "html/template"
+ "strings"
+)
+
+var files = shelves.Templates
+
+func MustParseEmbed(path string) *template.Template {
+ return template.Must(template.ParseFS(files, path))
+}
+
+func HTML(t *template.Template, name string, data any) template.HTML {
+ out := strings.Builder{}
+ err := t.ExecuteTemplate(&out, name, data)
+ out.WriteString(errorsx.String(err))
+
+ return template.HTML(out.String())
+}
diff --git a/templates/tmpls/form.tmpl.html b/internal/templates/tmpls/form.tmpl.html
similarity index 100%
rename from templates/tmpls/form.tmpl.html
rename to internal/templates/tmpls/form.tmpl.html
diff --git a/internal/templates/views/home.go b/internal/templates/views/home.go
new file mode 100644
index 0000000..e29e57d
--- /dev/null
+++ b/internal/templates/views/home.go
@@ -0,0 +1 @@
+package views
diff --git a/internal/templates/views/home.tmpl.html b/internal/templates/views/home.tmpl.html
new file mode 100644
index 0000000..3bf6544
--- /dev/null
+++ b/internal/templates/views/home.tmpl.html
@@ -0,0 +1,15 @@
+{{define "Title"}}Home{{end}}
+
+{{define "Body"}}
+
+
+
+{{end}}
+
+{{template "page.tmpl.html" .}}
diff --git a/internal/templates/views/login.tmpl.html b/internal/templates/views/login.tmpl.html
new file mode 100644
index 0000000..00a0edd
--- /dev/null
+++ b/internal/templates/views/login.tmpl.html
@@ -0,0 +1,6 @@
+{{template "page.tmpl.html" .}}
+
+{{define "Title"}}Login{{end}}
+
+{{define "Body"}}
+{{end}}
diff --git a/urls/urls.go b/internal/urls/urls.go
similarity index 100%
rename from urls/urls.go
rename to internal/urls/urls.go
diff --git a/routes/home.go b/routes/home.go
deleted file mode 100644
index 5cd01ac..0000000
--- a/routes/home.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package routes
-
-import (
- "net/http"
- "shelves/httpx"
- "shelves/templates"
-)
-
-type homeTemplate struct {
- templates.Page
-}
-
-func HomeGet(w http.ResponseWriter, req *http.Request) {
- ctx := httpx.GetCtx(req)
- tmpl := homeTemplate{
- Page: templates.Page{SessionInfo: ctx.SessionInfo},
- }
-
- html(w, templates.Tmpls.HTML("home.tmpl.html", tmpl))
-}
diff --git a/templates/page.go b/templates/page.go
deleted file mode 100644
index 72a0f05..0000000
--- a/templates/page.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package templates
-
-import (
- "html/template"
- "shelves/auth"
-)
-
-type PageBase struct {
- Title string
- Head template.HTML
- Body template.HTML
- BodyBefore template.HTML
- BodyAfter template.HTML
-}
-
-func (pb PageBase) HTML() template.HTML {
- return Tmpls.HTML("page_base.tmpl.html", pb)
-}
-
-type Page struct {
- SessionInfo auth.SessionInfo
-
- Title string
- Head template.HTML
- Body template.HTML
- BodyBefore template.HTML
- BodyAfter template.HTML
-}
-
-func (p Page) HTML() template.HTML {
- return Tmpls.HTML("page.tmpl.html", p)
-}
diff --git a/templates/templates.go b/templates/templates.go
deleted file mode 100644
index c909a69..0000000
--- a/templates/templates.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package templates
-
-import (
- "embed"
- "fmt"
- "html/template"
- "strings"
-)
-
-//go:embed tmpls/*
-var files embed.FS
-
-type Template struct {
- *template.Template
-}
-
-var Tmpls = Template{template.Must(template.ParseFS(files, "tmpls/*"))}
-
-func (tmpl Template) HTML(name string, data any) template.HTML {
- writer := &strings.Builder{}
- err := tmpl.ExecuteTemplate(writer, name, data)
-
- if err != nil {
- fmt.Fprint(writer, err)
- }
-
- return template.HTML(writer.String())
-}
diff --git a/templates/tmpls/home.tmpl.html b/templates/tmpls/home.tmpl.html
deleted file mode 100644
index 39014e4..0000000
--- a/templates/tmpls/home.tmpl.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{{define "Title"}}Home{{end}}
-
-{{template "page.tmpl.html" .}}
diff --git a/templates/tmpls/page_base.tmpl.html b/templates/tmpls/page_base.tmpl.html
deleted file mode 100644
index e69de29..0000000