Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add additional <meta> tags to <head> #16

Merged
merged 1 commit into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions cmd/web/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,33 @@ import (
"runtime/debug"
)

// aboutHandler displays the about page.
func (app *application) aboutHandler(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r)
data.Description = "About website"
data.ImageUrl = "/static/images/default_og_image.png"
data.PageType = "website"
data.Title = "About"
app.render(w, r, http.StatusOK, "home.tmpl", data)
}

// homeHandler displays the home page.
func (app *application) homeHandler(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r)
data.Description = "Homepage of a website"
data.ImageUrl = "/static/images/default_og_image.png"
data.PageType = "website"
data.Title = "Home"
app.render(w, r, http.StatusOK, "home.tmpl", data)
}

// notFoundHandler displays a 404 page.
func (app *application) notFoundHandler(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r)
data.Description = "404 page"
data.ImageUrl = "/static/images/default_og_image.png"
data.PageType = "website"
data.Title = "Not Found"
app.render(w, r, http.StatusNotFound, "404.tmpl", data)
}

Expand All @@ -25,5 +43,9 @@ func (app *application) serverErrorHandler(w http.ResponseWriter, r *http.Reques
return
}
data := app.newTemplateData(r)
data.Description = "Server error"
data.ImageUrl = "/static/images/default_og_image.png"
data.PageType = "website"
data.Title = "Server Error"
app.render(w, r, http.StatusInternalServerError, "500.tmpl", data)
}
14 changes: 2 additions & 12 deletions cmd/web/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"

"github.com/julienschmidt/httprouter"

"github.com/rynhndrcksn/go-starter-site/ui"
)

Expand All @@ -23,19 +24,8 @@ func (app *application) routes() http.Handler {

// Register routes.
router.HandlerFunc(http.MethodGet, "/", app.homeHandler)
router.HandlerFunc(http.MethodGet, "/about", app.aboutHandler)
router.Handler(http.MethodGet, "/debug/vars", expvar.Handler())

return app.recoverPanic(app.logRequest(app.commonHeaders(router)))
}

func (app *application) routeThatPanics() http.Handler {
// Initialize new httprouter instance.
router := httprouter.New()

// Register route to test against:
router.HandlerFunc(http.MethodGet, "/server-error", func(writer http.ResponseWriter, r *http.Request) {
panic("this triggers a 500 status page")
})

return app.recoverPanic(router)
}
33 changes: 29 additions & 4 deletions cmd/web/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"io/fs"
"net/http"
"path/filepath"
"strings"
"time"

"github.com/rynhndrcksn/go-starter-site/internal/env"
"github.com/rynhndrcksn/go-starter-site/ui"
)

Expand Down Expand Up @@ -55,15 +57,23 @@ func props(pairs ...any) (map[string]any, error) {

// templateData holds dynamic data that can be passed to the HTML templates.
type templateData struct {
CurrentYear int
Flash string
CanonicalUrl string
CurrentYear int
Description string
Flash string
ImageUrl string
PageType string
SiteName string
Title string
}

// newTemplateData initializes a new templateData struct and returns it.
func (app *application) newTemplateData(r *http.Request) templateData {
return templateData{
CurrentYear: time.Now().Year(),
Flash: app.sessionManager.PopString(r.Context(), "flash"),
CanonicalUrl: getCanonicalURL(r),
CurrentYear: time.Now().Year(),
Flash: app.sessionManager.PopString(r.Context(), "flash"),
SiteName: env.GetStringOrDefault("SITE_NAME", "Site"),
}
}

Expand Down Expand Up @@ -106,3 +116,18 @@ func newTemplateCache() (map[string]*template.Template, error) {

return cache, nil
}

// getCanonicalURL creates the canonical URL and returns it.
func getCanonicalURL(r *http.Request) string {
// Get the full URL from the request
scheme := "https"

// Remove www if present and clean the host
host := r.Host
host = strings.TrimPrefix(host, "www.")

// Build the canonical URL without query parameters
canonicalURL := scheme + "://" + host + r.URL.Path

return canonicalURL
}
13 changes: 13 additions & 0 deletions cmd/web/testutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/alexedwards/scs/v2"
"github.com/alexedwards/scs/v2/memstore"
"github.com/julienschmidt/httprouter"
)

// newTestApplication creates a new application struct containing mocked dependencies.
Expand Down Expand Up @@ -90,3 +91,15 @@ func (ts *testServer) get(t *testing.T, urlPath string) (int, http.Header, strin

return rs.StatusCode, rs.Header, string(body)
}

