html and css updates
This commit is contained in:
		
							parent
							
								
									762d00b21d
								
							
						
					
					
						commit
						2950c0de35
					
				| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,7 @@
 | 
			
		|||
    left: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    background-color: var(--fg_color);
 | 
			
		||||
    background-color: var(--bg_overlays);
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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%;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,24 +82,24 @@
 | 
			
		|||
      <width>128</width>
 | 
			
		||||
      <height>128</height>
 | 
			
		||||
    </image>
 | 
			
		||||
    #if timeline != nil:
 | 
			
		||||
    # if timeline.content.len > 0:
 | 
			
		||||
    ${renderRssTweets(timeline.content, prefs, hostname)}
 | 
			
		||||
    #end if
 | 
			
		||||
  </channel>
 | 
			
		||||
</rss>
 | 
			
		||||
#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 = ""
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
 | 
			
		||||
  <channel>
 | 
			
		||||
    <atom:link href="${link}" rel="self" type="application/rss+xml" />
 | 
			
		||||
    <title>${list} / @${name}</title>
 | 
			
		||||
    <title>${list.name} / @${list.username}</title>
 | 
			
		||||
    <link>${link}</link>
 | 
			
		||||
    <description>Twitter feed for: ${list} by @${name}. Generated by ${hostname}</description>
 | 
			
		||||
    <description>Twitter feed for: ${list.name} by @${list.username}. Generated by ${hostname}</description>
 | 
			
		||||
    <language>en-us</language>
 | 
			
		||||
    <ttl>40</ttl>
 | 
			
		||||
    ${renderRssTweets(tweets, prefs, hostname)}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue