edc_web_components/components/
dataset_card.rs1use crate::models::DataspaceDataset;
2use patternfly_yew::prelude::*;
3use stylist::yew::styled_component;
4use yew::prelude::*;
5
6#[derive(Clone, PartialEq, Properties)]
7pub struct DatasetCardProps {
8 pub dataset: DataspaceDataset,
9 #[prop_or_default]
10 pub on_offer_click: Option<Callback<()>>,
11 #[prop_or_default]
12 pub selected: bool,
13 #[prop_or_default]
14 pub on_selected: Option<Callback<bool>>,
15 #[prop_or(AttrValue::Static("Select"))]
16 pub button_label: AttrValue,
17}
18
19#[styled_component]
20pub fn DatasetCard(props: &DatasetCardProps) -> Html {
21 let card_class = css!(
22 width: 250px;
23 );
24
25 let thumbnails_class = css!(
26 height: 180px;
27 object-fit: cover;
28 );
29
30 let provider_logo_class = css!(
31 width: 50px;
32 height: 50px;
33 object-fit: contain;
34 );
35
36 let version_class = css!(
37 position: absolute;
38 top: 5px;
39 right: 5px;
40 );
41
42 let keyword_class = css!(
43 .pf-v6-l-split {
44 overflow: hidden;
45 }
46 );
47
48 let description_class = css!(
49 display: block;
50 display: -webkit-box;
51 -webkit-line-clamp: 5;
52 -webkit-box-orient: vertical;
53 text-overflow: ellipsis;
54 overflow: hidden;
55 );
56
57 let offer_button_class = css!(
58 text-align: right;
59 );
60
61 let offer_button = if let Some(offer) = props.on_offer_click.clone() {
62 html!(
63 <Button
64 variant={ButtonVariant::Primary}
65 icon={Icon::AngleRight}
66 onclick={offer.reform(|_| ())}
67 >
68 { props.button_label.clone() }
69 </Button>
70 )
71 } else {
72 html!()
73 };
74
75 let title = props.dataset.title.to_string();
76
77 let version = props
78 .dataset
79 .version
80 .clone()
81 .map(|version| version.to_string())
82 .unwrap_or_default();
83
84 let comment = props.dataset.comment.clone().unwrap_or_default();
85
86 let thumbnail = props
87 .dataset
88 .thumbnail
89 .clone()
90 .and_then(|thumbnail| thumbnail.resource)
91 .map(|thumbnail| html! { <img src={thumbnail} class={thumbnails_class.clone()} /> });
92
93 let provider_logo = props
94 .dataset
95 .creator
96 .clone()
97 .and_then(|creator| creator.thumbnail)
98 .and_then(|thumbnail| thumbnail.resource)
99 .map(|thumbnail| html! { <img src={thumbnail} class={provider_logo_class.clone()} /> });
100
101 let keywords = props.dataset.keywords.iter().map(|keyword| {
102 html_nested! {
103 <SplitItem>
104 <Label label={keyword.clone()} />
105 </SplitItem>
106 }
107 });
108
109 let selectable_actions = if let Some(on_selected) = props.on_selected.clone() {
110 let checked = if props.selected {
111 CheckboxState::Checked
112 } else {
113 CheckboxState::Unchecked
114 };
115
116 Some(yew::props!(CardSelectableActionsObjectProperties {
117 action: CardSelectableActionsVariant::MultiSelect {
118 checked,
119 onchange: on_selected.reform(move |checked: CheckboxState| {
120 match checked {
121 CheckboxState::Checked => true,
122 CheckboxState::Unchecked | CheckboxState::Indeterminate => false,
123 }
124 }),
125 }
126 }))
127 } else {
128 None
129 };
130
131 html!(
132 <Card full_height=true class={card_class.clone()} selectable={props.on_selected.is_some()}>
133 { thumbnail }
134 <div class={version_class.clone()}>
135 <Badge read=true>{ "v" }{ version }</Badge>
136 </div>
137 <CardHeader {selectable_actions}>
138 <div>
139 <div>{ provider_logo }</div>
140 <Truncate content={title} />
141 </div>
142 </CardHeader>
143 <CardBody>
144 <Stack gutter=true>
145 <StackItem fill=true>
146 <div class={description_class.clone()}>{ comment }</div>
147 </StackItem>
148 <StackItem>
149 <div class={offer_button_class.clone()}>{ offer_button.clone() }</div>
150 </StackItem>
151 </Stack>
152 </CardBody>
153 <CardFooter>
154 <slot class={keyword_class.clone()}>
155 <Split gutter=true>{ for keywords }</Split>
156 </slot>
157 </CardFooter>
158 </Card>
159 )
160}