nitter/src/views/tweet.nimf

199 lines
5.9 KiB
Plaintext

#? stdtmpl(subsChar = '$', metaChar = '#')
#import xmltree, strutils, strformat, sequtils, times, uri
#import ../types, ../formatters, ../utils
#
#proc renderHeading(tweet: Tweet): string =
#if tweet.retweet.isSome:
<div class="retweet">
<span>🔄 ${get(tweet.retweet).by} retweeted</span>
</div>
#end if
#if tweet.pinned:
<div class="pinned">
<span>📌 Pinned Tweet</span>
</div>
#end if
<div class="media-heading">
<div class="heading-name-row">
<a class="tweet-avatar" href="/${tweet.profile.username}">
${genImg(tweet.profile.getUserpic("_bigger"), "avatar")}
</a>
<div class="fullname-and-username">
${linkUser(tweet.profile, class="fullname")}
${linkUser(tweet.profile, class="username")}
</div>
<span class="heading-right">
<a href="${getLink(tweet)}" title="${tweet.getTime()}">${tweet.shortTime}</a>
</span>
</div>
</div>
#end proc
#
#proc renderMediaGroup(tweet: Tweet): string =
#let groups = if tweet.photos.len > 2: tweet.photos.distribute(2) else: @[tweet.photos]
#let class = if groups.len == 1 and groups[0].len == 1: "single-image" else: ""
#var first = true
<div class="attachments ${class}">
#for photos in groups:
#let margin = if not first: "margin-top: .25em;" else: ""
#let flex = if photos.len > 1 or groups.len > 1: "display: flex;" else: ""
<div class="gallery-row cover-fit" style="${margin}">
#for photo in photos:
<div class="attachment image">
##TODO: why doesn't this work?
<a href=${getSigUrl(photo & "?name=orig", "pic")} target="_blank" class="image-attachment">
<div class="still-image" style="${flex}">
${genImg(photo)}
</div>
</a>
</div>
#end for
</div>
#first = false
#end for
</div>
#end proc
#
#proc renderVideo(video: Video): string =
<div class="attachments">
<div class="gallery-video">
<div class="attachment video-container">
#case video.playbackType
#of mp4:
<video poster=${video.thumb.getSigUrl("pic")} controls>
<source src=${video.url.getSigUrl("video")} type="video/mp4">
</video>
#of m3u8, vmap:
<video poster=${video.thumb.getSigUrl("pic")} autoplay muted loop></video>
<div class="video-overlay">
<p>Video playback not supported</p>
</div>
#end case
</div>
</div>
</div>
#end proc
#
#proc renderGif(gif: Gif): string =
<div class="attachments media-gif">
<div class="gallery-gif" style="max-height: unset;">
<div class="attachment">
<video class="gif" poster=${gif.thumb.getSigUrl("pic")} autoplay muted loop>
<source src=${gif.url.getSigUrl("video")} type="video/mp4">
</video>
</div>
</div>
</div>
#end proc
#
#proc renderPoll(poll: Poll): string =
<div class="poll">
#for i in 0 ..< poll.options.len:
#let leader = if poll.leader == i: " leader" else: ""
<div class="poll-meter${leader}">
<span class="poll-choice-bar" style="width: ${poll.values[i]}%"></span>
<span class="poll-choice-value">${poll.values[i]}%</span>
<span class="poll-choice-option">${poll.options[i]}</span>
</div>
#end for
<span class="poll-info">${poll.votes} votes • ${poll.status}</span>
</div>
#end proc
#
#proc renderStats(stats: TweetStats): string =
<div class="tweet-stats">
<span class="tweet-stat">💬 ${$stats.replies}</span>
<span class="tweet-stat">🔄 ${$stats.retweets}</span>
<span class="tweet-stat">👍 ${$stats.likes}</span>
</div>
#end proc
#
#proc renderShowThread(tweet: Tweet | Quote): string =
<a href="${getLink(tweet)}">Show this thread</a>
#end proc
#
#proc renderReply(tweet: Tweet | Quote): string =
#let usernames = tweet.reply.mapIt(&"""<a href="/{it}">@{it}</a>""")
<div class="replying-to">Replying to ${usernames.join(" ")}</div>
#end proc
#
#proc renderQuote(quote: Quote): string =
#let hasMedia = quote.thumb.len > 0 or quote.sensitive
<div class="quote">
<div class="quote-container">
<a class="quote-link" href="${getLink(quote)}"></a>
#if hasMedia:
<div class="quote-media-container">
<div class="quote-media">
#if quote.thumb.len > 0:
${genImg(quote.thumb)}
#if quote.badge.len > 0:
<div class="quote-badge">
<div class="quote-badge-text">${quote.badge}</div>
</div>
#end if
#elif quote.sensitive:
<div class="quote-sensitive">
<span class="icon quote-sensitive-icon">❗</span>
</div>
#end if
</div>
</div>
#end if
<div class="fullname-and-username">
${linkUser(quote.profile, class="fullname")}
${linkUser(quote.profile, class="username")}
</div>
#if quote.reply.len > 0:
${renderReply(quote)}
#end if
<div class="quote-text">${linkifyText(quote.text)}</div>
#if quote.hasThread:
${renderShowThread(quote)}
#end if
</div>
</div>
#end proc
#
#proc renderTweet*(tweet: Tweet; class=""; first=true; last=false): string =
#var divClass = if last: "thread-last " & class else: class
#if divClass.len > 0:
<div class="${divClass}">
#end if
#if tweet.available:
<div class="status-el">
<div class="status-body">
${renderHeading(tweet)}
#if first and tweet.reply.len > 0:
${renderReply(tweet)}
#end if
<div class="status-content-wrapper">
<div class="status-content media-body">${linkifyText(tweet.text)}</div>
</div>
#if tweet.photos.len > 0:
${renderMediaGroup(tweet)}
#elif tweet.video.isSome:
${renderVideo(tweet.video.get())}
#elif tweet.gif.isSome:
${renderGif(tweet.gif.get())}
#elif tweet.quote.isSome:
${renderQuote(tweet.quote.get())}
#elif tweet.poll.isSome:
${renderPoll(tweet.poll.get())}
#end if
${renderStats(tweet.stats)}
#if tweet.hasThread and "timeline" in class:
${renderShowThread(tweet)}
#end if
</div>
</div>
#else:
<div class="status-el unavailable">
<div class="unavailable-box">This tweet is unavailable</div>
</div>
#end if
#if divClass.len > 0:
</div>
#end if
#end proc