timeline.nim 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import strutils, strformat, algorithm, times
  2. import karax/[karaxdsl, vdom, vstyles]
  3. import ../types, ../search
  4. import tweet, renderutils
  5. proc getQuery(timeline: Timeline): string =
  6. if timeline.query.isNone: "?"
  7. else: genQueryUrl(get(timeline.query))
  8. proc getTabClass(timeline: Timeline; tab: string): string =
  9. var classes = @["tab-item"]
  10. if timeline.query.isNone or get(timeline.query).kind == multi:
  11. if tab == "posts":
  12. classes.add "active"
  13. elif $get(timeline.query).kind == tab:
  14. classes.add "active"
  15. return classes.join(" ")
  16. proc renderSearchTabs(timeline: Timeline; username: string): VNode =
  17. let link = "/" & username
  18. buildHtml(ul(class="tab")):
  19. li(class=timeline.getTabClass("posts")):
  20. a(href=link): text "Tweets"
  21. li(class=timeline.getTabClass("replies")):
  22. a(href=(link & "/replies")): text "Tweets & Replies"
  23. li(class=timeline.getTabClass("media")):
  24. a(href=(link & "/media")): text "Media"
  25. proc renderNewer(timeline: Timeline; username: string): VNode =
  26. buildHtml(tdiv(class="status-el show-more")):
  27. a(href=("/" & username & getQuery(timeline).strip(chars={'?'}))):
  28. text "Load newest tweets"
  29. proc renderOlder(timeline: Timeline; username: string): VNode =
  30. buildHtml(tdiv(class="show-more")):
  31. a(href=(&"/{username}{getQuery(timeline)}after={timeline.minId}")):
  32. text "Load older tweets"
  33. proc renderNoMore(): VNode =
  34. buildHtml(tdiv(class="timeline-footer")):
  35. h2(class="timeline-end", style={textAlign: "center"}):
  36. text "No more tweets."
  37. proc renderNoneFound(): VNode =
  38. buildHtml(tdiv(class="timeline-header")):
  39. h2(class="timeline-none", style={textAlign: "center"}):
  40. text "No tweets found."
  41. proc renderProtected(username: string): VNode =
  42. buildHtml(tdiv(class="timeline-header timeline-protected")):
  43. h2: text "This account's tweets are protected."
  44. p: text &"Only confirmed followers have access to @{username}'s tweets."
  45. proc renderThread(thread: seq[Tweet]): VNode =
  46. buildHtml(tdiv(class="timeline-tweet thread-line")):
  47. for i, threadTweet in thread.sortedByIt(it.time):
  48. renderTweet(threadTweet, "thread", index=i, total=thread.high)
  49. proc threadFilter(it: Tweet; tweetThread: string): bool =
  50. it.retweet.isNone and it.reply.len == 0 and it.threadId == tweetThread
  51. proc renderTweets(timeline: Timeline): VNode =
  52. buildHtml(tdiv(id="posts")):
  53. var threads: seq[string]
  54. for tweet in timeline.tweets:
  55. if tweet.threadId in threads: continue
  56. let thread = timeline.tweets.filterIt(threadFilter(it, tweet.threadId))
  57. if thread.len < 2:
  58. renderTweet(tweet, "timeline-tweet")
  59. else:
  60. renderThread(thread)
  61. threads &= tweet.threadId
  62. proc renderTimeline*(timeline: Timeline; username: string;
  63. protected: bool; multi=false): VNode =
  64. buildHtml(tdiv):
  65. if multi:
  66. tdiv(class="multi-header"):
  67. text username.replace(",", " | ")
  68. if not protected:
  69. renderSearchTabs(timeline, username)
  70. if not timeline.beginning:
  71. renderNewer(timeline, username)
  72. if protected:
  73. renderProtected(username)
  74. elif timeline.tweets.len == 0:
  75. renderNoneFound()
  76. else:
  77. renderTweets(timeline)
  78. if timeline.hasMore or timeline.query.isSome:
  79. renderOlder(timeline, username)
  80. else:
  81. renderNoMore()