Initial commit

This commit is contained in:
Zed
2019-06-20 16:16:20 +02:00
commit cea5cc0523
14 changed files with 1370 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
#? stdtmpl(subsChar = '$', metaChar = '#')
#import xmltree, strutils, uri
#import ../types, ../formatters, ./tweet
#
#proc renderConversation*(conversation: Conversation): string =
<div class="conversation" id="tweets">
<div class="main-thread">
#if conversation.before.len > 0:
<div class="before-tweet">
#for tweet in conversation.before:
${renderTweet(tweet)}
#end for
</div>
#end if
<div class="main-tweet">
${renderTweet(conversation.tweet)}
</div>
#if conversation.after.len > 0:
<div class="after-tweet">
#for tweet in conversation.after:
${renderTweet(tweet)}
#end for
</div>
#end if
</div>
#if conversation.replies.len > 0:
<div class="replies">
#for thread in conversation.replies:
<div class="thread">
#for tweet in thread:
${renderTweet(tweet)}
#end for
</div>
#end for
</div>
#end if
</div>
#end proc

50
src/views/general.nim Normal file
View File

@@ -0,0 +1,50 @@
#? stdtmpl(subsChar = '$', metaChar = '#')
#import user
#import xmltree
#
#proc renderMain*(body: string): string =
<!DOCTYPE html>
<html>
<head>
<title>Nitter</title>
<link rel="stylesheet" type="text/css" href="/style.css">
</head>
<body>
<nav id="nav" class="nav-bar container">
<div class="inner-nav">
<div class="item">
<a href="/" class="site-name">twatter</a>
</div>
</div>
</nav>
<div id="content" class="container">
${body}
</div>
</body>
</html>
#end proc
#
#proc renderSearchPanel*(): string =
<div class="panel">
<div class="search-panel">
<form action="search" method="post">
<input type="text" name="query" placeholder="Enter username...">
<button type="submit" name="button">🔎</button>
</form>
</div>
</div>
#end proc
#
#proc renderError*(error: string): string =
<div class="panel">
<div class="error-panel">
<span>${error}</span>
</div>
</div>
#end proc
#
#proc showError*(error: string): string =
${renderMain(renderError(error))}
#end proc

99
src/views/tweet.nim Normal file
View File

@@ -0,0 +1,99 @@
#? stdtmpl(subsChar = '$', metaChar = '#')
#import xmltree, strutils, times, sequtils, uri
#import ../types, ../formatters, ../utils
#
#proc renderHeading(tweet: Tweet): string =
#if tweet.retweetBy != "":
<div class="retweet">
<span>🔄 ${tweet.retweetBy} 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">
<img class="avatar" src=${tweet.profile.getUserpic("_bigger").getSigUrl("pic")}>
<div class="name-and-account-name">
${linkUser(tweet.profile, "h4", class="username", username=false)}
${linkUser(tweet.profile, "", class="account-name")}
</div>
<span class="heading-right">
<a href="${tweet.link}" class="timeago faint-link">
<time title="${tweet.time.format("d/M/yyyy', ' HH:mm:ss")}">${tweet.shortTime}</time>
</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 groupStyle = if groups.len == 1 and groups[0].len < 2: "" else: "background-color: #0f0f0f;"
#var first = true
<div class="attachments media-body" style="${groupStyle}">
#for photos in groups:
#let style = if first: "" else: "margin-top: .25em;"
<div class="gallery-row cover-fit" style="${style}">
#for photo in photos:
<div class="attachment image">
##TODO: why doesn't this work?
<a href=${getSigUrl(photo & ":large", "pic")} target="_blank" class="image-attachment">
#let style = if photos.len > 1 or groups.len > 1: "display: flex;" else: ""
#let istyle = if photos.len > 1 or groups.len > 1: "" else: "border-radius: 7px;"
<div class="still-image" style="${style}">
<img src=${getSigUrl(photo, "pic")} referrerpolicy="" style="${istyle}">
</div>
</a>
</div>
#end for
</div>
#first = false
#end for
</div>
#end proc
#
#proc renderGif(tweet: Tweet): string =
#let thumbUrl = getGifThumb(tweet).getSigUrl("pic")
#let videoUrl = getGifSrc(tweet).getSigUrl("video")
<div class="attachments media-body">
<div class="gallery-row" style="max-height: unset;">
<div class="attachment image">
<video poster=${thumbUrl} style="width: 100%; height: 100%;" autoplay muted loop>
<source src=${videoUrl} type="video/mp4">
</video>
</div>
</div>
</div>
#end proc
#
#proc renderStats(tweet: Tweet): string =
<div class="tweet-stats">
<span class="tweet-stat">💬 ${$tweet.replies}</span>
<span class="tweet-stat">🔄 ${$tweet.retweets}</span>
<span class="tweet-stat">👍 ${$tweet.likes}</span>
</div>
#end proc
#
#proc renderTweet*(tweet: Tweet; class=""): string =
<div class="${class}">
<div class="status-el">
<div class="status-body">
${renderHeading(tweet)}
<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.gif.len > 0:
${renderGif(tweet)}
#end if
${renderStats(tweet)}
</div>
</div>
</div>
#end proc

