Skip to main content

systemprompt_content/
branding_provider.rs

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