oxiced 0.5.1

An iced themeing library
Documentation
use iced::{
    Alignment, Element, Length, Theme,
    alignment::{Horizontal, Vertical},
    border,
    widget::{Row, column, container::Style, row, text},
};

use crate::{
    theme::theme::OXITHEME,
    widgets::{
        oxi_button::{self, ButtonVariant},
        oxi_icon::icon_widget,
    },
};

pub enum CardHeader<'a, T: Clone, I: ToString> {
    Title(String),
    TitleWithIcon {
        title: String,
        icon: I,
    },
    TitleWithElement {
        title: String,
        element: Element<'a, T>,
    },
    Custom(Element<'a, T>),
}

impl<'a, T: Clone + 'a, I: ToString> CardHeader<'a, T, I> {
    fn mk_title(
        title: String,
        icon_opt: Option<I>,
        element: Option<Element<'a, T>>,
    ) -> Element<'a, T> {
        let palette = OXITHEME;
        let mut elems: Vec<Element<'a, T>> = vec![
            text(title).size(palette.font_xl).into(),
            column!(element.unwrap_or(row!().into()))
                .width(Length::Fill)
                .align_x(Alignment::End)
                .into(),
        ];
        if let Some(icon) = icon_opt {
            elems.insert(0, icon_widget::<I>(icon).into());
        }
        Row::from_vec(elems).padding(palette.padding_lg).into()
    }

    fn mk_header(self) -> Element<'a, T> {
        match self {
            CardHeader::Title(title) => Self::mk_title(title, None, None),
            CardHeader::TitleWithIcon { title, icon } => Self::mk_title(title, Some(icon), None),
            CardHeader::TitleWithElement { title, element } => {
                Self::mk_title(title, None, Some(element))
            }
            CardHeader::Custom(element) => element,
        }
    }
}

pub struct Card<'a, T: Clone + 'a, I: ToString> {
    header: Option<CardHeader<'a, T, I>>,
    body: Element<'a, T>,
    on_click: Option<fn() -> T>,
}

impl<'a, T: Clone + 'a> Card<'a, T, String> {
    pub fn mk_title_card(title: String, body: Element<'a, T>) -> Element<'a, T> {
        Self {
            header: Some(CardHeader::Title(title)),
            body,
            on_click: None,
        }
        .view()
    }
}

impl<'a, T: Clone + 'a, I: ToString + 'a> Card<'a, T, I> {
    fn style(_: &Theme) -> Style {
        let palette = OXITHEME;

        Style {
            background: Some(palette.mantle.into()),
            border: border::rounded(palette.border_radius),
            ..Style::default()
        }
    }

    fn clickable_card(
        element: impl Into<Element<'a, T>>,
        on_click: fn() -> T,
    ) -> impl Into<Element<'a, T>> {
        oxi_button::button(element, ButtonVariant::Neutral).on_press_with(on_click)
    }

    fn view(self) -> Element<'a, T> {
        let card = iced::widget::container(
            column!(
                self.header
                    .map(|value| value.mk_header())
                    .unwrap_or(row!().into()),
                self.body,
            )
            .spacing(OXITHEME.padding_md)
            .width(Length::Fill)
            .height(Length::Fill),
        )
        .padding(OXITHEME.padding_lg)
        .style(Self::style)
        .align_x(Horizontal::Center)
        .align_y(Vertical::Center);
        if let Some(click) = self.on_click {
            Self::clickable_card(card, click).into()
        } else {
            card.into()
        }
    }
}