1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Every degree of freedom a `Shadow` has, and where a ladder of them lives.
//!
//! guido ships no elevation level and no table behind one. A shadow is four
//! numbers — offset, blur, spread and colour — and a design system's steps are
//! `Shadow` constants the application writes down, the way it writes down its
//! colours. Row 1 is one such ladder; the rows below it are what a single
//! number could never say.
use guido::prelude::*;
/// A ladder, defined where a ladder belongs: in the application.
///
/// `Shadow::new` is `const`, so these cost nothing and can be shared from a
/// theme module.
mod elevation {
use guido::prelude::{Color, Shadow};
const fn step(offset_y: f32, blur: f32, alpha: f32) -> Shadow {
Shadow::new(
(0.0, offset_y),
blur,
0.0,
Color::rgba(0.0, 0.0, 0.0, alpha),
)
}
pub const FLAT: Shadow = Shadow::none();
pub const LOW: Shadow = step(1.0, 3.0, 0.12);
pub const RAISED: Shadow = step(3.0, 6.0, 0.19);
pub const HIGH: Shadow = step(6.0, 10.0, 0.22);
}
fn card<M>(label: &str, shadow: impl IntoAnimated<Shadow, M>) -> Container {
container()
.padding(28.0)
.background(Color::WHITE)
.corners(8.0)
.shadow(shadow)
.child(text(label.to_string()).color(Color::rgb(0.2, 0.2, 0.2)))
}
fn row() -> Container {
container().layout(Flex::row().spacing(48.0))
}
fn main() {
App::new().run(|app| {
app.add_surface(
SurfaceConfig::new()
.width(1200)
.height(700)
.anchor(Anchor::TOP | Anchor::LEFT)
.background_color(Color::rgb(0.85, 0.85, 0.9)),
|| {
container()
.padding(48.0)
.layout(Flex::column().spacing(48.0))
// A ladder the application owns.
.child(
row()
.child(card("Flat", elevation::FLAT))
.child(card("Low", elevation::LOW))
.child(card("Raised", elevation::RAISED))
.child(card("High", elevation::HIGH)),
)
// The three the old elevation level could not reach: it
// always wrote `(0.0, offset_y)`, a spread of `0.0`, and
// black at the alpha its table chose.
.child(
row()
.child(card(
"Sideways",
Shadow::new(
(18.0, 0.0),
10.0,
0.0,
Color::rgba(0.0, 0.0, 0.0, 0.35),
),
))
.child(card(
"Coloured",
Shadow::new(
(0.0, 8.0),
14.0,
0.0,
Color::rgba(0.85, 0.1, 0.2, 0.55),
),
))
.child(card(
"Spread, no offset",
Shadow::new(
(0.0, 0.0),
8.0,
10.0,
Color::rgba(0.1, 0.2, 0.8, 0.45),
),
)),
)
// The motion rides with the declaration, so a hover lifts
// the card rather than snapping it.
.child(
row()
.child(
card("Hover me", elevation::LOW.transition(160.0))
.when_hovered(|s| s.shadow(elevation::HIGH)),
)
.child(
card(
"Hover me too",
elevation::FLAT.transition(SpringConfig::BOUNCY),
)
.when_hovered(|s| {
s.shadow(Shadow::new(
(0.0, 10.0),
20.0,
2.0,
Color::rgba(0.1, 0.1, 0.4, 0.4),
))
}),
),
)
},
);
});
}