timeline.nim 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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:
  11. if tab == "tweets":
  12. classes.add "active"
  13. elif $timeline.query.get().kind == tab:
  14. classes.add "active"
  15. return classes.join(" ")
  16. proc renderSearchTabs(timeline: Timeline; profile: Profile): VNode =
  17. let link = "/" & profile.username
  18. buildHtml(ul(class="tab")):
  19. li(class=timeline.getTabClass("tweets")):
  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; profile: Profile): VNode =
  26. buildHtml(tdiv(class="status-el show-more")):
  27. a(href=("/" & profile.username & getQuery(timeline).strip(chars={'?'}))):
  28. text "Load newest tweets"
  29. proc renderOlder(timeline: Timeline; profile: Profile): VNode =
  30. buildHtml(tdiv(class="show-more")):
  31. a(href=(&"/{profile.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="tweets")):
  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; profile: Profile): VNode =
  63. buildHtml(tdiv):
  64. renderSearchTabs(timeline, profile)
  65. if not profile.protected and not timeline.beginning:
  66. renderNewer(timeline, profile)
  67. if profile.protected:
  68. renderProtected(profile.username)
  69. elif timeline.tweets.len == 0:
  70. renderNoneFound()
  71. else:
  72. renderTweets(timeline)
  73. if timeline.hasMore or timeline.query.isSome:
  74. renderOlder(timeline, profile)
  75. else:
  76. renderNoMore()