mirror of
https://github.com/facundoolano/jorge.git
synced 2024-12-26 21:58:51 +01:00
expose site posts and tags to template rendering
Squashed commit of the following: commit c45734422ef038438a0b6eb4c3065df9cbebcc5e Author: facundoolano <facundo.olano@gmail.com> Date: Tue Feb 13 21:27:47 2024 -0300 tags test passing commit 88294405603b2103f9f8cba3b130ad2d40e58a36 Author: facundoolano <facundo.olano@gmail.com> Date: Tue Feb 13 21:12:08 2024 -0300 ensure posts are sorted by date commit df7c945fcc1490613b6068da3fc487b9ffa44ba5 Author: facundoolano <facundo.olano@gmail.com> Date: Tue Feb 13 20:55:51 2024 -0300 prepare to test tags commit 3d7c3f380c3933d6cd9f949d3d2cf9ef144bd6ae Author: facundoolano <facundo.olano@gmail.com> Date: Tue Feb 13 20:51:08 2024 -0300 preload context in site fields commit a3afaacc67a9d748cfd42ecbeb7b2d302c3560b2 Author: facundoolano <facundo.olano@gmail.com> Date: Tue Feb 13 20:39:42 2024 -0300 test passing pending refactor commit 13de5017f654c8d82b1ba7beb01066a9c22f19fc Author: facundoolano <facundo.olano@gmail.com> Date: Tue Feb 13 20:18:07 2024 -0300 add (failing) archive test
This commit is contained in:
parent
f9e6d211b1
commit
88efad43db
4 changed files with 175 additions and 39 deletions
|
@ -45,7 +45,7 @@ func Build() error {
|
|||
os.MkdirAll(targetPath, FILE_RW_MODE)
|
||||
} else {
|
||||
|
||||
if templ, ok := site.TemplateIndex[path]; ok {
|
||||
if templ, ok := site.Templates[path]; ok {
|
||||
// if a template was found at source, render it
|
||||
content, err := site.Render(templ)
|
||||
if err != nil {
|
||||
|
|
81
site/site.go
81
site/site.go
|
@ -2,11 +2,14 @@ package site
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/facundoolano/blorg/templates"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/facundoolano/blorg/templates"
|
||||
)
|
||||
|
||||
// TODO review build and other commands and think what can be brought over here.
|
||||
|
@ -14,19 +17,20 @@ import (
|
|||
type Site struct {
|
||||
config map[string]string // may need to make this interface{} if config gets sophisticated
|
||||
layouts map[string]templates.Template
|
||||
posts []templates.Template
|
||||
pages []templates.Template
|
||||
tags map[string]*templates.Template
|
||||
posts []map[string]interface{}
|
||||
pages []map[string]interface{}
|
||||
tags map[string][]map[string]interface{}
|
||||
|
||||
TemplateIndex map[string]*templates.Template
|
||||
Templates map[string]*templates.Template
|
||||
}
|
||||
|
||||
func Load(srcDir string, layoutsDir string) (*Site, error) {
|
||||
// TODO load config from config.yml
|
||||
site := Site{
|
||||
layouts: make(map[string]templates.Template),
|
||||
TemplateIndex: make(map[string]*templates.Template),
|
||||
config: make(map[string]string),
|
||||
layouts: make(map[string]templates.Template),
|
||||
Templates: make(map[string]*templates.Template),
|
||||
config: make(map[string]string),
|
||||
tags: make(map[string][]map[string]interface{}),
|
||||
}
|
||||
|
||||
if err := site.loadLayouts(layoutsDir); err != nil {
|
||||
|
@ -74,7 +78,7 @@ func (site *Site) loadTemplates(srcDir string) error {
|
|||
return fmt.Errorf("couldn't read %s", srcDir)
|
||||
}
|
||||
|
||||
return filepath.WalkDir(srcDir, func(path string, entry fs.DirEntry, err error) error {
|
||||
err = filepath.WalkDir(srcDir, func(path string, entry fs.DirEntry, err error) error {
|
||||
if !entry.IsDir() {
|
||||
templ, err := templates.Parse(path)
|
||||
// if sometime fails or this is not a template, skip
|
||||
|
@ -82,23 +86,58 @@ func (site *Site) loadTemplates(srcDir string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// set site related (?) metadata. Not sure if this should go elsewhere
|
||||
relPath, _ := filepath.Rel(srcDir, path)
|
||||
templ.Metadata["path"] = relPath
|
||||
templ.Metadata["url"] = "/" + strings.TrimSuffix(relPath, ".html")
|
||||
templ.Metadata["dir"] = "/" + filepath.Base(relPath)
|
||||
|
||||
// posts are templates that can be chronologically sorted --that have a date.
|
||||
// the rest are pages.
|
||||
if _, ok := templ.Metadata["date"]; ok {
|
||||
site.posts = append(site.posts, *templ)
|
||||
} else {
|
||||
site.pages = append(site.pages, *templ)
|
||||
}
|
||||
site.TemplateIndex[path] = templ
|
||||
site.posts = append(site.posts, templ.Metadata)
|
||||
|
||||
// TODO load tags
|
||||
// also add to tags index
|
||||
if tags, ok := templ.Metadata["tags"]; ok {
|
||||
for _, tag := range tags.([]interface{}) {
|
||||
tag := tag.(string)
|
||||
site.tags[tag] = append(site.tags[tag], templ.Metadata)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
site.pages = append(site.pages, templ.Metadata)
|
||||
}
|
||||
site.Templates[path] = templ
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sort posts by reverse chronological order
|
||||
Compare := func(a map[string]interface{}, b map[string]interface{}) int {
|
||||
return b["date"].(time.Time).Compare(a["date"].(time.Time))
|
||||
}
|
||||
slices.SortFunc(site.posts, Compare)
|
||||
for _, posts := range site.tags {
|
||||
slices.SortFunc(posts, Compare)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (site Site) Render(templ *templates.Template) (string, error) {
|
||||
ctx := site.baseContext()
|
||||
ctx := map[string]interface{}{
|
||||
"site": map[string]interface{}{
|
||||
"config": site.config,
|
||||
"posts": site.posts,
|
||||
"tags": site.tags,
|
||||
"pages": site.pages,
|
||||
},
|
||||
}
|
||||
|
||||
ctx["page"] = templ.Metadata
|
||||
content, err := templ.Render(ctx)
|
||||
if err != nil {
|
||||
|
@ -120,13 +159,3 @@ func (site Site) Render(templ *templates.Template) (string, error) {
|
|||
|
||||
return content, err
|
||||
}
|
||||
|
||||
func (site Site) baseContext() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"site": map[string]interface{}{
|
||||
"config": site.config,
|
||||
"posts": site.posts,
|
||||
"tags": site.tags,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func TestLoadAndRenderTemplates(t *testing.T) {
|
||||
root, src, layouts := newProject()
|
||||
root, layouts, src := newProject()
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
// add two layouts
|
||||
|
@ -40,7 +40,8 @@ date: 2024-01-01
|
|||
---
|
||||
<p>Hello world!</p>`
|
||||
file = newFile(src, "hello.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
helloPath := file.Name()
|
||||
defer os.Remove(helloPath)
|
||||
|
||||
content = `---
|
||||
layout: post
|
||||
|
@ -50,7 +51,8 @@ date: 2024-02-01
|
|||
---
|
||||
<p>goodbye world!</p>`
|
||||
file = newFile(src, "goodbye.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
goodbyePath := file.Name()
|
||||
defer os.Remove(goodbyePath)
|
||||
|
||||
// add a page (no date)
|
||||
content = `---
|
||||
|
@ -59,7 +61,8 @@ title: about
|
|||
---
|
||||
<p>about this site</p>`
|
||||
file = newFile(src, "about.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
aboutPath := file.Name()
|
||||
defer os.Remove(aboutPath)
|
||||
|
||||
// add a static file (no front matter)
|
||||
content = `go away!`
|
||||
|
@ -78,8 +81,7 @@ title: about
|
|||
_, ok = site.layouts["post"]
|
||||
assert(t, ok)
|
||||
|
||||
hello := site.posts[1]
|
||||
content, err = site.Render(&hello)
|
||||
content, err = site.Render(site.Templates[helloPath])
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, content, `<html>
|
||||
<head><title>hello world!</title></head>
|
||||
|
@ -90,8 +92,7 @@ title: about
|
|||
</body>
|
||||
</html>`)
|
||||
|
||||
goodbye := site.posts[0]
|
||||
content, err = site.Render(&goodbye)
|
||||
content, err = site.Render(site.Templates[goodbyePath])
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, content, `<html>
|
||||
<head><title>goodbye!</title></head>
|
||||
|
@ -102,8 +103,7 @@ title: about
|
|||
</body>
|
||||
</html>`)
|
||||
|
||||
about := site.pages[0]
|
||||
content, err = site.Render(&about)
|
||||
content, err = site.Render(site.Templates[aboutPath])
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, content, `<html>
|
||||
<head><title>about</title></head>
|
||||
|
@ -115,10 +115,117 @@ title: about
|
|||
}
|
||||
|
||||
func TestRenderArchive(t *testing.T) {
|
||||
// TODO
|
||||
root, layouts, src := newProject()
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
content := `---
|
||||
title: hello world!
|
||||
date: 2024-01-01
|
||||
---
|
||||
<p>Hello world!</p>`
|
||||
file := newFile(src, "hello.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
content = `---
|
||||
title: goodbye!
|
||||
date: 2024-02-01
|
||||
---
|
||||
<p>goodbye world!</p>`
|
||||
file = newFile(src, "goodbye.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
content = `---
|
||||
title: an oldie!
|
||||
date: 2023-01-01
|
||||
---
|
||||
<p>oldie</p>`
|
||||
file = newFile(src, "an-oldie.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
// add a page (no date)
|
||||
content = `---
|
||||
---
|
||||
<ul>{% for post in site.posts %}
|
||||
<li>{{ post.date | date: "%Y-%m-%d" }} <a href="{{ post.url }}">{{post.title}}</a></li>{%endfor%}
|
||||
</ul>`
|
||||
|
||||
file = newFile(src, "about.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
site, err := Load(src, layouts)
|
||||
content, err = site.Render(site.Templates[file.Name()])
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, content, `<ul>
|
||||
<li>2024-02-01 <a href="/goodbye">goodbye!</a></li>
|
||||
<li>2024-01-01 <a href="/hello">hello world!</a></li>
|
||||
<li>2023-01-01 <a href="/an-oldie">an oldie!</a></li>
|
||||
</ul>`)
|
||||
}
|
||||
|
||||
func TestRenderTags(t *testing.T) {
|
||||
root, layouts, src := newProject()
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
content := `---
|
||||
title: hello world!
|
||||
date: 2024-01-01
|
||||
tags: [web, software]
|
||||
---
|
||||
<p>Hello world!</p>`
|
||||
file := newFile(src, "hello.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
content = `---
|
||||
title: goodbye!
|
||||
date: 2024-02-01
|
||||
tags: [web]
|
||||
---
|
||||
<p>goodbye world!</p>`
|
||||
file = newFile(src, "goodbye.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
content = `---
|
||||
title: an oldie!
|
||||
date: 2023-01-01
|
||||
tags: [software]
|
||||
---
|
||||
<p>oldie</p>`
|
||||
file = newFile(src, "an-oldie.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
// add a page (no date)
|
||||
content = `---
|
||||
---
|
||||
{% for tag in site.tags %}<h1>{{tag[0]}}</h1>{% for post in tag[1] %}
|
||||
{{post.title}}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
`
|
||||
|
||||
file = newFile(src, "about.html", content)
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
site, err := Load(src, layouts)
|
||||
content, err = site.Render(site.Templates[file.Name()])
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, content, `<h1>software</h1>
|
||||
hello world!
|
||||
|
||||
an oldie!
|
||||
|
||||
<h1>web</h1>
|
||||
goodbye!
|
||||
|
||||
hello world!
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
func TestRenderPagesInDir(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func TestRenderArchiveWithExcerpts(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ func Parse(path string) (*Template, error) {
|
|||
return nil, errors.New("front matter not closed")
|
||||
}
|
||||
|
||||
var metadata map[string]interface{}
|
||||
metadata := make(map[string]interface{})
|
||||
if len(yamlContent) != 0 {
|
||||
err := yaml.Unmarshal([]byte(yamlContent), &metadata)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue