Fix up landing page colors

This commit is contained in:
Ben Visness 2021-04-23 23:27:45 -05:00
parent a04b00c0a7
commit 292c400dfb
11 changed files with 220 additions and 168 deletions

View File

@ -7438,6 +7438,15 @@ article code {
.mw-site { .mw-site {
max-width: 80rem; } max-width: 80rem; }
.mh-3 {
max-height: 4rem; }
.mh-4 {
max-height: 8rem; }
.mh-5 {
max-height: 16rem; }
.mh-100 { .mh-100 {
max-height: 100%; } max-height: 100%; }
@ -8576,17 +8585,6 @@ input[type=submit] {
border-bottom-color: transparent; } border-bottom-color: transparent; }
.thread .title:hover { .thread .title:hover {
border-bottom-color: initial; } border-bottom-color: initial; }
.thread.read {
color: #555;
color: var(--forum-thread-read-color); }
.thread.read td {
color: #555;
color: var(--forum-thread-read-color); }
.thread.read a {
color: #888;
color: var(--forum-thread-read-link-color); }
.thread.read .title {
font-weight: 500; }
.forum .thread .info th { .forum .thread .info th {
width: 50px; } width: 50px; }
@ -8598,18 +8596,18 @@ input[type=submit] {
overflow: hidden; overflow: hidden;
background-color: #bbb; background-color: #bbb;
background-color: var(--dimmest-color); } background-color: var(--dimmest-color); }
.thread .avatar-icon:not(.lite) {
left: 30px; .read {
bottom: 10px; } color: #555;
.thread .info .avatar-icon:not(.lite) { color: var(--forum-thread-read-color); }
bottom: 0px; .read td {
left: 0px; } color: #555;
.feed .avatar-icon:not(.lite) { color: var(--forum-thread-read-color); }
left: -50px; .read a {
bottom: -10px; } color: #888;
.project .box .avatar-icon:not(.lite) { color: var(--forum-thread-read-link-color); }
left: 0px; .read .title {
bottom: -10px; } font-weight: 500; }
.goto { .goto {
font-size: 200%; font-size: 200%;
@ -9220,6 +9218,10 @@ span.icon-rss::before {
width: 10rem; width: 10rem;
height: 10rem; } } height: 10rem; } }
.landing .excerpt-fade {
background-image: linear-gradient(to top, var(--content-background), rgba(0, 0, 0, 0));
pointer-events: none; }
.star-btn { .star-btn {
border-bottom-width: 2px; border-bottom-width: 2px;
background-color: #fff; background-color: #fff;

View File

@ -72,11 +72,18 @@ func (it *StructQueryIterator) Next() (interface{}, bool) {
field = field.Elem() field = field.Elem()
} }
// Some actual values still come through as pointers (like net.IPNet). Dunno why.
// Regardless, we know it's not nil, so we can get at the contents.
valReflected := reflect.ValueOf(val)
if valReflected.Kind() == reflect.Ptr {
valReflected = valReflected.Elem()
}
switch field.Kind() { switch field.Kind() {
case reflect.Int: case reflect.Int:
field.SetInt(reflect.ValueOf(val).Int()) field.SetInt(valReflected.Int())
default: default:
field.Set(reflect.ValueOf(val)) field.Set(valReflected)
} }
} }

View File

@ -248,6 +248,18 @@ article code {
max-width: 80rem; max-width: 80rem;
} }
.mh-3 {
max-height: $height-3;
}
.mh-4 {
max-height: $height-4;
}
.mh-5 {
max-height: $height-5;
}
.mh-100 { .mh-100 {
max-height: 100%; max-height: 100%;
} }

View File

@ -47,22 +47,6 @@
} }
} }
&.read {
@include usevar('color', 'forum-thread-read-color');
td {
@include usevar('color', 'forum-thread-read-color');
}
a {
@include usevar('color', 'forum-thread-read-link-color');
}
.title {
font-weight: 500;
}
}
.forum & .info th { .forum & .info th {
width: 50px; width: 50px;
} }
@ -75,27 +59,21 @@
border-radius: 100%; border-radius: 100%;
overflow: hidden; overflow: hidden;
@include usevar(background-color, dimmest-color); @include usevar(background-color, dimmest-color);
}
&:not(.lite) { .read {
.thread & { @include usevar('color', 'forum-thread-read-color');
left: 30px;
bottom: 10px;
}
.thread .info & { td {
bottom: 0px; @include usevar('color', 'forum-thread-read-color');
left: 0px; }
}
.feed & { a {
left: -50px; @include usevar('color', 'forum-thread-read-link-color');
bottom: -10px; }
}
.project .box & { .title {
left: 0px; font-weight: 500;
bottom: -10px;
}
} }
} }