100
src/views/user.nim Normal file
View File

@@ -0,0 +1,100 @@
#? stdtmpl(subsChar = '$', metaChar = '#')
#import xmltree, strutils, uri, htmlgen
#import ../types, ../formatters, ../utils
#import ./tweet
#
#proc renderProfileCard*(profile: Profile): string =
#let pic = profile.getUserpic().getSigUrl("pic")
#let smallPic = profile.getUserpic("_200x200").getSigUrl("pic")
<div class="profile-card">
<a class="profile-card-avatar" href="${pic}">
<img src="${smallPic}">
</a>
<div class="profile-card-tabs">
<div class="profile-card-tabs-name">
${linkUser(profile, "h1", class="profile-card-name", username=false)}
${linkUser(profile, "h2", class="profile-card-username")}
</div>
</div>
<div class="profile-card-extra">
<div class="profile-bio">
#if profile.description.len > 0:
<div class="profile-description">
<p>${linkifyText(xmltree.escape(profile.description))}</p>
</div>
#end if
</div>
<div class="profile-card-extra-links">
<ul class="profile-statlist">
<li class="tweets">
<span class="profile-stat-header">Tweets</span>
<span>${$profile.tweets}</span>
</li>
<li class="followers">
<span class="profile-stat-header">Followers</span>
<span>${$profile.followers}</span>
</li>
<li class="following">
<span class="profile-stat-header">Following</span>
<span>${$profile.following}</span>
</li>
</ul>
</div>
</div>
</div>
#end proc
#
#proc renderBanner(profile: Profile): string =
#if "#" in profile.banner:
<div style="${profile.banner}" class="profile-banner-color"></div>
#else:
#let url = getSigUrl(profile.banner, "pic")
<a href="${url}">
<img src="${url}">
</a>
#end if
#end proc
#
#proc renderTimeline*(tweets: Tweets; profile: Profile; beginning: bool): string =
<div id="tweets">
#if profile.protected:
<div class="timeline-protected">
<h2 class="timeline-protected-header">This account's Tweets are protected.</h2>
<p class="timeline-protected-explanation">Only confirmed followers have access to @${profile.username}'s Tweets.
</div>
#end if
#if not beginning:
<div class="show-more status-el">
<a href="/${profile.username}">Load newest tweets</a>
</div>
#end if
#var retweets: Tweets
#for tweet in tweets:
#if tweet in retweets: continue
#end if
#if tweet.retweetBy.len > 0: retweets.add tweet
#end if
${renderTweet(tweet, "timeline-tweet")}
#end for
#if tweets.len > 0:
<div class="show-more">
<a href="/${profile.username}?after=${$tweets[^1].id}">Load older tweets</a>
</div>
#end if
</div>
#end proc
#
#proc renderProfile*(profile: Profile; tweets: Tweets; beginning: bool): string =
<div class="profile-tabs">
<div class="profile-banner">
${renderBanner(profile)}
</div>
<div class="profile-tab">
${renderProfileCard(profile)}
</div>
<div class="timeline-tab">
${renderTimeline(tweets, profile, beginning)}
</div>
</div>
#end proc