feature: Wire up contact and thank you pages, add showInNav meta functionality

This commit is contained in:
Keith Solomon
2025-04-21 15:10:28 -05:00
parent 1a9b58d7d7
commit 29b398921b
20 changed files with 280 additions and 533 deletions

5
content/thanks.md Normal file
View File

@@ -0,0 +1,5 @@
---
title: Thank You
navTitle: ""
showInNav: false
---

View File

@@ -107,6 +107,10 @@ h3 a, .h3 a {
text-decoration: underline; text-decoration: underline;
} }
#site_head h1 a {
@apply text-white text-40px hover:text-primary-200;
}
p { p {
margin-top: 0; margin-top: 0;
margin-bottom: 1rem; margin-bottom: 1rem;

43
main.go
View File

@@ -26,6 +26,7 @@ type NavItem struct {
type PageMeta struct { type PageMeta struct {
Title string `yaml:"title"` Title string `yaml:"title"`
NavTitle string `yaml:"navTitle"` NavTitle string `yaml:"navTitle"`
ShowInNav *bool `yaml:"showInNav"`
Description string `yaml:"description"` Description string `yaml:"description"`
Date string `yaml:"date"` Date string `yaml:"date"`
Categories []string `yaml:"categories"` Categories []string `yaml:"categories"`
@@ -54,6 +55,8 @@ func main() {
nav := buildNav(entries, contentDir) nav := buildNav(entries, contentDir)
renderStaticPages(files, contentDir, outputDir, tpl, nav) renderStaticPages(files, contentDir, outputDir, tpl, nav)
blogPosts, categoryMap := processBlogPosts(contentDir, outputDir, tpl, nav) blogPosts, categoryMap := processBlogPosts(contentDir, outputDir, tpl, nav)
renderContactPage(contentDir, outputDir, tpl, nav)
renderThanksPage(contentDir, outputDir, tpl, nav)
buildBlogIndex(blogPosts, tpl, outputDir, nav) buildBlogIndex(blogPosts, tpl, outputDir, nav)
buildCategoryPages(categoryMap, tpl, outputDir, nav) buildCategoryPages(categoryMap, tpl, outputDir, nav)
@@ -83,10 +86,18 @@ func buildNav(entries []fs.DirEntry, contentDir string) []NavItem {
meta, _ := parseFrontMatter(rawContent) meta, _ := parseFrontMatter(rawContent)
title := meta.NavTitle title := strings.TrimSpace(meta.NavTitle)
if title == "" { if title == "" {
title = meta.Title title = meta.Title
} }
if title == "" {
title = strings.Title(name)
}
// Respect showInNav: false
if meta.ShowInNav != nil && !*meta.ShowInNav {
continue
}
if title == "" && name == "index" { if title == "" && name == "index" {
title = "Home" title = "Home"
} else if title == "" { } else if title == "" {
@@ -202,6 +213,36 @@ func renderContactPage(contentDir, outputDir string, tpl *template.Template, nav
fmt.Println("Generated: /contact/") fmt.Println("Generated: /contact/")
} }
func renderThanksPage(contentDir, outputDir string, tpl *template.Template, nav []NavItem) {
path := filepath.Join(contentDir, "thanks.md")
rawContent, err := os.ReadFile(path)
if err != nil {
fmt.Printf("Thanks page not found: %v\n", err)
return
}
meta, _ := parseFrontMatter(rawContent)
outPath := filepath.Join(outputDir, "thanks", "index.html")
os.MkdirAll(filepath.Dir(outPath), os.ModePerm)
outFile, err := os.Create(outPath)
if err != nil {
fmt.Printf("Failed to create thanks page: %v\n", err)
return
}
tpl.ExecuteTemplate(outFile, "thanks_page", map[string]interface{}{
"Title": meta.Title,
"Description": meta.Description,
"Nav": nav,
"Year": time.Now().Year(),
"PageTemplate": "thanks_page",
})
fmt.Println("Generated: /thanks/")
}
func processBlogPosts(contentDir, outputDir string, tpl *template.Template, nav []NavItem) ([]PageMeta, map[string][]PageMeta) { 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)

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Go SSG - About</title> <title>Go SSG - About</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -42,7 +43,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

41
public/assets/contact.js Normal file
View File

@@ -0,0 +1,41 @@
document.getElementById("contactForm").addEventListener("submit", function (e) {
const name = document.getElementById("name");
const email = document.getElementById("email");
const message = document.getElementById("message");
let valid = true;
// Clear errors
document.querySelectorAll("[data-error]").forEach(el => {
el.classList.add("hidden");
el.textContent = "";
});
// Validate name
if (name.value.trim() === "") {
showError("name", "Name is required");
valid = false;
}
// Validate email
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email.value)) {
showError("email", "Enter a valid email address");
valid = false;
}
// Validate message
if (message.value.trim().length < 10) {
showError("message", "Message must be at least 10 characters");
valid = false;
}
if (!valid) {
e.preventDefault();
}
function showError(field, message) {
const el = document.querySelector(`[data-error="\${field}"]`);
el.textContent = message;
el.classList.remove("hidden");
}
});

BIN
public/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View File

@@ -6,25 +6,30 @@
--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-red-600: oklch(57.7% 0.245 27.325);
--color-green-700: oklch(52.7% 0.154 150.069);
--color-blue-600: oklch(54.6% 0.245 262.881); --color-blue-600: oklch(54.6% 0.245 262.881);
--color-blue-700: oklch(48.8% 0.243 264.376); --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-xl: 36rem;
--container-2xl: 42rem;
--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: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875); --text-sm--line-height: calc(1.25 / 0.875);
--text-base: 1rem; --text-base: 1rem;
--text-lg: 1.125rem;
--text-lg--line-height: calc(1.75 / 1.125);
--text-2xl: 1.5rem; --text-2xl: 1.5rem;
--text-2xl--line-height: calc(2 / 1.5); --text-2xl--line-height: calc(2 / 1.5);
--text-3xl: 1.875rem;
--text-3xl--line-height: calc(2.25 / 1.875);
--font-weight-medium: 500; --font-weight-medium: 500;
--font-weight-bold: 700; --font-weight-bold: 700;
--radius-sm: 0.25rem; --radius-sm: 0.25rem;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-sans); --default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono); --default-mono-font-family: var(--font-mono);
--spacing-section: 2rem; --spacing-section: 2rem;
@@ -63,22 +68,6 @@
--tw-prose-pre-bg: var(--color-secondary); --tw-prose-pre-bg: var(--color-secondary);
--tw-prose-th-borders: var(--color-secondary); --tw-prose-th-borders: var(--color-secondary);
--tw-prose-td-borders: var(--color-secondary); --tw-prose-td-borders: var(--color-secondary);
--tw-prose-invert-body: var(--color-primary);
--tw-prose-invert-headings: var(--color-primary);
--tw-prose-invert-lead: var(--color-primary);
--tw-prose-invert-links: var(--color-secondary);
--tw-prose-invert-bold: var(--color-primary);
--tw-prose-invert-counters: var(--color-primary);
--tw-prose-invert-bullets: var(--color-primary);
--tw-prose-invert-hr: var(--color-secondary);
--tw-prose-invert-quotes: var(--color-primary);
--tw-prose-invert-quote-borders: var(--color-primary);
--tw-prose-invert-captions: var(--color-primary);
--tw-prose-invert-code: var(--color-secondary);
--tw-prose-invert-pre-code: var(--color-primary);
--tw-prose-invert-pre-bg: oklch(0% 0 0 / 50%);
--tw-prose-invert-th-borders: var(--color-primary);
--tw-prose-invert-td-borders: var(--color-primary);
} }
} }
@layer base { @layer base {
@@ -230,447 +219,14 @@
.static { .static {
position: static; position: static;
} }
.container {
width: 100%;
@media (width >= 22.5rem) {
max-width: 22.5rem;
}
@media (width >= 29.6875rem) {
max-width: 29.6875rem;
}
@media (width >= 40rem) {
max-width: 40rem;
}
@media (width >= 48rem) {
max-width: 48rem;
}
@media (width >= 64rem) {
max-width: 64rem;
}
@media (width >= 80rem) {
max-width: 80rem;
}
@media (width >= 96rem) {
max-width: 96rem;
}
}
.m-0 { .m-0 {
margin: calc(var(--spacing) * 0); margin: calc(var(--spacing) * 0);
} }
.prose { .mx-auto {
color: var(--tw-prose-body); margin-inline: auto;
max-width: 65ch; }
:where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { .mt-10 {
margin-top: 1.25em; margin-top: calc(var(--spacing) * 10);
margin-bottom: 1.25em;
}
:where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-lead);
font-size: 1.25em;
line-height: 1.6;
margin-top: 1.2em;
margin-bottom: 1.2em;
}
:where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-links);
text-decoration: underline;
font-weight: 500;
}
:where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-bold);
font-weight: 600;
}
:where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: decimal;
margin-top: 1.25em;
margin-bottom: 1.25em;
padding-inline-start: 1.625em;
}
:where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: upper-alpha;
}
:where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: lower-alpha;
}
:where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: upper-alpha;
}
:where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: lower-alpha;
}
:where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: upper-roman;
}
:where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: lower-roman;
}
:where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: upper-roman;
}
:where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: lower-roman;
}
:where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: decimal;
}
:where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
list-style-type: disc;
margin-top: 1.25em;
margin-bottom: 1.25em;
padding-inline-start: 1.625em;
}
:where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker {
font-weight: 400;
color: var(--tw-prose-counters);
}
:where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker {
color: var(--tw-prose-bullets);
}
:where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-headings);
font-weight: 600;
margin-top: 1.25em;
}
:where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
border-color: var(--tw-prose-hr);
border-top-width: 1;
margin-top: 3em;
margin-bottom: 3em;
}
:where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
font-weight: 500;
font-style: italic;
color: var(--tw-prose-quotes);
border-inline-start-width: 0.25rem;
border-inline-start-color: var(--tw-prose-quote-borders);
quotes: "\201C""\201D""\2018""\2019";
margin-top: 1.6em;
margin-bottom: 1.6em;
padding-inline-start: 1em;
}
:where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before {
content: open-quote;
}
:where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after {
content: close-quote;
}
:where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-headings);
font-weight: 800;
font-size: 2.25em;
margin-top: 0;
margin-bottom: 0.8888889em;
line-height: 1.1111111;
}
:where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
font-weight: 900;
color: inherit;
}
:where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-headings);
font-weight: 700;
font-size: 1.5em;
margin-top: 2em;
margin-bottom: 1em;
line-height: 1.3333333;
}
:where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
font-weight: 800;
color: inherit;
}
:where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-headings);
font-weight: 600;
font-size: 1.25em;
margin-top: 1.6em;
margin-bottom: 0.6em;
line-height: 1.6;
}
:where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
font-weight: 700;
color: inherit;
}
:where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-headings);
font-weight: 600;
margin-top: 1.5em;
margin-bottom: 0.5em;
line-height: 1.5;
}
:where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
font-weight: 700;
color: inherit;
}
:where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 2em;
margin-bottom: 2em;
}
:where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
display: block;
margin-top: 2em;
margin-bottom: 2em;
}
:where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 2em;
margin-bottom: 2em;
}
:where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
font-weight: 500;
font-family: inherit;
color: var(--tw-prose-kbd);
box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);
font-size: 0.875em;
border-radius: 0.3125rem;
padding-top: 0.1875em;
padding-inline-end: 0.375em;
padding-bottom: 0.1875em;
padding-inline-start: 0.375em;
}
:where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-code);
font-weight: 600;
font-size: 0.875em;
}
:where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before {
content: "`";
}
:where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after {
content: "`";
}
:where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
font-size: 0.875em;
}
:where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
font-size: 0.9em;
}
:where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: inherit;
}
:where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-pre-code);
background-color: var(--tw-prose-pre-bg);
overflow-x: auto;
font-weight: 400;
font-size: 0.875em;
line-height: 1.7142857;
margin-top: 1.7142857em;
margin-bottom: 1.7142857em;
border-radius: 0.375rem;
padding-top: 0.8571429em;
padding-inline-end: 1.1428571em;
padding-bottom: 0.8571429em;
padding-inline-start: 1.1428571em;
}
:where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
background-color: transparent;
border-width: 0;
border-radius: 0;
padding: 0;
font-weight: inherit;
color: inherit;
font-size: inherit;
font-family: inherit;
line-height: inherit;
}
:where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before {
content: none;
}
:where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after {
content: none;
}
:where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
width: 100%;
table-layout: auto;
margin-top: 2em;
margin-bottom: 2em;
font-size: 0.875em;
line-height: 1.7142857;
}
:where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
border-bottom-width: 1px;
border-bottom-color: var(--tw-prose-th-borders);
}
:where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-headings);
font-weight: 600;
vertical-align: bottom;
padding-inline-end: 0.5714286em;
padding-bottom: 0.5714286em;
padding-inline-start: 0.5714286em;
}
:where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
border-bottom-width: 1px;
border-bottom-color: var(--tw-prose-td-borders);
}
:where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
border-bottom-width: 0;
}
:where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
vertical-align: baseline;
}
:where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
border-top-width: 1px;
border-top-color: var(--tw-prose-th-borders);
}
:where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
vertical-align: top;
}
:where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
text-align: start;
}
:where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0;
margin-bottom: 0;
}
:where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
color: var(--tw-prose-captions);
font-size: 0.875em;
line-height: 1.4285714;
margin-top: 0.8571429em;
}
--tw-prose-body: oklch(37.3% 0.034 259.733);
--tw-prose-headings: oklch(21% 0.034 264.665);
--tw-prose-lead: oklch(44.6% 0.03 256.802);
--tw-prose-links: oklch(21% 0.034 264.665);
--tw-prose-bold: oklch(21% 0.034 264.665);
--tw-prose-counters: oklch(55.1% 0.027 264.364);
--tw-prose-bullets: oklch(87.2% 0.01 258.338);
--tw-prose-hr: oklch(92.8% 0.006 264.531);
--tw-prose-quotes: oklch(21% 0.034 264.665);
--tw-prose-quote-borders: oklch(92.8% 0.006 264.531);
--tw-prose-captions: oklch(55.1% 0.027 264.364);
--tw-prose-kbd: oklch(21% 0.034 264.665);
--tw-prose-kbd-shadows: NaN NaN NaN;
--tw-prose-code: oklch(21% 0.034 264.665);
--tw-prose-pre-code: oklch(92.8% 0.006 264.531);
--tw-prose-pre-bg: oklch(27.8% 0.033 256.848);
--tw-prose-th-borders: oklch(87.2% 0.01 258.338);
--tw-prose-td-borders: oklch(92.8% 0.006 264.531);
--tw-prose-invert-body: oklch(87.2% 0.01 258.338);
--tw-prose-invert-headings: #fff;
--tw-prose-invert-lead: oklch(70.7% 0.022 261.325);
--tw-prose-invert-links: #fff;
--tw-prose-invert-bold: #fff;
--tw-prose-invert-counters: oklch(70.7% 0.022 261.325);
--tw-prose-invert-bullets: oklch(44.6% 0.03 256.802);
--tw-prose-invert-hr: oklch(37.3% 0.034 259.733);
--tw-prose-invert-quotes: oklch(96.7% 0.003 264.542);
--tw-prose-invert-quote-borders: oklch(37.3% 0.034 259.733);
--tw-prose-invert-captions: oklch(70.7% 0.022 261.325);
--tw-prose-invert-kbd: #fff;
--tw-prose-invert-kbd-shadows: 255 255 255;
--tw-prose-invert-code: #fff;
--tw-prose-invert-pre-code: oklch(87.2% 0.01 258.338);
--tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);
--tw-prose-invert-th-borders: oklch(44.6% 0.03 256.802);
--tw-prose-invert-td-borders: oklch(37.3% 0.034 259.733);
font-size: 1rem;
line-height: 1.75;
:where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0;
margin-bottom: 0;
}
:where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
:where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
padding-inline-start: 0.375em;
}
:where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
padding-inline-start: 0.375em;
}
:where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0.75em;
margin-bottom: 0.75em;
}
:where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 1.25em;
}
:where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-bottom: 1.25em;
}
:where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 1.25em;
}
:where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-bottom: 1.25em;
}
:where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0.75em;
margin-bottom: 0.75em;
}
:where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 1.25em;
margin-bottom: 1.25em;
}
:where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0.5em;
padding-inline-start: 1.625em;
}
:where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0;
}
:where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0;
}
:where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0;
}
:where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0;
}
:where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
padding-inline-start: 0;
}
:where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
padding-inline-end: 0;
}
:where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
padding-top: 0.5714286em;
padding-inline-end: 0.5714286em;
padding-bottom: 0.5714286em;
padding-inline-start: 0.5714286em;
}
:where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
padding-inline-start: 0;
}
:where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
padding-inline-end: 0;
}
:where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 2em;
margin-bottom: 2em;
}
:where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-top: 0;
}
:where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
margin-bottom: 0;
}
} }
.mb-4 { .mb-4 {
margin-bottom: calc(var(--spacing) * 4); margin-bottom: calc(var(--spacing) * 4);
@@ -681,21 +237,15 @@
.hidden { .hidden {
display: none; display: none;
} }
.table {
display: table;
}
.w-full { .w-full {
width: 100%; width: 100%;
} }
.max-w-2xl {
max-width: var(--container-2xl);
}
.max-w-xl { .max-w-xl {
max-width: var(--container-xl); max-width: var(--container-xl);
} }
.border-collapse {
border-collapse: collapse;
}
.resize {
resize: both;
}
.list-none { .list-none {
list-style-type: none; list-style-type: none;
} }
@@ -731,17 +281,25 @@
.py-4 { .py-4 {
padding-block: calc(var(--spacing) * 4); padding-block: calc(var(--spacing) * 4);
} }
.text-center {
text-align: center;
}
.text-2xl { .text-2xl {
font-size: var(--text-2xl); font-size: var(--text-2xl);
line-height: var(--tw-leading, var(--text-2xl--line-height)); line-height: var(--tw-leading, var(--text-2xl--line-height));
} }
.text-3xl {
font-size: var(--text-3xl);
line-height: var(--tw-leading, var(--text-3xl--line-height));
}
.text-lg {
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
}
.text-sm { .text-sm {
font-size: var(--text-sm); font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height)); line-height: var(--tw-leading, var(--text-sm--line-height));
} }
.text-40px {
font-size: var(--text-40px);
}
.leading-none { .leading-none {
--tw-leading: 1; --tw-leading: 1;
line-height: 1; line-height: 1;
@@ -754,24 +312,18 @@
--tw-font-weight: var(--font-weight-medium); --tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
} }
.text-green-700 {
color: var(--color-green-700);
}
.text-primary { .text-primary {
color: var(--color-primary); color: var(--color-primary);
} }
.text-red-600 {
color: var(--color-red-600);
}
.text-white { .text-white {
color: var(--color-white); color: var(--color-white);
} }
.underline {
text-decoration-line: underline;
}
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
.transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.hover\:bg-blue-700 { .hover\:bg-blue-700 {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
@@ -898,6 +450,15 @@ h1 a, .h1 a, h2 a, .h2 a, h3 a, .h3 a {
color: inherit; color: inherit;
text-decoration: underline; text-decoration: underline;
} }
#site_head h1 a {
font-size: var(--text-40px);
color: var(--color-white);
&:hover {
@media (hover: hover) {
color: var(--color-primary-200);
}
}
}
p { p {
margin-top: 0; margin-top: 0;
margin-bottom: 1rem; margin-bottom: 1rem;
@@ -1449,11 +1010,6 @@ footer#site_foot {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
} }
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-space-x-reverse { @property --tw-space-x-reverse {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
@@ -1466,7 +1022,6 @@ footer#site_foot {
--tw-border-style: solid; --tw-border-style: solid;
--tw-leading: initial; --tw-leading: initial;
--tw-font-weight: initial; --tw-font-weight: initial;
--tw-outline-style: solid;
--tw-space-x-reverse: 0; --tw-space-x-reverse: 0;
} }
} }

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Go SSG - Another Blog Post</title> <title>Go SSG - Another Blog Post</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -69,7 +70,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Category: Anger</title> <title>Category: Anger</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -43,7 +44,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Category: Go</title> <title>Category: Go</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -45,7 +46,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Category: Progrmming</title> <title>Category: Progrmming</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -43,7 +44,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Blog Index</title> <title>Blog Index</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -48,7 +49,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Go SSG - My First Blog Post</title> <title>Go SSG - My First Blog Post</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -69,7 +70,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Contact</title> <title>Contact</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -32,8 +33,40 @@
<main> <main>
<article> <article>
<h1>Contact</h1> <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">
<input type="hidden" name="accessKey" value="sf_5m86ek16hmele1jlkl62ghml" />
<input type="hidden" name="redirectTo" value="/thanks/" />
<label>
<span>Name</span>
<input id="name" type="text" name="name" required class="w-full border p-2 rounded" />
<span class="text-red-600 text-sm hidden" data-error="name"></span>
</label>
<label>
<span>Email</span>
<input id="email" type="email" name="email" required class="w-full border p-2 rounded" />
<span class="text-red-600 text-sm hidden" data-error="email"></span>
</label>
<label>
<span>Message</span>
<textarea id="message" name="message" rows="5" required class="w-full border p-2 rounded"></textarea>
<span class="text-red-600 text-sm hidden" data-error="message"></span>
</label>
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
Send Message
</button>
</form>
</article> </article>
</main> </main>
@@ -41,7 +74,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
<script src="/assets/contact.js" defer></script></body>
</body>
</html> </html>