View File

@ -83,4 +83,9 @@
height: 10rem; height: 10rem;
} }
} }
.excerpt-fade {
background-image: linear-gradient(to top, var(--content-background) , rgba(0, 0, 0, 0));
pointer-events: none;
}
} }

View File

@ -1,10 +1,10 @@
{{/* {{/*
This template is intended to display a single post or thread in the context of a forum, the feed, or a similar layout. This template is intended to display a single post or thread in the context of a forum, the feed, or a similar layout.
It should be called with PostListItemData. It should be called with PostListItem.
*/}} */}}
<div class="flex items-center ph3 pv2"> <div class="post-list-item flex items-center ph3 pv2 {{ if .Unread }}unread{{ else }}read{{ end }}">
<img class="avatar-icon mr2" src="{{ .User.AvatarUrl }}"> <img class="avatar-icon mr2" src="{{ .User.AvatarUrl }}">
<div class="flex-grow-1 overflow-hidden"> <div class="flex-grow-1 overflow-hidden">
<div class="breadcrumbs"> <div class="breadcrumbs">

View File

@ -1,5 +1,33 @@
{{ template "base.html" . }} {{ template "base.html" . }}
{{ define "extrahead" }}
<link rel="stylesheet" type="text/css" href="{{ static "landing.css" }}"/>
<script type="text/javascript" src="{{ static "util.js" }}"></script>
<style type="text/css">
{{ $base := . }}
{{ range $col := .PostColumns }}
{{ range $entry := $col }}
{{ $c1 := hex2color .Project.Color1 }}
{{ $linkColor := eq $base.Theme "dark" | ternary (lightness 0.55 $c1) (lightness 0.35 $c1) | color2css }}
{{ $linkHoverColor := eq $base.Theme "dark" | ternary (lightness 0.65 $c1) (lightness 0.45 $c1) | color2css }}
{{ $projectPostBackground := eq $base.Theme "dark" | ternary (lightness 0.15 $c1) (lightness 0.95 $c1) | alpha 0.2 | color2css }}
#p{{ .Project.Subdomain }} a.project-title { color: {{ $linkColor }}; }
#p{{ .Project.Subdomain }} .unread a { color: {{ $linkColor }}; }
#p{{ .Project.Subdomain }} .unread a:hover { color: {{ $linkHoverColor }} }
#p{{ .Project.Subdomain }} .unread .avatar-icon { border-color: {{ $linkColor }}; }
#p{{ .Project.Subdomain }} .post-list-item:nth-of-type(even) { background-color: {{ $projectPostBackground }}; }
#p{{ .Project.Subdomain }} .thread.more { background-color:transparent; }
{{ end }}
{{ end }}
</style>
{{/*
<script type="text/javascript" src="{% static 'templates.js' %}?v={% cachebust %}"></script>
<script type="text/javascript" src="{% static 'timeline.js' %}?v={% cachebust %}"></script>
<script type="text/javascript" src="{% static 'showcase.js' %}?v={% cachebust %}"></script>
*/}}
{{ end }}
{{ define "content" }} {{ define "content" }}
<div class="content-block"> <div class="content-block">
<div class="optionbar pb2"> <div class="optionbar pb2">
@ -33,58 +61,41 @@
</div> </div>
<div class="content-block news cf"> <div class="content-block news cf">
{{ $newsPost := .NewsPost }}
{{ range $i, $col := .PostColumns }} {{ range $i, $col := .PostColumns }}
<div class="fl w-100 w-50-l"> <div class="fl w-100 w-50-l">
<div class="mw7 mw-none-l center-layout"> <div class="mw7 mw-none-l center-layout">
{{ if eq $i 0 }} {{ if eq $i 0 }}
<div class="pt3"> <div class="pt3">
Wow, a featured post! {{ template "landing_page_featured_post" $newsPost}}
{{/* {% include "blog_index_thread_list_entry.html" with post=featured_post align_top=True %} */}}
</div> </div>
{{ end }} {{ end }}
{{ range $entry := $col }} {{ range $entry := $col }}
{{ $proj := $entry.Project }} {{ $proj := $entry.Project }}
{{ $posts := $entry.Posts }} {{ $posts := $entry.Posts }}
<div class="pt3" id="p{{ $proj.Subdomain }}"> {{/* TODO: Is this ID used for anything? */}} <div class="pt3" id="p{{ $proj.Subdomain }}">
<a {{/* TODO: Replace this special-case style with a CSS class */}} {{ $c1 := hex2color $proj.Color1 }}
<a
class="project-title"
href="{{ projecturl "/" $proj }}" href="{{ projecturl "/" $proj }}"
style="color: #{{ eq $.Theme "dark" | ternary (brighten $proj.Color1 0.1) (darken $proj.Color1 0.2) }}"
> >
<h2 class="ph3">{{ $proj.Name }}</h2> <h2 class="ph3">{{ $proj.Name }}</h2>
</a> </a>
{{ with $entry.FeaturedPost }} {{ with $entry.FeaturedPost }}
<div class="flex items-start ph3 pv2"> {{ template "landing_page_featured_post" . }}
<img class="avatar-icon mr2" src="{{ .User.AvatarUrl }}">
<div class="flex-grow-1">
<div class="overflow-hidden">
<div class="title nowrap truncate"><a href="{{ .Url }}">{{ .Title }}</a></div>
<div class="details">
<a class="user" href="{{ .User.ProfileUrl }}">{{ .User.Name }}</a> &mdash; <span class="datetime">{{ relativedate .Date }}</span>
</div>
</div>
<div>
{{ .Content }}
</div>
</div>
</div>
{{ end }} {{ end }}
{{ range $post := $posts }} {{ range $post := $posts }}
{{ template "post_list_item.html" $post }} {{ template "post_list_item.html" $post }}
{{ end }} {{ end }}
{{/*
{% with more=posts|length|add:-5|clamp_lower:0 %} <div class="ph3 thread unread more">
{% if more > 0 %} <a class="title" href="{{ projecturl "/forums" $proj }}">
<div class="ph3 thread unread more"> More posts &rarr;
<a class="title" </a>
href="{% url 'project_forum' subdomain=proj.slug %}" </div>
>{{ more }} more recently &rarr;</a>
</div>
{% endif %}
{% endwith %}
*/}}
</div> </div>
{{ end }} {{ end }}
</div> </div>
@ -94,43 +105,6 @@
{{ end }} {{ end }}
{{/* {{/*
{{ define "extrahead" }}
<link rel="stylesheet" type="text/css" href="{{ static "landing.css" }}"/>
<script type="text/javascript" src="{{ static "util.js" }}"></script>
<style type="text/css">
{{ range _, $col := .RecentPostColumns }}
{{ range _, $entry := $col }}
{{ $themeDim := eq .Theme "dark" | ternary (darken .Color 0.5) (brighten .Color 0.2) }}
{{ $themeDimmer := eq .Theme "dark" | ternary (darken .Color 0.65) (brighten .Color 0.4) }}
{{ $themeDimmest := eq .Theme "dark" | ternary (darken .Color 0.8) (brighten .Color 0.6) }}
{{ $linkColor := eq .Theme "dark" | ternary (brighten .Color 0.1) (darken .Color 0.2) }}
{{ $linkHoverColor := eq .Theme "dark" | ternary (brighten .Color 0.2) (darken .Color 0.1) }}
{{ eq .Theme "dark" }}
#p{{ .Project.Subdomain }} .unread a { color: #{% rgb_accent entry.project.color_1 0.55 %}; }
#p{{ .Project.Subdomain }} .unread a:hover { color: #{% rgb_accent entry.project.color_1 0.65 %}; }
#p{{ .Project.Subdomain }} .unread .avatar-icon { border: 2px solid #{% rgb_accent entry.project.color_1 0.55 %}; }
#p{{ .Project.Subdomain }} .thread:nth-of-type(even) { background-color:#{% rgb_accent entry.project.color_1 0.14 False 0.03%}; }
#p{{ .Project.Subdomain }} .forum .post:nth-of-type(even) { background-color:#{% rgb_accent entry.project.color_1 0.14 False 0.03 %}; }
#p{{ .Project.Subdomain }} .blog .post:nth-of-type(even) { background-color:#{% rgb_accent entry.project.color_1 0.14 False 0.03 %}; }
{{ else }}
#p{{ .Project.Subdomain }} .unread a { color: #{% rgb_accent entry.project.color_1 0.35 %}; }
#p{{ .Project.Subdomain }} .unread a:hover { color: #{% rgb_accent entry.project.color_1 0.45 %}; }
#p{{ .Project.Subdomain }} .unread .avatar-icon { border: 2px solid #{% rgb_accent entry.project.color_1 0.35 %}; }
#p{{ .Project.Subdomain }} .thread:nth-of-type(even) { background-color:#{% rgb_accent entry.project.color_1 0.94 False 0.2 %}; }
#p{{ .Project.Subdomain }} .forum .post:nth-of-type(even) { background-color:#{% rgb_accent entry.project.color_1 0.94 False 0.2 %}; }
#p{{ .Project.Subdomain }} .blog .post:nth-of-type(even) { background-color:#{% rgb_accent entry.project.color_1 0.94 False 0.2 %}; }
{{ end }}
#p{{ .Project.Subdomain }} .thread.more { background-color:transparent; }
{{ end }}
{{ end }}
</style>
<script type="text/javascript" src="{% static 'templates.js' %}?v={% cachebust %}"></script>
<script type="text/javascript" src="{% static 'timeline.js' %}?v={% cachebust %}"></script>
<script type="text/javascript" src="{% static 'showcase.js' %}?v={% cachebust %}"></script>
{{ end }}
{% block columns %} {% block columns %}
{% include "showcase/js_templates.html" %} {% include "showcase/js_templates.html" %}
{% include "timeline/js_templates.html" %} {% include "timeline/js_templates.html" %}
@ -288,4 +262,28 @@
</div> </div>
{% endspaceless %} {% endspaceless %}
{% endblock %} {% endblock %}
*/}} */}}
{{ define "landing_page_featured_post" }}
{{/* Call this template with a LandingPageFeaturedPost. */}}
<div class="flex items-start ph3 pv2 {{ if .Unread }}unread{{ else }}read{{ end }}">
<img class="avatar-icon mr2" src="{{ .User.AvatarUrl }}">
<div class="flex-grow-1">
<div class="overflow-hidden">
<div class="title nowrap truncate"><a href="{{ .Url }}">{{ .Title }}</a></div>
<div class="details">
<a class="user" href="{{ .User.ProfileUrl }}">{{ .User.Name }}</a> &mdash; <span class="datetime">{{ relativedate .Date }}</span>
</div>
</div>
<div class="overflow-hidden mh-5 mt2 relative">
<div>
{{ .Content }}
</div>
<div class="excerpt-fade absolute w-100 h4 bottom-0"></div>
</div>
<div class="mt2">
<a href="{{ .Url }}">Read More &rarr;</a>
</div>
</div>
</div>
{{ end }}

