Get and set site name
This commit is contained in:
parent
beef4523c2
commit
7aa3c4fb3f
69
db.go
69
db.go
@ -1,6 +1,7 @@
|
|||||||
package peachy
|
package peachy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "embed"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@ -29,9 +30,11 @@ type DB struct {
|
|||||||
conn *sqlite.Conn
|
conn *sqlite.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Close() {
|
func (db DB) Close() {
|
||||||
|
if db.conn != nil {
|
||||||
db.conn.Close()
|
db.conn.Close()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var tableNameMatcher = match.MustCompile("(%s%s)")
|
var tableNameMatcher = match.MustCompile("(%s%s)")
|
||||||
|
|
||||||
@ -72,7 +75,7 @@ func setupConn(conn *sqlite.Conn) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Open(path string) (db *DB, err error) {
|
func Open(path string) (db DB, err error) {
|
||||||
var conn *sqlite.Conn
|
var conn *sqlite.Conn
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -84,11 +87,11 @@ func Open(path string) (db *DB, err error) {
|
|||||||
switch sqlite.ErrCode(err) {
|
switch sqlite.ErrCode(err) {
|
||||||
case sqlite.ResultOK:
|
case sqlite.ResultOK:
|
||||||
case sqlite.ResultCantOpen:
|
case sqlite.ResultCantOpen:
|
||||||
return nil, ErrFileNotExist
|
return db, ErrFileNotExist
|
||||||
case sqlite.ResultNotADB:
|
case sqlite.ResultNotADB:
|
||||||
return nil, ErrInvalidDB
|
return db, ErrInvalidDB
|
||||||
default:
|
default:
|
||||||
return nil, DBError{err}
|
return db, DBError{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
var goodAppID bool
|
var goodAppID bool
|
||||||
@ -98,16 +101,20 @@ func Open(path string) (db *DB, err error) {
|
|||||||
return nil
|
return nil
|
||||||
}})
|
}})
|
||||||
if !goodAppID {
|
if !goodAppID {
|
||||||
return nil, ErrInvalidDB
|
return db, ErrInvalidDB
|
||||||
}
|
}
|
||||||
err = setupConn(conn)
|
err = setupConn(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return db, err
|
||||||
}
|
}
|
||||||
return &DB{conn: conn}, nil
|
return DB{conn: conn}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Create(path string) (db *DB, err error) {
|
//go:embed metadata_schema.sql
|
||||||
|
var metadataSchema string
|
||||||
|
|
||||||
|
func Create(path string) (db DB, err error) {
|
||||||
|
fmt.Println("metadata schema:\n", metadataSchema)
|
||||||
var conn *sqlite.Conn
|
var conn *sqlite.Conn
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,23 +124,29 @@ func Create(path string) (db *DB, err error) {
|
|||||||
|
|
||||||
finfo, _ := os.Stat(path)
|
finfo, _ := os.Stat(path)
|
||||||
if finfo != nil {
|
if finfo != nil {
|
||||||
return nil, ErrFileExists
|
return db, ErrFileExists
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = sqlite.OpenConn(path, sqlite.OpenCreate|sqlite.OpenReadWrite|sqlite.OpenWAL)
|
conn, err = sqlite.OpenConn(path, sqlite.OpenCreate|sqlite.OpenReadWrite|sqlite.OpenWAL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not create database: %w", err)
|
return db, fmt.Errorf("could not create database: %w", err)
|
||||||
}
|
}
|
||||||
query := fmt.Sprintf("PRAGMA application_id=%d", AppID)
|
query := fmt.Sprintf("PRAGMA application_id=%d", AppID)
|
||||||
err = sqlitex.ExecuteTransient(conn, query, nil)
|
err = sqlitex.ExecuteTransient(conn, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, DBError{err}
|
return db, DBError{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = sqlitex.ExecuteScript(conn, metadataSchema, nil)
|
||||||
|
if err != nil {
|
||||||
|
return db, DBError{err}
|
||||||
|
}
|
||||||
|
|
||||||
err = setupConn(conn)
|
err = setupConn(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return db, err
|
||||||
}
|
}
|
||||||
return &DB{conn: conn}, nil
|
return DB{conn: conn}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func quoteName(name string) string {
|
func quoteName(name string) string {
|
||||||
@ -161,7 +174,7 @@ const addAbstractCompositeTypeQuery = `CREATE TABLE %s (
|
|||||||
%s_value_id INTEGER NOT NULL REFERENCES %s(id)
|
%s_value_id INTEGER NOT NULL REFERENCES %s(id)
|
||||||
);`
|
);`
|
||||||
|
|
||||||
func (db *DB) AddCompositeType(name string, kind CompositeKind) error {
|
func (db DB) AddCompositeType(name string, kind CompositeKind) error {
|
||||||
var kindStr string
|
var kindStr string
|
||||||
switch kind {
|
switch kind {
|
||||||
case Record:
|
case Record:
|
||||||
@ -201,7 +214,7 @@ FROM sqlite_schema
|
|||||||
WHERE parse_table_name(name, 'class') IN ('record-value', 'variant-value')
|
WHERE parse_table_name(name, 'class') IN ('record-value', 'variant-value')
|
||||||
ORDER BY parse_table_name(name, 'name') ASC;`
|
ORDER BY parse_table_name(name, 'name') ASC;`
|
||||||
|
|
||||||
func (db *DB) GetCompositeTypes() ([]CompositeType, error) {
|
func (db DB) GetCompositeTypes() ([]CompositeType, error) {
|
||||||
var results []CompositeType
|
var results []CompositeType
|
||||||
err := sqlitex.Execute(db.conn, getCompositeTypesQuery, &sqlitex.ExecOptions{
|
err := sqlitex.Execute(db.conn, getCompositeTypesQuery, &sqlitex.ExecOptions{
|
||||||
ResultFunc: func(stmt *sqlite.Stmt) error {
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
@ -220,3 +233,27 @@ func (db *DB) GetCompositeTypes() ([]CompositeType, error) {
|
|||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db DB) SiteName() (string, error) {
|
||||||
|
var name string
|
||||||
|
err := sqlitex.Execute(db.conn, "SELECT name FROM site_metadata", &sqlitex.ExecOptions{
|
||||||
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
|
name = stmt.ColumnText(0)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("SiteName: %w", err)
|
||||||
|
}
|
||||||
|
return name, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db DB) SetSiteName(name string) error {
|
||||||
|
err := sqlitex.Execute(db.conn, "UPDATE site_metadata SET name = ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []any{name},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("SetSiteName: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
35
db_test.go
35
db_test.go
@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.codemonkeysoftware.net/b/peachy-go"
|
"git.codemonkeysoftware.net/b/peachy-go"
|
||||||
|
"github.com/shoenig/test"
|
||||||
"github.com/shoenig/test/must"
|
"github.com/shoenig/test/must"
|
||||||
"zombiezen.com/go/sqlite"
|
"zombiezen.com/go/sqlite"
|
||||||
)
|
)
|
||||||
@ -14,12 +15,6 @@ func pending(t *testing.T) {
|
|||||||
t.Fatalf("test not implemented")
|
t.Fatalf("test not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeIfExists(db *peachy.DB) {
|
|
||||||
if db != nil {
|
|
||||||
db.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOpen(t *testing.T) {
|
func TestOpen(t *testing.T) {
|
||||||
t.Run("Open succeeds on DB created by Create", func(t *testing.T) {
|
t.Run("Open succeeds on DB created by Create", func(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
@ -29,8 +24,7 @@ func TestOpen(t *testing.T) {
|
|||||||
db.Close()
|
db.Close()
|
||||||
|
|
||||||
db, err = peachy.Open(dbPath)
|
db, err = peachy.Open(dbPath)
|
||||||
defer closeIfExists(db)
|
defer db.Close()
|
||||||
must.NotNil(t, db)
|
|
||||||
must.NoError(t, err)
|
must.NoError(t, err)
|
||||||
|
|
||||||
// TODO Make sure the DB works once it has any methods.
|
// TODO Make sure the DB works once it has any methods.
|
||||||
@ -43,16 +37,14 @@ func TestOpen(t *testing.T) {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
|
|
||||||
db, err := peachy.Open(dbPath)
|
db, err := peachy.Open(dbPath)
|
||||||
defer closeIfExists(db)
|
defer db.Close()
|
||||||
must.Nil(t, db)
|
|
||||||
must.ErrorIs(t, err, peachy.ErrInvalidDB)
|
must.ErrorIs(t, err, peachy.ErrInvalidDB)
|
||||||
})
|
})
|
||||||
t.Run("Open fails on nonexistent file", func(t *testing.T) {
|
t.Run("Open fails on nonexistent file", func(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
dbPath := filepath.Join(dir, "test.db")
|
dbPath := filepath.Join(dir, "test.db")
|
||||||
db, err := peachy.Open(dbPath)
|
db, err := peachy.Open(dbPath)
|
||||||
defer closeIfExists(db)
|
defer db.Close()
|
||||||
must.Nil(t, db)
|
|
||||||
must.ErrorIs(t, err, peachy.ErrFileNotExist)
|
must.ErrorIs(t, err, peachy.ErrFileNotExist)
|
||||||
must.FileNotExists(t, dbPath)
|
must.FileNotExists(t, dbPath)
|
||||||
})
|
})
|
||||||
@ -62,12 +54,27 @@ func TestOpen(t *testing.T) {
|
|||||||
must.NoError(t, err)
|
must.NoError(t, err)
|
||||||
|
|
||||||
db, err := peachy.Open(path)
|
db, err := peachy.Open(path)
|
||||||
defer closeIfExists(db)
|
defer db.Close()
|
||||||
must.Nil(t, db)
|
|
||||||
must.ErrorIs(t, err, peachy.ErrInvalidDB, must.Sprint(sqlite.ErrCode(err)))
|
must.ErrorIs(t, err, peachy.ErrInvalidDB, must.Sprint(sqlite.ErrCode(err)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSiteName(t *testing.T) {
|
||||||
|
db, err := peachy.Create(":memory:")
|
||||||
|
must.NoError(t, err)
|
||||||
|
|
||||||
|
initial, err := db.SiteName()
|
||||||
|
test.NoError(t, err)
|
||||||
|
test.EqOp(t, "", initial)
|
||||||
|
|
||||||
|
const expected = "aoeuhtns"
|
||||||
|
test.NoError(t, db.SetSiteName(expected))
|
||||||
|
|
||||||
|
actual, err := db.SiteName()
|
||||||
|
test.NoError(t, err)
|
||||||
|
test.EqOp(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCompositeTypes(t *testing.T) {
|
func TestCompositeTypes(t *testing.T) {
|
||||||
db, err := peachy.Create(":memory:")
|
db, err := peachy.Create(":memory:")
|
||||||
must.NoError(t, err)
|
must.NoError(t, err)
|
||||||
|
5
desktop/fields/fields.go
Normal file
5
desktop/fields/fields.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package fields
|
||||||
|
|
||||||
|
const (
|
||||||
|
SiteName = "sitename"
|
||||||
|
)
|
@ -19,13 +19,11 @@ var assets embed.FS
|
|||||||
const ListenPort = "9245"
|
const ListenPort = "9245"
|
||||||
const WindowNameMain = "mainwindow"
|
const WindowNameMain = "mainwindow"
|
||||||
|
|
||||||
var globalDB *peachy.DB
|
var globalDB peachy.DB
|
||||||
|
|
||||||
func closeDB() {
|
func closeDB() {
|
||||||
if globalDB != nil {
|
|
||||||
globalDB.Close()
|
globalDB.Close()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// SetURl is a workaround for WebviewWindow.SetURL not adding the base URL
|
// SetURl is a workaround for WebviewWindow.SetURL not adding the base URL
|
||||||
// to relative URLs.
|
// to relative URLs.
|
||||||
@ -36,10 +34,10 @@ func SetURL(win application.Window, path string) application.Window {
|
|||||||
return win.SetURL(u)
|
return win.SetURL(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDB(db *peachy.DB) error {
|
func setDB(db peachy.DB) error {
|
||||||
slog.Info("opened DB, setting URL")
|
slog.Info("opened DB, setting URL")
|
||||||
globalDB = db
|
globalDB = db
|
||||||
SetURL(application.Get().GetWindowByName(WindowNameMain), "/").SetTitle("you opened a DB")
|
SetURL(application.Get().GetWindowByName(WindowNameMain), "/site")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,13 +71,12 @@ func dbFileFilter() []application.FileFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
r := routes.NewChiRouter(ListenPort)
|
r := routes.NewChiRouter(ListenPort, &globalDB)
|
||||||
|
|
||||||
// Create the application
|
|
||||||
app := application.New(application.Options{
|
app := application.New(application.Options{
|
||||||
Name: "Peachy",
|
Name: "Peachy",
|
||||||
Description: "A demo of using raw HTML & CSS", // Description of the application
|
Description: "A desktop CMS for static sites",
|
||||||
Assets: application.AssetOptions{ // Assets to embed (our static files)
|
Assets: application.AssetOptions{
|
||||||
Handler: application.AssetFileServerFS(assets),
|
Handler: application.AssetFileServerFS(assets),
|
||||||
Middleware: func(next http.Handler) http.Handler {
|
Middleware: func(next http.Handler) http.Handler {
|
||||||
r.NotFound(next.ServeHTTP)
|
r.NotFound(next.ServeHTTP)
|
||||||
@ -94,14 +91,13 @@ func main() {
|
|||||||
closeDB()
|
closeDB()
|
||||||
})
|
})
|
||||||
|
|
||||||
// V3 introduces multiple windows, so we need to create a window
|
|
||||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||||
Name: WindowNameMain,
|
Name: WindowNameMain,
|
||||||
Title: "Your Project",
|
Title: "Your Project",
|
||||||
Mac: application.MacWindow{
|
Mac: application.MacWindow{
|
||||||
Backdrop: application.MacBackdropTranslucent,
|
Backdrop: application.MacBackdropTranslucent,
|
||||||
},
|
},
|
||||||
URL: "/splash", // URL to load when the window is created
|
URL: "/", // URL to load when the window is created
|
||||||
Width: 1080, // Width of the window
|
Width: 1080, // Width of the window
|
||||||
Height: 720, // Height of the window
|
Height: 720, // Height of the window
|
||||||
Centered: false,
|
Centered: false,
|
||||||
|
@ -4,40 +4,37 @@ import (
|
|||||||
h "git.codemonkeysoftware.net/b/hatmill"
|
h "git.codemonkeysoftware.net/b/hatmill"
|
||||||
a "git.codemonkeysoftware.net/b/hatmill/attribute"
|
a "git.codemonkeysoftware.net/b/hatmill/attribute"
|
||||||
e "git.codemonkeysoftware.net/b/hatmill/element"
|
e "git.codemonkeysoftware.net/b/hatmill/element"
|
||||||
|
"git.codemonkeysoftware.net/b/peachy-go"
|
||||||
|
"git.codemonkeysoftware.net/b/peachy-go/desktop/fields"
|
||||||
|
"git.codemonkeysoftware.net/b/peachy-go/hx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func hxGet(url string) h.Attrib {
|
func HomePage(db *peachy.DB) (func() h.ParentElement, error) {
|
||||||
return h.Attrib{
|
siteName, err := db.SiteName()
|
||||||
Key: "hx-get",
|
if err != nil {
|
||||||
Value: a.String(url),
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
return func() h.ParentElement {
|
||||||
|
|
||||||
func hxTrigger(event string) h.Attrib {
|
|
||||||
return h.Attrib{
|
|
||||||
Key: "hx-trigger",
|
|
||||||
Value: a.String(event),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hxTarget(target string) h.Attrib {
|
|
||||||
return h.Attrib{
|
|
||||||
Key: "hx-target",
|
|
||||||
Value: a.String(target),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HomePage() h.ParentElement {
|
|
||||||
return e.Div()(
|
return e.Div()(
|
||||||
e.H1()(h.Text("[untitled]")),
|
e.Input(
|
||||||
|
a.Type("text"),
|
||||||
|
a.Value(siteName),
|
||||||
|
a.Placeholder("site name"),
|
||||||
|
a.Name(fields.SiteName),
|
||||||
|
hx.Trigger("change"),
|
||||||
|
hx.Target("this"),
|
||||||
|
hx.Patch("/site"),
|
||||||
|
hx.Swap(hx.OuterHTML),
|
||||||
|
),
|
||||||
e.Button(
|
e.Button(
|
||||||
a.Type("button"),
|
a.Type("button"),
|
||||||
hxGet("/hello"),
|
hx.Get("/hello"),
|
||||||
hxTrigger("click"),
|
hx.Trigger("click"),
|
||||||
hxTarget("#hello"),
|
hx.Target("#hello"),
|
||||||
)(h.Text("Click Here!")),
|
)(h.Text("Click Here!")),
|
||||||
e.Div(a.Id("hello"))(),
|
e.Div(a.Id("hello"))(),
|
||||||
)
|
)
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Splash() h.Term {
|
func Splash() h.Term {
|
||||||
|
@ -4,7 +4,9 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.codemonkeysoftware.net/b/peachy-go"
|
||||||
"git.codemonkeysoftware.net/b/peachy-go/desktop/components"
|
"git.codemonkeysoftware.net/b/peachy-go/desktop/components"
|
||||||
|
"git.codemonkeysoftware.net/b/peachy-go/desktop/fields"
|
||||||
"git.codemonkeysoftware.net/b/peachy-go/desktop/pages"
|
"git.codemonkeysoftware.net/b/peachy-go/desktop/pages"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
@ -14,7 +16,7 @@ import (
|
|||||||
/*
|
/*
|
||||||
Create a new chi router, configure it and return it.
|
Create a new chi router, configure it and return it.
|
||||||
*/
|
*/
|
||||||
func NewChiRouter(port string) *chi.Mux {
|
func NewChiRouter(port string, db *peachy.DB) *chi.Mux {
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
@ -40,14 +42,31 @@ func NewChiRouter(port string) *chi.Mux {
|
|||||||
|
|
||||||
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
||||||
|
|
||||||
r.Get("/splash", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
slog.Info("we splashin")
|
|
||||||
HXRender(w, r, pages.Splash)
|
HXRender(w, r, pages.Splash)
|
||||||
})
|
})
|
||||||
|
|
||||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/site", func(w http.ResponseWriter, r *http.Request) {
|
||||||
slog.Info("we homies")
|
page, err := pages.HomePage(db)
|
||||||
HXRender(w, r, pages.HomePage)
|
if err != nil {
|
||||||
|
logger.Error("internal error", "path", r.URL.Path, "error", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
HXRender(w, r, page)
|
||||||
|
})
|
||||||
|
|
||||||
|
r.Patch("/site", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.ParseForm()
|
||||||
|
if r.Form.Has(fields.SiteName) {
|
||||||
|
err := db.SetSiteName(r.Form.Get(fields.SiteName))
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("internal error", "path", r.URL.Path, "error", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
})
|
})
|
||||||
|
|
||||||
r.Get("/hello", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/hello", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
12
go.mod
12
go.mod
@ -9,21 +9,21 @@ require (
|
|||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||||
github.com/shoenig/test v1.11.0
|
github.com/shoenig/test v1.11.0
|
||||||
pgregory.net/rapid v1.1.0
|
pgregory.net/rapid v1.1.0
|
||||||
zombiezen.com/go/sqlite v1.3.0
|
zombiezen.com/go/sqlite v1.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
golang.org/x/sys v0.21.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
modernc.org/libc v1.41.0 // indirect
|
modernc.org/libc v1.55.3 // indirect
|
||||||
modernc.org/mathutil v1.6.0 // indirect
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
modernc.org/memory v1.7.2 // indirect
|
modernc.org/memory v1.8.0 // indirect
|
||||||
modernc.org/sqlite v1.29.1 // indirect
|
modernc.org/sqlite v1.33.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace git.codemonkeysoftware.net/b/gigaparsec v0.0.0-20240917174243-4fa3c2a46611 => ../gigaparsec
|
replace git.codemonkeysoftware.net/b/gigaparsec v0.0.0-20240917174243-4fa3c2a46611 => ../gigaparsec
|
||||||
|
40
go.sum
40
go.sum
@ -52,8 +52,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
|
|||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||||
@ -169,8 +169,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
@ -204,15 +204,31 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
|
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
|
||||||
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
|
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
|
||||||
|
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||||
|
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||||
|
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||||
|
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||||
|
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||||
|
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||||
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||||
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||||
modernc.org/sqlite v1.29.1 h1:19GY2qvWB4VPw0HppFlZCPAbmxFU41r+qjKZQdQ1ryA=
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
modernc.org/sqlite v1.29.1/go.mod h1:hG41jCYxOAOoO6BRK66AdRlmOcDzXf7qnwlwjUIOqa0=
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||||
|
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||||
|
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
|
||||||
|
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
|
||||||
|
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||||
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
|
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
|
||||||
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
||||||
zombiezen.com/go/sqlite v1.3.0 h1:98g1gnCm+CNz6AuQHu0gqyw7gR2WU3O3PJufDOStpUs=
|
zombiezen.com/go/sqlite v1.4.0 h1:N1s3RIljwtp4541Y8rM880qgGIgq3fTD2yks1xftnKU=
|
||||||
zombiezen.com/go/sqlite v1.3.0/go.mod h1:yRl27//s/9aXU3RWs8uFQwjkTG9gYNGEls6+6SvrclY=
|
zombiezen.com/go/sqlite v1.4.0/go.mod h1:0w9F1DN9IZj9AcLS9YDKMboubCACkwYCGkzoy3eG5ik=
|
||||||
|
54
hx/hx.go
Normal file
54
hx/hx.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package hx
|
||||||
|
|
||||||
|
import (
|
||||||
|
h "git.codemonkeysoftware.net/b/hatmill"
|
||||||
|
a "git.codemonkeysoftware.net/b/hatmill/attribute"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Get(url string) h.Attrib {
|
||||||
|
return h.Attrib{
|
||||||
|
Key: "hx-get",
|
||||||
|
Value: a.String(url),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Patch(url string) h.Attrib {
|
||||||
|
return h.Attrib{
|
||||||
|
Key: "hx-patch",
|
||||||
|
Value: a.String(url),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Trigger(event string) h.Attrib {
|
||||||
|
return h.Attrib{
|
||||||
|
Key: "hx-trigger",
|
||||||
|
Value: a.String(event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Target(target string) h.Attrib {
|
||||||
|
return h.Attrib{
|
||||||
|
Key: "hx-target",
|
||||||
|
Value: a.String(target),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SwapKind string
|
||||||
|
|
||||||
|
const (
|
||||||
|
InnerHTML SwapKind = "innerHTML"
|
||||||
|
OuterHTML SwapKind = "outerHTML"
|
||||||
|
AfterBegin SwapKind = "afterbegin"
|
||||||
|
BeforeBegin SwapKind = "beforebegin"
|
||||||
|
BeforeEnd SwapKind = "beforeend"
|
||||||
|
AfterEnd SwapKind = "afterend"
|
||||||
|
Delete SwapKind = "delete"
|
||||||
|
None SwapKind = "none"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Swap(kind SwapKind) h.Attrib {
|
||||||
|
return h.Attrib{
|
||||||
|
Key: "hx-target",
|
||||||
|
Value: a.String(kind),
|
||||||
|
}
|
||||||
|
}
|
4
metadata_schema.sql
Normal file
4
metadata_schema.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
CREATE TABLE site_metadata (
|
||||||
|
name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
INSERT INTO site_metadata(name) VALUES ('');
|
Loading…
Reference in New Issue
Block a user