Add settings page, improve navigation
This commit is contained in:
parent
f268759bee
commit
46e45e8b68
|
@ -23,7 +23,7 @@ hyaenidae-profiles = { version = "0.1.0", path = "../profiles" }
|
|||
hyaenidae-toolkit = { version = "0.1.0", path = "../toolkit" }
|
||||
log = "0.4"
|
||||
mime = "0.3.16"
|
||||
minify-html = "0.3.9"
|
||||
minify-html = "0.4.0"
|
||||
rand = "0.7"
|
||||
once_cell = "1.5.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
|
|
@ -1,8 +1,53 @@
|
|||
|
||||
.error {
|
||||
color: #c92a60;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.top-bar__mobile {
|
||||
display: none;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #333;
|
||||
padding: 8px 16px;
|
||||
border-bottom: 3px solid #555;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #222;
|
||||
padding: 8px 16px;
|
||||
border-bottom: 2px solid #999;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.home-content {
|
||||
padding: 32px 0;
|
||||
}
|
||||
|
||||
.account-page {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
@ -13,6 +58,10 @@
|
|||
color: #f5f5f5;
|
||||
overflow: hidden;
|
||||
|
||||
&.card-top {
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
&.standalone {
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
|
@ -118,6 +167,13 @@
|
|||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.top-bar {
|
||||
display: none;
|
||||
}
|
||||
.top-bar__mobile {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.columns {
|
||||
flex-direction: column;
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ use crate::{
|
|||
};
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Scope};
|
||||
use hyaenidae_accounts::{
|
||||
Authenticated, CookiesArgs, CookiesPageArgs, DeleteUserArgs, DeleteUserPageArgs, LoginArgs,
|
||||
LoginPageArgs, LogoutArgs, Pages as _, RegisterArgs, RegisterPageArgs, UpdatePasswordArgs,
|
||||
UpdatePasswordPageArgs, UpdateUsernameArgs, UpdateUsernamePageArgs,
|
||||
CookiesArgs, CookiesPageArgs, DeleteUserArgs, DeleteUserPageArgs, LoginArgs, LoginPageArgs,
|
||||
LogoutArgs, LogoutState, Pages as _, RegisterArgs, RegisterPageArgs, UpdatePasswordArgs,
|
||||
UpdatePasswordPageArgs, UpdateUsernameArgs, UpdateUsernamePageArgs, User,
|
||||
};
|
||||
|
||||
pub(crate) struct Pages;
|
||||
|
@ -109,7 +109,7 @@ async fn cookies_page(
|
|||
};
|
||||
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::cookies(cursor, &cookie_state)
|
||||
crate::templates::session::cookies(cursor, &cookie_state)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ async fn login_page(
|
|||
};
|
||||
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::login(cursor, &login_state)
|
||||
crate::templates::session::login(cursor, &login_state)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ async fn login(args: LoginArgs, state: web::Data<State>) -> Result<HttpResponse,
|
|||
};
|
||||
|
||||
rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::login(cursor, &login_state)
|
||||
crate::templates::session::login(cursor, &login_state)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ async fn register_page(
|
|||
};
|
||||
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::register(cursor, ®ister_state)
|
||||
crate::templates::session::register(cursor, ®ister_state)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ async fn register(args: RegisterArgs, state: web::Data<State>) -> Result<HttpRes
|
|||
};
|
||||
|
||||
rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::register(cursor, ®ister_state)
|
||||
crate::templates::session::register(cursor, ®ister_state)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -179,15 +179,15 @@ async fn logout(args: LogoutArgs) -> HttpResponse {
|
|||
async fn account_page(
|
||||
uname_args: UpdateUsernamePageArgs,
|
||||
pass_args: UpdatePasswordPageArgs,
|
||||
authenticated: Authenticated,
|
||||
user: User,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let uname_state = hyaenidae_accounts::update_username_page(uname_args);
|
||||
let pass_state = hyaenidae_accounts::update_password_page(pass_args);
|
||||
let user = authenticated.user();
|
||||
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::account(cursor, &user, &uname_state, &pass_state)
|
||||
crate::templates::session::account(cursor, &user, &uname_state, &pass_state, logout)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -201,7 +201,8 @@ async fn to_account() -> HttpResponse {
|
|||
async fn update_username(
|
||||
uname_args: UpdateUsernameArgs,
|
||||
pass_args: UpdatePasswordPageArgs,
|
||||
authenticated: Authenticated,
|
||||
user: User,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let uname_state = match hyaenidae_accounts::update_username(uname_args)
|
||||
|
@ -212,10 +213,9 @@ async fn update_username(
|
|||
Err(res) => return Ok(res),
|
||||
};
|
||||
let pass_state = hyaenidae_accounts::update_password_page(pass_args);
|
||||
let user = authenticated.user();
|
||||
|
||||
rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::account(cursor, &user, &uname_state, &pass_state)
|
||||
crate::templates::session::account(cursor, &user, &uname_state, &pass_state, logout)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -223,7 +223,8 @@ async fn update_username(
|
|||
async fn update_password(
|
||||
uname_args: UpdateUsernamePageArgs,
|
||||
pass_args: UpdatePasswordArgs,
|
||||
authenticated: Authenticated,
|
||||
user: User,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let uname_state = hyaenidae_accounts::update_username_page(uname_args);
|
||||
|
@ -234,16 +235,16 @@ async fn update_password(
|
|||
Ok(state) => state,
|
||||
Err(res) => return Ok(res),
|
||||
};
|
||||
let user = authenticated.user();
|
||||
|
||||
rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::account(cursor, &user, &uname_state, &pass_state)
|
||||
crate::templates::session::account(cursor, &user, &uname_state, &pass_state, logout)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
async fn delete_account_page(
|
||||
args: DeleteUserPageArgs,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let delete_state = match hyaenidae_accounts::delete_user_page(args) {
|
||||
|
@ -252,13 +253,14 @@ async fn delete_account_page(
|
|||
};
|
||||
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::delete_account(cursor, &delete_state)
|
||||
crate::templates::session::delete_account(cursor, &delete_state, logout)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
async fn delete_account(
|
||||
args: DeleteUserArgs,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let delete_state = match hyaenidae_accounts::delete_user(args).await.state(&state)? {
|
||||
|
@ -267,7 +269,7 @@ async fn delete_account(
|
|||
};
|
||||
|
||||
rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::delete_account(cursor, &delete_state)
|
||||
crate::templates::session::delete_account(cursor, &delete_state, logout)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
|
145
server/src/back.rs
Normal file
145
server/src/back.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
use actix_session::{Session, UserSession};
|
||||
use actix_web::{
|
||||
dev::{Payload, Service, ServiceRequest, ServiceResponse, Transform},
|
||||
FromRequest, HttpRequest, HttpResponse, Responder,
|
||||
};
|
||||
use futures_core::future::LocalBoxFuture;
|
||||
use futures_util::future::{ok, Ready};
|
||||
use hyaenidae_accounts::AcceptedCookies;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Back {
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub(crate) struct BackPage;
|
||||
pub(crate) struct BackMiddleware<S>(S);
|
||||
|
||||
impl FromRequest for Back {
|
||||
type Config = ();
|
||||
type Error = actix_web::Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
|
||||
|
||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||
let session = req.get_session();
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(Back::data(&session)?.unwrap_or(Back {
|
||||
path: "/".to_owned(),
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Back {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.path, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Responder for Back {
|
||||
type Error = actix_web::Error;
|
||||
type Future = Ready<Result<HttpResponse, Self::Error>>;
|
||||
|
||||
fn respond_to(self, _: &HttpRequest) -> Self::Future {
|
||||
ok(HttpResponse::SeeOther()
|
||||
.header("Location", self.path)
|
||||
.finish())
|
||||
}
|
||||
}
|
||||
|
||||
impl Back {
|
||||
fn set_data(path: String, session: &Session) -> Result<(), actix_web::Error> {
|
||||
session.set("back-data", Back { path })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn data(session: &Session) -> Result<Option<Self>, actix_web::Error> {
|
||||
Ok(session.get("back-data")?)
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Back {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B> Transform<S> for BackPage
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
type Error = S::Error;
|
||||
type InitError = ();
|
||||
type Transform = BackMiddleware<S>;
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ok(BackMiddleware(service))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B> Service for BackMiddleware<S>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
type Error = S::Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn poll_ready(
|
||||
&mut self,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Result<(), Self::Error>> {
|
||||
self.0.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: S::Request) -> Self::Future {
|
||||
let session = req.get_session();
|
||||
|
||||
let path = req
|
||||
.uri()
|
||||
.path_and_query()
|
||||
.map(|paq| paq.as_str())
|
||||
.unwrap_or("/")
|
||||
.to_owned();
|
||||
|
||||
let (req, pl) = req.into_parts();
|
||||
let cookie_fut = AcceptedCookies::extract(&req);
|
||||
let req = ServiceRequest::from_parts(req, pl)
|
||||
.map_err(|_| ())
|
||||
.expect("Request has been cloned");
|
||||
|
||||
let fut = self.0.call(req);
|
||||
|
||||
Box::pin(async move {
|
||||
if let Err(_) = cookie_fut.await {
|
||||
return fut.await;
|
||||
}
|
||||
|
||||
match fut.await {
|
||||
Ok(response) => {
|
||||
if let Some(content_type) = response.headers().get("Content-Type") {
|
||||
if let Ok(s) = content_type.to_str() {
|
||||
if s == "text/html" {
|
||||
Back::set_data(path, &session)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(response)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -5,20 +5,22 @@ use actix_web::{
|
|||
middleware::{Compress, Logger},
|
||||
web, App, HttpResponse, HttpServer,
|
||||
};
|
||||
use hyaenidae_accounts::{Auth, Authenticated};
|
||||
use hyaenidae_accounts::{Auth, LogoutState, User};
|
||||
use sled::Db;
|
||||
use std::{fmt, time::SystemTime};
|
||||
use structopt::StructOpt;
|
||||
|
||||
mod accounts;
|
||||
mod apub;
|
||||
mod back;
|
||||
mod error;
|
||||
mod images;
|
||||
mod jobs;
|
||||
mod profiles;
|
||||
|
||||
use back::{Back, BackPage};
|
||||
use error::{Error, OptionExt, ResultExt, StateError};
|
||||
use profiles::CurrentProfile;
|
||||
use profiles::{CurrentProfile, Profile};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|
||||
|
||||
|
@ -87,17 +89,20 @@ async fn main() -> anyhow::Result<()> {
|
|||
let accounts_state = accounts_state.clone();
|
||||
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.wrap(Compress::default())
|
||||
.wrap(BackPage)
|
||||
.wrap(CurrentProfile(state.clone()))
|
||||
.data(state)
|
||||
.wrap(Auth(accounts_state.clone()))
|
||||
.data(accounts_state)
|
||||
.data(SystemTime::now())
|
||||
.wrap(hyaenidae_accounts::cookie_middlware(&accounts_config))
|
||||
.wrap(Compress::default())
|
||||
.wrap(Logger::default())
|
||||
.route("/", web::get().to(home))
|
||||
.route("/nav", web::get().to(nav_page))
|
||||
.route("/404", web::get().to(not_found))
|
||||
.route("/500", web::get().to(serve_error))
|
||||
.route("/settings", web::get().to(settings))
|
||||
.route("/toolkit/{name}", web::get().to(toolkit))
|
||||
.route("/static/{name}", web::get().to(statics))
|
||||
.service(accounts::scope())
|
||||
|
@ -271,20 +276,29 @@ async fn statics(path: web::Path<String>, startup: web::Data<SystemTime>) -> Htt
|
|||
|
||||
async fn home(
|
||||
state: web::Data<State>,
|
||||
authenticated: Option<Authenticated>,
|
||||
logout_args: Option<hyaenidae_accounts::LogoutPageArgs>,
|
||||
user: Option<User>,
|
||||
profile: Option<Profile>,
|
||||
logout: Option<LogoutState>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let logout_opt = logout_args.map(|args| hyaenidae_accounts::logout_page(args));
|
||||
let authenticated_opt = authenticated.and_then(|a| logout_opt.map(|l| (a.user(), l)));
|
||||
|
||||
if user.is_some() && profile.is_none() {
|
||||
return Ok(profiles::to_create());
|
||||
}
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
templates::index(cursor, authenticated_opt)
|
||||
templates::index(cursor, &logout, &profile)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
fn to_404() -> HttpResponse {
|
||||
HttpResponse::SeeOther().header("Location", "/404").finish()
|
||||
redirect("/404")
|
||||
}
|
||||
|
||||
fn to_home() -> HttpResponse {
|
||||
redirect("/")
|
||||
}
|
||||
|
||||
fn redirect(path: &str) -> HttpResponse {
|
||||
HttpResponse::SeeOther().header("Location", path).finish()
|
||||
}
|
||||
|
||||
async fn not_found(state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
||||
|
@ -301,17 +315,42 @@ async fn serve_error(state: web::Data<State>) -> Result<HttpResponse, StateError
|
|||
.state(&state)
|
||||
}
|
||||
|
||||
async fn nav_page(
|
||||
logout: Option<LogoutState>,
|
||||
back: Back,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
templates::nav::page(cursor, &logout, &back)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
async fn settings(
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
rendered(HttpResponse::Ok(), |cursor| {
|
||||
templates::settings(cursor, logout)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
fn rendered(
|
||||
mut builder: HttpResponseBuilder,
|
||||
f: impl FnOnce(&mut std::io::Cursor<Vec<u8>>) -> std::io::Result<()>,
|
||||
f: impl FnOnce(&mut std::io::Cursor<&mut Vec<u8>>) -> std::io::Result<()>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let mut cursor = std::io::Cursor::new(vec![]);
|
||||
(f)(&mut cursor).map_err(Error::Render)?;
|
||||
let mut html = cursor.into_inner();
|
||||
let len = minify_html::in_place(&mut html, &minify_html::Cfg { minify_js: false })?;
|
||||
html.truncate(len);
|
||||
let mut bytes = vec![];
|
||||
(f)(&mut std::io::Cursor::new(&mut bytes)).map_err(Error::Render)?;
|
||||
minify_html::truncate(
|
||||
&mut bytes,
|
||||
&minify_html::Cfg {
|
||||
minify_js: false,
|
||||
minify_css: false,
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(builder
|
||||
.content_type(mime::TEXT_HTML.essence_str())
|
||||
.body(html))
|
||||
.body(bytes))
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ pub(crate) struct ProfileMiddleware<S>(State, S);
|
|||
|
||||
#[derive(Clone)]
|
||||
struct ProfileExtractor(Rc<RefCell<Option<Profile>>>, Rc<Cell<bool>>, Rc<Event>);
|
||||
struct ProfileDropGuard(Rc<Event>);
|
||||
struct ProfileDropGuard(Rc<Event>, Rc<Cell<bool>>);
|
||||
|
||||
fn profile_extractor() -> (ProfileExtractor, ProfileDropGuard) {
|
||||
let event = Rc::new(Event::new());
|
||||
|
@ -122,13 +122,14 @@ fn profile_extractor() -> (ProfileExtractor, ProfileDropGuard) {
|
|||
let flag = Rc::new(Cell::new(false));
|
||||
|
||||
(
|
||||
ProfileExtractor(state, flag, Rc::clone(&event)),
|
||||
ProfileDropGuard(event),
|
||||
ProfileExtractor(state, Rc::clone(&flag), Rc::clone(&event)),
|
||||
ProfileDropGuard(event, flag),
|
||||
)
|
||||
}
|
||||
|
||||
impl Drop for ProfileDropGuard {
|
||||
fn drop(&mut self) {
|
||||
self.1.set(true);
|
||||
self.0.notify(usize::MAX);
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +189,7 @@ where
|
|||
let user_id = if let Ok(auth) = user_fut.await {
|
||||
auth.user().id()
|
||||
} else {
|
||||
drop(drop_guard);
|
||||
return fut.await;
|
||||
};
|
||||
|
||||
|
@ -210,8 +212,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
extractor.1.set(true);
|
||||
drop(drop_guard);
|
||||
|
||||
fut.await
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
};
|
||||
use actix_session::Session;
|
||||
use actix_web::{dev::Payload, web, HttpRequest, HttpResponse, Scope};
|
||||
use hyaenidae_accounts::Authenticated;
|
||||
use hyaenidae_accounts::{LogoutState, User};
|
||||
use uuid::Uuid;
|
||||
|
||||
mod middleware;
|
||||
|
@ -75,7 +75,7 @@ pub(super) fn scope() -> Scope {
|
|||
)
|
||||
}
|
||||
|
||||
fn to_create() -> HttpResponse {
|
||||
pub(super) fn to_create() -> HttpResponse {
|
||||
redirect("/profiles/create/handle")
|
||||
}
|
||||
|
||||
|
@ -269,25 +269,27 @@ async fn profiles() -> HttpResponse {
|
|||
|
||||
async fn current_profile(
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_profile(profile).await.state(&state)
|
||||
do_profile(profile, logout).await.state(&state)
|
||||
}
|
||||
|
||||
async fn do_profile(profile: Profile) -> Result<HttpResponse, Error> {
|
||||
async fn do_profile(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
|
||||
let profile_state = ProfileState::new(profile);
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::current(cursor, &profile_state)
|
||||
crate::templates::profiles::current(cursor, &profile_state, logout)
|
||||
})
|
||||
}
|
||||
|
||||
async fn update_bio(
|
||||
form: web::Form<BioForm>,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_update_bio(form.into_inner(), profile, &state)
|
||||
do_update_bio(form.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -295,6 +297,7 @@ async fn update_bio(
|
|||
async fn do_update_bio(
|
||||
form: BioForm,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let display_name = form.display_name.clone();
|
||||
|
@ -321,7 +324,7 @@ async fn do_update_bio(
|
|||
};
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::current(cursor, &state)
|
||||
crate::templates::profiles::current(cursor, &state, logout)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -329,9 +332,10 @@ async fn update_icon(
|
|||
request: HttpRequest,
|
||||
payload: web::Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_update_icon(request, payload.into_inner(), profile, &state)
|
||||
do_update_icon(request, payload.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -340,6 +344,7 @@ async fn do_update_icon(
|
|||
request: HttpRequest,
|
||||
payload: Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let res = state.profiles.upload_image(request, payload).await;
|
||||
|
@ -366,7 +371,7 @@ async fn do_update_icon(
|
|||
state.icon_error(&error);
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::current(cursor, &state)
|
||||
crate::templates::profiles::current(cursor, &state, logout)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -374,9 +379,10 @@ async fn update_banner(
|
|||
request: HttpRequest,
|
||||
payload: web::Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_update_banner(request, payload.into_inner(), profile, &state)
|
||||
do_update_banner(request, payload.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -385,6 +391,7 @@ async fn do_update_banner(
|
|||
request: HttpRequest,
|
||||
payload: Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let res = state.profiles.upload_image(request, payload).await;
|
||||
|
@ -411,16 +418,17 @@ async fn do_update_banner(
|
|||
state.banner_error(&error);
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::current(cursor, &state)
|
||||
crate::templates::profiles::current(cursor, &state, logout)
|
||||
})
|
||||
}
|
||||
|
||||
async fn update_require_login(
|
||||
form: web::Form<RequireLoginForm>,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_update_require_login(form.into_inner(), profile, &state)
|
||||
do_update_require_login(form.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -428,6 +436,7 @@ async fn update_require_login(
|
|||
async fn do_update_require_login(
|
||||
form: RequireLoginForm,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let login_required = form.require_login.is_some();
|
||||
|
@ -452,7 +461,7 @@ async fn do_update_require_login(
|
|||
};
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::current(cursor, &state)
|
||||
crate::templates::profiles::current(cursor, &state, logout)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -462,15 +471,20 @@ struct ChangeProfileForm {
|
|||
}
|
||||
|
||||
async fn change_profile_page(
|
||||
auth: Authenticated,
|
||||
user: User,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let user_id = auth.user().id();
|
||||
|
||||
do_change_profile_page(user_id, &state).await.state(&state)
|
||||
do_change_profile_page(user.id(), logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
async fn do_change_profile_page(user_id: Uuid, state: &State) -> Result<HttpResponse, Error> {
|
||||
async fn do_change_profile_page(
|
||||
user_id: Uuid,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let profiles = state
|
||||
.profiles
|
||||
.store
|
||||
|
@ -480,18 +494,17 @@ async fn do_change_profile_page(user_id: Uuid, state: &State) -> Result<HttpResp
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::list(cursor, &profiles)
|
||||
crate::templates::profiles::list(cursor, &profiles, logout)
|
||||
})
|
||||
}
|
||||
|
||||
async fn change_profile(
|
||||
auth: Authenticated,
|
||||
user: User,
|
||||
session: Session,
|
||||
form: web::Form<ChangeProfileForm>,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let user_id = auth.user().id();
|
||||
do_change_profile(user_id, session, form.into_inner(), &state)
|
||||
do_change_profile(user.id(), session, form.into_inner(), &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -511,7 +524,7 @@ async fn do_change_profile(
|
|||
.ok()
|
||||
.req()?;
|
||||
|
||||
Ok(to_current_profile())
|
||||
Ok(crate::to_home())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
|
@ -519,34 +532,39 @@ pub struct HandleForm {
|
|||
pub(crate) handle: String,
|
||||
}
|
||||
|
||||
async fn new_handle(_: Authenticated, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
||||
async fn new_handle(
|
||||
_: User,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
let mut handle_input = hyaenidae_toolkit::TextInput::new("handle");
|
||||
handle_input.placeholder("Handle").title("Handle");
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::create::handle(cursor, &handle_input)
|
||||
crate::templates::profiles::create::handle(cursor, &handle_input, logout)
|
||||
})
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
async fn create_handle(
|
||||
auth: Authenticated,
|
||||
user: User,
|
||||
form: web::Form<HandleForm>,
|
||||
session: Session,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_create_handle(auth, form.into_inner(), session, &state)
|
||||
do_create_handle(user.id(), form.into_inner(), session, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
||||
async fn do_create_handle(
|
||||
auth: Authenticated,
|
||||
user_id: Uuid,
|
||||
form: HandleForm,
|
||||
session: Session,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let user_id = auth.user().id();
|
||||
let domain = state.domain.clone();
|
||||
let handle = form.handle.clone();
|
||||
|
||||
|
@ -585,7 +603,7 @@ async fn do_create_handle(
|
|||
.error_opt(error);
|
||||
|
||||
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::profiles::create::handle(cursor, &handle_input)
|
||||
crate::templates::profiles::create::handle(cursor, &handle_input, logout)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -595,11 +613,15 @@ pub struct BioForm {
|
|||
pub(crate) description: String,
|
||||
}
|
||||
|
||||
async fn new_bio(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
||||
do_new_bio(profile).await.state(&state)
|
||||
async fn new_bio(
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_new_bio(profile, logout).await.state(&state)
|
||||
}
|
||||
|
||||
async fn do_new_bio(profile: Profile) -> Result<HttpResponse, Error> {
|
||||
async fn do_new_bio(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
|
||||
let mut display_name = hyaenidae_toolkit::TextInput::new("display_name");
|
||||
display_name
|
||||
.title("Display Name")
|
||||
|
@ -618,16 +640,23 @@ async fn do_new_bio(profile: Profile) -> Result<HttpResponse, Error> {
|
|||
}
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::create::bio(cursor, &display_name, &description, &profile)
|
||||
crate::templates::profiles::create::bio(
|
||||
cursor,
|
||||
&display_name,
|
||||
&description,
|
||||
&profile,
|
||||
logout,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async fn create_bio(
|
||||
form: web::Form<BioForm>,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_create_bio(form.into_inner(), profile, &state)
|
||||
do_create_bio(form.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -635,6 +664,7 @@ async fn create_bio(
|
|||
async fn do_create_bio(
|
||||
form: BioForm,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let display_name = form.display_name.clone();
|
||||
|
@ -671,21 +701,31 @@ async fn do_create_bio(
|
|||
|
||||
let profile = profile.refresh(state)?;
|
||||
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::profiles::create::bio(cursor, &display_name, &description, &profile)
|
||||
crate::templates::profiles::create::bio(
|
||||
cursor,
|
||||
&display_name,
|
||||
&description,
|
||||
&profile,
|
||||
logout,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async fn new_icon(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
||||
do_new_icon(profile).await.state(&state)
|
||||
async fn new_icon(
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_new_icon(profile, logout).await.state(&state)
|
||||
}
|
||||
|
||||
async fn do_new_icon(profile: Profile) -> Result<HttpResponse, Error> {
|
||||
async fn do_new_icon(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
|
||||
let mut icon_input =
|
||||
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Icon", "icon-input");
|
||||
icon_input.accept(ACCEPT_TYPES);
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::create::icon(cursor, &icon_input, None, &profile)
|
||||
crate::templates::profiles::create::icon(cursor, &icon_input, None, &profile, logout)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -693,9 +733,10 @@ async fn create_icon(
|
|||
request: HttpRequest,
|
||||
payload: web::Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_create_icon(request, payload.into_inner(), profile, &state)
|
||||
do_create_icon(request, payload.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -704,6 +745,7 @@ async fn do_create_icon(
|
|||
request: HttpRequest,
|
||||
payload: Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let res = state.profiles.upload_image(request, payload).await;
|
||||
|
@ -732,21 +774,25 @@ async fn do_create_icon(
|
|||
|
||||
let profile = profile.refresh(state)?;
|
||||
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::profiles::create::icon(cursor, &icon_input, error, &profile)
|
||||
crate::templates::profiles::create::icon(cursor, &icon_input, error, &profile, logout)
|
||||
})
|
||||
}
|
||||
|
||||
async fn new_banner(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
||||
do_new_banner(profile).await.state(&state)
|
||||
async fn new_banner(
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_new_banner(profile, logout).await.state(&state)
|
||||
}
|
||||
|
||||
async fn do_new_banner(profile: Profile) -> Result<HttpResponse, Error> {
|
||||
async fn do_new_banner(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
|
||||
let mut banner_input =
|
||||
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Banner", "banner-input");
|
||||
banner_input.accept(ACCEPT_TYPES);
|
||||
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::create::banner(cursor, &banner_input, None, &profile)
|
||||
crate::templates::profiles::create::banner(cursor, &banner_input, None, &profile, logout)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -754,9 +800,10 @@ async fn create_banner(
|
|||
request: HttpRequest,
|
||||
payload: web::Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_create_banner(request, payload.into_inner(), profile, &state)
|
||||
do_create_banner(request, payload.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -765,6 +812,7 @@ async fn do_create_banner(
|
|||
request: HttpRequest,
|
||||
payload: Payload,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let res = state.profiles.upload_image(request, payload).await;
|
||||
|
@ -793,7 +841,7 @@ async fn do_create_banner(
|
|||
|
||||
let profile = profile.refresh(state)?;
|
||||
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
||||
crate::templates::profiles::create::banner(cursor, &banner_input, error, &profile)
|
||||
crate::templates::profiles::create::banner(cursor, &banner_input, error, &profile, logout)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -804,18 +852,23 @@ struct RequireLoginForm {
|
|||
|
||||
async fn new_require_login(
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_new_require_login(profile).await.state(&state)
|
||||
do_new_require_login(profile, logout).await.state(&state)
|
||||
}
|
||||
|
||||
async fn do_new_require_login(profile: Profile) -> Result<HttpResponse, Error> {
|
||||
async fn do_new_require_login(
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::create::require_login(
|
||||
cursor,
|
||||
profile.inner.login_required(),
|
||||
None,
|
||||
&profile,
|
||||
logout,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -823,9 +876,10 @@ async fn do_new_require_login(profile: Profile) -> Result<HttpResponse, Error> {
|
|||
async fn create_require_login(
|
||||
form: web::Form<RequireLoginForm>,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_create_require_login(form.into_inner(), profile, &state)
|
||||
do_create_require_login(form.into_inner(), profile, logout, &state)
|
||||
.await
|
||||
.state(&state)
|
||||
}
|
||||
|
@ -833,6 +887,7 @@ async fn create_require_login(
|
|||
async fn do_create_require_login(
|
||||
form: RequireLoginForm,
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: &State,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
||||
|
@ -857,16 +912,21 @@ async fn do_create_require_login(
|
|||
form.require_login.is_some(),
|
||||
error,
|
||||
&profile,
|
||||
logout,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async fn done(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
||||
do_done(profile).await.state(&state)
|
||||
async fn done(
|
||||
profile: Profile,
|
||||
logout: LogoutState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, StateError> {
|
||||
do_done(profile, logout).await.state(&state)
|
||||
}
|
||||
|
||||
async fn do_done(profile: Profile) -> Result<HttpResponse, Error> {
|
||||
async fn do_done(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
|
||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||
crate::templates::profiles::create::done(cursor, &profile)
|
||||
crate::templates::profiles::create::done(cursor, &profile, logout)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
@use super::layout;
|
||||
@use hyaenidae_accounts::{templates::{update_password, update_username}, UpdatePasswordState, UpdateUsernameState, User};
|
||||
@use hyaenidae_toolkit::{templates::{button, card, card_body, link}, Button, Card, Link};
|
||||
|
||||
@(user: &User, uname_state: &UpdateUsernameState, pass_state: &UpdatePasswordState)
|
||||
|
||||
@:layout(&format!("Account Settings for {}", user.username()), "Update account information", {}, {
|
||||
@:update_username(Card::full_width().classes(&["account-page"]), uname_state)
|
||||
@:update_password(Card::full_width().classes(&["account-page"]), pass_state)
|
||||
@:card(Card::full_width().classes(&["account-page"]), { Danger }, {
|
||||
@:card_body({
|
||||
@:button(Button::primary("Delete Account").href("/session/account/delete"))
|
||||
})
|
||||
})
|
||||
@:card(Card::full_width().classes(&["account-page"]), { Nav }, {
|
||||
@:card_body({
|
||||
@:link(&Link::current_tab("/"), { Return Home })
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,9 +0,0 @@
|
|||
@use super::layout;
|
||||
@use hyaenidae_accounts::{templates::delete_user, DeleteUserState};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(state: &DeleteUserState)
|
||||
|
||||
@:layout("Delete Account", "Are you sure you want to delete your account?", {}, {
|
||||
@:delete_user(&Card::full_width(), state)
|
||||
})
|
|
@ -1,12 +1,11 @@
|
|||
@use super::layout;
|
||||
@use hyaenidae_toolkit::{templates::{card, card_body, link}, Card, Link};
|
||||
@use crate::templates::layouts::main;
|
||||
@use hyaenidae_toolkit::{templates::{card, card_body, card_title, link}, Card, Link};
|
||||
|
||||
@(error: String)
|
||||
|
||||
@:layout("Error", "There was an error processing your request", {}, {
|
||||
@:main("Error", "There was an error processing your request", {}, {
|
||||
@:card(&Card::full_width(), {
|
||||
There was an error processing your request
|
||||
}, {
|
||||
@:card_title({ There was an error processing your request })
|
||||
@:card_body({ @error })
|
||||
@:card_body({
|
||||
@:link(&Link::current_tab("/"), { Return Home })
|
||||
|
|
|
@ -1,28 +1,22 @@
|
|||
@use super::layout;
|
||||
@use hyaenidae_accounts::{LogoutState, User};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, link}, Button, Card, Link};
|
||||
@use crate::{profiles::Profile, templates::layouts::home};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{card, card_body, card_title}, Card};
|
||||
|
||||
@(logout_opt: Option<(User, LogoutState)>)
|
||||
@(logout_opt: &Option<LogoutState>, profile: &Option<Profile>)
|
||||
|
||||
@:layout("Hyaenidae", "A simple website", {}, {
|
||||
@if let Some((user, logout_state)) = logout_opt {
|
||||
@:card(&Card::full_width(), { Welcome, @user.username() }, {
|
||||
@:home("Hyaenidae", "A simple website", logout_opt, {}, {
|
||||
@if let Some(profile) = profile {
|
||||
@:card(&Card::full_width(), {
|
||||
@:card_title({ Welcome, @profile.name() })
|
||||
@:card_body({
|
||||
@:link(&Link::current_tab("/session/account"), { Account Settings })
|
||||
})
|
||||
@:card_body({
|
||||
@:button_group(&[
|
||||
Button::primary_outline("Profile").href("/profiles"),
|
||||
logout_state.button(&Button::primary_outline("Logout"))
|
||||
])
|
||||
<span>e</span>
|
||||
})
|
||||
})
|
||||
} else {
|
||||
@:card(&Card::full_width(), { Home... }, {
|
||||
@:card(&Card::full_width(), {
|
||||
@:card_title({ Home })
|
||||
@:card_body({
|
||||
@:button_group(&[
|
||||
Button::primary_outline("Login").href("/session/auth/login")
|
||||
])
|
||||
<span>e</span>
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
26
server/templates/layouts/home.rs.html
Normal file
26
server/templates/layouts/home.rs.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
@use crate::templates::{layouts::root, nav::nav};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{centered, link}, Link};
|
||||
|
||||
@(title: &str, description: &str, logout_opt: &Option<LogoutState>, head: Content, body: Content)
|
||||
|
||||
@:root(title, description, { @:head() }, {
|
||||
<div class="top-bar">
|
||||
<div class="top-bar--left">
|
||||
<h2>@title</h2>
|
||||
</div>
|
||||
<div class="top-bar--right">
|
||||
@:nav(logout_opt)
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-bar__mobile">
|
||||
<h2>@title</h2>
|
||||
<h3>@:link(&Link::current_tab("/nav"), { Nav })</h3>
|
||||
</div>
|
||||
<div class="home-content">
|
||||
@:centered(false, {
|
||||
@:body()
|
||||
})
|
||||
</div>
|
||||
})
|
||||
|
14
server/templates/layouts/main.rs.html
Normal file
14
server/templates/layouts/main.rs.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
@use crate::templates::layouts::root;
|
||||
@use hyaenidae_toolkit::templates::centered;
|
||||
|
||||
@(title: &str, description: &str, head: Content, body: Content)
|
||||
|
||||
@:root(title, description, { @:head() }, {
|
||||
@:centered(true, {
|
||||
<h2 class="title">@title</h2>
|
||||
<p class="description">@description</p>
|
||||
})
|
||||
@:centered(false, {
|
||||
@:body()
|
||||
})
|
||||
})
|
|
@ -1,5 +1,5 @@
|
|||
@use crate::{toolkit_path, statics_path, templates::statics::layout_css};
|
||||
@use hyaenidae_toolkit::templates::{centered, statics::toolkit_css};
|
||||
@use hyaenidae_toolkit::templates::statics::toolkit_css;
|
||||
|
||||
@(title: &str, description: &str, head: Content, body: Content)
|
||||
|
||||
|
@ -18,12 +18,6 @@
|
|||
@:head()
|
||||
</head>
|
||||
<body>
|
||||
@:centered(true, {
|
||||
<h2 class="title">@title</h2>
|
||||
<p class="description">@description</p>
|
||||
})
|
||||
@:centered(false, {
|
||||
@:body()
|
||||
})
|
||||
@:body()
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +0,0 @@
|
|||
@use super::layout;
|
||||
@use hyaenidae_accounts::{templates::login, LoginState};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(login_state: &LoginState)
|
||||
|
||||
@:layout("Login", "Log into Hyaenidae", {}, {
|
||||
@:login(&Card::full_width(), login_state)
|
||||
})
|
18
server/templates/nav/nav.rs.html
Normal file
18
server/templates/nav/nav.rs.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::button_group, Button};
|
||||
|
||||
@(user_opt: &Option<LogoutState>)
|
||||
|
||||
@if let Some(logout_state) = user_opt.as_ref() {
|
||||
@:button_group(&[
|
||||
Button::primary("Home").href("/"),
|
||||
Button::secondary("Settings").href("/settings"),
|
||||
Button::secondary("Switch Profile").href("/profiles/change"),
|
||||
logout_state.button(&Button::primary_outline("Logout"))
|
||||
])
|
||||
} else {
|
||||
@:button_group(&[
|
||||
Button::primary_outline("Login").href("/session/auth/login"),
|
||||
Button::primary_outline("Register").href("/session/auth/register"),
|
||||
])
|
||||
}
|
18
server/templates/nav/page.rs.html
Normal file
18
server/templates/nav/page.rs.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
@use crate::{templates::{layouts::root, nav::nav}, Back};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, centered}, Button, Card};
|
||||
|
||||
@(user_opt: &Option<LogoutState>, back: &Back)
|
||||
|
||||
@:root("Navigation", "Links to get around", {}, {
|
||||
@:centered(false, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_body({
|
||||
@:nav(user_opt)
|
||||
})
|
||||
@:card_body({
|
||||
@:button_group(&[Button::primary_outline("Back").href(back.as_str())])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,10 +1,11 @@
|
|||
@use super::layout;
|
||||
@use hyaenidae_toolkit::{templates::{card, card_body, link}, Card, Link};
|
||||
@use crate::templates::layouts::main;
|
||||
@use hyaenidae_toolkit::{templates::{card, card_body, card_title, link}, Card, Link};
|
||||
|
||||
@()
|
||||
|
||||
@:layout("404", "Not Found", {}, {
|
||||
@:card(&Card::full_width(), { We couldn't find that }, {
|
||||
@:main("404", "Not Found", {}, {
|
||||
@:card(&Card::full_width(), {
|
||||
@:card_title({ We couldn't find that })
|
||||
@:card_body({
|
||||
@:link(&Link::current_tab("/"), { Return Home })
|
||||
})
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
@use crate::{templates::{layout, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, file_input}, Button, Card, FileInput};
|
||||
@use crate::{templates::{layouts::home, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, statics::{button_js, file_input_js}}, Button, Card, FileInput};
|
||||
|
||||
@(banner_input: &FileInput, error: Option<String>, profile: &Profile)
|
||||
@(banner_input: &FileInput, error: Option<String>, profile: &Profile, logout: LogoutState)
|
||||
|
||||
@:layout("Create Profile", "Create a new profile on Hyaenidae", {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Add a banner }, {
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", &Some(logout), {
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
<form method="POST" action="/profiles/create/banner" enctype="multipart/form-data">
|
||||
@:card_title({ Add a banner })
|
||||
@:card_body({
|
||||
<p>
|
||||
This banner will be displayed on your profile behind your icon.
|
||||
|
@ -29,7 +34,8 @@
|
|||
})
|
||||
</form>
|
||||
})
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Preview }, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Preview })
|
||||
@:view("", profile)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
@use crate::{templates::{layout, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, text_input}, Button, Card, TextInput};
|
||||
@use crate::{templates::{layouts::home, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, text_input, statics::button_js}, Button, Card, TextInput};
|
||||
|
||||
@(display_name_input: &TextInput, description_input: &TextInput, profile: &Profile)
|
||||
@(display_name_input: &TextInput, description_input: &TextInput, profile: &Profile, logout: LogoutState)
|
||||
|
||||
@:layout("Create Profile", "Create a new profile on Hyaenidae", {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Create a Bio }, {
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", &Some(logout), {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
<form method="POST" action="/profiles/create/bio">
|
||||
@:card_title({ Create a Bio })
|
||||
@:card_body({
|
||||
<p>
|
||||
This is where you can talk a bit about yourself. the Display Name is the name
|
||||
|
@ -25,7 +29,8 @@
|
|||
})
|
||||
</form>
|
||||
})
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Preview }, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Preview })
|
||||
@:view("", profile)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
@use crate::{templates::{layout, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body}, Button, Card};
|
||||
@use crate::{templates::{layouts::home, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title}, Button, Card};
|
||||
|
||||
@(profile: &Profile)
|
||||
@(profile: &Profile, logout: LogoutState)
|
||||
|
||||
@:layout("Create Profile", "Create a new profile on Hyaenidae", {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Finished! }, {
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", &Some(logout), {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Finished! })
|
||||
@:card_body({
|
||||
<p>
|
||||
Congratulations! You're profile is all set up! Now you can start to browse
|
||||
|
@ -22,7 +24,8 @@
|
|||
])
|
||||
})
|
||||
})
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Preview }, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Preview })
|
||||
@:view("", profile)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
@use crate::templates::layout;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, text_input}, Button, Card, TextInput};
|
||||
@use crate::templates::layouts::home;
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, text_input, statics::button_js}, Button, Card, TextInput};
|
||||
|
||||
@(handle_input: &TextInput)
|
||||
@(handle_input: &TextInput, logout: LogoutState)
|
||||
|
||||
@:layout("Create Profile", "Create a new profile on Hyaenidae", {}, {
|
||||
@:card(&Card::full_width(), { Create a Handle }, {
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", &Some(logout), {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
<form method="POST" action="/profiles/create/handle">
|
||||
@:card_title({ Create a Handle })
|
||||
@:card_body({
|
||||
<p>
|
||||
A handle is how people on Hyaenidae will find your account. You can make this the
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
@use crate::{templates::{layout, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, file_input}, Button, Card, FileInput};
|
||||
@use crate::{templates::{layouts::home, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, statics::{button_js, file_input_js}}, Button, Card, FileInput};
|
||||
|
||||
@(icon_input: &FileInput, error: Option<String>, profile: &Profile)
|
||||
@(icon_input: &FileInput, error: Option<String>, profile: &Profile, logout: LogoutState)
|
||||
|
||||
@:layout("Create Profile", "Create a new profile on Hyaenidae", {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Add an Icon }, {
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", &Some(logout), {
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
<form method="POST" action="/profiles/create/icon" enctype="multipart/form-data">
|
||||
@:card_title({ Add an Icon })
|
||||
@:card_body({
|
||||
<p>
|
||||
This icon will be displayed on your profile, and next to submissions
|
||||
|
@ -30,7 +35,8 @@
|
|||
})
|
||||
</form>
|
||||
})
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Preview }, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Preview })
|
||||
@:view("", profile)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
@use crate::{templates::{layout, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body}, Button, Card};
|
||||
@use crate::{templates::{layouts::home, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, statics::button_js}, Button, Card};
|
||||
|
||||
@(require_login: bool, error: Option<String>, profile: &Profile)
|
||||
@(require_login: bool, error: Option<String>, profile: &Profile, logout: LogoutState)
|
||||
|
||||
@:layout("Create Profile", "Create a new profile on Hyaenidae", {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Require Login }, {
|
||||
@:home("Create Profile", "Create a new profile on Hyaenidae", &Some(logout), {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
<form method="POST" action="/profiles/create/require-login">
|
||||
@:card_title({ Require Login })
|
||||
@:card_body({
|
||||
<p>
|
||||
If you would like to hide your profile from people without accounts, you
|
||||
|
@ -43,7 +47,8 @@
|
|||
})
|
||||
</form>
|
||||
})
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Preview }, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Preview })
|
||||
@:view("", profile)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
@use crate::{templates::{layout, profiles::{banner, icon, view}}, profiles::ProfileState};
|
||||
@use hyaenidae_toolkit::{templates::{button, button_group, card, card_body, file_input, text_input}, Button, Card};
|
||||
@use crate::{templates::{layouts::home, profiles::{banner, icon, view}}, profiles::ProfileState};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button, button_group, card, card_body, card_title, file_input, text_input, statics::{button_js, file_input_js}}, Button, Card};
|
||||
|
||||
@(state: &ProfileState)
|
||||
@(state: &ProfileState, logout: LogoutState)
|
||||
|
||||
@:layout("Profile Settings", &format!("{}'s profile", state.profile.name()), {}, {
|
||||
@:home("Profile Settings", &format!("{}'s profile", state.profile.name()), &Some(logout), {
|
||||
<script src="/toolkit/@file_input_js.name"></script>
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:view("standalone account-page", &state.profile)
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Update Profile }, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Update Profile })
|
||||
@:card_body({
|
||||
<form method="POST" action="/profiles/update/bio">
|
||||
<div class="columns">
|
||||
|
@ -131,10 +136,4 @@
|
|||
</form>
|
||||
})
|
||||
})
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:button_group(&[
|
||||
Button::primary_outline("Create New Profile").href("/profiles/create/handle"),
|
||||
Button::primary_outline("Switch Profile").href("/profiles/change"),
|
||||
])
|
||||
}, {})
|
||||
})
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
@use crate::{templates::{layout, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body}, Button, Card};
|
||||
@use crate::{templates::{layouts::home, profiles::view}, profiles::Profile};
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title}, Button, Card};
|
||||
|
||||
@(profiles: &[Profile])
|
||||
@(profiles: &[Profile], logout: LogoutState)
|
||||
|
||||
@:layout("Switch Profile", "Select the profile you wish to use", {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), { Create New Profile }, {
|
||||
@:home("Switch Profile", "Select the profile you wish to use", &Some(logout), {}, {
|
||||
@for profile in profiles {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:view("card-top", profile)
|
||||
@:card_body({
|
||||
<form method="POST" action="/profiles/change">
|
||||
<input type="hidden" name="profile_id" value="@profile.id()" />
|
||||
@:button_group(&[&Button::primary(&format!("Select {}", profile.name()))])
|
||||
</form>
|
||||
})
|
||||
})
|
||||
}
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Create a New Profile })
|
||||
@:card_body({
|
||||
@:button_group(&[
|
||||
Button::primary_outline("Create").href("/profiles/create/handle"),
|
||||
])
|
||||
})
|
||||
})
|
||||
@for profile in profiles {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@profile.name()
|
||||
}, {
|
||||
@:view("", profile)
|
||||
@:card_body({
|
||||
<form method="POST" action="/profiles/change">
|
||||
<input type="hidden" name="profile_id" value="@profile.id()" />
|
||||
@:button_group(&[&Button::primary("Select")])
|
||||
</form>
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
@use super::layout;
|
||||
@use hyaenidae_accounts::{templates::register, RegisterState};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(register_state: &RegisterState)
|
||||
|
||||
@:layout("Register", "Register for Hyaenidae", {}, {
|
||||
@:register(&Card::full_width(), register_state)
|
||||
})
|
23
server/templates/session/account.rs.html
Normal file
23
server/templates/session/account.rs.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
@use crate::templates::layouts::home;
|
||||
@use hyaenidae_accounts::{templates::{update_password, update_username}, LogoutState, UpdatePasswordState, UpdateUsernameState, User};
|
||||
@use hyaenidae_toolkit::{templates::{button, card, card_body, card_title, link, statics::button_js}, Button, Card, Link};
|
||||
|
||||
@(user: &User, uname_state: &UpdateUsernameState, pass_state: &UpdatePasswordState, logout: LogoutState)
|
||||
|
||||
@:home(&format!("Account Settings for {}", user.username()), "Update account information", &Some(logout), {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:update_username(Card::full_width().classes(&["account-page"]), uname_state)
|
||||
@:update_password(Card::full_width().classes(&["account-page"]), pass_state)
|
||||
@:card(Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Danger })
|
||||
@:card_body({
|
||||
@:button(Button::primary("Delete Account").href("/session/account/delete"))
|
||||
})
|
||||
})
|
||||
@:card(Card::full_width().classes(&["account-page"]), {
|
||||
@:card_body({
|
||||
@:link(&Link::current_tab("/"), { Return Home })
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,10 +1,10 @@
|
|||
@use super::layout;
|
||||
@use crate::templates::layouts::home;
|
||||
@use hyaenidae_accounts::{templates::cookies, CookiesState};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(cookie_state: &CookiesState)
|
||||
|
||||
@:layout("Accept Cookies", "Review the cookie policy", {}, {
|
||||
@:home("Accept Cookies", "Review the cookie policy", &None, {}, {
|
||||
@:cookies(&Card::full_width(), cookie_state)
|
||||
})
|
||||
|
9
server/templates/session/delete_account.rs.html
Normal file
9
server/templates/session/delete_account.rs.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
@use crate::templates::layouts::home;
|
||||
@use hyaenidae_accounts::{templates::delete_user, DeleteUserState, LogoutState};
|
||||
@use hyaenidae_toolkit::Card;
|
||||
|
||||
@(state: &DeleteUserState, logout: LogoutState)
|
||||
|
||||
@:home("Delete Account", "Are you sure you want to delete your account?", &Some(logout), {}, {
|
||||
@:delete_user(&Card::full_width(), state)
|
||||
})
|
11
server/templates/session/login.rs.html
Normal file
11
server/templates/session/login.rs.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
@use crate::templates::layouts::home;
|
||||
@use hyaenidae_accounts::{templates::login, LoginState};
|
||||
@use hyaenidae_toolkit::{templates::statics::button_js, Card};
|
||||
|
||||
@(login_state: &LoginState)
|
||||
|
||||
@:home("Login", "Log into Hyaenidae", &None, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:login(&Card::full_width(), login_state)
|
||||
})
|
11
server/templates/session/register.rs.html
Normal file
11
server/templates/session/register.rs.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
@use crate::templates::layouts::home;
|
||||
@use hyaenidae_accounts::{templates::register, RegisterState};
|
||||
@use hyaenidae_toolkit::{templates::statics::button_js, Card};
|
||||
|
||||
@(register_state: &RegisterState)
|
||||
|
||||
@:home("Register", "Register for Hyaenidae", &None, {
|
||||
<script src="/toolkit/@button_js.name"></script>
|
||||
}, {
|
||||
@:register(&Card::full_width(), register_state)
|
||||
})
|
30
server/templates/settings.rs.html
Normal file
30
server/templates/settings.rs.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
@use crate::templates::layouts::home;
|
||||
@use hyaenidae_accounts::LogoutState;
|
||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, link}, Button, Card, Link};
|
||||
|
||||
@(logout: LogoutState)
|
||||
|
||||
@:home("Settings", "Update settings", &Some(logout.clone()), {}, {
|
||||
@:card(&Card::full_width().classes(&["account-page"]), {
|
||||
@:card_title({ Settings })
|
||||
@:card_body({
|
||||
<ul>
|
||||
<li>
|
||||
@:link(&Link::current_tab("/profiles"), {
|
||||
Profile Settings
|
||||
})
|
||||
</li>
|
||||
<li>
|
||||
@:link(&Link::current_tab("/session/account"), {
|
||||
Account Settings
|
||||
})
|
||||
</li>
|
||||
</ul>
|
||||
})
|
||||
@:card_body({
|
||||
@:button_group(&[
|
||||
logout.button(&Button::primary_outline("Logout"))
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue