Use shared theme text and controls throughout native dialogs

This commit is contained in:
Samuel Onoja committed 2026-09-30 02:46:08 +01:00
1 parent 29a71e9974
commit 46a6d08a83
6 files changed
+108 -82

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ prompt and screen-sharing/recording chooser.
- `Palette` resolves KDL colors and corners and builds the native toolkit theme. - `Palette` resolves KDL colors and corners and builds the native toolkit theme.
- `PRESETS` defines the six built-in color schemes. - `PRESETS` defines the six built-in color schemes.
- `font` and `text` share bounded font-name storage and explicit font selection. - `font` and `text` share bounded font-name storage and explicit font selection.
- `controls` supplies surfaces, navigation, buttons and input styles. - `controls` supplies surfaces, navigation, font-aware text buttons and input styles.
- `menus` supplies headings, rows, sections, separators, switches and slider styles. - `menus` supplies headings, rows, sections, separators, switches and slider styles.
- `calendar` supplies date/time labels, stacked clock digits and calendar grids. - `calendar` supplies date/time labels, stacked clock digits and calendar grids.
Callers supply the date and navigation controls. Callers supply the date and navigation controls.
+22
View File
@@ -13,6 +13,28 @@ pub fn button_style(p: Palette, selected: bool) -> theme::Button {
styled_button(p, selected, false) styled_button(p, selected, false)
} }
pub fn text_button<'a, M: Clone + 'a>(
label: impl Into<std::borrow::Cow<'a, str>> + 'a,
font: cosmic::font::Font,
palette: Palette,
selected: bool,
) -> button::Button<'a, M> {
let theme = cosmic::theme::active();
let native = theme.cosmic();
let content = widget::row![
crate::text(label, font)
.size(14)
.line_height(cosmic::iced::widget::text::LineHeight::Absolute(20.into())),
]
.height(native.space_l())
.padding([0, native.space_s()])
.align_y(cosmic::iced::Alignment::Center);
button::custom(content)
.padding(0)
.class(button_style(palette, selected))
}
pub fn navigation_style(p: Palette, selected: bool) -> theme::Button { pub fn navigation_style(p: Palette, selected: bool) -> theme::Button {
styled_button(p, selected, true) styled_button(p, selected, true)
} }
+12 -16
View File
@@ -44,7 +44,7 @@ struct Picker {
prompt: Prompt, prompt: Prompt,
selected: Vec<usize>, selected: Vec<usize>,
background: cosmic::iced::Color, background: cosmic::iced::Color,
foreground: cosmic::iced::Color, palette: ferese_theme::Palette,
font: cosmic::font::Font, font: cosmic::font::Font,
} }
@@ -64,7 +64,7 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
return Err("No shareable displays".into()); return Err("No shareable displays".into());
} }
let (theme, font, background, foreground) = appearance(); let (theme, font, background, palette) = appearance();
let height = 180. + (prompt.sources.len().min(4) as f32 * 56.); let height = 180. + (prompt.sources.len().min(4) as f32 * 56.);
cosmic::app::run::<Picker>( cosmic::app::run::<Picker>(
Settings::default() Settings::default()
@@ -75,7 +75,7 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
.default_font(font) .default_font(font)
.default_text_size(14.) .default_text_size(14.)
.is_daemon(false), .is_daemon(false),
(prompt, background, foreground, font), (prompt, background, palette, font),
)?; )?;
Ok(()) Ok(())
@@ -86,7 +86,7 @@ impl cosmic::Application for Picker {
type Flags = ( type Flags = (
Prompt, Prompt,
cosmic::iced::Color, cosmic::iced::Color,
cosmic::iced::Color, ferese_theme::Palette,
cosmic::font::Font, cosmic::font::Font,
); );
type Message = Message; type Message = Message;
@@ -102,7 +102,7 @@ impl cosmic::Application for Picker {
fn init( fn init(
mut core: Core, mut core: Core,
(prompt, background, foreground, font): Self::Flags, (prompt, background, palette, font): Self::Flags,
) -> (Self, Task<Message>) { ) -> (Self, Task<Message>) {
core.window.show_headerbar = false; core.window.show_headerbar = false;
core.window.border_padding = Some(0); core.window.border_padding = Some(0);
@@ -115,7 +115,7 @@ impl cosmic::Application for Picker {
prompt, prompt,
selected: Vec::new(), selected: Vec::new(),
background, background,
foreground, palette,
font, font,
}; };
let task = app let task = app
@@ -194,15 +194,11 @@ impl cosmic::Application for Picker {
} }
fn style(&self) -> Option<cosmic::iced::theme::Style> { fn style(&self) -> Option<cosmic::iced::theme::Style> {
Some(cosmic::iced::theme::Style { Some(self.palette.application_style(if self.material.is_some() {
background_color: if self.material.is_some() {
cosmic::iced::Color::TRANSPARENT cosmic::iced::Color::TRANSPARENT
} else { } else {
self.background self.background
}, }))
text_color: self.foreground,
icon_color: self.foreground,
})
} }
fn view(&self) -> Element<'_, Message> { fn view(&self) -> Element<'_, Message> {
@@ -265,7 +261,7 @@ impl cosmic::Application for Picker {
.class(if selected { .class(if selected {
ferese_theme::accent_button() ferese_theme::accent_button()
} else { } else {
cosmic::theme::Button::Standard ferese_theme::controls::navigation_style(self.palette, false)
}) })
.padding(8) .padding(8)
.width(Length::Fill) .width(Length::Fill)
@@ -304,7 +300,7 @@ impl cosmic::Application for Picker {
content = content.push( content = content.push(
row![ row![
button::custom(self.text("Cancel")) button::custom(self.text("Cancel"))
.class(cosmic::theme::Button::Text) .class(ferese_theme::controls::button_style(self.palette, false))
.on_press(Message::Cancel), .on_press(Message::Cancel),
share share
] ]
@@ -327,7 +323,7 @@ pub(crate) fn appearance() -> (
cosmic::Theme, cosmic::Theme,
cosmic::font::Font, cosmic::font::Font,
cosmic::iced::Color, cosmic::iced::Color,
cosmic::iced::Color, ferese_theme::Palette,
) { ) {
let document = ferese_config::config_path() let document = ferese_config::config_path()
.and_then(|path| std::fs::read_to_string(path).ok()) .and_then(|path| std::fs::read_to_string(path).ok())
@@ -345,6 +341,6 @@ pub(crate) fn appearance() -> (
a: ferese_theme::material_opacity(document.as_ref()), a: ferese_theme::material_opacity(document.as_ref()),
..palette.sidebar ..palette.sidebar
}, },
palette.text, palette,
) )
} }
+23 -29
View File
@@ -2,9 +2,9 @@ use crate::PromptEvent;
use cosmic::{ use cosmic::{
Element, Element,
app::{Core, Settings, Task}, app::{Core, Settings, Task},
iced::{Alignment, Background, Border, Color, Length, Size, Subscription, window}, iced::{Alignment, Color, Length, Size, Subscription, window},
theme, theme,
widget::{self, button, column, container, row, text}, widget::{self, button, column, container, row},
}; };
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
@@ -198,15 +198,15 @@ impl cosmic::Application for Prompt {
} }
fn style(&self) -> Option<cosmic::iced::theme::Style> { fn style(&self) -> Option<cosmic::iced::theme::Style> {
Some(cosmic::iced::theme::Style { Some(
background_color: if self.material.is_some() { self.appearance
.palette()
.application_style(if self.material.is_some() {
cosmic::iced::Color::TRANSPARENT cosmic::iced::Color::TRANSPARENT
} else { } else {
self.appearance.surface self.appearance.surface
}, }),
text_color: self.appearance.text, )
icon_color: self.appearance.text,
})
} }
fn init( fn init(
@@ -334,7 +334,7 @@ impl cosmic::Application for Prompt {
Message::Submit Message::Submit
}); });
} }
let action = button::custom(text("Authenticate").font(palette.font).size(13)) let action = button::custom(ferese_theme::text("Authenticate", palette.font).size(13))
.class(ferese_theme::accent_button()) .class(ferese_theme::accent_button())
.height(Length::Fixed(36.)) .height(Length::Fixed(36.))
.padding([8, 16]) .padding([8, 16])
@@ -346,20 +346,13 @@ impl cosmic::Application for Prompt {
.height(40) .height(40)
.center_x(40) .center_x(40)
.center_y(40) .center_y(40)
.class(theme::Container::custom(move |_| { .class(ferese_theme::controls::surface(
widget::container::Style { palette.accent.scale_alpha(0.13),
background: Some(Background::Color(palette.accent.scale_alpha(0.13))), 12.,
border: Border { )),
radius: 12.0.into(),
..Default::default()
},
..Default::default()
}
})),
column![ column![
text("Authentication required").font(palette.font).size(18), ferese_theme::text("Authentication required", palette.font).size(18),
text(format!("Confirm as {}", self.user)) ferese_theme::text(format!("Confirm as {}", self.user), palette.font)
.font(palette.font)
.size(12) .size(12)
.class(theme::Text::Color(palette.muted)), .class(theme::Text::Color(palette.muted)),
] ]
@@ -369,30 +362,31 @@ impl cosmic::Application for Prompt {
.align_y(Alignment::Center); .align_y(Alignment::Center);
let mut body = column![ let mut body = column![
heading, heading,
text(&self.description).font(palette.font).size(13), ferese_theme::text(&self.description, palette.font).size(13),
input input
] ]
.spacing(14) .spacing(14)
.width(Length::Fill); .width(Length::Fill);
if let Some(error) = &self.error { if let Some(error) = &self.error {
body = body.push( body = body.push(
text(error) ferese_theme::text(error, palette.font)
.font(palette.font)
.size(12) .size(12)
.class(theme::Text::Color(Color::from_rgb8(235, 98, 98))), .class(theme::Text::Color(Color::from_rgb8(235, 98, 98))),
); );
} else if let Some(info) = &self.info { } else if let Some(info) = &self.info {
body = body.push( body = body.push(
text(info) ferese_theme::text(info, palette.font)
.font(palette.font)
.size(12) .size(12)
.class(theme::Text::Color(palette.muted)), .class(theme::Text::Color(palette.muted)),
); );
} }
body = body.push( body = body.push(
row![ row![
button::custom(text("Cancel").font(palette.font).size(13)) button::custom(ferese_theme::text("Cancel", palette.font).size(13))
.class(theme::Button::Text) .class(ferese_theme::controls::button_style(
palette.palette(),
false
))
.padding([8, 14]) .padding([8, 14])
.on_press(Message::Cancel), .on_press(Message::Cancel),
action action
+15 -16
View File
@@ -1514,12 +1514,14 @@ impl FereseShell {
.align_x(alignment); .align_x(alignment);
if note.interactive { if note.interactive {
let title = cosmic::widget::text(if note.title.is_empty() { let title = ferese_theme::text(
if note.title.is_empty() {
"⋮⋮" "⋮⋮"
} else { } else {
&note.title &note.title
}) },
.font(font) font,
)
.size(note.title_size) .size(note.title_size)
.class(theme::Text::Color(foreground)); .class(theme::Text::Color(foreground));
let header = cosmic::widget::mouse_area(container(title).width(Length::Fill)) let header = cosmic::widget::mouse_area(container(title).width(Length::Fill))
@@ -1549,11 +1551,13 @@ impl FereseShell {
); );
} else if !note.title.is_empty() { } else if !note.title.is_empty() {
body = body.push( body = body.push(
cosmic::widget::text(note.title.clone()) ferese_theme::text(
.font(cosmic::font::Font { note.title.clone(),
cosmic::font::Font {
weight: cosmic::iced::font::Weight::Semibold, weight: cosmic::iced::font::Weight::Semibold,
..font ..font
}) },
)
.size(note.title_size) .size(note.title_size)
.width(Length::Fill) .width(Length::Fill)
.align_x(alignment) .align_x(alignment)
@@ -1582,8 +1586,7 @@ impl FereseShell {
); );
} else { } else {
body = body.push( body = body.push(
cosmic::widget::text(note.text.clone()) ferese_theme::text(note.text.clone(), font)
.font(font)
.size(note.text_size) .size(note.text_size)
.width(Length::Fill) .width(Length::Fill)
.align_x(alignment) .align_x(alignment)
@@ -1747,8 +1750,7 @@ impl FereseShell {
if pixel && clock.show_date { if pixel && clock.show_date {
labels = labels.push( labels = labels.push(
cosmic::widget::text(self.desktop_clock.1.clone()) ferese_theme::text(self.desktop_clock.1.clone(), date_font)
.font(date_font)
.size(clock.date_size) .size(clock.date_size)
.class(theme::Text::Color(tint( .class(theme::Text::Color(tint(
&clock.date_color, &clock.date_color,
@@ -1780,8 +1782,7 @@ impl FereseShell {
for (position, digit) in digits.chars().enumerate() { for (position, digit) in digits.chars().enumerate() {
digit_row = digit_row.push( digit_row = digit_row.push(
cosmic::widget::text(digit.to_string()) ferese_theme::text(digit.to_string(), font)
.font(font)
.size(size) .size(size)
.line_height(cosmic::iced::widget::text::LineHeight::Relative(0.8)) .line_height(cosmic::iced::widget::text::LineHeight::Relative(0.8))
.class(theme::Text::Color(digit_colors[(line + position) % 2])), .class(theme::Text::Color(digit_colors[(line + position) % 2])),
@@ -1809,8 +1810,7 @@ impl FereseShell {
.min(available_height / 1.3); .min(available_height / 1.3);
labels = labels.push( labels = labels.push(
cosmic::widget::text(self.desktop_clock.0.clone()) ferese_theme::text(self.desktop_clock.0.clone(), font)
.font(font)
.size(size) .size(size)
.width(Length::Fill) .width(Length::Fill)
.align_x(alignment) .align_x(alignment)
@@ -1820,8 +1820,7 @@ impl FereseShell {
if !pixel && clock.show_date { if !pixel && clock.show_date {
labels = labels.push( labels = labels.push(
cosmic::widget::text(self.desktop_clock.1.clone()) ferese_theme::text(self.desktop_clock.1.clone(), font)
.font(font)
.size(clock.date_size) .size(clock.date_size)
.width(Length::Fill) .width(Length::Fill)
.align_x(alignment) .align_x(alignment)
+35 -20
View File
@@ -1,6 +1,6 @@
use super::*; use super::*;
use cosmic::iced::widget::Space; use cosmic::iced::widget::Space;
use cosmic::widget::{column, text}; use cosmic::widget::column;
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum PowerAction { pub(super) enum PowerAction {
@@ -436,9 +436,8 @@ impl FereseShell {
let rows = match &modal.content { let rows = match &modal.content {
Content::Power(action) => { Content::Power(action) => {
let mut rows = column![ let mut rows = column![
text(action.title()).font(shell_font()).size(23), text(action.title()).size(23),
text(action.description()) text(action.description())
.font(shell_font())
.size(14) .size(14)
.class(theme::Text::Color(palette.muted)), .class(theme::Text::Color(palette.muted)),
] ]
@@ -448,13 +447,12 @@ impl FereseShell {
{ {
rows = rows.push( rows = rows.push(
text("Applications requested that this action be prevented:") text("Applications requested that this action be prevented:")
.font(shell_font())
.size(13) .size(13)
.class(theme::Text::Color(palette.muted)), .class(theme::Text::Color(palette.muted)),
); );
let items = inhibitors.reasons.iter().fold( let items = inhibitors.reasons.iter().fold(
column::with_capacity(inhibitors.reasons.len()).spacing(6), column::with_capacity(inhibitors.reasons.len()).spacing(6),
|rows, reason| rows.push(text(reason).font(shell_font()).size(13)), |rows, reason| rows.push(text(reason).size(13)),
); );
rows = rows.push( rows = rows.push(
container(cosmic::widget::scrollable(items).height(Length::Shrink)) container(cosmic::widget::scrollable(items).height(Length::Shrink))
@@ -476,11 +474,14 @@ impl FereseShell {
rows.push( rows.push(
row![ row![
Space::new().width(Length::Fill), Space::new().width(Length::Fill),
button::text("Cancel") ferese_theme::controls::text_button(
.class(ferese_theme::controls::button_style(palette, false)) "Cancel",
shell_font(),
palette,
false
)
.on_press(cosmic::Action::App(Message::CancelPower)), .on_press(cosmic::Action::App(Message::CancelPower)),
button::text(label) ferese_theme::controls::text_button(label, shell_font(), palette, true)
.class(ferese_theme::controls::button_style(palette, true))
.on_press_maybe( .on_press_maybe(
modal modal
.inhibitors .inhibitors
@@ -496,12 +497,8 @@ impl FereseShell {
for entry in entries { for entry in entries {
bindings = bindings.push( bindings = bindings.push(
row![ row![
text(&entry.keys) text(&entry.keys).size(13).width(Length::FillPortion(1)),
.font(shell_font())
.size(13)
.width(Length::FillPortion(1)),
text(&entry.description) text(&entry.description)
.font(shell_font())
.size(13) .size(13)
.width(Length::FillPortion(1)), .width(Length::FillPortion(1)),
] ]
@@ -518,12 +515,30 @@ impl FereseShell {
.saturating_sub(360) .saturating_sub(360)
.clamp(40, 400) as f32; .clamp(40, 400) as f32;
column![ column![
text("Welcome to Ferese").font(shell_font()).size(23), text("Welcome to Ferese").size(23),
text("Your active shortcuts").font(shell_font()).size(14).class(theme::Text::Color(palette.muted)), ferese_theme::menus::section_label(
container(cosmic::widget::scrollable(bindings).height(Length::Shrink)).max_height(height), "Your active shortcuts",
text("Disable this guide in Settings → Shortcuts. It appears at each login until disabled.").font(shell_font()).size(12).class(theme::Text::Color(palette.muted)), shell_font(),
row![Space::new().width(Length::Fill), button::text("Got it").class(ferese_theme::controls::button_style(palette, true)).on_press(cosmic::Action::App(Message::CancelPower))], palette.muted,
].spacing(14) )
.size(14),
container(cosmic::widget::scrollable(bindings).height(Length::Shrink))
.max_height(height),
text("Disable this guide in Settings → Shortcuts. It appears at each login until disabled.")
.size(12)
.class(theme::Text::Color(palette.muted)),
row![
Space::new().width(Length::Fill),
ferese_theme::controls::text_button(
"Got it",
shell_font(),
palette,
true,
)
.on_press(cosmic::Action::App(Message::CancelPower)),
],
]
.spacing(14)
} }
}; };
container(rows) container(rows)