From 0b61d3995bc01a5c8345b719459da261b92d3063 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Mon, 15 Apr 2024 11:11:20 +0200 Subject: wip: render 404 and home pages --- cmd/build/main.go | 126 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 25 deletions(-) diff --git a/cmd/build/main.go b/cmd/build/main.go index 48c9739..0776951 100644 --- a/cmd/build/main.go +++ b/cmd/build/main.go @@ -17,9 +17,11 @@ import ( "github.com/PuerkitoBio/goquery" "github.com/adrg/frontmatter" "github.com/antchfx/xmlquery" + "github.com/antchfx/xpath" mapset "github.com/deckarep/golang-set/v2" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/renderer/html" ) type PostMatter struct { @@ -67,6 +69,9 @@ func readPosts(root string, inputDir string, outputDir string) ([]Post, Tags) { urlReplacer := strings.NewReplacer(root, "", ".md", "/") check(err) md := goldmark.New( + goldmark.WithRendererOptions( + html.WithUnsafe(), + ), goldmark.WithExtensions( extension.GFM, extension.Footnote, @@ -106,13 +111,15 @@ func readPosts(root string, inputDir string, outputDir string) ([]Post, Tags) { return posts, tags } -func layout(html string, config Config, pageTitle string) *goquery.Document { +func layout(filename string, config Config, pageTitle string) *goquery.Document { css, err := os.ReadFile("templates/style.css") check(err) - doc, err := goquery.NewDocumentFromReader(strings.NewReader(html)) + html, err := os.Open(filename) + doc, err := goquery.NewDocumentFromReader(html) check(err) doc.Find("html").SetAttr("lang", config.DefaultLanguage) - doc.Find("head > link[rel=alternate]").Add(".title").SetAttr("title", config.Title) + doc.Find("head > link[rel=alternate]").SetAttr("title", config.Title) + doc.Find(".title").SetText(config.Title) doc.Find("title").Add(".p-name").SetText(pageTitle) doc.Find("head > style").SetText(string(css)) nav := doc.Find("nav") @@ -125,9 +132,7 @@ func layout(html string, config Config, pageTitle string) *goquery.Document { } func renderPost(post Post, config Config) string { - tbytes, err := os.ReadFile("templates/post.html") - check(err) - doc := layout(string(tbytes), config, post.PostMatter.Title) + doc := layout("templates/post.html", config, post.PostMatter.Title) doc.Find(".title").AddClass("h-card p-author").SetAttr("rel", "author") datetime, err := post.PostMatter.Date.MarshalText() check(err) @@ -147,10 +152,7 @@ func renderPost(post Post, config Config) string { } func renderTags(tags Tags, config Config) string { - tbytes, err := os.ReadFile("templates/tags.html") - check(err) - - doc := layout(string(tbytes), config, config.Title) + doc := layout("templates/tags.html", config, config.Title) tagList := doc.Find(".tags") tpl := doc.Find(".h-feed") tpl.Remove() @@ -165,15 +167,13 @@ func renderTags(tags Tags, config Config) string { } func renderListPage(tag string, config Config, posts []Post) string { - tbytes, err := os.ReadFile("templates/list.html") - check(err) var title string if len(tag) > 0 { title = tag } else { title = config.Title } - doc := layout(string(tbytes), config, title) + doc := layout("templates/list.html", config, title) feed := doc.Find(".h-feed") tpl := feed.Find(".h-entry") tpl.Remove() @@ -200,6 +200,61 @@ func renderListPage(tag string, config Config, posts []Post) string { return html } +func renderHomepage(config Config, posts []Post) string { + _, index := getPost("content/_index.md") + doc := layout("templates/homepage.html", config, config.Title) + doc.Find("body").AddClass("h-card") + doc.Find(".title").AddClass("p-name u-url") + var buf bytes.Buffer + + md := goldmark.New(goldmark.WithRendererOptions(html.WithUnsafe())) + err := md.Convert(index, &buf) + check(err) + doc.Find("#content").SetHtml(buf.String()) + + feed := doc.Find(".h-feed") + tpl := feed.Find(".h-entry") + tpl.Remove() + + for _, post := range posts { + entry := tpl.Clone() + entry.Find(".p-name").SetText(post.Title) + entry.Find(".u-url").SetAttr("href", post.URL) + datetime, err := post.PostMatter.Date.MarshalText() + check(err) + entry. + Find(".dt-published"). + SetAttr("datetime", string(datetime)). + SetText(post.PostMatter.Date.Format("2006-01-02")) + + feed.AppendSelection(entry) + } + doc.Find(".u-email"). + SetAttr("href", fmt.Sprintf("mailto:%s", config.Email)). + SetText(config.Email) + + elsewhere := doc.Find(".elsewhere") + linkRelMe := elsewhere.Find(".u-url[rel=me]").ParentsUntil("ul") + linkRelMe.Remove() + + for _, link := range config.Menus["me"] { + el := linkRelMe.Clone() + el.Find("a").SetAttr("href", link.URL).SetText(link.Name) + elsewhere.AppendSelection(el) + } + + html, err := doc.Html() + check(err) + return html +} + +func render404(config Config) string { + doc := layout("templates/404.html", config, "404 Not Found") + html, err := doc.Html() + check(err) + return html +} + func renderFeed(title string, config Config, posts []Post, specific string) string { reader, err := os.Open("templates/feed.xml") check(err) @@ -241,24 +296,46 @@ func renderFeed(title string, config Config, posts []Post, specific string) stri return doc.OutputXML(true) } +func renderFeedStyles() string { + reader, err := os.Open("templates/feed-styles.xsl") + nsMap := map[string]string{ + "xsl": "http://www.w3.org/1999/XSL/Transform", + "atom": "http://www.w3.org/2005/Atom", + "xhtml": "http://www.w3.org/1999/xhtml", + } + check(err) + doc, err := xmlquery.Parse(reader) + expr, err := xpath.CompileWithNS("//xhtml:style", nsMap) + check(err) + style := xmlquery.QuerySelector(doc, expr) + css, err := os.ReadFile("templates/style.css") + check(err) + xmlquery.AddChild(style, &xmlquery.Node{ + Type: xmlquery.TextNode, + Data: string(css), + }) + return doc.OutputXML(true) +} + func main() { err, config := GetConfig() + outDir := "new" check(err) - err = os.MkdirAll("public/post", 0755) + err = os.MkdirAll(path.Join(outDir, "post"), 0755) check(err) log.Print("Generating site...") - posts, tags := readPosts("content", "post", "public") + posts, tags := readPosts("content", "post", outDir) for _, post := range posts { - err := os.MkdirAll(path.Join("public", "post", post.Basename), 0755) + err := os.MkdirAll(path.Join(outDir, "post", post.Basename), 0755) check(err) // output := renderPost(post, config) // err = os.WriteFile(post.Output, []byte(output), 0755) // check(err) } - err = os.MkdirAll("public/tags", 0755) + err = os.MkdirAll(path.Join(outDir, "tags"), 0755) check(err) // fmt.Printf("%+v\n", renderTags(tags, config)) - // err = os.WriteFile("public/tags/index.html", []byte(renderTags(tags, config)), 0755) + // err = os.WriteFile(path.Join(outDir, "tags", "index.html"), []byte(renderTags(tags, config)), 0755) // check(err) for _, tag := range tags.ToSlice() { matchingPosts := []Post{} @@ -267,26 +344,25 @@ func main() { matchingPosts = append(matchingPosts, post) } } - err := os.MkdirAll(path.Join("public", "tags", tag), 0755) + err := os.MkdirAll(path.Join(outDir, "tags", tag), 0755) check(err) // tagPage := renderListPage(tag, config, matchingPosts) // fmt.Printf("%+v\n", tagPage) - // err = os.WriteFile(path.Join("public", "tags", tag, "index.html"), []byte(tagPage), 0755) + // err = os.WriteFile(path.Join(outDir, "tags", tag, "index.html"), []byte(tagPage), 0755) // check(err) - // TODO: tag atom // fmt.Printf("%+v\n", renderFeed(fmt.Sprintf("%s - %s", config.Title, tag), config, matchingPosts, tag)) // fmt.Printf("%+v\n", renderListPage("", config, posts)) - // TODO: atom // fmt.Printf("%+v\n", renderFeed(config.Title, config, posts, "feed")) - // TODO: renderFeedStyles + // fmt.Printf("%+v\n", renderFeedStyles()) - // TODO: renderHomepage + // fmt.Printf("%+v\n", renderHomepage(config, posts)) - // TODO: render404Page + fmt.Printf("%+v\n", render404(config)) + fmt.Println(config.DefaultLanguage) } fmt.Printf("%+v\n", tags) -- cgit 1.4.1