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