add a bunch of frontend stuff
This commit is contained in:
parent
2586161abd
commit
bc85b7c340
30 changed files with 1459 additions and 136 deletions
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"trailingComma": "all",
|
||||
"singleQuote": false
|
||||
}
|
19
assets/scss/_variables.scss
Normal file
19
assets/scss/_variables.scss
Normal file
|
@ -0,0 +1,19 @@
|
|||
:root {
|
||||
--dark-background: #2B303A;
|
||||
--light-background: #F5F5F5;
|
||||
|
||||
--dark-text: #FFFFFF;
|
||||
--light-text: #000000;
|
||||
|
||||
--dark-primary: #087E8B;
|
||||
--light-primary: #67AEB5;
|
||||
|
||||
--dark-secondary: #7C7F85;
|
||||
--light-secondary: #A4A6AA;
|
||||
|
||||
--dark-danger: #D64933;
|
||||
--light-danger: #FF5A5F;
|
||||
|
||||
--dark-success: #4DA167;
|
||||
--light-success: #77B68B;
|
||||
}
|
26
assets/scss/style.scss
Normal file
26
assets/scss/style.scss
Normal file
|
@ -0,0 +1,26 @@
|
|||
@use "node_modules/normalize.css/normalize";
|
||||
@use "_variables";
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background-color: var(--light-background);
|
||||
color: var(--light-text);
|
||||
|
||||
&:dark {
|
||||
background-color: var(--dark-background);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
}
|
||||
|
||||
.auth {
|
||||
width: 100%;
|
||||
@media (min-width: 640px) {
|
||||
max-width: 520px;
|
||||
}
|
||||
margin: 1rem auto;
|
||||
|
||||
p {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
|
@ -30,7 +30,10 @@ func run(c *cli.Context) error {
|
|||
return errors.Wrap(err, "creating postgres database")
|
||||
}
|
||||
|
||||
a := app.NewApp(cfg, db)
|
||||
a, err := app.NewApp(cfg, db)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "creating app")
|
||||
}
|
||||
|
||||
log.Debug().Msg("Creating account")
|
||||
acct, err := a.Account().CreateLocal(c.Context, "testington", "no@mercury.example", []byte("password"))
|
||||
|
|
|
@ -39,7 +39,10 @@ func run(c *cli.Context) error {
|
|||
return errors.Wrap(err, "creating postgres database")
|
||||
}
|
||||
|
||||
a := app.NewApp(cfg, db)
|
||||
a, err := app.NewApp(cfg, db)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "creating app")
|
||||
}
|
||||
|
||||
log.Debug().Msg("Mounting routes")
|
||||
web.Routes(a)
|
||||
|
|
|
@ -13,10 +13,14 @@
|
|||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||
"@tsconfig/svelte": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"sass": "^1.66.1",
|
||||
"svelte": "^4.0.5",
|
||||
"svelte-check": "^3.4.6",
|
||||
"tslib": "^2.6.0",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"normalize.css": "^8.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
lockfileVersion: "6.0"
|
||||
|
||||
dependencies:
|
||||
normalize.css:
|
||||
specifier: ^8.0.1
|
||||
version: 8.0.1
|
||||
|
||||
devDependencies:
|
||||
"@sveltejs/vite-plugin-svelte":
|
||||
specifier: ^2.4.2
|
||||
|
@ -10,12 +15,15 @@ devDependencies:
|
|||
prettier:
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3
|
||||
sass:
|
||||
specifier: ^1.66.1
|
||||
version: 1.66.1
|
||||
svelte:
|
||||
specifier: ^4.0.5
|
||||
version: 4.0.5
|
||||
svelte-check:
|
||||
specifier: ^3.4.6
|
||||
version: 3.4.6(svelte@4.0.5)
|
||||
version: 3.4.6(sass@1.66.1)(svelte@4.0.5)
|
||||
tslib:
|
||||
specifier: ^2.6.0
|
||||
version: 2.6.0
|
||||
|
@ -24,7 +32,7 @@ devDependencies:
|
|||
version: 5.0.2
|
||||
vite:
|
||||
specifier: ^4.4.5
|
||||
version: 4.4.5
|
||||
version: 4.4.5(sass@1.66.1)
|
||||
|
||||
packages:
|
||||
/@ampproject/remapping@2.2.1:
|
||||
|
@ -391,7 +399,7 @@ packages:
|
|||
"@sveltejs/vite-plugin-svelte": 2.4.2(svelte@4.0.5)(vite@4.4.5)
|
||||
debug: 4.3.4
|
||||
svelte: 4.0.5
|
||||
vite: 4.4.5
|
||||
vite: 4.4.5(sass@1.66.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
@ -413,7 +421,7 @@ packages:
|
|||
magic-string: 0.30.3
|
||||
svelte: 4.0.5
|
||||
svelte-hmr: 0.15.3(svelte@4.0.5)
|
||||
vite: 4.4.5
|
||||
vite: 4.4.5(sass@1.66.1)
|
||||
vitefu: 0.2.4(vite@4.4.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -747,6 +755,13 @@ packages:
|
|||
}
|
||||
dev: true
|
||||
|
||||
/immutable@4.3.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==,
|
||||
}
|
||||
dev: true
|
||||
|
||||
/import-fresh@3.3.0:
|
||||
resolution:
|
||||
{
|
||||
|
@ -947,6 +962,13 @@ packages:
|
|||
engines: { node: ">=0.10.0" }
|
||||
dev: true
|
||||
|
||||
/normalize.css@8.0.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==,
|
||||
}
|
||||
dev: false
|
||||
|
||||
/once@1.4.0:
|
||||
resolution:
|
||||
{
|
||||
|
@ -1106,6 +1128,19 @@ packages:
|
|||
rimraf: 2.7.1
|
||||
dev: true
|
||||
|
||||
/sass@1.66.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==,
|
||||
}
|
||||
engines: { node: ">=14.0.0" }
|
||||
hasBin: true
|
||||
dependencies:
|
||||
chokidar: 3.5.3
|
||||
immutable: 4.3.4
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/sorcery@0.11.0:
|
||||
resolution:
|
||||
{
|
||||
|
@ -1137,7 +1172,7 @@ packages:
|
|||
min-indent: 1.0.1
|
||||
dev: true
|
||||
|
||||
/svelte-check@3.4.6(svelte@4.0.5):
|
||||
/svelte-check@3.4.6(sass@1.66.1)(svelte@4.0.5):
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-OBlY8866Zh1zHQTkBMPS6psPi7o2umTUyj6JWm4SacnIHXpWFm658pG32m3dKvKFL49V4ntAkfFHKo4ztH07og==,
|
||||
|
@ -1153,7 +1188,7 @@ packages:
|
|||
picocolors: 1.0.0
|
||||
sade: 1.8.1
|
||||
svelte: 4.0.5
|
||||
svelte-preprocess: 5.0.4(svelte@4.0.5)(typescript@5.2.2)
|
||||
svelte-preprocess: 5.0.4(sass@1.66.1)(svelte@4.0.5)(typescript@5.2.2)
|
||||
typescript: 5.2.2
|
||||
transitivePeerDependencies:
|
||||
- "@babel/core"
|
||||
|
@ -1179,7 +1214,7 @@ packages:
|
|||
svelte: 4.0.5
|
||||
dev: true
|
||||
|
||||
/svelte-preprocess@5.0.4(svelte@4.0.5)(typescript@5.2.2):
|
||||
/svelte-preprocess@5.0.4(sass@1.66.1)(svelte@4.0.5)(typescript@5.2.2):
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==,
|
||||
|
@ -1223,6 +1258,7 @@ packages:
|
|||
"@types/pug": 2.0.6
|
||||
detect-indent: 6.1.0
|
||||
magic-string: 0.27.0
|
||||
sass: 1.66.1
|
||||
sorcery: 0.11.0
|
||||
strip-indent: 3.0.0
|
||||
svelte: 4.0.5
|
||||
|
@ -1286,7 +1322,7 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/vite@4.4.5:
|
||||
/vite@4.4.5(sass@1.66.1):
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-4m5kEtAWHYr0O1Fu7rZp64CfO1PsRGZlD3TAB32UmQlpd7qg15VF7ROqGN5CyqN7HFuwr7ICNM2+fDWRqFEKaA==,
|
||||
|
@ -1320,6 +1356,7 @@ packages:
|
|||
esbuild: 0.18.20
|
||||
postcss: 8.4.29
|
||||
rollup: 3.28.1
|
||||
sass: 1.66.1
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
@ -1335,7 +1372,7 @@ packages:
|
|||
vite:
|
||||
optional: true
|
||||
dependencies:
|
||||
vite: 4.4.5
|
||||
vite: 4.4.5(sass@1.66.1)
|
||||
dev: true
|
||||
|
||||
/wrappy@1.0.2:
|
||||
|
|
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.19
|
|||
require (
|
||||
emperror.dev/errors v0.8.1
|
||||
github.com/BurntSushi/toml v1.2.1
|
||||
github.com/flosch/pongo2/v6 v6.0.0
|
||||
github.com/georgysavva/scany/v2 v2.0.0
|
||||
github.com/go-chi/chi/v5 v5.0.8
|
||||
github.com/go-chi/render v1.0.2
|
||||
|
|
2
go.sum
2
go.sum
|
@ -102,6 +102,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU=
|
||||
github.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
|
|
16
package.json
Normal file
16
package.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "mercury",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"watch:style": "sass -I . -w assets/scss/:web/frontend/assets/css/ --style compressed"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "sam <sam@sleepycat.moe>",
|
||||
"license": "APGL-3.0-only",
|
||||
"devDependencies": {
|
||||
"normalize.css": "^8.0.1",
|
||||
"sass": "^1.66.1"
|
||||
}
|
||||
}
|
1028
pnpm-lock.yaml
Normal file
1028
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
packages:
|
||||
- .
|
||||
- frontend
|
|
@ -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,8 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{.Config.Name}}</title>
|
||||
|
||||
{{.Vue.RenderTags}}
|
||||
|
|
|
@ -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…
Reference in a new issue