feat: bootstrap homepage for unauthenticated visitors
This commit is contained in:
parent
d994400ff1
commit
d9fc1b8533
3 changed files with 210 additions and 15 deletions
|
@ -14,17 +14,24 @@
|
|||
* 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/>.
|
||||
*/
|
||||
use std::cell::RefCell;
|
||||
|
||||
use actix_identity::Identity;
|
||||
use actix_web::http::header;
|
||||
use actix_web::*;
|
||||
use lazy_static::lazy_static;
|
||||
use rust_embed::RustEmbed;
|
||||
use serde::*;
|
||||
use tera::*;
|
||||
|
||||
use crate::pages::errors::*;
|
||||
use crate::settings::Settings;
|
||||
use crate::static_assets::ASSETS;
|
||||
use crate::AppCtx;
|
||||
use crate::{GIT_COMMIT_HASH, VERSION};
|
||||
|
||||
pub mod auth;
|
||||
pub mod dash;
|
||||
pub mod errors;
|
||||
pub mod routes;
|
||||
|
||||
|
@ -69,6 +76,8 @@ lazy_static! {
|
|||
errors::register_templates(&mut tera);
|
||||
tera.autoescape_on(vec![".html", ".sql"]);
|
||||
auth::register_templates(&mut tera);
|
||||
dash::register_templates(&mut tera);
|
||||
HOME.register(&mut tera).expect(HOME.name);
|
||||
tera
|
||||
};
|
||||
}
|
||||
|
@ -96,15 +105,6 @@ pub fn context(s: &Settings) -> Context {
|
|||
}
|
||||
|
||||
pub fn auth_ctx(username: Option<&str>, s: &Settings) -> Context {
|
||||
// use routes::GistProfilePathComponent;
|
||||
// let mut profile_link = None;
|
||||
// if let Some(name) = username {
|
||||
// profile_link = Some(
|
||||
// PAGES
|
||||
// .gist
|
||||
// .get_profile_route(GistProfilePathComponent { username: name }),
|
||||
// );
|
||||
// }
|
||||
let mut ctx = Context::new();
|
||||
let footer = Footer::new(s);
|
||||
ctx.insert("footer", &footer);
|
||||
|
@ -135,8 +135,52 @@ impl<'a> Footer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const HOME: TemplateFile = TemplateFile::new("home", "pages/index.html");
|
||||
|
||||
pub struct Home {
|
||||
ctx: RefCell<Context>,
|
||||
}
|
||||
|
||||
impl CtxError for Home {
|
||||
fn with_error(&self, e: &ReadableError) -> String {
|
||||
self.ctx.borrow_mut().insert(ERROR_KEY, e);
|
||||
self.render()
|
||||
}
|
||||
}
|
||||
|
||||
impl Home {
|
||||
pub fn new(settings: &Settings) -> Self {
|
||||
let ctx = RefCell::new(context(settings));
|
||||
Self { ctx }
|
||||
}
|
||||
|
||||
pub fn render(&self) -> String {
|
||||
TEMPLATES.render(HOME.name, &self.ctx.borrow()).unwrap()
|
||||
}
|
||||
|
||||
pub fn page(s: &Settings) -> String {
|
||||
let p = Self::new(s);
|
||||
p.render()
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_web_codegen_const_routes::get(path = "PAGES.home")]
|
||||
pub async fn home(ctx: AppCtx, id: Identity) -> impl Responder {
|
||||
if id.identity().is_none() {
|
||||
let home = Home::page(&ctx.settings);
|
||||
let html = header::ContentType::html();
|
||||
HttpResponse::Ok().content_type(html).body(home)
|
||||
} else {
|
||||
HttpResponse::Found()
|
||||
.append_header((header::LOCATION, PAGES.dash.home))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||
auth::services(cfg);
|
||||
dash::services(cfg);
|
||||
cfg.service(home);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -158,6 +202,7 @@ mod tests {
|
|||
auth::login::LOGIN,
|
||||
auth::register::REGISTER,
|
||||
errors::ERROR_TEMPLATE,
|
||||
HOME,
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
|
@ -186,7 +231,7 @@ mod http_page_tests {
|
|||
async fn templates_work(ctx: ArcCtx) {
|
||||
let app = get_app!(ctx).await;
|
||||
|
||||
for file in [PAGES.auth.login, PAGES.auth.register].iter() {
|
||||
for file in [PAGES.auth.login, PAGES.auth.register, PAGES.home].iter() {
|
||||
let resp = get_request!(&app, file);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
}
|
||||
|
|
|
@ -27,14 +27,16 @@ pub struct Pages {
|
|||
pub auth: Auth,
|
||||
/// home page
|
||||
pub home: &'static str,
|
||||
pub dash: Dash,
|
||||
}
|
||||
|
||||
impl Pages {
|
||||
/// create new instance of Routes
|
||||
const fn new() -> Pages {
|
||||
let auth = Auth::new();
|
||||
let home = auth.login;
|
||||
Pages { auth, home }
|
||||
let dash = Dash::new();
|
||||
let home = "/";
|
||||
Pages { auth, home, dash }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,9 +65,19 @@ impl Auth {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GistProfilePathComponent<'a> {
|
||||
pub username: &'a str,
|
||||
#[derive(Serialize)]
|
||||
/// Dashboard routes
|
||||
pub struct Dash {
|
||||
/// home route
|
||||
pub home: &'static str,
|
||||
}
|
||||
|
||||
impl Dash {
|
||||
/// create new instance of Dash route
|
||||
pub const fn new() -> Dash {
|
||||
let home = "/dash";
|
||||
Dash { home }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_auth_middleware() -> Authentication<Pages> {
|
||||
|
|
138
templates/pages/index.html
Normal file
138
templates/pages/index.html
Normal file
|
@ -0,0 +1,138 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="{{ assets.css }}" />
|
||||
<title>LibrePages</title>
|
||||
</head>
|
||||
<body class="auth__body">
|
||||
<header>
|
||||
<nav>
|
||||
<p>LibrePages</p>
|
||||
<span class="nav__spacer"></span>
|
||||
<ul class="nav__links">
|
||||
<li class="nav__item">Help</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<h1>LibrePages: FOSS static site hosting</h1>
|
||||
<p>Welcome to LibrePages. Homepage.</p>
|
||||
</main>
|
||||
{% include "footer" %}
|
||||
</body>
|
||||
|
||||
<style>
|
||||
header {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav__spacer {
|
||||
flex: 4;
|
||||
}
|
||||
|
||||
.nav__links {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav__item {
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
main {
|
||||
width: 100%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.sites__collection {
|
||||
margin: auto;
|
||||
width: 70%;
|
||||
|
||||
border: 1px solid #e8ebed;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.sites__actions {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 20px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.sites__actions__new-site {
|
||||
min-height: 36px;
|
||||
background: green;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0px 8px;
|
||||
}
|
||||
|
||||
.sites__actions__new-site > button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
border: none;
|
||||
width: 100%;
|
||||
color: white;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.site__container {
|
||||
box-sizing: border-box;
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.site__container:hover {
|
||||
background: #f7f8f8;
|
||||
}
|
||||
|
||||
.site__info--head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.site__info--column {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.site__info--column > p,
|
||||
.site__info--column > a {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.site__container:visited,
|
||||
.site__container {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.site__container--preview {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
</html>
|
Loading…
Reference in a new issue