use std::ops::{Deref, DerefMut};
use blinc_layout::div::{Div, ElementBuilder, ElementTypeId};
use blinc_layout::prelude::*;
use blinc_theme::{ColorToken, SpacingToken, ThemeState};
pub struct Card {
inner: Div,
}
impl Card {
pub fn new() -> Self {
let inner = div().class("cn-card").shadow_sm().flex_col().items_start();
Self { inner }
}
pub fn child(mut self, content: impl ElementBuilder + 'static) -> Self {
self.inner = self.inner.child(content);
self
}
pub fn w(mut self, width: f32) -> Self {
self.inner = self.inner.w(width);
self
}
pub fn h(mut self, height: f32) -> Self {
self.inner = self.inner.h(height);
self
}
pub fn w_full(mut self) -> Self {
self.inner = self.inner.w_full();
self
}
pub fn p(mut self, padding: f32) -> Self {
self.inner = self.inner.p(padding);
self
}
pub fn px(mut self, padding: f32) -> Self {
self.inner = self.inner.px(padding);
self
}
pub fn py(mut self, padding: f32) -> Self {
self.inner = self.inner.py(padding);
self
}
pub fn m(mut self, margin: f32) -> Self {
self.inner = self.inner.m(margin);
self
}
pub fn shadow_lg(mut self) -> Self {
self.inner = self.inner.shadow_lg();
self
}
pub fn shadow_md(mut self) -> Self {
self.inner = self.inner.shadow_md();
self
}
pub fn bg(mut self, color: blinc_core::Color) -> Self {
self.inner = self.inner.bg(color);
self
}
pub fn class(mut self, name: impl Into<String>) -> Self {
self.inner = self.inner.class(name);
self
}
pub fn id(mut self, id: &str) -> Self {
self.inner = self.inner.id(id);
self
}
}
impl Default for Card {
fn default() -> Self {
Self::new()
}
}
impl Deref for Card {
type Target = Div;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for Card {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl ElementBuilder for Card {
fn build(&self, tree: &mut blinc_layout::tree::LayoutTree) -> blinc_layout::tree::LayoutNodeId {
self.inner.build(tree)
}
fn render_props(&self) -> blinc_layout::element::RenderProps {
self.inner.render_props()
}
fn children_builders(&self) -> &[Box<dyn ElementBuilder>] {
self.inner.children_builders()
}
fn event_handlers(&self) -> Option<&blinc_layout::event_handler::EventHandlers> {
ElementBuilder::event_handlers(&self.inner)
}
fn layout_style(&self) -> Option<&taffy::Style> {
ElementBuilder::layout_style(&self.inner)
}
fn element_type_id(&self) -> ElementTypeId {
ElementBuilder::element_type_id(&self.inner)
}
fn element_classes(&self) -> &[String] {
self.inner.element_classes()
}
fn element_id(&self) -> Option<&str> {
self.inner.element_id()
}
}
pub fn card() -> Card {
Card::new()
}
pub struct CardHeader {
inner: Div,
}
impl CardHeader {
pub fn new() -> Self {
let theme = ThemeState::get();
let gap = theme.spacing_value(SpacingToken::Space1_5); let inner = div()
.class("cn-card-header")
.flex_col()
.items_start()
.w_full()
.gap_px(gap);
Self { inner }
}
pub fn title(mut self, title: impl Into<String>) -> Self {
let theme = ThemeState::get();
self.inner = self.inner.child(
text(title)
.size(18.0)
.semibold()
.color(theme.color(ColorToken::TextPrimary)),
);
self
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
let theme = ThemeState::get();
self.inner = self.inner.child(
text(desc)
.size(14.0)
.color(theme.color(ColorToken::TextSecondary)),
);
self
}
}
impl Default for CardHeader {
fn default() -> Self {
Self::new()
}
}
impl Deref for CardHeader {
type Target = Div;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for CardHeader {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl ElementBuilder for CardHeader {
fn build(&self, tree: &mut blinc_layout::tree::LayoutTree) -> blinc_layout::tree::LayoutNodeId {
self.inner.build(tree)
}
fn render_props(&self) -> blinc_layout::element::RenderProps {
self.inner.render_props()
}
fn children_builders(&self) -> &[Box<dyn ElementBuilder>] {
self.inner.children_builders()
}
fn event_handlers(&self) -> Option<&blinc_layout::event_handler::EventHandlers> {
ElementBuilder::event_handlers(&self.inner)
}
fn layout_style(&self) -> Option<&taffy::Style> {
ElementBuilder::layout_style(&self.inner)
}
fn element_type_id(&self) -> ElementTypeId {
ElementBuilder::element_type_id(&self.inner)
}
fn element_classes(&self) -> &[String] {
self.inner.element_classes()
}
fn element_id(&self) -> Option<&str> {
self.inner.element_id()
}
}
pub fn card_header() -> CardHeader {
CardHeader::new()
}
pub struct CardContent {
inner: Div,
}
impl CardContent {
pub fn new() -> Self {
let inner = div()
.flex_col()
.flex_1() .w_full();
Self { inner }
}
pub fn child(mut self, content: impl ElementBuilder + 'static) -> Self {
self.inner = self.inner.child(content);
self
}
}
impl Default for CardContent {
fn default() -> Self {
Self::new()
}
}
impl Deref for CardContent {
type Target = Div;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for CardContent {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl ElementBuilder for CardContent {
fn build(&self, tree: &mut blinc_layout::tree::LayoutTree) -> blinc_layout::tree::LayoutNodeId {
self.inner.build(tree)
}
fn render_props(&self) -> blinc_layout::element::RenderProps {
self.inner.render_props()
}
fn children_builders(&self) -> &[Box<dyn ElementBuilder>] {
self.inner.children_builders()
}
fn event_handlers(&self) -> Option<&blinc_layout::event_handler::EventHandlers> {
ElementBuilder::event_handlers(&self.inner)
}
fn layout_style(&self) -> Option<&taffy::Style> {
ElementBuilder::layout_style(&self.inner)
}
fn element_type_id(&self) -> ElementTypeId {
ElementBuilder::element_type_id(&self.inner)
}
fn element_classes(&self) -> &[String] {
self.inner.element_classes()
}
fn element_id(&self) -> Option<&str> {
self.inner.element_id()
}
}
pub fn card_content() -> CardContent {
CardContent::new()
}
pub struct CardFooter {
inner: Div,
}
impl CardFooter {
pub fn new() -> Self {
let theme = ThemeState::get();
let gap = theme.spacing_value(SpacingToken::Space2); let inner = div()
.class("cn-card-footer")
.flex_row()
.w_full()
.gap_px(gap)
.justify_end();
Self { inner }
}
pub fn child(mut self, content: impl ElementBuilder + 'static) -> Self {
self.inner = self.inner.child(content);
self
}
}
impl Default for CardFooter {
fn default() -> Self {
Self::new()
}
}
impl Deref for CardFooter {
type Target = Div;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for CardFooter {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl ElementBuilder for CardFooter {
fn build(&self, tree: &mut blinc_layout::tree::LayoutTree) -> blinc_layout::tree::LayoutNodeId {
self.inner.build(tree)
}
fn render_props(&self) -> blinc_layout::element::RenderProps {
self.inner.render_props()
}
fn children_builders(&self) -> &[Box<dyn ElementBuilder>] {
self.inner.children_builders()
}
fn event_handlers(&self) -> Option<&blinc_layout::event_handler::EventHandlers> {
ElementBuilder::event_handlers(&self.inner)
}
fn layout_style(&self) -> Option<&taffy::Style> {
ElementBuilder::layout_style(&self.inner)
}
fn element_type_id(&self) -> ElementTypeId {
ElementBuilder::element_type_id(&self.inner)
}
fn element_classes(&self) -> &[String] {
self.inner.element_classes()
}
fn element_id(&self) -> Option<&str> {
self.inner.element_id()
}
}
pub fn card_footer() -> CardFooter {
CardFooter::new()
}
#[cfg(test)]
mod tests {
use super::*;
fn init_theme() {
let _ = ThemeState::try_get().unwrap_or_else(|| {
ThemeState::init_default();
ThemeState::get()
});
}
#[test]
fn test_card_default() {
init_theme();
let _ = card();
}
#[test]
fn test_card_with_content() {
init_theme();
let _ = card().child(text("Content"));
}
#[test]
fn test_card_header() {
init_theme();
let _ = card_header().title("Title").description("Description");
}
#[test]
fn test_card_footer() {
init_theme();
let _ = card_footer();
}
}