split templates into one file per type

This commit is contained in:
Niko Abeler 2022-12-05 19:51:42 +01:00
parent 9209f227c4
commit b61e2ff50c
10 changed files with 276 additions and 26 deletions

72
embed/article/detail.html Normal file
View File

@ -0,0 +1,72 @@
<div class="h-entry">
<hgroup>
<h1 class="p-name">{{.Title}}</h1>
<small>
<a class="u-url" href="{{.Post.FullUrl}}">#</a>
Published:
<time class="dt-published" datetime="{{.Post.Meta.Date}}">
{{.Post.Meta.FormattedDate}}
</time>
{{ if .Post.User.Config.AuthorName }}
by
<a class="p-author h-card" href="{{.Post.User.FullUrl}}">
{{ if .Post.User.AvatarUrl }}
<img class="u-photo u-logo" style="height: 1em;" src="{{ .Post.User.AvatarUrl }}"
alt="{{ .Post.User.Config.Title }}" />
{{ end }}
{{.Post.User.Config.AuthorName}}
</a>
{{ end }}
</small>
</hgroup>
<hr>
<br>
{{ if .Post.Meta.Reply.Url }}
<p style="font-style: italic;filter: opacity(80%);">
In reply to: <a class="u-in-reply-to h-cite" rel="in-reply-to" href="{{.Post.Meta.Reply.Url}}">
{{ if .Post.Meta.Reply.Text }}
{{.Post.Meta.Reply.Text}}
{{ else }}
{{.Post.Meta.Reply.Url}}
{{ end }}
</a>
</p>
{{ end }}
{{ if .Post.Meta.Bookmark.Url }}
<p style="font-style: italic;filter: opacity(80%);">
Bookmark: <a class="u-bookmark-of h-cite" href="{{.Post.Meta.Bookmark.Url}}">
{{ if .Post.Meta.Bookmark.Text }}
{{.Post.Meta.Bookmark.Text}}
{{ else }}
{{.Post.Meta.Bookmark.Url}}
{{ end }}
</a>
</p>
{{ end }}
<div class="e-content">
{{.Content}}
</div>
<hr>
{{if .Post.ApprovedIncomingWebmentions}}
<h3>
Webmentions
</h3>
<ul>
{{range .Post.ApprovedIncomingWebmentions}}
<li>
<a href="{{.Source}}">
{{if .Title}}
{{.Title}}
{{else}}
{{.Source}}
{{end}}
</a>
</li>
{{end}}
</ul>
{{end}}
</div>

72
embed/note/detail.html Normal file
View File

@ -0,0 +1,72 @@
<div class="h-entry">
<hgroup>
<h1 class="p-name">{{.Title}}</h1>
<small>
<a class="u-url" href="{{.Post.FullUrl}}">#</a>
Published:
<time class="dt-published" datetime="{{.Post.Meta.Date}}">
{{.Post.Meta.FormattedDate}}
</time>
{{ if .Post.User.Config.AuthorName }}
by
<a class="p-author h-card" href="{{.Post.User.FullUrl}}">
{{ if .Post.User.AvatarUrl }}
<img class="u-photo u-logo" style="height: 1em;" src="{{ .Post.User.AvatarUrl }}"
alt="{{ .Post.User.Config.Title }}" />
{{ end }}
{{.Post.User.Config.AuthorName}}
</a>
{{ end }}
</small>
</hgroup>
<hr>
<br>
{{ if .Post.Meta.Reply.Url }}
<p style="font-style: italic;filter: opacity(80%);">
In reply to: <a class="u-in-reply-to h-cite" rel="in-reply-to" href="{{.Post.Meta.Reply.Url}}">
{{ if .Post.Meta.Reply.Text }}
{{.Post.Meta.Reply.Text}}
{{ else }}
{{.Post.Meta.Reply.Url}}
{{ end }}
</a>
</p>
{{ end }}
{{ if .Post.Meta.Bookmark.Url }}
<p style="font-style: italic;filter: opacity(80%);">
Bookmark: <a class="u-bookmark-of h-cite" href="{{.Post.Meta.Bookmark.Url}}">
{{ if .Post.Meta.Bookmark.Text }}
{{.Post.Meta.Bookmark.Text}}
{{ else }}
{{.Post.Meta.Bookmark.Url}}
{{ end }}
</a>
</p>
{{ end }}
<div class="e-content">
{{.Content}}
</div>
<hr>
{{if .Post.ApprovedIncomingWebmentions}}
<h3>
Webmentions
</h3>
<ul>
{{range .Post.ApprovedIncomingWebmentions}}
<li>
<a href="{{.Source}}">
{{if .Title}}
{{.Title}}
{{else}}
{{.Source}}
{{end}}
</a>
</li>
{{end}}
</ul>
{{end}}
</div>

