feat(ui): add responsive mobile layout with hamburger menu
Some checks failed
CI / Format (push) Failing after 3s
CI / Clippy (push) Failing after 4s
CI / Security Audit (push) Has been skipped
CI / Tests (push) Has been skipped
CI / Format (pull_request) Failing after 3s
CI / Clippy (pull_request) Failing after 4s
CI / Security Audit (pull_request) Has been skipped
CI / Tests (pull_request) Has been skipped
CI / Deploy (push) Has been skipped
CI / Deploy (pull_request) Has been skipped
Some checks failed
CI / Format (push) Failing after 3s
CI / Clippy (push) Failing after 4s
CI / Security Audit (push) Has been skipped
CI / Tests (push) Has been skipped
CI / Format (pull_request) Failing after 3s
CI / Clippy (pull_request) Failing after 4s
CI / Security Audit (pull_request) Has been skipped
CI / Tests (pull_request) Has been skipped
CI / Deploy (push) Has been skipped
CI / Deploy (pull_request) Has been skipped
Add three responsive breakpoints (1024px, 768px, 480px) to make the dashboard fully usable on tablets and phones. The sidebar now slides in as an overlay on mobile with a hamburger toggle in a fixed header bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
292
assets/main.css
292
assets/main.css
@@ -57,6 +57,16 @@ h6 {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== Mobile Header ===== */
|
||||||
|
.mobile-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Sidebar Backdrop ===== */
|
||||||
|
.sidebar-backdrop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== Sidebar ===== */
|
/* ===== Sidebar ===== */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 260px;
|
width: 260px;
|
||||||
@@ -2940,7 +2950,7 @@ h6 {
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Responsive: Dashboard Pages ===== */
|
/* ===== Responsive: Tablet (max-width: 1024px) ===== */
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
|
|
||||||
.news-grid,
|
.news-grid,
|
||||||
@@ -2988,10 +2998,97 @@ h6 {
|
|||||||
.news-grid--compact {
|
.news-grid--compact {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
padding: 32px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-page {
|
||||||
|
margin: -32px -24px;
|
||||||
|
height: calc(100vh - 64px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== Responsive: Mobile (max-width: 768px) ===== */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
||||||
|
/* -- Mobile header bar with hamburger -- */
|
||||||
|
.mobile-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 90;
|
||||||
|
height: 56px;
|
||||||
|
padding: 0 16px;
|
||||||
|
background-color: var(--bg-sidebar);
|
||||||
|
border-bottom: 1px solid var(--border-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-btn:hover {
|
||||||
|
background-color: var(--bg-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header-title {
|
||||||
|
font-family: 'Space Grotesk', sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Sidebar: hidden off-screen, slides in as overlay -- */
|
||||||
|
.app-shell {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 200;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
transition: transform 0.25s ease;
|
||||||
|
width: 280px;
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar--open {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-backdrop {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 199;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Main content: add top padding for mobile header -- */
|
||||||
|
.main-content {
|
||||||
|
padding: 72px 16px 24px;
|
||||||
|
min-height: calc(100vh - 56px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Dashboard grids -- */
|
||||||
.news-grid,
|
.news-grid,
|
||||||
.tools-grid,
|
.tools-grid,
|
||||||
.pricing-grid {
|
.pricing-grid {
|
||||||
@@ -3002,9 +3099,16 @@ h6 {
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Chat page -- */
|
||||||
.chat-page {
|
.chat-page {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
min-height: calc(100vh - 56px);
|
||||||
|
margin: -72px -16px -24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-sidebar-panel {
|
.chat-sidebar-panel {
|
||||||
@@ -3015,11 +3119,34 @@ h6 {
|
|||||||
border-bottom: 1px solid var(--border-primary);
|
border-bottom: 1px solid var(--border-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-messages,
|
||||||
|
.chat-message-list {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-input-bar {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-model-bar {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-bubble {
|
||||||
|
max-width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Page header -- */
|
||||||
.page-header {
|
.page-header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Stats bars -- */
|
||||||
.analytics-stats-bar {
|
.analytics-stats-bar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -3028,8 +3155,171 @@ h6 {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Sub navigation (Developer/Org tabs) -- */
|
||||||
|
.sub-nav {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-nav-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Modal -- */
|
||||||
.modal-content {
|
.modal-content {
|
||||||
min-width: unset;
|
min-width: unset;
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
|
max-width: calc(100vw - 32px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Dashboard filters -- */
|
||||||
|
.dashboard-filters {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tab {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Providers page -- */
|
||||||
|
.providers-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Tables: horizontal scroll -- */
|
||||||
|
.knowledge-table-wrapper,
|
||||||
|
.org-table-wrapper {
|
||||||
|
margin: 0 -16px;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings -- */
|
||||||
|
.settings-input {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Placeholder pages -- */
|
||||||
|
.placeholder-card {
|
||||||
|
padding: 32px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Article detail -- */
|
||||||
|
.article-detail-title {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-detail-content {
|
||||||
|
padding-right: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- CTA banner -- */
|
||||||
|
.cta-banner {
|
||||||
|
padding: 32px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-title {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Pricing cards -- */
|
||||||
|
.pricing-card {
|
||||||
|
padding: 24px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Responsive: Small Phones (max-width: 480px) ===== */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
padding: 64px 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-page {
|
||||||
|
margin: -64px -12px -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-subtitle {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-heading {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-card {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-card {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-card-body {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-proof-stats {
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proof-divider {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proof-stat-value {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 260px;
|
||||||
|
min-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-bubble {
|
||||||
|
max-width: 95%;
|
||||||
|
padding: 10px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-nav-inner {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features-section,
|
||||||
|
.how-it-works-section {
|
||||||
|
padding: 48px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-card {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card {
|
||||||
|
padding: 20px 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,6 +356,95 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.dropdown {
|
||||||
|
@layer daisyui.l1.l2.l3 {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
position-area: var(--anchor-v, bottom) var(--anchor-h, span-right);
|
||||||
|
& > *:not(:has(~ [class*="dropdown-content"])):focus {
|
||||||
|
--tw-outline-style: none;
|
||||||
|
outline-style: none;
|
||||||
|
@media (forced-colors: active) {
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropdown-content {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
&.dropdown-close .dropdown-content, &:not(details, .dropdown-open, .dropdown-hover:hover, :focus-within) .dropdown-content, &.dropdown-hover:not(:hover) [tabindex]:first-child:focus:not(:focus-visible) ~ .dropdown-content {
|
||||||
|
display: none;
|
||||||
|
transform-origin: top;
|
||||||
|
opacity: 0%;
|
||||||
|
scale: 95%;
|
||||||
|
}
|
||||||
|
&[popover], .dropdown-content {
|
||||||
|
z-index: 999;
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
animation: dropdown 0.2s;
|
||||||
|
transition-property: opacity, scale, display;
|
||||||
|
transition-behavior: allow-discrete;
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@starting-style {
|
||||||
|
&[popover], .dropdown-content {
|
||||||
|
scale: 95%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(.dropdown-close) {
|
||||||
|
&.dropdown-open, &:not(.dropdown-hover):focus, &:focus-within {
|
||||||
|
> [tabindex]:first-child {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.dropdown-content {
|
||||||
|
opacity: 100%;
|
||||||
|
scale: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.dropdown-hover:hover {
|
||||||
|
.dropdown-content {
|
||||||
|
opacity: 100%;
|
||||||
|
scale: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:is(details) {
|
||||||
|
summary {
|
||||||
|
&::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:where([popover]) {
|
||||||
|
background: #0000;
|
||||||
|
}
|
||||||
|
&[popover] {
|
||||||
|
position: fixed;
|
||||||
|
color: inherit;
|
||||||
|
@supports not (position-area: bottom) {
|
||||||
|
margin: auto;
|
||||||
|
&.dropdown-close, &.dropdown-open:not(:popover-open) {
|
||||||
|
display: none;
|
||||||
|
transform-origin: top;
|
||||||
|
opacity: 0%;
|
||||||
|
scale: 95%;
|
||||||
|
}
|
||||||
|
&::backdrop {
|
||||||
|
background-color: color-mix(in oklab, #000 30%, #0000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.dropdown-close, &:not(.dropdown-open, :popover-open) {
|
||||||
|
display: none;
|
||||||
|
transform-origin: top;
|
||||||
|
opacity: 0%;
|
||||||
|
scale: 95%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.btn {
|
.btn {
|
||||||
:where(&) {
|
:where(&) {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_free_icons::icons::bs_icons::{BsList, BsX};
|
||||||
|
use dioxus_free_icons::Icon;
|
||||||
|
|
||||||
use crate::components::sidebar::Sidebar;
|
use crate::components::sidebar::Sidebar;
|
||||||
use crate::i18n::{t, tw, Locale};
|
use crate::i18n::{t, tw, Locale};
|
||||||
@@ -14,6 +16,7 @@ use crate::Route;
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn AppShell() -> Element {
|
pub fn AppShell() -> Element {
|
||||||
let locale = use_context::<Signal<Locale>>();
|
let locale = use_context::<Signal<Locale>>();
|
||||||
|
let mut mobile_menu_open = use_signal(|| false);
|
||||||
|
|
||||||
// use_resource memoises the async call and avoids infinite re-render
|
// use_resource memoises the async call and avoids infinite re-render
|
||||||
// loops that use_effect + spawn + signal writes can cause.
|
// loops that use_effect + spawn + signal writes can cause.
|
||||||
@@ -26,12 +29,44 @@ pub fn AppShell() -> Element {
|
|||||||
|
|
||||||
match auth_snapshot {
|
match auth_snapshot {
|
||||||
Some(Ok(info)) if info.authenticated => {
|
Some(Ok(info)) if info.authenticated => {
|
||||||
|
let menu_open = *mobile_menu_open.read();
|
||||||
|
let sidebar_cls = if menu_open {
|
||||||
|
"sidebar sidebar--open"
|
||||||
|
} else {
|
||||||
|
"sidebar"
|
||||||
|
};
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "app-shell",
|
div { class: "app-shell",
|
||||||
|
// Mobile top bar (visible only on small screens via CSS)
|
||||||
|
header { class: "mobile-header",
|
||||||
|
button {
|
||||||
|
class: "mobile-menu-btn",
|
||||||
|
onclick: move |_| {
|
||||||
|
let current = *mobile_menu_open.read();
|
||||||
|
mobile_menu_open.set(!current);
|
||||||
|
},
|
||||||
|
if menu_open {
|
||||||
|
Icon { icon: BsX, width: 24, height: 24 }
|
||||||
|
} else {
|
||||||
|
Icon { icon: BsList, width: 24, height: 24 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span { class: "mobile-header-title", "CERTifAI" }
|
||||||
|
}
|
||||||
|
// Backdrop overlay when sidebar is open on mobile
|
||||||
|
if menu_open {
|
||||||
|
div {
|
||||||
|
class: "sidebar-backdrop",
|
||||||
|
onclick: move |_| mobile_menu_open.set(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
Sidebar {
|
Sidebar {
|
||||||
email: info.email,
|
email: info.email,
|
||||||
name: info.name,
|
name: info.name,
|
||||||
avatar_url: info.avatar_url,
|
avatar_url: info.avatar_url,
|
||||||
|
class: sidebar_cls,
|
||||||
|
on_nav: move |_| mobile_menu_open.set(false),
|
||||||
}
|
}
|
||||||
main { class: "main-content", Outlet::<Route> {} }
|
main { class: "main-content", Outlet::<Route> {} }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,19 @@ struct NavItem {
|
|||||||
/// * `name` - User display name (shown in header if non-empty).
|
/// * `name` - User display name (shown in header if non-empty).
|
||||||
/// * `email` - Email address displayed beneath the avatar placeholder.
|
/// * `email` - Email address displayed beneath the avatar placeholder.
|
||||||
/// * `avatar_url` - URL for the avatar image (unused placeholder for now).
|
/// * `avatar_url` - URL for the avatar image (unused placeholder for now).
|
||||||
|
/// * `class` - CSS class override (e.g. to add `sidebar--open` on mobile).
|
||||||
|
/// * `on_nav` - Callback fired when a nav link is clicked (used to close
|
||||||
|
/// the mobile menu).
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Sidebar(name: String, email: String, avatar_url: String) -> Element {
|
pub fn Sidebar(
|
||||||
|
name: String,
|
||||||
|
email: String,
|
||||||
|
avatar_url: String,
|
||||||
|
#[props(default = "sidebar".to_string())]
|
||||||
|
class: String,
|
||||||
|
#[props(default)]
|
||||||
|
on_nav: EventHandler<()>,
|
||||||
|
) -> Element {
|
||||||
let locale = use_context::<Signal<Locale>>();
|
let locale = use_context::<Signal<Locale>>();
|
||||||
let locale_val = *locale.read();
|
let locale_val = *locale.read();
|
||||||
|
|
||||||
@@ -82,7 +93,7 @@ pub fn Sidebar(name: String, email: String, avatar_url: String) -> Element {
|
|||||||
let logout_label = t(locale_val, "common.logout");
|
let logout_label = t(locale_val, "common.logout");
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
aside { class: "sidebar",
|
aside { class: "{class}",
|
||||||
div { class: "sidebar-top-row",
|
div { class: "sidebar-top-row",
|
||||||
SidebarHeader { name, email: email.clone(), avatar_url }
|
SidebarHeader { name, email: email.clone(), avatar_url }
|
||||||
LocalePicker {}
|
LocalePicker {}
|
||||||
@@ -104,7 +115,10 @@ pub fn Sidebar(name: String, email: String, avatar_url: String) -> Element {
|
|||||||
};
|
};
|
||||||
let cls = if is_active { "sidebar-link active" } else { "sidebar-link" };
|
let cls = if is_active { "sidebar-link active" } else { "sidebar-link" };
|
||||||
rsx! {
|
rsx! {
|
||||||
Link { to: item.route, class: cls,
|
Link {
|
||||||
|
to: item.route,
|
||||||
|
class: cls,
|
||||||
|
onclick: move |_| on_nav.call(()),
|
||||||
{item.icon}
|
{item.icon}
|
||||||
span { "{item.label}" }
|
span { "{item.label}" }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user