mirror of
https://github.com/jlelse/GoBlog
synced 2024-06-14 15:37:08 +00:00
Replace more templates
This commit is contained in:
parent
bf812d9650
commit
e02ec1cd71
|
@ -1,6 +1,6 @@
|
|||
# How to use GoBlog
|
||||
|
||||
This section of the documentation is a work in progress!
|
||||
This section of the documentation is a **work in progress**!
|
||||
|
||||
## Posting
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
// Check if files at all
|
||||
if len(files) == 0 {
|
||||
a.render(w, r, templateEditorFiles, &renderData{
|
||||
Data: map[string]interface{}{},
|
||||
a.renderNew(w, r, a.renderEditorFiles, &renderData{
|
||||
Data: &editorFilesRenderData{},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
@ -39,10 +39,10 @@ func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
// Serve HTML
|
||||
a.render(w, r, templateEditorFiles, &renderData{
|
||||
Data: map[string]interface{}{
|
||||
"Files": files,
|
||||
"Uses": uses,
|
||||
a.renderNew(w, r, a.renderEditorFiles, &renderData{
|
||||
Data: &editorFilesRenderData{
|
||||
files: files,
|
||||
uses: uses,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -55,7 +55,7 @@ require (
|
|||
// master
|
||||
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
|
||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
|
||||
golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8
|
||||
golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/text v0.3.7
|
||||
|
|
4
go.sum
4
go.sum
|
@ -472,8 +472,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI=
|
||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 h1:kACShD3qhmr/3rLmg1yXyt+N4HcwutKyPRB93s54TIU=
|
||||
golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
|
|
@ -31,7 +31,7 @@ func (a *goBlog) indieAuthRequest(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
// Render page that let's the user authorize the app
|
||||
a.render(w, r, templateIndieAuth, &renderData{
|
||||
a.renderNew(w, r, a.renderIndieAuth, &renderData{
|
||||
Data: iareq,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -154,13 +154,13 @@ func (a *goBlog) notificationsAdmin(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
nextPath = fmt.Sprintf("%s/page/%d", notificationsPath, nextPage)
|
||||
// Render
|
||||
a.render(w, r, templateNotificationsAdmin, &renderData{
|
||||
Data: map[string]interface{}{
|
||||
"Notifications": notifications,
|
||||
"HasPrev": hasPrev,
|
||||
"HasNext": hasNext,
|
||||
"Prev": prevPath,
|
||||
"Next": nextPath,
|
||||
a.renderNew(w, r, a.renderNotificationsAdmin, &renderData{
|
||||
Data: ¬ificationsRenderData{
|
||||
notifications: notifications,
|
||||
hasPrev: hasPrev,
|
||||
hasNext: hasNext,
|
||||
prev: prevPath,
|
||||
next: nextPath,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
11
postsDb.go
11
postsDb.go
|
@ -628,7 +628,7 @@ select name, count(path) as count from (
|
|||
group by name;
|
||||
`
|
||||
|
||||
func (db *database) usesOfMediaFile(names ...string) (counts map[string]int, err error) {
|
||||
func (db *database) usesOfMediaFile(names ...string) (counts []int, err error) {
|
||||
sqlArgs := []interface{}{dbNoCache}
|
||||
var nameValues strings.Builder
|
||||
for i, n := range names {
|
||||
|
@ -645,7 +645,7 @@ func (db *database) usesOfMediaFile(names ...string) (counts map[string]int, err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
counts = map[string]int{}
|
||||
counts = make([]int, len(names))
|
||||
var name string
|
||||
var count int
|
||||
for rows.Next() {
|
||||
|
@ -653,7 +653,12 @@ func (db *database) usesOfMediaFile(names ...string) (counts map[string]int, err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
counts[name] = count
|
||||
for i, n := range names {
|
||||
if n == name {
|
||||
counts[i] = count
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return counts, nil
|
||||
}
|
||||
|
|
|
@ -358,7 +358,7 @@ func Test_usesOfMediaFile(t *testing.T) {
|
|||
counts, err := app.db.usesOfMediaFile("test.jpg")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, counts, 1)
|
||||
if assert.NotNil(t, counts["test.jpg"]) {
|
||||
assert.Equal(t, 2, counts["test.jpg"])
|
||||
if assert.NotEmpty(t, counts) {
|
||||
assert.Equal(t, 2, counts[0])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,8 @@ const (
|
|||
|
||||
templateBase = "base"
|
||||
templateEditor = "editor"
|
||||
templateEditorFiles = "editorfiles"
|
||||
templateCommentsAdmin = "commentsadmin"
|
||||
templateNotificationsAdmin = "notificationsadmin"
|
||||
templateWebmentionAdmin = "webmentionadmin"
|
||||
templateIndieAuth = "indieauth"
|
||||
)
|
||||
|
||||
func (a *goBlog) initRendering() error {
|
||||
|
@ -42,14 +39,12 @@ func (a *goBlog) initRendering() error {
|
|||
},
|
||||
// Others
|
||||
"dateformat": dateFormat,
|
||||
"isodate": isoDateFormat,
|
||||
"unixtodate": unixToLocalDateString,
|
||||
"now": localNowString,
|
||||
"asset": a.assetFileName,
|
||||
"string": a.ts.GetTemplateStringVariantFunc(),
|
||||
"absolute": a.getFullAddress,
|
||||
"opensearch": openSearchUrl,
|
||||
"mbytes": mBytesString,
|
||||
"editortemplate": a.editorPostTemplate,
|
||||
"editorpostdesc": a.editorPostDesc,
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
{{ define "title" }}
|
||||
<title>{{ string .Blog.Lang "mediafiles" }} - {{ mdtitle .Blog.Title }}</title>
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<main>
|
||||
{{ $blog := .Blog }}
|
||||
<h2>{{ string .Blog.Lang "mediafiles" }}</h2>
|
||||
{{ if .Data.Files }}
|
||||
<form class="fw p" method="post">
|
||||
<select name="filename">
|
||||
{{ $uses := .Data.Uses }}
|
||||
{{ range $i, $file := .Data.Files }}
|
||||
<option value="{{ $file.Name }}">{{ $file.Name }} ({{ isodate $file.Time.String }}, {{ mbytes $file.Size }}, ~{{ index $uses $file.Name }} {{ string $blog.Lang "fileuses" }})</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
<input type="submit" formaction="{{ .Blog.RelativePath "/editor/files/view" }}" value="{{ string .Blog.Lang "view" }}">
|
||||
<input type="submit" formaction="{{ .Blog.RelativePath "/editor/files/delete" }}" value="{{ string .Blog.Lang "delete" }}" class="confirm" data-confirmmessage="{{ string .Blog.Lang "confirmdelete" }}">
|
||||
</form>
|
||||
<script defer src="{{ asset "js/formconfirm.js" }}"></script>
|
||||
{{ else }}
|
||||
<p>{{ string .Blog.Lang "nofiles" }}</p>
|
||||
{{ end }}
|
||||
</main>
|
||||
{{ end }}
|
||||
|
||||
{{ define "editorfiles" }}
|
||||
{{ template "base" . }}
|
||||
{{ end }}
|
|
@ -1,33 +0,0 @@
|
|||
{{ define "title" }}
|
||||
<title>{{ string .Blog.Lang "indieauth" }} - {{ .Blog.Title }}</title>
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<main>
|
||||
<h1>{{ string .Blog.Lang "indieauth" }}</h1>
|
||||
<div class="p">
|
||||
<form method="post" action="/indieauth/accept">
|
||||
{{ if .Data.Scopes }}
|
||||
<h3>{{ string .Blog.Lang "scopes" }}</h3>
|
||||
<ul>
|
||||
{{ range $i, $scope := .Data.Scopes }}
|
||||
<li><input type="checkbox" name="scopes" value="{{ $scope }}" id="scope-{{ $scope }}" checked><label for="scope-{{ $scope }}">{{ $scope }}</label></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ end }}
|
||||
<p><strong>client_id:</strong> {{ .Data.ClientID }}</p>
|
||||
<p><strong>redirect_uri:</strong> {{ .Data.RedirectURI }}</p>
|
||||
<input type="hidden" name="redirect_uri" value="{{ .Data.RedirectURI }}">
|
||||
<input type="hidden" name="state" value="{{ .Data.State }}">
|
||||
<input type="hidden" name="client_id" value="{{ .Data.ClientID }}">
|
||||
<input type="hidden" name="code_challenge" value="{{ .Data.CodeChallenge }}">
|
||||
<input type="hidden" name="code_challenge_method" value="{{ .Data.CodeChallengeMethod }}">
|
||||
<input type="submit" value="{{ string .Blog.Lang "authenticate" }}">
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
{{ end }}
|
||||
|
||||
{{ define "indieauth" }}
|
||||
{{ template "base" . }}
|
||||
{{ end }}
|
|
@ -1,29 +0,0 @@
|
|||
{{ define "title" }}
|
||||
<title>{{ string "notifications" }} - {{ mdtitle .Blog.Title }}</title>
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<main>
|
||||
<h1>{{ string "notifications" }}</h1>
|
||||
{{ range $i, $notification := .Data.Notifications }}
|
||||
<div class="p">
|
||||
<p><i>{{ unixtodate $notification.Time }}</i></p>
|
||||
{{ md $notification.Text }}
|
||||
<form method="post">
|
||||
<input type="hidden" name="notificationid" value="{{ $notification.ID }}">
|
||||
<input type="submit" formaction="/notifications/delete" value="{{ string "delete" }}">
|
||||
</form>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if .Data.HasPrev }}
|
||||
<p><a href="{{ .Data.Prev }}">{{ string "prev" }}</a></p>
|
||||
{{ end }}
|
||||
{{ if .Data.HasNext }}
|
||||
<p><a href="{{ .Data.Next }}">{{ string "next" }}</a></p>
|
||||
{{ end }}
|
||||
</main>
|
||||
{{ end }}
|
||||
|
||||
{{ define "notificationsadmin" }}
|
||||
{{ template "base" . }}
|
||||
{{ end }}
|
185
ui.go
185
ui.go
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hacdias/indieauth"
|
||||
"github.com/kaorimatz/go-opml"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
@ -398,20 +399,7 @@ func (a *goBlog) renderIndex(hb *htmlBuilder, rd *renderData) {
|
|||
hb.writeElementClose("p")
|
||||
}
|
||||
// Navigation
|
||||
if id.hasPrev {
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeElementOpen("a", "href", id.prev) // TODO: rel=prev?
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "prev"))
|
||||
hb.writeElementClose("a")
|
||||
hb.writeElementClose("p")
|
||||
}
|
||||
if id.hasNext {
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeElementOpen("a", "href", id.next) // TODO: rel=next?
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "next"))
|
||||
hb.writeElementClose("a")
|
||||
hb.writeElementClose("p")
|
||||
}
|
||||
a.renderPagination(hb, rd.Blog, id.hasPrev, id.hasNext, id.prev, id.next)
|
||||
// Author
|
||||
a.renderAuthor(hb)
|
||||
hb.writeElementClose("main")
|
||||
|
@ -1054,3 +1042,172 @@ func (a *goBlog) renderStaticHome(hb *htmlBuilder, rd *renderData) {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (a *goBlog) renderIndieAuth(hb *htmlBuilder, rd *renderData) {
|
||||
indieAuthRequest, ok := rd.Data.(*indieauth.AuthenticationRequest)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
a.renderBase(
|
||||
hb, rd,
|
||||
func(hb *htmlBuilder) {
|
||||
a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "indieauth"))
|
||||
},
|
||||
func(hb *htmlBuilder) {
|
||||
hb.writeElementOpen("main")
|
||||
// Title
|
||||
hb.writeElementOpen("h1")
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "indieauth"))
|
||||
hb.writeElementClose("h1")
|
||||
hb.writeElementClose("main")
|
||||
// Form
|
||||
hb.writeElementOpen("form", "method", "post", "action", "/indieauth/accept", "class", "p")
|
||||
// Scopes
|
||||
if scopes := indieAuthRequest.Scopes; len(scopes) > 0 {
|
||||
hb.writeElementOpen("h3")
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "scopes"))
|
||||
hb.writeElementClose("h3")
|
||||
hb.writeElementOpen("ul")
|
||||
for _, scope := range scopes {
|
||||
hb.writeElementOpen("li")
|
||||
hb.writeElementOpen("input", "type", "checkbox", "name", "scopes", "value", scope, "id", "scope-"+scope, "checked", "")
|
||||
hb.writeElementOpen("label", "for", "scope-"+scope)
|
||||
hb.writeEscaped(scope)
|
||||
hb.writeElementClose("label")
|
||||
hb.writeElementClose("li")
|
||||
}
|
||||
hb.writeElementClose("ul")
|
||||
}
|
||||
// Client ID
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeElementOpen("strong")
|
||||
hb.writeEscaped("client_id:")
|
||||
hb.writeElementClose("strong")
|
||||
hb.write(" ")
|
||||
hb.writeEscaped(indieAuthRequest.ClientID)
|
||||
hb.writeElementClose("p")
|
||||
// Redirect URI
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeElementOpen("strong")
|
||||
hb.writeEscaped("redirect_uri:")
|
||||
hb.writeElementClose("strong")
|
||||
hb.write(" ")
|
||||
hb.writeEscaped(indieAuthRequest.RedirectURI)
|
||||
hb.writeElementClose("p")
|
||||
// Hidden form fields
|
||||
hb.writeElementOpen("input", "type", "hidden", "name", "client_id", "value", indieAuthRequest.ClientID)
|
||||
hb.writeElementOpen("input", "type", "hidden", "name", "redirect_uri", "value", indieAuthRequest.RedirectURI)
|
||||
hb.writeElementOpen("input", "type", "hidden", "name", "state", "value", indieAuthRequest.State)
|
||||
hb.writeElementOpen("input", "type", "hidden", "name", "code_challenge", "value", indieAuthRequest.CodeChallenge)
|
||||
hb.writeElementOpen("input", "type", "hidden", "name", "code_challenge_method", "value", indieAuthRequest.CodeChallengeMethod)
|
||||
// Submit button
|
||||
hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "authenticate"))
|
||||
hb.writeElementClose("form")
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type editorFilesRenderData struct {
|
||||
files []*mediaFile
|
||||
uses []int
|
||||
}
|
||||
|
||||
func (a *goBlog) renderEditorFiles(hb *htmlBuilder, rd *renderData) {
|
||||
ef, ok := rd.Data.(*editorFilesRenderData)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
a.renderBase(
|
||||
hb, rd,
|
||||
func(hb *htmlBuilder) {
|
||||
a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "mediafiles"))
|
||||
},
|
||||
func(hb *htmlBuilder) {
|
||||
hb.writeElementOpen("main")
|
||||
// Title
|
||||
hb.writeElementOpen("h1")
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "mediafiles"))
|
||||
hb.writeElementClose("h1")
|
||||
// Files
|
||||
if len(ef.files) > 0 {
|
||||
// Form
|
||||
hb.writeElementOpen("form", "method", "post", "class", "fw p")
|
||||
// Select with number of uses
|
||||
hb.writeElementOpen("select", "name", "filename")
|
||||
usesString := a.ts.GetTemplateStringVariant(rd.Blog.Lang, "fileuses")
|
||||
for i, f := range ef.files {
|
||||
hb.writeElementOpen("option", "value", f.Name)
|
||||
hb.writeEscaped(fmt.Sprintf("%s (%s), %s, ~%d %s", f.Name, isoDateFormat(f.Time.String()), mBytesString(f.Size), ef.uses[i], usesString))
|
||||
hb.writeElementClose("option")
|
||||
}
|
||||
hb.writeElementClose("select")
|
||||
// View button
|
||||
hb.writeElementOpen(
|
||||
"input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "view"),
|
||||
"formaction", rd.Blog.getRelativePath("/editor/files/view"),
|
||||
)
|
||||
// Delete button
|
||||
hb.writeElementOpen(
|
||||
"input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete"),
|
||||
"formaction", rd.Blog.getRelativePath("/editor/files/delete"),
|
||||
"class", "confirm", "data-confirmmessage", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "confirmdelete"),
|
||||
)
|
||||
hb.writeElementOpen("script", "src", a.assetFileName("js/formconfirm.js"), "defer", "")
|
||||
hb.writeElementClose("script")
|
||||
hb.writeElementClose("form")
|
||||
} else {
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "nofiles"))
|
||||
hb.writeElementClose("p")
|
||||
}
|
||||
hb.writeElementClose("main")
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type notificationsRenderData struct {
|
||||
notifications []*notification
|
||||
hasPrev, hasNext bool
|
||||
prev, next string
|
||||
}
|
||||
|
||||
func (a *goBlog) renderNotificationsAdmin(hb *htmlBuilder, rd *renderData) {
|
||||
nrd, ok := rd.Data.(*notificationsRenderData)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
a.renderBase(
|
||||
hb, rd,
|
||||
func(hb *htmlBuilder) {
|
||||
a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "notifications"))
|
||||
},
|
||||
func(hb *htmlBuilder) {
|
||||
hb.writeElementOpen("main")
|
||||
// Title
|
||||
hb.writeElementOpen("h1")
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "notifications"))
|
||||
hb.writeElementClose("h1")
|
||||
// Notifications
|
||||
for _, n := range nrd.notifications {
|
||||
hb.writeElementOpen("div", "class", "p")
|
||||
// Date
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeElementOpen("i")
|
||||
hb.writeEscaped(unixToLocalDateString(n.Time))
|
||||
hb.writeElementClose("i")
|
||||
hb.writeElementClose("p")
|
||||
// Message
|
||||
a.renderMarkdownToWriter(hb, n.Text, false)
|
||||
// Delete form
|
||||
hb.writeElementOpen("form", "method", "post", "action", "/notifications/delete")
|
||||
hb.writeElementOpen("input", "type", "hidden", "name", "notificationid", "value", n.ID)
|
||||
hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete"))
|
||||
hb.writeElementClose("form")
|
||||
hb.writeElementClose("div")
|
||||
}
|
||||
// Pagination
|
||||
a.renderPagination(hb, rd.Blog, nrd.hasPrev, nrd.hasNext, nrd.prev, nrd.next)
|
||||
hb.writeElementClose("main")
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -384,3 +384,21 @@ func (a *goBlog) renderTitleTag(hb *htmlBuilder, blog *configBlog, optionalTitle
|
|||
hb.writeEscaped(a.renderMdTitle(blog.Title))
|
||||
hb.writeElementClose("title")
|
||||
}
|
||||
|
||||
func (a *goBlog) renderPagination(hb *htmlBuilder, blog *configBlog, hasPrev, hasNext bool, prev, next string) {
|
||||
// Navigation
|
||||
if hasPrev {
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeElementOpen("a", "href", prev) // TODO: rel=prev?
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(blog.Lang, "prev"))
|
||||
hb.writeElementClose("a")
|
||||
hb.writeElementClose("p")
|
||||
}
|
||||
if hasNext {
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeElementOpen("a", "href", next) // TODO: rel=next?
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(blog.Lang, "next"))
|
||||
hb.writeElementClose("a")
|
||||
hb.writeElementClose("p")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user