use comrak::{markdown_to_html, ComrakOptions}; use gloo::utils::document; use gloo_net::http::Request; use serde::Deserialize; use yew::{function_component, html, Html, UseStateHandle, use_state, use_effect_with_deps, Properties, Children, use_context, Callback}; use yewprint::{Divider, Elevation, Card, Tag, Intent, Icon, Overlay}; use crate::{util::log, theme::{ThemeContext, ThemeState}, component::image_viewer::{ImageDescription, ImageViewer}}; #[derive(Debug)] enum TagType { NaturalLanguage, CodeLanguage, Interest } #[derive(PartialEq)] enum ImageSource { Link(String), Icon(Icon, Intent) } #[derive(PartialEq)] struct ImageResource { source: ImageSource, clickable: bool } impl ImageResource { pub fn new_link(link: String, clickable: bool) -> Self { Self { source: ImageSource::Link(link), clickable } } pub fn new_icon(icon: Icon, intent: Intent, clickable: bool) -> Self { Self { source: ImageSource::Icon(icon, intent), clickable } } } #[derive(PartialEq)] struct DescribedImage { pub image: ImageResource, pub description: &'static str } #[derive(Properties, PartialEq)] struct HomeCardProps { #[prop_or_default] pub image: Option, pub children: Children } #[derive(Clone, PartialEq, Deserialize)] struct GithubEntry { link: String, title: String, description: String } #[function_component] pub fn Home() -> Html { html! { <>
} } #[function_component] fn HomeTitle() -> Html { html! {

{"Gabriel Tofvesson"}

} } fn get_text_resource(file: String, on_result: impl (FnOnce(String) -> ()) + 'static) { wasm_bindgen_futures::spawn_local(async move { log(&format!("Fetching {file}")); let response = Request::get(file.as_str()).send().await; if let Ok(response) = response { if let Ok(text) = response.text().await { on_result(text); } } }); } fn get_json_resource(file: &'static str, on_result: impl FnOnce(Vec) -> () + 'static) where T: for<'a> Deserialize<'a> { wasm_bindgen_futures::spawn_local(async move { log(&format!("Fetching {file}")); let response = Request::get(file).send().await; if let Ok(response) = response { if let Ok(value) = response.json::>().await { on_result(value); } } }); } #[function_component] fn ProfileTags() -> Html { let natural_languages: UseStateHandle> = use_state(|| vec![]); let code_languages: UseStateHandle> = use_state(|| vec![]); let interests: UseStateHandle> = use_state(|| vec![]); // TODO: Cache results { let natural_languages = natural_languages.clone(); use_effect_with_deps( move |_| get_json_resource( "/res/languages.json", move |it| natural_languages.set(it) ), () ); } { let code_languages = code_languages.clone(); use_effect_with_deps( move |_| get_json_resource( "/res/code.json", move |it| code_languages.set(it) ), () ); } { let interests = interests.clone(); use_effect_with_deps( move |_| get_json_resource( "/res/interests.json", move |it| interests.set(it) ), () ); } let tags = vec![ natural_languages.iter().map(|it| (it, TagType::NaturalLanguage)).collect::>(), code_languages.iter().map(|it| (it, TagType::CodeLanguage)).collect::>(), interests.iter().map(|it| (it, TagType::Interest)).collect::>() ].into_iter().flatten().map(|(tag, tag_type)| { html! { Intent::Primary, TagType::CodeLanguage => Intent::Warning, TagType::Interest => Intent::Success } }> {tag} } }).collect::(); html! {
{tags}
} } #[function_component] fn Profile() -> Html { let profile_text = use_state(|| "".to_owned()); { let profile_text = profile_text.clone(); use_effect_with_deps(move |_| { get_text_resource("/res/profile.md".to_owned(), move |text| profile_text.set(markdown_to_html(&text, &ComrakOptions::default()))); }, ()); } html! { {Html::from_html_unchecked(profile_text.to_string().into())} } } #[function_component] fn HomeCard(props: &HomeCardProps) -> Html { let overlay_state = use_state(|| false); let open_overlay_state = overlay_state.clone(); html! { { if let Some(image) = &props.image { html! {
{ match &image.image.source { ImageSource::Link(link) => html! { }, ImageSource::Icon(icon, intent) => html! { } } } { if image.image.clickable { if let ImageSource::Link(link) = &image.image.source { html! { } } else { html! {} } } else { html! {} } } {image.description}
} } else { html! {} } }
{props.children.clone()}
} } #[function_component] fn Github() -> Html { let github_entries: UseStateHandle> = use_state(|| vec![]); { let github_entries = github_entries.clone(); use_effect_with_deps(move |_| get_json_resource("/res/github.json", move |it| github_entries.set(it)), ()); } let theme_state = use_context::().expect("Theme context"); html! { { github_entries.iter().map(|it| { let link = it.link.clone(); html! {

{it.title.clone()}

{it.description.clone()}

} }).collect::() }
} }