View File

@ -31,8 +31,8 @@
background-size: "{{ . }}"; background-size: "{{ . }}";
{{ end }} {{ end }}
{{ else }} {{ else }}
{{ $bgcolor := or .Project.Color1 "999999" }} {{ $bgcolor := or .Project.Color1 "999999" | hex2color }}
background-color: #{{ eq .Theme "dark" | ternary (darken $bgcolor 0.6) (brighten $bgcolor 0.6) }}; background-color: {{ eq .Theme "dark" | ternary (darken 0.6 $bgcolor) (brighten 0.6 $bgcolor) | color2css }};
background-image: url('data:image/png;base64,{{ eq .Theme "dark" | ternary $bgdark $bglight }}'); background-image: url('data:image/png;base64,{{ eq .Theme "dark" | ternary $bgdark $bglight }}');
background-size: auto; background-size: auto;
{{ end }} {{ end }}

View File

@ -1,43 +1,44 @@
{{ $themeDim := eq .Theme "dark" | ternary (darken .Color 0.5) (brighten .Color 0.2) }} {{ $c := hex2color .Color }}
{{ $themeDimmer := eq .Theme "dark" | ternary (darken .Color 0.65) (brighten .Color 0.4) }} {{ $themeDim := eq .Theme "dark" | ternary (lightness 0.35 $c) (lightness 0.75 $c) | color2css }}
{{ $themeDimmest := eq .Theme "dark" | ternary (darken .Color 0.8) (brighten .Color 0.6) }} {{ $themeDimmer := eq .Theme "dark" | ternary (lightness 0.3 $c) (lightness 0.8 $c) | color2css }}
{{ $themeDimmest := eq .Theme "dark" | ternary (lightness 0.2 $c) (lightness 0.85 $c) | color2css }}
{{ $linkColor := eq .Theme "dark" | ternary (brighten .Color 0.1) (darken .Color 0.2) }} {{ $linkColor := eq .Theme "dark" | ternary (lightness 0.55 $c) (lightness 0.35 $c) | color2css }}
{{ $linkHoverColor := eq .Theme "dark" | ternary (brighten .Color 0.2) (darken .Color 0.1) }} {{ $linkHoverColor := eq .Theme "dark" | ternary (lightness 0.65 $c) (lightness 0.45 $c) | color2css }}
:root { :root {
--theme-color: #{{ .Color }}; --theme-color: {{ $c | color2css }};
--theme-color-dim: #{{ $themeDim }}; --theme-color-dim: {{ $themeDim }};
--theme-color-dimmer: #{{ $themeDimmer }}; --theme-color-dimmer: {{ $themeDimmer }};
--theme-color-dimmest: #{{ $themeDimmest }}; --theme-color-dimmest: {{ $themeDimmest }};
--link-color: #{{ $linkColor }}; --link-color: {{ $linkColor }};
--link-color-hover: #{{ $linkHoverColor }}; --link-color-hover: {{ $linkHoverColor }};
} }
.accent { .accent {
background-color: #{{ $themeDim }}; background-color: {{ $themeDim }};
background-color: var(--theme-dim); background-color: var(--theme-dim);
} }
.user-bar { .user-bar {
border-bottom-color: #{{ $themeDim }}; border-bottom-color: {{ $themeDim }};
border-bottom-color: var(--theme-dim); border-bottom-color: var(--theme-dim);
} }
header .content-title .subtitle { header .content-title .subtitle {
border-top-color: #{{ $themeDim }}; border-top-color: {{ $themeDim }};
border-top-color: var(--theme-dim); border-top-color: var(--theme-dim);
} }
a, .thread:before, button, .button, input[type=button], input[type=submit] { a, .thread:before, button, .button, input[type=button], input[type=submit] {
color: #{{ $linkColor }}; color: {{ $linkColor }};
color: var(--link-color); color: var(--link-color);
} }
a:hover, button:hover, .button:hover, input[type=button]:hover, input[type=submit]:hover { a:hover, button:hover, .button:hover, input[type=button]:hover, input[type=submit]:hover {
color: #{{ $linkHoverColor }}; color: {{ $linkHoverColor }};
color: var(--link-hover-color); color: var(--link-hover-color);
} }
.unread .avatar-icon { .unread .avatar-icon {
border: 2px solid #{{ $linkColor }}; border: 2px solid {{ $linkColor }};
border: 2px solid var(--link-color); border: 2px solid var(--link-color);
} }
@ -91,7 +92,7 @@ all of this CSS.
{% endif %} */ {% endif %} */
:root { :root {
--background-even-background: #{{ eq .Theme "dark" | ternary (darken .Color 0.8) (brighten .Color 0.9) }}; --background-even-background: {{ eq .Theme "dark" | ternary (lightness 0.15 $c) (lightness 0.95 $c) | color2css }};
} }
/* Assets */ /* Assets */

