Compare commits

...

2 Commits

Author SHA1 Message Date
Savanni D'Gerinel b3f88a49aa Clean up the authentication page CSS
Center the authentication field in the authentication page. Provide some padding within the card, and arrange the form itself.
2023-10-06 19:05:24 -04:00
Savanni D'Gerinel 3f1316b3dd Serve the CSS file 2023-10-06 19:04:15 -04:00
5 changed files with 103 additions and 22 deletions

View File

@ -9,6 +9,8 @@ use warp::{filters::multipart::FormData, http::Response, multipart::Part};
use crate::{pages, App, AuthToken, FileId, FileInfo, ReadFileError, SessionToken}; use crate::{pages, App, AuthToken, FileId, FileInfo, ReadFileError, SessionToken};
const CSS: &str = include_str!("../templates/style.css");
pub async fn handle_index( pub async fn handle_index(
app: App, app: App,
token: Option<SessionToken>, token: Option<SessionToken>,
@ -22,6 +24,13 @@ pub async fn handle_index(
} }
} }
pub async fn handle_css() -> Result<Response<String>, Error> {
Response::builder()
.header("content-type", "text/css")
.status(StatusCode::OK)
.body(CSS.to_owned())
}
pub fn render_auth_page(message: Option<String>) -> Result<Response<String>, Error> { pub fn render_auth_page(message: Option<String>) -> Result<Response<String>, Error> {
Response::builder() Response::builder()
.status(StatusCode::OK) .status(StatusCode::OK)

View File

@ -2,6 +2,7 @@ use build_html::{self, Html, HtmlContainer};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Form { pub struct Form {
classes: Option<String>,
path: String, path: String,
method: String, method: String,
encoding: Option<String>, encoding: Option<String>,
@ -11,6 +12,7 @@ pub struct Form {
impl Form { impl Form {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
classes: None,
path: "/".to_owned(), path: "/".to_owned(),
method: "get".to_owned(), method: "get".to_owned(),
encoding: None, encoding: None,
@ -36,16 +38,21 @@ impl Form {
impl Html for Form { impl Html for Form {
fn to_html_string(&self) -> String { fn to_html_string(&self) -> String {
let classes = match self.classes {
Some(ref classes) => format!("class=\"{}\"", classes),
None => "".to_owned(),
};
let encoding = match self.encoding { let encoding = match self.encoding {
Some(ref encoding) => format!("enctype=\"{encoding}\"", encoding = encoding), Some(ref encoding) => format!("enctype=\"{encoding}\"", encoding = encoding),
None => "".to_owned(), None => "".to_owned(),
}; };
format!( format!(
"<form action=\"{path}\" method=\"{method}\" {encoding}>\n{elements}\n</form>\n", "<form action=\"{path}\" method=\"{method}\" {encoding} {classes}>\n{elements}\n</form>\n",
path = self.path, path = self.path,
method = self.method, method = self.method,
encoding = encoding, encoding = encoding,
elements = self.elements.to_html_string() elements = self.elements.to_html_string(),
classes = classes,
) )
} }
} }
@ -62,7 +69,7 @@ pub struct Input {
name: String, name: String,
id: Option<String>, id: Option<String>,
value: Option<String>, value: Option<String>,
content: Option<String>, attributes: Vec<(String, String)>,
} }
impl Html for Input { impl Html for Input {
@ -75,14 +82,20 @@ impl Html for Input {
Some(ref value) => format!("value=\"{}\"", value), Some(ref value) => format!("value=\"{}\"", value),
None => "".to_owned(), None => "".to_owned(),
}; };
let attrs = self
.attributes
.iter()
.map(|(key, value)| format!("{}=\"{}\"", key, value))
.collect::<Vec<String>>()
.join(" ");
format!( format!(
"<input type=\"{ty}\" name=\"{name}\" {id} {value}>{content}</input>\n", "<input type=\"{ty}\" name=\"{name}\" {id} {value} {attrs} />\n",
ty = self.ty, ty = self.ty,
name = self.name, name = self.name,
id = id, id = id,
value = value, value = value,
content = self.content.clone().unwrap_or("".to_owned()), attrs = attrs,
) )
} }
} }
@ -94,7 +107,7 @@ impl Input {
name: name.to_owned(), name: name.to_owned(),
id: None, id: None,
value: None, value: None,
content: None, attributes: vec![],
} }
} }
@ -108,12 +121,16 @@ impl Input {
self self
} }
/* pub fn with_attributes<'a>(
pub fn with_content(mut self, val: &str) -> Self { mut self,
self.content = Some(val.to_owned()); values: impl IntoIterator<Item = (&'a str, &'a str)>,
) -> Self {
self.attributes = values
.into_iter()
.map(|(a, b)| (a.to_owned(), b.to_owned()))
.collect::<Vec<(String, String)>>();
self self
} }
*/
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@ -1,7 +1,7 @@
extern crate log; extern crate log;
use cookie::Cookie; use cookie::Cookie;
use handlers::{file, handle_auth, handle_upload, thumbnail}; use handlers::{file, handle_auth, handle_css, handle_upload, thumbnail};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
convert::Infallible, convert::Infallible,
@ -119,6 +119,8 @@ pub async fn main() {
.and(maybe_with_session()) .and(maybe_with_session())
.then(handle_index); .then(handle_index);
let styles = warp::path!("css").and(warp::get()).then(handle_css);
let auth = warp::path!("auth") let auth = warp::path!("auth")
.and(warp::post()) .and(warp::post())
.and(with_app(app.clone())) .and(with_app(app.clone()))
@ -145,7 +147,8 @@ pub async fn main() {
.then(move |id, old_etags, app: App| file(app, id, old_etags)); .then(move |id, old_etags, app: App| file(app, id, old_etags));
let server = warp::serve( let server = warp::serve(
root.or(auth) root.or(styles)
.or(auth)
.or(upload_via_form) .or(upload_via_form)
.or(thumbnail) .or(thumbnail)
.or(file) .or(file)

View File

@ -5,14 +5,32 @@ use file_service::{FileHandle, FileId, ReadFileError};
pub fn auth(_message: Option<String>) -> build_html::HtmlPage { pub fn auth(_message: Option<String>) -> build_html::HtmlPage {
build_html::HtmlPage::new() build_html::HtmlPage::new()
.with_title("Authentication") .with_title("Authentication")
.with_html( .with_stylesheet("/css")
Form::new() .with_container(
.with_path("/auth") Container::new(ContainerType::Div)
.with_method("post") .with_attributes([("class", "authentication-page")])
.with_container( .with_container(
Container::new(ContainerType::Div) Container::new(ContainerType::Div)
.with_html(Input::new("token", "token").with_id("for-token-input")) .with_attributes([("class", "authentication-form")])
.with_html(Label::new("for-token-input", "Authentication Token")), .with_html(
Form::new()
.with_path("/auth")
.with_method("post")
.with_container(
Container::new(ContainerType::Div)
.with_attributes([("class", "authentication-form__label")])
.with_html(Label::new("for-token-input", "Authentication")),
)
.with_container(
Container::new(ContainerType::Div)
.with_attributes([("class", "authentication-form__input")])
.with_html(
Input::new("token", "token")
.with_id("for-token-input")
.with_attributes([("size", "50")]),
),
),
),
), ),
) )
} }
@ -20,6 +38,7 @@ pub fn auth(_message: Option<String>) -> build_html::HtmlPage {
pub fn gallery(handles: Vec<Result<FileHandle, ReadFileError>>) -> build_html::HtmlPage { pub fn gallery(handles: Vec<Result<FileHandle, ReadFileError>>) -> build_html::HtmlPage {
let mut page = build_html::HtmlPage::new() let mut page = build_html::HtmlPage::new()
.with_title("Admin list of files") .with_title("Admin list of files")
.with_stylesheet("/css")
.with_header(1, "Admin list of files") .with_header(1, "Admin list of files")
.with_html( .with_html(
Form::new() Form::new()

View File

@ -1,5 +1,39 @@
:root {
--main-bg-color: #e5f0fc;
--fg-color: #449dfc;
--px-4: 4px;
--px-8: 8px;
--px-12: 12px;
--hover-low: 4px 4px 4px gray;
}
body { body {
font-family: 'Ariel', sans-serif; font-family: 'Ariel', sans-serif;
background-color: var(--main-bg-color);
}
.authentication-page {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
.authentication-form {
border: 1px solid black;
border-radius: 5px;
border-shadow: var(--hover-low);
padding: var(--px-12);
}
.authentication-form__label {
margin: var(--px-4);
}
.authentication-form__input {
margin: var(--px-4);
} }
.files { .files {
@ -33,9 +67,6 @@ img {
.uploadform { .uploadform {
display: flex; display: flex;
margin: 1em; margin: 1em;
background-color: #e5f0fc;
border: 1px solid #449dfc;
border-radius: 5px;
padding: 1em; padding: 1em;
} }
@ -72,7 +103,8 @@ img {
outline: -webkit-focus-ring-color auto 5px; outline: -webkit-focus-ring-color auto 5px;
} }
@media screen and (max-width: 980px) { /* This is the screen width of a OnePlus 5t */ /*
@media screen and (max-width: 980px) { /* This is the screen width of a OnePlus 5t
body { body {
font-size: xx-large; font-size: xx-large;
} }
@ -101,3 +133,4 @@ img {
width: 100%; width: 100%;
} }
} }
*/