Split monolithic app.rs into focused, reusable components: - Sidebar component for user info, navigation and calendar management - CalendarListItem component for individual calendar items with color picker - RouteHandler component to eliminate duplicated routing logic - Reduced app.rs from 645 to 338 lines (47% reduction) - Improved separation of concerns and maintainability - Clean props-based component communication 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
89 lines
3.6 KiB
Rust
89 lines
3.6 KiB
Rust
use yew::prelude::*;
|
|
use yew_router::prelude::*;
|
|
use crate::services::calendar_service::UserInfo;
|
|
use crate::components::CalendarListItem;
|
|
|
|
#[derive(Clone, Routable, PartialEq)]
|
|
pub enum Route {
|
|
#[at("/")]
|
|
Home,
|
|
#[at("/login")]
|
|
Login,
|
|
#[at("/calendar")]
|
|
Calendar,
|
|
}
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
pub struct SidebarProps {
|
|
pub user_info: Option<UserInfo>,
|
|
pub on_logout: Callback<()>,
|
|
pub on_create_calendar: Callback<()>,
|
|
pub color_picker_open: Option<String>,
|
|
pub on_color_change: Callback<(String, String)>,
|
|
pub on_color_picker_toggle: Callback<String>,
|
|
pub available_colors: Vec<String>,
|
|
pub on_calendar_context_menu: Callback<(MouseEvent, String)>,
|
|
}
|
|
|
|
#[function_component(Sidebar)]
|
|
pub fn sidebar(props: &SidebarProps) -> Html {
|
|
html! {
|
|
<aside class="app-sidebar">
|
|
<div class="sidebar-header">
|
|
<h1>{"Calendar App"}</h1>
|
|
{
|
|
if let Some(ref info) = props.user_info {
|
|
html! {
|
|
<div class="user-info">
|
|
<div class="username">{&info.username}</div>
|
|
<div class="server-url">{&info.server_url}</div>
|
|
</div>
|
|
}
|
|
} else {
|
|
html! { <div class="user-info loading">{"Loading..."}</div> }
|
|
}
|
|
}
|
|
</div>
|
|
<nav class="sidebar-nav">
|
|
<Link<Route> to={Route::Calendar} classes="nav-link">{"Calendar"}</Link<Route>>
|
|
</nav>
|
|
{
|
|
if let Some(ref info) = props.user_info {
|
|
if !info.calendars.is_empty() {
|
|
html! {
|
|
<div class="calendar-list">
|
|
<h3>{"My Calendars"}</h3>
|
|
<ul>
|
|
{
|
|
info.calendars.iter().map(|cal| {
|
|
html! {
|
|
<CalendarListItem
|
|
calendar={cal.clone()}
|
|
color_picker_open={props.color_picker_open.as_ref() == Some(&cal.path)}
|
|
on_color_change={props.on_color_change.clone()}
|
|
on_color_picker_toggle={props.on_color_picker_toggle.clone()}
|
|
available_colors={props.available_colors.clone()}
|
|
on_context_menu={props.on_calendar_context_menu.clone()}
|
|
/>
|
|
}
|
|
}).collect::<Html>()
|
|
}
|
|
</ul>
|
|
</div>
|
|
}
|
|
} else {
|
|
html! { <div class="no-calendars">{"No calendars found"}</div> }
|
|
}
|
|
} else {
|
|
html! {}
|
|
}
|
|
}
|
|
<div class="sidebar-footer">
|
|
<button onclick={props.on_create_calendar.reform(|_| ())} class="create-calendar-button">
|
|
{"+ Create Calendar"}
|
|
</button>
|
|
<button onclick={props.on_logout.reform(|_| ())} class="logout-button">{"Logout"}</button>
|
|
</div>
|
|
</aside>
|
|
}
|
|
} |