ui/styles/shadow.rs
1//! Elevation shadow scale for the design system.
2//!
3//! GPUI has no CSS-style `.shadow-*` utility; the primitive is a
4//! `Vec<BoxShadow>` applied via the [`gpui::Styled::shadow`] method. This
5//! module provides a generic named scale ([`Shadow`]) whose values mirror the
6//! Tailwind box-shadow reference, plus a [`StyledShadow`] ext so components can
7//! write `el.shadow_level(Shadow::Md)`.
8
9use gpui::{BoxShadow, Styled, hsla, point, px};
10use smallvec::{SmallVec, smallvec};
11
12/// Named elevation levels. Values mirror the Tailwind box-shadow scale.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Shadow {
15 /// Subtle 1px shadow (`shadow-sm`).
16 Sm,
17 /// Default card shadow (`shadow`).
18 Base,
19 /// Medium raised shadow (`shadow-md`).
20 Md,
21 /// Large popover/dropdown shadow (`shadow-lg`).
22 Lg,
23 /// Extra-large modal shadow (`shadow-xl`).
24 Xl,
25}
26
27fn black(alpha: f32) -> gpui::Hsla {
28 hsla(0., 0., 0., alpha)
29}
30
31impl Shadow {
32 /// The box-shadow layers for this elevation level.
33 pub fn box_shadows(self) -> SmallVec<[BoxShadow; 2]> {
34 match self {
35 Shadow::Sm => smallvec![BoxShadow {
36 color: black(0.05),
37 offset: point(px(0.), px(1.)),
38 blur_radius: px(2.),
39 spread_radius: px(0.),
40 }],
41 Shadow::Base => smallvec![
42 BoxShadow {
43 color: black(0.1),
44 offset: point(px(0.), px(1.)),
45 blur_radius: px(3.),
46 spread_radius: px(0.),
47 },
48 BoxShadow {
49 color: black(0.1),
50 offset: point(px(0.), px(1.)),
51 blur_radius: px(2.),
52 spread_radius: px(-1.),
53 },
54 ],
55 Shadow::Md => smallvec![
56 BoxShadow {
57 color: black(0.1),
58 offset: point(px(0.), px(4.)),
59 blur_radius: px(6.),
60 spread_radius: px(-1.),
61 },
62 BoxShadow {
63 color: black(0.1),
64 offset: point(px(0.), px(2.)),
65 blur_radius: px(4.),
66 spread_radius: px(-2.),
67 },
68 ],
69 Shadow::Lg => smallvec![
70 BoxShadow {
71 color: black(0.1),
72 offset: point(px(0.), px(10.)),
73 blur_radius: px(15.),
74 spread_radius: px(-3.),
75 },
76 BoxShadow {
77 color: black(0.1),
78 offset: point(px(0.), px(4.)),
79 blur_radius: px(6.),
80 spread_radius: px(-4.),
81 },
82 ],
83 Shadow::Xl => smallvec![
84 BoxShadow {
85 color: black(0.1),
86 offset: point(px(0.), px(20.)),
87 blur_radius: px(25.),
88 spread_radius: px(-5.),
89 },
90 BoxShadow {
91 color: black(0.1),
92 offset: point(px(0.), px(8.)),
93 blur_radius: px(10.),
94 spread_radius: px(-6.),
95 },
96 ],
97 }
98 }
99}
100
101/// Extends [`gpui::Styled`] with a named shadow scale.
102pub trait StyledShadow: Styled + Sized {
103 /// Applies the box-shadow layers for the given [`Shadow`] level.
104 fn shadow_level(self, level: Shadow) -> Self {
105 self.shadow(level.box_shadows().to_vec())
106 }
107}
108
109impl<E: Styled> StyledShadow for E {}