Skip to main content

systemprompt_content/
branding_provider.rs

1//! Page-data provider supplying site branding values to content pages.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use std::sync::Arc;
7
8use async_trait::async_trait;
9use serde_json::Value;
10use systemprompt_cloud::constants::storage;
11use systemprompt_models::ContentConfigRaw;
12use systemprompt_provider_contracts::{
13    PageContext, PageDataProvider, ProviderError, ProviderResult,
14};
15
16#[derive(Debug, Clone, Copy, Default)]
17pub struct DefaultBrandingProvider;
18
19fn resolve_content_raw<'a>(ctx: &'a PageContext<'_>) -> ProviderResult<&'a ContentConfigRaw> {
20    ctx.content_config::<ContentConfigRaw>().ok_or_else(|| {
21        ProviderError::Configuration("ContentConfig not available in PageContext".into())
22    })
23}
24
25#[async_trait]
26impl PageDataProvider for DefaultBrandingProvider {
27    fn provider_id(&self) -> &'static str {
28        "default-branding"
29    }
30
31    async fn provide_page_data(&self, ctx: &PageContext<'_>) -> ProviderResult<Value> {
32        let content_config = resolve_content_raw(ctx)?;
33
34        let org = &content_config.metadata.structured_data.organization;
35        let branding = &ctx.web_config.branding;
36
37        Ok(serde_json::json!({
38            "ORG_NAME": org.name,
39            "ORG_URL": org.url,
40            "ORG_LOGO": org.logo,
41            "LOGO_PATH": branding.logo.primary.svg.as_deref().unwrap_or(""),
42            "FAVICON_PATH": &branding.favicon,
43            "TWITTER_HANDLE": &branding.twitter_handle,
44            "DISPLAY_SITENAME": branding.display_sitename,
45            "CSS_BASE_PATH": format!("/{}", storage::CSS),
46            "JS_BASE_PATH": format!("/{}", storage::JS),
47            "HEADER_CTA_URL": "/",
48        }))
49    }
50}
51
52pub fn default_branding_provider() -> Arc<dyn PageDataProvider> {
53    Arc::new(DefaultBrandingProvider)
54}