Community Notes support
This commit is contained in:
parent
f5fadca631
commit
1e9d4bae83
6 changed files with 81 additions and 0 deletions
|
@ -466,6 +466,14 @@ proc parseGraphTweet(js: JsonNode; isLegacy=false): Tweet =
|
|||
if result.quote.isSome:
|
||||
result.quote = some(parseGraphTweet(js{"quoted_status_result", "result"}, isLegacy))
|
||||
|
||||
with communityNote, js{"birdwatch_pivot"}:
|
||||
let note = BirdwatchNote(
|
||||
id: communityNote{"note", "rest_id"}.getId,
|
||||
title: communityNote{"title"}.getStr,
|
||||
)
|
||||
note.expandBirdwatchEntities(communityNote{"subtitle"})
|
||||
result.birdwatch = some(note)
|
||||
|
||||
proc parseGraphThread(js: JsonNode): tuple[thread: Chain; self: bool] =
|
||||
for t in js{"content", "items"}:
|
||||
let entryId = t{"entryId"}.getStr
|
||||
|
|
|
@ -319,3 +319,28 @@ proc expandNoteTweetEntities*(tweet: Tweet; js: JsonNode) =
|
|||
tweet.expandTextEntities(entities, text, textSlice)
|
||||
|
||||
tweet.text = tweet.text.multiReplace((unicodeOpen, xmlOpen), (unicodeClose, xmlClose))
|
||||
|
||||
proc expandBirdwatchEntities*(note: BirdwatchNote; js: JsonNode) =
|
||||
let
|
||||
entities = ? js{"entities"}
|
||||
text = js{"text"}.getStr
|
||||
runes = text.toRunes
|
||||
|
||||
var replacements = newSeq[ReplaceSlice]()
|
||||
|
||||
for ent in entities:
|
||||
let
|
||||
# twitter devs in their infinite wisdom making these entities of all others 1 indexed
|
||||
slice = (ent{"fromIndex"}.getInt - 1) .. (ent{"toIndex"}.getInt - 1)
|
||||
refType = ent{"ref", "type"}.getStr
|
||||
|
||||
case refType
|
||||
of "TimelineUrl":
|
||||
let
|
||||
url = ent{"ref", "url"}.getStr
|
||||
display = $runes[slice]
|
||||
|
||||
replacements.add ReplaceSlice(kind: rkUrl, slice: slice, url: url, display: display)
|
||||
|
||||
note.text = runes.replacedWith(replacements, 0 .. runes.len)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
@import 'card';
|
||||
@import 'poll';
|
||||
@import 'quote';
|
||||
@import 'community_note';
|
||||
|
||||
.tweet-body {
|
||||
flex: 1;
|
||||
|
|
30
src/sass/tweet/community_note.scss
Normal file
30
src/sass/tweet/community_note.scss
Normal file
|
@ -0,0 +1,30 @@
|
|||
@import '_variables';
|
||||
|
||||
.community-note {
|
||||
margin-top: 10px;
|
||||
border: solid 1px var(--dark_grey);
|
||||
border-radius: 10px;
|
||||
background-color: var(--bg_elements);
|
||||
overflow: hidden;
|
||||
pointer-events: all;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--grey);
|
||||
}
|
||||
|
||||
.community-note-title {
|
||||
font-weight: bold;
|
||||
background-color: var(--bg_overlays);
|
||||
padding: 6px 8px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.community-note-text {
|
||||
overflow: hidden;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
|
@ -198,6 +198,11 @@ type
|
|||
likes*: int
|
||||
quotes*: int
|
||||
|
||||
BirdwatchNote* = ref object
|
||||
id*: int64
|
||||
title*: string
|
||||
text*: string
|
||||
|
||||
Tweet* = ref object
|
||||
id*: int64
|
||||
threadId*: int64
|
||||
|
@ -223,6 +228,7 @@ type
|
|||
gif*: Option[Gif]
|
||||
video*: Option[Video]
|
||||
photos*: seq[string]
|
||||
birdwatch*: Option[BirdwatchNote]
|
||||
|
||||
Tweets* = seq[Tweet]
|
||||
|
||||
|
|
|
@ -263,6 +263,14 @@ proc renderQuote(quote: Tweet; prefs: Prefs; path: string): VNode =
|
|||
if quote.photos.len > 0 or quote.video.isSome or quote.gif.isSome:
|
||||
renderQuoteMedia(quote, prefs, path)
|
||||
|
||||
proc renderCommunityNote(note: BirdwatchNote; prefs: Prefs): VNode =
|
||||
buildHtml(tdiv(class="community-note")):
|
||||
tdiv(class="community-note-title"):
|
||||
text note.title
|
||||
|
||||
tdiv(class="community-note-text", dir="auto"):
|
||||
verbatim replaceUrls(note.text, prefs)
|
||||
|
||||
proc renderLocation*(tweet: Tweet): string =
|
||||
let (place, url) = tweet.getLocation()
|
||||
if place.len == 0: return
|
||||
|
@ -343,6 +351,9 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0;
|
|||
if tweet.quote.isSome:
|
||||
renderQuote(tweet.quote.get(), prefs, path)
|
||||
|
||||
if mainTweet and tweet.birdwatch.isSome:
|
||||
renderCommunityNote(tweet.birdwatch.get(), prefs)
|
||||
|
||||
if mainTweet:
|
||||
p(class="tweet-published"): text &"{getTime(tweet)}"
|
||||
|
||||
|
|
Loading…
Reference in a new issue