use dioxus::prelude::*;
#[component]
pub fn UrlPreviewCard(url: String) -> Element {
let mut preview_data = use_signal(|| Option::<UrlPreviewData>::None);
let mut loading = use_signal(|| true);
let mut failed = use_signal(|| false);
let url_for_fetch = url.clone();
use_effect(move || {
let url = url_for_fetch.clone();
spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
if let Ok(parsed) = url::Url::parse(&url) {
let domain = parsed.host_str().unwrap_or("").to_string();
let title = parsed.path().split('/').last().unwrap_or("").to_string();
preview_data.set(Some(UrlPreviewData {
url: url.clone(),
title: if title.is_empty() { domain.clone() } else { title },
description: None,
image_url: None,
site_name: Some(domain),
}));
} else {
failed.set(true);
}
loading.set(false);
});
});
if *failed.read() || *loading.read() {
return rsx! {};
}
let data_cloned = preview_data.read().clone();
if let Some(data) = data_cloned {
let title = data.title.clone();
let desc = data.description.clone();
let site = data.site_name.clone();
let href = data.url.clone();
let img_url = data.image_url.clone();
rsx! {
a {
class: "url-preview",
href: "{href}",
target: "_blank",
rel: "noopener noreferrer",
if let Some(ref img) = img_url {
img {
class: "url-preview__image",
src: "{img}",
alt: "",
}
}
div {
class: "url-preview__info",
if let Some(ref site) = site {
span { class: "url-preview__site", "{site}" }
}
span { class: "url-preview__title", "{title}" }
if let Some(ref desc) = desc {
span { class: "url-preview__description", "{desc}" }
}
}
}
}
} else {
rsx! {}
}
}
#[derive(Clone, Debug)]
struct UrlPreviewData {
url: String,
title: String,
description: Option<String>,
image_url: Option<String>,
site_name: Option<String>,
}