View File

@ -67,15 +67,19 @@ func names(ts []*template.Template) []string {
} }
var HMNTemplateFuncs = template.FuncMap{ var HMNTemplateFuncs = template.FuncMap{
"brighten": func(hexColor string, amount float64) (string, error) { "alpha": func(alpha float64, color noire.Color) noire.Color {
if len(hexColor) < 6 { color.Alpha = alpha
return "", fmt.Errorf("couldn't brighten invalid hex color: %v", hexColor) return color
} },
return noire.NewHex(hexColor).Tint(amount).Hex(), nil "brighten": func(amount float64, color noire.Color) noire.Color {
return color.Tint(amount)
}, },
"cachebust": func() string { "cachebust": func() string {
return cachebust return cachebust
}, },
"color2css": func(color noire.Color) template.CSS {
return template.CSS(color.HTML())
},
"currentprojecturl": func(url string) string { "currentprojecturl": func(url string) string {
return hmnurl.Url(url, nil) // TODO: Use project subdomain return hmnurl.Url(url, nil) // TODO: Use project subdomain
}, },
@ -83,11 +87,18 @@ var HMNTemplateFuncs = template.FuncMap{
absUrl := hmnurl.Url(url, nil) absUrl := hmnurl.Url(url, nil)
return fmt.Sprintf("%s?%s", absUrl, query) // TODO: Use project subdomain return fmt.Sprintf("%s?%s", absUrl, query) // TODO: Use project subdomain
}, },
"darken": func(hexColor string, amount float64) (string, error) { "darken": func(amount float64, color noire.Color) noire.Color {
if len(hexColor) < 6 { return color.Shade(amount)
return "", fmt.Errorf("couldn't darken invalid hex color: %v", hexColor) },
"hex2color": func(hex string) (noire.Color, error) {
if len(hex) < 6 {
return noire.Color{}, fmt.Errorf("hex color was invalid: %v", hex)
} }
return noire.NewHex(hexColor).Shade(amount).Hex(), nil return noire.NewHex(hex), nil
},
"lightness": func(lightness float64, color noire.Color) noire.Color {
h, s, _, a := color.HSLA()
return noire.NewHSLA(h, s, lightness*100, a)
}, },
"projecturl": func(url string, proj interface{}) string { "projecturl": func(url string, proj interface{}) string {
return hmnurl.ProjectUrl(url, nil, getProjectSubdomain(proj)) return hmnurl.ProjectUrl(url, nil, getProjectSubdomain(proj))

View File

@ -1,6 +1,7 @@
package website package website
import ( import (
"html/template"
"net/http" "net/http"
"time" "time"
@ -13,6 +14,7 @@ import (
type LandingTemplateData struct { type LandingTemplateData struct {
templates.BaseData templates.BaseData
NewsPost LandingPageFeaturedPost
PostColumns [][]LandingPageProject PostColumns [][]LandingPageProject
ShowcaseTimelineJson string ShowcaseTimelineJson string
} }
@ -29,7 +31,7 @@ type LandingPageFeaturedPost struct {
User templates.User User templates.User
Date time.Time Date time.Time
Unread bool Unread bool
Content string Content template.HTML
} }
func Index(c *RequestContext) ResponseData { func Index(c *RequestContext) ResponseData {
@ -67,7 +69,7 @@ func Index(c *RequestContext) ResponseData {
for _, projRow := range allProjects { for _, projRow := range allProjects {
proj := projRow.(*models.Project) proj := projRow.(*models.Project)
type ProjectPost struct { type projectPostQuery struct {
Post models.Post `db:"post"` Post models.Post `db:"post"`
Thread models.Thread `db:"thread"` Thread models.Thread `db:"thread"`
Cat models.Category `db:"cat"` Cat models.Category `db:"cat"`
@ -75,8 +77,7 @@ func Index(c *RequestContext) ResponseData {
ThreadLastReadTime *time.Time `db:"tlri.lastread"` ThreadLastReadTime *time.Time `db:"tlri.lastread"`
CatLastReadTime *time.Time `db:"clri.lastread"` CatLastReadTime *time.Time `db:"clri.lastread"`
} }
projectPostIter, err := db.Query(c.Context(), c.Conn, projectPostQuery{},
projectPostIter, err := db.Query(c.Context(), c.Conn, ProjectPost{},
` `
SELECT $columns SELECT $columns
FROM FROM
@ -116,7 +117,7 @@ func Index(c *RequestContext) ResponseData {
} }
for _, projectPostRow := range projectPosts { for _, projectPostRow := range projectPosts {
projectPost := projectPostRow.(*ProjectPost) projectPost := projectPostRow.(*projectPostQuery)
hasRead := false hasRead := false
if projectPost.ThreadLastReadTime != nil && projectPost.ThreadLastReadTime.After(projectPost.Post.PostDate) { if projectPost.ThreadLastReadTime != nil && projectPost.ThreadLastReadTime.After(projectPost.Post.PostDate) {
@ -148,20 +149,18 @@ func Index(c *RequestContext) ResponseData {
} }
content := contentResult.(*featuredContentResult).Content content := contentResult.(*featuredContentResult).Content
// c.Logger.Debug().Str("content", content).Msg("")
landingPageProject.FeaturedPost = &LandingPageFeaturedPost{ landingPageProject.FeaturedPost = &LandingPageFeaturedPost{
Title: projectPost.Thread.Title, Title: projectPost.Thread.Title,
Url: templates.PostUrl(projectPost.Post, projectPost.Cat.Kind, proj.Subdomain()), // TODO Url: templates.PostUrl(projectPost.Post, projectPost.Cat.Kind, proj.Subdomain()),
User: templates.UserToTemplate(&projectPost.User), User: templates.UserToTemplate(&projectPost.User),
Date: projectPost.Post.PostDate, Date: projectPost.Post.PostDate,
Unread: !hasRead, Unread: !hasRead,
Content: content, Content: template.HTML(content),
} }
} else { } else {
landingPageProject.Posts = append(landingPageProject.Posts, templates.PostListItem{ landingPageProject.Posts = append(landingPageProject.Posts, templates.PostListItem{
Title: projectPost.Thread.Title, Title: projectPost.Thread.Title,
Url: templates.PostUrl(projectPost.Post, projectPost.Cat.Kind, proj.Subdomain()), // TODO Url: templates.PostUrl(projectPost.Post, projectPost.Cat.Kind, proj.Subdomain()),
User: templates.UserToTemplate(&projectPost.User), User: templates.UserToTemplate(&projectPost.User),
Date: projectPost.Post.PostDate, Date: projectPost.Post.PostDate,
Unread: !hasRead, Unread: !hasRead,
@ -230,12 +229,51 @@ func Index(c *RequestContext) ResponseData {
} }
} }
type newsPostQuery struct {
Post models.Post `db:"post"`
PostVersion models.PostVersion `db:"ver"`
Thread models.Thread `db:"thread"`
User models.User `db:"auth_user"`
}
newsPostRow, err := db.QueryOne(c.Context(), c.Conn, newsPostQuery{},
`
SELECT $columns
FROM
handmade_post AS post
JOIN handmade_thread AS thread ON post.thread_id = thread.id
JOIN handmade_category AS cat ON thread.category_id = cat.id
JOIN auth_user ON post.author_id = auth_user.id
JOIN handmade_postversion AS ver ON post.current_id = ver.id
WHERE
cat.project_id = $1
AND cat.kind = $2
AND post.id = thread.first_id
AND thread.moderated = 0
ORDER BY post.postdate DESC
LIMIT 1
`,
models.HMNProjectID,
models.CatTypeBlog,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news post"))
}
newsPostResult := newsPostRow.(*newsPostQuery)
baseData := getBaseData(c) baseData := getBaseData(c)
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
err = res.WriteTemplate("index.html", LandingTemplateData{ err = res.WriteTemplate("index.html", LandingTemplateData{
BaseData: getBaseData(c), BaseData: baseData,
NewsPost: LandingPageFeaturedPost{
Title: newsPostResult.Thread.Title,
Url: templates.PostUrl(newsPostResult.Post, models.CatTypeBlog, ""),
User: templates.UserToTemplate(&newsPostResult.User),
Date: newsPostResult.Post.PostDate,
Unread: true, // TODO
Content: template.HTML(newsPostResult.PostVersion.TextParsed),
},
PostColumns: cols, PostColumns: cols,
}) })
if err != nil { if err != nil {