Added theme to context and added empty-avatar support
This commit is contained in:
parent
e5beb209c0
commit
9c19484333
|
@ -72,14 +72,6 @@ func ProjectUrlWithFragment(path string, query []Q, slug string, fragment string
|
|||
return url.String()
|
||||
}
|
||||
|
||||
func StaticUrl(path string, query []Q) string {
|
||||
return Url(StaticPath+"/"+trim(path), query)
|
||||
}
|
||||
|
||||
func StaticThemeUrl(path string, theme string, query []Q) string {
|
||||
return Url(StaticThemePath+"/"+theme+"/"+trim(path), query)
|
||||
}
|
||||
|
||||
func trim(path string) string {
|
||||
if len(path) > 0 && path[0] == '/' {
|
||||
return path[1:]
|
||||
|
|
|
@ -329,14 +329,17 @@ func TestProjectCSS(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPublic(t *testing.T) {
|
||||
AssertRegexMatch(t, BuildPublic("test"), RegexPublic, nil)
|
||||
AssertRegexMatch(t, BuildPublic("/test"), RegexPublic, nil)
|
||||
AssertRegexMatch(t, BuildPublic("/test/"), RegexPublic, nil)
|
||||
AssertRegexMatch(t, BuildPublic("/test/thing/image.png"), RegexPublic, nil)
|
||||
assert.Panics(t, func() { BuildPublic("") })
|
||||
assert.Panics(t, func() { BuildPublic("/") })
|
||||
assert.Panics(t, func() { BuildPublic("/thing//image.png") })
|
||||
assert.Panics(t, func() { BuildPublic("/thing/ /image.png") })
|
||||
AssertRegexMatch(t, BuildPublic("test", false), RegexPublic, nil)
|
||||
AssertRegexMatch(t, BuildPublic("/test", true), RegexPublic, nil)
|
||||
AssertRegexMatch(t, BuildPublic("/test/", false), RegexPublic, nil)
|
||||
AssertRegexMatch(t, BuildPublic("/test/thing/image.png", true), RegexPublic, nil)
|
||||
assert.Panics(t, func() { BuildPublic("", false) })
|
||||
assert.Panics(t, func() { BuildPublic("/", false) })
|
||||
assert.Panics(t, func() { BuildPublic("/thing//image.png", false) })
|
||||
assert.Panics(t, func() { BuildPublic("/thing/ /image.png", false) })
|
||||
assert.Panics(t, func() { BuildPublic("/thing/image.png?hello", false) })
|
||||
|
||||
AssertRegexMatch(t, BuildTheme("test.css", "light", true), RegexPublic, nil)
|
||||
}
|
||||
|
||||
func TestMarkRead(t *testing.T) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package hmnurl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
@ -577,11 +578,14 @@ func BuildProjectCSS(color string) string {
|
|||
|
||||
var RegexPublic = regexp.MustCompile("^/public/.+$")
|
||||
|
||||
func BuildPublic(filepath string) string {
|
||||
func BuildPublic(filepath string, cachebust bool) string {
|
||||
filepath = strings.Trim(filepath, "/")
|
||||
if len(strings.TrimSpace(filepath)) == 0 {
|
||||
panic(oops.New(nil, "Attempted to build a /public url with no path"))
|
||||
}
|
||||
if strings.Contains(filepath, "?") {
|
||||
panic(oops.New(nil, "Public url failpath must not contain query params"))
|
||||
}
|
||||
var builder strings.Builder
|
||||
builder.WriteString("/public")
|
||||
pathParts := strings.Split(filepath, "/")
|
||||
|
@ -593,7 +597,18 @@ func BuildPublic(filepath string) string {
|
|||
builder.WriteRune('/')
|
||||
builder.WriteString(part)
|
||||
}
|
||||
return Url(builder.String(), nil)
|
||||
var query []Q
|
||||
if cachebust {
|
||||
query = []Q{{"v", cacheBust}}
|
||||
}
|
||||
return Url(builder.String(), query)
|
||||
}
|
||||
|
||||
func BuildTheme(filepath string, theme string, cachebust bool) string {
|
||||
if len(theme) == 0 {
|
||||
panic(oops.New(nil, "Theme can't be blank"))
|
||||
}
|
||||
return BuildPublic(fmt.Sprintf("themes/%s/%s", theme, strings.Trim(filepath, "/")), cachebust)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
"git.handmade.network/hmn/hmn/src/models"
|
||||
)
|
||||
|
||||
func PostToTemplate(p *models.Post, author *models.User) Post {
|
||||
func PostToTemplate(p *models.Post, author *models.User, currentTheme string) Post {
|
||||
var authorUser *User
|
||||
if author != nil {
|
||||
authorTmpl := UserToTemplate(author)
|
||||
authorTmpl := UserToTemplate(author, currentTheme)
|
||||
authorUser = &authorTmpl
|
||||
}
|
||||
|
||||
|
@ -31,11 +31,11 @@ func PostToTemplate(p *models.Post, author *models.User) Post {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *Post) AddContentVersion(ver models.PostVersion, editor *models.User) {
|
||||
func (p *Post) AddContentVersion(ver models.PostVersion, editor *models.User, currentTheme string) {
|
||||
p.Content = template.HTML(ver.TextParsed)
|
||||
|
||||
if editor != nil {
|
||||
editorTmpl := UserToTemplate(editor)
|
||||
editorTmpl := UserToTemplate(editor, currentTheme)
|
||||
p.Editor = &editorTmpl
|
||||
p.EditDate = ver.EditDate
|
||||
p.EditIP = maybeIp(ver.EditIP)
|
||||
|
@ -76,12 +76,14 @@ func ThreadToTemplate(t *models.Thread) Thread {
|
|||
}
|
||||
}
|
||||
|
||||
func UserToTemplate(u *models.User) User {
|
||||
func UserToTemplate(u *models.User, currentTheme string) User {
|
||||
// TODO: Handle deleted users. Maybe not here, but if not, at call sites of this function.
|
||||
|
||||
avatar := ""
|
||||
if u.Avatar != nil {
|
||||
avatar = hmnurl.StaticUrl(*u.Avatar, nil)
|
||||
if u.Avatar != nil && len(*u.Avatar) > 0 {
|
||||
avatar = hmnurl.BuildPublic(*u.Avatar, false)
|
||||
} else {
|
||||
avatar = hmnurl.BuildTheme("empty-avatar.svg", currentTheme, true)
|
||||
}
|
||||
|
||||
name := u.Name
|
||||
|
@ -99,7 +101,7 @@ func UserToTemplate(u *models.User) User {
|
|||
Name: name,
|
||||
Blurb: u.Blurb,
|
||||
Signature: u.Signature,
|
||||
AvatarUrl: avatar, // TODO
|
||||
AvatarUrl: avatar,
|
||||
ProfileUrl: hmnurl.Url("m/"+u.Username, nil),
|
||||
|
||||
DarkTheme: u.DarkTheme,
|
||||
|
|
|
@ -86,7 +86,9 @@
|
|||
<span class="pl3">
|
||||
Edited by
|
||||
<a class="name" href="{{ .Editor.ProfileUrl }}" target="_blank">{{ coalesce .Editor.Name .Editor.Username }}</a>
|
||||
{{ if and $.User.IsStaff .EditIP }}<span class="ip">[{{ .EditIP }}]</span>{{ end }}
|
||||
{{ if $.User }}
|
||||
{{ if and $.User.IsStaff .EditIP }}<span class="ip">[{{ .EditIP }}]</span>{{ end }}
|
||||
{{ end }}
|
||||
on {{ timehtml (absolutedate .EditDate) .EditDate }}
|
||||
{{ with .EditReason }}
|
||||
Reason: {{ . }}
|
||||
|
|
|
@ -26,4 +26,4 @@ It should be called with PostListItem.
|
|||
<div class="goto">
|
||||
<a href="{{ .Url }}">»</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -33,4 +33,4 @@ It should be called with ThreadListItem.
|
|||
<div class="goto">
|
||||
<a href="{{ .Url }}">»</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -149,28 +149,21 @@ var HMNTemplateFuncs = template.FuncMap{
|
|||
}
|
||||
},
|
||||
"static": func(filepath string) string {
|
||||
return hmnurl.StaticUrl(filepath, []hmnurl.Q{{"v", cachebust}})
|
||||
return hmnurl.BuildPublic(filepath, true)
|
||||
},
|
||||
"staticnobust": func(filepath string) string {
|
||||
return hmnurl.StaticUrl(filepath, nil)
|
||||
return hmnurl.BuildPublic(filepath, false)
|
||||
},
|
||||
"statictheme": func(theme string, filepath string) string {
|
||||
return hmnurl.StaticThemeUrl(filepath, theme, []hmnurl.Q{{"v", cachebust}})
|
||||
return hmnurl.BuildTheme(filepath, theme, true)
|
||||
},
|
||||
"staticthemenobust": func(theme string, filepath string) string {
|
||||
return hmnurl.StaticThemeUrl(filepath, theme, nil)
|
||||
return hmnurl.BuildTheme(filepath, theme, false)
|
||||
},
|
||||
"timehtml": func(formatted string, t time.Time) template.HTML {
|
||||
iso := t.Format(time.RFC3339)
|
||||
return template.HTML(fmt.Sprintf(`<time datetime="%s">%s</time>`, iso, formatted))
|
||||
},
|
||||
"url": func(url string) string {
|
||||
return hmnurl.Url(url, nil)
|
||||
},
|
||||
"urlq": func(url string, query string) string {
|
||||
absUrl := hmnurl.Url(url, nil)
|
||||
return fmt.Sprintf("%s?%s", absUrl, query)
|
||||
},
|
||||
}
|
||||
|
||||
type ErrInvalidHexColor struct {
|
||||
|
|
|
@ -148,6 +148,7 @@ func Feed(c *RequestContext) ResponseData {
|
|||
postResult.LibraryResource,
|
||||
!hasRead,
|
||||
true,
|
||||
c.Theme,
|
||||
))
|
||||
}
|
||||
c.Perf.EndBlock()
|
||||
|
|
|
@ -141,9 +141,9 @@ func ForumCategory(c *RequestContext) ResponseData {
|
|||
return templates.ThreadListItem{
|
||||
Title: row.Thread.Title,
|
||||
Url: hmnurl.BuildForumThread(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(row.Thread.CategoryID), row.Thread.ID, row.Thread.Title, 1),
|
||||
FirstUser: templates.UserToTemplate(row.FirstUser),
|
||||
FirstUser: templates.UserToTemplate(row.FirstUser, c.Theme),
|
||||
FirstDate: row.FirstPost.PostDate,
|
||||
LastUser: templates.UserToTemplate(row.LastUser),
|
||||
LastUser: templates.UserToTemplate(row.LastUser, c.Theme),
|
||||
LastDate: row.LastPost.PostDate,
|
||||
|
||||
Unread: !hasRead,
|
||||
|
@ -403,8 +403,8 @@ func ForumThread(c *RequestContext) ResponseData {
|
|||
for _, irow := range itPosts.ToSlice() {
|
||||
row := irow.(*postsQueryResult)
|
||||
|
||||
post := templates.PostToTemplate(&row.Post, row.Author)
|
||||
post.AddContentVersion(row.Ver, row.Editor)
|
||||
post := templates.PostToTemplate(&row.Post, row.Author, c.Theme)
|
||||
post.AddContentVersion(row.Ver, row.Editor, c.Theme)
|
||||
post.AddUrls(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, post.ID)
|
||||
|
||||
posts = append(posts, post)
|
||||
|
|
|
@ -183,7 +183,7 @@ func Index(c *RequestContext) ResponseData {
|
|||
landingPageProject.FeaturedPost = &LandingPageFeaturedPost{
|
||||
Title: projectPost.Thread.Title,
|
||||
Url: hmnurl.BuildBlogPost(proj.Slug, projectPost.Thread.ID, projectPost.Post.ID),
|
||||
User: templates.UserToTemplate(&projectPost.User),
|
||||
User: templates.UserToTemplate(&projectPost.User, c.Theme),
|
||||
Date: projectPost.Post.PostDate,
|
||||
Unread: !hasRead,
|
||||
Content: template.HTML(content),
|
||||
|
@ -200,6 +200,7 @@ func Index(c *RequestContext) ResponseData {
|
|||
projectPost.LibraryResource,
|
||||
!hasRead,
|
||||
false,
|
||||
c.Theme,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -293,7 +294,7 @@ func Index(c *RequestContext) ResponseData {
|
|||
NewsPost: LandingPageFeaturedPost{
|
||||
Title: newsPostResult.Thread.Title,
|
||||
Url: hmnurl.BuildBlogPost(models.HMNProjectSlug, newsPostResult.Thread.ID, newsPostResult.Post.ID),
|
||||
User: templates.UserToTemplate(&newsPostResult.User),
|
||||
User: templates.UserToTemplate(&newsPostResult.User, c.Theme),
|
||||
Date: newsPostResult.Post.PostDate,
|
||||
Unread: true, // TODO
|
||||
Content: template.HTML(newsPostResult.PostVersion.TextParsed),
|
||||
|
|
|
@ -30,11 +30,11 @@ func UrlForGenericPost(post *models.Post, subforums []string, threadTitle string
|
|||
}
|
||||
|
||||
// NOTE(asaf): THIS DOESN'T HANDLE WIKI EDIT ITEMS. Wiki edits are PostTextVersions, not Posts.
|
||||
func MakePostListItem(lineageBuilder *models.CategoryLineageBuilder, project *models.Project, thread *models.Thread, post *models.Post, user *models.User, libraryResource *models.LibraryResource, unread bool, includeBreadcrumbs bool) templates.PostListItem {
|
||||
func MakePostListItem(lineageBuilder *models.CategoryLineageBuilder, project *models.Project, thread *models.Thread, post *models.Post, user *models.User, libraryResource *models.LibraryResource, unread bool, includeBreadcrumbs bool, currentTheme string) templates.PostListItem {
|
||||
var result templates.PostListItem
|
||||
|
||||
result.Title = thread.Title
|
||||
result.User = templates.UserToTemplate(user)
|
||||
result.User = templates.UserToTemplate(user, currentTheme)
|
||||
result.Date = post.PostDate
|
||||
result.Unread = unread
|
||||
libraryResourceId := 0
|
||||
|
|
|
@ -121,6 +121,7 @@ type RequestContext struct {
|
|||
Conn *pgxpool.Pool
|
||||
CurrentProject *models.Project
|
||||
CurrentUser *models.User
|
||||
Theme string
|
||||
|
||||
Perf *perf.RequestPerf
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ func getBaseData(c *RequestContext) templates.BaseData {
|
|||
Project: templates.ProjectToTemplate(c.CurrentProject),
|
||||
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
|
||||
User: templateUser,
|
||||
Theme: "light",
|
||||
Theme: c.Theme,
|
||||
ProjectCSSUrl: hmnurl.BuildProjectCSS(c.CurrentProject.Color1),
|
||||
Header: templates.Header{
|
||||
AdminUrl: hmnurl.BuildHomepage(), // TODO(asaf)
|
||||
|
@ -279,6 +279,13 @@ func LoadCommonWebsiteData(c *RequestContext) (bool, ResponseData) {
|
|||
// http.ErrNoCookie is the only error Cookie ever returns, so no further handling to do here.
|
||||
}
|
||||
|
||||
theme := "light"
|
||||
if c.CurrentUser != nil && c.CurrentUser.DarkTheme {
|
||||
theme = "dark"
|
||||
}
|
||||
|
||||
c.Theme = theme
|
||||
|
||||
return true, ResponseData{}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue