chore: audit all components (#2)
Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
+138
-18
@@ -23,6 +23,10 @@ pub use system::{AccessibilityPreferences, PartialPalette, SourceKind, SystemThe
|
||||
use gpui::{App, Global, Hsla, Pixels, WindowAppearance, px};
|
||||
use std::time::Duration;
|
||||
|
||||
/// The hairline width of the control border every button and field paints;
|
||||
/// sized outside the stated metrics so control sizes match across platforms.
|
||||
pub const BORDER_WIDTH: Pixels = px(1.0);
|
||||
|
||||
/// Light or dark, resolved from the system appearance.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
@@ -48,6 +52,9 @@ pub struct Theme {
|
||||
pub colors: ColorTokens,
|
||||
pub ramps: Ramps,
|
||||
pub radius: Radius,
|
||||
/// Per-platform border and focus chrome.
|
||||
pub borders: Borders,
|
||||
pub spacing: Spacing,
|
||||
pub elevations: Elevations,
|
||||
/// Overlay transition timing; gpui's animation primitives do the rest.
|
||||
pub motion: Motion,
|
||||
@@ -88,6 +95,59 @@ impl Default for Radius {
|
||||
}
|
||||
}
|
||||
|
||||
/// Which surfaces keep a 1px border, per the platform's chrome: Windows and
|
||||
/// KDE frame their controls, macOS and GNOME paint fills.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Borders {
|
||||
/// Filled actions keep a border (Windows, KDE).
|
||||
pub buttons: bool,
|
||||
/// Text fields and selects keep a border.
|
||||
pub fields: bool,
|
||||
/// Floating layers keep a border.
|
||||
pub overlays: bool,
|
||||
/// Keyboard focus paints an accent ring around the control.
|
||||
pub focus_ring: bool,
|
||||
}
|
||||
|
||||
impl Borders {
|
||||
pub(crate) fn for_platform(source: SourceKind, variant: ThemeVariant) -> Self {
|
||||
let overlays = variant == ThemeVariant::Dark;
|
||||
|
||||
match source {
|
||||
SourceKind::Windows | SourceKind::Kde => Self {
|
||||
buttons: true,
|
||||
fields: true,
|
||||
overlays: true,
|
||||
focus_ring: false,
|
||||
},
|
||||
SourceKind::Macos => Self {
|
||||
buttons: false,
|
||||
fields: true,
|
||||
overlays,
|
||||
focus_ring: true,
|
||||
},
|
||||
SourceKind::Omarchy | SourceKind::Gnome => Self {
|
||||
buttons: false,
|
||||
fields: false,
|
||||
overlays,
|
||||
focus_ring: true,
|
||||
},
|
||||
SourceKind::Fallback => Self {
|
||||
buttons: true,
|
||||
fields: true,
|
||||
overlays: true,
|
||||
focus_ring: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The spacing rhythm of the platform: paddings and gaps step by this unit.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Spacing {
|
||||
pub unit: Pixels,
|
||||
}
|
||||
|
||||
/// One layer of a floating panel's drop shadow.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Shadow {
|
||||
@@ -129,6 +189,13 @@ pub struct Elevation {
|
||||
}
|
||||
|
||||
impl Elevation {
|
||||
/// No shadow: dark floating layers separate by border.
|
||||
fn none() -> Self {
|
||||
Self {
|
||||
layers: [Shadow::none(), Shadow::none()],
|
||||
}
|
||||
}
|
||||
|
||||
fn single(key: Shadow) -> Self {
|
||||
Self {
|
||||
layers: [key, Shadow::none()],
|
||||
@@ -172,8 +239,8 @@ impl Elevations {
|
||||
pub(crate) fn for_platform(source: SourceKind, variant: ThemeVariant) -> Self {
|
||||
if variant == ThemeVariant::Dark {
|
||||
return Self {
|
||||
popover: Elevation::single(Shadow::black(0., 4., 24., 0.3)),
|
||||
dialog: Elevation::single(Shadow::black(0., 8., 40., 0.35)),
|
||||
popover: Elevation::none(),
|
||||
dialog: Elevation::none(),
|
||||
control: Elevation::single(Shadow::black(0., 1., 2., 0.25)),
|
||||
};
|
||||
}
|
||||
@@ -283,12 +350,18 @@ pub struct ControlMetrics {
|
||||
pub avatar_size: Pixels,
|
||||
/// Dense label text.
|
||||
pub caption_size: Pixels,
|
||||
/// Tight horizontal padding inside pills, segments, and fields.
|
||||
/// Tight horizontal padding inside pills, segments, fields, and icon-only buttons.
|
||||
pub dense_padding_x: Pixels,
|
||||
/// The inset between a control's edge and a raised inner plate.
|
||||
pub plate_inset: Pixels,
|
||||
/// The band height of multi-segment strips.
|
||||
pub strip_height: Pixels,
|
||||
/// The height of one menu row.
|
||||
pub menu_item_height: Pixels,
|
||||
/// Switch track height, width, and knob size.
|
||||
pub switch_height: Pixels,
|
||||
pub switch_width: Pixels,
|
||||
pub switch_knob: Pixels,
|
||||
}
|
||||
|
||||
/// The control metrics for every size class.
|
||||
@@ -309,6 +382,7 @@ impl SizeTable {
|
||||
avatar: f32,
|
||||
strip: f32,
|
||||
inset: f32,
|
||||
floor_icon: bool,
|
||||
}
|
||||
|
||||
let small = ClassFactors {
|
||||
@@ -319,6 +393,7 @@ impl SizeTable {
|
||||
avatar: 1.5,
|
||||
strip: 1.5,
|
||||
inset: 0.125,
|
||||
floor_icon: false,
|
||||
};
|
||||
|
||||
let medium = ClassFactors {
|
||||
@@ -329,6 +404,7 @@ impl SizeTable {
|
||||
avatar: 2.0,
|
||||
strip: 2.0,
|
||||
inset: 0.25,
|
||||
floor_icon: true,
|
||||
};
|
||||
|
||||
let large = ClassFactors {
|
||||
@@ -339,21 +415,34 @@ impl SizeTable {
|
||||
avatar: 3.0,
|
||||
strip: 3.0,
|
||||
inset: 0.375,
|
||||
floor_icon: true,
|
||||
};
|
||||
|
||||
let metrics = |f: &ClassFactors| ControlMetrics {
|
||||
control_height: rem_size * f.height,
|
||||
input_height: rem_size * (f.height + 0.125),
|
||||
padding_x: rem_size * f.padding,
|
||||
text_size: rem_size * f.text,
|
||||
icon_size: rem_size * f.icon,
|
||||
dense_icon_size: rem_size * f.icon * 0.75,
|
||||
indicator_size: rem_size * f.height * 0.7,
|
||||
avatar_size: rem_size * f.avatar,
|
||||
caption_size: rem_size * f.text,
|
||||
dense_padding_x: rem_size * f.padding * 0.75,
|
||||
plate_inset: rem_size * f.inset,
|
||||
strip_height: rem_size * f.strip,
|
||||
let metrics = |f: &ClassFactors| {
|
||||
let icon_size = if f.floor_icon {
|
||||
(rem_size * f.icon).max(px(16.))
|
||||
} else {
|
||||
rem_size * f.icon
|
||||
};
|
||||
let switch_height = rem_size * f.height * 0.75;
|
||||
ControlMetrics {
|
||||
control_height: rem_size * f.height,
|
||||
input_height: rem_size * (f.height + 0.125),
|
||||
padding_x: rem_size * f.padding,
|
||||
text_size: rem_size * f.text,
|
||||
icon_size,
|
||||
dense_icon_size: icon_size * 0.75,
|
||||
indicator_size: rem_size * f.height * 0.7,
|
||||
avatar_size: rem_size * f.avatar,
|
||||
caption_size: rem_size * f.text,
|
||||
dense_padding_x: rem_size * f.padding * 0.75,
|
||||
plate_inset: rem_size * f.inset,
|
||||
strip_height: rem_size * f.strip,
|
||||
menu_item_height: rem_size * f.height * 0.85,
|
||||
switch_height,
|
||||
switch_width: switch_height * 2.25,
|
||||
switch_knob: switch_height * 0.85,
|
||||
}
|
||||
};
|
||||
|
||||
let mut table = Self {
|
||||
@@ -379,9 +468,38 @@ impl SizeTable {
|
||||
/// Sets the medium class's text-field height to the platform's stated value.
|
||||
pub fn set_input_height(&mut self, medium_input_height: Pixels) {
|
||||
let ratio = medium_input_height / self.medium.input_height;
|
||||
self.small.input_height *= ratio;
|
||||
self.small.input_height = (self.small.input_height * ratio).floor();
|
||||
self.medium.input_height = medium_input_height;
|
||||
self.large.input_height *= ratio;
|
||||
self.large.input_height = (self.large.input_height * ratio).floor();
|
||||
}
|
||||
|
||||
/// Sets the medium class's control height to the platform's stated value.
|
||||
pub fn set_control_height(&mut self, medium_control_height: Pixels) {
|
||||
let ratio = medium_control_height / self.medium.control_height;
|
||||
self.small.control_height = (self.small.control_height * ratio).floor();
|
||||
self.medium.control_height = medium_control_height;
|
||||
self.large.control_height = (self.large.control_height * ratio).floor();
|
||||
}
|
||||
|
||||
/// Sets the medium class's menu row height to the platform's stated value.
|
||||
pub fn set_menu_item_height(&mut self, medium_menu_item_height: Pixels) {
|
||||
let ratio = medium_menu_item_height / self.medium.menu_item_height;
|
||||
self.small.menu_item_height *= ratio;
|
||||
self.medium.menu_item_height = medium_menu_item_height;
|
||||
self.large.menu_item_height *= ratio;
|
||||
}
|
||||
|
||||
/// Sets the medium class's switch dimensions to the platform's stated values.
|
||||
pub fn set_switch_metrics(&mut self, track_height: Pixels, track_width: Pixels, knob: Pixels) {
|
||||
let ratio = track_height / self.medium.switch_height;
|
||||
for metrics in [&mut self.small, &mut self.large] {
|
||||
metrics.switch_height *= ratio;
|
||||
metrics.switch_width *= ratio;
|
||||
metrics.switch_knob *= ratio;
|
||||
}
|
||||
self.medium.switch_height = track_height;
|
||||
self.medium.switch_width = track_width;
|
||||
self.medium.switch_knob = knob;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,6 +526,8 @@ impl Theme {
|
||||
colors: resolved.colors,
|
||||
ramps: resolved.ramps,
|
||||
radius: resolved.radius,
|
||||
borders: resolved.borders,
|
||||
spacing: resolved.spacing,
|
||||
elevations: resolved.elevations,
|
||||
motion: resolved.motion,
|
||||
scrollbar: resolved.scrollbar,
|
||||
|
||||
Reference in New Issue
Block a user