diff --git a/src/sass/profile/card.scss b/src/sass/profile/card.scss
index f775a0b..7c44781 100644
--- a/src/sass/profile/card.scss
+++ b/src/sass/profile/card.scss
@@ -42,7 +42,8 @@
img {
display: block;
- width: calc(100% - 8px);
+ box-sizing: border-box;
+ width: 100%;
height: 100%;
margin: 0;
border: 4px solid var(--darker_grey);
diff --git a/src/sass/profile/photo-rail.scss b/src/sass/profile/photo-rail.scss
index 1cc78d7..ebe2321 100644
--- a/src/sass/profile/photo-rail.scss
+++ b/src/sass/profile/photo-rail.scss
@@ -14,9 +14,10 @@
}
&-header-mobile {
- padding: 5px 12px 0;
display: none;
- width: calc(100% - 24px);
+ box-sizing: border-box;
+ padding: 5px 12px 0;
+ width: 100%;
float: unset;
color: var(--accent);
justify-content: space-between;
diff --git a/src/sass/timeline.scss b/src/sass/timeline.scss
index 02e4423..db19bed 100644
--- a/src/sass/timeline.scss
+++ b/src/sass/timeline.scss
@@ -13,18 +13,28 @@
}
.timeline-header {
+ width: 100%;
background-color: var(--bg_panel);
text-align: center;
padding: 8px;
display: block;
font-weight: bold;
margin-bottom: 5px;
+ box-sizing: border-box;
button {
float: unset;
}
}
+.timeline-banner img {
+ width: 100%;
+}
+
+.timeline-description {
+ font-weight: normal;
+}
+
.tab {
align-items: center;
display: flex;
diff --git a/src/sass/tweet/card.scss b/src/sass/tweet/card.scss
index 680b379..205fecb 100644
--- a/src/sass/tweet/card.scss
+++ b/src/sass/tweet/card.scss
@@ -76,7 +76,7 @@
left: 0;
bottom: 0;
right: 0;
- background-color: var(--fg_color);
+ background-color: var(--bg_overlays);
img {
width: 100%;
diff --git a/src/sass/tweet/media.scss b/src/sass/tweet/media.scss
index f29c717..68a7dbf 100644
--- a/src/sass/tweet/media.scss
+++ b/src/sass/tweet/media.scss
@@ -13,7 +13,7 @@
.still-image {
width: 100%;
- display: block;
+ display: flex;
}
}
@@ -67,17 +67,17 @@
display: inline-block;
}
-.single-image {
- display: inline-block;
- width: 100%;
- max-height: 600px;
+// .single-image {
+// display: inline-block;
+// width: 100%;
+// max-height: 600px;
- .attachments {
- width: unset;
- max-height: unset;
- display: inherit;
- }
-}
+// .attachments {
+// width: unset;
+// max-height: unset;
+// display: inherit;
+// }
+// }
.overlay-circle {
border-radius: 50%;
diff --git a/src/sass/tweet/quote.scss b/src/sass/tweet/quote.scss
index 02e9b56..a4ec146 100644
--- a/src/sass/tweet/quote.scss
+++ b/src/sass/tweet/quote.scss
@@ -5,10 +5,10 @@
border: solid 1px var(--dark_grey);
border-radius: 10px;
background-color: var(--bg_elements);
- overflow: auto;
- padding: 6px;
- position: relative;
+ overflow: hidden;
pointer-events: all;
+ position: relative;
+ width: 100%;
&:hover {
border-color: var(--grey);
@@ -17,91 +17,73 @@
&.unavailable:hover {
border-color: var(--dark_grey);
}
+
+ .tweet-name-row {
+ padding: 6px 6px 0px 6px;
+ }
+
+ .quote-text {
+ overflow: hidden;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ padding: 3px 6px 6px 6px;
+ }
+
+ .show-thread {
+ padding: 0px 6px 3px 6px;
+ margin-top: -3px;
+ }
+
+ .replying-to {
+ padding: 0px 6px;
+ margin: unset;
+ }
}
.unavailable-quote {
- padding: 6px;
+ padding: 12px;
}
.quote-link {
- height: 100%;
width: 100%;
+ height: 100%;
left: 0;
top: 0;
position: absolute;
}
-.quote .quote-link {
- z-index: 1;
-}
-
-.quote-text {
- overflow: hidden;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
.quote-media-container {
+ max-height: 300px;
display: flex;
- flex-direction: column;
- align-items: center;
- overflow: hidden;
- max-height: 102px;
- width: 102px;
- float: left;
- margin-right: 7px;
- border-radius: 7px;
- position: relative;
-}
-.quote-media {
- display: flex;
- justify-content: center;
- pointer-events: none;
+ .card {
+ margin: unset;
+ }
- img {
+ .media-gif {
width: 100%;
- height: 100%;
- align-self: center;
- }
-}
-
-.quote-badge {
- left: 0;
- bottom: 0;
- position: absolute;
- z-index: 1;
- align-self: flex-end;
-}
-
-.quote-badge-text {
- margin: 4px;
- background: $shadow;
- border-radius: 4px;
- color: #fffffff0;
- padding: 1px 3px;
- font-size: 12px;
- font-weight: bold;
-}
-
-.quote-sensitive {
- background: var(--darker_grey);
- width: 102px;
- height: 102px;
- border-radius: 12px;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.quote-sensitive-icon {
- font-size: 40px;
- color: var(--grey);
-}
-
-@media(max-width: 600px) {
- .quote-media-container {
- width: 70px;
- max-height: 70px;
+ }
+
+ .attachments {
+ border-radius: 0;
+ }
+
+ .gallery-gif .attachment {
+ display: flex;
+ justify-content: center;
+ background-color: var(--bg_color);
+
+ video {
+ height: unset;
+ width: unset;
+ }
+ }
+
+ .gallery-video, .gallery-gif {
+ max-height: 300px;
+ }
+
+ .still-image img {
+ max-height: 250px
}
}
diff --git a/src/views/list.nim b/src/views/list.nim
index f66a605..4af3ad7 100644
--- a/src/views/list.nim
+++ b/src/views/list.nim
@@ -2,7 +2,7 @@ import strformat
import karax/[karaxdsl, vdom]
import renderutils
-import ".."/[types]
+import ".."/[types, utils]
proc renderListTabs*(query: Query; path: string): VNode =
buildHtml(ul(class="tab")):
@@ -11,10 +11,18 @@ proc renderListTabs*(query: Query; path: string): VNode =
li(class=query.getTabClass(userList)):
a(href=(path & "/members")): text "Members"
-proc renderList*(body: VNode; query: Query; name, list: string): VNode =
+proc renderList*(body: VNode; query: Query; list: List): VNode =
buildHtml(tdiv(class="timeline-container")):
- tdiv(class="timeline-header"):
- text &"\"{list}\" by @{name}"
+ if list.banner.len > 0:
+ tdiv(class="timeline-banner"):
+ a(href=getPicUrl(list.banner), target="_blank"):
+ genImg(list.banner)
- renderListTabs(query, &"/{name}/lists/{list}")
+ tdiv(class="timeline-header"):
+ text &"\"{list.name}\" by @{list.username}"
+
+ tdiv(class="timeline-description"):
+ text list.description
+
+ renderListTabs(query, &"/{list.username}/lists/{list.name}")
body
diff --git a/src/views/profile.nim b/src/views/profile.nim
index aaf86c8..3e1b260 100644
--- a/src/views/profile.nim
+++ b/src/views/profile.nim
@@ -58,14 +58,15 @@ proc renderProfileCard*(profile: Profile; prefs: Prefs): VNode =
renderStat(profile.likes, "likes")
proc renderPhotoRail(profile: Profile; photoRail: PhotoRail): VNode =
+ let count = insertSep($profile.media, ',')
buildHtml(tdiv(class="photo-rail-card")):
tdiv(class="photo-rail-header"):
a(href=(&"/{profile.username}/media")):
- icon "picture", $profile.media & " Photos and videos"
+ icon "picture", count & " Photos and videos"
input(id="photo-rail-grid-toggle", `type`="checkbox")
label(`for`="photo-rail-grid-toggle", class="photo-rail-header-mobile"):
- icon "picture", $profile.media & " Photos and videos"
+ icon "picture", count & " Photos and videos"
icon "down"
tdiv(class="photo-rail-grid"):
@@ -73,7 +74,7 @@ proc renderPhotoRail(profile: Profile; photoRail: PhotoRail): VNode =
if i == 16: break
a(href=(&"/{profile.username}/status/{photo.tweetId}#m"),
style={backgroundColor: photo.color}):
- genImg(photo.url & ":thumb")
+ genImg(photo.url & (if "format" in photo.url: "" else: ":thumb"))
proc renderBanner(profile: Profile): VNode =
buildHtml():
@@ -89,7 +90,7 @@ proc renderProtected(username: string): VNode =
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;
+proc renderProfile*(profile: Profile; timeline: var Timeline;
photoRail: PhotoRail; prefs: Prefs; path: string): VNode =
timeline.query.fromUser = @[profile.username]
buildHtml(tdiv(class="profile-tabs")):
diff --git a/src/views/renderutils.nim b/src/views/renderutils.nim
index bb16de7..db76cab 100644
--- a/src/views/renderutils.nim
+++ b/src/views/renderutils.nim
@@ -1,7 +1,6 @@
-import strutils, xmltree
+import strutils
import karax/[karaxdsl, vdom, vstyles]
-
-import ../types, ../utils
+import ".."/[types, utils]
proc icon*(icon: string; text=""; title=""; class=""; href=""): VNode =
var c = "icon-" & icon
diff --git a/src/views/rss.nimf b/src/views/rss.nimf
index 50415dc..2ea4bc4 100644
--- a/src/views/rss.nimf
+++ b/src/views/rss.nimf
@@ -82,24 +82,24 @@
128
128
- #if timeline != nil:
+ # if timeline.content.len > 0:
${renderRssTweets(timeline.content, prefs, hostname)}
#end if
#end proc
#
-#proc renderListRss*(tweets: seq[Tweet]; name, list, hostname: string): string =
+#proc renderListRss*(tweets: seq[Tweet]; list: List; hostname: string): string =
#let prefs = Prefs(replaceTwitter: hostname, replaceYouTube: "invidio.us")
-#let link = &"https://{hostname}/{name}/lists/{list}"
+#let link = &"https://{hostname}/{list.username}/lists/{list.name}"
#result = ""
- ${list} / @${name}
+ ${list.name} / @${list.username}
${link}
- Twitter feed for: ${list} by @${name}. Generated by ${hostname}
+ Twitter feed for: ${list.name} by @${list.username}. Generated by ${hostname}
en-us
40
${renderRssTweets(tweets, prefs, hostname)}
diff --git a/src/views/search.nim b/src/views/search.nim
index 774354e..81bc809 100644
--- a/src/views/search.nim
+++ b/src/views/search.nim
@@ -1,8 +1,8 @@
import strutils, strformat, sequtils, unicode, tables
-import karax/[karaxdsl, vdom, vstyles]
+import karax/[karaxdsl, vdom]
import renderutils, timeline
-import ".."/[types, formatters, query]
+import ".."/[types, query]
let toggles = {
"nativeretweets": "Retweets",
@@ -93,13 +93,15 @@ proc renderTweetSearch*(results: Result[Tweet]; prefs: Prefs; path: string): VNo
if query.fromUser.len > 1:
tdiv(class="timeline-header"):
text query.fromUser.join(" | ")
+
+ if query.fromUser.len > 0:
+ renderProfileTabs(query, query.fromUser.join(","))
+
if query.fromUser.len == 0 or query.kind == tweets:
tdiv(class="timeline-header"):
renderSearchPanel(query)
- if query.fromUser.len > 0:
- renderProfileTabs(query, query.fromUser.join(","))
- else:
+ if query.fromUser.len == 0:
renderSearchTabs(query)
renderTimelineTweets(results, prefs, path)
diff --git a/src/views/status.nim b/src/views/status.nim
index 24f116d..aec042f 100644
--- a/src/views/status.nim
+++ b/src/views/status.nim
@@ -1,3 +1,4 @@
+import uri
import karax/[karaxdsl, vdom]
import ".."/[types, formatters]
@@ -13,7 +14,7 @@ proc renderMoreReplies(thread: Chain): VNode =
let reply = if thread.more == 1: "reply" else: "replies"
let link = getLink(thread.content[^1])
buildHtml(tdiv(class="timeline-item more-replies")):
- if link.len > 0:
+ if thread.content[^1].available:
a(class="more-replies-text", href=link):
text $num & "more " & reply
else:
@@ -32,41 +33,45 @@ proc renderReplyThread(thread: Chain; prefs: Prefs; path: string): VNode =
proc renderReplies*(replies: Result[Chain]; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="replies", id="r")):
for thread in replies.content:
- if thread == nil: continue
+ if thread.content.len == 0: continue
renderReplyThread(thread, prefs, path)
- if replies.hasMore:
- renderMore(Query(), replies.minId, focus="#r")
+ if replies.bottom.len > 0:
+ renderMore(Query(), encodeUrl(replies.bottom), focus="#r")
-proc renderConversation*(conversation: Conversation; prefs: Prefs; path: string): VNode =
- let hasAfter = conversation.after != nil
- let showReplies = not prefs.hideReplies
+proc renderConversation*(conv: Conversation; prefs: Prefs; path: string): VNode =
+ let hasAfter = conv.after.content.len > 0
+ let threadId = conv.tweet.threadId
buildHtml(tdiv(class="conversation")):
tdiv(class="main-thread"):
- if conversation.before != nil:
+ if conv.before.content.len > 0:
tdiv(class="before-tweet thread-line"):
- if conversation.before.more == -1:
- renderEarlier(conversation.before)
- for i, tweet in conversation.before.content:
+ let first = conv.before.content[0]
+ if threadId != first.id and (first.replyId > 0 or not first.available):
+ renderEarlier(conv.before)
+ for i, tweet in conv.before.content:
renderTweet(tweet, prefs, path, index=i)
tdiv(class="main-tweet", id="m"):
let afterClass = if hasAfter: "thread thread-line" else: ""
- renderTweet(conversation.tweet, prefs, path, class=afterClass,
- mainTweet=true)
+ renderTweet(conv.tweet, prefs, path, class=afterClass, mainTweet=true)
if hasAfter:
tdiv(class="after-tweet thread-line"):
- let total = conversation.after.content.high
- let more = conversation.after.more
- for i, tweet in conversation.after.content:
- renderTweet(tweet, prefs, path, index=i, last=(i == total and more == 0))
+ let
+ total = conv.after.content.high
+ more = conv.after.more
+ for i, tweet in conv.after.content:
+ renderTweet(tweet, prefs, path, index=i,
+ last=(i == total and more == 0), afterTweet=true)
if more != 0:
- renderMoreReplies(conversation.after)
+ renderMoreReplies(conv.after)
- if conversation.replies != nil and showReplies:
- if not conversation.replies.beginning:
- renderNewer(Query(), getLink(conversation.tweet))
- if conversation.replies.content.len > 0:
- renderReplies(conversation.replies, prefs, path)
+ if not prefs.hideReplies:
+ if not conv.replies.beginning:
+ renderNewer(Query(), getLink(conv.tweet), focus="#r")
+ if conv.replies.content.len > 0 or conv.replies.bottom.len > 0:
+ renderReplies(conv.replies, prefs, path)
+
+ renderToTop(focus="#m")
diff --git a/src/views/timeline.nim b/src/views/timeline.nim
index 58bf339..4457802 100644
--- a/src/views/timeline.nim
+++ b/src/views/timeline.nim
@@ -10,16 +10,22 @@ proc getQuery(query: Query): string =
if result.len > 0:
result &= "&"
-proc renderNewer*(query: Query; path: string): VNode =
- let q = genQueryUrl(query)
- let url = if q.len > 0: "?" & q else: ""
+proc renderToTop*(focus="#"): VNode =
+ buildHtml(tdiv(class="top-ref")):
+ icon "down", href=focus
+
+proc renderNewer*(query: Query; path: string; focus=""): VNode =
+ let
+ q = genQueryUrl(query)
+ url = if q.len > 0: "?" & q else: ""
+ p = if focus.len > 0: path.replace("#m", focus) else: path
buildHtml(tdiv(class="timeline-item show-more")):
- a(href=(path & url)):
+ a(href=(p & url)):
text "Load newest"
-proc renderMore*(query: Query; minId: string; focus=""): VNode =
+proc renderMore*(query: Query; cursor: string; focus=""): VNode =
buildHtml(tdiv(class="show-more")):
- a(href=(&"?{getQuery(query)}max_position={minId}{focus}")):
+ a(href=(&"?{getQuery(query)}cursor={encodeUrl(cursor)}{focus}")):
text "Load more"
proc renderNoMore(): VNode =
@@ -32,10 +38,6 @@ proc renderNoneFound(): VNode =
h2(class="timeline-none"):
text "No items found"
-proc renderToTop(): VNode =
- buildHtml(tdiv(class="top-ref")):
- icon "down", href="#"
-
proc renderThread(thread: seq[Tweet]; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="thread-line")):
let sortedThread = thread.sortedByIt(it.id)
@@ -43,10 +45,16 @@ proc renderThread(thread: seq[Tweet]; prefs: Prefs; path: string): VNode =
let show = i == thread.high and sortedThread[0].id != tweet.threadId
let header = if tweet.pinned or tweet.retweet.isSome: "with-header " else: ""
renderTweet(tweet, prefs, path, class=(header & "thread"),
- index=i, total=thread.high, showThread=show)
+ index=i, last=(i == thread.high), showThread=show)
-proc threadFilter(it: Tweet; thread: int64): bool =
- it.retweet.isNone and it.reply.len == 0 and it.threadId == thread
+proc threadFilter(tweets: openArray[Tweet]; threads: openArray[int64]; it: Tweet): seq[Tweet] =
+ result = @[it]
+ if it.retweet.isSome or it.replyId in threads: return
+ for t in tweets:
+ if t.id == result[0].replyId:
+ result.insert t
+ elif t.replyId == result[0].id:
+ result.add t
proc renderUser(user: Profile; prefs: Prefs): VNode =
buildHtml(tdiv(class="timeline-item")):
@@ -72,8 +80,8 @@ proc renderTimelineUsers*(results: Result[Profile]; prefs: Prefs; path=""): VNod
if results.content.len > 0:
for user in results.content:
renderUser(user, prefs)
- if results.minId != "0":
- renderMore(results.query, results.minId)
+ if results.bottom.len > 0:
+ renderMore(results.query, results.bottom)
renderToTop()
elif results.beginning:
renderNoneFound()
@@ -86,24 +94,31 @@ proc renderTimelineTweets*(results: Result[Tweet]; prefs: Prefs; path: string):
renderNewer(results.query, parseUri(path).path)
if results.content.len == 0:
- renderNoneFound()
+ if not results.beginning:
+ renderNoMore()
+ else:
+ renderNoneFound()
else:
- var threads: seq[int64]
- var retweets: seq[int64]
+ var
+ threads: seq[int64]
+ retweets: seq[int64]
+
for tweet in results.content:
- if tweet.threadId in threads or tweet.id in retweets: continue
- if tweet.pinned and prefs.hidePins: continue
- let thread = results.content.filterIt(threadFilter(it, tweet.threadId))
+ let rt = if tweet.retweet.isSome: get(tweet.retweet).id else: 0
+
+ if tweet.id in threads or rt in retweets or
+ tweet.pinned and prefs.hidePins: continue
+
+ let thread = results.content.threadFilter(threads, tweet)
if thread.len < 2:
- if tweet.retweet.isSome:
- retweets &= tweet.id
- renderTweet(tweet, prefs, path, showThread=tweet.hasThread)
+ var hasThread = tweet.hasThread
+ if rt != 0:
+ retweets &= rt
+ hasThread = get(tweet.retweet).hasThread
+ renderTweet(tweet, prefs, path, showThread=hasThread)
else:
renderThread(thread, prefs, path)
- threads &= tweet.threadId
+ threads &= thread.mapIt(it.id)
- if results.hasMore or results.query.kind != posts:
- renderMore(results.query, results.minId)
- else:
- renderNoMore()
+ renderMore(results.query, results.bottom)
renderToTop()
diff --git a/src/views/tweet.nim b/src/views/tweet.nim
index f1061ed..6edacb0 100644
--- a/src/views/tweet.nim
+++ b/src/views/tweet.nim
@@ -4,11 +4,11 @@ import karax/[karaxdsl, vdom, vstyles]
import renderutils
import ".."/[types, utils, formatters]
-proc renderHeader(tweet: Tweet): VNode =
+proc renderHeader(tweet: Tweet; retweet=""): VNode =
buildHtml(tdiv):
- if tweet.retweet.isSome:
+ if retweet.len > 0:
tdiv(class="retweet-header"):
- span: icon "retweet", get(tweet.retweet).by & " retweeted"
+ span: icon "retweet", retweet & " retweeted"
if tweet.pinned:
tdiv(class="pinned"):
@@ -24,31 +24,24 @@ proc renderHeader(tweet: Tweet): VNode =
linkUser(tweet.profile, class="username")
span(class="tweet-date"):
- a(href=getLink(tweet), title=tweet.getTime()):
- text tweet.shortTime
+ a(href=getLink(tweet), title=tweet.getTime):
+ text tweet.getShortTime
proc renderAlbum(tweet: Tweet): VNode =
let
groups = if tweet.photos.len < 3: @[tweet.photos]
else: tweet.photos.distribute(2)
- if groups.len == 1 and groups[0].len == 1:
- buildHtml(tdiv(class="single-image")):
- tdiv(class="attachments gallery-row"):
- a(href=getPicUrl(groups[0][0] & "?name=orig"), class="still-image",
- target="_blank"):
- genImg(groups[0][0])
- else:
- buildHtml(tdiv(class="attachments")):
- for i, photos in groups:
- let margin = if i > 0: ".25em" else: ""
- let flex = if photos.len > 1 or groups.len > 1: "flex" else: "block"
- tdiv(class="gallery-row", style={marginTop: margin}):
- for photo in photos:
- tdiv(class="attachment image"):
- a(href=getPicUrl(photo & "?name=orig"), class="still-image",
- target="_blank", style={display: flex}):
- genImg(photo)
+ buildHtml(tdiv(class="attachments")):
+ for i, photos in groups:
+ let margin = if i > 0: ".25em" else: ""
+ tdiv(class="gallery-row", style={marginTop: margin}):
+ for photo in photos:
+ tdiv(class="attachment image"):
+ var url = photo
+ if "=orig" notin url: url &= "?name=orig"
+ a(href=getPicUrl(url), class="still-image", target="_blank"):
+ genImg(photo)
proc isPlaybackEnabled(prefs: Prefs; video: Video): bool =
case video.playbackType
@@ -88,7 +81,8 @@ proc renderVideo*(video: Video; prefs: Prefs; path: string): VNode =
elif not prefs.isPlaybackEnabled(video):
renderVideoDisabled(video, path)
else:
- let source = getVidUrl(video.url)
+ let vid = video.variants.filterIt(it.videoType == video.playbackType)
+ let source = getVidUrl(vid[0].url)
case video.playbackType
of mp4:
if prefs.muteVideos:
@@ -138,7 +132,7 @@ proc renderPoll(poll: Poll): VNode =
proc renderCardImage(card: Card): VNode =
buildHtml(tdiv(class="card-image-container")):
tdiv(class="card-image"):
- img(src=getPicUrl(get(card.image)))
+ img(src=getPicUrl(card.image), alt="")
if card.kind == player:
tdiv(class="card-overlay"):
tdiv(class="overlay-circle"):
@@ -151,9 +145,8 @@ proc renderCardContent(card: Card): VNode =
span(class="card-destination"): text card.dest
proc renderCard(card: Card; prefs: Prefs; path: string): VNode =
- const largeCards = {summaryLarge, liveEvent, promoWebsite,
- promoVideo, promoVideoConvo}
- let large = if card.kind in largeCards: " large" else: ""
+ const smallCards = {player, summary}
+ let large = if card.kind notin smallCards: " large" else: ""
let url = replaceUrl(card.url, prefs)
buildHtml(tdiv(class=("card" & large))):
@@ -164,7 +157,7 @@ proc renderCard(card: Card; prefs: Prefs; path: string): VNode =
renderCardContent(card)
else:
a(class="card-container", href=url):
- if card.image.isSome:
+ if card.image.len > 0:
renderCardImage(card)
tdiv(class="card-content-container"):
renderCardContent(card)
@@ -184,13 +177,6 @@ proc renderReply(tweet: Tweet): VNode =
if i > 0: text " "
a(href=("/" & u)): text "@" & u
-proc renderReply(quote: Quote): VNode =
- buildHtml(tdiv(class="replying-to")):
- text "Replying to "
- for i, u in quote.reply:
- if i > 0: text " "
- a(href=("/" & u)): text "@" & u
-
proc renderAttribution(profile: Profile): VNode =
let avatarUrl = getPicUrl(profile.getUserpic("_200x200"))
buildHtml(a(class="attribution", href=("/" & profile.username))):
@@ -206,19 +192,17 @@ proc renderMediaTags(tags: seq[Profile]): VNode =
if i < tags.high:
text ", "
-proc renderQuoteMedia(quote: Quote): VNode =
+proc renderQuoteMedia(quote: Tweet; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="quote-media-container")):
- if quote.thumb.len > 0:
- tdiv(class="quote-media"):
- genImg(quote.thumb)
- if quote.badge.len > 0:
- tdiv(class="quote-badge"):
- tdiv(class="quote-badge-text"): text quote.badge
- elif quote.sensitive:
- tdiv(class="quote-sensitive"):
- icon "attention", class="quote-sensitive-icon"
+ if quote.photos.len > 0:
+ renderAlbum(quote)
+ # genImg(quote.photos[0])
+ elif quote.video.isSome:
+ renderVideo(quote.video.get(), prefs, path)
+ elif quote.gif.isSome:
+ renderGif(quote.gif.get(), prefs)
-proc renderQuote(quote: Quote; prefs: Prefs): VNode =
+proc renderQuote(quote: Tweet; prefs: Prefs; path: string): VNode =
if not quote.available:
return buildHtml(tdiv(class="quote unavailable")):
tdiv(class="unavailable-quote"):
@@ -227,26 +211,32 @@ proc renderQuote(quote: Quote; prefs: Prefs): VNode =
else:
text "This tweet is unavailable"
- buildHtml(tdiv(class="quote")):
+ buildHtml(tdiv(class="quote quote-big")):
a(class="quote-link", href=getLink(quote))
- if quote.thumb.len > 0 or quote.sensitive:
- renderQuoteMedia(quote)
+ tdiv(class="tweet-name-row"):
+ tdiv(class="fullname-and-username"):
+ linkUser(quote.profile, class="fullname")
+ linkUser(quote.profile, class="username")
- tdiv(class="fullname-and-username"):
- linkUser(quote.profile, class="fullname")
- linkUser(quote.profile, class="username")
+ span(class="tweet-date"):
+ a(href=getLink(quote), title=quote.getTime):
+ text quote.getShortTime
if quote.reply.len > 0:
renderReply(quote)
- tdiv(class="quote-text"):
- verbatim replaceUrl(quote.text, prefs)
+ if quote.text.len > 0:
+ tdiv(class="quote-text"):
+ verbatim replaceUrl(quote.text, prefs)
if quote.hasThread:
a(class="show-thread", href=getLink(quote)):
text "Show this thread"
+ if quote.photos.len > 0 or quote.video.isSome or quote.gif.isSome:
+ renderQuoteMedia(quote, prefs, path)
+
proc renderLocation*(tweet: Tweet): string =
let (place, url) = tweet.getLocation()
if place.len == 0: return
@@ -258,11 +248,10 @@ proc renderLocation*(tweet: Tweet): string =
text place
return $node
-proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
- index=0; total=(-1); last=false; showThread=false;
- mainTweet=false): VNode =
+proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0;
+ last=false; showThread=false; mainTweet=false; afterTweet=false): VNode =
var divClass = class
- if index == total or last:
+ if index == -1 or last:
divClass = "thread-last " & class
if not tweet.available:
@@ -273,15 +262,22 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
else:
text "This tweet is unavailable"
+ let fullTweet = tweet
+ var retweet: string
+ var tweet = fullTweet
+ if tweet.retweet.isSome:
+ tweet = tweet.retweet.get
+ retweet = fullTweet.profile.fullname
+
buildHtml(tdiv(class=("timeline-item " & divClass))):
if not mainTweet:
a(class="tweet-link", href=getLink(tweet))
tdiv(class="tweet-body"):
var views = ""
- renderHeader(tweet)
+ renderHeader(tweet, retweet)
- if index == 0 and tweet.reply.len > 0 and
+ if not afterTweet and index == 0 and tweet.reply.len > 0 and
(tweet.reply.len > 1 or tweet.reply[0] != tweet.profile.username):
renderReply(tweet)
@@ -293,7 +289,8 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
if tweet.card.isSome:
renderCard(tweet.card.get(), prefs, path)
- elif tweet.photos.len > 0:
+
+ if tweet.photos.len > 0:
renderAlbum(tweet)
elif tweet.video.isSome:
renderVideo(tweet.video.get(), prefs, path)
@@ -301,11 +298,12 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class="";
elif tweet.gif.isSome:
renderGif(tweet.gif.get(), prefs)
views = "GIF"
- elif tweet.poll.isSome:
+
+ if tweet.poll.isSome:
renderPoll(tweet.poll.get())
if tweet.quote.isSome:
- renderQuote(tweet.quote.get(), prefs)
+ renderQuote(tweet.quote.get(), prefs, path)
if mainTweet:
p(class="tweet-published"): text getTweetTime(tweet)