View File

@@ -7,12 +7,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Go SSG - Home</title> <title>Go SSG - Home</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">
@@ -42,7 +43,6 @@
<footer id="site_foot"> <footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p> <p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer> </footer>
</body> </body>
</html> </html>

47
public/thanks/index.html Normal file
View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thank You</title>
<link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head>
<body>
<header id="site_head">
<h1><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>
<div class="max-w-2xl mx-auto mt-10 text-center">
<h1 class="text-3xl font-bold text-green-700 mb-4">Thanks for reaching out!</h1>
<p class="text-lg">Your message has been received. Ill get back to you as soon as I can.</p>
</div>
</main>
<footer id="site_foot">
<p class="p-0 py-4 m-0 leading-none">&copy; 2025 Keith Solomon - Go SSG</p>
</footer>
</body>
</html>

View File

@@ -6,6 +6,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{{ .Title }}</title> <title>{{ .Title }}</title>
<link rel="stylesheet" href="/assets/style.css"> <link rel="stylesheet" href="/assets/style.css">
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
@@ -22,12 +23,18 @@
{{ template "category_content" . }} {{ template "category_content" . }}
{{- else if eq .PageTemplate "contact_page" -}} {{- else if eq .PageTemplate "contact_page" -}}
{{ template "contact_content" . }} {{ template "contact_content" . }}
{{- else if eq .PageTemplate "thanks_page" -}}
{{ template "thanks_content" . }}
{{- else -}} {{- else -}}
<p>Unknown PageTemplate: {{ .PageTemplate }}</p> <p>Unknown PageTemplate: {{ .PageTemplate }}</p>
{{- end -}} {{- end -}}
</main> </main>
{{ template "footer" . }} {{ template "footer" . }}
{{- if eq .PageTemplate "contact_page" -}}
<script src="/assets/contact.js" defer></script>
{{- end -}}
</body> </body>
</html> </html>
{{ end }} {{ end }}

