diff options
| author | Felix Hanley <felix@userspace.com.au> | 2020-02-19 02:17:11 +0000 |
|---|---|---|
| committer | Felix Hanley <felix@userspace.com.au> | 2020-02-19 02:17:11 +0000 |
| commit | ee02835f27fc7bd222a34d86cafbd723b05946c0 (patch) | |
| tree | d918b796f7552ec8f81dea740670659d254c9b90 | |
| parent | 5c23a2bfb751f2435d9d6ebfa4e168b115988f0b (diff) | |
| download | sws-ee02835f27fc7bd222a34d86cafbd723b05946c0.tar.gz sws-ee02835f27fc7bd222a34d86cafbd723b05946c0.tar.bz2 | |
Update templates to nest correctly
| -rw-r--r-- | cmd/server/handlers.go | 15 | ||||
| -rw-r--r-- | cmd/server/main.go | 40 | ||||
| -rw-r--r-- | cmd/server/sites.go | 15 | ||||
| -rw-r--r-- | go.mod | 21 | ||||
| -rw-r--r-- | public/default.css | 70 | ||||
| -rw-r--r-- | templates/charts.tmpl (renamed from templates/partials/barChart.tmpl) | 2 | ||||
| -rw-r--r-- | templates/gen.go | 4 | ||||
| -rw-r--r-- | templates/home.tmpl | 5 | ||||
| -rw-r--r-- | templates/layouts/base.tmpl | 24 | ||||
| -rw-r--r-- | templates/layouts/public.tmpl | 16 | ||||
| -rw-r--r-- | templates/partials/navMain.tmpl | 8 | ||||
| -rw-r--r-- | templates/partials/navService.tmpl | 5 | ||||
| -rw-r--r-- | templates/partials/pageFoot.tmpl | 4 | ||||
| -rw-r--r-- | templates/partials/pageForList.tmpl | 7 | ||||
| -rw-r--r-- | templates/partials/pageHead.tmpl | 10 | ||||
| -rw-r--r-- | templates/partials/siteForList.tmpl | 7 | ||||
| -rw-r--r-- | templates/site.tmpl | 27 | ||||
| -rw-r--r-- | templates/sites.tmpl | 31 |
18 files changed, 191 insertions, 120 deletions
diff --git a/cmd/server/handlers.go b/cmd/server/handlers.go index de3bfa3..e47fd30 100644 --- a/cmd/server/handlers.go +++ b/cmd/server/handlers.go @@ -1,20 +1,25 @@ package main import ( - "html/template" "net/http" ) -func handleIndex(tmpls *template.Template) http.HandlerFunc { +func handleIndex(rndr Renderer) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") - tmpls.ExecuteTemplate(w, "home", nil) + if err := rndr.Render(w, "home", nil); err != nil { + log(err) + http.Error(w, http.StatusText(500), 500) + } } } -func handleExample(tmpls *template.Template) http.HandlerFunc { +func handleExample(rndr Renderer) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") - tmpls.ExecuteTemplate(w, "example", nil) + if err := rndr.Render(w, "example", nil); err != nil { + log(err) + http.Error(w, http.StatusText(500), 500) + } } } diff --git a/cmd/server/main.go b/cmd/server/main.go index 386247e..d23fb8f 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -4,7 +4,6 @@ import ( "context" "flag" "fmt" - "html/template" "net/http" "os" "path/filepath" @@ -19,6 +18,7 @@ import ( _ "github.com/mattn/go-sqlite3" "src.userspace.com.au/sws" "src.userspace.com.au/sws/store" + "src.userspace.com.au/templates" ) // Flags @@ -44,6 +44,10 @@ func init() { debug = func(v ...interface{}) {} } +type Renderer interface { + Render(http.ResponseWriter, string, interface{}) error +} + func main() { flag.Parse() @@ -91,18 +95,18 @@ func main() { st = store.NewSqlite3Store(db) } - tmpls := template.Must(loadTemplateHTML([]string{ - "home", - "sites", - "example", - "partials/navMain", - "partials/pageHead", - "partials/pageFoot", - "partials/siteForList", - "partials/pageForList", - "partials/barChart", - }, funcMap)) - debug(tmpls.DefinedTemplates()) + tmpls, err := LoadHTMLTemplateMap(map[string][]string{ + "sites": []string{"layouts/base", "sites", "charts"}, + "site": []string{"layouts/base", "site", "charts"}, + "home": []string{"layouts/public", "home"}, + "example": []string{"example"}, + }, funcMap) + if err != nil { + log(err) + os.Exit(1) + } + //debug(tmpls.DefinedTemplates()) + renderer := templates.NewRenderer(tmpls) r := chi.NewRouter() r.Use(middleware.RequestID) @@ -121,10 +125,10 @@ func main() { // For UI r.Get("/hits", handleHits(st)) r.Route("/sites", func(r chi.Router) { - r.Get("/", handleSites(st, tmpls)) + r.Get("/", handleSites(st, renderer)) r.Route("/{siteID}", func(r chi.Router) { r.Use(siteCtx) - r.Get("/", handleSite(st, tmpls)) + r.Get("/", handleSite(st, renderer)) r.Route("/sparklines", func(r chi.Router) { r.Get("/{b:\\d+}-{e:\\d+}.svg", sparklineHandler(st)) }) @@ -143,11 +147,11 @@ func main() { } // Example - r.Get("/test.html", handleExample(tmpls)) - r.Get("/test-again.html", handleExample(tmpls)) + r.Get("/test.html", handleExample(renderer)) + r.Get("/test-again.html", handleExample(renderer)) r.Route("/", func(r chi.Router) { - r.Get("/", handleIndex(tmpls)) + r.Get("/", handleIndex(renderer)) fileServer(r, filepath.Dir(staticPath), "/", http.Dir(staticPath)) }) diff --git a/cmd/server/sites.go b/cmd/server/sites.go index 7e5cacd..1dc265e 100644 --- a/cmd/server/sites.go +++ b/cmd/server/sites.go @@ -1,14 +1,13 @@ package main import ( - "html/template" "net/http" "time" "src.userspace.com.au/sws" ) -func handleSites(db sws.SiteStore, tmpls *template.Template) http.HandlerFunc { +func handleSites(db sws.SiteStore, rndr Renderer) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { sites, err := db.GetSites() if err != nil { @@ -20,11 +19,14 @@ func handleSites(db sws.SiteStore, tmpls *template.Template) http.HandlerFunc { }{ Sites: sites, } - tmpls.ExecuteTemplate(w, "sites", payload) + if err := rndr.Render(w, "sites", payload); err != nil { + log(err) + http.Error(w, http.StatusText(500), 500) + } } } -func handleSite(db sws.SiteStore, tmpls *template.Template) http.HandlerFunc { +func handleSite(db sws.SiteStore, rndr Renderer) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() site, ok := ctx.Value("site").(*sws.Site) @@ -64,6 +66,9 @@ func handleSite(db sws.SiteStore, tmpls *template.Template) http.HandlerFunc { Pages: pages, Hits: buckets, } - tmpls.ExecuteTemplate(w, "site", payload) + if err := rndr.Render(w, "site", payload); err != nil { + log(err) + http.Error(w, http.StatusText(500), 500) + } } } @@ -1,26 +1,19 @@ module src.userspace.com.au/sws require ( - github.com/blend/go-sdk v2.0.0+incompatible // indirect - github.com/cockroachdb/apd v1.1.0 // indirect - github.com/go-chi/chi v3.3.3+incompatible + github.com/go-chi/chi v4.0.3+incompatible github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect - github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect - github.com/jackc/pgx v3.3.0+incompatible + github.com/jackc/pgx v3.6.2+incompatible github.com/jmoiron/sqlx v1.2.0 - github.com/kr/pretty v0.2.0 // indirect - github.com/lib/pq v1.3.0 // indirect - github.com/mattn/go-sqlite3 v1.10.0 - github.com/pkg/errors v0.8.0 // indirect - github.com/satori/go.uuid v1.2.0 // indirect - github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 // indirect + github.com/mattn/go-sqlite3 v2.0.3+incompatible + github.com/pkg/errors v0.9.1 // indirect github.com/speps/go-hashids v2.0.0+incompatible github.com/wcharczuk/go-chart v2.0.1+incompatible + golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 // indirect golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect - google.golang.org/appengine v1.6.5 // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + golang.org/x/text v0.3.2 // indirect src.userspace.com.au/go-migrate v0.0.0-20200208102934-cf11cf76db3f - src.userspace.com.au/templates v0.0.0-20200214092258-6bc0451a1d45 + src.userspace.com.au/templates v0.0.0-20200219010204-50adadd75f25 ) go 1.13 diff --git a/public/default.css b/public/default.css index f424a07..42f5b81 100644 --- a/public/default.css +++ b/public/default.css @@ -1,10 +1,53 @@ +body { + background-color: #fffaf7; + display: flex; + flex-direction: column; + font-family: Liberation Sans, Arial, sans-serif; + line-height: 1.5; + min-height: 100vh; + margin: 0; +} +ul { + list-style: none; + padding: 0; +} +.page { + display: flex; + display: flex; + flex-direction: column; + outline: 1px solid red; +} +.sidebar { + flex: 0 0 12em; + order: -1; + outline: 1px solid red; +} +main { + flex: 1; + outline: 1px solid red; +} + +@media (min-width: 768px) { + .page { + flex-direction: row; + flex: 1; + } + main { + flex: 1; + } + .sidebar { + /* 12em is the width of the columns */ + flex: 0 0 12em; + } +} + .chart { align-items: stretch; display: flex; - height: 200px; - list-style: none; + height: 100px; margin: 0; - padding: 0; + padding-top: 2em; + padding-bottom: 2em; width: 100%; } .chart .slot { @@ -12,29 +55,42 @@ flex: 1 1; position: relative; } +.chart .slot.midnight { + border-left: 1px solid #ddd; +} +.chart .slot:hover { + background: #f5f5f5; +} .chart .bar { background: #4c92ff; + border-top-left-radius: 3px; + border-top-right-radius: 3px; bottom: 0; left: 0; position: absolute; right: 0; } +.chart .slot:hover .bar { + background: #88b6ff; +} .chart .slot:before, .chart .slot:after { bottom: 100%; - content: attr(data-date); + content: attr(data-count); display: none; + font-size: .75em; left: 50%; margin-bottom: .5rem; - margin-left: -5rem; + margin-left: -2.5rem; position: absolute; text-align: center; - width: 10rem; + width: 5rem; } +/* time */ .chart .slot:after { + content: attr(data-date); margin-top: .5rem; top: 100%; - content: attr(data-count) " hits"; } .chart .slot:hover:before, .chart .slot:hover:after { diff --git a/templates/partials/barChart.tmpl b/templates/charts.tmpl index d8a3db8..aa4ca65 100644 --- a/templates/partials/barChart.tmpl +++ b/templates/charts.tmpl @@ -2,7 +2,7 @@ <ul class="chart"> {{ $max := .CountMax }} {{ range .Buckets }} - <li class="slot" data-date="{{ .Time|timeHour }}" data-count="{{ .Count }}"> + <li class="slot{{ if eq .Time.Hour 0 }} midnight{{ end }}" data-date="{{ .Time|timeHour }}" data-count="{{ .Count }}" data-percent="{{ percent .Count $max }}"> <div class="bar" style="height:{{ percent .Count $max }}%" /> </li> {{ end }} diff --git a/templates/gen.go b/templates/gen.go index 81811a9..5fe1f3e 100644 --- a/templates/gen.go +++ b/templates/gen.go @@ -9,7 +9,9 @@ import ( ) func main() { - tmpl := templates.Must(templates.New(templates.EnableHTMLTemplates())) + tmpl := templates.Must(templates.New( + templates.EnableHTMLTemplates(), + )) if _, err := tmpl.WriteTo(os.Stdout); err != nil { panic(err) } diff --git a/templates/home.tmpl b/templates/home.tmpl index d95845a..7920916 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -1,8 +1,5 @@ -{{ define "home" }} - {{ template "pageHead" }} - {{ template "navMain" }} +{{ define "content" }} <main> home page </main> - {{ template "pageFoot" }} {{ end }} diff --git a/templates/layouts/base.tmpl b/templates/layouts/base.tmpl new file mode 100644 index 0000000..1b7f9ad --- /dev/null +++ b/templates/layouts/base.tmpl @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html lang="en-au"> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Simple Web Stats</title> + <link rel="stylesheet" href="/default.css"> + </head> + <body> + <header class="site"> + </header> + <div class="page"> + <div class="sidebar"> + <nav> + <a href="/">Home</a> + <a href="/sites">Sites</a> + <a href="/sites/new">New site</a> + <a href="/logout">Logout</a> + </nav> + </div> + {{ template "content" . }} + </div> + <footer></footer> + </body> +</html> diff --git a/templates/layouts/public.tmpl b/templates/layouts/public.tmpl new file mode 100644 index 0000000..98a03c2 --- /dev/null +++ b/templates/layouts/public.tmpl @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html lang="en-au"> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Simple Web Stats</title> + <link rel="stylesheet" href="/default.css"> + </head> + <body> + <header class="site"> + </header> + <div class="page"> + {{ template "content" . }} + </div> + <footer></footer> + </body> +</html> diff --git a/templates/partials/navMain.tmpl b/templates/partials/navMain.tmpl deleted file mode 100644 index e74f015..0000000 --- a/templates/partials/navMain.tmpl +++ /dev/null @@ -1,8 +0,0 @@ -{{ define "navMain" }} -<nav> - <a href="/">Home</a> - <a href="/sites">Sites</a> - <a href="/sites/new">New site</a> - <a href="/logout">Logout</a> -</nav> -{{ end }} diff --git a/templates/partials/navService.tmpl b/templates/partials/navService.tmpl deleted file mode 100644 index 66ef680..0000000 --- a/templates/partials/navService.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -{{ define "navService" }} -<nav> - <a href="">Stats</a> -</nav> -{{ end }} diff --git a/templates/partials/pageFoot.tmpl b/templates/partials/pageFoot.tmpl deleted file mode 100644 index d054b3d..0000000 --- a/templates/partials/pageFoot.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -{{ define "pageFoot" }} - </body> -</html> -{{ end }} diff --git a/templates/partials/pageForList.tmpl b/templates/partials/pageForList.tmpl deleted file mode 100644 index a1d52f5..0000000 --- a/templates/partials/pageForList.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -{{ define "pageForList" }} -<li> - <span class="path">{{ .Path }}</a> - <span class="title">{{ .Title }}</span> - <span class="last-visit">{{ .LastVisitedAt.Unix }}</span> -</li> -{{ end }} diff --git a/templates/partials/pageHead.tmpl b/templates/partials/pageHead.tmpl deleted file mode 100644 index 6605a0b..0000000 --- a/templates/partials/pageHead.tmpl +++ /dev/null @@ -1,10 +0,0 @@ -{{ define "pageHead" }} -<!DOCTYPE html> -<html lang="en-au"> - <head> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Simple Web Stats</title> - <link rel="stylesheet" href="/default.css"> - </head> - <body> -{{ end }} diff --git a/templates/partials/siteForList.tmpl b/templates/partials/siteForList.tmpl deleted file mode 100644 index 2a33d24..0000000 --- a/templates/partials/siteForList.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -{{ define "siteForList" }} -<li> - <a href="/sites/{{ .ID }}/">{{ .Name }}</a> - <span>{{ .Description }}</span> - <img src="{{ sparkline .ID }}" /> -</li> -{{ end }} diff --git a/templates/site.tmpl b/templates/site.tmpl new file mode 100644 index 0000000..f52c9cd --- /dev/null +++ b/templates/site.tmpl @@ -0,0 +1,27 @@ +{{ define "content" }} + <main> + <header> + {{ with .Site }} + <h1>{{ .Name }}</h1> + <span>{{ .Description }}</span> + {{ end }} + </header> + <fig> + {{ template "barChart" .Hits }} + </fig> + <h2>Popular pages</h2> + <ul class="pages"> + {{ range .Pages }} + {{ template "pageForList" . }} + {{ end }} + </ul> + </main> +{{ end }} + +{{ define "pageForList" }} +<li> + <h4 class="path">{{ .Path }}</h4> + <span class="title">{{ .Title }}</span> + <span class="last-visit">{{ .LastVisitedAt.Unix }}</span> +</li> +{{ end }} diff --git a/templates/sites.tmpl b/templates/sites.tmpl index 0a4d015..c7a2002 100644 --- a/templates/sites.tmpl +++ b/templates/sites.tmpl @@ -1,6 +1,4 @@ -{{ define "sites" }} - {{ template "pageHead" }} - {{ template "navMain" }} +{{ define "content" }} <main> <header> <h1>Sites</h1> @@ -11,27 +9,12 @@ {{ end }} </ul> </main> - {{ template "pageFoot" }} {{ end }} -{{ define "site" }} - {{ template "pageHead" }} - {{ template "navMain" }} - <main> - <header> - {{ with .Site }} - <h1>{{ .Name }}</h1> - <span>{{ .Description }}</span> - {{ end }} - </header> - <fig> - {{ template "barChart" .Hits }} - </fig> - <ul class="pages"> - {{ range .Pages }} - {{ template "pageForList" . }} - {{ end }} - </ul> - </main> - {{ template "pageFoot" }} +{{ define "siteForList" }} +<li> + <a href="/sites/{{ .ID }}/">{{ .Name }}</a> + <span>{{ .Description }}</span> + <img src="{{ sparkline .ID }}" /> +</li> {{ end }} |
