#![allow(non_snake_case)]
mod components;
pub use components::*;
use std::rc::Rc;
use repose_core::*;
use repose_ui::{
Box, Column, Row, Spacer, Stack, Surface, Text, TextStyle, ViewExt, anim::animate_f32,
overlay::SnackbarAction,
};
pub fn AlertDialog(
visible: bool,
on_dismiss: impl Fn() + 'static,
title: View,
text: View,
confirm_button: View,
dismiss_button: Option<View>,
) -> View {
if !visible {
return Box(Modifier::new());
}
Stack(Modifier::new().fill_max_size()).child((
Box(Modifier::new()
.fill_max_size()
.background(Color::from_hex("#000000AA"))
.clickable()
.on_pointer_down(move |_| on_dismiss())),
Surface(
Modifier::new()
.size(280.0, 200.0)
.background(theme().surface)
.clip_rounded(28.0)
.padding(24.0),
Column(Modifier::new()).child((
title,
Box(Modifier::new().size(1.0, 16.0)),
text,
Spacer(),
Row(Modifier::new()).child((
dismiss_button.unwrap_or(Box(Modifier::new())),
Spacer(),
confirm_button,
)),
)),
),
))
}
pub fn BottomSheet(
visible: bool,
on_dismiss: impl Fn() + 'static,
modifier: Modifier,
content: View,
) -> View {
let offset = animate_f32(
"sheet_offset",
if visible { 0.0 } else { 800.0 },
AnimationSpec::spring_gentle(),
);
Stack(Modifier::new().fill_max_size()).child((
if visible {
Box(Modifier::new()
.fill_max_size()
.background(Color::from_hex("#00000055"))
.on_pointer_down(move |_| on_dismiss()))
} else {
Box(Modifier::new())
},
Box(modifier
.absolute()
.offset(None, Some(offset), Some(0.0), Some(0.0)))
.child(content),
))
}
pub fn NavigationBar(selected_index: usize, items: Vec<NavItem>) -> View {
Row(Modifier::new()
.fill_max_size()
.background(theme().surface)
.padding(8.0))
.child(
items
.into_iter()
.enumerate()
.map(|(i, item)| NavigationBarItem(item, i == selected_index))
.collect::<Vec<_>>(),
)
}
pub struct NavItem {
pub icon: View,
pub label: String,
pub on_click: Rc<dyn Fn()>,
}
fn NavigationBarItem(item: NavItem, selected: bool) -> View {
let color = if selected {
theme().primary
} else {
theme().on_surface
};
Column(
Modifier::new()
.flex_grow(1.0)
.clickable()
.on_pointer_down(move |_| (item.on_click)()),
)
.child((
item.icon, Text(item.label).color(color),
))
}
pub fn Card(modifier: Modifier, elevated: bool, content: View) -> View {
Surface(
modifier
.background(theme().surface)
.border(1.0, Color::from_hex("#22222222"), 12.0)
.clip_rounded(12.0)
.padding(16.0),
content,
)
}
pub fn Snackbar(
message: impl Into<String>,
action: Option<SnackbarAction>,
base_modifier: Modifier,
) -> View {
let msg = message.into();
let th = theme();
let bg = th.surface_variant;
let fg = th.on_surface;
let action_color = th.primary;
let modifier = base_modifier
.background(bg)
.clip_rounded(th.shapes.small)
.border(1.0, th.outline_variant, th.shapes.small)
.padding_values(PaddingValues {
left: 16.0,
right: 16.0,
top: 12.0,
bottom: 12.0,
})
.min_height(48.0)
.min_width(280.0);
Surface(
modifier,
Row(Modifier::new().align_items(repose_core::AlignItems::Center)).child((
Text(msg)
.color(fg)
.size(th.typography.body_medium)
.max_lines(2)
.overflow_ellipsize(),
Spacer(),
action
.map(|a| {
let label = a.label.clone();
Box(Modifier::new()
.padding_values(PaddingValues {
left: 8.0,
right: 8.0,
top: 6.0,
bottom: 6.0,
})
.clip_rounded(th.shapes.extra_small)
.clickable()
.on_pointer_down(move |_| (a.on_click)()))
.child(
Text(label)
.color(action_color)
.size(th.typography.label_large)
.single_line(),
)
})
.unwrap_or(Box(Modifier::new())),
)),
)
}
pub fn OutlinedCard(modifier: Modifier, content: View) -> View {
Surface(
modifier
.border(1.0, Color::from_hex("#444444"), 12.0)
.clip_rounded(12.0)
.padding(16.0),
content,
)
}
pub fn FilterChip(
selected: bool,
on_click: impl Fn() + 'static,
label: View,
leading_icon: Option<View>,
) -> View {
let bg = if selected {
theme().primary
} else {
theme().surface
};
let fg = if selected {
theme().on_primary
} else {
theme().on_surface
};
Surface(
Modifier::new()
.background(bg)
.border(1.0, Color::from_hex("#444444"), 8.0)
.clip_rounded(8.0)
.padding(12.0)
.clickable()
.on_pointer_down(move |_| on_click()),
Row(Modifier::new()).child((leading_icon.unwrap_or(Box(Modifier::new())), label)),
)
}
pub fn Scaffold(
top_bar: Option<View>,
bottom_bar: Option<View>,
floating_action_button: Option<View>,
content: impl Fn(PaddingValues) -> View,
) -> View {
Stack(Modifier::new().fill_max_size()).child((
Box(Modifier::new()
.fill_max_size()
.padding_values(PaddingValues {
top: if top_bar.is_some() { 64.0 } else { 0.0 },
bottom: if bottom_bar.is_some() { 80.0 } else { 0.0 },
..Default::default()
}))
.child(content(PaddingValues::default())),
if let Some(bar) = top_bar {
Box(Modifier::new()
.absolute()
.offset(Some(0.0), Some(0.0), Some(0.0), None))
.child(bar)
} else {
Box(Modifier::new())
},
if let Some(bar) = bottom_bar {
Box(Modifier::new()
.absolute()
.offset(Some(0.0), None, Some(0.0), Some(0.0)))
.child(bar)
} else {
Box(Modifier::new())
},
if let Some(fab) = floating_action_button {
Box(Modifier::new()
.absolute()
.offset(None, None, Some(16.0), Some(16.0)))
.child(fab)
} else {
Box(Modifier::new())
},
))
}