package main
import (
"fmt"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
"github.com/russross/blackfriday/v2"
)
// NavItem represents a link in the navigation menu
type NavItem struct {
Title string
URL string
}
func main() {
contentDir := "./content"
outputDir := "./public"
templateFile := "./templates/layout.html"
tpl, err := parseTemplate(templateFile)
if err != nil {
fmt.Printf("Template parsing error: %v\n", err)
return
}
files, err := readContentFiles(contentDir)
if err != nil {
fmt.Printf("Failed to read content directory: %v\n", err)
return
}
nav := buildNavigation(files)
for _, file := range files {
if filepath.Ext(file.Name()) == ".md" {
err := generateHTML(file, contentDir, outputDir, tpl, nav)
if err != nil {
fmt.Printf("Error generating HTML for %s: %v\n", file.Name(), err)
}
}
}
fmt.Println("✅ Site generation complete.")
}
func parseTemplate(templateFile string) (*template.Template, error) {
return template.ParseFiles(templateFile)
}
func readContentFiles(contentDir string) ([]os.FileInfo, error) {
return ioutil.ReadDir(contentDir)
}
func buildNavigation(files []os.FileInfo) []NavItem {
var nav []NavItem
for _, file := range files {
if filepath.Ext(file.Name()) == ".md" {
name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
title := strings.Title(name)
url := "/"
if name != "index" {
url = "/" + name + "/"
}
nav = append(nav, NavItem{Title: title, URL: url})
}
}
return nav
}
func generateHTML(file os.FileInfo, contentDir, outputDir string, tpl *template.Template, nav []NavItem) error {
name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
title := strings.Title(name)
mdPath := filepath.Join(contentDir, file.Name())
mdContent, err := ioutil.ReadFile(mdPath)
if err != nil {
return fmt.Errorf("failed to read %s: %w", file.Name(), err)
}
htmlContent := blackfriday.Run(mdContent)
var outPath string
if name == "index" {
outPath = filepath.Join(outputDir, "index.html")
} else {
subDir := filepath.Join(outputDir, name)
os.MkdirAll(subDir, os.ModePerm)
outPath = filepath.Join(subDir, "index.html")
}
outFile, err := os.Create(outPath)
if err != nil {
return fmt.Errorf("failed to create %s: %w", outPath, err)
}
defer outFile.Close()
data := map[string]interface{}{
"Content": template.HTML(htmlContent),
"Title": title,
"Nav": nav,
"Year": time.Now().Year(),
"Date": time.Now().Format("January 2, 2006"),
}
return tpl.Execute(outFile, data)
}