View File

@@ -3,35 +3,40 @@
{{ end }} {{ end }}
{{ define "contact_content" }} {{ define "contact_content" }}
<h1 class="text-2xl font-bold mb-4">Contact Me</h1> <article>
<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"> <form action="https://api.staticforms.xyz/submit" method="POST" class="space-y-4 max-w-xl">
<!-- StaticForms API Key --> <!-- StaticForms API Key -->
<input type="hidden" name="accessKey" value="sf_5m86ek16hmele1jlkl62ghml" /> <input type="hidden" name="accessKey" value="sf_5m86ek16hmele1jlkl62ghml" />
<!-- Optional redirect after success --> <!-- Optional redirect after success -->
<!-- <input type="hidden" name="redirectTo" value="https://yourdomain.com/thanks/" /> --> <input type="hidden" name="redirectTo" value="/thanks/" />
<label class="block"> <label>
<span class="block text-sm font-medium">Your Name</span> <span>Name</span>
<input type="text" name="name" required class="w-full border p-2 rounded" /> <input id="name" type="text" name="name" required class="w-full border p-2 rounded" />
</label> <span class="text-red-600 text-sm hidden" data-error="name"></span>
</label>
<label class="block"> <label>
<span class="block text-sm font-medium">Email Address</span> <span>Email</span>
<input type="email" name="email" required class="w-full border p-2 rounded" /> <input id="email" type="email" name="email" required class="w-full border p-2 rounded" />
</label> <span class="text-red-600 text-sm hidden" data-error="email"></span>
</label>
<label class="block"> <label>
<span class="block text-sm font-medium">Message</span> <span>Message</span>
<textarea name="message" rows="5" required class="w-full border p-2 rounded"></textarea> <textarea id="message" name="message" rows="5" required class="w-full border p-2 rounded"></textarea>
</label> <span class="text-red-600 text-sm hidden" data-error="message"></span>
</label>
<!-- reCAPTCHA if configured in dashboard --> <!-- reCAPTCHA if configured in dashboard -->
<!-- <div class="g-recaptcha" data-sitekey="your-recaptcha-site-key"></div> --> <!-- <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"> <button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
Send Message Send Message
</button> </button>
</form> </form>
</article>
{{ end }} {{ end }}

View File

@@ -1,6 +1,6 @@
{{ define "header" }} {{ define "header" }}
<header id="site_head"> <header id="site_head">
<h1 class="text-white text-40px hover:text-primary-200"><a href="/">Go SSG</a></h1> <h1><a href="/">Go SSG</a></h1>
<nav> <nav>
<ul class="list-none"> <ul class="list-none">

View File

@@ -0,0 +1,10 @@
{{ define "thanks_page" }}
{{ template "base" . }}
{{ end }}
{{ define "thanks_content" }}
<div class="max-w-2xl mx-auto mt-10 text-center">
<h1 class="text-3xl font-bold text-green-700 mb-4">Thanks for reaching out!</h1>
<p class="text-lg">Your message has been received. Ill get back to you as soon as I can.</p>
</div>
{{ end }}