templates
This commit is contained in:
parent
33a7a1882c
commit
bc63926d18
42 changed files with 1224 additions and 90 deletions
2
Makefile
2
Makefile
|
@ -30,9 +30,9 @@ frontend: ## Build frontend assets
|
||||||
@yarn install
|
@yarn install
|
||||||
@-rm -rf ./static/cache/bundle/
|
@-rm -rf ./static/cache/bundle/
|
||||||
@-mkdir ./static/cache/bundle/css/
|
@-mkdir ./static/cache/bundle/css/
|
||||||
|
@yarn sass
|
||||||
@yarn build
|
@yarn build
|
||||||
@./scripts/bundle.sh
|
@./scripts/bundle.sh
|
||||||
#@yarn run dart-sass -s compressed templates/main.scss ./static/cache/bundle/css/main.css
|
|
||||||
|
|
||||||
lint: ## Lint codebase
|
lint: ## Lint codebase
|
||||||
cargo fmt -v --all -- --emit files
|
cargo fmt -v --all -- --emit files
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --mode production",
|
"build": "webpack --mode production",
|
||||||
"sass": "yarn run dart-sass",
|
"sass": "dart-sass -s compressed templates/main.scss ./static/cache/bundle/css/main.css",
|
||||||
"start": "webpack-dev-server --mode development --progress --color",
|
"start": "webpack-dev-server --mode development --progress --color",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -29,7 +29,7 @@ mod api;
|
||||||
mod data;
|
mod data;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod middleware;
|
mod middleware;
|
||||||
//mod pages;
|
mod pages;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod static_assets;
|
mod static_assets;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -39,7 +39,7 @@ mod tests;
|
||||||
pub use crate::data::Data;
|
pub use crate::data::Data;
|
||||||
pub use api::v1::ROUTES as V1_API_ROUTES;
|
pub use api::v1::ROUTES as V1_API_ROUTES;
|
||||||
pub use middleware::auth::CheckLogin;
|
pub use middleware::auth::CheckLogin;
|
||||||
//pub use pages::routes::ROUTES as PAGES;
|
pub use pages::routes::ROUTES as PAGES;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
pub use static_assets::static_files::assets;
|
pub use static_assets::static_files::assets;
|
||||||
|
|
||||||
|
@ -48,9 +48,9 @@ use static_assets::FileMap;
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref SETTINGS: Settings = Settings::new().unwrap();
|
pub static ref SETTINGS: Settings = Settings::new().unwrap();
|
||||||
pub static ref FILES: FileMap = FileMap::new();
|
pub static ref FILES: FileMap = FileMap::new();
|
||||||
//
|
|
||||||
// pub static ref CSS: &'static str =
|
pub static ref CSS: &'static str =
|
||||||
// FILES.get("./static/cache/bundle/css/main.css").unwrap();
|
FILES.get("./static/cache/bundle/css/main.css").unwrap();
|
||||||
pub static ref JS: &'static str =
|
pub static ref JS: &'static str =
|
||||||
FILES.get("./static/cache/bundle/bundle.js").unwrap();
|
FILES.get("./static/cache/bundle/bundle.js").unwrap();
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ pub fn get_identity_service() -> IdentityService<CookieIdentityPolicy> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
|
pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
|
||||||
//pages::services(cfg);
|
pages::services(cfg);
|
||||||
api::v1::services(cfg);
|
api::v1::services(cfg);
|
||||||
static_assets::services(cfg);
|
static_assets::services(cfg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use actix_web::{error::ResponseError, http::header, web, HttpResponse, Responder
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use sailfish::TemplateOnce;
|
use sailfish::TemplateOnce;
|
||||||
|
|
||||||
use crate::api::v1::auth::runners;
|
use crate::api::v1::admin::auth::runners;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::pages::errors::ErrorPage;
|
use crate::pages::errors::ErrorPage;
|
||||||
use crate::AppData;
|
use crate::AppData;
|
||||||
|
@ -92,10 +92,10 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::api::v1::account::{
|
use crate::api::v1::admin::account::{
|
||||||
username::runners::username_exists, AccountCheckPayload,
|
username::runners::username_exists, AccountCheckPayload,
|
||||||
};
|
};
|
||||||
use crate::api::v1::auth::runners::Register;
|
use crate::api::v1::admin::auth::runners::Register;
|
||||||
use crate::data::Data;
|
use crate::data::Data;
|
||||||
use crate::tests::*;
|
use crate::tests::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
|
@ -21,7 +21,7 @@ use lazy_static::lazy_static;
|
||||||
use my_codegen::{get, post};
|
use my_codegen::{get, post};
|
||||||
use sailfish::TemplateOnce;
|
use sailfish::TemplateOnce;
|
||||||
|
|
||||||
use crate::api::v1::auth::runners;
|
use crate::api::v1::admin::auth::runners;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::pages::errors::ErrorPage;
|
use crate::pages::errors::ErrorPage;
|
||||||
use crate::AppData;
|
use crate::AppData;
|
||||||
|
@ -95,7 +95,7 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::api::v1::auth::runners::{Login, Register};
|
use crate::api::v1::admin::auth::runners::{Login, Register};
|
||||||
use crate::data::Data;
|
use crate::data::Data;
|
||||||
use crate::tests::*;
|
use crate::tests::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
@ -120,7 +120,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
let resp = test::call_service(
|
let resp = test::call_service(
|
||||||
&app,
|
&app,
|
||||||
post_request!(&msg, V1_API_ROUTES.auth.register).to_request(),
|
post_request!(&msg, V1_API_ROUTES.admin.auth.register).to_request(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
|
@ -18,6 +18,8 @@ pub mod join;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod sudo;
|
pub mod sudo;
|
||||||
|
|
||||||
|
pub use crate::api::v1::admin::get_admin_check_login;
|
||||||
|
|
||||||
pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
|
pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
|
||||||
cfg.service(login::login);
|
cfg.service(login::login);
|
||||||
cfg.service(login::login_submit);
|
cfg.service(login::login_submit);
|
||||||
|
@ -33,8 +35,8 @@ pub mod routes {
|
||||||
impl Auth {
|
impl Auth {
|
||||||
pub const fn new() -> Auth {
|
pub const fn new() -> Auth {
|
||||||
Auth {
|
Auth {
|
||||||
login: "/login",
|
login: "/api/v1/admin/page/login",
|
||||||
join: "/join",
|
join: "/api/v1/admin/page/join",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,14 @@ mod tests {
|
||||||
let app = get_app!(data).await;
|
let app = get_app!(data).await;
|
||||||
|
|
||||||
let urls = vec![
|
let urls = vec![
|
||||||
PAGES.home.into(),
|
//PAGES.home.into(),
|
||||||
PAGES.panel.campaigns.home.into(),
|
PAGES.panel.campaigns.home.into(),
|
||||||
PAGES.panel.campaigns.new.into(),
|
PAGES.panel.campaigns.new.into(),
|
||||||
PAGES.panel.campaigns.get_feedback_route(&campaign.uuid),
|
// PAGES.panel.campaigns.get_feedback_route(&campaign.uuid),
|
||||||
PAGES.panel.campaigns.get_delete_route(&campaign.uuid),
|
PAGES
|
||||||
|
.panel
|
||||||
|
.campaigns
|
||||||
|
.get_delete_route(&campaign.campaign_id),
|
||||||
];
|
];
|
||||||
|
|
||||||
for url in urls.iter() {
|
for url in urls.iter() {
|
||||||
|
|
|
@ -25,8 +25,9 @@ use my_codegen::{get, post};
|
||||||
use sailfish::TemplateOnce;
|
use sailfish::TemplateOnce;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::api::v1::auth::runners::{login_runner, Login, Password};
|
use super::get_admin_check_login;
|
||||||
use crate::api::v1::campaign::runners;
|
use crate::api::v1::admin::auth::runners::{login_runner, Login, Password};
|
||||||
|
use crate::api::v1::admin::campaigns::runners;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::pages::auth::sudo::SudoPage;
|
use crate::pages::auth::sudo::SudoPage;
|
||||||
use crate::AppData;
|
use crate::AppData;
|
||||||
|
@ -43,11 +44,11 @@ async fn get_title(
|
||||||
let campaign = sqlx::query_as!(
|
let campaign = sqlx::query_as!(
|
||||||
Name,
|
Name,
|
||||||
"SELECT name
|
"SELECT name
|
||||||
FROM kaizen_campaign
|
FROM survey_campaigns
|
||||||
WHERE
|
WHERE
|
||||||
uuid = $1
|
id = $1
|
||||||
AND
|
AND
|
||||||
user_id = (SELECT ID from kaizen_users WHERE name = $2)",
|
user_id = (SELECT ID from survey_admins WHERE name = $2)",
|
||||||
&uuid,
|
&uuid,
|
||||||
&username
|
&username
|
||||||
)
|
)
|
||||||
|
@ -57,7 +58,10 @@ async fn get_title(
|
||||||
Ok(format!("Delete camapign \"{}\"?", campaign.name))
|
Ok(format!("Delete camapign \"{}\"?", campaign.name))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get(path = "PAGES.panel.campaigns.delete", wrap = "crate::CheckLogin")]
|
#[get(
|
||||||
|
path = "PAGES.panel.campaigns.delete",
|
||||||
|
wrap = "get_admin_check_login()"
|
||||||
|
)]
|
||||||
pub async fn delete_campaign(
|
pub async fn delete_campaign(
|
||||||
id: Identity,
|
id: Identity,
|
||||||
path: web::Path<String>,
|
path: web::Path<String>,
|
||||||
|
@ -80,7 +84,10 @@ pub async fn delete_campaign(
|
||||||
.body(page))
|
.body(page))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post(path = "PAGES.panel.campaigns.delete", wrap = "crate::CheckLogin")]
|
#[post(
|
||||||
|
path = "PAGES.panel.campaigns.delete",
|
||||||
|
wrap = "get_admin_check_login()"
|
||||||
|
)]
|
||||||
pub async fn delete_campaign_submit(
|
pub async fn delete_campaign_submit(
|
||||||
id: Identity,
|
id: Identity,
|
||||||
path: web::Path<String>,
|
path: web::Path<String>,
|
||||||
|
@ -102,7 +109,7 @@ pub async fn delete_campaign_submit(
|
||||||
let status = e.status_code();
|
let status = e.status_code();
|
||||||
let heading = status.canonical_reason().unwrap_or("Error");
|
let heading = status.canonical_reason().unwrap_or("Error");
|
||||||
|
|
||||||
let form_route = crate::V1_API_ROUTES.campaign.get_delete_route(&path);
|
let form_route = crate::V1_API_ROUTES.admin.campaign.get_delete_route(&path);
|
||||||
let title = get_title(&username, &uuid, &data).await?;
|
let title = get_title(&username, &uuid, &data).await?;
|
||||||
let mut ctx = SudoPage::new(&form_route, &title);
|
let mut ctx = SudoPage::new(&form_route, &title);
|
||||||
let err = format!("{}", e);
|
let err = format!("{}", e);
|
||||||
|
@ -179,7 +186,7 @@ mod tests {
|
||||||
&app,
|
&app,
|
||||||
post_request!(
|
post_request!(
|
||||||
&creds,
|
&creds,
|
||||||
&PAGES.panel.campaigns.get_delete_route(&uuid.uuid),
|
&PAGES.panel.campaigns.get_delete_route(&uuid.campaign_id),
|
||||||
FORM
|
FORM
|
||||||
)
|
)
|
||||||
.cookie(cookies.clone())
|
.cookie(cookies.clone())
|
||||||
|
|
|
@ -14,48 +14,49 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
use actix_identity::Identity;
|
//use actix_identity::Identity;
|
||||||
use actix_web::{web, HttpResponse, Responder};
|
//use actix_web::{web, HttpResponse, Responder};
|
||||||
use my_codegen::get;
|
//use my_codegen::get;
|
||||||
use sailfish::TemplateOnce;
|
//use sailfish::TemplateOnce;
|
||||||
|
//
|
||||||
use crate::api::v1::campaign::{runners, GetFeedbackResp};
|
//use crate::api::v1::admin::campaigns::{runners, GetFeedbackResp};
|
||||||
use crate::AppData;
|
//use crate::AppData;
|
||||||
use crate::PAGES;
|
//use crate::PAGES;
|
||||||
|
//use super::get_admin_check_login;
|
||||||
#[derive(TemplateOnce)]
|
//
|
||||||
#[template(path = "panel/campaigns/get/index.html")]
|
//#[derive(TemplateOnce)]
|
||||||
struct ViewFeedback<'a> {
|
//#[template(path = "panel/campaigns/get/index.html")]
|
||||||
campaign: GetFeedbackResp,
|
//struct ViewFeedback<'a> {
|
||||||
uuid: &'a str,
|
// campaign: GetFeedbackResp,
|
||||||
}
|
// uuid: &'a str,
|
||||||
|
//}
|
||||||
const PAGE: &str = "New Campaign";
|
//
|
||||||
|
//const PAGE: &str = "New Campaign";
|
||||||
impl<'a> ViewFeedback<'a> {
|
//
|
||||||
pub fn new(campaign: GetFeedbackResp, uuid: &'a str) -> Self {
|
//impl<'a> ViewFeedback<'a> {
|
||||||
Self { campaign, uuid }
|
// pub fn new(campaign: GetFeedbackResp, uuid: &'a str) -> Self {
|
||||||
}
|
// Self { campaign, uuid }
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
#[get(
|
//
|
||||||
path = "PAGES.panel.campaigns.get_feedback",
|
//#[get(
|
||||||
wrap = "crate::CheckLogin"
|
// path = "PAGES.panel.campaigns.get_feedback",
|
||||||
)]
|
// wrap = "get_admin_check_login()"
|
||||||
pub async fn get_feedback(
|
//)]
|
||||||
id: Identity,
|
//pub async fn get_feedback(
|
||||||
data: AppData,
|
// id: Identity,
|
||||||
path: web::Path<String>,
|
// data: AppData,
|
||||||
) -> impl Responder {
|
// path: web::Path<String>,
|
||||||
let username = id.identity().unwrap();
|
//) -> impl Responder {
|
||||||
let path = path.into_inner();
|
// let username = id.identity().unwrap();
|
||||||
let feedback_resp = runners::get_feedback(&username, &path, &data)
|
// let path = path.into_inner();
|
||||||
.await
|
// let feedback_resp = runners::get_feedback(&username, &path, &data)
|
||||||
.unwrap();
|
// .await
|
||||||
let page = ViewFeedback::new(feedback_resp, &path)
|
// .unwrap();
|
||||||
.render_once()
|
// let page = ViewFeedback::new(feedback_resp, &path)
|
||||||
.unwrap();
|
// .render_once()
|
||||||
HttpResponse::Ok()
|
// .unwrap();
|
||||||
.content_type("text/html; charset=utf-8")
|
// HttpResponse::Ok()
|
||||||
.body(page)
|
// .content_type("text/html; charset=utf-8")
|
||||||
}
|
// .body(page)
|
||||||
|
//}
|
||||||
|
|
|
@ -18,10 +18,14 @@ use actix_web::{HttpResponse, Responder};
|
||||||
use my_codegen::get;
|
use my_codegen::get;
|
||||||
use sailfish::TemplateOnce;
|
use sailfish::TemplateOnce;
|
||||||
|
|
||||||
use crate::api::v1::campaign::{runners::list_campaign_runner, ListCampaignResp};
|
use crate::api::v1::admin::campaigns::{
|
||||||
|
runners::list_campaign_runner, ListCampaignResp,
|
||||||
|
};
|
||||||
use crate::AppData;
|
use crate::AppData;
|
||||||
use crate::PAGES;
|
use crate::PAGES;
|
||||||
|
|
||||||
|
use super::get_admin_check_login;
|
||||||
|
|
||||||
pub mod delete;
|
pub mod delete;
|
||||||
pub mod get;
|
pub mod get;
|
||||||
pub mod new;
|
pub mod new;
|
||||||
|
@ -36,10 +40,10 @@ pub mod routes {
|
||||||
impl Campaigns {
|
impl Campaigns {
|
||||||
pub const fn new() -> Campaigns {
|
pub const fn new() -> Campaigns {
|
||||||
Campaigns {
|
Campaigns {
|
||||||
home: "/campaigns",
|
home: "/api/v1/admin/page/campaigns",
|
||||||
new: "/campaigns/new",
|
new: "/api/v1/admin/page/campaigns/new",
|
||||||
get_feedback: "/campaigns/{uuid}/feedback",
|
get_feedback: "/api/v1/admin/page/campaigns/{uuid}/feedback",
|
||||||
delete: "/campaigns/{uuid}/delete",
|
delete: "/api/v1/admin/page/campaigns/{uuid}/delete",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +66,7 @@ pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
|
||||||
cfg.service(home);
|
cfg.service(home);
|
||||||
cfg.service(new::new_campaign);
|
cfg.service(new::new_campaign);
|
||||||
cfg.service(new::new_campaign_submit);
|
cfg.service(new::new_campaign_submit);
|
||||||
cfg.service(get::get_feedback);
|
// cfg.service(get::get_feedback);
|
||||||
cfg.service(delete::delete_campaign);
|
cfg.service(delete::delete_campaign);
|
||||||
cfg.service(delete::delete_campaign_submit);
|
cfg.service(delete::delete_campaign_submit);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +85,7 @@ impl HomePage {
|
||||||
|
|
||||||
const PAGE: &str = "Campaigns";
|
const PAGE: &str = "Campaigns";
|
||||||
|
|
||||||
#[get(path = "PAGES.panel.campaigns.home", wrap = "crate::CheckLogin")]
|
#[get(path = "PAGES.panel.campaigns.home", wrap = "get_admin_check_login()")]
|
||||||
pub async fn home(data: AppData, id: Identity) -> impl Responder {
|
pub async fn home(data: AppData, id: Identity) -> impl Responder {
|
||||||
let username = id.identity().unwrap();
|
let username = id.identity().unwrap();
|
||||||
let campaigns = list_campaign_runner(&username, &data).await.unwrap();
|
let campaigns = list_campaign_runner(&username, &data).await.unwrap();
|
||||||
|
|
|
@ -21,12 +21,14 @@ use lazy_static::lazy_static;
|
||||||
use my_codegen::{get, post};
|
use my_codegen::{get, post};
|
||||||
use sailfish::TemplateOnce;
|
use sailfish::TemplateOnce;
|
||||||
|
|
||||||
use crate::api::v1::campaign::{runners, CreateReq};
|
use crate::api::v1::admin::campaigns::{runners, AddCapmaign};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::pages::errors::ErrorPage;
|
use crate::pages::errors::ErrorPage;
|
||||||
use crate::AppData;
|
use crate::AppData;
|
||||||
use crate::PAGES;
|
use crate::PAGES;
|
||||||
|
|
||||||
|
use super::get_admin_check_login;
|
||||||
|
|
||||||
#[derive(Clone, TemplateOnce)]
|
#[derive(Clone, TemplateOnce)]
|
||||||
#[template(path = "panel/campaigns/new/index.html")]
|
#[template(path = "panel/campaigns/new/index.html")]
|
||||||
struct NewCampaign<'a> {
|
struct NewCampaign<'a> {
|
||||||
|
@ -53,20 +55,23 @@ lazy_static! {
|
||||||
static ref INDEX: String = NewCampaign::default().render_once().unwrap();
|
static ref INDEX: String = NewCampaign::default().render_once().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get(path = "PAGES.panel.campaigns.new", wrap = "crate::CheckLogin")]
|
#[get(path = "PAGES.panel.campaigns.new", wrap = "get_admin_check_login()")]
|
||||||
pub async fn new_campaign() -> impl Responder {
|
pub async fn new_campaign() -> impl Responder {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.content_type("text/html; charset=utf-8")
|
.content_type("text/html; charset=utf-8")
|
||||||
.body(&*INDEX)
|
.body(&*INDEX)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post(path = "PAGES.panel.campaigns.new", wrap = "crate::CheckLogin")]
|
#[post(path = "PAGES.panel.campaigns.new", wrap = "get_admin_check_login()")]
|
||||||
pub async fn new_campaign_submit(
|
pub async fn new_campaign_submit(
|
||||||
id: Identity,
|
id: Identity,
|
||||||
payload: web::Form<CreateReq>,
|
payload: web::Json<AddCapmaign>,
|
||||||
data: AppData,
|
data: AppData,
|
||||||
) -> PageResult<impl Responder> {
|
) -> PageResult<impl Responder> {
|
||||||
match runners::new(&payload.into_inner(), &data, &id).await {
|
let username = id.identity().unwrap();
|
||||||
|
let mut payload = payload.into_inner();
|
||||||
|
|
||||||
|
match runners::add_runner(&username, &mut payload, &data).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
Ok(HttpResponse::Found()
|
Ok(HttpResponse::Found()
|
||||||
//TODO show stats of new campaign
|
//TODO show stats of new campaign
|
||||||
|
@ -113,17 +118,19 @@ mod tests {
|
||||||
let (_, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await;
|
let (_, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await;
|
||||||
let cookies = get_cookie!(signin_resp);
|
let cookies = get_cookie!(signin_resp);
|
||||||
|
|
||||||
let new = CreateReq {
|
let new = AddCapmaign {
|
||||||
name: CAMPAIGN_NAME.into(),
|
name: CAMPAIGN_NAME.into(),
|
||||||
|
difficulties: DIFFICULTIES.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_resp = test::call_service(
|
let new_resp = test::call_service(
|
||||||
&app,
|
&app,
|
||||||
post_request!(&new, PAGES.panel.campaigns.new, FORM)
|
post_request!(&new, crate::PAGES.panel.campaigns.new)
|
||||||
.cookie(cookies.clone())
|
.cookie(cookies)
|
||||||
.to_request(),
|
.to_request(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert_eq!(new_resp.status(), StatusCode::FOUND);
|
assert_eq!(new_resp.status(), StatusCode::FOUND);
|
||||||
let headers = new_resp.headers();
|
let headers = new_resp.headers();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
use actix_web::{http, HttpResponse, Responder};
|
use actix_web::{http, HttpResponse, Responder};
|
||||||
use my_codegen::get;
|
use my_codegen::get;
|
||||||
|
|
||||||
|
pub use crate::api::v1::admin::get_admin_check_login;
|
||||||
|
|
||||||
use crate::PAGES;
|
use crate::PAGES;
|
||||||
|
|
||||||
mod campaigns;
|
mod campaigns;
|
||||||
|
@ -30,7 +32,7 @@ pub mod routes {
|
||||||
impl Panel {
|
impl Panel {
|
||||||
pub const fn new() -> Panel {
|
pub const fn new() -> Panel {
|
||||||
Panel {
|
Panel {
|
||||||
home: "/",
|
home: "/api/v1/admin/home/",
|
||||||
campaigns: Campaigns::new(),
|
campaigns: Campaigns::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +49,7 @@ pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
|
||||||
campaigns::services(cfg);
|
campaigns::services(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get(path = "PAGES.panel.home", wrap = "crate::CheckLogin")]
|
#[get(path = "PAGES.panel.home", wrap = "get_admin_check_login()")]
|
||||||
pub async fn home() -> impl Responder {
|
pub async fn home() -> impl Responder {
|
||||||
HttpResponse::Found()
|
HttpResponse::Found()
|
||||||
.insert_header((http::header::LOCATION, PAGES.panel.campaigns.home))
|
.insert_header((http::header::LOCATION, PAGES.panel.campaigns.home))
|
||||||
|
|
|
@ -127,6 +127,7 @@ mod tests {
|
||||||
assets::LOGO.path,
|
assets::LOGO.path,
|
||||||
assets::HEADSETS.path,
|
assets::HEADSETS.path,
|
||||||
*crate::JS,
|
*crate::JS,
|
||||||
|
*crate::CSS,
|
||||||
*crate::GLUE,
|
*crate::GLUE,
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
11
templates/auth/demo-user-banner.html
Normal file
11
templates/auth/demo-user-banner.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<. if crate::SETTINGS.allow_demo && crate::SETTINGS.allow_registration { .>
|
||||||
|
<p class="auth__demo-user__banner">
|
||||||
|
Try Kaizen without joining<br />
|
||||||
|
<span class="auth__demo-user__cred" >
|
||||||
|
<b>user:</b> <.= crate::demo::DEMO_USER .>
|
||||||
|
</span>
|
||||||
|
<span class="auth__demo-user__cred">
|
||||||
|
<b>password:</b> <.= crate::demo::DEMO_PASSWORD .>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<. } .>
|
69
templates/auth/join/index.html
Normal file
69
templates/auth/join/index.html
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<. include!("../../components/base/top.html"); .>
|
||||||
|
<body class="auth__body">
|
||||||
|
<main class="auth__container">
|
||||||
|
<img src="<.= crate::assets::LOGO.path .>" alt="logo" class="auth__logo" />
|
||||||
|
<h1>Join Kaizen</h1>
|
||||||
|
<. include!("../../components/error/index.html"); .>
|
||||||
|
<form
|
||||||
|
action="<.= crate::PAGES.auth.join .>"
|
||||||
|
method="POST"
|
||||||
|
class="form"
|
||||||
|
accept-charset="utf-8"
|
||||||
|
>
|
||||||
|
<label class="form__label" for="username">
|
||||||
|
Username
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="username"
|
||||||
|
required
|
||||||
|
id="username"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="form__label" for="email">
|
||||||
|
Email(optional)
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
type="email"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="form__label" for="password">
|
||||||
|
password
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="password"
|
||||||
|
required
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="form__label" for="confirm_password">
|
||||||
|
Re-enter Password
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="confirm_password"
|
||||||
|
required
|
||||||
|
id="confirm_password"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="form__action-container">
|
||||||
|
<a href="/forgot-password">Forgot password?</a>
|
||||||
|
<button class="form__submit" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="form__alt-action">
|
||||||
|
Already have an account?
|
||||||
|
<a href="<.= crate::PAGES.auth.login .>"> Login </a>
|
||||||
|
</p>
|
||||||
|
</main>
|
||||||
|
<. include!("../../components/footer/index.html"); .>
|
||||||
|
</body>
|
||||||
|
<. include!("../../components/base/bottom.html"); .>
|
48
templates/auth/login/index.html
Normal file
48
templates/auth/login/index.html
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<. include!("../../components/base/top.html"); .>
|
||||||
|
<body class="auth__body">
|
||||||
|
<main class="auth__container">
|
||||||
|
<img src="<.= crate::assets::LOGO.path .>" alt="logo" class="auth__logo" />
|
||||||
|
<h1>Sign in</h1>
|
||||||
|
<. include!("../../components/error/index.html"); .>
|
||||||
|
<form
|
||||||
|
action="<.= crate::PAGES.auth.login .>"
|
||||||
|
method="POST"
|
||||||
|
class="form"
|
||||||
|
accept-charset="utf-8"
|
||||||
|
>
|
||||||
|
<label class="form__label" for="login">
|
||||||
|
Username or Email
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="login"
|
||||||
|
required
|
||||||
|
id="login"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="form__label" for="password">
|
||||||
|
password
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="password"
|
||||||
|
required
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="form__action-container">
|
||||||
|
<a href="/forgot-password">Forgot password?</a>
|
||||||
|
<button class="form__submit" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="form__alt-action">
|
||||||
|
New to Kaizen?
|
||||||
|
<a href="<.= crate::PAGES.auth.join .>">Create an account </a>
|
||||||
|
</p>
|
||||||
|
</main>
|
||||||
|
<. include!("../../components/footer/index.html"); .>
|
||||||
|
</body>
|
||||||
|
<. include!("../../components/base/bottom.html"); .>
|
50
templates/auth/main.scss
Normal file
50
templates/auth/main.scss
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
.auth__body {
|
||||||
|
height: 100vh;
|
||||||
|
max-height: 100vh;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth__container {
|
||||||
|
width: 380px;
|
||||||
|
align-items: center;
|
||||||
|
margin: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth__logo {
|
||||||
|
width: 150px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth__demo-user__banner {
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 5px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth__demo-user__cred {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sudo__message {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
34
templates/auth/sudo/index.html
Normal file
34
templates/auth/sudo/index.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<. include!("../../components/base/top.html"); .>
|
||||||
|
<body class="auth__body">
|
||||||
|
<main class="auth__container">
|
||||||
|
<img src="<.= crate::assets::LOGO.path .>" alt="logo" class="auth__logo" />
|
||||||
|
<h1>Confirm Access</h1>
|
||||||
|
|
||||||
|
<p class="sudo__message"><b><.= title .></b></p>
|
||||||
|
<. include!("../../components/error/index.html"); .>
|
||||||
|
<form
|
||||||
|
action="<.= url .>"
|
||||||
|
class="form"
|
||||||
|
method="POST"
|
||||||
|
accept-charset="utf-8"
|
||||||
|
>
|
||||||
|
<label class="form__label" for="password">
|
||||||
|
password
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="password"
|
||||||
|
required
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="form__action-container">
|
||||||
|
<a href="/forgot-password">Forgot password?</a>
|
||||||
|
<button class="form__submit" type="submit">Authorize</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
<. include!("../../components/footer/index.html"); .>
|
||||||
|
</body>
|
||||||
|
<. include!("../../components/base/bottom.html"); .>
|
38
templates/components/_button.scss
Normal file
38
templates/components/_button.scss
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@mixin button {
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
// margin: 10px 0;
|
||||||
|
// background-color: none;
|
||||||
|
background-color: #b4345b;
|
||||||
|
color: #fff;
|
||||||
|
// text-align: center;
|
||||||
|
|
||||||
|
border-radius: 0px;
|
||||||
|
|
||||||
|
padding: 0.1rem 0.75rem;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.2rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
user-select: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
1
templates/components/base/bottom.html
Normal file
1
templates/components/base/bottom.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
</html>
|
8
templates/components/base/top.html
Normal file
8
templates/components/base/top.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title><.= PAGE .> | <.= crate::pages::NAME .></title>
|
||||||
|
<link rel="stylesheet" href="<.= &*crate::CSS .>" />
|
||||||
|
</head>
|
6
templates/components/error/index.html
Normal file
6
templates/components/error/index.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<. if let Some(error) = error { .>
|
||||||
|
<div class="error__container">
|
||||||
|
<p class="error__title"><b><.= error.title .></b></p>
|
||||||
|
<p class="error__msg"><.= error.message .></p>
|
||||||
|
</div>
|
||||||
|
<. } .>
|
36
templates/components/error/main.scss
Normal file
36
templates/components/error/main.scss
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.error__container {
|
||||||
|
width: 350px;
|
||||||
|
background-color: #d63f3f;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 0;
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error__title {
|
||||||
|
color: #fff;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error__msg {
|
||||||
|
color: #fff;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
24
templates/components/footer/index.html
Normal file
24
templates/components/footer/index.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<footer class="footer">
|
||||||
|
<. use crate::PAGES; .>
|
||||||
|
<ul class="footer__section">
|
||||||
|
<li class="footer__item">
|
||||||
|
<a class="footer__link" href="<.= PAGES.about .>">About</a>
|
||||||
|
</li>
|
||||||
|
<li class="footer__item">
|
||||||
|
<a class="footer__link" href="<.= PAGES.donate .>">Donate</a>
|
||||||
|
</li>
|
||||||
|
<li class="footer__item">
|
||||||
|
<a class="footer__link" href="<.= PAGES.privacy .>">Privacy</a>
|
||||||
|
</li>
|
||||||
|
<li class="footer__item">
|
||||||
|
<a class="footer__link" href="<.= PAGES.security .>">Security</a>
|
||||||
|
</li>
|
||||||
|
<li class="footer__item">
|
||||||
|
<a class="footer__link" href="<.= PAGES.thanks .>">Thanks</a>
|
||||||
|
</li>
|
||||||
|
<li class="footer__item">
|
||||||
|
<a class="footer__link" href="<.= &*crate::SOURCE_FILES_OF_INSTANCE .>">
|
||||||
|
v<.= crate::VERSION .>-<.= crate::GIT_COMMIT_HASH[0..8] .>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</footer>
|
36
templates/components/footer/main.scss
Normal file
36
templates/components/footer/main.scss
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 0px 20px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
bottom: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer__section {
|
||||||
|
display: inline;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer__item {
|
||||||
|
display: inline;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
55
templates/components/form/_partials.scss
Normal file
55
templates/components/form/_partials.scss
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
@import "../button";
|
||||||
|
|
||||||
|
@mixin form {
|
||||||
|
margin: 15px auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin label {
|
||||||
|
display: block;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin input {
|
||||||
|
display: block;
|
||||||
|
margin: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 0px;
|
||||||
|
border: 1px solid grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin action_container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin alt_action {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin submit {
|
||||||
|
@include button;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin submit_hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
45
templates/components/form/main.scss
Normal file
45
templates/components/form/main.scss
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
@import "partials";
|
||||||
|
|
||||||
|
.form {
|
||||||
|
@include form;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__label {
|
||||||
|
@include label;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__input {
|
||||||
|
@include input;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__action-container {
|
||||||
|
@include action_container;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__alt-action {
|
||||||
|
@include alt_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__submit {
|
||||||
|
@include submit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__submit:hover {
|
||||||
|
@include submit_hover;
|
||||||
|
}
|
0
templates/components/header.html
Normal file
0
templates/components/header.html
Normal file
9
templates/errors/index.html
Normal file
9
templates/errors/index.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<. include!("../components/base/top.html"); .>
|
||||||
|
<body class="panel__body">
|
||||||
|
<main class="panel__container">
|
||||||
|
<h1 class="error-title"><.= title .></h1>
|
||||||
|
<p class="error-message"><.= message .></p>
|
||||||
|
</main>
|
||||||
|
<. include!("../components/footer/index.html"); .>
|
||||||
|
</body>
|
||||||
|
<. include!("../components/base/bottom.html"); .>
|
23
templates/errors/main.scss
Normal file
23
templates/errors/main.scss
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
.error-title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
text-align: center;
|
||||||
|
}
|
63
templates/index.html
Normal file
63
templates/index.html
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<. include!("./components/base/top.html"); .>
|
||||||
|
<body class="panel__body">
|
||||||
|
<main class="panel__container">
|
||||||
|
<h1>mCaptcha device benchmark survey</h1>
|
||||||
|
<h2>Why should I participate</h2>
|
||||||
|
<p>
|
||||||
|
<a href="https://mcaptcha.org" target="_blank">mCaptcha</a>
|
||||||
|
is a cutting edge, privacy respecting CAPTCHA system. We use a
|
||||||
|
<a href="https://en.wikipedia.org/wiki/Proof_of_work" target="_blank"
|
||||||
|
>proof of work</a
|
||||||
|
>
|
||||||
|
based mechanism to defend against
|
||||||
|
<a href="https://en.wikipedia.org/wiki/Proof_of_work" target="_blank"
|
||||||
|
>denial-of-service attacks</a
|
||||||
|
>
|
||||||
|
which allows for a non-interactive CAPTCHA experience. We require
|
||||||
|
performance metrics measured on a wide range of devices to fine-tune the
|
||||||
|
system for optimal user experience, see for yourself!
|
||||||
|
</p>
|
||||||
|
<div style="width: 304px; height: 78px">
|
||||||
|
<iframe
|
||||||
|
title="mCaptcha"
|
||||||
|
src="https://demo.mcaptcha.org/widget/?sitekey=6o3p1Fx94hJRFm8g8IHBB7sv8D0em20k"
|
||||||
|
role="presentation"
|
||||||
|
name="mcaptcha-widget__iframe"
|
||||||
|
id="mcaptcha-widget__iframe"
|
||||||
|
scrolling="no"
|
||||||
|
sandbox="allow-same-origin allow-scripts"
|
||||||
|
width="304"
|
||||||
|
height="78"
|
||||||
|
data-mcaptcha_host="https://demo.mcaptcha.org"
|
||||||
|
frameborder="0"
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>What do I get?</h2>
|
||||||
|
<p>
|
||||||
|
We are conducting a lucky draw. Two lucky participants, selected at
|
||||||
|
random, will win a pair of
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
href="https://www.amazon.in/JBL-Detachable-Directional-Headphones-Conference/dp/B0948TG7H8"
|
||||||
|
>JBL headsets worth over ₹2,500</a
|
||||||
|
>! Also, you will be helping us make the internet healthier :)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Privacy policy</h2>
|
||||||
|
<p>This survey collects the following information:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Device name</li>
|
||||||
|
<li>Operating system</li>
|
||||||
|
<li>Processor information</li>
|
||||||
|
<li>Benchmark results</li>
|
||||||
|
</ul>
|
||||||
|
<b>No Personally identifying information is collected</b>
|
||||||
|
</main>
|
||||||
|
<. include!("../components/footer/index.html"); .>
|
||||||
|
<a href="<.= crate::V1_API_ROUTES.benches.register .>" target="_blank"
|
||||||
|
>Get started</a
|
||||||
|
>
|
||||||
|
</body>
|
||||||
|
<script src="./dist/bundle.js"></script>
|
||||||
|
<. include!("./components/base/bottom.html"); .>
|
51
templates/main.scss
Normal file
51
templates/main.scss
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
@import "./components/footer/main";
|
||||||
|
@import "./components/form/main";
|
||||||
|
@import "./components/error/main";
|
||||||
|
|
||||||
|
@import "./auth/main";
|
||||||
|
@import "./panel/main";
|
||||||
|
@import "./panel/campaigns/new/main";
|
||||||
|
@import "./panel/campaigns/get/main";
|
||||||
|
@import "./errors/main";
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
|
||||||
|
font-family: "Inter UI", -apple-system, BlinkMacSystemFont, "Roboto",
|
||||||
|
"Segoe UI", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: rgb(0, 86, 179);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
max-width: 100vw;
|
||||||
|
overflow-x: hidden;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
58
templates/panel/campaigns/get/index.html
Normal file
58
templates/panel/campaigns/get/index.html
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<. include!("../../../components/base/top.html"); .>
|
||||||
|
<body class="panel__body">
|
||||||
|
<. include!("../../nav/index.html"); .>
|
||||||
|
<main class="panel__container">
|
||||||
|
<h1><.= campaign.name .></h1>
|
||||||
|
<a href="<.= crate::PAGES.panel.campaigns.get_delete_route(&uuid) .>" >
|
||||||
|
<img src="<.= crate::assets::TRASH.path .>" alt="<.= crate::assets::TRASH.name .>" class="feedback__trash-logo" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="asset__container">
|
||||||
|
<span class="asset__name">Campaign ID</span>
|
||||||
|
<code id="campaign-id" class="asset__value"><.= uuid .></code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<. if campaign.feedbacks.is_empty() { .>
|
||||||
|
<p>
|
||||||
|
Looks like you don't have any feedback on this campaign.
|
||||||
|
</p>
|
||||||
|
<. } else { .>
|
||||||
|
<table class="feedback__table">
|
||||||
|
<thead class="feedback__heading">
|
||||||
|
<tr>
|
||||||
|
<th class="feedback__title-text--normal">Time</th>
|
||||||
|
<th class="feedback__title-text--small">Helpful</th>
|
||||||
|
<th class="feedback__title-text--large">Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="feedback__body">
|
||||||
|
<. for feedback in campaign.feedbacks.iter() { .>
|
||||||
|
<tr class="feedback__item">
|
||||||
|
<td>
|
||||||
|
<.= feedback.time .>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<.= feedback.helpful .>
|
||||||
|
</td>
|
||||||
|
<td class="feedback__description">
|
||||||
|
<. if feedback.description.len() > 60 { .>
|
||||||
|
<details>
|
||||||
|
<. let (summary, rest) = feedback.description.split_at(60); .>
|
||||||
|
<summary>
|
||||||
|
<.= summary .>
|
||||||
|
</summary> >>
|
||||||
|
<.= rest .>
|
||||||
|
</details>
|
||||||
|
<. } else { .>
|
||||||
|
<.= feedback.description .>
|
||||||
|
<. } .>
|
||||||
|
<. } .>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<. } .>
|
||||||
|
</main>
|
||||||
|
<. include!("../../../components/footer/index.html"); .>
|
||||||
|
</body>
|
||||||
|
<. include!("../../../components/base/bottom.html"); .>
|
37
templates/panel/campaigns/get/main.scss
Normal file
37
templates/panel/campaigns/get/main.scss
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
.feedback__table {
|
||||||
|
width: 80%;
|
||||||
|
margin: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback__title-text--small {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback__title-text--large {
|
||||||
|
width: 350px;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback__title-text--normal {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback__description{
|
||||||
|
text-align: start;
|
||||||
|
}
|
42
templates/panel/campaigns/index.html
Normal file
42
templates/panel/campaigns/index.html
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<. include!("../../components/base/top.html"); .>
|
||||||
|
<body class="panel__body">
|
||||||
|
<. include!("../nav/index.html"); .>
|
||||||
|
<main class="panel__container">
|
||||||
|
<. if data.is_empty() { .>
|
||||||
|
<p>
|
||||||
|
Looks like you don't have any campaings registered,
|
||||||
|
<a class="link__btn" href="<.= crate::PAGES.panel.campaigns.new .>"> click here </a>
|
||||||
|
to create a new campaign!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<. } else { .>
|
||||||
|
<table class="campaign__table">
|
||||||
|
<thead class="campaign__heading">
|
||||||
|
<tr>
|
||||||
|
<th class="campaign__title-text">Name</th>
|
||||||
|
<th class="campaign__title-text">UUID</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="campaign__body">
|
||||||
|
<. for campaign in data.iter() { .>
|
||||||
|
<. let route = crate::PAGES.panel.campaigns.get_feedback_route(&campaign.uuid); .>
|
||||||
|
<tr class="campaign__item">
|
||||||
|
<td>
|
||||||
|
<a href="<.= &route .>">
|
||||||
|
<p class="campaign__item-heading"><.= campaign.name .></p>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="<.= &route .>">
|
||||||
|
<p class="campaign__item-text"><.= campaign.uuid .></p></a
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<. } .>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<. } .>
|
||||||
|
</main>
|
||||||
|
<. include!("../../components/footer/index.html"); .>
|
||||||
|
</body>
|
||||||
|
<. include!("../../components/base/bottom.html"); .>
|
21
templates/panel/campaigns/new/form.html
Normal file
21
templates/panel/campaigns/new/form.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<h1>Create new campaigns</h1>
|
||||||
|
<. include!("../../../components/error/index.html"); .>
|
||||||
|
<form
|
||||||
|
action="<.= crate::PAGES.panel.campaigns.new .>"
|
||||||
|
method="POST"
|
||||||
|
class="new-campaign__form"
|
||||||
|
accept-charset="utf-8"
|
||||||
|
>
|
||||||
|
<label class="form__label" for="name">
|
||||||
|
Name
|
||||||
|
<input
|
||||||
|
class="form__input"
|
||||||
|
name="name"
|
||||||
|
placeholder=" Joe's website or https://example.com/docs/"
|
||||||
|
required
|
||||||
|
id="name"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button class="form__submit" type="submit">Create Campaign</button>
|
||||||
|
</form>
|
7
templates/panel/campaigns/new/index.html
Normal file
7
templates/panel/campaigns/new/index.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<. include!("../../../components/base/top.html"); .>
|
||||||
|
<body class="panel__body">
|
||||||
|
<. include!("../../nav/index.html"); .>
|
||||||
|
<main class="panel__container"><. include!("./form.html"); .></main>
|
||||||
|
<. include!("../../../components/footer/index.html"); .>
|
||||||
|
</body>
|
||||||
|
<. include!("../../../components/base/bottom.html"); .>
|
22
templates/panel/campaigns/new/main.scss
Normal file
22
templates/panel/campaigns/new/main.scss
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
@import "../../../components/form/partials";
|
||||||
|
|
||||||
|
.new-campaign__form {
|
||||||
|
@include form;
|
||||||
|
width: 480px;
|
||||||
|
}
|
91
templates/panel/main.scss
Normal file
91
templates/panel/main.scss
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
@import "./nav/main.scss";
|
||||||
|
@import "../components/button";
|
||||||
|
|
||||||
|
.panel__body {
|
||||||
|
width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel__container {
|
||||||
|
width: 80%;
|
||||||
|
align-items: center;
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link__btn {
|
||||||
|
@include button;
|
||||||
|
margin: 0px 5px;
|
||||||
|
padding: 0.3rem 0.3rem;
|
||||||
|
padding-bottom: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
caption-side: bottom;
|
||||||
|
border-color: #e9ecef;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 50%;
|
||||||
|
margin: 20px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
table > thead {
|
||||||
|
vertical-align: bottom;
|
||||||
|
border-bottom: 1px solid #cdc8ca;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
margin: auto;
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 1px solid #edddd1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset__container {
|
||||||
|
margin: 10px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset__name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset__value {
|
||||||
|
margin: 10px 0;
|
||||||
|
display: inline;
|
||||||
|
width: auto;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
padding: 0.125rem 0.25rem;
|
||||||
|
margin: 0 0.25rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 1em;
|
||||||
|
color: #1a1a1a;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
45
templates/panel/nav/index.html
Normal file
45
templates/panel/nav/index.html
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<nav class="nav__container">
|
||||||
|
<input type="checkbox" class="nav__toggle" id="nav__toggle" />
|
||||||
|
|
||||||
|
<div class="nav__header">
|
||||||
|
<a class="nav__logo-container" href="<.= crate::PAGES.home .>">
|
||||||
|
<img src="<.= crate::assets::LOGO.path .>" alt="<.= crate::assets::LOGO.name .>" class="nav__logo" />
|
||||||
|
<p class="nav__logo-text">KAIZEN</p>
|
||||||
|
</a>
|
||||||
|
<label class="nav__hamburger-menu" for="nav__toggle">
|
||||||
|
<span class="nav__hamburger-inner"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav__spacer"></div>
|
||||||
|
|
||||||
|
<div class="nav__link-group">
|
||||||
|
<div class="nav__link-container">
|
||||||
|
<a class="nav__link" rel="noreferrer" href="<.= crate::PAGES.home .>"
|
||||||
|
>Home</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav__link-container">
|
||||||
|
<a
|
||||||
|
class="nav__link"
|
||||||
|
rel="noreferrer"
|
||||||
|
href="<.= crate::PAGES.panel.campaigns.home .>"
|
||||||
|
>Campaigns</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav__link-container">
|
||||||
|
<a class="nav__link" rel="noreferrer" href="/settings">Settings</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav__link-container">
|
||||||
|
<a
|
||||||
|
class="nav__link"
|
||||||
|
rel="noreferrer"
|
||||||
|
href="<.= crate::V1_API_ROUTES.admin.auth.logout .>"
|
||||||
|
>Log out</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
75
templates/panel/nav/main.scss
Normal file
75
templates/panel/nav/main.scss
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.nav__container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-menu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__spacer {
|
||||||
|
flex: 3;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__logo-container {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__logo {
|
||||||
|
display: inline-flex;
|
||||||
|
margin: auto;
|
||||||
|
padding: 5px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__logo-text {
|
||||||
|
margin: auto;
|
||||||
|
letter-spacing: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__link-group {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
align-self: center;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__link-container {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
height: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__link {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
102
templates/panel/nav/mobile.scss
Normal file
102
templates/panel/nav/mobile.scss
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
$hamburger-menu-animation: 0.4s ease-out;
|
||||||
|
$nav__hamburger-inner-height: 1.3px;
|
||||||
|
|
||||||
|
.nav__container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
min-width: 100%;
|
||||||
|
height: 55px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__link-group {
|
||||||
|
position: sticky;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-menu {
|
||||||
|
display: inline-block;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__spacer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__toggle:not(:checked) ~ .nav__link-group {
|
||||||
|
max-height: 0;
|
||||||
|
transition: max-height $hamburger-menu-animation;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__toggle:checked ~ .nav__link-group {
|
||||||
|
max-height: 500px;
|
||||||
|
transition: max-height $hamburger-menu-animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__toggle:checked ~ .nav__header {
|
||||||
|
.nav__hamburger-inner::after {
|
||||||
|
width: 24px;
|
||||||
|
bottom: $nav__hamburger-inner-height;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
transition: bottom 0.1s ease-out,
|
||||||
|
transform 0.22s cubic-bezier(0.215, 0.61, 0.355, 1) 0.12s,
|
||||||
|
width 0.1s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.1s ease-out, opacity 0.1s ease-out 0.12s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-inner {
|
||||||
|
transform: rotate(225deg);
|
||||||
|
transition-delay: 0.12s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-inner::after {
|
||||||
|
bottom: -7px;
|
||||||
|
transition: bottom 0.1s ease-in 0.25s,
|
||||||
|
transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19),
|
||||||
|
width 0.1s ease-in 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-inner::after,
|
||||||
|
.nav__hamburger-inner::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-inner::before {
|
||||||
|
top: -7px;
|
||||||
|
transition: top 0.1s ease-in 0.25s, opacity 0.1s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-inner {
|
||||||
|
top: 50%;
|
||||||
|
margin: auto;
|
||||||
|
transition-duration: 0.22s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-inner,
|
||||||
|
.nav__hamburger-inner::after,
|
||||||
|
.nav__hamburger-inner::before {
|
||||||
|
width: 24px;
|
||||||
|
height: $nav__hamburger-inner-height;
|
||||||
|
position: relative;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__hamburger-menu,
|
||||||
|
.nav__hamburger-inner {
|
||||||
|
display: block;
|
||||||
|
}
|
Loading…
Reference in a new issue