remove sandbox, move todo-app to index page
This commit is contained in:
parent
9e44fb5d52
commit
94f7d53a0d
30 changed files with 29 additions and 1110 deletions
|
|
@ -15,6 +15,14 @@ func PushUrlHeader(url string) *Headers {
|
||||||
return NewHeaders(hx.PushUrlHeader, url)
|
return NewHeaders(hx.PushUrlHeader, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PushQsHeader(ctx *RequestContext, qs *Qs) *Headers {
|
||||||
|
parsed, err := url.Parse(ctx.currentBrowserUrl)
|
||||||
|
if err != nil {
|
||||||
|
return NewHeaders()
|
||||||
|
}
|
||||||
|
return NewHeaders(hx.ReplaceUrlHeader, SetQueryParams(parsed.Path, qs))
|
||||||
|
}
|
||||||
|
|
||||||
func CombineHeaders(headers ...*Headers) *Headers {
|
func CombineHeaders(headers ...*Headers) *Headers {
|
||||||
m := make(Headers)
|
m := make(Headers)
|
||||||
for _, h := range headers {
|
for _, h := range headers {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package h
|
package h
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/maddalax/htmgo/framework/hx"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -49,14 +48,6 @@ func (q *Qs) ToString() string {
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func PushQsHeader(ctx *RequestContext, qs *Qs) *Headers {
|
|
||||||
parsed, err := url.Parse(ctx.currentBrowserUrl)
|
|
||||||
if err != nil {
|
|
||||||
return NewHeaders()
|
|
||||||
}
|
|
||||||
return NewHeaders(hx.ReplaceUrlHeader, SetQueryParams(parsed.Path, qs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetQueryParam(ctx *RequestContext, key string) string {
|
func GetQueryParam(ctx *RequestContext, key string) string {
|
||||||
value := ctx.QueryParam(key)
|
value := ctx.QueryParam(key)
|
||||||
if value == "" {
|
if value == "" {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
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%)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [],
|
|
||||||
};
|
|
||||||
Binary file not shown.
|
|
@ -1,136 +0,0 @@
|
||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
once sync.Once
|
|
||||||
rdb *redis.Client
|
|
||||||
)
|
|
||||||
|
|
||||||
func Connect() *redis.Client {
|
|
||||||
once.Do(func() {
|
|
||||||
var ctx = context.Background()
|
|
||||||
var err error
|
|
||||||
rdb = redis.NewClient(&redis.Options{
|
|
||||||
Addr: "localhost:6379",
|
|
||||||
Password: "", // no password set
|
|
||||||
DB: 0, // use default DB
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := rdb.Ping(ctx)
|
|
||||||
|
|
||||||
if cmd.Err() != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return rdb
|
|
||||||
}
|
|
||||||
|
|
||||||
func Incr(key string) int64 {
|
|
||||||
db := Connect()
|
|
||||||
result := db.Incr(context.Background(), key)
|
|
||||||
return result.Val()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Set[T any](key string, value T) error {
|
|
||||||
db := Connect()
|
|
||||||
serialized, err := json.Marshal(value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
result := db.Set(context.Background(), key, serialized, time.Duration(0))
|
|
||||||
return result.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
func HSet[T any](set string, key string, value T) error {
|
|
||||||
db := Connect()
|
|
||||||
serialized, err := json.Marshal(value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
result := db.HSet(context.Background(), set, key, serialized)
|
|
||||||
return result.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
func HIncr(set string, key string) int64 {
|
|
||||||
db := Connect()
|
|
||||||
result := db.HIncrBy(context.Background(), set, key, 1)
|
|
||||||
return result.Val()
|
|
||||||
}
|
|
||||||
|
|
||||||
func HGet[T any](set string, key string) *T {
|
|
||||||
db := Connect()
|
|
||||||
val, err := db.HGet(context.Background(), set, key).Result()
|
|
||||||
if err != nil || val == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := new(T)
|
|
||||||
err = json.Unmarshal([]byte(val), result)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetOrSet[T any](key string, cb func() T) (*T, error) {
|
|
||||||
db := Connect()
|
|
||||||
val, err := db.Get(context.Background(), key).Result()
|
|
||||||
if err == nil {
|
|
||||||
result := new(T)
|
|
||||||
err = json.Unmarshal([]byte(val), result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
value := cb()
|
|
||||||
err = Set(key, value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Get[T any](key string) (*T, error) {
|
|
||||||
db := Connect()
|
|
||||||
val, err := db.Get(context.Background(), key).Result()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := new(T)
|
|
||||||
err = json.Unmarshal([]byte(val), result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func HList[T any](key string) ([]*T, error) {
|
|
||||||
db := Connect()
|
|
||||||
val, err := db.HGetAll(context.Background(), key).Result()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := make([]*T, len(val))
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
for _, t := range val {
|
|
||||||
item := new(T)
|
|
||||||
err = json.Unmarshal([]byte(t), item)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result[count] = item
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
package patient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"starter-template/database"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Patient struct {
|
|
||||||
Name string
|
|
||||||
ReasonForVisit string
|
|
||||||
AppointmentDate time.Time
|
|
||||||
LocationName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
ctx echo.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(ctx echo.Context) *Service {
|
|
||||||
return &Service{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreatePatientRequest struct {
|
|
||||||
Name string
|
|
||||||
ReasonForVisit string
|
|
||||||
LocationName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Service) Create(request CreatePatientRequest) error {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
database.HSet("patients", uuid.New().String(), Patient{
|
|
||||||
Name: request.Name,
|
|
||||||
ReasonForVisit: request.ReasonForVisit,
|
|
||||||
AppointmentDate: time.Now(),
|
|
||||||
LocationName: "New York",
|
|
||||||
})
|
|
||||||
return errors.New("error creating patient")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Service) List() ([]*Patient, error) {
|
|
||||||
patients, err := database.HList[Patient]("patients")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return patients, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
module sandbox
|
|
||||||
|
|
||||||
go 1.23.0
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/google/uuid v1.6.0
|
|
||||||
github.com/maddalax/htmgo/framework v0.0.0-20240914010415-2397bf9fb057
|
|
||||||
github.com/maddalax/htmgo/framework-ui v0.0.0-20240914003619-c256552b2143
|
|
||||||
github.com/redis/go-redis/v9 v9.6.1
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // 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/rivo/uniseg v0.2.0 // 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
|
|
||||||
golang.org/x/sys v0.25.0 // indirect
|
|
||||||
)
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
|
||||||
github.com/labstack/echo/v4 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
|
||||||
github.com/labstack/echo/v4 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
|
||||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
|
||||||
github.com/maddalax/htmgo/framework v0.0.0-20240914010415-2397bf9fb057 h1:DTc3qPMvwrh6wPIusGmQ1jPxngy7T6maUDh5RwYf6H0=
|
|
||||||
github.com/maddalax/htmgo/framework v0.0.0-20240914010415-2397bf9fb057/go.mod h1:O8ogYQjCn5iD9CzjdRgfrJfP9uMpx8rrx6YD5N4AecY=
|
|
||||||
github.com/maddalax/htmgo/framework-ui v0.0.0-20240914003619-c256552b2143 h1:aGpoab8N9rzXJAHIP8WiW5CsHjpSCrGlnbd0bQCRS3g=
|
|
||||||
github.com/maddalax/htmgo/framework-ui v0.0.0-20240914003619-c256552b2143/go.mod h1:Z8Mym1vqAMNcgtu1sHbWwQIwTvtNr6VqRZhKBweiCNE=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
|
||||||
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
|
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
|
||||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
|
||||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
|
||||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
|
||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
|
||||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"log"
|
|
||||||
"starter-template/pages"
|
|
||||||
"starter-template/partials/load"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
f := echo.New()
|
|
||||||
|
|
||||||
f.Static("/public", "./assets/dist")
|
|
||||||
|
|
||||||
f.Use(func(ctx echo.Context) error {
|
|
||||||
if ctx.Cookies("htmgo-session") != "" {
|
|
||||||
return ctx.Next()
|
|
||||||
}
|
|
||||||
id := ctx.IP() + uuid.NewString()
|
|
||||||
ctx.Cookie(&echo.Cookie{
|
|
||||||
Name: "htmgo-session",
|
|
||||||
Value: id,
|
|
||||||
SessionOnly: true,
|
|
||||||
})
|
|
||||||
return ctx.Next()
|
|
||||||
})
|
|
||||||
|
|
||||||
f.Use(func(ctx echo.Context) error {
|
|
||||||
if ctx.Path() == "/livereload" {
|
|
||||||
return ctx.Next()
|
|
||||||
}
|
|
||||||
now := time.Now()
|
|
||||||
err := ctx.Next()
|
|
||||||
duration := time.Since(now)
|
|
||||||
ctx.Set("X-Response-Time", duration.String())
|
|
||||||
// Log or print the request method, URL, and duration
|
|
||||||
log.Printf("Request: %s %s took %dms", ctx.Method(), ctx.OriginalURL(), duration.Milliseconds())
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
load.RegisterPartials(f)
|
|
||||||
pages.RegisterPages(f)
|
|
||||||
|
|
||||||
h.Start(f, h.App{
|
|
||||||
LiveReload: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
package news
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/maddalax/htmgo/framework/util/httpjson"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Post struct {
|
|
||||||
By string `json:"by"`
|
|
||||||
Descendants int `json:"descendants"`
|
|
||||||
Id int `json:"id"`
|
|
||||||
Kids []int `json:"kids"`
|
|
||||||
Score int `json:"score"`
|
|
||||||
Time int `json:"time"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Url string `json:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func List() ([]Post, error) {
|
|
||||||
responseIds, err := httpjson.Get[[]int64]("https://hacker-news.firebaseio.com/v0/topstories.json")
|
|
||||||
responseIds = responseIds[0:50]
|
|
||||||
if err != nil {
|
|
||||||
return []Post{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
posts := make([]Post, len(responseIds))
|
|
||||||
|
|
||||||
for index, id := range responseIds {
|
|
||||||
wg.Add(1)
|
|
||||||
id := id
|
|
||||||
index := index
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
url := fmt.Sprintf("https://hacker-news.firebaseio.com/v0/item/%d.json", id)
|
|
||||||
post, err := httpjson.Get[Post](url)
|
|
||||||
if err != nil {
|
|
||||||
println(err.Error())
|
|
||||||
}
|
|
||||||
posts[index] = post
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
return posts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Get(id string) (Post, error) {
|
|
||||||
url := fmt.Sprintf("https://hacker-news.firebaseio.com/v0/item/%s.json", id)
|
|
||||||
post, err := httpjson.Get[Post](url)
|
|
||||||
if err != nil {
|
|
||||||
return Post{}, err
|
|
||||||
}
|
|
||||||
return post, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
package news
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"starter-template/database"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func StoryList() h.Ren {
|
|
||||||
|
|
||||||
posts, _ := database.GetOrSet[[]Post]("posts", func() []Post {
|
|
||||||
p, _ := List()
|
|
||||||
return p
|
|
||||||
})
|
|
||||||
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
|
|
||||||
if len(*posts) == 0 {
|
|
||||||
return h.Pf("No results found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.Fragment(
|
|
||||||
h.Div(h.List(*posts, func(item Post, index int) h.Ren {
|
|
||||||
return StoryCard(item)
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func StoryCard(post Post) h.Ren {
|
|
||||||
url := fmt.Sprintf("/news/%d", post.Id)
|
|
||||||
return h.Div(
|
|
||||||
h.Class("items-center bg-indigo-200 p-4 rounded"),
|
|
||||||
h.A(h.Text(post.Title), h.Href(url)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func StoryFull(id string) h.Ren {
|
|
||||||
post, err := Get(id)
|
|
||||||
if err != nil {
|
|
||||||
return h.Pf(err.Error())
|
|
||||||
}
|
|
||||||
return StoryCard(post)
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package base
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"starter-template/partials"
|
|
||||||
"starter-template/partials/sheet"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RootPage(children ...h.Ren) h.Ren {
|
|
||||||
return h.Html(
|
|
||||||
h.HxExtension("path-deps, response-targets, mutation-error"),
|
|
||||||
h.Head(
|
|
||||||
h.Link("/public/main.css", "stylesheet"),
|
|
||||||
h.Script("/public/htmgo.js"),
|
|
||||||
),
|
|
||||||
h.Body(
|
|
||||||
partials.NavBar(),
|
|
||||||
sheet.Closed(),
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex flex-col gap-2 bg-white h-full"),
|
|
||||||
h.Fragment(children...),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
// Package pages THIS FILE IS GENERATED. DO NOT EDIT.
|
|
||||||
package pages
|
|
||||||
|
|
||||||
import "github.com/labstack/echo/v4"
|
|
||||||
import "github.com/maddalax/htmgo/framework/h"
|
|
||||||
|
|
||||||
func RegisterPages(f *echo.Echo) {
|
|
||||||
f.Get("/", func(ctx echo.Context) error {
|
|
||||||
return h.HtmlView(ctx, IndexPage(ctx))
|
|
||||||
})
|
|
||||||
f.Get("/news/:id", func(ctx echo.Context) error {
|
|
||||||
return h.HtmlView(ctx, Test(ctx))
|
|
||||||
})
|
|
||||||
f.Get("/news", func(ctx echo.Context) error {
|
|
||||||
return h.HtmlView(ctx, ListPage(ctx))
|
|
||||||
})
|
|
||||||
f.Get("/patients", func(ctx echo.Context) error {
|
|
||||||
return h.HtmlView(ctx, PatientsIndex(ctx))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
package pages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func IndexPage(c echo.Context) *h.Page {
|
|
||||||
return h.NewPage(h.Html(
|
|
||||||
h.Class("bg-background flex flex-col items-center"),
|
|
||||||
h.Head(
|
|
||||||
h.Link("/public/main.css", "stylesheet"),
|
|
||||||
h.Script("/public/htmgo.js"),
|
|
||||||
h.Script("/public/scripts/shiki.js"),
|
|
||||||
),
|
|
||||||
h.Body(
|
|
||||||
h.Class("flex flex-col gap-3"),
|
|
||||||
// Navbar
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex justify-between items-center w-full p-6"),
|
|
||||||
h.Div(
|
|
||||||
h.Class("text-white text-xl font-bold"),
|
|
||||||
h.Text("htmgo"),
|
|
||||||
),
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex gap-4"),
|
|
||||||
h.A(h.Href("/pricing"), h.Class("text-white"), h.Text("Pricing")),
|
|
||||||
h.A(h.Href("/docs"), h.Class("text-white"), h.Text("Docs")),
|
|
||||||
h.A(h.Href("/app"), h.Class("text-white"), h.Text("App")),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Hero Section
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex flex-col items-center justify-center gap-6 p-12 bg-background text-center"),
|
|
||||||
h.H1(
|
|
||||||
h.Class("text-white text-4xl sm:text-5xl font-bold max-w-3xl"),
|
|
||||||
h.Text("Go and HTMX: The Simple Stack"),
|
|
||||||
),
|
|
||||||
h.P(
|
|
||||||
h.Class("text-white text-lg sm:text-xl max-w-2xl"),
|
|
||||||
h.Text("Combine the simplicity of Go with the power of HTMX for dynamic, JavaScript-light web development."),
|
|
||||||
),
|
|
||||||
h.A(h.Href("/get-started"),
|
|
||||||
h.Class("bg-white text-background px-6 py-3 rounded-md font-semibold mt-4"),
|
|
||||||
h.Text("Join the waitlist"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Explore Section
|
|
||||||
h.Div(
|
|
||||||
h.Class("w-full max-w-4xl"),
|
|
||||||
CodeExample(),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Footer Section
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex justify-center items-center py-6"),
|
|
||||||
h.Text(fmt.Sprintf("© %d htmgo", time.Now().Year())),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
func CodeExample() h.Ren {
|
|
||||||
code, err := os.ReadFile("pages/assets/_example.go")
|
|
||||||
scriptSrc, err := os.ReadFile("pages/assets/shiki.js")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return h.Pf("Error loading code example")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%s\n", code)
|
|
||||||
|
|
||||||
script := fmt.Sprintf(string(scriptSrc), string(code))
|
|
||||||
|
|
||||||
return h.Div(
|
|
||||||
h.Class("text-white rounded-lg"),
|
|
||||||
h.Pre(h.Id("foo")),
|
|
||||||
h.RawF(`
|
|
||||||
<script type="module">
|
|
||||||
%s
|
|
||||||
</script>
|
|
||||||
`, script),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package pages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test(ctx echo.Context) *h.Page {
|
|
||||||
text := fmt.Sprintf("News ID: %s", ctx.Params("id"))
|
|
||||||
return h.NewPage(
|
|
||||||
h.Div(h.Text(text)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package pages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"starter-template/pages/base"
|
|
||||||
"starter-template/partials"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ListPage(ctx echo.Context) *h.Page {
|
|
||||||
return h.NewPage(base.RootPage(
|
|
||||||
list(ctx),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
func list(ctx echo.Context) h.Ren {
|
|
||||||
return h.Fragment(
|
|
||||||
h.ViewOnLoad(partials.NewsSheet),
|
|
||||||
h.Div(
|
|
||||||
h.Class("inline-flex flex-col gap-4 p-4"),
|
|
||||||
h.Div(
|
|
||||||
h.Class("max-w-md flex flex-col gap-4 "),
|
|
||||||
partials.OpenSheetButton(h.GetQueryParam(ctx, "open") == "true"),
|
|
||||||
),
|
|
||||||
h.Div(
|
|
||||||
h.ViewOnLoad(partials.NewsSheetOpenCount),
|
|
||||||
h.Text("you opened sheet 0 times")),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package pages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"starter-template/pages/base"
|
|
||||||
"starter-template/partials/patient"
|
|
||||||
)
|
|
||||||
|
|
||||||
func PatientsIndex(ctx echo.Context) *h.Page {
|
|
||||||
return h.NewPage(base.RootPage(
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex flex-col p-4 w-full"),
|
|
||||||
h.Div(
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex justify-between items-center"),
|
|
||||||
h.P(h.Text("Manage Patients"), h.Class("text-lg font-bold")),
|
|
||||||
patient.AddPatientButton(),
|
|
||||||
),
|
|
||||||
h.View(patient.List, h.ReloadParams{
|
|
||||||
Triggers: h.CreateTriggers("load", "path-deps"),
|
|
||||||
Children: h.Children(h.Attribute("path-deps", h.GetPartialPath(patient.Create))),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package partials
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/maddalax/htmgo/framework-ui/ui"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
)
|
|
||||||
|
|
||||||
func OpenSheetButton(open bool, children ...h.Ren) h.Ren {
|
|
||||||
if open {
|
|
||||||
return ui.PrimaryButton(ui.ButtonProps{
|
|
||||||
Id: "open-sheet",
|
|
||||||
Text: "Close NewsSheet",
|
|
||||||
Target: "#sheet-partial",
|
|
||||||
Get: h.GetPartialPathWithQs(NewsSheet, "open=false"),
|
|
||||||
Children: children,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return ui.PrimaryButton(ui.ButtonProps{
|
|
||||||
Id: "open-sheet",
|
|
||||||
Text: "Open NewsSheet",
|
|
||||||
Target: "#sheet-partial",
|
|
||||||
Get: h.GetPartialPathWithQs(NewsSheet, "open=true"),
|
|
||||||
Children: children,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
// Package partials THIS FILE IS GENERATED. DO NOT EDIT.
|
|
||||||
package load
|
|
||||||
|
|
||||||
import "github.com/maddalax/htmgo/framework/h"
|
|
||||||
import "github.com/labstack/echo/v4"
|
|
||||||
import "starter-template/partials"
|
|
||||||
import "starter-template/partials/patient"
|
|
||||||
import "starter-template/partials/sheet"
|
|
||||||
|
|
||||||
func GetPartialFromContext(ctx echo.Context) *h.Partial {
|
|
||||||
path := ctx.Path()
|
|
||||||
if path == "NewsSheet" || path == "/starter-template/partials.NewsSheet" {
|
|
||||||
return partials.NewsSheet(ctx)
|
|
||||||
}
|
|
||||||
if path == "NewsSheetOpenCount" || path == "/starter-template/partials.NewsSheetOpenCount" {
|
|
||||||
return partials.NewsSheetOpenCount(ctx)
|
|
||||||
}
|
|
||||||
if path == "Create" || path == "/starter-template/partials/patient.Create" {
|
|
||||||
return patient.Create(ctx)
|
|
||||||
}
|
|
||||||
if path == "List" || path == "/starter-template/partials/patient.List" {
|
|
||||||
return patient.List(ctx)
|
|
||||||
}
|
|
||||||
if path == "AddPatientSheetPartial" || path == "/starter-template/partials/patient.AddPatientSheetPartial" {
|
|
||||||
return patient.AddPatientSheetPartial(ctx)
|
|
||||||
}
|
|
||||||
if path == "ValidateForm" || path == "/starter-template/partials/patient.ValidateForm" {
|
|
||||||
return patient.ValidateForm(ctx)
|
|
||||||
}
|
|
||||||
if path == "Close" || path == "/starter-template/partials/sheet.Close" {
|
|
||||||
return sheet.Close(ctx)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterPartials(f *echo.Echo) {
|
|
||||||
f.All("starter-template/partials*", func(ctx echo.Context) error {
|
|
||||||
partial := GetPartialFromContext(ctx)
|
|
||||||
if partial == nil {
|
|
||||||
return ctx.SendStatus(404)
|
|
||||||
}
|
|
||||||
return h.PartialView(ctx, partial)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package partials
|
|
||||||
|
|
||||||
import "github.com/maddalax/htmgo/framework/h"
|
|
||||||
|
|
||||||
type Link struct {
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NavBar() h.Ren {
|
|
||||||
|
|
||||||
links := []Link{
|
|
||||||
{"Home", "/"},
|
|
||||||
{"News", "/news"},
|
|
||||||
{"Patients", "/patients"},
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.Nav(h.Class("flex gap-4 items-center p-4 text-slate-600"),
|
|
||||||
h.Boost(),
|
|
||||||
h.Children(
|
|
||||||
h.Map(links, func(link Link) h.Ren {
|
|
||||||
return h.A(h.Text(link.Name), h.Href(link.Path), h.Class("cursor-pointer hover:text-blue-400"))
|
|
||||||
})...,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
package partials
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework-ui/ui"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"starter-template/news"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewsSheet(ctx echo.Context) *h.Partial {
|
|
||||||
open := h.GetQueryParam(ctx, "open") == "true"
|
|
||||||
return h.NewPartialWithHeaders(
|
|
||||||
&map[string]string{
|
|
||||||
"hx-trigger": "sheetOpened",
|
|
||||||
"hx-push-url": fmt.Sprintf("/news%s", h.Ternary(open, "?open=true", "")),
|
|
||||||
},
|
|
||||||
SheetWrapper(
|
|
||||||
h.IfElseLazy(open, SheetOpen, SheetClosed),
|
|
||||||
h.OobSwap(ctx, OpenSheetButton(open)),
|
|
||||||
h.OobSwap(ctx, NewsSheetOpenCount(ctx).Root),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewsSheetOpenCount(ctx echo.Context) *h.Partial {
|
|
||||||
|
|
||||||
open := h.GetQueryParam(ctx, "open") == "true"
|
|
||||||
|
|
||||||
return h.NewPartial(h.Div(
|
|
||||||
h.Id("sheet-open-count"),
|
|
||||||
h.IfElse(open,
|
|
||||||
h.Text(fmt.Sprintf("you opened sheet %d times", 1)),
|
|
||||||
h.Text("sheet is not open")),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SheetWrapper(children ...h.Ren) h.Ren {
|
|
||||||
return h.Div(h.Id("sheet-partial"), h.Fragment(children...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func SheetClosed() h.Ren {
|
|
||||||
return h.Div()
|
|
||||||
}
|
|
||||||
|
|
||||||
func SheetOpen() h.Ren {
|
|
||||||
return h.Fragment(h.Div(
|
|
||||||
h.Class(`fixed top-0 right-0 h-full w-96 bg-gray-100 shadow-lg z-50`),
|
|
||||||
h.Div(
|
|
||||||
h.Class("p-4 overflow-y-auto h-full w-full flex flex-col gap-4"),
|
|
||||||
h.P(h.Text("News Sheet"),
|
|
||||||
h.Class("text-lg font-bold"),
|
|
||||||
),
|
|
||||||
h.P(h.Text("Here are the latest news stories."),
|
|
||||||
h.Class("text-sm mt-2"),
|
|
||||||
),
|
|
||||||
ui.Button(ui.ButtonProps{
|
|
||||||
Text: "Close NewsSheet",
|
|
||||||
Target: "#sheet-partial",
|
|
||||||
Get: h.GetPartialPathWithQs(NewsSheet, "open=false"),
|
|
||||||
}),
|
|
||||||
news.StoryList(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
package patient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"starter-template/features/patient"
|
|
||||||
"starter-template/partials/sheet"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Create(ctx echo.Context) *h.Partial {
|
|
||||||
name := ctx.FormValue("name")
|
|
||||||
reason := ctx.FormValue("reason-for-visit")
|
|
||||||
location := ctx.FormValue("location-name")
|
|
||||||
|
|
||||||
err := patient.NewService(ctx).Create(patient.CreatePatientRequest{
|
|
||||||
Name: name,
|
|
||||||
ReasonForVisit: reason,
|
|
||||||
LocationName: location,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ctx.Status(500)
|
|
||||||
return h.NewPartialWithHeaders(h.NewHeaders(""),
|
|
||||||
h.Div(
|
|
||||||
h.Text("Error creating patient"),
|
|
||||||
h.Class("text-red-500"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
headers := h.CombineHeaders(h.PushQsHeader(ctx, "adding", ""), &map[string]string{
|
|
||||||
"HX-HxTrigger": "patient-added",
|
|
||||||
})
|
|
||||||
|
|
||||||
return h.NewPartialWithHeaders(
|
|
||||||
headers,
|
|
||||||
sheet.Close(ctx))
|
|
||||||
}
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
package patient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework-ui/ui"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"starter-template/features/patient"
|
|
||||||
"starter-template/partials/sheet"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func List(ctx echo.Context) *h.Partial {
|
|
||||||
patients, err := patient.NewService(ctx).List()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return h.NewPartial(h.Div(
|
|
||||||
h.Class("patient-list"),
|
|
||||||
h.Pf("Error loading patients"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(patients) == 0 {
|
|
||||||
return h.NewPartial(h.Div(
|
|
||||||
h.Class("patient-list"),
|
|
||||||
h.Pf("No patients found"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.NewPartial(h.Div(
|
|
||||||
h.Class("mt-8"),
|
|
||||||
h.Id("patient-list"),
|
|
||||||
h.List(patients, Row),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddPatientSheetPartial(ctx echo.Context) *h.Partial {
|
|
||||||
closePathQs := h.GetQueryParam(ctx, "onClosePath")
|
|
||||||
return h.NewPartialWithHeaders(
|
|
||||||
h.PushQsHeader(ctx, "adding", "true"),
|
|
||||||
AddPatientSheet(
|
|
||||||
h.Ternary(closePathQs != "", closePathQs, h.CurrentPath(ctx)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddPatientSheet(onClosePath string) h.Ren {
|
|
||||||
return sheet.Opened(
|
|
||||||
sheet.Props{
|
|
||||||
OnClosePath: onClosePath,
|
|
||||||
ClassName: "w-[400px] bg-gray-100 p-4",
|
|
||||||
Root: h.Div(
|
|
||||||
h.Class("flex flex-col gap-4"),
|
|
||||||
h.P(h.Text("Add Patient"), h.Class("text-lg font-bold")),
|
|
||||||
addPatientForm(),
|
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateForm(ctx echo.Context) *h.Partial {
|
|
||||||
trigger := h.GetTriggerName(ctx)
|
|
||||||
value := ctx.FormValue(trigger)
|
|
||||||
|
|
||||||
if trigger == "name" {
|
|
||||||
if strings.ToLower(value) == "sydne" {
|
|
||||||
return h.NewPartial(h.Pf("that name is reserved"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if trigger == "reason-for-visit" {
|
|
||||||
if strings.ToLower(value) == "arm hurts" {
|
|
||||||
return h.NewPartial(h.Pf("lol that reason is fake"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if trigger == "location-name" {
|
|
||||||
if strings.ToLower(value) == "hospital" {
|
|
||||||
return h.NewPartial(h.Pf("that location is reserved"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.NewPartial(h.Fragment())
|
|
||||||
}
|
|
||||||
|
|
||||||
func addPatientForm() h.Ren {
|
|
||||||
return h.Form(
|
|
||||||
h.HxExtension("debug, trigger-children"),
|
|
||||||
h.Attribute("hx-target-5*", "#submit-error"),
|
|
||||||
h.Post(h.GetPartialPath(Create)),
|
|
||||||
h.Class("flex flex-col gap-2"),
|
|
||||||
ui.Input(ui.InputProps{
|
|
||||||
Type: "text",
|
|
||||||
Label: "Name",
|
|
||||||
Name: "name",
|
|
||||||
DefaultValue: "",
|
|
||||||
ValidationPath: h.GetPartialPath(ValidateForm),
|
|
||||||
}),
|
|
||||||
ui.Input(ui.InputProps{
|
|
||||||
Type: "text",
|
|
||||||
Label: "Reason for visit",
|
|
||||||
Name: "reason-for-visit",
|
|
||||||
ValidationPath: h.GetPartialPath(ValidateForm),
|
|
||||||
}),
|
|
||||||
ui.Input(ui.InputProps{
|
|
||||||
Type: "date",
|
|
||||||
Label: "Appointment Date",
|
|
||||||
Name: "appointment-date",
|
|
||||||
}),
|
|
||||||
ui.Input(ui.InputProps{
|
|
||||||
Type: "text",
|
|
||||||
Label: "Location Name",
|
|
||||||
Name: "location-name",
|
|
||||||
ValidationPath: h.GetPartialPath(ValidateForm),
|
|
||||||
}),
|
|
||||||
ui.PrimaryButton(ui.ButtonProps{
|
|
||||||
Text: "Add Patient",
|
|
||||||
Class: "rounded p-2",
|
|
||||||
Type: "submit",
|
|
||||||
}),
|
|
||||||
h.Div(
|
|
||||||
h.Id("submit-error"),
|
|
||||||
h.Class("text-red-500"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Row(patient *patient.Patient, index int) h.Ren {
|
|
||||||
return h.Div(
|
|
||||||
h.Class("flex flex-col gap-2 rounded p-4", h.Ternary(index%2 == 0, "bg-red-100", "")),
|
|
||||||
h.Pf("Name: %s", patient.Name),
|
|
||||||
h.Pf("Reason for visit: %s", patient.ReasonForVisit),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddPatientButton() h.Ren {
|
|
||||||
return ui.Button(ui.ButtonProps{
|
|
||||||
Id: "add-patient",
|
|
||||||
Text: "Add Patient",
|
|
||||||
Class: "bg-blue-700 text-white rounded p-2 h-12",
|
|
||||||
Trigger: "qs:adding, click",
|
|
||||||
Target: sheet.Id,
|
|
||||||
Get: h.GetPartialPathWithQs(AddPatientSheetPartial, "onClosePath=/patients"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package sheet
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Props struct {
|
|
||||||
ClassName string
|
|
||||||
Root h.Ren
|
|
||||||
OnClosePath string
|
|
||||||
}
|
|
||||||
|
|
||||||
var Id = "#active-modal"
|
|
||||||
|
|
||||||
func Opened(props Props) h.Ren {
|
|
||||||
return h.Fragment(h.Div(
|
|
||||||
h.Class(`fixed top-0 right-0 h-full shadow-lg z-50`,
|
|
||||||
h.Ternary(props.ClassName != "", props.ClassName, "w-96 bg-gray-100")),
|
|
||||||
closeButton(props),
|
|
||||||
h.Div(
|
|
||||||
props.Root,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Closed() h.Ren {
|
|
||||||
return h.Div(h.Id(Id))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Close(ctx echo.Context) *h.Partial {
|
|
||||||
return h.NewPartialWithHeaders(
|
|
||||||
h.Ternary(ctx.Query("path") != "", h.ReplaceUrlHeader(ctx.Query("path")), h.NewHeaders()),
|
|
||||||
h.OobSwap(ctx, Closed()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeButton(props Props) h.Ren {
|
|
||||||
return h.Div(
|
|
||||||
h.Class("absolute top-0 right-0 p-3"),
|
|
||||||
h.Button(
|
|
||||||
h.Class("text-gray-500"),
|
|
||||||
h.GetPartialWithQs(Close, fmt.Sprintf("path=%s", props.OnClosePath)),
|
|
||||||
h.Text("X"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -2,20 +2,11 @@ package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"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 {
|
func RootPage(children ...h.Ren) h.Ren {
|
||||||
return h.Html(
|
return h.Html(
|
||||||
h.HxExtension(Extensions()),
|
h.HxExtension(h.BaseExtensions()),
|
||||||
h.Head(
|
h.Head(
|
||||||
h.Link("/public/main.css", "stylesheet"),
|
h.Link("/public/main.css", "stylesheet"),
|
||||||
h.Script("/public/htmgo.js"),
|
h.Script("/public/htmgo.js"),
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,6 @@ import "github.com/maddalax/htmgo/framework/h"
|
||||||
|
|
||||||
func RegisterPages(f *echo.Echo) {
|
func RegisterPages(f *echo.Echo) {
|
||||||
f.GET("/", func(ctx echo.Context) error {
|
f.GET("/", func(ctx echo.Context) error {
|
||||||
cc := ctx.(*h.RequestContext)
|
|
||||||
return h.HtmlView(ctx, IndexPage(cc))
|
|
||||||
})
|
|
||||||
f.GET("/tasks", func(ctx echo.Context) error {
|
|
||||||
cc := ctx.(*h.RequestContext)
|
cc := ctx.(*h.RequestContext)
|
||||||
return h.HtmlView(ctx, TaskListPage(cc))
|
return h.HtmlView(ctx, TaskListPage(cc))
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,29 @@
|
||||||
package pages
|
package pages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
"todolist/pages/base"
|
"todolist/pages/base"
|
||||||
"todolist/partials"
|
"todolist/partials/task"
|
||||||
|
|
||||||
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IndexPage(c echo.Context) *h.Page {
|
func TaskListPage(ctx *h.RequestContext) *h.Page {
|
||||||
return h.NewPage(h.Html(
|
|
||||||
h.HxExtension(base.Extensions()),
|
title := h.Div(
|
||||||
h.Class("bg-red-200 flex flex-col items-center h-full w-full"),
|
h.H1(h.Class("text-7xl font-extralight text-rose-500 tracking-wide"), h.Text("todos")),
|
||||||
h.Head(
|
)
|
||||||
h.Link("/public/main.css", "stylesheet"),
|
|
||||||
h.Script("/public/htmgo.js"),
|
return h.NewPage(base.RootPage(
|
||||||
|
h.Div(
|
||||||
|
h.Class("bg-neutral-100 min-h-screen"),
|
||||||
|
h.Div(
|
||||||
|
h.Class("flex flex-col gap-6 p-4 items-center max-w-xl mx-auto pb-12"),
|
||||||
|
title,
|
||||||
|
task.Card(ctx),
|
||||||
|
h.Children(
|
||||||
|
h.Div(h.Text("Double-click to edit a todo")),
|
||||||
),
|
),
|
||||||
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.AfterRequest(
|
|
||||||
h.SetDisabled(true),
|
|
||||||
h.RemoveClass("bg-red-600"),
|
|
||||||
h.AddClass("bg-gray-500"),
|
|
||||||
),
|
|
||||||
h.GetPartial(partials.SamplePartial),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package pages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"todolist/pages/base"
|
|
||||||
"todolist/partials/task"
|
|
||||||
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TaskListPage(ctx *h.RequestContext) *h.Page {
|
|
||||||
|
|
||||||
title := h.Div(
|
|
||||||
h.H1(h.Class("text-7xl font-extralight text-rose-500 tracking-wide"), h.Text("todos")),
|
|
||||||
)
|
|
||||||
|
|
||||||
return h.NewPage(base.RootPage(
|
|
||||||
h.Div(
|
|
||||||
h.Class("bg-neutral-100 min-h-screen"),
|
|
||||||
h.Div(
|
|
||||||
h.Class("flex flex-col gap-6 p-4 items-center max-w-xl mx-auto pb-12"),
|
|
||||||
title,
|
|
||||||
task.Card(ctx),
|
|
||||||
h.Children(
|
|
||||||
h.Div(h.Text("Double-click to edit a todo")),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
@ -314,7 +314,7 @@ func ChangeTab(ctx *h.RequestContext) *h.Partial {
|
||||||
tab := ctx.QueryParam("tab")
|
tab := ctx.QueryParam("tab")
|
||||||
|
|
||||||
return h.SwapManyPartialWithHeaders(ctx,
|
return h.SwapManyPartialWithHeaders(ctx,
|
||||||
h.PushUrlHeader(fmt.Sprintf("/tasks?tab=%s", tab)),
|
h.PushQsHeader(ctx, h.NewQs("tab", tab)),
|
||||||
List(list, tab),
|
List(list, tab),
|
||||||
Footer(list, tab),
|
Footer(list, tab),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue