templates: added header, with menu system
This commit is contained in:
parent
fe6ab1bd71
commit
4ff866090b
8 changed files with 162 additions and 0 deletions
|
|
@ -6,6 +6,7 @@ mod error;
|
||||||
mod file_from_bytes;
|
mod file_from_bytes;
|
||||||
mod guards;
|
mod guards;
|
||||||
mod id;
|
mod id;
|
||||||
|
mod menu;
|
||||||
mod page;
|
mod page;
|
||||||
mod response_timer;
|
mod response_timer;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
|
|
||||||
24
crates/ezidam/src/menu.rs
Normal file
24
crates/ezidam/src/menu.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
mod items;
|
||||||
|
mod template;
|
||||||
|
|
||||||
|
pub use items::Item;
|
||||||
|
pub use template::Template;
|
||||||
|
|
||||||
|
pub struct Menu {
|
||||||
|
pub selected: Item,
|
||||||
|
pub list: Vec<Item>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Item> for Menu {
|
||||||
|
fn from(value: Item) -> Self {
|
||||||
|
Self {
|
||||||
|
selected: value,
|
||||||
|
list: list(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declare list of ordered menu items
|
||||||
|
fn list() -> Vec<Item> {
|
||||||
|
vec![Item::Home]
|
||||||
|
}
|
||||||
32
crates/ezidam/src/menu/items.rs
Normal file
32
crates/ezidam/src/menu/items.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
pub enum Item {
|
||||||
|
Home,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Item {
|
||||||
|
pub fn id(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Item::Home => "home",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn label(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Item::Home => "Home",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn link(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Item::Home => "/",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find icons on https://tabler-icons.io
|
||||||
|
pub fn icon(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Item::Home => {
|
||||||
|
r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-home" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 12l-2 0l9 -9l9 9l-2 0"></path><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7"></path><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"></path></svg>"#
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
crates/ezidam/src/menu/template.rs
Normal file
22
crates/ezidam/src/menu/template.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
use super::Item;
|
||||||
|
use rocket::serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct Template {
|
||||||
|
id: &'static str,
|
||||||
|
label: &'static str,
|
||||||
|
link: &'static str,
|
||||||
|
icon: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Item> for Template {
|
||||||
|
fn from(value: Item) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.id(),
|
||||||
|
label: value.label(),
|
||||||
|
link: value.link(),
|
||||||
|
icon: value.icon(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ mod responder;
|
||||||
mod template;
|
mod template;
|
||||||
|
|
||||||
use self::content::*;
|
use self::content::*;
|
||||||
|
use crate::menu::{Item, Menu};
|
||||||
use erased_serde::Serialize;
|
use erased_serde::Serialize;
|
||||||
|
|
||||||
pub use flash::FlashKind;
|
pub use flash::FlashKind;
|
||||||
|
|
@ -33,6 +34,15 @@ impl Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show menu with active item
|
||||||
|
fn menu(&self) -> Option<Menu> {
|
||||||
|
match self {
|
||||||
|
Page::Error(_) => None,
|
||||||
|
Page::Setup => None,
|
||||||
|
Page::Homepage(_) => Some(Item::Home.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Structure to render in page
|
/// Structure to render in page
|
||||||
fn content(self) -> Box<dyn Serialize> {
|
fn content(self) -> Box<dyn Serialize> {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use super::Page;
|
use super::Page;
|
||||||
|
use crate::menu::Template as MenuTemplate;
|
||||||
use rocket::request::FlashMessage;
|
use rocket::request::FlashMessage;
|
||||||
use rocket::serde::Serialize;
|
use rocket::serde::Serialize;
|
||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
|
|
@ -8,6 +9,7 @@ use rocket_dyn_templates::Template;
|
||||||
struct TemplateContent<S: Serialize> {
|
struct TemplateContent<S: Serialize> {
|
||||||
title: &'static str,
|
title: &'static str,
|
||||||
version: &'static str,
|
version: &'static str,
|
||||||
|
menu: Option<(&'static str, Vec<MenuTemplate>)>,
|
||||||
flash: Option<(String, String)>,
|
flash: Option<(String, String)>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
|
@ -20,6 +22,12 @@ fn render(p: Page, flash: Option<(String, String)>) -> Template {
|
||||||
TemplateContent {
|
TemplateContent {
|
||||||
title: p.page_title(),
|
title: p.page_title(),
|
||||||
version: env!("CARGO_PKG_VERSION"),
|
version: env!("CARGO_PKG_VERSION"),
|
||||||
|
menu: p.menu().map(|menu| {
|
||||||
|
(
|
||||||
|
menu.selected.id(),
|
||||||
|
menu.list.into_iter().map(MenuTemplate::from).collect(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
flash,
|
flash,
|
||||||
content: p.content(),
|
content: p.content(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
43
crates/ezidam/templates/shell/header.html.tera
Normal file
43
crates/ezidam/templates/shell/header.html.tera
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<header class="navbar navbar-expand-md navbar-light d-print-none">
|
||||||
|
<div class="container-xl">
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu" aria-controls="navbar-menu" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<h1 class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
|
||||||
|
{% include "utils/logo_header" %}
|
||||||
|
</h1>
|
||||||
|
<div class="navbar-nav flex-row order-md-last">
|
||||||
|
<div class="d-none d-md-flex me-3">
|
||||||
|
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode" data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="bottom">
|
||||||
|
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" /></svg>
|
||||||
|
</a>
|
||||||
|
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode" data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="bottom">
|
||||||
|
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" /><path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" /></svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item dropdown">
|
||||||
|
<a href="#" class="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown" aria-label="Open user menu">
|
||||||
|
<span class="avatar avatar-sm" style="background-image: url(/avatar/ycpkJNdAiz947WB?size=250)"></span>
|
||||||
|
<div class="d-none d-xl-block ps-2">
|
||||||
|
<div>Dunn Slane</div>
|
||||||
|
<div class="mt-1 small text-muted">Research Nurse</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
||||||
|
<a href="./settings" class="dropdown-item">Settings</a>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
<a href="#" class="dropdown-item">Logout</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if menu %}
|
||||||
|
{% include "shell/nav" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
22
crates/ezidam/templates/shell/nav.html.tera
Normal file
22
crates/ezidam/templates/shell/nav.html.tera
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="collapse navbar-collapse" id="navbar-menu">
|
||||||
|
<div class="d-flex flex-column flex-md-row flex-fill align-items-stretch align-items-md-center">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
{% for item in menu.1 %}
|
||||||
|
|
||||||
|
{% if item.id == menu.0 %}
|
||||||
|
<li class="nav-item active">
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<a class="nav-link" href="{{ item.link }}">
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">{{item.icon | safe }}</span>
|
||||||
|
<span class="nav-link-title">{{ item.label }}</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue