things3_cloud/ui/components/
project_item.rs1use crate::store::Task;
2use crate::ui::components::details_container::DetailsContainer;
3use crate::ui::components::id::Id;
4use crate::ui::components::progress_badge::ProgressBadge;
5use crate::ui::components::task_line::TaskLine;
6use crate::ui::components::tasks::TaskOptions;
7use iocraft::prelude::*;
8
9#[derive(Default, Props)]
10pub struct ProjectItemProps<'a> {
11 pub project: Option<&'a Task>,
12 pub options: TaskOptions,
13 pub id_prefix_len: usize,
14}
15
16#[component]
17pub fn ProjectItem<'a>(props: &ProjectItemProps<'a>) -> impl Into<AnyElement<'a>> {
18 let Some(project) = props.project else {
19 return element!(Fragment).into_any();
20 };
21
22 let details = if props.options.detailed {
23 element!(ProjectDetails(project: project)).into_any()
24 } else {
25 element!(Fragment).into_any()
26 };
27
28 element! {
29 View(flex_direction: FlexDirection::Row, gap: 1) {
30 Id(id: &project.uuid, length: props.id_prefix_len)
31 View(flex_direction: FlexDirection::Column) {
32 ProjectText(project: project, options: props.options)
33 #(details)
34 }
35 }
36 }
37 .into_any()
38}
39
40#[derive(Default, Props)]
41struct ProjectTextProps<'a> {
42 pub project: Option<&'a Task>,
43 pub options: TaskOptions,
44}
45
46#[component]
47fn ProjectText<'a>(props: &ProjectTextProps<'a>) -> impl Into<AnyElement<'a>> {
48 let Some(project) = props.project else {
49 return element!(Fragment).into_any();
50 };
51
52 element! {
53 View(flex_direction: FlexDirection::Row, gap: 1) {
54 ProgressBadge(project)
55 TaskLine(
56 task: project,
57 show_today_markers: props.options.show_today_markers,
58 show_staged_today_marker: props.options.show_staged_today_marker,
59 show_tags: true,
60 show_project: false,
61 show_area: props.options.show_area,
62 )
63 }
64 }
65 .into_any()
66}
67
68#[derive(Default, Props)]
69struct ProjectDetailsProps<'a> {
70 pub project: Option<&'a Task>,
71}
72
73#[component]
74fn ProjectDetails<'a>(props: &ProjectDetailsProps<'a>) -> impl Into<AnyElement<'a>> {
75 let Some(project) = props.project else {
76 return element!(Fragment).into_any();
77 };
78
79 let note_text = project.notes.as_deref().unwrap_or("").trim();
80 if note_text.is_empty() {
81 return element!(Fragment).into_any();
82 }
83
84 element! {
85 DetailsContainer {
86 Text(content: note_text, wrap: TextWrap::NoWrap, color: Color::DarkGrey)
87 }
88 }
89 .into_any()
90}