Merge pull request #78 from mcrossman/subscriptions
Subscribing to subreddits (favorites)
This commit is contained in:
commit
79027c4c75
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -480,9 +480,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.5.0"
|
||||
version = "3.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f07aa6688c702439a1be0307b6a94dffe1168569e45b9500c1372bc580740d59"
|
||||
checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@ -531,9 +531,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chunked_transfer"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca"
|
||||
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
@ -628,9 +628,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.19"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
|
||||
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crc32fast",
|
||||
@ -988,9 +988,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.83"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eb0c4e9c72ee9d69b767adebc5f4788462a3b45624acd919475c92597bcaf4f"
|
||||
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
|
||||
|
||||
[[package]]
|
||||
name = "libreddit"
|
||||
|
21
src/main.rs
21
src/main.rs
@ -54,7 +54,7 @@ async fn main() -> std::io::Result<()> {
|
||||
.wrap_fn(move |req, srv| {
|
||||
let secure = req.connection_info().scheme() == "https";
|
||||
let https_url = format!("https://{}{}", req.connection_info().host(), req.uri().to_string());
|
||||
srv.call(req).map(move |res: Result<ServiceResponse, _>|
|
||||
srv.call(req).map(move |res: Result<ServiceResponse, _>| {
|
||||
if force_https && !secure {
|
||||
Ok(ServiceResponse::new(
|
||||
res.unwrap().request().to_owned(),
|
||||
@ -63,16 +63,21 @@ async fn main() -> std::io::Result<()> {
|
||||
} else {
|
||||
res
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
// Append trailing slash and remove double slashes
|
||||
.wrap(middleware::NormalizePath::default())
|
||||
// Apply default headers for security
|
||||
.wrap(middleware::DefaultHeaders::new()
|
||||
.header("Referrer-Policy", "no-referrer")
|
||||
.header("X-Content-Type-Options", "nosniff")
|
||||
.header("X-Frame-Options", "DENY")
|
||||
.header("Content-Security-Policy", "default-src 'none'; media-src 'self'; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none';"))
|
||||
.wrap(
|
||||
middleware::DefaultHeaders::new()
|
||||
.header("Referrer-Policy", "no-referrer")
|
||||
.header("X-Content-Type-Options", "nosniff")
|
||||
.header("X-Frame-Options", "DENY")
|
||||
.header(
|
||||
"Content-Security-Policy",
|
||||
"default-src 'none'; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none';",
|
||||
),
|
||||
)
|
||||
// Default service in case no routes match
|
||||
.default_service(web::get().to(|| utils::error("Nothing here".to_string())))
|
||||
// Read static files
|
||||
@ -99,6 +104,8 @@ async fn main() -> std::io::Result<()> {
|
||||
// See posts and info about subreddit
|
||||
.route("/", web::get().to(subreddit::page))
|
||||
.route("/{sort:hot|new|top|rising|controversial}/", web::get().to(subreddit::page))
|
||||
// Handle subscribe/unsubscribe
|
||||
.route("/{action:subscribe|unsubscribe}/", web::post().to(subreddit::subscriptions))
|
||||
// View post on subreddit
|
||||
.service(
|
||||
web::scope("/comments/{id}/{title}")
|
||||
|
32
src/proxy.rs
32
src/proxy.rs
@ -24,26 +24,24 @@ pub async fn handler(web::Path(b64): web::Path<String>) -> Result<HttpResponse>
|
||||
let decoded = decode(b64).map(|bytes| String::from_utf8(bytes).unwrap_or_default());
|
||||
|
||||
match decoded {
|
||||
Ok(media) => {
|
||||
match Url::parse(media.as_str()) {
|
||||
Ok(url) => {
|
||||
let domain = url.domain().unwrap_or_default();
|
||||
Ok(media) => match Url::parse(media.as_str()) {
|
||||
Ok(url) => {
|
||||
let domain = url.domain().unwrap_or_default();
|
||||
|
||||
if domains.contains(&domain) {
|
||||
Client::default().get(media.replace("&", "&")).send().await.map_err(Error::from).map(|res| {
|
||||
HttpResponse::build(res.status())
|
||||
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
|
||||
.header("Content-Length", res.headers().get("Content-Length").unwrap().to_owned())
|
||||
.header("Content-Type", res.headers().get("Content-Type").unwrap().to_owned())
|
||||
.streaming(res)
|
||||
})
|
||||
} else {
|
||||
Err(error::ErrorForbidden("Resource must be from Reddit"))
|
||||
}
|
||||
if domains.contains(&domain) {
|
||||
Client::default().get(media.replace("&", "&")).send().await.map_err(Error::from).map(|res| {
|
||||
HttpResponse::build(res.status())
|
||||
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
|
||||
.header("Content-Length", res.headers().get("Content-Length").unwrap().to_owned())
|
||||
.header("Content-Type", res.headers().get("Content-Type").unwrap().to_owned())
|
||||
.streaming(res)
|
||||
})
|
||||
} else {
|
||||
Err(error::ErrorForbidden("Resource must be from Reddit"))
|
||||
}
|
||||
_ => Err(error::ErrorBadRequest("Can't parse base64 into URL")),
|
||||
}
|
||||
}
|
||||
_ => Err(error::ErrorBadRequest("Can't parse base64 into URL")),
|
||||
},
|
||||
_ => Err(error::ErrorBadRequest("Can't decode base64")),
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
// CRATES
|
||||
use crate::utils::*;
|
||||
use actix_web::{HttpRequest, HttpResponse, Result};
|
||||
use actix_web::{cookie::Cookie, HttpRequest, HttpResponse, Result};
|
||||
use askama::Template;
|
||||
use time::{Duration, OffsetDateTime};
|
||||
|
||||
// STRUCTS
|
||||
#[derive(Template)]
|
||||
@ -25,23 +26,43 @@ struct WikiTemplate {
|
||||
|
||||
// SERVICES
|
||||
pub async fn page(req: HttpRequest) -> HttpResponse {
|
||||
let path = format!("{}.json?{}", req.path(), req.query_string());
|
||||
let default = cookie(&req, "front_page");
|
||||
let sub_name = req
|
||||
let subscribed = cookie(&req, "subscriptions");
|
||||
let front_page = cookie(&req, "front_page");
|
||||
let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
|
||||
|
||||
let sub = req
|
||||
.match_info()
|
||||
.get("sub")
|
||||
.unwrap_or(if default.is_empty() { "popular" } else { default.as_str() })
|
||||
.to_string();
|
||||
let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
|
||||
.map(String::from)
|
||||
.unwrap_or(if front_page == "default" || front_page.is_empty() {
|
||||
if subscribed.is_empty() {
|
||||
"popular".to_string()
|
||||
} else {
|
||||
subscribed.to_owned()
|
||||
}
|
||||
} else {
|
||||
front_page.to_owned()
|
||||
});
|
||||
|
||||
let path = format!("/r/{}.json?{}", sub, req.query_string());
|
||||
|
||||
match fetch_posts(&path, String::new()).await {
|
||||
Ok((posts, after)) => {
|
||||
// If you can get subreddit posts, also request subreddit metadata
|
||||
let sub = if !sub_name.contains('+') && sub_name != "popular" && sub_name != "all" {
|
||||
subreddit(&sub_name).await.unwrap_or_default()
|
||||
} else if sub_name.contains('+') {
|
||||
let sub = if !sub.contains('+') && sub != subscribed && sub != "popular" && sub != "all" {
|
||||
// Regular subreddit
|
||||
subreddit(&sub).await.unwrap_or_default()
|
||||
} else if sub == subscribed {
|
||||
// Subscription feed
|
||||
if req.path().starts_with("/r/") {
|
||||
subreddit(&sub).await.unwrap_or_default()
|
||||
} else {
|
||||
Subreddit::default()
|
||||
}
|
||||
} else if sub.contains('+') {
|
||||
// Multireddit
|
||||
Subreddit {
|
||||
name: sub_name,
|
||||
name: sub,
|
||||
..Subreddit::default()
|
||||
}
|
||||
} else {
|
||||
@ -63,6 +84,50 @@ pub async fn page(req: HttpRequest) -> HttpResponse {
|
||||
}
|
||||
}
|
||||
|
||||
// Sub or unsub by setting subscription cookie using response "Set-Cookie" header
|
||||
pub async fn subscriptions(req: HttpRequest) -> HttpResponse {
|
||||
let mut res = HttpResponse::Found();
|
||||
|
||||
let sub = req.match_info().get("sub").unwrap_or_default().to_string();
|
||||
let action = req.match_info().get("action").unwrap_or_default().to_string();
|
||||
let mut sub_list = prefs(req.to_owned()).subs;
|
||||
|
||||
// Modify sub list based on action
|
||||
if action == "subscribe" && !sub_list.contains(&sub) {
|
||||
sub_list.push(sub.to_owned());
|
||||
sub_list.sort();
|
||||
} else if action == "unsubscribe" {
|
||||
sub_list.retain(|s| s != &sub);
|
||||
}
|
||||
|
||||
// Delete cookie if empty, else set
|
||||
if sub_list.is_empty() {
|
||||
res.del_cookie(&Cookie::build("subscriptions", "").path("/").finish());
|
||||
} else {
|
||||
res.cookie(
|
||||
Cookie::build("subscriptions", sub_list.join("+"))
|
||||
.path("/")
|
||||
.http_only(true)
|
||||
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
||||
.finish(),
|
||||
);
|
||||
}
|
||||
|
||||
// Redirect back to subreddit
|
||||
// check for redirect parameter if unsubscribing from outside sidebar
|
||||
let redirect_path = param(&req.uri().to_string(), "redirect");
|
||||
let path = if !redirect_path.is_empty() && redirect_path.starts_with('/') {
|
||||
redirect_path
|
||||
} else {
|
||||
format!("/r/{}", sub)
|
||||
};
|
||||
|
||||
res
|
||||
.content_type("text/html")
|
||||
.set_header("Location", path.to_owned())
|
||||
.body(format!("Redirecting to <a href=\"{0}\">{0}</a>...", path))
|
||||
}
|
||||
|
||||
pub async fn wiki(req: HttpRequest) -> HttpResponse {
|
||||
let sub = req.match_info().get("sub").unwrap_or("reddit.com").to_string();
|
||||
let page = req.match_info().get("page").unwrap_or("index").to_string();
|
||||
|
@ -129,6 +129,7 @@ pub struct Preferences {
|
||||
pub wide: String,
|
||||
pub hide_nsfw: String,
|
||||
pub comment_sort: String,
|
||||
pub subs: Vec<String>,
|
||||
}
|
||||
|
||||
//
|
||||
@ -144,6 +145,7 @@ pub fn prefs(req: HttpRequest) -> Preferences {
|
||||
wide: cookie(&req, "wide"),
|
||||
hide_nsfw: cookie(&req, "hide_nsfw"),
|
||||
comment_sort: cookie(&req, "comment_sort"),
|
||||
subs: cookie(&req, "subscriptions").split('+').map(String::from).filter(|s| s != "").collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
150
static/style.css
150
static/style.css
@ -68,11 +68,12 @@ pre, form, fieldset, table, th, td, select, input {
|
||||
body {
|
||||
background: var(--background);
|
||||
font-size: 15px;
|
||||
padding-top: 60px;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: grid;
|
||||
grid-template-areas: "logo searchbox code";
|
||||
grid-template-areas: "logo searchbox links";
|
||||
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
@ -83,7 +84,7 @@ nav {
|
||||
|
||||
font-size: 20px;
|
||||
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
padding: 5px 15px;
|
||||
min-height: 40px;
|
||||
@ -94,12 +95,23 @@ nav {
|
||||
nav * { color: var(--text); }
|
||||
nav #reddit, #code { color: var(--accent); }
|
||||
nav #logo { grid-area: logo; }
|
||||
nav #code { grid-area: code; }
|
||||
nav #version { opacity: 50%; }
|
||||
|
||||
nav #links {
|
||||
grid-area: links;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
nav #version {
|
||||
opacity: 50%;
|
||||
vertical-align: -2px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
nav #libreddit {
|
||||
vertical-align: -2px;
|
||||
}
|
||||
|
||||
#settings_link {
|
||||
font-size: 18px;
|
||||
margin-left: 10px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@ -108,7 +120,7 @@ main {
|
||||
justify-content: center;
|
||||
max-width: 1000px;
|
||||
padding: 10px 20px;
|
||||
margin: 60px auto 20px auto
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.wide main {
|
||||
@ -232,6 +244,71 @@ aside {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* Subscriptions */
|
||||
|
||||
#sub_subscription {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.subscribe, .unsubscribe {
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.subscribe {
|
||||
color: var(--foreground);
|
||||
background-color: var(--accent);
|
||||
}
|
||||
|
||||
.unsubscribe {
|
||||
color: var(--text);
|
||||
background-color: var(--highlighted);
|
||||
}
|
||||
|
||||
/* Subscribed subreddit list */
|
||||
|
||||
#subscriptions {
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
border: var(--panel-border);
|
||||
background-color: var(--outside);
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
font-size: 15px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#subscriptions > summary {
|
||||
padding: 8px 15px;
|
||||
}
|
||||
|
||||
#sub_list {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
min-width: 100%;
|
||||
border-radius: 5px;
|
||||
box-shadow: var(--shadow);
|
||||
background: var(--outside);
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#sub_list > a {
|
||||
padding: 10px 20px;
|
||||
transition: 0.2s background;
|
||||
}
|
||||
|
||||
#sub_list > .selected {
|
||||
background-color: var(--accent);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
#sub_list > a:not(.selected):hover {
|
||||
background-color: var(--foreground);
|
||||
}
|
||||
|
||||
/* Wiki Pages */
|
||||
|
||||
#wiki {
|
||||
@ -452,10 +529,6 @@ a.search_subreddit:hover {
|
||||
|
||||
.post:not(:last-child) { margin-bottom: 10px; }
|
||||
|
||||
.post.highlighted {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.post:hover {
|
||||
background: var(--foreground);
|
||||
}
|
||||
@ -789,7 +862,7 @@ a.search_subreddit:hover {
|
||||
|
||||
/* Settings */
|
||||
|
||||
#settings {
|
||||
#settings, #settings > form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@ -802,7 +875,7 @@ a.search_subreddit:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
#prefs {
|
||||
.prefs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
@ -812,7 +885,7 @@ a.search_subreddit:hover {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#prefs > div {
|
||||
.prefs > div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
@ -820,17 +893,21 @@ a.search_subreddit:hover {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#prefs > div:not(:last-of-type) {
|
||||
.prefs > div:not(:last-of-type) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#prefs select {
|
||||
.prefs select {
|
||||
border-radius: 5px;
|
||||
box-shadow: var(--shadow);
|
||||
margin-left: 20px;
|
||||
background: var(--foreground);
|
||||
}
|
||||
|
||||
aside.prefs {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#save {
|
||||
background: var(--highlighted);
|
||||
padding: 10px 15px;
|
||||
@ -843,6 +920,27 @@ input[type="submit"] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
#settings_subs {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#settings_subs > li {
|
||||
display: flex;
|
||||
margin: 10px 0;
|
||||
}
|
||||
#settings_subs > li:last-of-type { margin-bottom: 0; }
|
||||
|
||||
#settings_subs > li > span {
|
||||
padding: 10px 0;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#settings_subs .unsubscribe {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
/* Markdown */
|
||||
|
||||
.md > *:not(:first-child) {
|
||||
@ -916,6 +1014,8 @@ td, th {
|
||||
/* Mobile */
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
#version { display: none; }
|
||||
|
||||
.post {
|
||||
grid-template: "post_header post_header post_thumbnail" auto
|
||||
"post_title post_title post_thumbnail" 1fr
|
||||
@ -954,25 +1054,37 @@ td, th {
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
body { padding-top: 120px }
|
||||
|
||||
main {
|
||||
flex-direction: column-reverse;
|
||||
padding: 10px;
|
||||
margin: 100px 0 10px 0;
|
||||
margin: 0 0 10px 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
nav {
|
||||
grid-template-areas: 'logo code' 'searchbox searchbox';
|
||||
grid-template-areas: 'logo links' 'searchbox searchbox';
|
||||
padding: 10px;
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
nav #links { margin-left: auto; }
|
||||
|
||||
#subscriptions { position: unset; }
|
||||
|
||||
#sub_list {
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
aside, #subreddit, #user {
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#user, #sidebar { margin: 20px 0; }
|
||||
#logo { margin: 5px auto; }
|
||||
#logo, #links { margin-bottom: 5px; }
|
||||
#searchbox { width: calc(100vw - 35px); }
|
||||
}
|
||||
|
@ -16,15 +16,18 @@
|
||||
{% if prefs.theme != "system" %} {{ prefs.theme }}{% endif %}">
|
||||
<!-- NAVIGATION BAR -->
|
||||
<nav>
|
||||
<p id="logo">
|
||||
<div id="logo">
|
||||
<a id="libreddit" href="/">
|
||||
<span id="lib">lib</span><span id="reddit">reddit.</span>
|
||||
</a>
|
||||
<span id="version">v{{ env!("CARGO_PKG_VERSION") }}</span>
|
||||
<a id="settings_link" href="/settings">settings</a>
|
||||
</p>
|
||||
{% block subscriptions %}{% endblock %}
|
||||
</div>
|
||||
{% block search %}{% endblock %}
|
||||
<a id="code" href="https://github.com/spikecodes/libreddit">code</a>
|
||||
<div id="links">
|
||||
<a id="settings_link" href="/settings">settings</a>
|
||||
<a id="code" href="https://github.com/spikecodes/libreddit">code</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
|
@ -13,6 +13,10 @@
|
||||
<meta name="author" content="u/{{ post.author.name }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block subscriptions %}
|
||||
{% call utils::sub_list(post.community.as_str()) %}
|
||||
{% endblock %}
|
||||
|
||||
<!-- OPEN COMMENT MACRO -->
|
||||
{% macro comment(item) -%}
|
||||
<div id="{{ item.id }}" class="comment">
|
||||
|
@ -3,6 +3,10 @@
|
||||
|
||||
{% block title %}Libreddit: search results - {{ params.q }}{% endblock %}
|
||||
|
||||
{% block subscriptions %}
|
||||
{% call utils::sub_list("") %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="column_one">
|
||||
<form id="search_sort">
|
||||
|
@ -8,45 +8,63 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form id="settings" action="/settings" method="POST">
|
||||
<div id="prefs">
|
||||
<p>Appearance</p>
|
||||
<div id="theme">
|
||||
<label for="theme">Theme:</label>
|
||||
<select name="theme">
|
||||
{% call utils::options(prefs.theme, ["system", "light", "dark"], "system") %}
|
||||
</select>
|
||||
<div id="settings">
|
||||
<form action="/settings" method="POST">
|
||||
<div class="prefs">
|
||||
<p>Appearance</p>
|
||||
<div id="theme">
|
||||
<label for="theme">Theme:</label>
|
||||
<select name="theme">
|
||||
{% call utils::options(prefs.theme, ["system", "light", "dark"], "system") %}
|
||||
</select>
|
||||
</div>
|
||||
<p>Interface</p>
|
||||
<div id="front_page">
|
||||
<label for="front_page">Front page:</label>
|
||||
<select name="front_page">
|
||||
{% call utils::options(prefs.front_page, ["default", "popular", "all"], "default") %}
|
||||
</select>
|
||||
</div>
|
||||
<div id="layout">
|
||||
<label for="layout">Layout:</label>
|
||||
<select name="layout">
|
||||
{% call utils::options(prefs.layout, ["card", "clean", "compact"], "card") %}
|
||||
</select>
|
||||
</div>
|
||||
<div id="wide">
|
||||
<label for="wide">Wide UI:</label>
|
||||
<input type="checkbox" name="wide" {% if prefs.wide == "on" %}checked{% endif %}>
|
||||
</div>
|
||||
<p>Content</p>
|
||||
<div id="comment_sort">
|
||||
<label for="comment_sort">Default comment sort:</label>
|
||||
<select name="comment_sort">
|
||||
{% call utils::options(prefs.comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %}
|
||||
</select>
|
||||
</div>
|
||||
<div id="hide_nsfw">
|
||||
<label for="hide_nsfw">Hide NSFW posts:</label>
|
||||
<input type="checkbox" name="hide_nsfw" {% if prefs.hide_nsfw == "on" %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<p>Interface</p>
|
||||
<div id="front_page">
|
||||
<label for="front_page">Front page:</label>
|
||||
<select name="front_page">
|
||||
{% call utils::options(prefs.front_page, ["popular", "all"], "popular") %}
|
||||
</select>
|
||||
</div>
|
||||
<div id="layout">
|
||||
<label for="layout">Layout:</label>
|
||||
<select name="layout">
|
||||
{% call utils::options(prefs.layout, ["card", "clean", "compact"], "card") %}
|
||||
</select>
|
||||
</div>
|
||||
<div id="wide">
|
||||
<label for="wide">Wide UI:</label>
|
||||
<input type="checkbox" name="wide" {% if prefs.wide == "on" %}checked{% endif %}>
|
||||
</div>
|
||||
<p>Content</p>
|
||||
<div id="comment_sort">
|
||||
<label for="comment_sort">Default comment sort:</label>
|
||||
<select name="comment_sort">
|
||||
{% call utils::options(prefs.comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %}
|
||||
</select>
|
||||
</div>
|
||||
<div id="hide_nsfw">
|
||||
<label for="hide_nsfw">Hide NSFW posts:</label>
|
||||
<input type="checkbox" name="hide_nsfw" {% if prefs.hide_nsfw == "on" %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<p id="settings_note"><b>Note:</b> settings are saved in browser cookies. Clearing your cookie data will reset them.</p>
|
||||
<input id="save" type="submit" value="Save">
|
||||
</form>
|
||||
<p id="settings_note"><b>Note:</b> settings are saved in browser cookies. Clearing your cookie data will reset them.</p>
|
||||
<input id="save" type="submit" value="Save">
|
||||
</form>
|
||||
{% if prefs.subs.len() > 0 %}
|
||||
<aside class="prefs">
|
||||
<p>Subscribed Subreddits</p>
|
||||
<ul id="settings_subs">
|
||||
{% for sub in prefs.subs %}
|
||||
<li>
|
||||
<span>{{ sub }}</span>
|
||||
<form action="/r/{{ sub }}/unsubscribe/?redirect=/settings" method="POST">
|
||||
<button class="unsubscribe">Unsubscribe</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</aside>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -11,6 +11,10 @@
|
||||
{% call utils::search(["/r/", sub.name.as_str()].concat(), "") %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subscriptions %}
|
||||
{% call utils::sub_list(sub.name.as_str(), "wide") %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<main>
|
||||
<div id="column_one">
|
||||
@ -121,6 +125,17 @@
|
||||
<div>{{ sub.members }}</div>
|
||||
<div>{{ sub.active }}</div>
|
||||
</div>
|
||||
<div id="sub_subscription">
|
||||
{% if prefs.subs.contains(sub.name) %}
|
||||
<form action="/r/{{ sub.name }}/unsubscribe" method="POST">
|
||||
<button class="unsubscribe">Unsubscribe</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/r/{{ sub.name }}/subscribe" method="POST">
|
||||
<button class="subscribe">Subscribe</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<details class="panel" id="sidebar">
|
||||
|
@ -7,6 +7,10 @@
|
||||
|
||||
{% block title %}{{ user.name.replace("u/", "") }} (u/{{ user.name }}) - Libreddit{% endblock %}
|
||||
|
||||
{% block subscriptions %}
|
||||
{% call utils::sub_list("") %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<main>
|
||||
<div id="column_one">
|
||||
|
@ -39,3 +39,16 @@
|
||||
{% else if flair_part.flair_part_type == "text" %}<span>{{ flair_part.value }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro sub_list(current) -%}
|
||||
{% if prefs.subs.len() > 0 %}
|
||||
<details id="subscriptions">
|
||||
<summary>Subscriptions</summary>
|
||||
<div id="sub_list">
|
||||
{% for sub in prefs.subs %}
|
||||
<a href="/r/{{ sub }}" {% if sub == current %}class="selected"{% endif %}>{{ sub }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
@ -10,6 +10,10 @@
|
||||
{% call utils::search(["/r/", sub.as_str()].concat(), "") %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subscriptions %}
|
||||
{% call utils::sub_list(sub.as_str()) %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<main>
|
||||
<div class="panel" id="column_one">
|
||||
|
Loading…
Reference in New Issue
Block a user