diff --git a/src/formatters.nim b/src/formatters.nim index b251ccf..2ae3077 100644 --- a/src/formatters.nim +++ b/src/formatters.nim @@ -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 diff --git a/src/routes/embed.nim b/src/routes/embed.nim index d9a9ee9..1a93d40 100644 --- a/src/routes/embed.nim +++ b/src/routes/embed.nim @@ -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 diff --git a/src/routes/router_utils.nim b/src/routes/router_utils.nim index 7159890..a071a0d 100644 --- a/src/routes/router_utils.nim +++ b/src/routes/router_utils.nim @@ -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)) diff --git a/src/sass/tweet/_base.scss b/src/sass/tweet/_base.scss index 80a1171..aa87ff1 100644 --- a/src/sass/tweet/_base.scss +++ b/src/sass/tweet/_base.scss @@ -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; diff --git a/src/views/embed.nim b/src/views/embed.nim index 4c2f7b3..e6afffd 100644 --- a/src/views/embed.nim +++ b/src/views/embed.nim @@ -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 = "\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, "") diff --git a/src/views/general.nim b/src/views/general.nim index 4a8b4a3..f909eb0 100644 --- a/src/views/general.nim +++ b/src/views/general.nim @@ -11,6 +11,9 @@ const doctype = "\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) diff --git a/src/views/tweet.nim b/src/views/tweet.nim index 7494685..e8dfc83 100644 --- a/src/views/tweet.nim +++ b/src/views/tweet.nim @@ -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)