split templates into one file per type
This commit is contained in:
parent
9209f227c4
commit
b61e2ff50c
|
@ -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>
|
|
@ -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>
|
|
@ -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
34
post.go
|
@ -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"`
|
||||
|
|
|
@ -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"
|
||||
}
|
22
renderer.go
22
renderer.go
|
@ -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{
|
||||
Title: post.Title(),
|
||||
Post: post,
|
||||
Content: template.HTML(buf),
|
||||
})
|
||||
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),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
33
user.go
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue