add custom style and settings

master
lamacchinadesiderante 8 months ago
parent 36c72f9860
commit 47283ca285

@ -3,7 +3,11 @@ version: "3"
services:
nitter:
image: zedeus/nitter:latest
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
image: lamacchinadesiderante/nitter:latest
container_name: nitter
ports:
- "127.0.0.1:8080:8080" # Replace with "8080:8080" if you don't use a reverse proxy
@ -11,7 +15,6 @@ services:
- ./nitter.conf:/src/nitter.conf:ro
depends_on:
- nitter-redis
restart: unless-stopped
healthcheck:
test: wget -nv --tries=1 --spider http://127.0.0.1:8080/Jack/status/20 || exit 1
interval: 30s

@ -5,12 +5,12 @@ https = false # disable to enable cookies when not using https
httpMaxConnections = 100
staticDir = "./public"
title = "nitter"
hostname = "nitter.net"
hostname = "nitter.copyriot.xyz"
[Cache]
listMinutes = 240 # how long to cache list info (not the tweets, so keep it high)
rssMinutes = 10 # how long to cache rss queries
redisHost = "localhost" # Change to "nitter-redis" if using docker-compose
redisHost = "nitter-redis" # Change to "nitter-redis" if using docker-compose
redisPort = 6379
redisPassword = ""
redisConnections = 20 # connection pool size
@ -36,9 +36,9 @@ tokenCount = 10
# Change default preferences here, see src/prefs_impl.nim for a complete list
[Preferences]
theme = "Nitter"
replaceTwitter = "nitter.net"
replaceYouTube = "piped.video"
replaceReddit = "teddit.net"
replaceTwitter = "nitter.copyriot.xyz"
replaceYouTube = "invidious.copyriot.xyz"
replaceReddit = "libreddit.copyriot.xyz"
replaceInstagram = ""
proxyVideos = true
hlsPlayback = false

@ -0,0 +1,9 @@
@font-face {
font-family: 'Lemon Yellow Sun';
src: url("/fonts/LemonYellowSun.otf") format("opentype");
}
.header-title {
font-family: 'Lemon Yellow Sun' !important;
font-size: 24px;
}

Binary file not shown.

@ -21,7 +21,7 @@ proc getConfig*(path: string): (Config, parseCfg.Config) =
httpMaxConns: cfg.get("Server", "httpMaxConnections", 100),
staticDir: cfg.get("Server", "staticDir", "./public"),
title: cfg.get("Server", "title", "Nitter"),
hostname: cfg.get("Server", "hostname", "nitter.net"),
hostname: cfg.get("Server", "hostname", "nitter.copyriot.xyz"),
# Cache
listCacheTime: cfg.get("Cache", "listMinutes", 120),

@ -52,49 +52,49 @@ macro genPrefs*(prefDsl: untyped) =
genPrefs:
Display:
theme(select, "Nitter"):
"Theme"
"Tema"
infiniteScroll(checkbox, false):
"Infinite scrolling (experimental, requires JavaScript)"
"Infinite scrolling (sperimentale, serve JavaScript abilitato)"
stickyProfile(checkbox, true):
"Make profile sidebar stick to top"
"Sidebar profilo fissata in cima"
bidiSupport(checkbox, false):
"Support bidirectional text (makes clicking on tweets harder)"
"Supporto al testo bidirezionale"
hideTweetStats(checkbox, false):
"Hide tweet stats (replies, retweets, likes)"
"Nascondi statistiche tweet (risposte, retweets, likes)"
hideBanner(checkbox, false):
"Hide profile banner"
"Nascondi banner profilo"
hidePins(checkbox, false):
"Hide pinned tweets"
"Nascondi pinned tweets"
hideReplies(checkbox, false):
"Hide tweet replies"
"Nascondi risposte ai tweet"
squareAvatars(checkbox, false):
"Square profile pictures"
"Profile pictures quadrate"
Media:
mp4Playback(checkbox, true):
"Enable mp4 video playback (only for gifs)"
"Abilita playback video mp4 (solo gif)"
hlsPlayback(checkbox, false):
"Enable hls video streaming (requires JavaScript)"
"Abilita streaming video hls (richiede JavaScript attivo)"
proxyVideos(checkbox, true):
"Proxy video streaming through the server (might be slow)"
"Proxy streaming tramite server (potrebbe essere lento)"
muteVideos(checkbox, false):
"Mute videos by default"
"Silenzia video di default"
autoplayGifs(checkbox, true):
"Autoplay gifs"
"Autoplay gif"
"Link replacements (blank to disable)":
"Sostituisci link (vuoto per disabilitare)":
replaceTwitter(input, ""):
"Twitter -> Nitter"
placeholder: "Nitter hostname"

