Files
Ely-GPUI-Components/src/theme/tokens.rs
T

467 lines
11 KiB
Rust

use gpui::{BoxShadow, Hsla, Pixels, Point, Rems, Size, point, px, rems, size};
use super::{Mode, Theme};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Density {
Compact,
#[default]
Standard,
Comfortable,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ControlSize {
Sm,
#[default]
Md,
Lg,
}
/// How large an avatar is.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum AvatarSize {
Xs,
Sm,
#[default]
Md,
Lg,
Xl,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum IconSize {
Xs,
Sm,
#[default]
Md,
Lg,
Xl,
Xxl,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TextSize {
Xs,
Sm,
Base,
Md,
Lg,
Xl,
Xxl,
Display,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ContainerSize {
Sm,
#[default]
Md,
Lg,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Radius {
Sm,
Md,
Lg,
Xl,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Elevation {
Raised,
Floating,
Modal,
}
fn px_to_rems(value: f32) -> Rems {
rems(value / 16.0)
}
impl Theme {
pub fn control_height(&self, size: ControlSize) -> Rems {
let base = match size {
ControlSize::Sm => 24.0,
ControlSize::Md => 28.0,
ControlSize::Lg => 32.0,
};
let delta = match self.density {
Density::Compact => -4.0,
Density::Standard => 0.0,
Density::Comfortable => 4.0,
};
px_to_rems(base + delta)
}
pub fn control_padding(&self, size: ControlSize) -> Rems {
let base = match size {
ControlSize::Sm => 8.0,
ControlSize::Md => 12.0,
ControlSize::Lg => 16.0,
};
let delta = match self.density {
Density::Compact => -2.0,
Density::Standard => 0.0,
Density::Comfortable => 2.0,
};
px_to_rems(base + delta)
}
pub fn avatar_size(&self, size: AvatarSize) -> Rems {
px_to_rems(match size {
AvatarSize::Xs => 20.0,
AvatarSize::Sm => 24.0,
AvatarSize::Md => 32.0,
AvatarSize::Lg => 40.0,
AvatarSize::Xl => 56.0,
})
}
pub fn icon_size(&self, size: IconSize) -> Rems {
let base = match size {
IconSize::Xs => 12.0,
IconSize::Sm => 14.0,
IconSize::Md => 16.0,
IconSize::Lg => 20.0,
IconSize::Xl => 24.0,
IconSize::Xxl => 32.0,
};
px_to_rems(base * self.font_scale)
}
pub fn container_width(&self, size: ContainerSize) -> Rems {
px_to_rems(match size {
ContainerSize::Sm => 640.0,
ContainerSize::Md => 960.0,
ContainerSize::Lg => 1200.0,
})
}
pub fn sidebar_width(&self, collapsed: bool) -> Rems {
px_to_rems(if collapsed { 56.0 } else { 240.0 })
}
/// Width of a side sheet, height of a top or bottom one.
pub fn sheet_size(&self) -> Rems {
px_to_rems(380.0)
}
pub fn scrollbar_thickness(&self) -> Rems {
px_to_rems(6.0)
}
pub fn scrollbar_min_thumb(&self) -> Rems {
px_to_rems(24.0)
}
/// Smallest a split pane or dock may shrink to.
pub fn pane_min(&self) -> Rems {
px_to_rems(160.0)
}
pub fn titlebar_height(&self) -> Rems {
px_to_rems(38.0)
}
/// Room kept for the macOS traffic lights.
pub fn traffic_light_inset(&self) -> Rems {
px_to_rems(78.0)
}
/// Where the system traffic lights sit in a window this crate opens.
pub fn traffic_light_origin(&self) -> Point<Pixels> {
point(px(14.0), px(13.0))
}
/// Underline under composing text.
pub fn underline_thickness(&self) -> Pixels {
px(1.0)
}
pub fn caret_width(&self) -> Rems {
px_to_rems(1.5)
}
/// Diameter of a floating action button.
pub fn fab_size(&self) -> Rems {
px_to_rems(56.0)
}
pub fn progress_thickness(&self) -> Rems {
px_to_rems(2.0)
}
/// A progress ring's width, room for a percent inside.
pub fn progress_ring(&self) -> Rems {
px_to_rems(48.0)
}
pub fn about_window(&self) -> Size<Pixels> {
size(px(360.0), px(400.0))
}
/// Update and crash windows.
pub fn dialog_window(&self) -> Size<Pixels> {
size(px(400.0), px(480.0))
}
pub fn splash_window(&self) -> Size<Pixels> {
size(px(480.0), px(300.0))
}
/// A window's rem size at 100% zoom; gpui's own default.
pub fn base_rem(&self) -> Pixels {
px(16.0)
}
/// Gap between the edge of a screen or window and what floats by it: a mini window, a toast stack.
pub fn window_margin(&self) -> Pixels {
px(24.0)
}
/// One drawn traffic light.
pub fn traffic_light(&self) -> Rems {
px_to_rems(12.0)
}
/// A Windows caption button.
pub fn caption_button_width(&self) -> Rems {
px_to_rems(46.0)
}
/// Resize margin of a client-drawn window.
pub fn window_inset(&self) -> Rems {
px_to_rems(10.0)
}
pub fn rail_width(&self) -> Rems {
px_to_rems(48.0)
}
/// Narrowest and widest window tab.
pub fn tab_width(&self) -> (Rems, Rems) {
(px_to_rems(96.0), px_to_rems(200.0))
}
/// The line that marks a chosen tab.
pub fn tab_indicator(&self) -> Rems {
px_to_rems(2.0)
}
/// Width of a navigation menu's panel of links.
pub fn nav_panel_width(&self) -> Rems {
px_to_rems(480.0)
}
/// A pie menu's ring radius and the size of each slice's button.
pub fn pie(&self) -> (Rems, Rems) {
(px_to_rems(84.0), px_to_rems(40.0))
}
/// Room between a box and what floats by it: a spotlight's ring, a selection's toolbar.
pub fn float_gap(&self) -> Rems {
px_to_rems(6.0)
}
/// Width of a dialog's card.
pub fn dialog_width(&self) -> Rems {
px_to_rems(440.0)
}
/// Width of a toast stack.
pub fn toast_width(&self) -> Rems {
px_to_rems(360.0)
}
/// How far a glow's light reaches at its brightest.
pub fn glow_reach(&self) -> Rems {
px_to_rems(20.0)
}
/// A picture's height in a skeleton card.
pub fn skeleton_media(&self) -> Rems {
px_to_rems(128.0)
}
/// How far each level of a tree steps in.
pub fn tree_indent(&self) -> Rems {
px_to_rems(16.0)
}
/// How far past the viewport a long list builds rows ahead.
pub fn list_overdraw(&self) -> Rems {
px_to_rems(240.0)
}
/// One action behind a swiped row.
pub fn swipe_action(&self) -> Rems {
px_to_rems(72.0)
}
/// A QR code's tile.
pub fn qr_code(&self) -> Rems {
px_to_rems(160.0)
}
/// The narrowest bar of a barcode; the others are whole multiples.
pub fn barcode_module(&self) -> Rems {
px_to_rems(2.0)
}
pub fn barcode_height(&self) -> Rems {
px_to_rems(56.0)
}
/// A gauge's dial.
pub fn gauge(&self) -> Rems {
px_to_rems(144.0)
}
/// The track of a meter or a usage bar.
pub fn meter_track(&self) -> Rems {
px_to_rems(6.0)
}
/// One repeat of a watermark's text.
pub fn watermark_tile(&self) -> Size<Rems> {
size(px_to_rems(200.0), px_to_rems(96.0))
}
/// The label column of a description list.
pub fn label_width(&self) -> Rems {
px_to_rems(160.0)
}
/// Widest a centered block of prose runs, such as an empty state's help.
pub fn prose_width(&self) -> Rems {
px_to_rems(320.0)
}
/// Narrowest a menu's panel gets.
pub fn menu_width(&self) -> Rems {
px_to_rems(200.0)
}
/// A palette's card; its list scrolls inside.
pub fn palette_size(&self) -> Size<Rems> {
size(px_to_rems(600.0), px_to_rems(400.0))
}
/// Grab bar on a drawer.
pub fn grip(&self) -> Size<Rems> {
size(px_to_rems(36.0), px_to_rems(4.0))
}
/// Hit area of a split or resize handle.
pub fn handle_hit(&self) -> Rems {
px_to_rems(6.0)
}
/// Gap between the pointer and a tooltip.
pub fn cursor_offset(&self) -> Rems {
px_to_rems(18.0)
}
/// A checkbox or radio mark.
pub fn check_size(&self) -> Rems {
px_to_rems(16.0)
}
/// The dot inside a chosen radio.
pub fn radio_dot(&self) -> Rems {
px_to_rems(6.0)
}
/// A dot that marks a state, such as unsaved changes.
pub fn status_dot(&self) -> Rems {
px_to_rems(6.0)
}
/// A switch's track; its thumb fills the height inside a small inset.
pub fn switch_track(&self) -> Size<Rems> {
size(px_to_rems(32.0), px_to_rems(18.0))
}
pub fn slider_track(&self) -> Rems {
px_to_rems(4.0)
}
pub fn slider_thumb(&self) -> Rems {
px_to_rems(16.0)
}
/// Diameter and arc width of a knob.
pub fn knob(&self) -> (Rems, Rems) {
(px_to_rems(48.0), px_to_rems(3.0))
}
/// Height of a color picker's saturation and value plane.
pub fn color_plane(&self) -> Rems {
px_to_rems(152.0)
}
/// A signature pad's height and its ink's width.
pub fn signature(&self) -> (Rems, Rems) {
(px_to_rems(160.0), px_to_rems(2.0))
}
/// Tallest a list grows before it scrolls.
pub fn list_max_height(&self) -> Rems {
px_to_rems(280.0)
}
pub fn tooltip_max_width(&self) -> Rems {
px_to_rems(256.0)
}
pub fn text_size(&self, size: TextSize) -> Rems {
let base = match size {
TextSize::Xs => 11.0,
TextSize::Sm => 12.0,
TextSize::Base => 13.0,
TextSize::Md => 14.0,
TextSize::Lg => 16.0,
TextSize::Xl => 20.0,
TextSize::Xxl => 24.0,
TextSize::Display => 32.0,
};
px_to_rems(base * self.font_scale)
}
pub fn radius(&self, size: Radius) -> Rems {
let base = match size {
Radius::Sm => 4.0,
Radius::Md => 6.0,
Radius::Lg => 8.0,
Radius::Xl => 12.0,
};
px_to_rems(base * self.radius_scale)
}
pub fn elevation(&self, level: Elevation) -> Vec<BoxShadow> {
let dark = self.mode == Mode::Dark;
let layers: &[(f32, f32, f32)] = match (level, dark) {
(Elevation::Raised, false) => &[(1.0, 2.0, 0.06)],
(Elevation::Floating, false) => &[(1.0, 2.0, 0.04), (6.0, 16.0, 0.08)],
(Elevation::Modal, false) => &[(2.0, 4.0, 0.04), (16.0, 40.0, 0.14)],
(Elevation::Raised, true) => &[(1.0, 2.0, 0.4)],
(Elevation::Floating, true) => &[(2.0, 4.0, 0.3), (8.0, 24.0, 0.45)],
(Elevation::Modal, true) => &[(4.0, 8.0, 0.3), (20.0, 48.0, 0.55)],
};
layers
.iter()
.map(|&(y, blur, alpha)| shadow(self.colors.shadow.alpha(alpha), y, blur))
.collect()
}
}
fn shadow(color: Hsla, y: f32, blur: f32) -> BoxShadow {
BoxShadow {
color,
offset: point(px(0.0), px(y)),
blur_radius: px(blur),
spread_radius: px(0.0),
}
}