✨feature: Set up templated views and blog support
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
bak/
|
||||||
20
content/blog/another-blog-post.md
Normal file
20
content/blog/another-blog-post.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: Go SSG - Another Blog Post
|
||||||
|
description: A longer summary of the post. Lorem ipsum dolor set amit.
|
||||||
|
date: 2025-04-19
|
||||||
|
categories:
|
||||||
|
- go
|
||||||
|
- anger
|
||||||
|
---
|
||||||
|
|
||||||
|
# Why isn't this working?! 😭
|
||||||
|
|
||||||
|
This is my first Go SSG blog post.
|
||||||
|
|
||||||
|
This project is a simple static site generator written in Go. It is designed to be easy to use and extend, allowing you to create a static website quickly and efficiently.
|
||||||
|
|
||||||
|
It supports features like:
|
||||||
|
|
||||||
|
- Markdown content
|
||||||
|
- Customizable templates
|
||||||
|
- Simple configuration
|
||||||
@@ -2,8 +2,19 @@
|
|||||||
title: Go SSG - My First Blog Post
|
title: Go SSG - My First Blog Post
|
||||||
description: A short summary of the post.
|
description: A short summary of the post.
|
||||||
date: 2025-04-19
|
date: 2025-04-19
|
||||||
|
categories:
|
||||||
|
- progrmming
|
||||||
|
- go
|
||||||
---
|
---
|
||||||
|
|
||||||
# *Tap Tap Tap* Is this thing on?
|
# *Tap Tap Tap* Is this thing on?
|
||||||
|
|
||||||
This is my first blog post!
|
This is my first Go SSG blog post.
|
||||||
|
|
||||||
|
This project is a simple static site generator written in Go. It is designed to be easy to use and extend, allowing you to create a static website quickly and efficiently.
|
||||||
|
|
||||||
|
It supports features like:
|
||||||
|
|
||||||
|
- Markdown content
|
||||||
|
- Customizable templates
|
||||||
|
- Simple configuration
|
||||||
|
|||||||
138
main.go
138
main.go
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,6 +8,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -14,26 +16,27 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NavItem represents a navigation link
|
|
||||||
type NavItem struct {
|
type NavItem struct {
|
||||||
Title string
|
Title string
|
||||||
URL string
|
URL string
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageMeta holds front matter metadata
|
|
||||||
type PageMeta struct {
|
type PageMeta struct {
|
||||||
Title string `yaml:"title"`
|
Title string `yaml:"title"`
|
||||||
Description string `yaml:"description"`
|
Description string `yaml:"description"`
|
||||||
Date string `yaml:"date"`
|
Date string `yaml:"date"`
|
||||||
Slug string // we'll set this ourselves from filename
|
Categories []string `yaml:"categories"`
|
||||||
|
Slug string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var slugRegex = regexp.MustCompile(`[^a-z0-9]+`)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
contentDir := "./content"
|
contentDir := "./content"
|
||||||
outputDir := "./public"
|
outputDir := "./public"
|
||||||
templateFile := "./templates/layout.html"
|
|
||||||
|
|
||||||
tpl, err := template.ParseFiles(templateFile)
|
// Load all templates in the templates folder
|
||||||
|
tpl, err := template.New("").Funcs(templateFuncs()).ParseGlob("templates/*.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Template parsing error: %v\n", err)
|
fmt.Printf("Template parsing error: %v\n", err)
|
||||||
return
|
return
|
||||||
@@ -45,7 +48,6 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect nav info early
|
|
||||||
var nav []NavItem
|
var nav []NavItem
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if filepath.Ext(file.Name()) == ".md" {
|
if filepath.Ext(file.Name()) == ".md" {
|
||||||
@@ -54,26 +56,18 @@ func main() {
|
|||||||
if name != "index" {
|
if name != "index" {
|
||||||
url = "/" + name + "/"
|
url = "/" + name + "/"
|
||||||
}
|
}
|
||||||
nav = append(nav, NavItem{
|
nav = append(nav, NavItem{Title: strings.Title(name), URL: url})
|
||||||
Title: strings.Title(name),
|
|
||||||
URL: url,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add blog to the main nav
|
// Add blog to main nav
|
||||||
nav = append(nav, NavItem{
|
nav = append(nav, NavItem{Title: "Blog", URL: "/blog/"})
|
||||||
Title: "Blog",
|
|
||||||
URL: "/blog/",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Generate index.html for each static page markdown file
|
// Static page rendering
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if filepath.Ext(file.Name()) != ".md" {
|
if filepath.Ext(file.Name()) == ".md" {
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
||||||
|
title := strings.Title(name)
|
||||||
mdPath := filepath.Join(contentDir, file.Name())
|
mdPath := filepath.Join(contentDir, file.Name())
|
||||||
rawContent, err := ioutil.ReadFile(mdPath)
|
rawContent, err := ioutil.ReadFile(mdPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -83,8 +77,10 @@ func main() {
|
|||||||
|
|
||||||
meta, content := parseFrontMatter(rawContent)
|
meta, content := parseFrontMatter(rawContent)
|
||||||
htmlContent := blackfriday.Run(content)
|
htmlContent := blackfriday.Run(content)
|
||||||
|
if meta.Title == "" {
|
||||||
|
meta.Title = title
|
||||||
|
}
|
||||||
|
|
||||||
// Determine output path
|
|
||||||
var outPath string
|
var outPath string
|
||||||
if name == "index" {
|
if name == "index" {
|
||||||
outPath = filepath.Join(outputDir, "index.html")
|
outPath = filepath.Join(outputDir, "index.html")
|
||||||
@@ -100,31 +96,23 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall back to filename for title if none provided
|
tpl.ExecuteTemplate(outFile, "static_page", map[string]interface{}{
|
||||||
if meta.Title == "" {
|
|
||||||
meta.Title = strings.Title(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
data := map[string]interface{}{
|
|
||||||
"Title": meta.Title,
|
"Title": meta.Title,
|
||||||
"Description": meta.Description,
|
"Description": meta.Description,
|
||||||
"Date": meta.Date,
|
"Date": meta.Date,
|
||||||
|
"Categories": meta.Categories,
|
||||||
"Content": template.HTML(htmlContent),
|
"Content": template.HTML(htmlContent),
|
||||||
"Nav": nav,
|
"Nav": nav,
|
||||||
"Year": time.Now().Year(),
|
"Year": time.Now().Year(),
|
||||||
}
|
"PageTemplate": "static",
|
||||||
|
})
|
||||||
err = tpl.Execute(outFile, data)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Template execution failed for %s: %v\n", file.Name(), err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Generated: %s\n", outPath)
|
fmt.Printf("Generated: %s\n", outPath)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Generate blog index
|
|
||||||
var blogPosts []PageMeta
|
var blogPosts []PageMeta
|
||||||
|
categoryMap := make(map[string][]PageMeta)
|
||||||
|
|
||||||
blogDir := filepath.Join(contentDir, "blog")
|
blogDir := filepath.Join(contentDir, "blog")
|
||||||
blogFiles, _ := ioutil.ReadDir(blogDir)
|
blogFiles, _ := ioutil.ReadDir(blogDir)
|
||||||
@@ -144,12 +132,16 @@ func main() {
|
|||||||
|
|
||||||
meta, content := parseFrontMatter(rawContent)
|
meta, content := parseFrontMatter(rawContent)
|
||||||
html := blackfriday.Run(content)
|
html := blackfriday.Run(content)
|
||||||
|
|
||||||
meta.Slug = slug
|
meta.Slug = slug
|
||||||
if meta.Title == "" {
|
if meta.Title == "" {
|
||||||
meta.Title = strings.Title(slug)
|
meta.Title = strings.Title(slug)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, cat := range meta.Categories {
|
||||||
|
slug := slugify(cat)
|
||||||
|
categoryMap[slug] = append(categoryMap[slug], meta)
|
||||||
|
}
|
||||||
|
|
||||||
outPath := filepath.Join(outputDir, "blog", slug, "index.html")
|
outPath := filepath.Join(outputDir, "blog", slug, "index.html")
|
||||||
os.MkdirAll(filepath.Dir(outPath), os.ModePerm)
|
os.MkdirAll(filepath.Dir(outPath), os.ModePerm)
|
||||||
|
|
||||||
@@ -159,47 +151,54 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tpl.Execute(outFile, map[string]interface{}{
|
tpl.ExecuteTemplate(outFile, "blog_post_page", map[string]interface{}{
|
||||||
"Title": meta.Title,
|
"Title": meta.Title,
|
||||||
"Description": meta.Description,
|
"Description": meta.Description,
|
||||||
"Date": meta.Date,
|
"Date": meta.Date,
|
||||||
|
"Categories": meta.Categories,
|
||||||
"Content": template.HTML(html),
|
"Content": template.HTML(html),
|
||||||
"Nav": nav,
|
"Nav": nav,
|
||||||
"Year": time.Now().Year(),
|
"Year": time.Now().Year(),
|
||||||
|
"PageTemplate": "blog_post",
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Template error for blog post %s: %v\n", file.Name(), err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
blogPosts = append(blogPosts, meta)
|
blogPosts = append(blogPosts, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = buildBlogIndex(blogPosts, tpl, outputDir, nav)
|
buildBlogIndex(blogPosts, tpl, outputDir, nav)
|
||||||
|
|
||||||
|
for catSlug, posts := range categoryMap {
|
||||||
|
outDir := filepath.Join(outputDir, "blog", "category", catSlug)
|
||||||
|
os.MkdirAll(outDir, os.ModePerm)
|
||||||
|
|
||||||
|
outPath := filepath.Join(outDir, "index.html")
|
||||||
|
outFile, err := os.Create(outPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to build blog index:", err)
|
fmt.Printf("Failed to create category page for %s: %v\n", catSlug, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl.ExecuteTemplate(outFile, "category_page", map[string]interface{}{
|
||||||
|
"Title": "Category: " + strings.Title(strings.ReplaceAll(catSlug, "-", " ")),
|
||||||
|
"Posts": posts,
|
||||||
|
"Nav": nav,
|
||||||
|
"Year": time.Now().Year(),
|
||||||
|
"PageTemplate": "category_page",
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Printf("Generated category: /blog/category/%s/\n", catSlug)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ Site generation complete.")
|
fmt.Println("✅ Site generation complete.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFrontMatter splits raw markdown into meta + content
|
|
||||||
func parseFrontMatter(raw []byte) (PageMeta, []byte) {
|
func parseFrontMatter(raw []byte) (PageMeta, []byte) {
|
||||||
var meta PageMeta
|
var meta PageMeta
|
||||||
|
|
||||||
// Normalize line endings
|
|
||||||
raw = bytes.ReplaceAll(raw, []byte("\r\n"), []byte("\n"))
|
raw = bytes.ReplaceAll(raw, []byte("\r\n"), []byte("\n"))
|
||||||
|
|
||||||
// Only try to parse if the file starts with "---\n"
|
|
||||||
if bytes.HasPrefix(raw, []byte("---\n")) {
|
if bytes.HasPrefix(raw, []byte("---\n")) {
|
||||||
// Split after the first two "---\n" lines
|
|
||||||
parts := bytes.SplitN(raw, []byte("---\n"), 3)
|
parts := bytes.SplitN(raw, []byte("---\n"), 3)
|
||||||
|
if len(parts) == 3 {
|
||||||
if len(parts) >= 3 {
|
|
||||||
// parts[0] = empty (before first ---)
|
|
||||||
// parts[1] = YAML content
|
|
||||||
// parts[2] = remaining markdown content
|
|
||||||
err := yaml.Unmarshal(parts[1], &meta)
|
err := yaml.Unmarshal(parts[1], &meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("⚠️ Failed to parse front matter: %v\n", err)
|
fmt.Printf("⚠️ Failed to parse front matter: %v\n", err)
|
||||||
@@ -208,26 +207,39 @@ func parseFrontMatter(raw []byte) (PageMeta, []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no front matter, return raw as-is
|
|
||||||
return meta, raw
|
return meta, raw
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildBlogIndex generates the blog index page
|
func buildBlogIndex(posts []PageMeta, tpl *template.Template, outputDir string, nav []NavItem) {
|
||||||
func buildBlogIndex(posts []PageMeta, tpl *template.Template, outputDir string, nav []NavItem) error {
|
|
||||||
outPath := filepath.Join(outputDir, "blog", "index.html")
|
outPath := filepath.Join(outputDir, "blog", "index.html")
|
||||||
os.MkdirAll(filepath.Dir(outPath), os.ModePerm)
|
os.MkdirAll(filepath.Dir(outPath), os.ModePerm)
|
||||||
|
|
||||||
outFile, err := os.Create(outPath)
|
outFile, err := os.Create(outPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
fmt.Println("Failed to create blog index:", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := map[string]interface{}{
|
fmt.Printf("Rendering blog index: %d posts\n", len(posts))
|
||||||
"Title": "Go SSG - Blog",
|
tpl.ExecuteTemplate(outFile, "blog_index_page", map[string]interface{}{
|
||||||
|
"Title": "Blog Index",
|
||||||
"Posts": posts,
|
"Posts": posts,
|
||||||
"Nav": nav,
|
"Nav": nav,
|
||||||
"Year": time.Now().Year(),
|
"Year": time.Now().Year(),
|
||||||
}
|
"PageTemplate": "blog_index",
|
||||||
|
})
|
||||||
return tpl.Execute(outFile, data)
|
}
|
||||||
|
|
||||||
|
func slugify(s string) string {
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
s = slugRegex.ReplaceAllString(s, "-")
|
||||||
|
return strings.Trim(s, "-")
|
||||||
|
}
|
||||||
|
|
||||||
|
func templateFuncs() template.FuncMap {
|
||||||
|
return template.FuncMap{
|
||||||
|
"lower": strings.ToLower,
|
||||||
|
"slugify": slugify,
|
||||||
|
"urlquery": template.URLQueryEscaper,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Go SSG - About</title>
|
<title>Go SSG - About</title>
|
||||||
<meta name="description" content="More About My Go SSG Site.">
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header>
|
|
||||||
|
<header>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
@@ -20,21 +20,24 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<small>Published: 2025-04-19</small>
|
<article>
|
||||||
|
<h1>Go SSG - About</h1>
|
||||||
<h1>About</h1>
|
<h1>About</h1>
|
||||||
|
|
||||||
<p>Experimenting with Go. Seems pretty cool so far!</p>
|
<p>Experimenting with Go. Seems pretty cool so far!</p>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
</main>
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>© 2025 Keith Solomon</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
68
public/blog/another-blog-post/index.html
Normal file
68
public/blog/another-blog-post/index.html
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Go SSG - Another Blog Post</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li><a href="/">Index</a></li>
|
||||||
|
|
||||||
|
<li><a href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<article>
|
||||||
|
<h1>Go SSG - Another Blog Post</h1>
|
||||||
|
<p><small>2025-04-19</small></p>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Categories:
|
||||||
|
|
||||||
|
|
||||||
|
<a href="/blog/category/go/">go</a>
|
||||||
|
|
||||||
|
,
|
||||||
|
<a href="/blog/category/anger/">anger</a>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h1>Why isn’t this working?! 😭</h1>
|
||||||
|
|
||||||
|
<p>This is my first Go SSG blog post.</p>
|
||||||
|
|
||||||
|
<p>This project is a simple static site generator written in Go. It is designed to be easy to use and extend, allowing you to create a static website quickly and efficiently.</p>
|
||||||
|
|
||||||
|
<p>It supports features like:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Markdown content</li>
|
||||||
|
<li>Customizable templates</li>
|
||||||
|
<li>Simple configuration</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
42
public/blog/category/anger/index.html
Normal file
42
public/blog/category/anger/index.html
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Category: Anger</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li><a href="/">Index</a></li>
|
||||||
|
|
||||||
|
<li><a href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h1>Category: Anger</h1>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/blog/another-blog-post/">Go SSG - Another Blog Post</a><br>A longer summary of the post. Lorem ipsum dolor set amit.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
44
public/blog/category/go/index.html
Normal file
44
public/blog/category/go/index.html
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Category: Go</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li><a href="/">Index</a></li>
|
||||||
|
|
||||||
|
<li><a href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h1>Category: Go</h1>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/blog/another-blog-post/">Go SSG - Another Blog Post</a><br>A longer summary of the post. Lorem ipsum dolor set amit.</li>
|
||||||
|
|
||||||
|
<li><a href="/blog/my-first-blog-post/">Go SSG - My First Blog Post</a><br>A short summary of the post.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
42
public/blog/category/progrmming/index.html
Normal file
42
public/blog/category/progrmming/index.html
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Category: Progrmming</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li><a href="/">Index</a></li>
|
||||||
|
|
||||||
|
<li><a href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h1>Category: Progrmming</h1>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/blog/my-first-blog-post/">Go SSG - My First Blog Post</a><br>A short summary of the post.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Go SSG - Blog</title>
|
<title>Blog Index</title>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header>
|
|
||||||
|
<header>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
@@ -20,31 +20,25 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
<h1>Blog Index</h1>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="/blog/another-blog-post/">Go SSG - Another Blog Post</a><br>A longer summary of the post. Lorem ipsum dolor set amit.</li>
|
||||||
|
|
||||||
|
<li><a href="/blog/my-first-blog-post/">Go SSG - My First Blog Post</a><br>A short summary of the post.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2>Blog Posts</h2>
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a href="/blog/my-first-blog-post/">Go SSG - My First Blog Post</a>
|
|
||||||
<small>2025-04-19</small><br>
|
|
||||||
A short summary of the post.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>© 2025 Keith Solomon</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Go SSG - My First Blog Post</title>
|
<title>Go SSG - My First Blog Post</title>
|
||||||
<meta name="description" content="A short summary of the post.">
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header>
|
|
||||||
|
<header>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
@@ -20,21 +20,49 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<small>Published: 2025-04-19</small>
|
<article>
|
||||||
|
<h1>Go SSG - My First Blog Post</h1>
|
||||||
|
<p><small>2025-04-19</small></p>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Categories:
|
||||||
|
|
||||||
|
|
||||||
|
<a href="/blog/category/progrmming/">progrmming</a>
|
||||||
|
|
||||||
|
,
|
||||||
|
<a href="/blog/category/go/">go</a>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<h1><em>Tap Tap Tap</em> Is this thing on?</h1>
|
<h1><em>Tap Tap Tap</em> Is this thing on?</h1>
|
||||||
|
|
||||||
<p>This is my first blog post!</p>
|
<p>This is my first Go SSG blog post.</p>
|
||||||
|
|
||||||
|
<p>This project is a simple static site generator written in Go. It is designed to be easy to use and extend, allowing you to create a static website quickly and efficiently.</p>
|
||||||
|
|
||||||
|
<p>It supports features like:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Markdown content</li>
|
||||||
|
<li>Customizable templates</li>
|
||||||
|
<li>Simple configuration</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>© 2025 Keith Solomon</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Go SSG - Home</title>
|
<title>Go SSG - Home</title>
|
||||||
<meta name="description" content="My Go SSG Site.">
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header>
|
|
||||||
|
<header>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
@@ -20,21 +20,24 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<small>Published: 2025-04-19</small>
|
<article>
|
||||||
|
<h1>Go SSG - Home</h1>
|
||||||
<h1>Welcome</h1>
|
<h1>Welcome</h1>
|
||||||
|
|
||||||
<p>This is your first static site built with Go!</p>
|
<p>This is your first static site built with Go!</p>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
</main>
|
<footer>
|
||||||
|
<p>© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>© 2025 Keith Solomon</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
28
templates/base.html
Normal file
28
templates/base.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{{ define "base" }}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{{ .Title }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ template "header" . }}
|
||||||
|
|
||||||
|
<main>
|
||||||
|
{{- if eq .PageTemplate "blog_index" -}}
|
||||||
|
{{ template "blog_index_content" . }}
|
||||||
|
{{- else if eq .PageTemplate "static" -}}
|
||||||
|
{{ template "static_content" . }}
|
||||||
|
{{- else if eq .PageTemplate "blog_post" -}}
|
||||||
|
{{ template "blog_post_content" . }}
|
||||||
|
{{- else if eq .PageTemplate "category_page" -}}
|
||||||
|
{{ template "category_content" . }}
|
||||||
|
{{- else -}}
|
||||||
|
<p>Unknown PageTemplate: {{ .PageTemplate }}</p>
|
||||||
|
{{- end -}}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{{ template "footer" . }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{ end }}
|
||||||
14
templates/blog_index_page.html
Normal file
14
templates/blog_index_page.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{{ define "blog_index_page" }}
|
||||||
|
{{ template "base" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "blog_index_content" }}
|
||||||
|
<h1>Blog Index</h1>
|
||||||
|
<ul>
|
||||||
|
{{ range .Posts }}
|
||||||
|
<li><a href="/blog/{{ .Slug }}/">{{ .Title }}</a><br>{{ .Description }}</li>
|
||||||
|
{{ else }}
|
||||||
|
<li>No posts found.</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
{{ end }}
|
||||||
22
templates/blog_post_page.html
Normal file
22
templates/blog_post_page.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{{ define "blog_post_page" }}
|
||||||
|
{{ template "base" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "blog_post_content" }}
|
||||||
|
<article>
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
{{ if .Date }}<p><small>{{ .Date }}</small></p>{{ end }}
|
||||||
|
|
||||||
|
{{ if .Categories }}
|
||||||
|
<p>
|
||||||
|
Categories:
|
||||||
|
{{ range $i, $cat := .Categories }}
|
||||||
|
{{ if $i }}, {{ end }}
|
||||||
|
<a href="/blog/category/{{ $cat | slugify }}/">{{ $cat }}</a>
|
||||||
|
{{ end }}
|
||||||
|
</p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ .Content }}
|
||||||
|
</article>
|
||||||
|
{{ end }}
|
||||||
12
templates/category_page.html
Normal file
12
templates/category_page.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{{ define "category_page" }}
|
||||||
|
{{ template "base" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "category_content" }}
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
<ul>
|
||||||
|
{{ range .Posts }}
|
||||||
|
<li><a href="/blog/{{ .Slug }}/">{{ .Title }}</a><br>{{ .Description }}</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
{{ end }}
|
||||||
5
templates/footer.html
Normal file
5
templates/footer.html
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{{ define "footer" }}
|
||||||
|
<footer>
|
||||||
|
<p>© {{ .Year }} Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
{{ end }}
|
||||||
11
templates/header.html
Normal file
11
templates/header.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{{ define "header" }}
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
{{ range .Nav }}
|
||||||
|
<li><a href="{{ .URL }}">{{ .Title }}</a></li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
{{ end }}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>{{ .Title }}</title>
|
|
||||||
{{ if .Description }}<meta name="description" content="{{ .Description }}">{{ end }}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
{{ range .Nav }}
|
|
||||||
<li><a href="{{ .URL }}">{{ .Title }}</a></li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
{{ if .Date }}<small>Published: {{ .Date }}</small>{{ end }}
|
|
||||||
{{ .Content }}
|
|
||||||
|
|
||||||
{{ if .Posts }}
|
|
||||||
<section>
|
|
||||||
<h2>Blog Posts</h2>
|
|
||||||
<ul>
|
|
||||||
{{ range .Posts }}
|
|
||||||
<li>
|
|
||||||
<a href="/blog/{{ .Slug }}/">{{ .Title }}</a>
|
|
||||||
{{ if .Date }} <small>{{ .Date }}</small>{{ end }}<br>
|
|
||||||
{{ .Description }}
|
|
||||||
</li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
{{ end }}
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>© {{ .Year }} Keith Solomon</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
10
templates/static_page.html
Normal file
10
templates/static_page.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{{ define "static_page" }}
|
||||||
|
{{ template "base" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "static_content" }}
|
||||||
|
<article>
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
{{ .Content }}
|
||||||
|
</article>
|
||||||
|
{{ end }}
|
||||||
Reference in New Issue
Block a user