@ -2,8 +2,8 @@
$bg_color: #0F0F0F;
$fg_color: #F8F8F2;
$fg_faded: #F8F8F2CF;
$fg_dark: #FF6C60;
$fg_nav: #FF6C60;
$fg_dark: #facc00;
$fg_nav: #facc00;
$bg_panel: #161616;
$bg_elements: #121212;
@ -16,18 +16,18 @@ $darker_grey: #282828;
$darkest_grey: #222222;
$border_grey: #3E3E35;
$accent: #FF6C60;
$accent_light: #FFACA0;
$accent_dark: #8A3731;
$accent_border: #FF6C6091;
$accent: #facc00;
$accent_light: #fdd835;
$accent_dark: #9b7e00;
$accent_border: #facc008c;
$play_button: #D8574D;
$play_button_hover: #FF6C60;
$play_button: #c5a100;
$play_button_hover: #e7bd00;
$more_replies_dots: #AD433B;
$error_red: #420A05;
$more_replies_dots: #b19000;
$error_red: #fa4700;
$verified_blue: #1DA1F2;
$verified_blue: #009efa;
$icon_text: $fg_color;
$tab: $fg_color;

@ -38,6 +38,10 @@ nav {
}
}
.header-title {
}
.site-logo {
display: block;
width: 35px;

@ -23,18 +23,18 @@ proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode =
buildHtml(nav):
tdiv(class="inner-nav"):
tdiv(class="nav-item"):
a(class="site-name", href="/"): text cfg.title
a(class="site-name header-title", href="/"): text cfg.title
a(href="/"): img(class="site-logo", src="/logo.png", alt="Logo")
# a(href="/"): img(class="site-logo", src="/logo.png", alt="Logo")
tdiv(class="nav-item right"):
icon "search", title="Search", href="/search"
if cfg.enableRss and rss.len > 0:
icon "rss-feed", title="RSS Feed", href=rss
icon "bird", title="Open in Twitter", href=canonical
a(href="https://liberapay.com/zedeus"): verbatim lp
icon "info", title="About", href="/about"
icon "cog", title="Preferences", href=("/settings?referer=" & encodeUrl(path))
# icon "bird", title="Open in Twitter", href=canonical
# a(href="https://liberapay.com/zedeus"): verbatim lp
# icon "info", title="Info", href="/about"
icon "cog", title="Impostazioni", href=("/settings?referer=" & encodeUrl(path))
proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
video=""; images: seq[string] = @[]; banner=""; ogTitle="";
@ -54,6 +54,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
buildHtml(head):
link(rel="stylesheet", type="text/css", href="/css/style.css?v=18")
link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=2")
link(rel="stylesheet", type="text/css", href="/css/lemontree.css")
if theme.len > 0:
link(rel="stylesheet", type="text/css", href=(&"/css/themes/{theme}.css"))

@ -41,9 +41,9 @@ proc renderPreferences*(prefs: Prefs; path: string; themes: seq[string]): VNode
renderPrefs()
h4(class="note"):
text "Preferences are stored client-side using cookies without any personal information."
text "Le impostazioni sono salvate lato client nei cookies (senza informazioni personali)."
button(`type`="submit", class="pref-submit"):
text "Save preferences"
text "Salva impostazioni"
buttonReferer "/resetprefs", "Reset preferences", path, class="pref-reset"
buttonReferer "/resetprefs", "Reset impostazioni", path, class="pref-reset"

@ -56,12 +56,12 @@ proc renderUserCard*(user: User; prefs: Prefs): VNode =
span(title=getJoinDateFull(user)):
icon "calendar", getJoinDate(user)
tdiv(class="profile-card-extra-links"):
ul(class="profile-statlist"):
renderStat(user.tweets, "posts", text="Tweets")
renderStat(user.following, "following")
renderStat(user.followers, "followers")
renderStat(user.likes, "likes")
# tdiv(class="profile-card-extra-links"):
# ul(class="profile-statlist"):
# renderStat(user.tweets, "posts", text="Tweets")
# renderStat(user.following, "following")
# renderStat(user.followers, "followers")
# renderStat(user.likes, "likes")
proc renderPhotoRail(profile: Profile): VNode =
let count = insertSep($profile.user.media, ',')

@ -10,13 +10,13 @@ const toggles = {
"media": "Media",
"videos": "Videos",
"news": "News",
"verified": "Verified",
"native_video": "Native videos",
"replies": "Replies",
"verified": "Verificato",
"native_video": "Video nativi",
"replies": "Risposte",
"links": "Links",
"images": "Images",
"safe": "Safe",
"quote": "Quotes",
"images": "Immagini",
"safe": "Sicuro",
"quote": "Citazioni",
"pro_video": "Pro videos"
}.toOrderedTable
@ -26,7 +26,7 @@ proc renderSearch*(): VNode =
form(`method`="get", action="/search", autocomplete="off"):
hiddenField("f", "users")
input(`type`="text", name="q", autofocus="",
placeholder="Enter username...", dir="auto")
placeholder="Inserisci username...", dir="auto")
button(`type`="submit"): icon "search"
proc renderProfileTabs*(query: Query; username: string): VNode =
@ -39,7 +39,7 @@ proc renderProfileTabs*(query: Query; username: string): VNode =
li(class=query.getTabClass(media)):
a(href=(link & "/media")): text "Media"
li(class=query.getTabClass(tweets)):
a(href=(link & "/search")): text "Search"
a(href=(link & "/search")): text "Cerca"
proc renderSearchTabs*(query: Query): VNode =
var q = query
@ -49,7 +49,7 @@ proc renderSearchTabs*(query: Query): VNode =
a(href=("?" & genQueryUrl(q))): text "Tweets"
li(class=query.getTabClass(users)):
q.kind = users
a(href=("?" & genQueryUrl(q))): text "Users"
a(href=("?" & genQueryUrl(q))): text "Utenti"
proc isPanelOpen(q: Query): bool =
q.fromUser.len == 0 and (q.filters.len > 0 or q.excludes.len > 0 or
@ -61,7 +61,7 @@ proc renderSearchPanel*(query: Query): VNode =
buildHtml(form(`method`="get", action=action,
class="search-field", autocomplete="off")):
hiddenField("f", "tweets")
genInput("q", "", query.text, "Enter search...", class="pref-inline")
genInput("q", "", query.text, "Inserisci testo...", class="pref-inline")
button(`type`="submit"): icon "search"
if isPanelOpen(query):
input(id="search-panel-toggle", `type`="checkbox", checked="")
@ -81,14 +81,14 @@ proc renderSearchPanel*(query: Query): VNode =
tdiv(class="search-row"):
tdiv:
span(class="search-title"): text "Time range"
span(class="search-title"): text "Range temporale"
tdiv(class="date-range"):
genDate("since", query.since)
span(class="search-title"): text "-"
genDate("until", query.until)
tdiv:
span(class="search-title"): text "Near"
genInput("near", "", query.near, "Location...", autofocus=false)
genInput("near", "", query.near, "Posizione...", autofocus=false)
proc renderTweetSearch*(results: Result[Tweet]; prefs: Prefs; path: string;
pinned=none(Tweet)): VNode =
@ -115,7 +115,7 @@ proc renderUserSearch*(results: Result[User]; prefs: Prefs): VNode =
tdiv(class="timeline-header"):
form(`method`="get", action="/search", class="search-field", autocomplete="off"):
hiddenField("f", "users")
genInput("q", "", results.query.text, "Enter username...", class="pref-inline")
genInput("q", "", results.query.text, "Inserisci username...", class="pref-inline")
button(`type`="submit"): icon "search"
renderSearchTabs(results.query)

@ -22,22 +22,22 @@ proc renderNewer*(query: Query; path: string; focus=""): VNode =
p = if focus.len > 0: path.replace("#m", focus) else: path
buildHtml(tdiv(class="timeline-item show-more")):
a(href=(p & url)):
text "Load newest"
text "Carica più recenti"
proc renderMore*(query: Query; cursor: string; focus=""): VNode =
buildHtml(tdiv(class="show-more")):
a(href=(&"?{getQuery(query)}cursor={encodeUrl(cursor, usePlus=false)}{focus}")):
text "Load more"
text "Carica altro"
proc renderNoMore(): VNode =
buildHtml(tdiv(class="timeline-footer")):
h2(class="timeline-end"):
text "No more items"
text "Non ci sono altri elementi"
proc renderNoneFound(): VNode =
buildHtml(tdiv(class="timeline-header")):
h2(class="timeline-none"):
text "No items found"
text "Nessun elemento trovato"
proc renderThread(thread: seq[Tweet]; prefs: Prefs; path: string): VNode =
buildHtml(tdiv(class="thread-line")):

@ -40,14 +40,14 @@ class TweetTest(BaseTestCase):
@parameterized.expand(no_more)
def test_no_more(self, username):
self.open_nitter(username)
self.assert_text('No more items', Timeline.end)
self.assert_text('Non ci sono altri elementi', Timeline.end)
self.assert_element_present(Timeline.newest)
self.assert_element_absent(Timeline.older)
@parameterized.expand(empty)
def test_empty(self, username):
self.open_nitter(username)
self.assert_text('No items found', Timeline.none)
self.assert_text('Nessun elemento trovato', Timeline.none)
self.assert_element_absent(Timeline.newest)
self.assert_element_absent(Timeline.older)
self.assert_element_absent(Timeline.end)

Loading…
Cancel
Save