oranda 0.6.5

🎁 generate beautiful landing pages for your projects
Documentation
use crate::config::FundingConfig;
use crate::data::funding::{Funding, FundingContent, FundingType};
use crate::errors::Result;
use serde::Serialize;

#[derive(Serialize, Debug)]
pub struct FundingContext {
    preferred_funding: Option<Vec<FundingMethod>>,
    funding: Vec<FundingMethod>,
    docs_content: Option<String>,
}

#[derive(Serialize, Debug)]
pub struct FundingMethod {
    title: String,
    link: String,
    icon: Option<String>,
}

pub fn context(config: &FundingConfig, funding: &Funding) -> Result<FundingContext> {
    let mut funding_base = funding.content.clone();
    // Remove the preferred funding method from the generic content so that it's only
    // showed in its more prominent position.
    //
    // This silently ignores preferred_funding not resolving because earlier steps should
    // have produced an error to help the user catch that.
    let preferred_funding = config
        .preferred_funding
        .as_ref()
        .and_then(|preferred| Some((preferred, funding_base.remove(preferred)?)))
        .map(|(preferred, content)| to_funding_methods(preferred, &content));

    Ok(FundingContext {
        preferred_funding,
        funding: funding_base
            .iter()
            .flat_map(|(k, v)| to_funding_methods(k, v))
            .collect(),
        docs_content: funding.docs_content.clone(),
    })
}

fn to_funding_methods(ftype: &FundingType, content: &FundingContent) -> Vec<FundingMethod> {
    let mut return_vec = Vec::new();
    match ftype {
        FundingType::Github => {
            let items = one_or_multiple(content);
            for item in items {
                return_vec.push(FundingMethod {
                    title: "GitHub".to_string(),
                    link: format!("https://github.com/sponsors/{item}"),
                    icon: Some("github".to_string()),
                })
            }
        }
        FundingType::Patreon => {
            if let FundingContent::One(item) = content {
                return_vec.push(FundingMethod {
                    title: "Patreon".to_string(),
                    link: format!("https://patreon.com/{item}"),
                    icon: Some("patreon".to_string()),
                })
            }
        }
        FundingType::OpenCollective => {
            if let FundingContent::One(item) = content {
                return_vec.push(FundingMethod {
                    title: "OpenCollective".to_string(),
                    link: format!("https://opencollective.com/{item}"),
                    icon: Some("opencollective".to_string()),
                })
            }
        }
        FundingType::KoFi => {
            if let FundingContent::One(item) = content {
                return_vec.push(FundingMethod {
                    title: "Ko-fi".to_string(),
                    link: format!("https://ko-fi.com/{item}"),
                    icon: Some("kofi".to_string()),
                })
            }
        }
        FundingType::Tidelift => {
            if let FundingContent::One(item) = content {
                return_vec.push(FundingMethod {
                    title: "Tidelift".to_string(),
                    link: format!("https://tidelift.com/subscription/pkg/{item}"),
                    icon: Some("patreon".to_string()),
                })
            }
        }
        FundingType::CommunityBridge => {
            if let FundingContent::One(item) = content {
                return_vec.push(FundingMethod {
                    title: "CommunityBridge".to_string(),
                    link: format!("https://crowdfunding.lfx.linuxfoundation.org/projects/{item}"),
                    icon: None,
                })
            }
        }
        FundingType::Issuehunt => {
            if let FundingContent::One(item) = content {
                return_vec.push(FundingMethod {
                    title: "IssueHunt".to_string(),
                    link: format!("https://issuehunt.com/r/{item}"),
                    icon: None,
                })
            }
        }
        FundingType::Liberapay => {
            if let FundingContent::One(item) = content {
                return_vec.push(FundingMethod {
                    title: "Liberapay".to_string(),
                    link: format!("https://liberapay.com/{item}"),
                    icon: Some("liberapay".to_string()),
                })
            }
        }
        FundingType::Custom => {
            let items = one_or_multiple(content);
            for item in items {
                return_vec.push(FundingMethod {
                    title: item.clone(),
                    link: item,
                    icon: None,
                })
            }
        }
    }

    return_vec
}

/// Handles either one or multiple funding items, and puts them into a Vec.
fn one_or_multiple(funding: &FundingContent) -> Vec<String> {
    let mut vec = vec![];
    match funding {
        FundingContent::One(item) => vec.push(item.to_owned()),
        FundingContent::Multiple(items) => vec.extend(items.to_vec()),
    }

    vec
}