commit
						875e6c2cd6
					
				| 
						 | 
				
			
			@ -32,23 +32,25 @@ proc getUrlPrefix*(cfg: Config): string =
 | 
			
		|||
  if cfg.useHttps: https & cfg.hostname
 | 
			
		||||
  else: "http://" & cfg.hostname
 | 
			
		||||
 | 
			
		||||
proc stripHtml*(text: string): string =
 | 
			
		||||
proc shortLink*(text: string; length=28): string =
 | 
			
		||||
  result = text.replace(wwwRegex, "")
 | 
			
		||||
  if result.len > length:
 | 
			
		||||
    result = result[0 ..< length] & "…"
 | 
			
		||||
    
 | 
			
		||||
proc stripHtml*(text: string; shorten=false): string =
 | 
			
		||||
  var html = parseHtml(text)
 | 
			
		||||
  for el in html.findAll("a"):
 | 
			
		||||
    let link = el.attr("href")
 | 
			
		||||
    if "http" in link:
 | 
			
		||||
      if el.len == 0: continue
 | 
			
		||||
      el[0].text = link
 | 
			
		||||
      el[0].text =
 | 
			
		||||
        if shorten: link.shortLink
 | 
			
		||||
        else: link
 | 
			
		||||
  html.innerText()
 | 
			
		||||
 | 
			
		||||
proc sanitizeXml*(text: string): string =
 | 
			
		||||
  text.replace(illegalXmlRegex, "")
 | 
			
		||||
 | 
			
		||||
proc shortLink*(text: string; length=28): string =
 | 
			
		||||
  result = text.replace(wwwRegex, "")
 | 
			
		||||
  if result.len > length:
 | 
			
		||||
    result = result[0 ..< length] & "…"
 | 
			
		||||
 | 
			
		||||
proc replaceUrls*(body: string; prefs: Prefs; absolute=""): string =
 | 
			
		||||
  result = body
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,11 @@
 | 
			
		|||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
import asyncdispatch, strutils, options
 | 
			
		||||
import jester
 | 
			
		||||
import ".."/[types, api], ../views/embed
 | 
			
		||||
import jester, karax/vdom
 | 
			
		||||
import ".."/[types, api]
 | 
			
		||||
import ../views/[embed, tweet, general]
 | 
			
		||||
import router_utils
 | 
			
		||||
 | 
			
		||||
export api, embed
 | 
			
		||||
export api, embed, vdom, tweet, general, router_utils
 | 
			
		||||
 | 
			
		||||
proc createEmbedRouter*(cfg: Config) =
 | 
			
		||||
  router embed:
 | 
			
		||||
| 
						 | 
				
			
			@ -12,4 +14,23 @@ proc createEmbedRouter*(cfg: Config) =
 | 
			
		|||
      if convo == nil or convo.tweet == nil or convo.tweet.video.isNone:
 | 
			
		||||
        resp Http404
 | 
			
		||||
 | 
			
		||||
      resp renderVideoEmbed(cfg, convo.tweet)
 | 
			
		||||
      resp renderVideoEmbed(convo.tweet, cfg, request)
 | 
			
		||||
 | 
			
		||||
    get "/@user/status/@id/embed":
 | 
			
		||||
      let
 | 
			
		||||
        convo = await getTweet(@"id")
 | 
			
		||||
        prefs = cookiePrefs()
 | 
			
		||||
        path = getPath()
 | 
			
		||||
 | 
			
		||||
      if convo == nil or convo.tweet == nil:
 | 
			
		||||
        resp Http404
 | 
			
		||||
 | 
			
		||||
      resp $renderTweetEmbed(convo.tweet, path, prefs, cfg, request)
 | 
			
		||||
 | 
			
		||||
    get "/embed/Tweet.html":
 | 
			
		||||
      let id = @"id"
 | 
			
		||||
 | 
			
		||||
      if id.len > 0:
 | 
			
		||||
        redirect("/i/status/" & id & "/embed")
 | 
			
		||||
      else:
 | 
			
		||||
        resp Http404
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,12 +4,12 @@ from jester import Request, cookies
 | 
			
		|||
 | 
			
		||||
import ../views/general
 | 
			
		||||
import ".."/[utils, prefs, types]
 | 
			
		||||
export utils, prefs, types
 | 
			
		||||
export utils, prefs, types, uri
 | 
			
		||||
 | 
			
		||||
template savePref*(pref, value: string; req: Request; expire=false) =
 | 
			
		||||
  if not expire or pref in cookies(req):
 | 
			
		||||
    setCookie(pref, value, daysForward(when expire: -10 else: 360),
 | 
			
		||||
              httpOnly=true, secure=cfg.useHttps)
 | 
			
		||||
              httpOnly=true, secure=cfg.useHttps, sameSite=None)
 | 
			
		||||
 | 
			
		||||
