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
|
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"`
|
||||||
|
|
|
@ -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 (
|
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),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
33
user.go
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue