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};
const CSS: &str = include_str!("../templates/style.css");
pub async fn handle_index(
app: App,
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> {
Response::builder()
.status(StatusCode::OK)

View File

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

View File

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

View File

@ -5,14 +5,32 @@ use file_service::{FileHandle, FileId, ReadFileError};
pub fn auth(_message: Option<String>) -> build_html::HtmlPage {
build_html::HtmlPage::new()
.with_title("Authentication")
.with_stylesheet("/css")
.with_container(
Container::new(ContainerType::Div)
.with_attributes([("class", "authentication-page")])
.with_container(
Container::new(ContainerType::Div)
.with_attributes([("class", "authentication-form")])
.with_html(
Form::new()
.with_path("/auth")
.with_method("post")
.with_container(
Container::new(ContainerType::Div)
.with_html(Input::new("token", "token").with_id("for-token-input"))
.with_html(Label::new("for-token-input", "Authentication Token")),
.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 {
let mut page = build_html::HtmlPage::new()
.with_title("Admin list of files")
.with_stylesheet("/css")
.with_header(1, "Admin list of files")
.with_html(
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 {
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 {
@ -33,9 +67,6 @@ img {
.uploadform {
display: flex;
margin: 1em;
background-color: #e5f0fc;
border: 1px solid #449dfc;
border-radius: 5px;
padding: 1em;
}
@ -72,7 +103,8 @@ img {
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 {
font-size: xx-large;
}
@ -101,3 +133,4 @@ img {
width: 100%;
}
}
*/