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