add a bunch of frontend stuff
This commit is contained in:
parent
2586161abd
commit
bc85b7c340
30 changed files with 1459 additions and 136 deletions
|
@ -1,8 +1,11 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"emperror.dev/errors"
|
||||
"git.sleepycat.moe/sam/mercury/config"
|
||||
"git.sleepycat.moe/sam/mercury/internal/database/sql"
|
||||
"git.sleepycat.moe/sam/mercury/web/templates"
|
||||
"github.com/flosch/pongo2/v6"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
@ -12,19 +15,27 @@ type App struct {
|
|||
|
||||
Config config.Config
|
||||
Database *sql.Base
|
||||
|
||||
tmpl *pongo2.TemplateSet
|
||||
}
|
||||
|
||||
func NewApp(cfg config.Config, db *sql.Base) *App {
|
||||
func NewApp(cfg config.Config, db *sql.Base) (*App, error) {
|
||||
app := &App{
|
||||
Router: chi.NewRouter(),
|
||||
Config: cfg,
|
||||
Database: db,
|
||||
}
|
||||
|
||||
tmpl, err := templates.New(cfg.Core.Dev)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating templates")
|
||||
}
|
||||
app.tmpl = tmpl
|
||||
|
||||
app.Router.Use(app.Logger)
|
||||
app.Router.Use(middleware.Recoverer)
|
||||
|
||||
return app
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func (a *App) Account(q ...sql.Querier) *sql.AccountStore {
|
||||
|
|
52
web/app/template.go
Normal file
52
web/app/template.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/flosch/pongo2/v6"
|
||||
)
|
||||
|
||||
func (app *App) Template(w http.ResponseWriter, r *http.Request, tmplName string, ctx pongo2.Context) error {
|
||||
tmpl, err := app.tmpl.FromCache(tmplName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tctx := pongo2.Context{
|
||||
"flash_message": app.getFlash(w, r),
|
||||
}
|
||||
tctx.Update(ctx)
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
return tmpl.ExecuteWriter(tctx, w)
|
||||
}
|
||||
|
||||
const flashCookieName = "mercury-flash-message"
|
||||
|
||||
func (app *App) Flash(w http.ResponseWriter, msg string) {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: flashCookieName,
|
||||
Value: msg,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Expires: time.Now().Add(time.Minute),
|
||||
})
|
||||
}
|
||||
|
||||
func (app *App) getFlash(w http.ResponseWriter, r *http.Request) string {
|
||||
cookie, err := r.Cookie(flashCookieName)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
defer http.SetCookie(w, &http.Cookie{
|
||||
Name: flashCookieName,
|
||||
Value: "",
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Expires: time.Now(),
|
||||
})
|
||||
|
||||
return cookie.Value
|
||||
}
|
15
web/auth/auth.go
Normal file
15
web/auth/auth.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package auth
|
||||
|
||||
import "git.sleepycat.moe/sam/mercury/web/app"
|
||||
|
||||
type Auth struct {
|
||||
*app.App
|
||||
}
|
||||
|
||||
func New(app *app.App) *Auth {
|
||||
auth := &Auth{
|
||||
App: app,
|
||||
}
|
||||
|
||||
return auth
|
||||
}
|
11
web/auth/login.go
Normal file
11
web/auth/login.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/flosch/pongo2/v6"
|
||||
)
|
||||
|
||||
func (app *Auth) GetLogin(w http.ResponseWriter, r *http.Request) {
|
||||
app.Template(w, r, "auth/login.tpl", pongo2.Context{})
|
||||
}
|
1
web/frontend/.gitignore
vendored
Normal file
1
web/frontend/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
assets
|
|
@ -1,13 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Config.Name}}</title>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{.Config.Name}}</title>
|
||||
|
||||
{{.Vue.RenderTags}}
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
{{.Vue.RenderTags}}
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
package frontend
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.sleepycat.moe/sam/mercury/frontend"
|
||||
"git.sleepycat.moe/sam/mercury/internal/database"
|
||||
"git.sleepycat.moe/sam/mercury/web/app"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/rs/zerolog/log"
|
||||
vueglue "github.com/torenware/vite-go"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed app.html
|
||||
var htmlTemplate string
|
||||
|
||||
//go:embed assets
|
||||
var assets embed.FS
|
||||
|
||||
type Frontend struct {
|
||||
*app.App
|
||||
glue *vueglue.VueGlue
|
||||
|
@ -94,3 +98,14 @@ func (app *Frontend) ServeFrontend(w http.ResponseWriter, r *http.Request) {
|
|||
log.Err(err).Msg("executing frontend template")
|
||||
}
|
||||
}
|
||||
|
||||
func (app *Frontend) ServeStaticAssets(w http.ResponseWriter, r *http.Request) {
|
||||
if app.Config.Core.Dev {
|
||||
// TODO: this is unsafe
|
||||
path := filepath.Join("web/frontend/assets/", chi.URLParam(r, "*"))
|
||||
http.ServeFile(w, r, path)
|
||||
return
|
||||
}
|
||||
|
||||
_ = assets
|
||||
}
|
||||
|
|
|
@ -2,12 +2,23 @@ package web
|
|||
|
||||
import (
|
||||
"git.sleepycat.moe/sam/mercury/web/app"
|
||||
"git.sleepycat.moe/sam/mercury/web/auth"
|
||||
"git.sleepycat.moe/sam/mercury/web/frontend"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
func Routes(app *app.App) {
|
||||
// auth
|
||||
app.Router.Route("/auth", func(r chi.Router) {
|
||||
auth := auth.New(app)
|
||||
r.Get("/login", auth.GetLogin)
|
||||
})
|
||||
|
||||
// web app handlers
|
||||
// also assets
|
||||
frontend := frontend.New(app)
|
||||
app.Router.HandleFunc(frontend.AssetsPath(), frontend.ServeAssets)
|
||||
app.Router.HandleFunc("/static/*", frontend.ServeStaticAssets)
|
||||
app.Router.HandleFunc("/web", frontend.ServeFrontend)
|
||||
app.Router.HandleFunc("/web/*", frontend.ServeFrontend)
|
||||
}
|
||||
|
|
19
web/templates/auth/login.tpl
Normal file
19
web/templates/auth/login.tpl
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends 'base.tpl' %}
|
||||
{% block title %}
|
||||
Log in
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="auth">
|
||||
<form method="post">
|
||||
<p>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" name="username" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="username">Password</label>
|
||||
<input type="password" name="password" />
|
||||
</p>
|
||||
<input type="submit" value="Log in" />
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
13
web/templates/base.tpl
Normal file
13
web/templates/base.tpl
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
<title>{% block title %}Mercury{% endblock %}</title>
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
28
web/templates/templates.go
Normal file
28
web/templates/templates.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package templates
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
||||
"emperror.dev/errors"
|
||||
"github.com/flosch/pongo2/v6"
|
||||
)
|
||||
|
||||
//go:embed *
|
||||
var fs embed.FS
|
||||
|
||||
func New(dev bool) (*pongo2.TemplateSet, error) {
|
||||
if dev {
|
||||
loader, err := pongo2.NewLocalFileSystemLoader("web/templates")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating filesystem loader")
|
||||
}
|
||||
|
||||
ts := pongo2.NewSet("web", loader)
|
||||
ts.Debug = true
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
loader := pongo2.NewFSLoader(fs)
|
||||
ts := pongo2.NewSet("web", loader)
|
||||
return ts, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue