Add date list component #50
No files matched your search
+91
-88
@@ -1,116 +1,119 @@
|
|||||||
use crate::common::{DateInfo, DateRange, DateStatus};
|
use crate::common::{DateInfo, DateRange, DateStatus};
|
||||||
use leptos::either::{Either, EitherOf4};
|
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
/// # Date Component
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// Example usage - Single Date:
|
|
||||||
/// ```
|
|
||||||
/// <Date
|
|
||||||
/// important_dates=vec!{
|
|
||||||
/// DateInfo {
|
|
||||||
/// title: "Some Title".to_string(),
|
|
||||||
/// date: DateRange::Single("November 4th, 2025".to_string()),
|
|
||||||
/// description: "This is a test".to_string(),
|
|
||||||
/// status: DateStatus::Closed
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// icon="/icon.png"
|
|
||||||
/// />
|
|
||||||
/// ```
|
|
||||||
/// Example usage - Date Range
|
|
||||||
/// ```
|
|
||||||
/// <Date
|
|
||||||
/// important_dates=vec!{
|
|
||||||
/// DateInfo {
|
|
||||||
/// title: "Some Title".to_string(),
|
|
||||||
/// date: DateRange::Range("February 2nd, 2026".to_string(), "February 10th, 2026".to_string()),
|
|
||||||
/// description: "This is a test".to_string(),
|
|
||||||
/// status: DateStatus::Upcoming
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// icon="/icon.png"
|
|
||||||
/// />
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
fn render_dates(dates: DateRange) -> impl IntoView {
|
fn render_dates(dates: DateRange) -> impl IntoView {
|
||||||
match dates {
|
let date_text = match dates {
|
||||||
DateRange::Single(date) => Either::Left(view! {
|
DateRange::Single(date) => date,
|
||||||
<p> {date} </p>
|
DateRange::Range(start_date, end_date) =>
|
||||||
}),
|
format!("{} - {}", start_date, end_date),
|
||||||
DateRange::Range(start_date, end_date) => Either::Right(view! {
|
};
|
||||||
<p> {start_date} " - " {end_date} </p>
|
|
||||||
}),
|
view! {
|
||||||
|
<span>{move || date_text.clone()}</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_status(status: DateStatus) -> impl IntoView {
|
fn render_status(status: DateStatus) -> impl IntoView {
|
||||||
match status {
|
let status_text = match status {
|
||||||
DateStatus::Upcoming => EitherOf4::A(view! {
|
DateStatus::Upcoming => "Upcoming",
|
||||||
<span
|
DateStatus::Open => "Open",
|
||||||
class="inline-flex items-center justify-center rounded-md border border-yellow-100 bg-yellow-100 px-2 py-0.5 text-xs text-yellow-800 font-medium w-fit whitespace-nowrap shrink-0">
|
DateStatus::Deadline => "Deadline",
|
||||||
Upcoming
|
DateStatus::Closed => "Closed",
|
||||||
</span>
|
};
|
||||||
}),
|
|
||||||
DateStatus::Open => EitherOf4::B(view! {
|
view! {
|
||||||
<span
|
<span class="inline-flex items-center justify-center rounded-md border border-yellow-100
|
||||||
class="inline-flex items-center justify-center rounded-md border border-green-100 bg-green-100 px-2 py-0.5 text-xs text-green-800 font-medium w-fit whitespace-nowrap shrink-0">
|
bg-yellow-100 px-2 py-0.5 text-xs text-yellow-800 font-medium w-fit whitespace-nowrap
|
||||||
Open
|
shrink-0">
|
||||||
</span>
|
{move || status_text}
|
||||||
}),
|
</span>
|
||||||
DateStatus::Deadline => EitherOf4::C(view! {
|
|
||||||
<span
|
|
||||||
class="inline-flex items-center justify-center rounded-md border border-red-900 bg-red-900 px-2 py-0.5 text-xs text-white font-medium w-fit whitespace-nowrap shrink-0">
|
|
||||||
Deadline
|
|
||||||
</span>
|
|
||||||
}),
|
|
||||||
DateStatus::Closed => EitherOf4::D(view! {
|
|
||||||
<span
|
|
||||||
class="inline-flex items-center justify-center rounded-md border border-red-50 bg-red-100 px-2 py-0.5 text-xs text-red-800 font-medium w-fit whitespace-nowrap shrink-0">
|
|
||||||
Closed
|
|
||||||
</span>
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Date Component
|
||||||
|
/// A single date, for use in a [`DateList`] component.
|
||||||
|
///
|
||||||
|
/// Example usage:
|
||||||
|
/// ```
|
||||||
|
/// let date_info = DateInfo {
|
||||||
|
/// title: "Example Title".to_string(),
|
||||||
|
/// date: DateRange::Single("January 1st, 1990".to_string()),
|
||||||
|
/// description: "A description of the date.".to_string(),
|
||||||
|
/// status: DateStatus::Upcoming
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// view! {
|
||||||
|
/// <Date
|
||||||
|
/// info=date_info
|
||||||
|
/// />
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Date(
|
fn Date(
|
||||||
/// Struct of title, date, and description
|
/// Struct of title, date, and description
|
||||||
#[prop(into)]
|
#[prop(into)] info: Signal<DateInfo>,
|
||||||
important_dates: Vec<DateInfo>,
|
|
||||||
/// The file path or URL of the icon displayed at the top of the button.
|
|
||||||
#[prop(into)]
|
|
||||||
icon: String,
|
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
important_dates
|
view! {
|
||||||
.into_iter()
|
<div class="dashboard-button flex items-start gap-3 rounded-lg border-grey-300 p-3
|
||||||
.map(|info: DateInfo| {
|
w-full text-left shadow-[inset_0_0_6px_rgba(0,0,0,0.12)]">
|
||||||
view! {
|
// <div class="flex-shrink-0 mt-0.5">
|
||||||
<div class="dashboard-button flex items-start gap-3 rounded-lg border-grey-300 p-3
|
// <img src={icon} class="h-4 w-4" alt="icon"/>
|
||||||
hover:bg-gray-100 transition w-full text-left
|
// </div>
|
||||||
shadow-[inset_0_0_6px_rgba(0,0,0,0.12)]">
|
|
||||||
<div class="flex-shrink-0 mt-0.5">
|
|
||||||
<img src={icon.clone()} class="h-4 w-4" alt="icon"/>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
<div class="flex items-start justify-between">
|
<div class="flex items-start justify-between">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="font-bold text-md text-base">
|
<h3 class="font-bold text-md text-base">
|
||||||
{info.title}
|
{info.get().title}
|
||||||
</h3>
|
</h3>
|
||||||
<h3 class="text-md text-base mt-1">
|
<h3 class="text-md text-base mt-1">
|
||||||
{render_dates(info.date)}
|
{move || render_dates(info.get().date)}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-sm text-gray-600">
|
<p class="text-sm text-gray-600">
|
||||||
{info.description}
|
{info.get().description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-shrink-0 ml-2">
|
<div class="flex-shrink-0 ml-2">
|
||||||
{render_status(info.status)}
|
{move || render_status(info.get().status)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect_view()
|
|
||||||
|
///# Dates List Component
|
||||||
|
/// Displays a list of important dates in a column, with badges that draw attention to dates that
|
||||||
|
/// are more important.
|
||||||
|
///
|
||||||
|
/// Example usage:
|
||||||
|
/// ```
|
||||||
|
/// let dates = vec![
|
||||||
|
/// DateInfo {
|
||||||
|
/// title: "Example Title".to_string(),
|
||||||
|
/// date: DateRange::Single("January 1st, 1990".to_string()),
|
||||||
|
/// description: "A description of the date.".to_string(),
|
||||||
|
/// status: DateStatus::Upcoming
|
||||||
|
/// }
|
||||||
|
/// ]
|
||||||
|
///
|
||||||
|
/// view! {
|
||||||
|
/// <DateList dates=dates />
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[component]
|
||||||
|
pub fn DateList(
|
||||||
|
#[prop(into)] dates: Vec<DateInfo>,
|
||||||
|
) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
{move || {
|
||||||
|
dates.iter()
|
||||||
|
.map(|info| {
|
||||||
|
view! {
|
||||||
|
<Date
|
||||||
|
info=info.clone()
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
}).collect_view()
|
||||||
|
}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+7
-24
@@ -1,5 +1,5 @@
|
|||||||
use crate::common::{DateInfo, DateRange, DateStatus};
|
use crate::common::{DateInfo, DateRange, DateStatus};
|
||||||
use crate::components::{DashboardButton, Date};
|
use crate::components::{DashboardButton, DateList};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
@@ -36,50 +36,33 @@ pub fn TestPage() -> impl IntoView {
|
|||||||
</div>
|
</div>
|
||||||
<div class="p-6 space-y-6">
|
<div class="p-6 space-y-6">
|
||||||
<div class="bg-white rounded-md p-3 space-y-2">
|
<div class="bg-white rounded-md p-3 space-y-2">
|
||||||
<Date
|
<DateList
|
||||||
important_dates=vec!{
|
dates=vec![
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Title".to_string(),
|
title: "Title".to_string(),
|
||||||
date: DateRange::Range("February 2nd, 2026".to_string(), "February 10th, 2026".to_string()),
|
date: DateRange::Range("February 2nd, 2026".to_string(), "February 10th, 2026".to_string()),
|
||||||
description: "This is a test".to_string(),
|
description: "This is a test".to_string(),
|
||||||
status: DateStatus::Upcoming
|
status: DateStatus::Upcoming
|
||||||
}
|
},
|
||||||
}
|
|
||||||
icon="/Check_Style2.png"
|
|
||||||
|
|
||||||
/>
|
|
||||||
<Date
|
|
||||||
important_dates=vec!{
|
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Scholarships Due".to_string(),
|
title: "Scholarships Due".to_string(),
|
||||||
date: DateRange::Single("November 4th, 2025".to_string()),
|
date: DateRange::Single("November 4th, 2025".to_string()),
|
||||||
description: "This is a test".to_string(),
|
description: "This is a test".to_string(),
|
||||||
status: DateStatus::Open
|
status: DateStatus::Open
|
||||||
}
|
},
|
||||||
}
|
|
||||||
icon="/Warning_Style2.png"
|
|
||||||
/>
|
|
||||||
<Date
|
|
||||||
important_dates=vec!{
|
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Scholarships Due".to_string(),
|
title: "Scholarships Due".to_string(),
|
||||||
date: DateRange::Single("November 4th, 2025".to_string()),
|
date: DateRange::Single("November 4th, 2025".to_string()),
|
||||||
description: "This is a test".to_string(),
|
description: "This is a test".to_string(),
|
||||||
status: DateStatus::Deadline
|
status: DateStatus::Deadline
|
||||||
}
|
},
|
||||||
}
|
|
||||||
icon="/Warning_Style2.png"
|
|
||||||
/>
|
|
||||||
<Date
|
|
||||||
important_dates=vec!{
|
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Scholarships Due".to_string(),
|
title: "Scholarships Due".to_string(),
|
||||||
date: DateRange::Single("November 4th, 2025".to_string()),
|
date: DateRange::Single("November 4th, 2025".to_string()),
|
||||||
description: "This is a test".to_string(),
|
description: "This is a test".to_string(),
|
||||||
status: DateStatus::Closed
|
status: DateStatus::Closed
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
icon="/Warning_Style2.png"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user