Breadcrumbs
This commit is contained in:
parent
1f39b166cb
commit
d78a2e8e82
|
@ -88,7 +88,7 @@
|
||||||
{{- if gt $i 0 -}}
|
{{- if gt $i 0 -}}
|
||||||
<span class="ph2">»</span>
|
<span class="ph2">»</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<a class="breadcrumb {{ if .Current }}current{{ end }}" href="{{ .Url }}">{{ .Name }}</a>
|
<a class="breadcrumb" href="{{ .Url }}">{{ .Name }}</a>
|
||||||
{{- end }}
|
{{- end }}
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.handmade.network/hmn/hmn/src/oops"
|
"git.handmade.network/hmn/hmn/src/oops"
|
||||||
|
@ -34,6 +35,10 @@ func Int64Max(a, b int64) int64 {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NumPages(numThings, thingsPerPage int) int {
|
||||||
|
return IntMax(int(math.Ceil(float64(numThings)/float64(thingsPerPage))), 1)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Recover a panic and convert it to a returned error. Call it like so:
|
Recover a panic and convert it to a returned error. Call it like so:
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ func LoginPage(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("auth_login.html", LoginPageData{
|
res.MustWriteTemplate("auth_login.html", LoginPageData{
|
||||||
BaseData: getBaseData(c),
|
BaseData: getBaseDataAutocrumb(c, "Log in"),
|
||||||
RedirectUrl: c.Req.URL.Query().Get("redirect"),
|
RedirectUrl: c.Req.URL.Query().Get("redirect"),
|
||||||
ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(),
|
ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
|
@ -63,7 +63,7 @@ func Login(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
showLoginWithFailure := func(c *RequestContext, redirect string) ResponseData {
|
showLoginWithFailure := func(c *RequestContext, redirect string) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, "Log in")
|
||||||
baseData.AddImmediateNotice("failure", "Incorrect username or password")
|
baseData.AddImmediateNotice("failure", "Incorrect username or password")
|
||||||
res.MustWriteTemplate("auth_login.html", LoginPageData{
|
res.MustWriteTemplate("auth_login.html", LoginPageData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
@ -122,7 +122,7 @@ func RegisterNewUser(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
// TODO(asaf): Do something to prevent bot registration
|
// TODO(asaf): Do something to prevent bot registration
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("auth_register.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("auth_register.html", getBaseDataAutocrumb(c, "Register"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ func RegisterNewUserSuccess(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("auth_register_success.html", RegisterNewUserSuccessData{
|
res.MustWriteTemplate("auth_register_success.html", RegisterNewUserSuccessData{
|
||||||
BaseData: getBaseData(c),
|
BaseData: getBaseDataAutocrumb(c, "Register"),
|
||||||
ContactUsUrl: hmnurl.BuildContactPage(),
|
ContactUsUrl: hmnurl.BuildContactPage(),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
|
@ -321,7 +321,7 @@ func EmailConfirmation(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("auth_email_validation.html", EmailValidationData{
|
res.MustWriteTemplate("auth_email_validation.html", EmailValidationData{
|
||||||
BaseData: getBaseData(c),
|
BaseData: getBaseDataAutocrumb(c, "Register"),
|
||||||
Token: token,
|
Token: token,
|
||||||
Username: username,
|
Username: username,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
|
@ -346,11 +346,11 @@ func EmailConfirmationSubmit(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, err)
|
return c.ErrorResponse(http.StatusInternalServerError, err)
|
||||||
} else if !success {
|
} else if !success {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, "Register")
|
||||||
// NOTE(asaf): We can report that the password is incorrect, because an attacker wouldn't have a valid token to begin with.
|
// NOTE(asaf): We can report that the password is incorrect, because an attacker wouldn't have a valid token to begin with.
|
||||||
baseData.AddImmediateNotice("failure", "Incorrect password. Please try again.")
|
baseData.AddImmediateNotice("failure", "Incorrect password. Please try again.")
|
||||||
res.MustWriteTemplate("auth_email_validation.html", EmailValidationData{
|
res.MustWriteTemplate("auth_email_validation.html", EmailValidationData{
|
||||||
BaseData: getBaseData(c),
|
BaseData: baseData,
|
||||||
Token: token,
|
Token: token,
|
||||||
Username: username,
|
Username: username,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
|
@ -424,7 +424,7 @@ func RequestPasswordReset(c *RequestContext) ResponseData {
|
||||||
return c.Redirect(hmnurl.BuildHomepage(), http.StatusSeeOther)
|
return c.Redirect(hmnurl.BuildHomepage(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("auth_password_reset.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("auth_password_reset.html", getBaseDataAutocrumb(c, "Password Reset"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,7 +548,7 @@ func PasswordResetSent(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("auth_password_reset_sent.html", PasswordResetSentData{
|
res.MustWriteTemplate("auth_password_reset_sent.html", PasswordResetSentData{
|
||||||
BaseData: getBaseData(c),
|
BaseData: getBaseDataAutocrumb(c, "Password Reset"),
|
||||||
ContactUsUrl: hmnurl.BuildContactPage(),
|
ContactUsUrl: hmnurl.BuildContactPage(),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
|
@ -582,7 +582,7 @@ func DoPasswordReset(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
res.MustWriteTemplate("auth_do_password_reset.html", DoPasswordResetData{
|
res.MustWriteTemplate("auth_do_password_reset.html", DoPasswordResetData{
|
||||||
BaseData: getBaseData(c),
|
BaseData: getBaseDataAutocrumb(c, "Password Reset"),
|
||||||
Username: username,
|
Username: username,
|
||||||
Token: token,
|
Token: token,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
|
|
|
@ -53,7 +53,7 @@ func BlogIndex(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch total number of blog posts"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch total number of blog posts"))
|
||||||
}
|
}
|
||||||
|
|
||||||
numPages := NumPages(numPosts, postsPerPage)
|
numPages := utils.NumPages(numPosts, postsPerPage)
|
||||||
page, ok := ParsePageNumber(c, "page", numPages)
|
page, ok := ParsePageNumber(c, "page", numPages)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.Redirect(hmnurl.BuildBlog(c.CurrentProject.Slug, page), http.StatusSeeOther)
|
c.Redirect(hmnurl.BuildBlog(c.CurrentProject.Slug, page), http.StatusSeeOther)
|
||||||
|
@ -104,8 +104,7 @@ func BlogIndex(c *RequestContext) ResponseData {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(c, fmt.Sprintf("%s Blog", c.CurrentProject.Name), []templates.Breadcrumb{BlogBreadcrumb(c.CurrentProject.Slug)})
|
||||||
baseData.Title = fmt.Sprintf("%s Blog", c.CurrentProject.Name)
|
|
||||||
|
|
||||||
canCreate := false
|
canCreate := false
|
||||||
if c.CurrentUser != nil {
|
if c.CurrentUser != nil {
|
||||||
|
@ -181,8 +180,7 @@ func BlogThread(c *RequestContext) ResponseData {
|
||||||
templatePosts = append(templatePosts, post)
|
templatePosts = append(templatePosts, post)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(c, thread.Title, []templates.Breadcrumb{BlogBreadcrumb(c.CurrentProject.Slug)})
|
||||||
baseData.Title = thread.Title
|
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("blog_post.html", blogPostData{
|
res.MustWriteTemplate("blog_post.html", blogPostData{
|
||||||
|
@ -209,9 +207,11 @@ func BlogPostRedirectToThread(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BlogNewThread(c *RequestContext) ResponseData {
|
func BlogNewThread(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Title = fmt.Sprintf("Create New Post | %s", c.CurrentProject.Name)
|
c,
|
||||||
// TODO(ben): Set breadcrumbs
|
fmt.Sprintf("Create New Post | %s", c.CurrentProject.Name),
|
||||||
|
[]templates.Breadcrumb{BlogBreadcrumb(c.CurrentProject.Slug)},
|
||||||
|
)
|
||||||
|
|
||||||
editData := getEditorDataForNew(baseData, nil)
|
editData := getEditorDataForNew(baseData, nil)
|
||||||
editData.SubmitUrl = hmnurl.BuildBlogNewThread(c.CurrentProject.Slug)
|
editData.SubmitUrl = hmnurl.BuildBlogNewThread(c.CurrentProject.Slug)
|
||||||
|
@ -284,13 +284,17 @@ func BlogPostEdit(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
title := ""
|
||||||
if postData.Thread.FirstID == postData.Post.ID {
|
if postData.Thread.FirstID == postData.Post.ID {
|
||||||
baseData.Title = fmt.Sprintf("Editing \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
title = fmt.Sprintf("Editing \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
||||||
} else {
|
} else {
|
||||||
baseData.Title = fmt.Sprintf("Editing Post | %s", c.CurrentProject.Name)
|
title = fmt.Sprintf("Editing Post | %s", c.CurrentProject.Name)
|
||||||
}
|
}
|
||||||
// TODO(ben): Set breadcrumbs
|
baseData := getBaseData(
|
||||||
|
c,
|
||||||
|
title,
|
||||||
|
BlogThreadBreadcrumbs(c.CurrentProject.Slug, &postData.Thread),
|
||||||
|
)
|
||||||
|
|
||||||
editData := getEditorDataForEdit(baseData, postData)
|
editData := getEditorDataForEdit(baseData, postData)
|
||||||
editData.SubmitUrl = hmnurl.BuildBlogPostEdit(c.CurrentProject.Slug, cd.ThreadID, cd.PostID)
|
editData.SubmitUrl = hmnurl.BuildBlogPostEdit(c.CurrentProject.Slug, cd.ThreadID, cd.PostID)
|
||||||
|
@ -352,9 +356,11 @@ func BlogPostReply(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Title = fmt.Sprintf("Replying to comment in \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
c,
|
||||||
// TODO(ben): Set breadcrumbs
|
fmt.Sprintf("Replying to comment in \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name),
|
||||||
|
BlogThreadBreadcrumbs(c.CurrentProject.Slug, &postData.Thread),
|
||||||
|
)
|
||||||
|
|
||||||
replyPost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
replyPost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
||||||
replyPost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
replyPost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
||||||
|
@ -412,12 +418,17 @@ func BlogPostDelete(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
title := ""
|
||||||
if postData.Thread.FirstID == postData.Post.ID {
|
if postData.Thread.FirstID == postData.Post.ID {
|
||||||
baseData.Title = fmt.Sprintf("Deleting \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
title = fmt.Sprintf("Deleting \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
||||||
} else {
|
} else {
|
||||||
baseData.Title = fmt.Sprintf("Deleting comment in \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
title = fmt.Sprintf("Deleting comment in \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
||||||
}
|
}
|
||||||
|
baseData := getBaseData(
|
||||||
|
c,
|
||||||
|
title,
|
||||||
|
BlogThreadBreadcrumbs(c.CurrentProject.Slug, &postData.Thread),
|
||||||
|
)
|
||||||
// TODO(ben): Set breadcrumbs
|
// TODO(ben): Set breadcrumbs
|
||||||
|
|
||||||
templatePost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
templatePost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package website
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.handmade.network/hmn/hmn/src/hmnurl"
|
||||||
|
"git.handmade.network/hmn/hmn/src/models"
|
||||||
|
"git.handmade.network/hmn/hmn/src/templates"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProjectBreadcrumb(project *models.Project) templates.Breadcrumb {
|
||||||
|
return templates.Breadcrumb{
|
||||||
|
Name: project.Name,
|
||||||
|
Url: hmnurl.BuildProjectHomepage(project.Slug),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ForumBreadcrumb(projectSlug string) templates.Breadcrumb {
|
||||||
|
return templates.Breadcrumb{
|
||||||
|
Name: "Forums",
|
||||||
|
Url: hmnurl.BuildForum(projectSlug, nil, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubforumBreadcrumbs(lineageBuilder *models.SubforumLineageBuilder, project *models.Project, subforumID int) []templates.Breadcrumb {
|
||||||
|
var result []templates.Breadcrumb
|
||||||
|
result = []templates.Breadcrumb{
|
||||||
|
ProjectBreadcrumb(project),
|
||||||
|
ForumBreadcrumb(project.Slug),
|
||||||
|
}
|
||||||
|
subforums := lineageBuilder.GetSubforumLineage(subforumID)
|
||||||
|
slugs := lineageBuilder.GetSubforumLineageSlugs(subforumID)
|
||||||
|
for i, subforum := range subforums {
|
||||||
|
result = append(result, templates.Breadcrumb{
|
||||||
|
Name: subforum.Name,
|
||||||
|
Url: hmnurl.BuildForum(project.Slug, slugs[0:i+1], 1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ForumThreadBreadcrumbs(lineageBuilder *models.SubforumLineageBuilder, project *models.Project, thread *models.Thread) []templates.Breadcrumb {
|
||||||
|
result := SubforumBreadcrumbs(lineageBuilder, project, *thread.SubforumID)
|
||||||
|
result = append(result, templates.Breadcrumb{
|
||||||
|
Name: thread.Title,
|
||||||
|
Url: hmnurl.BuildForumThread(project.Slug, lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), thread.ID, thread.Title, 1),
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlogBreadcrumb(projectSlug string) templates.Breadcrumb {
|
||||||
|
return templates.Breadcrumb{
|
||||||
|
Name: "Blog",
|
||||||
|
Url: hmnurl.BuildBlog(projectSlug, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlogThreadBreadcrumbs(projectSlug string, thread *models.Thread) []templates.Breadcrumb {
|
||||||
|
result := []templates.Breadcrumb{
|
||||||
|
BlogBreadcrumb(projectSlug),
|
||||||
|
{Name: thread.Title, Url: hmnurl.BuildBlogThread(projectSlug, thread.ID, thread.Title)},
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
|
@ -88,7 +88,7 @@ func EpisodeList(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, fmt.Sprintf("Episode Guide"))
|
||||||
res.MustWriteTemplate("episode_list.html", EpisodeListData{
|
res.MustWriteTemplate("episode_list.html", EpisodeListData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
Content: template.HTML(guide),
|
Content: template.HTML(guide),
|
||||||
|
@ -147,8 +147,11 @@ func Episode(c *RequestContext) ResponseData {
|
||||||
content := contentMatches[episodeContentRegex.SubexpIndex("content")]
|
content := contentMatches[episodeContentRegex.SubexpIndex("content")]
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Title = title
|
c,
|
||||||
|
title,
|
||||||
|
[]templates.Breadcrumb{{Name: "Episode Guide", Url: hmnurl.BuildEpisodeList(c.CurrentProject.Slug, foundTopic)}},
|
||||||
|
)
|
||||||
res.MustWriteTemplate("episode.html", EpisodeData{
|
res.MustWriteTemplate("episode.html", EpisodeData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
Content: template.HTML(content),
|
Content: template.HTML(content),
|
||||||
|
|
|
@ -90,7 +90,7 @@ func Feed(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, "Feed")
|
||||||
baseData.BodyClasses = append(baseData.BodyClasses, "feed")
|
baseData.BodyClasses = append(baseData.BodyClasses, "feed")
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
|
|
|
@ -100,7 +100,7 @@ func Forum(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
|
|
||||||
numPages := NumPages(numThreads, threadsPerPage)
|
numPages := utils.NumPages(numThreads, threadsPerPage)
|
||||||
page, ok := ParsePageNumber(c, "page", numPages)
|
page, ok := ParsePageNumber(c, "page", numPages)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.Redirect(hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, page), http.StatusSeeOther)
|
c.Redirect(hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, page), http.StatusSeeOther)
|
||||||
|
@ -259,27 +259,11 @@ func Forum(c *RequestContext) ResponseData {
|
||||||
// Template assembly
|
// Template assembly
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Title = c.CurrentProject.Name + " Forums"
|
c,
|
||||||
baseData.Breadcrumbs = []templates.Breadcrumb{
|
fmt.Sprintf("%s Forums", c.CurrentProject.Name),
|
||||||
{
|
SubforumBreadcrumbs(cd.LineageBuilder, c.CurrentProject, cd.SubforumID),
|
||||||
Name: c.CurrentProject.Name,
|
)
|
||||||
Url: hmnurl.BuildProjectHomepage(c.CurrentProject.Slug),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Forums",
|
|
||||||
Url: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1),
|
|
||||||
Current: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSubforums := cd.LineageBuilder.GetSubforumLineage(cd.SubforumID)
|
|
||||||
for i, subforum := range currentSubforums {
|
|
||||||
baseData.Breadcrumbs = append(baseData.Breadcrumbs, templates.Breadcrumb{
|
|
||||||
Name: subforum.Name,
|
|
||||||
Url: hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs[0:i+1], 1),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("forum.html", forumData{
|
res.MustWriteTemplate("forum.html", forumData{
|
||||||
|
@ -511,9 +495,7 @@ func ForumThread(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(c, thread.Title, SubforumBreadcrumbs(cd.LineageBuilder, c.CurrentProject, cd.SubforumID))
|
||||||
baseData.Title = thread.Title
|
|
||||||
// TODO(asaf): Set breadcrumbs
|
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("forum_thread.html", forumThreadData{
|
res.MustWriteTemplate("forum_thread.html", forumThreadData{
|
||||||
|
@ -596,15 +578,12 @@ func ForumPostRedirect(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ForumNewThread(c *RequestContext) ResponseData {
|
func ForumNewThread(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(c)
|
|
||||||
baseData.Title = "Create New Thread"
|
|
||||||
// TODO(ben): Set breadcrumbs
|
|
||||||
|
|
||||||
cd, ok := getCommonForumData(c)
|
cd, ok := getCommonForumData(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
return FourOhFour(c)
|
return FourOhFour(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseData := getBaseData(c, "Create New Thread", SubforumBreadcrumbs(cd.LineageBuilder, c.CurrentProject, cd.SubforumID))
|
||||||
editData := getEditorDataForNew(baseData, nil)
|
editData := getEditorDataForNew(baseData, nil)
|
||||||
editData.SubmitUrl = hmnurl.BuildForumNewThread(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), true)
|
editData.SubmitUrl = hmnurl.BuildForumNewThread(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), true)
|
||||||
editData.SubmitLabel = "Post New Thread"
|
editData.SubmitLabel = "Post New Thread"
|
||||||
|
@ -683,9 +662,11 @@ func ForumPostReply(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Title = fmt.Sprintf("Replying to post | %s", cd.SubforumTree[cd.SubforumID].Name)
|
c,
|
||||||
// TODO(ben): Set breadcrumbs
|
fmt.Sprintf("Replying to post | %s", cd.SubforumTree[cd.SubforumID].Name),
|
||||||
|
ForumThreadBreadcrumbs(cd.LineageBuilder, c.CurrentProject, &postData.Thread),
|
||||||
|
)
|
||||||
|
|
||||||
replyPost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
replyPost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
||||||
replyPost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
replyPost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
||||||
|
@ -743,13 +724,13 @@ func ForumPostEdit(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
title := ""
|
||||||
if postData.Thread.FirstID == postData.Post.ID {
|
if postData.Thread.FirstID == postData.Post.ID {
|
||||||
baseData.Title = fmt.Sprintf("Editing \"%s\" | %s", postData.Thread.Title, cd.SubforumTree[cd.SubforumID].Name)
|
title = fmt.Sprintf("Editing \"%s\" | %s", postData.Thread.Title, cd.SubforumTree[cd.SubforumID].Name)
|
||||||
} else {
|
} else {
|
||||||
baseData.Title = fmt.Sprintf("Editing Post | %s", cd.SubforumTree[cd.SubforumID].Name)
|
title = fmt.Sprintf("Editing Post | %s", cd.SubforumTree[cd.SubforumID].Name)
|
||||||
}
|
}
|
||||||
// TODO(ben): Set breadcrumbs
|
baseData := getBaseData(c, title, ForumThreadBreadcrumbs(cd.LineageBuilder, c.CurrentProject, &postData.Thread))
|
||||||
|
|
||||||
editData := getEditorDataForEdit(baseData, postData)
|
editData := getEditorDataForEdit(baseData, postData)
|
||||||
editData.SubmitUrl = hmnurl.BuildForumPostEdit(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
editData.SubmitUrl = hmnurl.BuildForumPostEdit(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
||||||
|
@ -806,9 +787,11 @@ func ForumPostDelete(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Title = fmt.Sprintf("Deleting post in \"%s\" | %s", postData.Thread.Title, cd.SubforumTree[cd.SubforumID].Name)
|
c,
|
||||||
// TODO(ben): Set breadcrumbs
|
fmt.Sprintf("Deleting post in \"%s\" | %s", postData.Thread.Title, cd.SubforumTree[cd.SubforumID].Name),
|
||||||
|
ForumThreadBreadcrumbs(cd.LineageBuilder, c.CurrentProject, &postData.Thread),
|
||||||
|
)
|
||||||
|
|
||||||
templatePost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
templatePost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
||||||
templatePost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
templatePost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
||||||
|
|
|
@ -13,8 +13,7 @@ func JamIndex(c *RequestContext) ResponseData {
|
||||||
ogimageurl = urljoin(current_site_host(), ogimagepath)
|
ogimageurl = urljoin(current_site_host(), ogimagepath)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, "Wheel Reinvention Jam")
|
||||||
baseData.Title = "Wheel Reinvention Jam"
|
|
||||||
baseData.OpenGraphItems = []templates.OpenGraphItem{
|
baseData.OpenGraphItems = []templates.OpenGraphItem{
|
||||||
{Property: "og:site_name", Value: "Handmade.Network"},
|
{Property: "og:site_name", Value: "Handmade.Network"},
|
||||||
{Property: "og:type", Value: "website"},
|
{Property: "og:type", Value: "website"},
|
||||||
|
|
|
@ -316,7 +316,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
showcaseJson := templates.TimelineItemsToJSON(showcaseItems)
|
showcaseJson := templates.TimelineItemsToJSON(showcaseItems)
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(c, "", nil)
|
||||||
baseData.BodyClasses = append(baseData.BodyClasses, "hmdev", "landing") // TODO: Is "hmdev" necessary any more?
|
baseData.BodyClasses = append(baseData.BodyClasses, "hmdev", "landing") // TODO: Is "hmdev" necessary any more?
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
|
|
|
@ -44,8 +44,7 @@ func PodcastIndex(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, err)
|
return c.ErrorResponse(http.StatusInternalServerError, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, podcastResult.Podcast.Title)
|
||||||
baseData.Title = podcastResult.Podcast.Title
|
|
||||||
|
|
||||||
podcastIndexData := PodcastIndexData{
|
podcastIndexData := PodcastIndexData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
@ -89,8 +88,11 @@ func PodcastEdit(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile)
|
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile)
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Breadcrumbs = []templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}}
|
c,
|
||||||
|
fmt.Sprintf("Edit %s", podcast.Title),
|
||||||
|
[]templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}},
|
||||||
|
)
|
||||||
podcastEditData := PodcastEditData{
|
podcastEditData := PodcastEditData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
Podcast: podcast,
|
Podcast: podcast,
|
||||||
|
@ -229,9 +231,11 @@ func PodcastEpisode(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile)
|
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile)
|
||||||
episode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, podcastResult.Episodes[0], 0, podcastResult.ImageFile)
|
episode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, podcastResult.Episodes[0], 0, podcastResult.ImageFile)
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Title = podcastResult.Podcast.Title
|
c,
|
||||||
baseData.Breadcrumbs = []templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}}
|
fmt.Sprintf("%s | %s", episode.Title, podcast.Title),
|
||||||
|
[]templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}},
|
||||||
|
)
|
||||||
|
|
||||||
podcastEpisodeData := PodcastEpisodeData{
|
podcastEpisodeData := PodcastEpisodeData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
@ -280,8 +284,11 @@ func PodcastEpisodeNew(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "")
|
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "")
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Breadcrumbs = []templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}}
|
c,
|
||||||
|
fmt.Sprintf("New episode | %s", podcast.Title),
|
||||||
|
[]templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}},
|
||||||
|
)
|
||||||
err = res.WriteTemplate("podcast_episode_edit.html", PodcastEpisodeEditData{
|
err = res.WriteTemplate("podcast_episode_edit.html", PodcastEpisodeEditData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
IsEdit: false,
|
IsEdit: false,
|
||||||
|
@ -321,8 +328,11 @@ func PodcastEpisodeEdit(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "")
|
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "")
|
||||||
podcastEpisode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, episode, 0, "")
|
podcastEpisode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, episode, 0, "")
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
baseData.Breadcrumbs = []templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}, {Name: podcastEpisode.Title, Url: podcastEpisode.Url}}
|
c,
|
||||||
|
fmt.Sprintf("Edit episode %s | %s", podcastEpisode.Title, podcast.Title),
|
||||||
|
[]templates.Breadcrumb{{Name: podcast.Title, Url: podcast.Url}, {Name: podcastEpisode.Title, Url: podcastEpisode.Url}},
|
||||||
|
)
|
||||||
podcastEpisodeEditData := PodcastEpisodeEditData{
|
podcastEpisodeEditData := PodcastEpisodeEditData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
IsEdit: true,
|
IsEdit: true,
|
||||||
|
|
|
@ -31,30 +31,40 @@ var PostTypePrefix = map[templates.PostType]string{
|
||||||
templates.PostTypeForumReply: "Forum reply",
|
templates.PostTypeForumReply: "Forum reply",
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostBreadcrumbs(lineageBuilder *models.SubforumLineageBuilder, project *models.Project, thread *models.Thread) []templates.Breadcrumb {
|
var ThreadTypeDisplayNames = map[models.ThreadType]string{
|
||||||
|
models.ThreadTypeProjectBlogPost: "Blog",
|
||||||
|
models.ThreadTypeForumPost: "Forums",
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenericThreadBreadcrumbs(lineageBuilder *models.SubforumLineageBuilder, project *models.Project, thread *models.Thread) []templates.Breadcrumb {
|
||||||
var result []templates.Breadcrumb
|
var result []templates.Breadcrumb
|
||||||
result = append(result, templates.Breadcrumb{
|
if thread.Type == models.ThreadTypeForumPost {
|
||||||
Name: project.Name,
|
result = SubforumBreadcrumbs(lineageBuilder, project, *thread.SubforumID)
|
||||||
Url: hmnurl.BuildProjectHomepage(project.Slug),
|
} else {
|
||||||
})
|
result = []templates.Breadcrumb{
|
||||||
result = append(result, templates.Breadcrumb{
|
{
|
||||||
Name: ThreadTypeDisplayNames[thread.Type],
|
Name: project.Name,
|
||||||
Url: BuildProjectRootResourceUrl(project.Slug, thread.Type),
|
Url: hmnurl.BuildProjectHomepage(project.Slug),
|
||||||
})
|
},
|
||||||
switch thread.Type {
|
{
|
||||||
case models.ThreadTypeForumPost:
|
Name: ThreadTypeDisplayNames[thread.Type],
|
||||||
subforums := lineageBuilder.GetSubforumLineage(*thread.SubforumID)
|
Url: BuildProjectRootResourceUrl(project.Slug, thread.Type),
|
||||||
slugs := lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID)
|
},
|
||||||
for i, subforum := range subforums {
|
|
||||||
result = append(result, templates.Breadcrumb{
|
|
||||||
Name: subforum.Name,
|
|
||||||
Url: hmnurl.BuildForum(project.Slug, slugs[0:i+1], 1),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BuildProjectRootResourceUrl(projectSlug string, kind models.ThreadType) string {
|
||||||
|
switch kind {
|
||||||
|
case models.ThreadTypeProjectBlogPost:
|
||||||
|
return hmnurl.BuildBlog(projectSlug, 1)
|
||||||
|
case models.ThreadTypeForumPost:
|
||||||
|
return hmnurl.BuildForum(projectSlug, nil, 1)
|
||||||
|
}
|
||||||
|
return hmnurl.BuildProjectHomepage(projectSlug)
|
||||||
|
}
|
||||||
|
|
||||||
func MakePostListItem(
|
func MakePostListItem(
|
||||||
lineageBuilder *models.SubforumLineageBuilder,
|
lineageBuilder *models.SubforumLineageBuilder,
|
||||||
project *models.Project,
|
project *models.Project,
|
||||||
|
@ -87,7 +97,7 @@ func MakePostListItem(
|
||||||
result.PostTypePrefix = PostTypePrefix[result.PostType]
|
result.PostTypePrefix = PostTypePrefix[result.PostType]
|
||||||
|
|
||||||
if includeBreadcrumbs {
|
if includeBreadcrumbs {
|
||||||
result.Breadcrumbs = PostBreadcrumbs(lineageBuilder, project, thread)
|
result.Breadcrumbs = GenericThreadBreadcrumbs(lineageBuilder, project, thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -181,8 +181,7 @@ func ProjectIndex(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, "Project List")
|
||||||
baseData.Title = "Project List"
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("project_index.html", ProjectTemplateData{
|
res.MustWriteTemplate("project_index.html", ProjectTemplateData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
@ -369,7 +368,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
var projectHomepageData ProjectHomepageData
|
var projectHomepageData ProjectHomepageData
|
||||||
|
|
||||||
projectHomepageData.BaseData = getBaseData(c)
|
projectHomepageData.BaseData = getBaseData(c, project.Name, nil)
|
||||||
if canEdit {
|
if canEdit {
|
||||||
projectHomepageData.BaseData.Header.EditUrl = hmnurl.BuildProjectEdit(project.Slug, "")
|
projectHomepageData.BaseData.Header.EditUrl = hmnurl.BuildProjectEdit(project.Slug, "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,7 +280,7 @@ func (c *RequestContext) ErrorResponse(status int, errs ...error) ResponseData {
|
||||||
StatusCode: status,
|
StatusCode: status,
|
||||||
Errors: errs,
|
Errors: errs,
|
||||||
}
|
}
|
||||||
res.MustWriteTemplate("error.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("error.html", getBaseData(c, "", nil), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,13 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBaseData(c *RequestContext) templates.BaseData {
|
func getBaseDataAutocrumb(c *RequestContext, title string) templates.BaseData {
|
||||||
|
return getBaseData(c, title, []templates.Breadcrumb{{Name: title, Url: ""}})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(asaf): If you set breadcrumbs, the breadcrumb for the current project will automatically be prepended when necessary.
|
||||||
|
// If you pass nil, no breadcrumbs will be created.
|
||||||
|
func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadcrumb) templates.BaseData {
|
||||||
var templateUser *templates.User
|
var templateUser *templates.User
|
||||||
var templateSession *templates.Session
|
var templateSession *templates.Session
|
||||||
if c.CurrentUser != nil {
|
if c.CurrentUser != nil {
|
||||||
|
@ -264,6 +270,17 @@ func getBaseData(c *RequestContext) templates.BaseData {
|
||||||
|
|
||||||
notices := getNoticesFromCookie(c)
|
notices := getNoticesFromCookie(c)
|
||||||
|
|
||||||
|
if len(breadcrumbs) > 0 {
|
||||||
|
projectUrl := hmnurl.BuildProjectHomepage(c.CurrentProject.Slug)
|
||||||
|
if breadcrumbs[0].Url != projectUrl {
|
||||||
|
rootBreadcrumb := templates.Breadcrumb{
|
||||||
|
Name: c.CurrentProject.Name,
|
||||||
|
Url: projectUrl,
|
||||||
|
}
|
||||||
|
breadcrumbs = append([]templates.Breadcrumb{rootBreadcrumb}, breadcrumbs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
episodeGuideUrl := ""
|
episodeGuideUrl := ""
|
||||||
defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug]
|
defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug]
|
||||||
if hasAnnotations {
|
if hasAnnotations {
|
||||||
|
@ -271,7 +288,9 @@ func getBaseData(c *RequestContext) templates.BaseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := templates.BaseData{
|
baseData := templates.BaseData{
|
||||||
Theme: c.Theme,
|
Theme: c.Theme,
|
||||||
|
Title: title,
|
||||||
|
Breadcrumbs: breadcrumbs,
|
||||||
|
|
||||||
CurrentUrl: c.FullUrl(),
|
CurrentUrl: c.FullUrl(),
|
||||||
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
|
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
|
||||||
|
@ -365,7 +384,7 @@ func ProjectCSS(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusBadRequest, NewSafeError(nil, "You must provide a 'color' parameter.\n"))
|
return c.ErrorResponse(http.StatusBadRequest, NewSafeError(nil, "You must provide a 'color' parameter.\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(c, "", nil)
|
||||||
|
|
||||||
bgColor := noire.NewHex(color)
|
bgColor := noire.NewHex(color)
|
||||||
h, s, l := bgColor.HSL()
|
h, s, l := bgColor.HSL()
|
||||||
|
@ -408,7 +427,7 @@ func FourOhFour(c *RequestContext) ResponseData {
|
||||||
templates.BaseData
|
templates.BaseData
|
||||||
Wanted string
|
Wanted string
|
||||||
}{
|
}{
|
||||||
BaseData: getBaseData(c),
|
BaseData: getBaseData(c, "Page not found", nil),
|
||||||
Wanted: c.FullUrl(),
|
Wanted: c.FullUrl(),
|
||||||
}
|
}
|
||||||
res.MustWriteTemplate("404.html", templateData, c.Perf)
|
res.MustWriteTemplate("404.html", templateData, c.Perf)
|
||||||
|
@ -426,7 +445,7 @@ type RejectData struct {
|
||||||
func RejectRequest(c *RequestContext, reason string) ResponseData {
|
func RejectRequest(c *RequestContext, reason string) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
err := res.WriteTemplate("reject.html", RejectData{
|
err := res.WriteTemplate("reject.html", RejectData{
|
||||||
BaseData: getBaseData(c),
|
BaseData: getBaseData(c, "Rejected", nil),
|
||||||
RejectReason: reason,
|
RejectReason: reason,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -53,8 +53,7 @@ func Showcase(c *RequestContext) ResponseData {
|
||||||
jsonItems := templates.TimelineItemsToJSON(showcaseItems)
|
jsonItems := templates.TimelineItemsToJSON(showcaseItems)
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, "Community Showcase")
|
||||||
baseData.Title = "Community Showcase"
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("showcase.html", ShowcaseData{
|
res.MustWriteTemplate("showcase.html", ShowcaseData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
|
|
@ -103,7 +103,11 @@ func Snippet(c *RequestContext) ResponseData {
|
||||||
opengraph = append(opengraph, opengraphYoutube...)
|
opengraph = append(opengraph, opengraphYoutube...)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(
|
||||||
|
c,
|
||||||
|
fmt.Sprintf("Snippet by %s", snippet.OwnerName),
|
||||||
|
[]templates.Breadcrumb{{Name: snippet.OwnerName, Url: snippet.OwnerUrl}},
|
||||||
|
)
|
||||||
baseData.OpenGraphItems = opengraph // NOTE(asaf): We're overriding the defaults on purpose.
|
baseData.OpenGraphItems = opengraph // NOTE(asaf): We're overriding the defaults on purpose.
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
err = res.WriteTemplate("snippet.html", SnippetData{
|
err = res.WriteTemplate("snippet.html", SnippetData{
|
||||||
|
|
|
@ -2,42 +2,42 @@ package website
|
||||||
|
|
||||||
func Manifesto(c *RequestContext) ResponseData {
|
func Manifesto(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("manifesto.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("manifesto.html", getBaseDataAutocrumb(c, "Manifesto"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func About(c *RequestContext) ResponseData {
|
func About(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("about.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("about.html", getBaseDataAutocrumb(c, "About"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func CodeOfConduct(c *RequestContext) ResponseData {
|
func CodeOfConduct(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("code_of_conduct.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("code_of_conduct.html", getBaseDataAutocrumb(c, "Code of Conduct"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func CommunicationGuidelines(c *RequestContext) ResponseData {
|
func CommunicationGuidelines(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("communication_guidelines.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("communication_guidelines.html", getBaseDataAutocrumb(c, "Communication Guidelines"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func ContactPage(c *RequestContext) ResponseData {
|
func ContactPage(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("contact.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("contact.html", getBaseDataAutocrumb(c, "Contact Us"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonthlyUpdatePolicy(c *RequestContext) ResponseData {
|
func MonthlyUpdatePolicy(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("monthly_update_policy.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("monthly_update_policy.html", getBaseDataAutocrumb(c, "Monthly Update Policy"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectSubmissionGuidelines(c *RequestContext) ResponseData {
|
func ProjectSubmissionGuidelines(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("project_submission_guidelines.html", getBaseData(c), c.Perf)
|
res.MustWriteTemplate("project_submission_guidelines.html", getBaseDataAutocrumb(c, "Project Submission Guidelines"), c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package website
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.handmade.network/hmn/hmn/src/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ThreadTypeDisplayNames = map[models.ThreadType]string{
|
|
||||||
models.ThreadTypeProjectBlogPost: "Blog",
|
|
||||||
models.ThreadTypeForumPost: "Forums",
|
|
||||||
}
|
|
|
@ -70,7 +70,7 @@ func PostToTimelineItem(lineageBuilder *models.SubforumLineageBuilder, post *mod
|
||||||
Description: "", // NOTE(asaf): No description for posts
|
Description: "", // NOTE(asaf): No description for posts
|
||||||
|
|
||||||
Title: thread.Title,
|
Title: thread.Title,
|
||||||
Breadcrumbs: PostBreadcrumbs(lineageBuilder, project, thread),
|
Breadcrumbs: GenericThreadBreadcrumbs(lineageBuilder, project, thread),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
package website
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"git.handmade.network/hmn/hmn/src/hmnurl"
|
|
||||||
"git.handmade.network/hmn/hmn/src/models"
|
|
||||||
"git.handmade.network/hmn/hmn/src/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NumPages(numThings, thingsPerPage int) int {
|
|
||||||
return utils.IntMax(int(math.Ceil(float64(numThings)/float64(thingsPerPage))), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BuildProjectRootResourceUrl(projectSlug string, kind models.ThreadType) string {
|
|
||||||
switch kind {
|
|
||||||
case models.ThreadTypeProjectBlogPost:
|
|
||||||
return hmnurl.BuildBlog(projectSlug, 1)
|
|
||||||
case models.ThreadTypeForumPost:
|
|
||||||
return hmnurl.BuildForum(projectSlug, nil, 1)
|
|
||||||
}
|
|
||||||
return hmnurl.BuildProjectHomepage(projectSlug)
|
|
||||||
}
|
|
|
@ -224,8 +224,7 @@ func UserProfile(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
templateUser := templates.UserToTemplate(profileUser, c.Theme)
|
templateUser := templates.UserToTemplate(profileUser, c.Theme)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, templateUser.Name)
|
||||||
baseData.Title = templateUser.Name
|
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("user_profile.html", UserProfileTemplateData{
|
res.MustWriteTemplate("user_profile.html", UserProfileTemplateData{
|
||||||
|
@ -322,8 +321,7 @@ func UserSettings(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
templateUser := templates.UserToTemplate(c.CurrentUser, c.Theme)
|
templateUser := templates.UserToTemplate(c.CurrentUser, c.Theme)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, templateUser.Name)
|
||||||
baseData.Title = templateUser.Name
|
|
||||||
|
|
||||||
res.MustWriteTemplate("user_settings.html", UserSettingsTemplateData{
|
res.MustWriteTemplate("user_settings.html", UserSettingsTemplateData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
|
|
@ -25,8 +25,7 @@ func WhenIsIt(c *RequestContext) ResponseData {
|
||||||
hasTimestamp = (err == nil)
|
hasTimestamp = (err == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseDataAutocrumb(c, "When is it?")
|
||||||
baseData.Title = "When is it?"
|
|
||||||
|
|
||||||
baseData.OpenGraphItems = append(baseData.OpenGraphItems, templates.OpenGraphItem{
|
baseData.OpenGraphItems = append(baseData.OpenGraphItems, templates.OpenGraphItem{
|
||||||
Property: "og:title",
|
Property: "og:title",
|
||||||
|
|
Loading…
Reference in New Issue