func (app *application) routeThatPanics() http.Handler {
// Initialize new httprouter instance.
router := httprouter.New()

// Register route to test against:
router.HandlerFunc(http.MethodGet, "/server-error", func(writer http.ResponseWriter, r *http.Request) {
panic("this triggers a 500 status page")
})

return app.recoverPanic(router)
}
42 changes: 34 additions & 8 deletions ui/html/base.tmpl
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
{{- /*gotype: github.com/rynhndrcksn/go-starter-site/cmd/web.templateData*/ -}}
{{define "base"}}
<!doctype html>
<html lang="en">
<head>
<head prefix="og: https://ogp.me/ns#">
<meta charset="utf-8">
<title>{{template "title" .}} - Site</title>
<title>{{ .Title }} - {{ .SiteName }}</title>

<!-- Make the search engine overlords happy -->
<link rel="canonical" href="{{ .CanonicalUrl }}">
<meta name="description" content="{{ .Description }}">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="keyword" content="">

<!-- Open Graph -->
<meta property="og:site_name" content="{{ .SiteName }}">
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{ .Description }}">
<meta property="og:type" content="{{ .PageType }}">
<meta property="og:url" content="{{ .CanonicalUrl }}">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="{{ .ImageUrl }}">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<!-- Why no og:image:alt? Read this: https://yoast.com/developer-blog/why-we-dont-set-the-og-image-alt-tag/ -->

<!-- Twitter/X-->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ .Title }}">
<meta name="twitter:description" content="{{ .Description }}">
<meta name="twitter:image" content="{{ .ImageUrl }}">
<meta name="twitter:image:width" content="1200">
<meta name="twitter:image:height" content="630">
<!-- Why no twitter:image:alt? Read this: https://yoast.com/developer-blog/why-we-dont-set-the-og-image-alt-tag/ -->

<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="/static/css/main.css">
<link rel="shortcut icon" href="/static/img/favicon.ico" type="image/x-icon">
</head>
<body>
<header>
<h1><a href='/'>Home</a></h1>
</header>
{{template "nav" .}}
{{template "header" .}}
<main>
{{with .Flash}}
<div class="flash">{{.}}</div>
{{end}}
{{template "main" .}}
</main>
{{template "footer" .}}
<script src="/static/js/main.js" type="text/javascript" async defer></script>
<script src="/static/js/main.js" async defer></script>
</body>
</html>
{{end}}
2 changes: 1 addition & 1 deletion ui/html/components/nav-link.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{{define "nav-link"}}
<a href="{{.Link}}">{{.Text}}</a>
<a href="{{ .Link }}" class="{{ .Classes }}">{{ .Text }}</a>
{{end}}
2 changes: 0 additions & 2 deletions ui/html/pages/404.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{{define "title"}}Not Found{{end}}

{{define "main"}}
<p>We were unable to find what you were looking for! Want to go back <a href="/">home</a>?</p>
{{end}}
2 changes: 0 additions & 2 deletions ui/html/pages/500.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{{define "title"}}Server Error{{end}}

{{define "main"}}
<p>We encountered an unexpected error! Want to go back <a href="/">home</a>?</p>
{{end}}
3 changes: 3 additions & 0 deletions ui/html/pages/about.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{define "main"}}
<h1>There's nothing to read about yet!</h1>
{{end}}
2 changes: 0 additions & 2 deletions ui/html/pages/home.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{{define "title"}}Home{{end}}

{{define "main"}}
<h1>There's nothing to see here yet!</h1>
{{end}}
2 changes: 1 addition & 1 deletion ui/html/partials/footer.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{define "footer"}}
<footer>
<div>Powered by <a href="https://go.dev/" target="_blank">Go</a> in {{.CurrentYear}}</div>
<div>Powered by <a href="https://go.dev/" target="_blank">Go</a> in {{ .CurrentYear }}</div>
</footer>
{{end}}
5 changes: 5 additions & 0 deletions ui/html/partials/header.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{define "header"}}
<header>
{{template "nav" .}}
</header>
{{end}}
6 changes: 2 additions & 4 deletions ui/html/partials/nav.tmpl
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{{define "nav"}}
<nav>
<div>
{{template "nav-link" (props "Link" "/" "Text" "Home")}}
{{template "nav-link" (props "Link" "/about" "Text" "About")}}
</div>
{{template "nav-link" (props "Link" "/" "Text" "Home" "Classes" "home")}}
{{template "nav-link" (props "Link" "/about" "Text" "About" "Classes" "")}}
</nav>
{{end}}
3 changes: 3 additions & 0 deletions ui/static/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading