yggdrasil/components/
share_meta.rs1use leptos::prelude::*;
11use leptos::text_prop::TextProp;
12use leptos_meta::Meta;
13
14use crate::hooks::ssr_resource::JsonSliceCodec;
15use crate::models::post::Post;
16use crate::models::share::{PostShareCard, ShareContext};
17
18pub(crate) fn provide_share_context() {
21 provide_context(
22 SharedValue::<ShareContext, JsonSliceCodec>::new_with_encoding(share_context_from_request)
23 .into_inner(),
24 );
25}
26
27fn share_context_from_request() -> ShareContext {
28 #[cfg(feature = "server")]
29 {
30 crate::request_ctx::request_extension::<ShareContext>().unwrap_or_default()
31 }
32 #[cfg(not(feature = "server"))]
33 {
34 ShareContext::default()
35 }
36}
37
38fn use_share_context() -> ShareContext {
40 use_context::<ShareContext>().unwrap_or_default()
41}
42
43#[component]
47pub(crate) fn SiteShareMeta(#[prop(into)] path: Signal<String>) -> impl IntoView {
48 let ctx = use_share_context();
49 let base_url = ctx.base_url.clone();
50 view! {
51 <ShareTags
52 kind="website"
53 title="Yggdrasil"
54 description=ctx.description.clone()
55 url=move || format!("{base_url}{}", path.get())
56 image=format!("{}{}", ctx.base_url, ctx.site_image)
57 image_alt="Yggdrasil"
58 />
59 }
60}
61
62#[component]
64pub(crate) fn PostShareMeta(post: Post) -> impl IntoView {
65 let ctx = use_share_context();
66 let card = PostShareCard::from_post(&post);
67 let description = if card.summary.is_empty() {
68 ctx.description.clone()
69 } else {
70 card.summary.clone()
71 };
72 let published = post.published_at.unwrap_or(post.created_at).to_rfc3339();
73 let url = format!("{}/post/{}", ctx.base_url, post.slug);
74 let image = format!("{}{}", ctx.base_url, card.image_path(&post.slug));
75 let tags = post
76 .tags
77 .iter()
78 .map(|tag| view! { <Meta property="article:tag" content=tag.clone()/> })
79 .collect_view();
80
81 view! {
82 <ShareTags
83 kind="article"
84 title=card.title.clone()
85 description=description
86 url=url
87 image=image
88 image_alt=card.title.clone()
89 />
90 <Meta property="article:published_time" content=published/>
91 {tags}
92 }
93}
94
95#[component]
97fn ShareTags(
98 kind: &'static str,
99 #[prop(into)] title: TextProp,
100 #[prop(into)] description: TextProp,
101 #[prop(into)] url: TextProp,
102 #[prop(into)] image: TextProp,
103 #[prop(into)] image_alt: TextProp,
104) -> impl IntoView {
105 view! {
106 <Meta name="description" content=description.clone()/>
107 <Meta property="og:site_name" content="Yggdrasil"/>
108 <Meta property="og:locale" content="zh_CN"/>
109 <Meta property="og:type" content=kind/>
110 <Meta property="og:title" content=title/>
111 <Meta property="og:description" content=description/>
112 <Meta property="og:url" content=url/>
113 <Meta property="og:image" content=image/>
114 <Meta property="og:image:type" content="image/png"/>
115 <Meta property="og:image:width" content="1200"/>
116 <Meta property="og:image:height" content="630"/>
117 <Meta property="og:image:alt" content=image_alt/>
118 <Meta name="twitter:card" content="summary_large_image"/>
119 }
120}