templates: added header, with menu system

This commit is contained in:
Philippe Loctaux 2023-03-10 18:41:57 +01:00
parent fe6ab1bd71
commit 4ff866090b
8 changed files with 162 additions and 0 deletions

View file

@ -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
View 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]
}

View 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>"#
}
}
}
}

View 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(),
}
}
}

View file

@ -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 {

View file

@ -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(),
}, },

View 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>

View 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>