34
embed/page/detail.html Normal file
View File

@ -0,0 +1,34 @@
<div class="h-entry">
<hgroup>
<h1 class="p-name">{{.Title}}</h1>
<small>
<a class="u-url" href="{{.Post.FullUrl}}">#</a>
</small>
</hgroup>
<hr>
<br>
<div class="e-content">
{{.Content}}
</div>
<hr>
{{if .Post.ApprovedIncomingWebmentions}}
<h3>
Webmentions
</h3>
<ul>
{{range .Post.ApprovedIncomingWebmentions}}
<li>
<a href="{{.Source}}">
{{if .Title}}
{{.Title}}
{{else}}
{{.Source}}
{{end}}
</a>
</li>
{{end}}
</ul>
{{end}}
</div>

34
post.go
View File

@ -25,6 +25,40 @@ type Post struct {
wmLock sync.Mutex wmLock sync.Mutex
} }
func (post *Post) TemplateDir() string {
return "article"
}
type IPost interface {
TemplateDir() string
Id() string
User() *User
Dir() string
IncomingWebmentionsFile() string
OutgoingWebmentionsFile() string
MediaDir() string
UrlPath() string
FullUrl() string
UrlMediaPath(filename string) string
Title() string
ContentFile() string
Meta() PostMeta
Content() []byte
RenderedContent() string
Aliases() []string
LoadMeta() error
IncomingWebmentions() []WebmentionIn
OutgoingWebmentions() []WebmentionOut
PersistIncomingWebmention(webmention WebmentionIn) error
PersistOutgoingWebmention(webmention *WebmentionOut) error
AddIncomingWebmention(source string) error
EnrichWebmention(webmention WebmentionIn) error
ApprovedIncomingWebmentions() []WebmentionIn
ScanForLinks() error
SendWebmention(webmention WebmentionOut) error
}
type Reply struct { type Reply struct {
Url string `yaml:"url"` Url string `yaml:"url"`
Text string `yaml:"text"` Text string `yaml:"text"`

25
post_types.go Normal file
View File

@ -0,0 +1,25 @@
package owl
type Note struct {
Post
}
func (n *Note) TemplateDir() string {
return "note"
}
type Article struct {
Post
}
func (a *Article) TemplateDir() string {
return "article"
}
type Page struct {
Post
}
func (p *Page) TemplateDir() string {
return "page"
}

View File

@ -3,6 +3,7 @@ package owl
import ( import (
"bytes" "bytes"
_ "embed" _ "embed"
"fmt"
"html/template" "html/template"
"strings" "strings"
) )
@ -17,7 +18,7 @@ type PageContent struct {
type PostRenderData struct { type PostRenderData struct {
Title string Title string
Post *Post Post IPost
Content template.HTML Content template.HTML
} }
@ -118,23 +119,26 @@ func renderIntoBaseTemplate(user User, data PageContent) (string, error) {
return html.String(), err return html.String(), err
} }
func renderPostContent(post *Post) (string, error) { func renderPostContent(post IPost) (string, error) {
buf := post.RenderedContent() buf := post.RenderedContent()
postHtml, err := renderEmbedTemplate("embed/post.html", PostRenderData{ postHtml, err := renderEmbedTemplate(
Title: post.Title(), fmt.Sprintf("embed/%s/detail.html", post.TemplateDir()),
Post: post, PostRenderData{
Content: template.HTML(buf), Title: post.Title(),
}) Post: post,
Content: template.HTML(buf),
},
)
return postHtml, err return postHtml, err
} }
func RenderPost(post *Post) (string, error) { func RenderPost(post IPost) (string, error) {
postHtml, err := renderPostContent(post) postHtml, err := renderPostContent(post)
if err != nil { if err != nil {
return "", err return "", err
} }
return renderIntoBaseTemplate(*post.user, PageContent{ return renderIntoBaseTemplate(*post.User(), PageContent{
Title: post.Title(), Title: post.Title(),
Description: post.Meta().Description, Description: post.Meta().Description,
Content: template.HTML(postHtml), Content: template.HTML(postHtml),

View File

@ -158,12 +158,12 @@ func (repo Repository) GetUser(name string) (User, error) {
return user, nil return user, nil
} }
func (repo Repository) PostAliases() (map[string]*Post, error) { func (repo Repository) PostAliases() (map[string]IPost, error) {
users, err := repo.Users() users, err := repo.Users()
if err != nil { if err != nil {
return nil, err return nil, err
} }
aliases := make(map[string]*Post) aliases := make(map[string]IPost)
for _, user := range users { for _, user := range users {
user_aliases, err := user.PostAliases() user_aliases, err := user.PostAliases()
if err != nil { if err != nil {

View File

@ -213,7 +213,7 @@ func TestCanGetMapWithAllPostAliases(t *testing.T) {
posts, _ := user.PublishedPosts() posts, _ := user.PublishedPosts()
assertions.AssertLen(t, posts, 1) assertions.AssertLen(t, posts, 1)
var aliases map[string]*owl.Post var aliases map[string]owl.IPost
aliases, err := repo.PostAliases() aliases, err := repo.PostAliases()
assertions.AssertNoError(t, err, "Error getting post aliases: ") assertions.AssertNoError(t, err, "Error getting post aliases: ")
assertions.AssertMapLen(t, aliases, 2) assertions.AssertMapLen(t, aliases, 2)
@ -247,7 +247,7 @@ func TestAliasesHaveCorrectPost(t *testing.T) {
posts, _ := user.PublishedPosts() posts, _ := user.PublishedPosts()
assertions.AssertLen(t, posts, 2) assertions.AssertLen(t, posts, 2)
var aliases map[string]*owl.Post var aliases map[string]owl.IPost
aliases, err := repo.PostAliases() aliases, err := repo.PostAliases()
assertions.AssertNoError(t, err, "Error getting post aliases: ") assertions.AssertNoError(t, err, "Error getting post aliases: ")
assertions.AssertMapLen(t, aliases, 2) assertions.AssertMapLen(t, aliases, 2)

33
user.go
View File

@ -197,9 +197,9 @@ func (user User) FaviconUrl() string {
return "" return ""
} }
func (user User) AllPosts() ([]*Post, error) { func (user User) AllPosts() ([]IPost, error) {
postFiles := listDir(path.Join(user.Dir(), "public")) postFiles := listDir(path.Join(user.Dir(), "public"))
posts := make([]*Post, 0) posts := make([]IPost, 0)
for _, id := range postFiles { for _, id := range postFiles {
// if is a directory and has index.md, add to posts // if is a directory and has index.md, add to posts
if dirExists(path.Join(user.Dir(), "public", id)) { if dirExists(path.Join(user.Dir(), "public", id)) {
@ -211,7 +211,7 @@ func (user User) AllPosts() ([]*Post, error) {
} }
type PostWithDate struct { type PostWithDate struct {
post *Post post IPost
date time.Time date time.Time
} }
@ -233,7 +233,7 @@ func (user User) AllPosts() ([]*Post, error) {
return posts, nil return posts, nil
} }
func (user User) PublishedPosts() ([]*Post, error) { func (user User) PublishedPosts() ([]IPost, error) {
posts, _ := user.AllPosts() posts, _ := user.AllPosts()
// remove drafts // remove drafts
@ -249,7 +249,7 @@ func (user User) PublishedPosts() ([]*Post, error) {
return posts, nil return posts, nil
} }
func (user User) PrimaryFeedPosts() ([]*Post, error) { func (user User) PrimaryFeedPosts() ([]IPost, error) {
config := user.Config() config := user.Config()
include := config.PrimaryListInclude include := config.PrimaryListInclude
if len(include) == 0 { if len(include) == 0 {
@ -262,7 +262,7 @@ func (user User) PrimaryFeedPosts() ([]*Post, error) {
}) })
} }
func (user User) GetPostsOfList(list PostList) ([]*Post, error) { func (user User) GetPostsOfList(list PostList) ([]IPost, error) {
posts, _ := user.PublishedPosts() posts, _ := user.PublishedPosts()
// remove posts not included // remove posts not included
@ -278,17 +278,26 @@ func (user User) GetPostsOfList(list PostList) ([]*Post, error) {
return posts, nil return posts, nil
} }
func (user User) GetPost(id string) (*Post, error) { func (user User) GetPost(id string) (IPost, error) {
// check if posts index.md exists // check if posts index.md exists
if !fileExists(path.Join(user.Dir(), "public", id, "index.md")) { if !fileExists(path.Join(user.Dir(), "public", id, "index.md")) {
return &Post{}, fmt.Errorf("post %s does not exist", id) return &Post{}, fmt.Errorf("post %s does not exist", id)
} }
post := Post{user: &user, id: id} post := Post{user: &user, id: id}
if post.Meta().Type == "" {
return &Article{Post: post}, nil
}
switch post.Meta().Type {
case "article":
return &Article{Post: post}, nil
case "note":
return &Note{Post: post}, nil
}
return &post, nil return &post, nil
} }
func (user User) CreateNewPostFull(meta PostMeta, content string) (*Post, error) { func (user User) CreateNewPostFull(meta PostMeta, content string) (IPost, error) {
slugHint := meta.Title slugHint := meta.Title
if slugHint == "" { if slugHint == "" {
slugHint = "note" slugHint = "note"
@ -326,10 +335,10 @@ func (user User) CreateNewPostFull(meta PostMeta, content string) (*Post, error)
os.WriteFile(post.ContentFile(), []byte(initial_content), 0644) os.WriteFile(post.ContentFile(), []byte(initial_content), 0644)
// create media dir // create media dir
os.Mkdir(post.MediaDir(), 0755) os.Mkdir(post.MediaDir(), 0755)
return &post, nil return user.GetPost(post.Id())
} }
func (user User) CreateNewPost(title string, draft bool) (*Post, error) { func (user User) CreateNewPost(title string, draft bool) (IPost, error) {
meta := PostMeta{ meta := PostMeta{
Title: title, Title: title,
Date: time.Now(), Date: time.Now(),
@ -359,8 +368,8 @@ func (user User) SetConfig(new_config UserConfig) error {
return saveToYaml(user.ConfigFile(), new_config) return saveToYaml(user.ConfigFile(), new_config)
} }
func (user User) PostAliases() (map[string]*Post, error) { func (user User) PostAliases() (map[string]IPost, error) {
post_aliases := make(map[string]*Post) post_aliases := make(map[string]IPost)
posts, err := user.PublishedPosts() posts, err := user.PublishedPosts()
if err != nil { if err != nil {
return post_aliases, err return post_aliases, err

View File

@ -225,7 +225,7 @@ func TestPostsSortedByPublishingDateLatestFirst(t *testing.T) {
func TestPostsSortedByPublishingDateLatestFirst2(t *testing.T) { func TestPostsSortedByPublishingDateLatestFirst2(t *testing.T) {
user := getTestUser() user := getTestUser()
// Create a new post // Create a new post
posts := []*owl.Post{} posts := []owl.IPost{}
for i := 59; i >= 0; i-- { for i := 59; i >= 0; i-- {
post, _ := user.CreateNewPost("testpost", false) post, _ := user.CreateNewPost("testpost", false)
content := "---\n" content := "---\n"