Compare commits
2 Commits
704db60297
...
3d9a7e3014
| Author | SHA1 | Date | |
|---|---|---|---|
|
3d9a7e3014
|
|||
|
dba8410146
|
@@ -27,6 +27,7 @@ enableDebug = false # enable request logs and debug endpoints (/.sessions)
|
||||
logLevel = "info" # log level (debug, info, warn, error, fatal)
|
||||
proxy = "" # http/https url, SOCKS proxies are not supported
|
||||
proxyAuth = ""
|
||||
defaultFollowedAccounts = "eff,fsf" # default accounts to show when user follows none
|
||||
|
||||
# Change default preferences here, see src/prefs_impl.nim for a complete list
|
||||
[Preferences]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
import parsecfg except Config
|
||||
import types, strutils
|
||||
import types, strutils, sequtils
|
||||
|
||||
proc get*[T](config: parseCfg.Config; section, key: string; default: T): T =
|
||||
let val = config.getSectionValue(section, key)
|
||||
@@ -9,6 +9,7 @@ proc get*[T](config: parseCfg.Config; section, key: string; default: T): T =
|
||||
when T is int: parseInt(val)
|
||||
elif T is bool: parseBool(val)
|
||||
elif T is string: val
|
||||
elif T is seq[string]: val.split(',').mapIt(it.strip())
|
||||
|
||||
proc getConfig*(path: string): (Config, parseCfg.Config) =
|
||||
var cfg = loadConfig(path)
|
||||
@@ -41,7 +42,8 @@ proc getConfig*(path: string): (Config, parseCfg.Config) =
|
||||
enableDebug: cfg.get("Config", "enableDebug", false),
|
||||
logLevel: cfg.get("Config", "logLevel", ""),
|
||||
proxy: cfg.get("Config", "proxy", ""),
|
||||
proxyAuth: cfg.get("Config", "proxyAuth", "")
|
||||
proxyAuth: cfg.get("Config", "proxyAuth", ""),
|
||||
defaultFollowedAccounts: cfg.get("Config", "defaultFollowedAccounts", @["eff", "fsf"])
|
||||
)
|
||||
|
||||
return (conf, cfg)
|
||||
|
||||
@@ -7,7 +7,7 @@ from os import getEnv
|
||||
import jester
|
||||
|
||||
import types, config, prefs, formatters, redis_cache, http_pool, auth, query
|
||||
import views/[general, about, search, profile]
|
||||
import views/[general, about, search, profile, homepage]
|
||||
import karax/[karaxdsl, vdom]
|
||||
import routes/[
|
||||
preferences, timeline, status, media, search, rss, list, debug,
|
||||
@@ -101,37 +101,35 @@ routes:
|
||||
get "/":
|
||||
let prefs = cookiePrefs()
|
||||
|
||||
if prefs.following.len > 0:
|
||||
if prefs.following.len > 0 or cfg.defaultFollowedAccounts.len > 0:
|
||||
let
|
||||
cursor = getCursor()
|
||||
accounts = if prefs.following.len > 0: prefs.following else: cfg.defaultFollowedAccounts
|
||||
isDefault = prefs.following.len == 0
|
||||
currentPath = if @"f".len > 0: "/?f=" & @"f" else: "/"
|
||||
|
||||
var homepageQuery = initQuery(params(request))
|
||||
if @"f".len == 0:
|
||||
homepageQuery.kind = tweets
|
||||
|
||||
homepageQuery.fromUser = prefs.following
|
||||
homepageQuery.fromUser = accounts
|
||||
|
||||
let
|
||||
timeline = await getGraphTweetSearch(homepageQuery, cursor)
|
||||
html = renderHomepageTimeline(timeline, prefs, getPath())
|
||||
html = if isDefault:
|
||||
renderDefaultTimeline(timeline, prefs, getPath())
|
||||
else:
|
||||
renderHomepageTimeline(timeline, prefs, getPath())
|
||||
|
||||
var users: seq[User]
|
||||
for username in prefs.following:
|
||||
for username in accounts:
|
||||
try:
|
||||
let user = await getCachedUser(username)
|
||||
users.add(user)
|
||||
except:
|
||||
continue
|
||||
|
||||
let homepageHtml = buildHtml(tdiv(class="homepage-container")):
|
||||
tdiv(class="following-column"):
|
||||
tdiv(class="profile-cards"):
|
||||
for user in users:
|
||||
let currentPath = if @"f".len > 0: "/?f=" & @"f" else: "/"
|
||||
renderUserCard(user, prefs, currentPath)
|
||||
|
||||
tdiv(class="timeline"):
|
||||
html
|
||||
let homepageHtml = renderHomepage(users, html, prefs, currentPath)
|
||||
|
||||
resp renderMain(homepageHtml, request, cfg, prefs, "Following")
|
||||
else:
|
||||
|
||||
@@ -6,29 +6,48 @@
|
||||
gap: 5px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.following-column {
|
||||
.following-column,
|
||||
.timeline-users-column {
|
||||
width: 280px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.timeline-users-column {
|
||||
.timeline-item {
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.profile-cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.timeline-users-column > :first-child,
|
||||
.homepage-container .timeline-container > .timeline > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 887px) {
|
||||
@media (max-width: 1200px) {
|
||||
.homepage-container {
|
||||
max-width: 100%;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.following-column {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.timeline-users-column {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,25 @@
|
||||
button {
|
||||
float: unset;
|
||||
}
|
||||
|
||||
&.timeline-default {
|
||||
background-color: var(--bg_panel);
|
||||
border-bottom: 1px solid var(--bg_elements);
|
||||
margin-bottom: 5px;
|
||||
|
||||
.timeline-default-message {
|
||||
color: var(--fg_color);
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-banner img {
|
||||
|
||||
@@ -290,6 +290,7 @@ type
|
||||
logLevel*: string
|
||||
proxy*: string
|
||||
proxyAuth*: string
|
||||
defaultFollowedAccounts*: seq[string]
|
||||
|
||||
rssCacheTime*: int
|
||||
listCacheTime*: int
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
import karax/[karaxdsl, vdom]
|
||||
|
||||
import profile
|
||||
import timeline, profile
|
||||
import ".."/[types]
|
||||
|
||||
proc renderHomepage*(users: seq[User]; prefs: Prefs; path: string): VNode =
|
||||
proc renderHomepage*(users: seq[User]; timeline: VNode; prefs: Prefs; path: string): VNode =
|
||||
buildHtml(tdiv(class="homepage-container")):
|
||||
tdiv(class="timeline-users-column"):
|
||||
for user in users:
|
||||
renderUser(user, prefs, path)
|
||||
|
||||
tdiv(class="timeline"):
|
||||
timeline
|
||||
|
||||
tdiv(class="following-column"):
|
||||
tdiv(class="profile-cards"):
|
||||
for user in users:
|
||||
renderUserCard(user, prefs, path)
|
||||
|
||||
tdiv(class="timeline"):
|
||||
tdiv(id="timeline-container")
|
||||
|
||||
@@ -65,6 +65,19 @@ proc renderHomepageTimeline*(results: Timeline; prefs: Prefs; path: string): VNo
|
||||
|
||||
renderTimelineTweets(results, prefs, path)
|
||||
|
||||
proc renderDefaultTimeline*(results: Timeline; prefs: Prefs; path: string): VNode =
|
||||
let query = results.query
|
||||
buildHtml(tdiv(class="timeline-container")):
|
||||
tdiv(class="timeline-header timeline-default"):
|
||||
h2(class="timeline-default-message"):
|
||||
text "Follow people to populate your "
|
||||
strong: text "own"
|
||||
text " feed"
|
||||
|
||||
renderHomepageTabs(query)
|
||||
|
||||
renderTimelineTweets(results, prefs, path)
|
||||
|
||||
proc renderUserSearch*(results: Result[User]; prefs: Prefs; path: string): VNode =
|
||||
buildHtml(tdiv(class="timeline-container")):
|
||||
renderSearchTabs(results.query)
|
||||
|
||||
@@ -55,7 +55,7 @@ proc renderThread(thread: Tweets; prefs: Prefs; path: string): VNode =
|
||||
renderTweet(tweet, prefs, path, class=(header & "thread"),
|
||||
index=i, last=(i == thread.high), showThread=show)
|
||||
|
||||
proc renderUser(user: User; prefs: Prefs; path: string): VNode =
|
||||
proc renderUser*(user: User; prefs: Prefs; path: string): VNode =
|
||||
let class = if user.sensitive: "timeline-item nsfw" else: "timeline-item"
|
||||
buildHtml(tdiv(class=class)):
|
||||
a(class="tweet-link", href=("/" & user.username))
|
||||
|
||||
Reference in New Issue
Block a user