Add Contact Page and Update Navigation Links
- Updated navigation links across multiple blog pages to replace "Index" with "Home" and added "Contact" link. - Created a new contact page with a form for user inquiries. - Added a new contact template to render the contact page content. - Updated blog index page to enhance structure and styling. - Added a contact markdown file for content management.
This commit is contained in:
@@ -2,6 +2,7 @@ root = "."
|
|||||||
|
|
||||||
[build]
|
[build]
|
||||||
cmd = "go run main.go"
|
cmd = "go run main.go"
|
||||||
|
bin = ""
|
||||||
delay = 1000
|
delay = 1000
|
||||||
exclude_dir = ["assets", "tmp", "vendor", "bak", "node_modules", "public"]
|
exclude_dir = ["assets", "tmp", "vendor", "bak", "node_modules", "public"]
|
||||||
include_ext = ["go", "md", "html"]
|
include_ext = ["go", "md", "html"]
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
bak/
|
bak/
|
||||||
|
tmp/
|
||||||
|
*.log
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Go SSG - About
|
title: Go SSG - About
|
||||||
|
navTitle: About
|
||||||
description: More About My Go SSG Site.
|
description: More About My Go SSG Site.
|
||||||
date: 2025-04-19
|
date: 2025-04-19
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ categories:
|
|||||||
|
|
||||||
## *Tap Tap Tap* Is this thing on?
|
## *Tap Tap Tap* Is this thing on?
|
||||||
|
|
||||||
This is my first Go SSG blog post.
|
<p class="text-primary">This is my first Go SSG blog post.</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.
|
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.
|
||||||
|
|
||||||
|
|||||||
4
content/contact.md
Normal file
4
content/contact.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: Contact
|
||||||
|
navTitle: Contact
|
||||||
|
---
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Go SSG - Home
|
title: Go SSG - Home
|
||||||
|
navTitle: Home
|
||||||
description: My Go SSG Site.
|
description: My Go SSG Site.
|
||||||
date: 2025-04-19
|
date: 2025-04-19
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -17,14 +17,16 @@ header#site_head {
|
|||||||
@apply py-4 px-60;
|
@apply py-4 px-60;
|
||||||
|
|
||||||
nav ul {
|
nav ul {
|
||||||
@apply flex space-x-4 justify-end-safe;
|
@apply flex space-x-4 justify-end-safe prose-a:text-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
article, div.main {
|
||||||
@apply prose container mx-auto px-4 py-8 max-w-5xl;
|
@apply prose container mx-auto px-4 py-8 max-w-5xl;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
footer#site_foot {
|
footer#site_foot {
|
||||||
@apply bg-secondary text-white text-center;
|
@apply bg-secondary text-white text-center m-0 p-0;
|
||||||
}
|
}
|
||||||
|
|||||||
132
main.go
132
main.go
@@ -11,6 +11,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"sort"
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
"github.com/russross/blackfriday/v2"
|
"github.com/russross/blackfriday/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -23,6 +25,7 @@ type NavItem struct {
|
|||||||
|
|
||||||
type PageMeta struct {
|
type PageMeta struct {
|
||||||
Title string `yaml:"title"`
|
Title string `yaml:"title"`
|
||||||
|
NavTitle string `yaml:"navTitle"`
|
||||||
Description string `yaml:"description"`
|
Description string `yaml:"description"`
|
||||||
Date string `yaml:"date"`
|
Date string `yaml:"date"`
|
||||||
Categories []string `yaml:"categories"`
|
Categories []string `yaml:"categories"`
|
||||||
@@ -35,8 +38,7 @@ func main() {
|
|||||||
contentDir := "./content"
|
contentDir := "./content"
|
||||||
outputDir := "./public"
|
outputDir := "./public"
|
||||||
|
|
||||||
// Load all templates in the templates folder
|
tpl, err := loadTemplates()
|
||||||
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
|
||||||
@@ -48,31 +50,91 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entries, _ := os.ReadDir(contentDir)
|
||||||
|
nav := buildNav(entries, contentDir)
|
||||||
|
renderStaticPages(files, contentDir, outputDir, tpl, nav)
|
||||||
|
blogPosts, categoryMap := processBlogPosts(contentDir, outputDir, tpl, nav)
|
||||||
|
buildBlogIndex(blogPosts, tpl, outputDir, nav)
|
||||||
|
buildCategoryPages(categoryMap, tpl, outputDir, nav)
|
||||||
|
|
||||||
|
fmt.Println("✅ Site generation complete.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadTemplates() (*template.Template, error) {
|
||||||
|
return template.New("").Funcs(templateFuncs()).ParseGlob("templates/*.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildNav(entries []fs.DirEntry, contentDir string) []NavItem {
|
||||||
var nav []NavItem
|
var nav []NavItem
|
||||||
for _, file := range files {
|
|
||||||
if filepath.Ext(file.Name()) == ".md" {
|
for _, entry := range entries {
|
||||||
name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
if entry.Type().IsDir() || !strings.HasSuffix(entry.Name(), ".md") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name()))
|
||||||
|
path := filepath.Join(contentDir, entry.Name())
|
||||||
|
|
||||||
|
rawContent, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to read %s: %v\n", entry.Name(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
meta, _ := parseFrontMatter(rawContent)
|
||||||
|
|
||||||
|
title := meta.NavTitle
|
||||||
|
if title == "" {
|
||||||
|
title = meta.Title
|
||||||
|
}
|
||||||
|
if title == "" && name == "index" {
|
||||||
|
title = "Home"
|
||||||
|
} else if title == "" {
|
||||||
|
title = strings.Title(name)
|
||||||
|
}
|
||||||
|
|
||||||
url := "/"
|
url := "/"
|
||||||
if name != "index" {
|
if name != "index" {
|
||||||
url = "/" + name + "/"
|
url = "/" + name + "/"
|
||||||
}
|
}
|
||||||
nav = append(nav, NavItem{Title: strings.Title(name), URL: url})
|
|
||||||
}
|
nav = append(nav, NavItem{Title: title, URL: url})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add blog to main nav
|
// Add Blog manually
|
||||||
nav = append(nav, NavItem{Title: "Blog", URL: "/blog/"})
|
nav = append(nav, NavItem{Title: "Blog", URL: "/blog/"})
|
||||||
|
|
||||||
// Static page rendering
|
// Optional: order the nav explicitly
|
||||||
|
preferredOrder := map[string]int{
|
||||||
|
"Home": 0,
|
||||||
|
"Blog": 1,
|
||||||
|
"About": 2,
|
||||||
|
"Contact": 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.SliceStable(nav, func(i, j int) bool {
|
||||||
|
return preferredOrder[nav[i].Title] < preferredOrder[nav[j].Title]
|
||||||
|
})
|
||||||
|
|
||||||
|
return nav
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderStaticPages(files []os.FileInfo, contentDir, outputDir string, tpl *template.Template, nav []NavItem) {
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if filepath.Ext(file.Name()) == ".md" {
|
if filepath.Ext(file.Name()) == ".md" {
|
||||||
|
renderStaticPage(file, contentDir, outputDir, tpl, nav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderStaticPage(file os.FileInfo, contentDir, outputDir string, tpl *template.Template, nav []NavItem) {
|
||||||
name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
||||||
title := strings.Title(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 {
|
||||||
fmt.Printf("Failed to read %s: %v\n", file.Name(), err)
|
fmt.Printf("Failed to read %s: %v\n", file.Name(), err)
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, content := parseFrontMatter(rawContent)
|
meta, content := parseFrontMatter(rawContent)
|
||||||
@@ -93,7 +155,7 @@ func main() {
|
|||||||
outFile, err := os.Create(outPath)
|
outFile, err := os.Create(outPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to create %s: %v\n", outPath, err)
|
fmt.Printf("Failed to create %s: %v\n", outPath, err)
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tpl.ExecuteTemplate(outFile, "static_page", map[string]interface{}{
|
tpl.ExecuteTemplate(outFile, "static_page", map[string]interface{}{
|
||||||
@@ -109,8 +171,38 @@ func main() {
|
|||||||
|
|
||||||
fmt.Printf("Generated: %s\n", outPath)
|
fmt.Printf("Generated: %s\n", outPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renderContactPage(contentDir, outputDir string, tpl *template.Template, nav []NavItem) {
|
||||||
|
contactPath := filepath.Join(contentDir, "contact.md")
|
||||||
|
rawContent, err := os.ReadFile(contactPath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Contact page not found: %v\n", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta, _ := parseFrontMatter(rawContent)
|
||||||
|
|
||||||
|
outPath := filepath.Join(outputDir, "contact", "index.html")
|
||||||
|
os.MkdirAll(filepath.Dir(outPath), os.ModePerm)
|
||||||
|
|
||||||
|
outFile, err := os.Create(outPath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to create contact page: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl.ExecuteTemplate(outFile, "contact_page", map[string]interface{}{
|
||||||
|
"Title": meta.Title,
|
||||||
|
"Description": meta.Description,
|
||||||
|
"Nav": nav,
|
||||||
|
"Year": time.Now().Year(),
|
||||||
|
"PageTemplate": "contact_page",
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println("Generated: /contact/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func processBlogPosts(contentDir, outputDir string, tpl *template.Template, nav []NavItem) ([]PageMeta, map[string][]PageMeta) {
|
||||||
var blogPosts []PageMeta
|
var blogPosts []PageMeta
|
||||||
categoryMap := make(map[string][]PageMeta)
|
categoryMap := make(map[string][]PageMeta)
|
||||||
|
|
||||||
@@ -122,12 +214,19 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processBlogPost(file, blogDir, outputDir, tpl, nav, &blogPosts, categoryMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
return blogPosts, categoryMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func processBlogPost(file os.FileInfo, blogDir, outputDir string, tpl *template.Template, nav []NavItem, blogPosts *[]PageMeta, categoryMap map[string][]PageMeta) {
|
||||||
slug := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
slug := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
||||||
blogPath := filepath.Join(blogDir, file.Name())
|
blogPath := filepath.Join(blogDir, file.Name())
|
||||||
rawContent, err := ioutil.ReadFile(blogPath)
|
rawContent, err := ioutil.ReadFile(blogPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to read blog post %s: %v\n", file.Name(), err)
|
fmt.Printf("Failed to read blog post %s: %v\n", file.Name(), err)
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, content := parseFrontMatter(rawContent)
|
meta, content := parseFrontMatter(rawContent)
|
||||||
@@ -148,7 +247,7 @@ func main() {
|
|||||||
outFile, err := os.Create(outPath)
|
outFile, err := os.Create(outPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to create blog file %s: %v\n", outPath, err)
|
fmt.Printf("Failed to create blog file %s: %v\n", outPath, err)
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tpl.ExecuteTemplate(outFile, "blog_post_page", map[string]interface{}{
|
tpl.ExecuteTemplate(outFile, "blog_post_page", map[string]interface{}{
|
||||||
@@ -162,11 +261,10 @@ func main() {
|
|||||||
"PageTemplate": "blog_post",
|
"PageTemplate": "blog_post",
|
||||||
})
|
})
|
||||||
|
|
||||||
blogPosts = append(blogPosts, meta)
|
*blogPosts = append(*blogPosts, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildBlogIndex(blogPosts, tpl, outputDir, nav)
|
func buildCategoryPages(categoryMap map[string][]PageMeta, tpl *template.Template, outputDir string, nav []NavItem) {
|
||||||
|
|
||||||
for catSlug, posts := range categoryMap {
|
for catSlug, posts := range categoryMap {
|
||||||
outDir := filepath.Join(outputDir, "blog", "category", catSlug)
|
outDir := filepath.Join(outputDir, "blog", "category", catSlug)
|
||||||
os.MkdirAll(outDir, os.ModePerm)
|
os.MkdirAll(outDir, os.ModePerm)
|
||||||
@@ -188,8 +286,6 @@ func main() {
|
|||||||
|
|
||||||
fmt.Printf("Generated category: /blog/category/%s/\n", catSlug)
|
fmt.Printf("Generated category: /blog/category/%s/\n", catSlug)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ Site generation complete.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFrontMatter(raw []byte) (PageMeta, []byte) {
|
func parseFrontMatter(raw []byte) (PageMeta, []byte) {
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -6,13 +6,22 @@
|
|||||||
--font-sans: "Raleway", sans-serif;
|
--font-sans: "Raleway", sans-serif;
|
||||||
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
||||||
"Courier New", monospace;
|
"Courier New", monospace;
|
||||||
|
--color-blue-600: oklch(54.6% 0.245 262.881);
|
||||||
|
--color-blue-700: oklch(48.8% 0.243 264.376);
|
||||||
--color-black: oklch(0% 0 0);
|
--color-black: oklch(0% 0 0);
|
||||||
--color-white: oklch(100% 0 0);
|
--color-white: oklch(100% 0 0);
|
||||||
--spacing: 0.25rem;
|
--spacing: 0.25rem;
|
||||||
|
--container-xl: 36rem;
|
||||||
--container-5xl: 64rem;
|
--container-5xl: 64rem;
|
||||||
--text-xs: 0.75rem;
|
--text-xs: 0.75rem;
|
||||||
--text-xs--line-height: calc(1 / 0.75);
|
--text-xs--line-height: calc(1 / 0.75);
|
||||||
|
--text-sm: 0.875rem;
|
||||||
|
--text-sm--line-height: calc(1.25 / 0.875);
|
||||||
--text-base: 1rem;
|
--text-base: 1rem;
|
||||||
|
--text-2xl: 1.5rem;
|
||||||
|
--text-2xl--line-height: calc(2 / 1.5);
|
||||||
|
--font-weight-medium: 500;
|
||||||
|
--font-weight-bold: 700;
|
||||||
--radius-sm: 0.25rem;
|
--radius-sm: 0.25rem;
|
||||||
--default-transition-duration: 150ms;
|
--default-transition-duration: 150ms;
|
||||||
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
@@ -663,9 +672,24 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.mb-4 {
|
||||||
|
margin-bottom: calc(var(--spacing) * 4);
|
||||||
|
}
|
||||||
|
.block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.table {
|
.table {
|
||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.max-w-xl {
|
||||||
|
max-width: var(--container-xl);
|
||||||
|
}
|
||||||
.border-collapse {
|
.border-collapse {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
@@ -675,16 +699,46 @@
|
|||||||
.list-none {
|
.list-none {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
.space-y-4 {
|
||||||
|
:where(& > :not(:last-child)) {
|
||||||
|
--tw-space-y-reverse: 0;
|
||||||
|
margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));
|
||||||
|
margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rounded {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
.border {
|
.border {
|
||||||
border-style: var(--tw-border-style);
|
border-style: var(--tw-border-style);
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
}
|
}
|
||||||
|
.bg-blue-600 {
|
||||||
|
background-color: var(--color-blue-600);
|
||||||
|
}
|
||||||
.p-0 {
|
.p-0 {
|
||||||
padding: calc(var(--spacing) * 0);
|
padding: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.p-2 {
|
||||||
|
padding: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
.px-4 {
|
||||||
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
|
}
|
||||||
|
.py-2 {
|
||||||
|
padding-block: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
.py-4 {
|
.py-4 {
|
||||||
padding-block: calc(var(--spacing) * 4);
|
padding-block: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.text-2xl {
|
||||||
|
font-size: var(--text-2xl);
|
||||||
|
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
||||||
|
}
|
||||||
|
.text-sm {
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
|
}
|
||||||
.text-40px {
|
.text-40px {
|
||||||
font-size: var(--text-40px);
|
font-size: var(--text-40px);
|
||||||
}
|
}
|
||||||
@@ -692,6 +746,17 @@
|
|||||||
--tw-leading: 1;
|
--tw-leading: 1;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
.font-bold {
|
||||||
|
--tw-font-weight: var(--font-weight-bold);
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
.font-medium {
|
||||||
|
--tw-font-weight: var(--font-weight-medium);
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
}
|
||||||
|
.text-primary {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
.text-white {
|
.text-white {
|
||||||
color: var(--color-white);
|
color: var(--color-white);
|
||||||
}
|
}
|
||||||
@@ -707,6 +772,13 @@
|
|||||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||||
}
|
}
|
||||||
|
.hover\:bg-blue-700 {
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-blue-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.hover\:text-primary-200 {
|
.hover\:text-primary-200 {
|
||||||
&:hover {
|
&:hover {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
@@ -904,9 +976,13 @@ header#site_head {
|
|||||||
margin-inline-start: calc(calc(var(--spacing) * 4) * var(--tw-space-x-reverse));
|
margin-inline-start: calc(calc(var(--spacing) * 4) * var(--tw-space-x-reverse));
|
||||||
margin-inline-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse)));
|
margin-inline-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse)));
|
||||||
}
|
}
|
||||||
|
& :is(:where(a):not(:where([class~="not-prose"],[class~="not-prose"] *))) {
|
||||||
|
color: var(--color-white);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
|
article, div.main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@media (width >= 22.5rem) {
|
@media (width >= 22.5rem) {
|
||||||
max-width: 22.5rem;
|
max-width: 22.5rem;
|
||||||
@@ -1347,11 +1423,19 @@ main {
|
|||||||
padding-inline: calc(var(--spacing) * 4);
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
padding-block: calc(var(--spacing) * 8);
|
padding-block: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
footer#site_foot {
|
footer#site_foot {
|
||||||
|
margin: calc(var(--spacing) * 0);
|
||||||
background-color: var(--color-secondary);
|
background-color: var(--color-secondary);
|
||||||
|
padding: calc(var(--spacing) * 0);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--color-white);
|
color: var(--color-white);
|
||||||
}
|
}
|
||||||
|
@property --tw-space-y-reverse {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: 0;
|
||||||
|
}
|
||||||
@property --tw-border-style {
|
@property --tw-border-style {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -1361,6 +1445,10 @@ footer#site_foot {
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
|
@property --tw-font-weight {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
@property --tw-outline-style {
|
@property --tw-outline-style {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -1374,8 +1462,10 @@ footer#site_foot {
|
|||||||
@layer properties {
|
@layer properties {
|
||||||
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
||||||
*, ::before, ::after, ::backdrop {
|
*, ::before, ::after, ::backdrop {
|
||||||
|
--tw-space-y-reverse: 0;
|
||||||
--tw-border-style: solid;
|
--tw-border-style: solid;
|
||||||
--tw-leading: initial;
|
--tw-leading: initial;
|
||||||
|
--tw-font-weight: initial;
|
||||||
--tw-outline-style: solid;
|
--tw-outline-style: solid;
|
||||||
--tw-space-x-reverse: 0;
|
--tw-space-x-reverse: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -17,19 +17,23 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<h1>Blog Index</h1>
|
<div class="main">
|
||||||
|
<h1>Go SSG - Blog Index</h1>
|
||||||
|
|
||||||
<ul>
|
<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/another-blog-post/">Go SSG - Another Blog Post</a><br>A longer summary of the post. Lorem ipsum dolor set amit.</li>
|
||||||
@@ -37,6 +41,7 @@
|
|||||||
<li><a href="/blog/my-first-blog-post/">Go SSG - My First Blog Post</a><br>A short summary of the post.</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>
|
</ul>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
@@ -48,7 +50,7 @@
|
|||||||
|
|
||||||
<h2><em>Tap Tap Tap</em> Is this thing on?</h2>
|
<h2><em>Tap Tap Tap</em> Is this thing on?</h2>
|
||||||
|
|
||||||
<p>This is my first Go SSG blog post.</p>
|
<p class="text-primary">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>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>
|
||||||
|
|
||||||
|
|||||||
47
public/contact/index.html
Normal file
47
public/contact/index.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Contact</title>
|
||||||
|
<link rel="stylesheet" href="/assets/style.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header id="site_head">
|
||||||
|
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<ul class="list-none">
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<article>
|
||||||
|
<h1>Contact</h1>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer id="site_foot">
|
||||||
|
<p class="p-0 py-4 m-0 leading-none">© 2025 Keith Solomon - Go SSG</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -17,12 +17,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<ul class="list-none">
|
<ul class="list-none">
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Home</a></li>
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/">Index</a></li>
|
|
||||||
|
|
||||||
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/blog/">Blog</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/about/">About</a></li>
|
||||||
|
|
||||||
|
<li class="list-none"><a class="text-white hover:text-primary-200" href="/contact/">Contact</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
{{ template "blog_post_content" . }}
|
{{ template "blog_post_content" . }}
|
||||||
{{- else if eq .PageTemplate "category_page" -}}
|
{{- else if eq .PageTemplate "category_page" -}}
|
||||||
{{ template "category_content" . }}
|
{{ template "category_content" . }}
|
||||||
|
{{- else if eq .PageTemplate "contact_page" -}}
|
||||||
|
{{ template "contact_content" . }}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
<p>Unknown PageTemplate: {{ .PageTemplate }}</p>
|
<p>Unknown PageTemplate: {{ .PageTemplate }}</p>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{ define "blog_index_content" }}
|
{{ define "blog_index_content" }}
|
||||||
<h1>Blog Index</h1>
|
<div class="main">
|
||||||
|
<h1>Go SSG - Blog Index</h1>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{{ range .Posts }}
|
{{ range .Posts }}
|
||||||
<li><a href="/blog/{{ .Slug }}/">{{ .Title }}</a><br>{{ .Description }}</li>
|
<li><a href="/blog/{{ .Slug }}/">{{ .Title }}</a><br>{{ .Description }}</li>
|
||||||
@@ -11,4 +13,5 @@
|
|||||||
<li>No posts found.</li>
|
<li>No posts found.</li>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
37
templates/contact_page.html
Normal file
37
templates/contact_page.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{{ define "contact_page" }}
|
||||||
|
{{ template "base" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "contact_content" }}
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Contact Me</h1>
|
||||||
|
|
||||||
|
<form action="https://api.staticforms.xyz/submit" method="POST" class="space-y-4 max-w-xl">
|
||||||
|
<!-- StaticForms API Key -->
|
||||||
|
<input type="hidden" name="accessKey" value="sf_5m86ek16hmele1jlkl62ghml" />
|
||||||
|
|
||||||
|
<!-- Optional redirect after success -->
|
||||||
|
<!-- <input type="hidden" name="redirectTo" value="https://yourdomain.com/thanks/" /> -->
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<span class="block text-sm font-medium">Your Name</span>
|
||||||
|
<input type="text" name="name" required class="w-full border p-2 rounded" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<span class="block text-sm font-medium">Email Address</span>
|
||||||
|
<input type="email" name="email" required class="w-full border p-2 rounded" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<span class="block text-sm font-medium">Message</span>
|
||||||
|
<textarea name="message" rows="5" required class="w-full border p-2 rounded"></textarea>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- reCAPTCHA if configured in dashboard -->
|
||||||
|
<!-- <div class="g-recaptcha" data-sitekey="your-recaptcha-site-key"></div> -->
|
||||||
|
|
||||||
|
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
|
||||||
|
Send Message
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{{ end }}
|
||||||
Reference in New Issue
Block a user