create frontend template

This commit is contained in:
2024-10-05 14:57:39 +08:00
commit d29d63d3ce
23 changed files with 3855 additions and 0 deletions

View File

@ -0,0 +1,158 @@
use yew::{classes, function_component, html, use_state_eq, Callback, Html, MouseEvent};
use yew_router::{components::Link, hooks::use_location, Routable};
use crate::app::Route;
#[function_component(Nav)]
pub fn nav_bar() -> Html {
let show_dropdown = use_state_eq(|| false);
let show_dropdown_handle = show_dropdown.clone();
let mut dropdown_classes = vec![
"absolute", "right-0", "z-10", "mt-2", "w-48", "origin-top-right", "rounded-md", "bg-white", "py-1", "shadow-lg", "ring-1", "ring-black", "ring-opacity-5", "focus:outline-none"
];
if !*show_dropdown {
dropdown_classes.push("hidden");
}
let dropdown_toggler = Callback::from(move |_: MouseEvent| {
gloo::console::log!("dropdown: ", *show_dropdown_handle);
show_dropdown_handle.set(!*show_dropdown_handle);
});
let show_dropdown_handle = show_dropdown.clone();
let dropdown_leave = Callback::from(move |_: MouseEvent| {
show_dropdown_handle.set(false);
});
let show_mobile_menu = use_state_eq(||false);
let (mut mobile_icon, mut mobile_icon_expanded) = (vec!["h-6", "w-6", "block"], vec!["h-6", "w-6", "hidden"]);
let mut mobile_menu_classes = vec!["sm:hidden"];
if *show_mobile_menu {
(mobile_icon, mobile_icon_expanded) = (mobile_icon_expanded, mobile_icon);
} else {
mobile_menu_classes.push("hidden");
}
let show_mobile_menu_handler = show_mobile_menu.clone();
let mobile_menu_toggler = Callback::from(move |_:MouseEvent| {
show_mobile_menu_handler.set(!*show_mobile_menu_handler);
});
let mut menu = Vec::new();
let mut mobile_menu = Vec::new();
let maybe_location = use_location();
for (route, title) in [
(Route::Home, "Home"),
(Route::Counter, "Counter"),
] {
let active_item = if let Some(ref location) = maybe_location {
let path = location.path();
if let Some(recognized_route) = Route::recognize(path) {
recognized_route == route
} else {
false
}
} else {
false
};
let item_classes = if active_item {
"rounded-md bg-gray-900 px-3 py-2 text-sm font-medium text-white"
} else {
"rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
};
let mobile_classes = format!("block {item_classes}");
menu.push(html! {
<Link<Route> classes={item_classes} to={route.clone()}>{ title }</Link<Route>>
});
mobile_menu.push(html! {
<Link<Route> classes={classes!(mobile_classes)} to={route.clone()}>{ title }</Link<Route>>
});
}
html! {
<nav class="bg-gray-800">
<div class="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
<div class="relative flex h-16 items-center justify-between">
<div class="absolute inset-y-0 left-0 flex items-center sm:hidden">
// <!-- Mobile menu button-->
<button onclick={mobile_menu_toggler} type="button" class="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white" aria-controls="mobile-menu" aria-expanded="false">
<span class="absolute -inset-0.5"></span>
<span class="sr-only">{"Open main menu"}</span>
/*
Icon when menu is closed.
Menu open: "hidden", Menu closed: "block"
*/
<svg class={classes!(mobile_icon)} fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
/*
Icon when menu is open.
Menu open: "block", Menu closed: "hidden"
*/
<svg class={classes!(mobile_icon_expanded)} fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="flex flex-1 items-center justify-center sm:items-stretch sm:justify-start">
<div class="flex flex-shrink-0 items-center">
<img class="h-8 w-auto" src="https://tailwindui.com/plus/img/logos/mark.svg?color=indigo&shade=500" alt="Your Company" />
</div>
<div class="hidden sm:ml-6 sm:block">
<div class="flex space-x-4">
/* Current: "bg-gray-900 text-white", Default: "text-gray-300 hover:bg-gray-700 hover:text-white" */
{ menu.clone() }
</div>
</div>
</div>
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
<button type="button" class="relative rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800">
<span class="absolute -inset-1.5"></span>
<span class="sr-only">{"View notifications"}</span>
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0" />
</svg>
</button>
/* Profile dropdown */
<div class={classes!(vec!["relative", "ml-3"])} onclick={dropdown_toggler} >
<div>
<button type="button" class="relative flex rounded-full bg-gray-800 text-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800" id="user-menu-button" aria-expanded="false" aria-haspopup="true">
<span class="absolute -inset-1.5"></span>
<span class="sr-only">{"Open user menu"}</span>
<img class="h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" />
</button>
</div>
/*
Dropdown menu, show/hide based on menu state.
Entering: "transition ease-out duration-100"
From: "transform opacity-0 scale-95"
To: "transform opacity-100 scale-100"
Leaving: "transition ease-in duration-75"
From: "transform opacity-100 scale-100"
To: "transform opacity-0 scale-95"
*/
<div class={classes!(dropdown_classes)} onmouseleave={dropdown_leave} role="menu" aria-orientation="vertical" aria-labelledby="user-menu-button" tabindex="-1">
/* Active: "bg-gray-100", Not Active: "" */
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" 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>
</div>
</div>
</div>
</div>
</div>
/* Mobile menu, show/hide based on menu state. */
<div class={classes!(mobile_menu_classes)} id="mobile-menu">
<div class="space-y-1 px-2 pb-3 pt-2">
/* Current: "bg-gray-900 text-white", Default: "text-gray-300 hover:bg-gray-700 hover:text-white" */
{ mobile_menu.clone() }
</div>
</div>
</nav>
}
}