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

View File

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

View File

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

33
user.go
View File

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

View File

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