Theming (#624)
* Theming - Custom CSS for blogs - Custom themes for instance - New dark theme - UI to choose your instance theme - Option to disable blog themes if you prefer to only have the instance theme - UI to choose a blog theme
This commit is contained in:
@@ -238,6 +238,7 @@ Then try to restart Plume
|
||||
routes::session::password_reset_request,
|
||||
routes::session::password_reset_form,
|
||||
routes::session::password_reset,
|
||||
routes::theme_files,
|
||||
routes::plume_static_files,
|
||||
routes::static_files,
|
||||
routes::tags::tag,
|
||||
|
||||
@@ -181,6 +181,7 @@ pub struct EditForm {
|
||||
pub summary: String,
|
||||
pub icon: Option<i32>,
|
||||
pub banner: Option<i32>,
|
||||
pub theme: Option<String>,
|
||||
}
|
||||
|
||||
#[get("/~/<name>/edit")]
|
||||
@@ -207,6 +208,7 @@ pub fn edit(name: String, rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
|
||||
summary: blog.summary.clone(),
|
||||
icon: blog.icon_id,
|
||||
banner: blog.banner_id,
|
||||
theme: blog.theme.clone(),
|
||||
},
|
||||
ValidationErrors::default()
|
||||
)))
|
||||
@@ -318,6 +320,7 @@ pub fn update(
|
||||
);
|
||||
blog.icon_id = form.icon;
|
||||
blog.banner_id = form.banner;
|
||||
blog.theme = form.theme.clone();
|
||||
blog.save_changes::<Blog>(&*conn)
|
||||
.expect("Couldn't save blog changes");
|
||||
Ok(Flash::success(
|
||||
|
||||
+46
-3
@@ -2,15 +2,20 @@
|
||||
use atom_syndication::{ContentBuilder, Entry, EntryBuilder, LinkBuilder, Person, PersonBuilder};
|
||||
use rocket::{
|
||||
http::{
|
||||
hyper::header::{CacheControl, CacheDirective},
|
||||
hyper::header::{CacheControl, CacheDirective, ETag, EntityTag},
|
||||
uri::{FromUriParam, Query},
|
||||
RawStr, Status,
|
||||
},
|
||||
request::{self, FromFormValue, FromRequest, Request},
|
||||
response::{Flash, NamedFile, Redirect},
|
||||
response::{self, Flash, NamedFile, Redirect, Responder, Response},
|
||||
Outcome,
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
collections::hash_map::DefaultHasher,
|
||||
hash::Hasher,
|
||||
io::Read,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use template_utils::Ructe;
|
||||
|
||||
use plume_models::{posts::Post, Connection};
|
||||
@@ -168,6 +173,44 @@ pub struct CachedFile {
|
||||
cache_control: CacheControl,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ThemeFile(NamedFile);
|
||||
|
||||
impl<'r> Responder<'r> for ThemeFile {
|
||||
fn respond_to(mut self, r: &Request) -> response::Result<'r> {
|
||||
let mut contents = String::new();
|
||||
self.0
|
||||
.read_to_string(&mut contents)
|
||||
.map_err(|_| Status::InternalServerError)?;
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
hasher.write(&contents.as_bytes());
|
||||
let etag = format!("{:x}", hasher.finish());
|
||||
|
||||
if r.headers()
|
||||
.get("If-None-Match")
|
||||
.any(|s| s[1..s.len() - 1] == etag)
|
||||
{
|
||||
Response::build()
|
||||
.status(Status::NotModified)
|
||||
.header(ETag(EntityTag::strong(etag)))
|
||||
.ok()
|
||||
} else {
|
||||
Response::build()
|
||||
.merge(self.0.respond_to(r)?)
|
||||
.header(ETag(EntityTag::strong(etag)))
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/static/cached/<_build_id>/css/<file..>", rank = 1)]
|
||||
pub fn theme_files(file: PathBuf, _build_id: &RawStr) -> Option<ThemeFile> {
|
||||
NamedFile::open(Path::new("static/").join(file))
|
||||
.ok()
|
||||
.map(ThemeFile)
|
||||
}
|
||||
|
||||
#[get("/static/cached/<_build_id>/<file..>", rank = 2)]
|
||||
pub fn plume_static_files(file: PathBuf, _build_id: &RawStr) -> Option<CachedFile> {
|
||||
static_files(file)
|
||||
|
||||
+25
-20
@@ -1,5 +1,6 @@
|
||||
use activitypub::{activity::Create, collection::OrderedCollection};
|
||||
use atom_syndication::{Entry, FeedBuilder};
|
||||
use diesel::SaveChangesDsl;
|
||||
use rocket::{
|
||||
http::{ContentType, Cookies},
|
||||
request::LenientForm,
|
||||
@@ -20,8 +21,10 @@ use plume_models::{
|
||||
headers::Headers,
|
||||
inbox::inbox as local_inbox,
|
||||
instance::Instance,
|
||||
medias::Media,
|
||||
posts::{LicensedArticle, Post},
|
||||
reshares::Reshare,
|
||||
safe_string::SafeString,
|
||||
users::*,
|
||||
Error, PlumeRocket,
|
||||
};
|
||||
@@ -342,7 +345,9 @@ pub fn edit(name: String, user: User, rockets: PlumeRocket) -> Result<Ructe, Err
|
||||
UpdateUserForm {
|
||||
display_name: user.display_name.clone(),
|
||||
email: user.email.clone().unwrap_or_default(),
|
||||
summary: user.summary,
|
||||
summary: user.summary.clone(),
|
||||
theme: user.preferred_theme,
|
||||
hide_custom_css: user.hide_custom_css,
|
||||
},
|
||||
ValidationErrors::default()
|
||||
)))
|
||||
@@ -367,34 +372,34 @@ pub struct UpdateUserForm {
|
||||
pub display_name: String,
|
||||
pub email: String,
|
||||
pub summary: String,
|
||||
pub theme: Option<String>,
|
||||
pub hide_custom_css: bool,
|
||||
}
|
||||
|
||||
#[put("/@/<_name>/edit", data = "<form>")]
|
||||
pub fn update(
|
||||
_name: String,
|
||||
conn: DbConn,
|
||||
user: User,
|
||||
mut user: User,
|
||||
form: LenientForm<UpdateUserForm>,
|
||||
intl: I18n,
|
||||
) -> Result<Flash<Redirect>, ErrorPage> {
|
||||
user.update(
|
||||
&*conn,
|
||||
if !form.display_name.is_empty() {
|
||||
form.display_name.clone()
|
||||
} else {
|
||||
user.display_name.clone()
|
||||
},
|
||||
if !form.email.is_empty() {
|
||||
form.email.clone()
|
||||
} else {
|
||||
user.email.clone().unwrap_or_default()
|
||||
},
|
||||
if !form.summary.is_empty() {
|
||||
form.summary.clone()
|
||||
} else {
|
||||
user.summary.to_string()
|
||||
},
|
||||
)?;
|
||||
user.display_name = form.display_name.clone();
|
||||
user.email = Some(form.email.clone());
|
||||
user.summary = form.summary.clone();
|
||||
user.summary_html = SafeString::new(
|
||||
&utils::md_to_html(
|
||||
&form.summary,
|
||||
None,
|
||||
false,
|
||||
Some(Media::get_media_processor(&conn, vec![&user])),
|
||||
)
|
||||
.0,
|
||||
);
|
||||
user.preferred_theme = form.theme.clone();
|
||||
user.hide_custom_css = form.hide_custom_css;
|
||||
let _: User = user.save_changes(&*conn).map_err(Error::from)?;
|
||||
|
||||
Ok(Flash::success(
|
||||
Redirect::to(uri!(me)),
|
||||
i18n!(intl.catalog, "Your profile has been updated."),
|
||||
|
||||
Reference in New Issue
Block a user