Rework blog page, add latest news + unread
This commit is contained in:
parent
c624f722f7
commit
716014c607
|
@ -7164,6 +7164,7 @@ code {
|
||||||
--color: #000;
|
--color: #000;
|
||||||
--link-color: #d12991;
|
--link-color: #d12991;
|
||||||
--timeline-media-background: #b4b4b466;
|
--timeline-media-background: #b4b4b466;
|
||||||
|
--unread-color: #9498ff;
|
||||||
--border-color: var(--c4);
|
--border-color: var(--c4);
|
||||||
--border-color-focused: #4e55ff;
|
--border-color-focused: #4e55ff;
|
||||||
--border-color-error: #ff3a3a;
|
--border-color-error: #ff3a3a;
|
||||||
|
@ -8147,7 +8148,7 @@ input[type=submit]:not(.no-padding),
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 1000em;
|
border-radius: 1000em;
|
||||||
padding: 0 0.8em;
|
padding: 0 0.8em;
|
||||||
font-size: 0.9em;
|
font-size: 0.6em;
|
||||||
line-height: 1.8em;
|
line-height: 1.8em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
@ -8924,6 +8925,14 @@ code .ss,
|
||||||
max-height: calc(100vh - 2rem);
|
max-height: calc(100vh - 2rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.timeline-unread {
|
||||||
|
--size: 0.5rem;
|
||||||
|
display: inline-block;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
background-color: var(--unread-color);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
/* src/rawdata/scss/style.css */
|
/* src/rawdata/scss/style.css */
|
||||||
/*! TACHYONS v4.12.0 | http://tachyons.io */
|
/*! TACHYONS v4.12.0 | http://tachyons.io */
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 1000em;
|
border-radius: 1000em;
|
||||||
padding: 0 0.8em;
|
padding: 0 0.8em;
|
||||||
font-size: 0.9em;
|
font-size: 0.6em;
|
||||||
line-height: 1.8em;
|
line-height: 1.8em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
|
|
|
@ -70,3 +70,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timeline-unread {
|
||||||
|
--size: 0.5rem;
|
||||||
|
display: inline-block;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
background-color: var(--unread-color);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
|
@ -39,6 +39,8 @@ $breakpoint-large: screen and (min-width: 60em)
|
||||||
|
|
||||||
--timeline-media-background: #b4b4b466;
|
--timeline-media-background: #b4b4b466;
|
||||||
|
|
||||||
|
--unread-color: #9498ff;
|
||||||
|
|
||||||
--border-color: var(--c4);
|
--border-color: var(--c4);
|
||||||
--border-color-focused: #4e55ff;
|
--border-color-focused: #4e55ff;
|
||||||
--border-color-error: #ff3a3a;
|
--border-color-error: #ff3a3a;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<svg viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M7,5.444l5.444,-5.444l1.556,1.556l-5.444,5.444l5.444,5.444l-1.556,1.556l-5.444,-5.444l-5.444,5.444l-1.556,-1.556l5.444,-5.444l-5.444,-5.444l1.556,-1.556l5.444,5.444Z"/></svg>
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M7,5.444l5.444,-5.444l1.556,1.556l-5.444,5.444l5.444,5.444l-1.556,1.556l-5.444,-5.444l-5.444,5.444l-1.556,-1.556l5.444,-5.444l-5.444,-5.444l1.556,-1.556l5.444,5.444Z"/></svg>
|
Before Width: | Height: | Size: 257 B After Width: | Height: | Size: 300 B |
|
@ -1,77 +1,57 @@
|
||||||
{{ template "base-2024.html" . }}
|
{{ template "base-2024.html" . }}
|
||||||
|
|
||||||
{{ define "content" }}
|
{{ define "content" }}
|
||||||
<div class="flex justify-center pa3">
|
<div class="m-center mw-site pv3 pv5-ns ph3 ph0-l flex flex-column g2">
|
||||||
<div class="mw-site post-content flex flex-column g2">
|
<h1 class="tc-ns f3 f2-ns lh-title">{{ .Thread.Title }}</h1>
|
||||||
<div>
|
|
||||||
<h1>{{ .Thread.Title }}</h1>
|
|
||||||
{{ with .MainPost }}
|
{{ with .MainPost }}
|
||||||
<div class="flex justify-between items-center mt2 mb3">
|
<div class="flex justify-center-ns items-center g2">
|
||||||
<div class="flex items-center">
|
<img class="avatar avatar-user avatar-small" src="{{ .Author.AvatarUrl }}">
|
||||||
<div class="avatar contain bg-center" style="background-image:url('{{ .Author.AvatarUrl }}');"></div>
|
<span class="f6 f5-ns">
|
||||||
<div class="flex flex-column ml2">
|
<a class="b link-normal" href="{{ .Author.ProfileUrl }}">{{ .Author.Name }}</a>
|
||||||
<div>
|
— {{ timehtml (absoluteshortdate .PostDate) .PostDate }}
|
||||||
<a class="username" href="{{ .Author.ProfileUrl }}" target="_blank">{{ .Author.Name }}</a>
|
{{ if and $.User (or (eq .Author.ID $.User.ID) $.User.IsStaff) }}
|
||||||
</div>
|
(<a href="{{ .EditUrl }}" title="Edit">Edit</a>, <a href="{{ .DeleteUrl }}" title="Delete">Delete</a>)
|
||||||
<div class="c--dim f7">{{ timehtml (absoluteshortdate .PostDate) .PostDate }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="di ph1">
|
|
||||||
{{ if .Author.IsStaff }}
|
|
||||||
<div class="badge staff"></div>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1"></div>
|
|
||||||
<div>
|
|
||||||
{{ if and $.User $.Project.HasBlog }}
|
|
||||||
<div class="flex">
|
|
||||||
{{ if or (eq .Author.ID $.User.ID) $.User.IsStaff }}
|
|
||||||
<a class="delete action button" href="{{ .DeleteUrl }}" title="Delete">✖</a>
|
|
||||||
<a class="edit action button" href="{{ .EditUrl }}" title="Edit">✎</a>
|
|
||||||
{{ end }}
|
|
||||||
{{ if or (not $.Thread.Locked) $.User.IsStaff }}
|
|
||||||
{{ if $.Thread.Locked }}
|
|
||||||
WARNING: locked thread - use power responsibly!
|
|
||||||
{{ end }}
|
|
||||||
<a class="reply action button" href="{{ .ReplyUrl }}" title="Reply">↪</a>
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="m-center mw-site-narrow ph3 ph0-l flex flex-column g2">
|
||||||
{{ end }}
|
<div class="post-content overflow-x-auto {{ if .IsProjectPage }}mb3{{ end }}">
|
||||||
|
|
||||||
<!-- Main post -->
|
|
||||||
<div class="{{ if .IsProjectPage }}mb3{{ end }}">
|
|
||||||
<div class="post-content overflow-x-auto">
|
|
||||||
{{ .MainPost.Content }}
|
{{ .MainPost.Content }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{ if not .IsProjectPage }}
|
{{ if not .IsProjectPage }}
|
||||||
{{ template "newsletter_signup.html" . }}
|
{{ template "newsletter_signup.html" . }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="bb ba1"></div>
|
<hr class="m-center mw-site">
|
||||||
|
|
||||||
{{ range .Comments }}
|
<div class="pt4 m-center mw-site-narrow ph3 ph0-l flex flex-column g2">
|
||||||
<div class="pa2 flex items-start background-even">
|
|
||||||
<div>
|
|
||||||
<div class="avatar contain bg-center" style="background-image:url('{{ .Author.AvatarUrl }}');"></div>
|
|
||||||
</div>
|
|
||||||
<div class="pl3 flex flex-column w-100">
|
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div>
|
<h3 class="f4">Comments</h3>
|
||||||
<div>
|
{{ if .Project.HasBlog }}
|
||||||
<a class="username" href="{{ .Author.ProfileUrl }}" target="_blank">{{ .Author.Name }}</a>
|
<a class="flex items-center g2" href="{{ not (not $.User) | ternary .ReplyLink .LoginLink }}">{{ svg "add" }}<span>Leave a Comment</span></a>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<div class="c--dim f7">
|
<div class="flex flex-column g2">
|
||||||
{{ timehtml (relativedate .PostDate) .PostDate }}
|
{{ range .Comments }}
|
||||||
{{ if .Editor }}
|
<div class="bg3 pa3 flex flex-column g3">
|
||||||
<span class="pl3">
|
<div class="flex link-normal">
|
||||||
Edited by
|
<img class="avatar avatar-user mr2" src="{{ .Author.AvatarUrl }}">
|
||||||
<a class="name" href="{{ .Editor.ProfileUrl }}" target="_blank">{{ coalesce .Editor.Name .Editor.Username }}</a>
|
<div class="flex flex-column g1">
|
||||||
|
<div class="flex items-center g2">
|
||||||
|
<a class="b" href="{{ .Author.ProfileUrl }}">{{ .Author.Name }}</a>
|
||||||
|
{{ if .Author.IsStaff }}
|
||||||
|
<div class="badge staff"></div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<div class="f6">
|
||||||
|
{{ timehtml (absoluteshortdate .PostDate) .PostDate }}
|
||||||
|
{{- if .Editor -}}
|
||||||
|
.
|
||||||
|
Edited by <a class="name" href="{{ .Editor.ProfileUrl }}">{{ coalesce .Editor.Name .Editor.Username }}</a>
|
||||||
on {{ timehtml (absolutedate .EditDate) .EditDate }}
|
on {{ timehtml (absolutedate .EditDate) .EditDate }}
|
||||||
{{ with .EditReason }}
|
{{ with .EditReason }}
|
||||||
Reason: {{ . }}
|
Reason: {{ . }}
|
||||||
|
@ -80,11 +60,6 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="di ph1">
|
|
||||||
{{ if .Author.IsStaff }}
|
|
||||||
<div class="badge staff"></div>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1"></div>
|
<div class="flex-grow-1"></div>
|
||||||
<div>
|
<div>
|
||||||
{{ if and $.User $.Project.HasBlog }}
|
{{ if and $.User $.Project.HasBlog }}
|
||||||
|
@ -106,26 +81,22 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-100 pt3">
|
|
||||||
<div class="post-content overflow-x-auto">
|
<div class="post-content overflow-x-auto">
|
||||||
{{ .Content }}
|
{{ .Content }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
<div class="bb ba1"></div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{{ if .Project.HasBlog }}
|
|
||||||
{{ if $.User }}
|
|
||||||
<a href="{{ .ReplyLink }}"><span class="big pr1">+</span> Add Comment</a>
|
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<a href="{{ .LoginLink }}">Log in to comment</a>
|
<div class="bg3 tc pv4 f7">
|
||||||
{{ end }}
|
No comments yet.
|
||||||
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
{{ if .Project.HasBlog }}
|
||||||
|
{{ if gt (len .Comments) 0 }}
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<a class="flex items-center g2" href="{{ not (not $.User) | ternary .ReplyLink .LoginLink }}">{{ svg "add" }}<span>Leave a Comment</span></a>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -8,17 +8,17 @@
|
||||||
</a>
|
</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if .ForumLayout }}
|
{{ if .ForumLayout }}
|
||||||
<div class="overflow-hidden flex-grow-1 flex flex-column g1 justify-center">
|
<div class="overflow-hidden flex-grow-1 flex flex-column g1 justify-center link-normal">
|
||||||
{{ with .Breadcrumbs }}
|
{{ with .Breadcrumbs }}
|
||||||
{{ template "breadcrumbs.html" . }}
|
{{ template "breadcrumbs.html" . }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if .Title }}
|
{{ if .Title }}
|
||||||
<div class="f5 lh-title {{ if not .AllowTitleWrap }}nowrap truncate{{ end }}">
|
<div class="f5 lh-title {{ if not .AllowTitleWrap }}nowrap truncate{{ end }}">
|
||||||
{{ with .TypeTitle }}<b class="dn di-ns">{{ . }}:</b>{{ end }}
|
{{ with .TypeTitle }}<b class="dn di-ns">{{ . }}:</b>{{ end }}
|
||||||
<a href="{{ .Url }}">{{ .Title }}</a>
|
<a class="{{ if not .TypeTitle }}b{{ end }}" href="{{ .Url }}">{{ .Title }}</a>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<div class="details link-normal">
|
<div class="details">
|
||||||
<a class="user" href="{{ .OwnerUrl }}">{{ .OwnerName }}</a>
|
<a class="user" href="{{ .OwnerUrl }}">{{ .OwnerName }}</a>
|
||||||
— {{ timehtml (absoluteshortdate .Date) .Date }}
|
— {{ timehtml (absoluteshortdate .Date) .Date }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,10 +80,10 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{ if .Description }}
|
{{ if .Description }}
|
||||||
<div class="mt3 overflow-hidden relative {{ if .TruncateDescription }}maxh-5{{ end }}">
|
<div class="mt3 overflow-hidden relative {{ if .TruncateDescription }}maxh-4{{ end }}">
|
||||||
<div class="post-content">{{ trim .Description }}</div>
|
<div class="post-content">{{ trim .Description }}</div>
|
||||||
{{ if .TruncateDescription }}
|
{{ if .TruncateDescription }}
|
||||||
<div class="excerpt-fade absolute w-100 h4 bottom-0 z-999"></div>
|
<div class="excerpt-fade absolute w-100 h4 bottom-0 z-1"></div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
{{ if .TruncateDescription }}
|
{{ if .TruncateDescription }}
|
||||||
|
|
|
@ -141,6 +141,14 @@
|
||||||
|
|
||||||
<!-- Feed -->
|
<!-- Feed -->
|
||||||
<div class="flex flex-column flex-grow-1 overflow-hidden">
|
<div class="flex flex-column flex-grow-1 overflow-hidden">
|
||||||
|
{{ $latestNews := (index .NewsItems 0) }}
|
||||||
|
<div id="latest_news" class="mb2 bg3 link-normal" data-id="{{ $latestNews.ID }}" {{ if $latestNews.Unread }}data-unread{{ end }}>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<h2 class="pt3 ph3 f4">Latest News</h2>
|
||||||
|
<a class="pt3 ph3" href="#" onclick="closeLatestNews(event)">{{ svg "close" }}</a>
|
||||||
|
</div>
|
||||||
|
{{ template "timeline_item.html" $latestNews }}
|
||||||
|
</div>
|
||||||
<div id="landing-tabs">
|
<div id="landing-tabs">
|
||||||
<div class="bb mb2 flex f6">
|
<div class="bb mb2 flex f6">
|
||||||
{{ if .User }}
|
{{ if .User }}
|
||||||
|
@ -148,7 +156,7 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<div data-tab-button="featured" class="tab-button ph3 pv1 pointer">Featured</div>
|
<div data-tab-button="featured" class="tab-button ph3 pv1 pointer">Featured</div>
|
||||||
<div data-tab-button="recent" class="tab-button ph3 pv1 pointer">Recent</div>
|
<div data-tab-button="recent" class="tab-button ph3 pv1 pointer">Recent</div>
|
||||||
<div data-tab-button="news" class="tab-button ph3 pv1 pointer">News</div>
|
<div data-tab-button="news" class="tab-button ph3 pv1 pointer">News {{ if $latestNews.Unread }}<span class="timeline-unread"></span>{{ end }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{{ if .User }}
|
{{ if .User }}
|
||||||
|
@ -206,6 +214,27 @@
|
||||||
selectTab(tab, { sendEvent: false });
|
selectTab(tab, { sendEvent: false });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Latest news
|
||||||
|
|
||||||
|
const latestNews = document.querySelector("#latest_news");
|
||||||
|
const latestNewsPostID = latestNews.getAttribute("data-id");
|
||||||
|
const latestNewsClosedKey = "latest_news_closed";
|
||||||
|
|
||||||
|
function closeLatestNews(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
localStorage.setItem(latestNewsClosedKey, latestNewsPostID);
|
||||||
|
hideLatestNewsIfClosedOrRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideLatestNewsIfClosedOrRead() {
|
||||||
|
const isUnread = latestNews.hasAttribute("data-unread");
|
||||||
|
const closedID = localStorage.getItem(latestNewsClosedKey);
|
||||||
|
if (!isUnread || closedID === latestNewsPostID) {
|
||||||
|
latestNews.hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hideLatestNewsIfClosedOrRead();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -354,6 +354,8 @@ type TimelineItem struct {
|
||||||
|
|
||||||
Media []TimelineItemMedia
|
Media []TimelineItemMedia
|
||||||
|
|
||||||
|
Unread bool
|
||||||
|
|
||||||
ForumLayout bool
|
ForumLayout bool
|
||||||
AllowTitleWrap bool
|
AllowTitleWrap bool
|
||||||
TruncateDescription bool
|
TruncateDescription bool
|
||||||
|
|
|
@ -99,6 +99,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
item.Description = template.HTML(t.FirstPostCurrentVersion.TextParsed)
|
item.Description = template.HTML(t.FirstPostCurrentVersion.TextParsed)
|
||||||
item.AllowTitleWrap = true
|
item.AllowTitleWrap = true
|
||||||
item.TruncateDescription = true
|
item.TruncateDescription = true
|
||||||
|
item.Unread = t.Unread
|
||||||
newsItems = append(newsItems, item)
|
newsItems = append(newsItems, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,7 @@ func PostToTimelineItem(
|
||||||
ownerTmpl := templates.UserToTemplate(owner)
|
ownerTmpl := templates.UserToTemplate(owner)
|
||||||
|
|
||||||
item := templates.TimelineItem{
|
item := templates.TimelineItem{
|
||||||
|
ID: strconv.Itoa(post.ID),
|
||||||
Date: post.PostDate,
|
Date: post.PostDate,
|
||||||
Title: thread.Title,
|
Title: thread.Title,
|
||||||
Breadcrumbs: GenericThreadBreadcrumbs(urlContext, lineageBuilder, thread),
|
Breadcrumbs: GenericThreadBreadcrumbs(urlContext, lineageBuilder, thread),
|
||||||
|
|
Loading…
Reference in New Issue