Skip to main content

edc_web_components/components/
dataset_card.rs

1use 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}