feat: make Nav and Profile menu dynamic
This commit is contained in:
parent
aba6c101cb
commit
78bf81c301
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -69,6 +69,7 @@ dependencies = [
|
|||||||
"askama",
|
"askama",
|
||||||
"askama_axum",
|
"askama_axum",
|
||||||
"axum",
|
"axum",
|
||||||
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
]
|
]
|
||||||
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||||||
askama = "0.12.1"
|
askama = "0.12.1"
|
||||||
askama_axum = "0.4.0"
|
askama_axum = "0.4.0"
|
||||||
axum = "0.7.5"
|
axum = "0.7.5"
|
||||||
|
serde = { version = "1.0.204", features = ["derive"] }
|
||||||
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
|
||||||
tower-http = { version = "0.5.2", features = ["fs"] }
|
tower-http = { version = "0.5.2", features = ["fs"] }
|
||||||
|
|
||||||
|
@ -566,10 +566,6 @@ video {
|
|||||||
border-width: 0;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.visible {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.absolute {
|
.absolute {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
@ -586,15 +582,6 @@ video {
|
|||||||
inset: -0.375rem;
|
inset: -0.375rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inset-y-0 {
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-0 {
|
|
||||||
left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-0 {
|
.right-0 {
|
||||||
right: 0px;
|
right: 0px;
|
||||||
}
|
}
|
||||||
@ -608,22 +595,22 @@ video {
|
|||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ml-3 {
|
|
||||||
margin-left: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-2 {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.-mr-2 {
|
.-mr-2 {
|
||||||
margin-right: -0.5rem;
|
margin-right: -0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ml-3 {
|
||||||
|
margin-left: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.ml-auto {
|
.ml-auto {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mt-2 {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mt-3 {
|
.mt-3 {
|
||||||
margin-top: 0.75rem;
|
margin-top: 0.75rem;
|
||||||
}
|
}
|
||||||
@ -644,6 +631,10 @@ video {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-10 {
|
||||||
|
height: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.h-16 {
|
.h-16 {
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
}
|
}
|
||||||
@ -660,14 +651,14 @@ video {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h-10 {
|
|
||||||
height: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.min-h-full {
|
.min-h-full {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-10 {
|
||||||
|
width: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-48 {
|
.w-48 {
|
||||||
width: 12rem;
|
width: 12rem;
|
||||||
}
|
}
|
||||||
@ -684,10 +675,6 @@ video {
|
|||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-10 {
|
|
||||||
width: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.max-w-7xl {
|
.max-w-7xl {
|
||||||
max-width: 80rem;
|
max-width: 80rem;
|
||||||
}
|
}
|
||||||
@ -696,10 +683,6 @@ video {
|
|||||||
max-width: 20rem;
|
max-width: 20rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-1 {
|
|
||||||
flex: 1 1 0%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-shrink-0 {
|
.flex-shrink-0 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@ -708,32 +691,6 @@ video {
|
|||||||
transform-origin: top right;
|
transform-origin: top right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.-translate-y-full {
|
|
||||||
--tw-translate-y: -100%;
|
|
||||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
||||||
}
|
|
||||||
|
|
||||||
.translate-y-0 {
|
|
||||||
--tw-translate-y: 0px;
|
|
||||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
||||||
}
|
|
||||||
|
|
||||||
.scale-100 {
|
|
||||||
--tw-scale-x: 1;
|
|
||||||
--tw-scale-y: 1;
|
|
||||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
||||||
}
|
|
||||||
|
|
||||||
.scale-95 {
|
|
||||||
--tw-scale-x: .95;
|
|
||||||
--tw-scale-y: .95;
|
|
||||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
||||||
}
|
|
||||||
|
|
||||||
.transform {
|
|
||||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
||||||
}
|
|
||||||
|
|
||||||
.items-center {
|
.items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@ -760,6 +717,10 @@ video {
|
|||||||
border-radius: 0.375rem;
|
border-radius: 0.375rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-b {
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.border-b-2 {
|
.border-b-2 {
|
||||||
border-bottom-width: 2px;
|
border-bottom-width: 2px;
|
||||||
}
|
}
|
||||||
@ -768,14 +729,15 @@ video {
|
|||||||
border-left-width: 4px;
|
border-left-width: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.border-b {
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-t {
|
.border-t {
|
||||||
border-top-width: 1px;
|
border-top-width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-gray-200 {
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.border-indigo-500 {
|
.border-indigo-500 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(99 102 241 / var(--tw-border-opacity));
|
border-color: rgb(99 102 241 / var(--tw-border-opacity));
|
||||||
@ -785,11 +747,6 @@ video {
|
|||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.border-gray-200 {
|
|
||||||
--tw-border-opacity: 1;
|
|
||||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-gray-100 {
|
.bg-gray-100 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
||||||
@ -818,11 +775,6 @@ video {
|
|||||||
padding-right: 0.25rem;
|
padding-right: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.px-2 {
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
padding-right: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.px-4 {
|
.px-4 {
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
padding-right: 1rem;
|
padding-right: 1rem;
|
||||||
@ -848,18 +800,14 @@ video {
|
|||||||
padding-bottom: 2rem;
|
padding-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pb-4 {
|
.pb-3 {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pl-3 {
|
.pl-3 {
|
||||||
padding-left: 0.75rem;
|
padding-left: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pr-2 {
|
|
||||||
padding-right: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pr-4 {
|
.pr-4 {
|
||||||
padding-right: 1rem;
|
padding-right: 1rem;
|
||||||
}
|
}
|
||||||
@ -872,10 +820,6 @@ video {
|
|||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pb-3 {
|
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pt-4 {
|
.pt-4 {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
@ -921,11 +865,21 @@ video {
|
|||||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-gray-600 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(75 85 99 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.text-gray-700 {
|
.text-gray-700 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(55 65 81 / var(--tw-text-opacity));
|
color: rgb(55 65 81 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-gray-800 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(31 41 55 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.text-gray-900 {
|
.text-gray-900 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(17 24 39 / var(--tw-text-opacity));
|
color: rgb(17 24 39 / var(--tw-text-opacity));
|
||||||
@ -936,30 +890,6 @@ video {
|
|||||||
color: rgb(67 56 202 / var(--tw-text-opacity));
|
color: rgb(67 56 202 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-gray-600 {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(75 85 99 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-gray-800 {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(31 41 55 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.opacity-0 {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.opacity-100 {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow {
|
|
||||||
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
||||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow-lg {
|
.shadow-lg {
|
||||||
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||||
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
||||||
@ -981,34 +911,6 @@ video {
|
|||||||
--tw-ring-opacity: 0.05;
|
--tw-ring-opacity: 0.05;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transition {
|
|
||||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
|
|
||||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
|
|
||||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duration-200 {
|
|
||||||
transition-duration: 200ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duration-75 {
|
|
||||||
transition-duration: 75ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duration-300 {
|
|
||||||
transition-duration: 300ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ease-in {
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ease-out {
|
|
||||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover\:border-gray-300:hover {
|
.hover\:border-gray-300:hover {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
||||||
@ -1050,10 +952,6 @@ video {
|
|||||||
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.focus\:ring-inset:focus {
|
|
||||||
--tw-ring-inset: inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.focus\:ring-indigo-500:focus {
|
.focus\:ring-indigo-500:focus {
|
||||||
--tw-ring-opacity: 1;
|
--tw-ring-opacity: 1;
|
||||||
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
|
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
|
||||||
@ -1064,14 +962,6 @@ video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 640px) {
|
@media (min-width: 640px) {
|
||||||
.sm\:static {
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm\:inset-auto {
|
|
||||||
inset: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm\:-my-px {
|
.sm\:-my-px {
|
||||||
margin-top: -1px;
|
margin-top: -1px;
|
||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
@ -1093,14 +983,6 @@ video {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm\:items-stretch {
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm\:justify-start {
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm\:space-x-8 > :not([hidden]) ~ :not([hidden]) {
|
.sm\:space-x-8 > :not([hidden]) ~ :not([hidden]) {
|
||||||
--tw-space-x-reverse: 0;
|
--tw-space-x-reverse: 0;
|
||||||
margin-right: calc(2rem * var(--tw-space-x-reverse));
|
margin-right: calc(2rem * var(--tw-space-x-reverse));
|
||||||
@ -1111,10 +993,6 @@ video {
|
|||||||
padding-left: 1.5rem;
|
padding-left: 1.5rem;
|
||||||
padding-right: 1.5rem;
|
padding-right: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm\:pr-0 {
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
|
||||||
mod hello;
|
mod hello;
|
||||||
|
mod nav;
|
||||||
|
mod profile;
|
||||||
|
|
||||||
pub fn get_routes() -> Router {
|
pub fn get_routes() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.nest("/hello", hello::get_routes())
|
.nest("/hello", hello::get_routes())
|
||||||
|
.nest("/nav", nav::get_routes())
|
||||||
|
.nest("/profile", profile::get_routes())
|
||||||
}
|
}
|
||||||
|
65
crates/app/src/templates/nav.rs
Normal file
65
crates/app/src/templates/nav.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use askama::Template;
|
||||||
|
use askama_axum::IntoResponse;
|
||||||
|
use axum::{extract::Query, routing, Router};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
struct MenuItem {
|
||||||
|
label: String,
|
||||||
|
id: String,
|
||||||
|
current: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct MenuParameters {
|
||||||
|
mobile: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "layout/nav/nav-menu-items.html")]
|
||||||
|
struct MenuResponse {
|
||||||
|
mobile: bool,
|
||||||
|
items: Vec<MenuItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MenuResponse {
|
||||||
|
fn get_classes(&self, is_current_item: &bool) -> String {
|
||||||
|
let common_classes = match self.mobile {
|
||||||
|
true => "block border-l-4 py-2 pl-3 pr-4 text-base font-medium".to_string(),
|
||||||
|
false => "inline-flex items-center border-b-2 px-1 pt-1 text-sm font-medium".to_string(),
|
||||||
|
};
|
||||||
|
match (self.mobile, is_current_item) {
|
||||||
|
(true, true) => common_classes + " border-indigo-500 bg-indigo-50 text-indigo-700",
|
||||||
|
(true, false) => common_classes + " border-transparent text-gray-600 hover:border-gray-300 hover:bg-gray-50 hover:text-gray-800",
|
||||||
|
(false, true) => common_classes + " border-indigo-500 text-gray-900",
|
||||||
|
(false, false) => common_classes + " border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn menu(Query(params): Query<MenuParameters>) -> impl IntoResponse {
|
||||||
|
MenuResponse {
|
||||||
|
mobile: params.mobile,
|
||||||
|
items: vec![
|
||||||
|
MenuItem {
|
||||||
|
label: "Accueil".to_string(),
|
||||||
|
id: "home".to_string(),
|
||||||
|
current: true,
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
label: "À propos".to_string(),
|
||||||
|
id: "about".to_string(),
|
||||||
|
current: false,
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
label: "Contact".to_string(),
|
||||||
|
id: "contact".to_string(),
|
||||||
|
current: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}.into_response()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_routes() -> Router {
|
||||||
|
Router::new()
|
||||||
|
.route("/menu", routing::get(menu))
|
||||||
|
}
|
65
crates/app/src/templates/profile.rs
Normal file
65
crates/app/src/templates/profile.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use askama::Template;
|
||||||
|
use askama_axum::IntoResponse;
|
||||||
|
use axum::{extract::Query, routing, Router};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
struct MenuItem {
|
||||||
|
label: String,
|
||||||
|
id: String,
|
||||||
|
current: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct MenuParameters {
|
||||||
|
mobile: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "layout/nav/profile-menu-items.html")]
|
||||||
|
struct MenuResponse {
|
||||||
|
mobile: bool,
|
||||||
|
items: Vec<MenuItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MenuResponse {
|
||||||
|
fn get_classes(&self, is_current_item: &bool) -> String {
|
||||||
|
let common_classes = match self.mobile {
|
||||||
|
true => "block px-4 py-2 text-base font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-800".to_string(),
|
||||||
|
false => "block px-4 py-2 text-sm text-gray-700".to_string(),
|
||||||
|
};
|
||||||
|
match (self.mobile, is_current_item) {
|
||||||
|
(true, true) => common_classes + "", // ???
|
||||||
|
(true, false) => common_classes + "",
|
||||||
|
(false, true) => common_classes + " bg-gray-100",
|
||||||
|
(false, false) => common_classes + "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn menu(Query(params): Query<MenuParameters>) -> impl IntoResponse {
|
||||||
|
MenuResponse {
|
||||||
|
mobile: params.mobile,
|
||||||
|
items: vec![
|
||||||
|
MenuItem {
|
||||||
|
label: "Votre profil".to_string(),
|
||||||
|
id: "profile".to_string(),
|
||||||
|
current: false,
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
label: "Paramètres".to_string(),
|
||||||
|
id: "settings".to_string(),
|
||||||
|
current: false,
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
label: "Déconnexion".to_string(),
|
||||||
|
id: "logout".to_string(),
|
||||||
|
current: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}.into_response()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_routes() -> Router {
|
||||||
|
Router::new()
|
||||||
|
.route("/menu", routing::get(menu))
|
||||||
|
}
|
@ -19,7 +19,7 @@
|
|||||||
hx-trigger="load"
|
hx-trigger="load"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
>
|
>
|
||||||
Loading...
|
Chargement ...
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -1,22 +1,9 @@
|
|||||||
<!-- Current: "border-indigo-500 text-gray-900", Default: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" -->
|
<div
|
||||||
<a
|
id="nav-menu-desktop"
|
||||||
href="#"
|
hx-get="/nav/menu?mobile=false"
|
||||||
class="inline-flex items-center border-b-2 border-indigo-500 px-1 pt-1 text-sm font-medium text-gray-900"
|
hx-target="this"
|
||||||
aria-current="page"
|
hx-trigger="load"
|
||||||
>Dashboard</a
|
hx-swap="outerHTML"
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="inline-flex items-center border-b-2 border-transparent px-1 pt-1 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700"
|
|
||||||
>Team</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="inline-flex items-center border-b-2 border-transparent px-1 pt-1 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700"
|
|
||||||
>Projects</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="inline-flex items-center border-b-2 border-transparent px-1 pt-1 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700"
|
|
||||||
>Calendar</a
|
|
||||||
>
|
>
|
||||||
|
Chargement ...
|
||||||
|
</div>
|
||||||
|
@ -10,29 +10,13 @@
|
|||||||
x-cloak
|
x-cloak
|
||||||
x-transition
|
x-transition
|
||||||
>
|
>
|
||||||
<!-- Active: "bg-gray-100", Not Active: "" -->
|
<div
|
||||||
<a
|
id="profile-menu-desktop"
|
||||||
href="#"
|
hx-get="/profile/menu?mobile=false"
|
||||||
class="block px-4 py-2 text-sm text-gray-700"
|
hx-target="this"
|
||||||
role="menuitem"
|
hx-trigger="load"
|
||||||
tabindex="-1"
|
hx-swap="outerHTML"
|
||||||
id="user-menu-item-0"
|
|
||||||
>Your Profile</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="block px-4 py-2 text-sm text-gray-700"
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="-1"
|
|
||||||
id="user-menu-item-1"
|
|
||||||
>Settings</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="block px-4 py-2 text-sm text-gray-700"
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="-1"
|
|
||||||
id="user-menu-item-2"
|
|
||||||
>Sign out</a
|
|
||||||
>
|
>
|
||||||
|
Chargement ...
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,22 +1,9 @@
|
|||||||
<!-- Current: "border-indigo-500 bg-indigo-50 text-indigo-700", Default: "border-transparent text-gray-600 hover:border-gray-300 hover:bg-gray-50 hover:text-gray-800" -->
|
<div
|
||||||
<a
|
id="nav-menu-mobile"
|
||||||
href="#"
|
hx-get="/nav/menu?mobile=true"
|
||||||
class="block border-l-4 border-indigo-500 bg-indigo-50 py-2 pl-3 pr-4 text-base font-medium text-indigo-700"
|
hx-target="this"
|
||||||
aria-current="page"
|
hx-trigger="load"
|
||||||
>Dashboard</a
|
hx-swap="outerHTML"
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="block border-l-4 border-transparent py-2 pl-3 pr-4 text-base font-medium text-gray-600 hover:border-gray-300 hover:bg-gray-50 hover:text-gray-800"
|
|
||||||
>Team</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="block border-l-4 border-transparent py-2 pl-3 pr-4 text-base font-medium text-gray-600 hover:border-gray-300 hover:bg-gray-50 hover:text-gray-800"
|
|
||||||
>Projects</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="block border-l-4 border-transparent py-2 pl-3 pr-4 text-base font-medium text-gray-600 hover:border-gray-300 hover:bg-gray-50 hover:text-gray-800"
|
|
||||||
>Calendar</a
|
|
||||||
>
|
>
|
||||||
|
Chargement ...
|
||||||
|
</div>
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
<a
|
<div
|
||||||
href="#"
|
id="profile-menu-mobile"
|
||||||
class="block px-4 py-2 text-base font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-800"
|
hx-get="/profile/menu?mobile=true"
|
||||||
>Your Profile</a
|
hx-target="this"
|
||||||
>
|
hx-trigger="load"
|
||||||
<a
|
hx-swap="outerHTML"
|
||||||
href="#"
|
|
||||||
class="block px-4 py-2 text-base font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-800"
|
|
||||||
>Settings</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="block px-4 py-2 text-base font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-800"
|
|
||||||
>Sign out</a
|
|
||||||
>
|
>
|
||||||
|
Chargement ...
|
||||||
|
</div>
|
||||||
|
9
crates/app/templates/layout/nav/nav-menu-items.html
Normal file
9
crates/app/templates/layout/nav/nav-menu-items.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% for item in items %}
|
||||||
|
<a
|
||||||
|
href="#{{ item.id }}"
|
||||||
|
class="{{ Self::get_classes(self, item.current) }}"
|
||||||
|
aria-current="{% if item.current %}page{% endif %}"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
11
crates/app/templates/layout/nav/profile-menu-items.html
Normal file
11
crates/app/templates/layout/nav/profile-menu-items.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% for item in items %}
|
||||||
|
<a
|
||||||
|
href="#{{ item.id }}"
|
||||||
|
class="{{ Self::get_classes(self, item.current) }}"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="-1"
|
||||||
|
id="{{ item.id }}"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
Loading…
Reference in New Issue
Block a user