template cookiePrefs*(): untyped {.dirty.} =
 | 
			
		||||
  getPrefs(cookies(request))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,6 +98,8 @@
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
.avatar {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
 | 
			
		||||
    &.round {
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -110,6 +112,23 @@
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tweet-embed {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
 | 
			
		||||
    .tweet-content { 
 | 
			
		||||
        font-size: 18px 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .tweet-body { 
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        max-height: calc(100vh - 0.75em * 2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.attribution {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    pointer-events: all;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +1,19 @@
 | 
			
		|||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
import options
 | 
			
		||||
import karax/[karaxdsl, vdom]
 | 
			
		||||
from jester import Request
 | 
			
		||||
 | 
			
		||||
import ".."/[types, formatters]
 | 
			
		||||
import general, tweet
 | 
			
		||||
 | 
			
		||||
const doctype = "<!DOCTYPE html>\n"
 | 
			
		||||
 | 
			
		||||
proc renderVideoEmbed*(cfg: Config; tweet: Tweet): string =
 | 
			
		||||
proc renderVideoEmbed*(tweet: Tweet; cfg: Config; req: Request): string =
 | 
			
		||||
  let thumb = get(tweet.video).thumb
 | 
			
		||||
  let vidUrl = getVideoEmbed(cfg, tweet.id)
 | 
			
		||||
  let prefs = Prefs(hlsPlayback: true)
 | 
			
		||||
  let node = buildHtml(html(lang="en")):
 | 
			
		||||
    renderHead(prefs, cfg, video=vidUrl, images=(@[thumb]))
 | 
			
		||||
    renderHead(prefs, cfg, req, video=vidUrl, images=(@[thumb]))
 | 
			
		||||
 | 
			
		||||
    tdiv(class="embed-video"):
 | 
			
		||||
      renderVideo(get(tweet.video), prefs, "")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,9 @@ const
 | 
			
		|||
  doctype = "<!DOCTYPE html>\n"
 | 
			
		||||
  lp = readFile("public/lp.svg")
 | 
			
		||||
 | 
			
		||||
proc toTheme(theme: string): string =
 | 
			
		||||
  theme.toLowerAscii.replace(" ", "_")
 | 
			
		||||
 | 
			
		||||
proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode =
 | 
			
		||||
  var path = req.params.getOrDefault("referer")
 | 
			
		||||
  if path.len == 0:
 | 
			
		||||
| 
						 | 
				
			
			@ -33,9 +36,13 @@ proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode =
 | 
			
		|||
        icon "info", title="About", href="/about"
 | 
			
		||||
        icon "cog", title="Preferences", href=("/settings?referer=" & encodeUrl(path))
 | 
			
		||||
 | 
			
		||||
proc renderHead*(prefs: Prefs; cfg: Config; titleText=""; desc=""; video="";
 | 
			
		||||
                 images: seq[string] = @[]; banner=""; ogTitle=""; theme="";
 | 
			
		||||
proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
 | 
			
		||||
                 video=""; images: seq[string] = @[]; banner=""; ogTitle="";
 | 
			
		||||
                 rss=""; canonical=""): VNode =
 | 
			
		||||
  var theme = prefs.theme.toTheme
 | 
			
		||||
  if "theme" in req.params:
 | 
			
		||||
    theme = req.params["theme"].toTheme
 | 
			
		||||
    
 | 
			
		||||
  let ogType =
 | 
			
		||||
    if video.len > 0: "video"
 | 
			
		||||
    elif rss.len > 0: "object"
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +52,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; titleText=""; desc=""; video="";
 | 
			
		|||
  let opensearchUrl = getUrlPrefix(cfg) & "/opensearch"
 | 
			
		||||
 | 
			
		||||
  buildHtml(head):
 | 
			
		||||
    link(rel="stylesheet", type="text/css", href="/css/style.css?v=10")
 | 
			
		||||
    link(rel="stylesheet", type="text/css", href="/css/style.css?v=12")
 | 
			
		||||
    link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=2")
 | 
			
		||||
 | 
			
		||||
    if theme.len > 0:
 | 
			
		||||
| 
						 | 
				
			
			@ -118,15 +125,12 @@ proc renderHead*(prefs: Prefs; cfg: Config; titleText=""; desc=""; video="";
 | 
			
		|||
proc renderMain*(body: VNode; req: Request; cfg: Config; prefs=defaultPrefs;
 | 
			
		||||
                 titleText=""; desc=""; ogTitle=""; rss=""; video="";
 | 
			
		||||
                 images: seq[string] = @[]; banner=""): string =
 | 
			
		||||
  var theme = toLowerAscii(prefs.theme).replace(" ", "_")
 | 
			
		||||
  if "theme" in req.params:
 | 
			
		||||
    theme = toLowerAscii(req.params["theme"]).replace(" ", "_")
 | 
			
		||||
 | 
			
		||||
  let canonical = getTwitterLink(req.path, req.params)
 | 
			
		||||
 | 
			
		||||
  let node = buildHtml(html(lang="en")):
 | 
			
		||||
    renderHead(prefs, cfg, titleText, desc, video, images, banner, ogTitle,
 | 
			
		||||
               theme, rss, canonical)
 | 
			
		||||
    renderHead(prefs, cfg, req, titleText, desc, video, images, banner, ogTitle,
 | 
			
		||||
               rss, canonical)
 | 
			
		||||
 | 
			
		||||
    body:
 | 
			
		||||
      renderNavbar(cfg, req, rss, canonical)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,11 @@
 | 
			
		|||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
import strutils, sequtils, strformat, options
 | 
			
		||||
import karax/[karaxdsl, vdom, vstyles]
 | 
			
		||||
from jester import Request
 | 
			
		||||
 | 
			
		||||
import renderutils
 | 
			
		||||
import ".."/[types, utils, formatters]
 | 
			
		||||
import general
 | 
			
		||||
 | 
			
		||||
proc getSmallPic(url: string): string =
 | 
			
		||||
  result = url
 | 
			
		||||
| 
						 | 
				
			
			@ -353,3 +355,8 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0;
 | 
			
		|||
      if showThread:
 | 
			
		||||
        a(class="show-thread", href=("/i/status/" & $tweet.threadId)):
 | 
			
		||||
          text "Show this thread"
 | 
			
		||||
 | 
			
		||||
proc renderTweetEmbed*(tweet: Tweet; path: string; prefs: Prefs; cfg: Config; req: Request): VNode =
 | 
			
		||||
  buildHtml(tdiv(class="tweet-embed")):
 | 
			
		||||
    renderHead(prefs, cfg, req)
 | 
			
		||||
    renderTweet(tweet, prefs, path, mainTweet=true)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue