Merge pull request 'first push' (#1) from features/first-push into main
Reviewed-on: #1
This commit is contained in:
commit
574664b8c4
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,7 +8,8 @@
|
|||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
*_templ.txt
|
||||||
|
*_templ.go
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"**/*_templ.go": true,
|
||||||
|
"**/*_templ.txt": true
|
||||||
|
}
|
||||||
|
}
|
4
Justfile
Normal file
4
Justfile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
# Runs the 'templ generate` every time a file is updated and reloads the debugger
|
||||||
|
debug:
|
||||||
|
templ generate --watch --proxy="http://localhost:3000" --cmd="go run ."
|
18
client/apiclient.go
Normal file
18
client/apiclient.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
const (
|
||||||
|
HeaderContentType = "Content-Type"
|
||||||
|
MIMEApplicationForm = "application/x-www-form-urlencoded"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApiClient struct {
|
||||||
|
Auth Auth
|
||||||
|
|
||||||
|
ServerAddress string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(serverAddress string) ApiClient {
|
||||||
|
return ApiClient{
|
||||||
|
Auth: newAuthClient(serverAddress),
|
||||||
|
}
|
||||||
|
}
|
88
client/auth.go
Normal file
88
client/auth.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.jamestombleson.com/jtom38/go-cook/api/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Auth interface {
|
||||||
|
Register(username, password string) error
|
||||||
|
Login(username, password string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthClient struct {
|
||||||
|
serverAddress string
|
||||||
|
client http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAuthClient(serverAddress string) AuthClient {
|
||||||
|
return AuthClient{
|
||||||
|
serverAddress: serverAddress,
|
||||||
|
client: http.Client{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AuthClient) Register(username, password string) error {
|
||||||
|
endpoint := fmt.Sprintf("%s/api/v1/auth/register", a.serverAddress)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, endpoint, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set(HeaderContentType, MIMEApplicationForm)
|
||||||
|
req.Form.Add("username", username)
|
||||||
|
req.Form.Add("password", password)
|
||||||
|
resp, err := a.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
content, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var bind = domain.ErrorResponse{}
|
||||||
|
err = json.Unmarshal(content, &bind)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AuthClient) Login(username, password string) error {
|
||||||
|
endpoint := fmt.Sprintf("%s/api/v1/auth/register", a.serverAddress)
|
||||||
|
req, err := http.NewRequest(http.MethodPost, endpoint, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set(HeaderContentType, MIMEApplicationForm)
|
||||||
|
req.Form.Add("username", username)
|
||||||
|
req.Form.Add("password", password)
|
||||||
|
resp, err := a.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
content, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var bind = domain.ErrorResponse{}
|
||||||
|
err = json.Unmarshal(content, &bind)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
31
go.mod
Normal file
31
go.mod
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module templ-test
|
||||||
|
|
||||||
|
go 1.22.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
git.jamestombleson.com/jtom38/go-cook v0.0.0-20240406005506-adf6c1e9ddb3
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/a-h/templ v0.2.648
|
||||||
|
github.com/gorilla/sessions v1.2.2
|
||||||
|
github.com/labstack/echo-contrib v0.16.0
|
||||||
|
github.com/labstack/echo/v4 v4.11.4
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
|
github.com/gorilla/context v1.1.2 // indirect
|
||||||
|
github.com/gorilla/securecookie v1.1.2 // 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.21.0 // indirect
|
||||||
|
golang.org/x/net v0.22.0 // indirect
|
||||||
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
golang.org/x/time v0.5.0 // indirect
|
||||||
|
)
|
53
go.sum
Normal file
53
go.sum
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
git.jamestombleson.com/jtom38/go-cook v0.0.0-20240406005506-adf6c1e9ddb3 h1:XUnvhhRB5X8k5wg/kErQH0nCihbNR1mTxfCxWvWKIAM=
|
||||||
|
git.jamestombleson.com/jtom38/go-cook v0.0.0-20240406005506-adf6c1e9ddb3/go.mod h1:4l/tX7wJagBjEUf7a2hC4RhQhFEcn8OmI1D+FbiwYCs=
|
||||||
|
github.com/a-h/templ v0.2.648 h1:A1ggHGIE7AONOHrFaDTM8SrqgqHL6fWgWCijQ21Zy9I=
|
||||||
|
github.com/a-h/templ v0.2.648/go.mod h1:SA7mtYwVEajbIXFRh3vKdYm/4FYyLQAtPH1+KxzGPA8=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
||||||
|
github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
|
||||||
|
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||||
|
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||||
|
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
||||||
|
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/labstack/echo-contrib v0.16.0 h1:vk5Kd+egpTOJxD3l+3IvZzQWPbrXiYxhkkgkJL99j/w=
|
||||||
|
github.com/labstack/echo-contrib v0.16.0/go.mod h1:mjX5VB3OqJcroIEycptBOY9Hr7rK+unq79W8QFKGNV0=
|
||||||
|
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
|
||||||
|
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
|
||||||
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
|
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
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/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
|
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||||
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
|
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.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||||
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
24
handlers/auth.go
Normal file
24
handlers/auth.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"templ-test/views"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handlers) AuthLogin(c echo.Context) error {
|
||||||
|
return Render(c, http.StatusOK, views.AuthLogin())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) AuthLoginPost(c echo.Context) error {
|
||||||
|
// check the form data
|
||||||
|
//user := c.FormValue("email")
|
||||||
|
//password := c.FormValue("password")
|
||||||
|
|
||||||
|
// send request to the API
|
||||||
|
//h.api.
|
||||||
|
|
||||||
|
// render
|
||||||
|
return nil
|
||||||
|
}
|
40
handlers/handler.go
Normal file
40
handlers/handler.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"templ-test/client"
|
||||||
|
"templ-test/services"
|
||||||
|
|
||||||
|
"github.com/a-h/templ"
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
|
"github.com/labstack/echo-contrib/session"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handlers struct {
|
||||||
|
Server *echo.Echo
|
||||||
|
api client.ApiClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandlerClient(api client.ApiClient, cfg services.EnvConfig) *Handlers {
|
||||||
|
h := Handlers{
|
||||||
|
api: api,
|
||||||
|
}
|
||||||
|
|
||||||
|
e := echo.New()
|
||||||
|
e.Use(session.Middleware(sessions.NewCookieStore([]byte(cfg.CookieSecret))))
|
||||||
|
e.GET("/", h.HomeHandler)
|
||||||
|
e.GET("/list", h.ListHandler)
|
||||||
|
|
||||||
|
auth := e.Group("/auth")
|
||||||
|
auth.GET("/login", h.AuthLogin)
|
||||||
|
auth.POST("/login", h.AuthLoginPost)
|
||||||
|
|
||||||
|
h.Server = e
|
||||||
|
return &h
|
||||||
|
}
|
||||||
|
|
||||||
|
func Render(ctx echo.Context, statusCode int, t templ.Component) error {
|
||||||
|
ctx.Response().Writer.WriteHeader(statusCode)
|
||||||
|
ctx.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML)
|
||||||
|
return t.Render(ctx.Request().Context(), ctx.Response().Writer)
|
||||||
|
}
|
16
handlers/home.go
Normal file
16
handlers/home.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"templ-test/views"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handlers) HomeHandler(c echo.Context) error {
|
||||||
|
return Render(c, http.StatusOK, views.Home())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) ListHandler(c echo.Context) error {
|
||||||
|
return Render(c, http.StatusOK, views.List())
|
||||||
|
}
|
19
main.go
Normal file
19
main.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"templ-test/client"
|
||||||
|
"templ-test/handlers"
|
||||||
|
"templ-test/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := services.NewEnvConfig()
|
||||||
|
|
||||||
|
// connect to api server
|
||||||
|
apiClient := client.New(cfg.ApiServerUri)
|
||||||
|
handler := handlers.NewHandlerClient(apiClient, cfg)
|
||||||
|
|
||||||
|
fmt.Println("Listening on :3000")
|
||||||
|
handler.Server.Start(":3000")
|
||||||
|
}
|
25
services/config.go
Normal file
25
services/config.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EnvConfig struct {
|
||||||
|
ApiServerUri string
|
||||||
|
CookieSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnvConfig() EnvConfig {
|
||||||
|
err := godotenv.Load()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EnvConfig{
|
||||||
|
ApiServerUri: os.Getenv("ApiServerUri"),
|
||||||
|
CookieSecret: os.Getenv("CookieSecret"),
|
||||||
|
}
|
||||||
|
}
|
22
views/auth.templ
Normal file
22
views/auth.templ
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package views
|
||||||
|
|
||||||
|
templ AuthLogin() {
|
||||||
|
@WithLayout("Login", true) {
|
||||||
|
<form>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="exampleInputEmail1" class="form-label">Email address</label>
|
||||||
|
<input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"/>
|
||||||
|
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="exampleInputPassword1" class="form-label">Password</label>
|
||||||
|
<input type="password" class="form-control" id="exampleInputPassword1"/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="exampleCheck1"/>
|
||||||
|
<label class="form-check-label" for="exampleCheck1">Check me out</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary" hx-post="/auth/" >Submit</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
}
|
23
views/components/bootstrap/bs_card.templ
Normal file
23
views/components/bootstrap/bs_card.templ
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
const (
|
||||||
|
VariantPrimary = "primary"
|
||||||
|
VariantSecondary = "secondary"
|
||||||
|
VariantSuccess = "success"
|
||||||
|
VariantDanger = "danger"
|
||||||
|
VariantWarning = "warning"
|
||||||
|
VariantInfo = "info"
|
||||||
|
VariantLight = "light"
|
||||||
|
VariantDark = "dark"
|
||||||
|
VariantLink = "link"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ BootstrapAlert(message, variant string) {
|
||||||
|
<div class={ getAlertVariant(variant) } role="alert">
|
||||||
|
{ message }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ BootstrapButton(message, variant string) {
|
||||||
|
<button type="button" class={ getButtonVariant(variant) }>{ message }</button>
|
||||||
|
}
|
19
views/components/bootstrap/helper.go
Normal file
19
views/components/bootstrap/helper.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func getButtonVariant(variant string) string {
|
||||||
|
if variant == "" {
|
||||||
|
return "btn"
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("btn btn-%s", variant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAlertVariant(variant string) string {
|
||||||
|
if variant == "" {
|
||||||
|
return "alert"
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("alert alert-%s", variant)
|
||||||
|
}
|
||||||
|
}
|
16
views/components/bootstrap/table.templ
Normal file
16
views/components/bootstrap/table.templ
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
templ Table(header []string) {
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
for _, item := range header{
|
||||||
|
<th scope="col">{ item }</th>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
84
views/core.templ
Normal file
84
views/core.templ
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package views
|
||||||
|
|
||||||
|
templ WithLayout(pageName string, useDarkMode bool) {
|
||||||
|
<html>
|
||||||
|
@getHtmlHead()
|
||||||
|
<body>
|
||||||
|
@bootstrapNavBar()
|
||||||
|
@getBodyHeader(pageName)
|
||||||
|
<div class="container-fluid">
|
||||||
|
{ children... }
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ Testing(pageName string, useDarkMode bool) {
|
||||||
|
<html>
|
||||||
|
@getHtmlHead()
|
||||||
|
<body>
|
||||||
|
@bootstrapNavBar()
|
||||||
|
@getBodyHeader(pageName)
|
||||||
|
<div class="container-fluid">
|
||||||
|
{ children... }
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ getHtmlHead() {
|
||||||
|
<head>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"/>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous"></script>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="twitter:card" content="fill in later"/>
|
||||||
|
<meta name="twitter:image" content=""/>
|
||||||
|
<meta name="og:image" content=""/>
|
||||||
|
</head>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ getBodyHeader(pageName string) {
|
||||||
|
<header>
|
||||||
|
<h1>{ pageName }</h1>
|
||||||
|
</header>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ bootstrapNavBar() {
|
||||||
|
<nav class="navbar navbar-expand-lg bg-body-tertiary" data-bs-theme="dark">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="#">Navbar</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" aria-current="page" href="#">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">Link</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
Dropdown
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="#">Action</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#">Another action</a></li>
|
||||||
|
<li><hr class="dropdown-divider"/></li>
|
||||||
|
<li><a class="dropdown-item" href="#">Something else here</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<form class="d-flex" role="search">
|
||||||
|
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search"/>
|
||||||
|
<button class="btn btn-outline-success" type="submit">Search</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
}
|
22
views/home.templ
Normal file
22
views/home.templ
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package views
|
||||||
|
|
||||||
|
import "templ-test/views/components/bootstrap"
|
||||||
|
|
||||||
|
templ Home() {
|
||||||
|
@Testing("Home", true) {
|
||||||
|
<p>
|
||||||
|
this should be above the alert
|
||||||
|
</p>
|
||||||
|
@bootstrap.BootstrapAlert("Testing!", bootstrap.VariantDark)
|
||||||
|
<p>you should now see this under the Alert </p>
|
||||||
|
@bootstrap.BootstrapButton("I am in danger", bootstrap.VariantDanger)
|
||||||
|
@bootstrap.BootstrapButton("I am the darkness", bootstrap.VariantDark)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templ List() {
|
||||||
|
@Testing("Lists", true) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user