Skip to main content

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 {}