Refactor tweet/timeline views

This commit is contained in:
Zed 2019-09-13 19:57:27 +02:00
parent a687188dd1
commit eeae28da0c
8 changed files with 107 additions and 136 deletions

View file

@ -47,7 +47,7 @@
.profile-tabs {
width: 100vw;
.timeline-tab {
.timeline-container {
width: 100% !important;
}
}

View file

@ -1,30 +1,19 @@
@import '_variables';
#posts {
.timeline-container {
@include panel(100%, 600px);
}
.timeline {
background-color: $bg_panel;
> div:not(:last-child) {
border-bottom: 1px solid $border_grey;
}
.timeline-tab {
float: right;
padding: 0;
box-sizing: border-box;
display: inline-block;
font-size: 14px;
text-align: left;
vertical-align: top;
}
.multi-timeline {
max-width: 600px;
width: 100%;
margin: 0 auto;
.timeline-tab {
width: 100%;
}
}
.multi-header {
.timeline-header {
background-color: $bg_panel;
text-align: center;
padding: 10px;
@ -72,10 +61,6 @@
}
}
.timeline-tweet {
border-bottom: 1px solid $border_grey;
}
.timeline-footer {
background-color: $bg_panel;
padding: 6px 0;
@ -119,11 +104,7 @@
background-color: $bg_panel;
text-align: center;
padding: .75em 0;
display: block;
&.status-el {
border-bottom: 1px solid $border_grey;
}
display: block !important;
a {
background-color: $darkest_grey;
@ -137,3 +118,11 @@
}
}
}
.timeline-item {
overflow-wrap: break-word;
border-left-width: 0;
min-width: 0;
padding: .75em;
display: flex;
}

View file

@ -7,25 +7,17 @@
@import 'poll';
@import 'quote';
.status-el {
overflow-wrap: break-word;
border-left-width: 0;
min-width: 0;
padding: .75em;
display: flex;
.status-content {
font-family: $font_3;
line-height: 1.4em;
}
}
.status-body {
.tweet-body {
flex: 1;
min-width: 0;
margin-left: 58px;
}
.tweet-content {
font-family: $font_3;
line-height: 1.4em;
}
.tweet-header {
padding: 0;
vertical-align: bottom;
@ -79,7 +71,6 @@
float: left;
margin-top: 3px;
margin-left: -58px;
position: absolute;
width: 48px;
height: 48px;
border-radius: 50%;

View file

@ -10,7 +10,7 @@
background-color: $bg_panel;
}
.main-tweet .status-content {
.main-tweet .tweet-content {
font-size: 20px;
}
@ -20,7 +20,7 @@
}
.thread-line {
.status-el::before {
.timeline-item::before {
background: $accent_dark;
content: '';
position: relative;
@ -53,7 +53,7 @@
}
}
.thread-last .status-el::before {
.timeline-item.thread-last::before {
background: unset;
min-width: unset;
width: 0;

View file

@ -75,6 +75,12 @@ proc renderBanner(profile: Profile): VNode =
a(href=getPicUrl(profile.banner), target="_blank"):
genImg(profile.banner)
proc renderProtected(username: string): VNode =
buildHtml(tdiv(class="timeline-container timeline")):
tdiv(class="timeline-header timeline-protected"):
h2: text "This account's tweets are protected."
p: text &"Only confirmed followers have access to @{username}'s tweets."
proc renderProfile*(profile: Profile; timeline: Timeline;
photoRail: seq[GalleryPhoto]; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="profile-tabs")):
@ -88,11 +94,9 @@ proc renderProfile*(profile: Profile; timeline: Timeline;
if photoRail.len > 0:
renderPhotoRail(profile, photoRail)
tdiv(class="timeline-tab"):
renderTimeline(timeline, profile.username, profile.protected, prefs, path)
proc renderMulti*(timeline: Timeline; usernames: string;
prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="multi-timeline")):
tdiv(class="timeline-tab"):
renderTimeline(timeline, usernames, false, prefs, path, multi=true)
tdiv(class="timeline-container"):
if profile.protected:
renderProtected(profile.username)
else:
renderProfileTabs(timeline, profile.username)
renderTimelineTweets(timeline, prefs, path)

View file

@ -6,7 +6,7 @@ import tweet
proc renderMoreReplies(thread: Thread): VNode =
let num = if thread.more != -1: $thread.more & " " else: ""
let reply = if thread.more == 1: "reply" else: "replies"
buildHtml(tdiv(class="status-el more-replies")):
buildHtml(tdiv(class="timeline-item more-replies")):
a(class="more-replies-text", title="Not implemented yet"):
text $num & "more " & reply

View file

@ -1,25 +1,29 @@
import strutils, strformat, sequtils, algorithm, times
import karax/[karaxdsl, vdom, vstyles]
import ../types, ../search
import ".."/[types, query, formatters]
import tweet, renderutils
proc getQuery(timeline: Timeline): string =
if timeline.query.isNone: "?"
else: genQueryUrl(get(timeline.query))
proc getQuery(query: Option[Query]): string =
if query.isNone:
result = "?"
else:
result = genQueryUrl(get(query))
if result[^1] != '?':
result &= "&"
proc getTabClass(timeline: Timeline; tab: string): string =
proc getTabClass(results: Result; tab: string): string =
var classes = @["tab-item"]
if timeline.query.isNone or get(timeline.query).kind == multi:
if results.query.isNone or get(results.query).kind == multi:
if tab == "posts":
classes.add "active"
elif $get(timeline.query).kind == tab:
elif $get(results.query).kind == tab:
classes.add "active"
return classes.join(" ")
proc renderSearchTabs(timeline: Timeline; username: string): VNode =
proc renderProfileTabs*(timeline: Timeline; username: string): VNode =
let link = "/" & username
buildHtml(ul(class="tab")):
li(class=timeline.getTabClass("posts")):
@ -29,33 +33,28 @@ proc renderSearchTabs(timeline: Timeline; username: string): VNode =
li(class=timeline.getTabClass("media")):
a(href=(link & "/media")): text "Media"
proc renderNewer(timeline: Timeline; username: string): VNode =
buildHtml(tdiv(class="status-el show-more")):
a(href=("/" & username & getQuery(timeline).strip(chars={'?'}))):
text "Load newest tweets"
proc renderNewer(query: Option[Query]): VNode =
buildHtml(tdiv(class="timeline-item show-more")):
a(href=(getQuery(query).strip(chars={'?', '&'}))):
text "Load newest"
proc renderOlder(timeline: Timeline; username: string): VNode =
proc renderOlder(query: Option[Query]; minId: string): VNode =
buildHtml(tdiv(class="show-more")):
a(href=(&"/{username}{getQuery(timeline)}after={timeline.minId}")):
text "Load older tweets"
a(href=(&"{getQuery(query)}after={minId}")):
text "Load older"
proc renderNoMore(): VNode =
buildHtml(tdiv(class="timeline-footer")):
h2(class="timeline-end"):
text "No more tweets."
text "No more items"
proc renderNoneFound(): VNode =
buildHtml(tdiv(class="timeline-header")):
h2(class="timeline-none"):
text "No tweets found."
proc renderProtected(username: string): VNode =
buildHtml(tdiv(class="timeline-header timeline-protected")):
h2: text "This account's tweets are protected."
p: text &"Only confirmed followers have access to @{username}'s tweets."
text "No items found"
proc renderThread(thread: seq[Tweet]; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="timeline-tweet thread-line")):
buildHtml(tdiv(class="thread-line")):
for i, threadTweet in thread.sortedByIt(it.time):
renderTweet(threadTweet, prefs, path, class="thread",
index=i, total=thread.high)
@ -63,37 +62,26 @@ proc renderThread(thread: seq[Tweet]; prefs: Prefs; path: string): VNode =
proc threadFilter(it: Tweet; tweetThread: string): bool =
it.retweet.isNone and it.reply.len == 0 and it.threadId == tweetThread
proc renderTweets(timeline: Timeline; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(id="posts")):
proc renderTimelineTweets*(results: Result[Tweet]; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="timeline")):
if not results.beginning:
renderNewer(results.query)
if results.content.len == 0:
renderNoneFound()
else:
var threads: seq[string]
for tweet in timeline.content:
for tweet in results.content:
if tweet.threadId in threads: continue
let thread = timeline.content.filterIt(threadFilter(it, tweet.threadId))
let thread = results.content.filterIt(threadFilter(it, tweet.threadId))
if thread.len < 2:
renderTweet(tweet, prefs, path, class="timeline-tweet")
renderTweet(tweet, prefs, path)
else:
renderThread(thread, prefs, path)
threads &= tweet.threadId
proc renderTimeline*(timeline: Timeline; username: string; protected: bool;
prefs: Prefs; path: string; multi=false): VNode =
buildHtml(tdiv):
if multi:
tdiv(class="multi-header"):
text username.replace(",", " | ")
if not protected:
renderSearchTabs(timeline, username)
if not timeline.beginning:
renderNewer(timeline, username)
if protected:
renderProtected(username)
elif timeline.content.len == 0:
renderNoneFound()
else:
renderTweets(timeline, prefs, path)
if timeline.hasMore or timeline.query.isSome:
renderOlder(timeline, username)
if results.hasMore or results.query.isSome:
renderOlder(results.query, results.minId)
else:
renderNoMore()

View file

@ -224,23 +224,22 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
if not tweet.available:
return buildHtml(tdiv(class=divClass)):
tdiv(class="status-el unavailable"):
tdiv(class="timeline-item unavailable"):
tdiv(class="unavailable-box"):
if tweet.tombstone.len > 0:
text tweet.tombstone
else:
text "This tweet is unavailable"
buildHtml(tdiv(class=divClass)):
tdiv(class="status-el"):
tdiv(class="status-body"):
buildHtml(tdiv(class=("timeline-item " & divClass))):
tdiv(class="tweet-body"):
var views = ""
renderHeader(tweet)
if index == 0 and tweet.reply.len > 0:
renderReply(tweet)
tdiv(class="status-content media-body"):
tdiv(class="tweet-content media-body"):
verbatim linkifyText(tweet.text, prefs)
if tweet.quote.isSome: