M7: make brand accents legible and fix home tests

This commit is contained in:
YarilaFox
2026-10-19 20:51:47 +05:00
parent 4b12a82839
commit 5a4b7c2795
18 changed files with 66 additions and 59 deletions
+1
View File
@@ -25,6 +25,7 @@ jobs:
app-name: figcraft
app-title: FigCraft
craft-fonts-ref: 43913056ce82a3fdad0ef69f6b88d1dc922a8104
web-craft-fonts: true
has-server: true
version: ${{ inputs.version }}
secrets:
+2 -2
View File
@@ -65,8 +65,8 @@ fn craft_fonts(dir: &std::path::Path, manifest_rel: &str) -> Result<String, Stri
if cjk && std::env::var_os("FIGCRAFT_EMBED_CJK").is_none() {
continue;
}
// Web builds have a size budget: UI fonts, the FigCraft wordmark, and optionally CJK.
if wasm && *family != "Inter" && *family != "Archivo" && !cjk {
// Web builds have a size budget: UI fonts, only the SemiBold wordmark, and optionally CJK.
if wasm && *family != "Inter" && !(*family == "Archivo" && *style == "SemiBold") && !cjk {
continue;
}
let path = dir.join(file).canonicalize().map_err(|e| format!("{file}: {e}"))?;
+1 -1
View File
@@ -316,7 +316,7 @@ fn search_row(app: &mut FigApp, ui: &mut Ui, w: f32) -> String {
);
crate::widgets::select_all_on_focus(ui, &r, &filter);
if r.has_focus() {
ui.painter().rect_stroke(field, CornerRadius::same(5), Stroke::new(1.0, t.accent), egui::StrokeKind::Inside);
ui.painter().rect_stroke(field, CornerRadius::same(5), Stroke::new(1.0, crate::theme::ACCENT), egui::StrokeKind::Inside);
if ui.input(|i| i.key_pressed(egui::Key::Escape)) {
filter.clear();
}
+5 -4
View File
@@ -189,10 +189,10 @@ pub fn cluster(points: &[Pos2], r: f32) -> Vec<Vec<usize>> {
}
/// A message's text with its @mentions of `people` picked out, wrapped at `width`.
pub fn rich_text(text: &str, people: &[&str], color: Color32, width: f32) -> LayoutJob {
pub fn rich_text(text: &str, people: &[&str], color: Color32, mention_color: Color32, width: f32) -> LayoutJob {
let mut job = LayoutJob::default();
let plain = TextFormat { font_id: regular(12.0), color, ..Default::default() };
let mention = TextFormat { font_id: semibold(12.0), color: ACCENT, ..Default::default() };
let mention = TextFormat { font_id: semibold(12.0), color: mention_color, ..Default::default() };
let mut at = 0;
for r in mention_ranges(text, people) {
job.append(text.get(at..r.start).unwrap_or(""), 0.0, plain.clone());
@@ -729,7 +729,7 @@ fn message(
ui.add_space(indent);
let mut names: Vec<&str> = cx.people.iter().map(String::as_str).collect();
names.push(cx.me);
ui.add(egui::Label::new(rich_text(&m.text, &names, t.text, ui.available_width())).wrap());
ui.add(egui::Label::new(rich_text(&m.text, &names, t.text, t.accent_text, ui.available_width())).wrap());
});
}
}
@@ -1062,7 +1062,8 @@ pub fn panel(app: &mut FigApp, ui: &mut Ui) {
ui.add_space(16.0);
ui.label(egui::RichText::new(tr(app.ui.comments.filter.label())).font(regular(11.0)).color(t.text_secondary));
ui.add_space(4.0);
if ui.add(egui::Label::new(egui::RichText::new(tr("Show open")).font(regular(11.0)).color(ACCENT)).sense(Sense::click())).clicked() {
if ui.add(egui::Label::new(egui::RichText::new(tr("Show open")).font(regular(11.0)).color(t.accent_text)).sense(Sense::click())).clicked()
{
app.ui.comments.filter = Filter::Open;
}
});
+1 -1
View File
@@ -628,7 +628,7 @@ pub fn dev_resources_section(app: &mut FigApp, ui: &mut Ui, doc: &Document, id:
}
icons::paint(ui.painter(), Rect::from_center_size(pos2(r.min.x + PAD + 7.0, r.center().y), vec2(14.0, 14.0)), Icon::Link, t.icon_secondary);
let x = r.min.x + PAD + 22.0;
ui.painter().text(pos2(x, r.center().y - 7.0), Align2::LEFT_CENTER, widgets::elide(ui, name, text_w), semibold(11.0), ACCENT);
ui.painter().text(pos2(x, r.center().y - 7.0), Align2::LEFT_CENTER, widgets::elide(ui, name, text_w), semibold(11.0), t.accent_text);
let below = match item.from.and_then(|f| doc.node(f)) {
Some(m) => trf("From {name}", &[("name", &m.name)]),
None => url.clone(),
+1 -1
View File
@@ -324,7 +324,7 @@ fn action_card(ui: &mut Ui, t: &Tokens, icon: Icon, title: &str, sub: &str) -> b
}
card_frame(ui, t, r, &resp);
let ir = Rect::from_min_size(pos2(r.min.x + 16.0, r.center().y - 16.0), vec2(32.0, 32.0));
ui.painter().rect_filled(ir, CornerRadius::same(6), ACCENT);
ui.painter().rect_filled(ir, CornerRadius::same(6), t.accent);
icons::paint(ui.painter(), ir.shrink(8.0), icon, t.accent_on);
ui.painter().text(pos2(r.min.x + 60.0, r.center().y - 8.0), Align2::LEFT_CENTER, title_shown, semibold(12.0), t.text);
ui.painter().text(pos2(r.min.x + 60.0, r.center().y + 9.0), Align2::LEFT_CENTER, sub_shown, regular(11.0), t.text_secondary);
+1 -1
View File
@@ -738,7 +738,7 @@ fn file_icon(ui: &Ui, t: &Tokens, center: egui::Pos2, path: &str) {
let r = Rect::from_center_size(center, vec2(16.0, 16.0));
match FileKind::of(Path::new(path)) {
FileKind::FigCraft | FileKind::Fig => {
ui.painter().rect_filled(r, CornerRadius::same(4), ACCENT);
ui.painter().rect_filled(r, CornerRadius::same(4), t.accent);
icons::paint(ui.painter(), r.shrink(3.0), Icon::Logo, t.accent_on);
}
kind => {
+4 -2
View File
@@ -256,9 +256,11 @@ fn rects_of(s: &[Shape], c: egui::Color32) -> usize {
s.iter().filter(|s| matches!(s, Shape::Rect(r) if r.fill == c)).count()
}
/// Images drawn (meshes with a texture of their own).
/// Preview images in the main content area, excluding the branded sidebar icon.
fn images(s: &[Shape]) -> usize {
s.iter().filter(|s| matches!(s, Shape::Mesh(m) if m.texture_id != egui::TextureId::default())).count()
s.iter()
.filter(|s| matches!(s, Shape::Mesh(m) if m.texture_id != egui::TextureId::default() && m.vertices.iter().any(|v| v.pos.x > 240.0)))
.count()
}
#[test]
+2 -2
View File
@@ -332,7 +332,7 @@ fn pages_edge(app: &mut FigApp, ui: &mut Ui, shown: f32) {
if active {
ui.ctx().set_cursor_icon(egui::CursorIcon::ResizeVertical);
}
let (width, colour) = if active { (2.0, t.accent) } else { (1.0, t.border) };
let (width, colour) = if active { (2.0, ACCENT) } else { (1.0, t.border) };
ui.painter().line_segment([line.left_center(), line.right_center()], Stroke::new(width, colour));
let asked = if resp.double_clicked() {
Some(None)
@@ -642,7 +642,7 @@ fn search_field(app: &mut FigApp, ui: &mut Ui, t: &Tokens, w: f32, id: Id) {
);
crate::widgets::select_all_on_focus(ui, &r, &app.ui.layer_filter);
if r.has_focus() {
ui.painter().rect_stroke(field, CornerRadius::same(5), Stroke::new(1.0, t.accent), egui::StrokeKind::Inside);
ui.painter().rect_stroke(field, CornerRadius::same(5), Stroke::new(1.0, ACCENT), egui::StrokeKind::Inside);
}
if (r.has_focus() || r.lost_focus()) && ui.input(|i| i.key_pressed(egui::Key::Escape)) {
app.ui.layer_search = false;
+3 -3
View File
@@ -1032,7 +1032,7 @@ impl FigApp {
let resp = ui.interact(rect, id, egui::Sense::click_and_drag());
if resp.hovered() || resp.dragged() {
ui.ctx().set_cursor_icon(egui::CursorIcon::ResizeHorizontal);
ui.painter().vline(x, rows, egui::Stroke::new(2.0, theme::Tokens::get(ui.ctx()).accent));
ui.painter().vline(x, rows, egui::Stroke::new(2.0, theme::ACCENT));
}
if resp.double_clicked() {
return Some(PANEL_DEFAULT);
@@ -1716,11 +1716,11 @@ pub(crate) fn drop_overlay(ctx: &egui::Context, rect: egui::Rect, label: &str) {
let painter = ctx.layer_painter(egui::LayerId::new(egui::Order::Foreground, egui::Id::new("drop_overlay")));
let area = rect.shrink(4.0);
painter.rect_filled(area, egui::CornerRadius::same(8), t.accent.gamma_multiply(0.12));
painter.rect_stroke(area, egui::CornerRadius::same(8), egui::Stroke::new(2.0, t.accent), egui::StrokeKind::Inside);
painter.rect_stroke(area, egui::CornerRadius::same(8), egui::Stroke::new(2.0, theme::ACCENT), egui::StrokeKind::Inside);
let galley = painter.layout_no_wrap(label.to_owned(), theme::semibold(14.0), t.text);
let pill = egui::Rect::from_center_size(area.center(), galley.size() + egui::vec2(32.0, 16.0));
painter.rect_filled(pill, egui::CornerRadius::same(8), t.panel);
painter.rect_stroke(pill, egui::CornerRadius::same(8), egui::Stroke::new(1.0, t.accent), egui::StrokeKind::Inside);
painter.rect_stroke(pill, egui::CornerRadius::same(8), egui::Stroke::new(1.0, theme::ACCENT), egui::StrokeKind::Inside);
painter.galley(pill.center() - galley.size() / 2.0, galley, t.text);
// Hovering sends no pointer events on every platform: keep the overlay current.
ctx.request_repaint();
+1 -1
View File
@@ -2223,7 +2223,7 @@ fn top_bar(p: &mut Presenter, ui: &mut Ui, bar: Rect, now: f64, chrome: Chrome)
}
let on = (*act == BarAction::Comments && p.view.comments) || (*act == BarAction::Inspect && p.view.inspect);
if on {
ui.painter().rect_filled(br, CornerRadius::same(5), ACCENT);
ui.painter().rect_filled(br, CornerRadius::same(5), t.accent);
} else if resp.hovered() {
ui.painter().rect_filled(br, CornerRadius::same(5), hover);
}
+1 -1
View File
@@ -763,7 +763,7 @@ fn trigger_rows(app: &mut FigApp, ui: &mut Ui, node: NodeId, k: usize, it: &Inte
let id = capture_id().with("field");
ui.painter().rect_filled(r, CornerRadius::same(5), t.field);
if cap {
ui.painter().rect_stroke(r, CornerRadius::same(5), Stroke::new(1.0, t.accent), StrokeKind::Inside);
ui.painter().rect_stroke(r, CornerRadius::same(5), Stroke::new(1.0, ACCENT), StrokeKind::Inside);
ui.memory_mut(|m| m.request_focus(id));
let _ = ui.interact(r, id, Sense::focusable_noninteractive());
let pressed = ui.input(|i| {
+4 -4
View File
@@ -11,7 +11,7 @@ use crate::i18n::{tr, trf, trn};
use crate::icons::{self, Icon};
use crate::list_drag::{ListDrag, move_flags, remove_flags};
use crate::style_picker::{self, StyleSlot};
use crate::theme::{ACCENT, Tokens, regular, semibold};
use crate::theme::{Tokens, regular, semibold};
use crate::widgets::{self, Edit, FIELD_H, FieldEdit, Lead, PAD};
use crate::{FigApp, RightTab};
@@ -88,7 +88,7 @@ pub fn right_panel(app: &mut FigApp, ui: &mut Ui) {
let sw = (label.size().x + 24.0).max(56.0);
let share = Rect::from_min_size(pos2(top.max.x - 14.0 - sw, top.center().y - 16.0), vec2(sw, 32.0));
let sresp = ui.interact(share, ui.id().with("share"), Sense::click()).tip(tr("Share: live session, export"));
ui.painter().rect_filled(share, CornerRadius::same(6), if sresp.hovered() { t.accent_hover } else { ACCENT });
ui.painter().rect_filled(share, CornerRadius::same(6), if sresp.hovered() { t.accent_hover } else { t.accent });
ui.painter().galley(share.center() - label.size() / 2.0, label, t.accent_on);
crate::live::share_popover(app, &sresp);
// Play presents; its chevron opens the play menu (present, or preview in a pane).
@@ -286,11 +286,11 @@ pub fn menu_row(ui: &mut Ui, label: &str, shortcut: &str, art_w: f32, art: impl
if hovered {
ui.painter().rect_filled(r, CornerRadius::same(5), t.menu_hover);
}
let col = if hovered { Color32::WHITE } else { t.text };
let col = t.menu_text;
ui.painter().galley(pos2(r.min.x + MENU_PAD, r.center().y - text.size().y / 2.0), text, col);
if let Some(k) = keys {
let at = pos2(r.max.x - MENU_PAD - k.size().x, r.center().y - k.size().y / 2.0);
ui.painter().galley(at, k, if hovered { Color32::WHITE } else { t.text_secondary });
ui.painter().galley(at, k, if hovered { t.menu_text } else { t.menu_dim });
}
art(ui.painter(), r, col);
resp
+1 -1
View File
@@ -482,7 +482,7 @@ fn style_grid(ui: &mut Ui, list: &[(&Style, Key)], applied: Option<&Key>, editab
None => preview(ui, r, s, StyleSlot::Fill),
}
if applied == Some(key) {
ui.painter().rect_stroke(r.expand(2.0), CornerRadius::same(5), Stroke::new(2.0, t.accent), egui::StrokeKind::Inside);
ui.painter().rect_stroke(r.expand(2.0), CornerRadius::same(5), Stroke::new(2.0, crate::theme::ACCENT), egui::StrokeKind::Inside);
} else if resp.hovered() && !text {
ui.painter().rect_stroke(r.expand(2.0), CornerRadius::same(4), Stroke::new(1.0, t.menu_text), egui::StrokeKind::Inside);
}
+22 -19
View File
@@ -45,14 +45,17 @@ pub struct Tokens {
pub focus: Color32,
}
/// FigCraft's brand green, shared with the original app icon.
pub const ACCENT: Color32 = Color32::from_rgb(0x02, 0xDA, 0x96);
/// FigCraft's brand green for solid surfaces.
pub const BRAND: Color32 = Color32::from_rgb(0x02, 0xDA, 0x96);
/// Contrast-safe green for thin selection outlines and white-on-green labels.
/// It reaches 4.5:1 on white and 3:1 on the dark canvas.
pub const ACCENT: Color32 = Color32::from_rgb(0x00, 0x87, 0x5F);
/// Ink on the bright green brand surface (white would not have enough contrast).
pub const ACCENT_ON: Color32 = Color32::from_rgb(0x07, 0x35, 0x2A);
pub const COMPONENT: Color32 = Color32::from_rgb(0x97, 0x47, 0xFF);
/// Handoff status badges (white text on these, in both themes).
pub const DEV_READY: Color32 = Color32::from_rgb(0x14, 0xAE, 0x5C);
pub const DEV_CHANGED: Color32 = Color32::from_rgb(0xD9, 0x7A, 0x06);
pub const DEV_READY: Color32 = Color32::from_rgb(0x08, 0x7D, 0x4F);
pub const DEV_CHANGED: Color32 = Color32::from_rgb(0xA7, 0x5B, 0x00);
pub const DEV_COMPLETED: Color32 = Color32::from_rgb(0x6E, 0x6E, 0x73);
impl Tokens {
@@ -74,7 +77,7 @@ impl Tokens {
pressed: Color32::from_rgb(0xE6, 0xE6, 0xE6),
field: Color32::from_rgb(0xF5, 0xF5, 0xF5),
field_hover_border: Color32::from_rgb(0xE6, 0xE6, 0xE6),
accent: ACCENT,
accent: BRAND,
accent_hover: Color32::from_rgb(0x00, 0xAD, 0x78),
accent_on: ACCENT_ON,
// Darker green keeps links and labels legible on white and selected rows.
@@ -84,7 +87,7 @@ impl Tokens {
component: COMPONENT,
component_row: Color32::from_rgb(0xF1, 0xE9, 0xFF),
danger: Color32::from_rgb(0xF2, 0x48, 0x22),
success: Color32::from_rgb(0x14, 0xAE, 0x5C),
success: DEV_READY,
warning: Color32::from_rgb(0xFF, 0xCD, 0x29),
guide: Color32::from_rgb(0xF2, 0x48, 0x22),
tab_bar: Color32::from_rgb(0xE8, 0xE8, 0xE8),
@@ -92,7 +95,7 @@ impl Tokens {
shadow: Color32::from_black_alpha(40),
menu: Color32::from_rgb(0x1E, 0x1E, 0x1E),
menu_text: Color32::from_rgb(0xFF, 0xFF, 0xFF),
menu_hover: Color32::from_rgb(0x00, 0x6B, 0x4C),
menu_hover: ACCENT,
menu_dim: Color32::from_rgb(0x9A, 0x9A, 0x9A),
focus: Color32::from_rgb(0x00, 0x7A, 0x56),
}
@@ -115,7 +118,7 @@ impl Tokens {
pressed: Color32::from_rgb(0x44, 0x44, 0x44),
field: Color32::from_rgb(0x38, 0x38, 0x38),
field_hover_border: Color32::from_rgb(0x4D, 0x4D, 0x4D),
accent: ACCENT,
accent: BRAND,
accent_hover: Color32::from_rgb(0x52, 0xE9, 0xB7),
accent_on: ACCENT_ON,
accent_text: Color32::from_rgb(0x52, 0xE9, 0xB7),
@@ -124,7 +127,7 @@ impl Tokens {
component: Color32::from_rgb(0xD2, 0x7C, 0xFF),
component_row: Color32::from_rgb(0x3E, 0x30, 0x52),
danger: Color32::from_rgb(0xF2, 0x48, 0x22),
success: Color32::from_rgb(0x14, 0xAE, 0x5C),
success: DEV_READY,
warning: Color32::from_rgb(0xFF, 0xCD, 0x29),
guide: Color32::from_rgb(0xF2, 0x48, 0x22),
tab_bar: Color32::from_rgb(0x1E, 0x1E, 0x1E),
@@ -132,9 +135,9 @@ impl Tokens {
shadow: Color32::from_black_alpha(90),
menu: Color32::from_rgb(0x1E, 0x1E, 0x1E),
menu_text: Color32::from_rgb(0xFF, 0xFF, 0xFF),
menu_hover: Color32::from_rgb(0x00, 0x6B, 0x4C),
menu_hover: ACCENT,
menu_dim: Color32::from_rgb(0x9A, 0x9A, 0x9A),
focus: ACCENT,
focus: BRAND,
}
}
@@ -192,7 +195,7 @@ fn visuals(t: Tokens) -> Visuals {
v.window_corner_radius = egui::CornerRadius::same(13);
v.menu_corner_radius = egui::CornerRadius::same(13);
v.selection.bg_fill = t.accent.gamma_multiply(0.3);
v.selection.stroke = Stroke::new(1.0, t.accent);
v.selection.stroke = Stroke::new(1.0, ACCENT);
v.hyperlink_color = t.accent_text;
for w in [&mut v.widgets.inactive, &mut v.widgets.hovered, &mut v.widgets.active, &mut v.widgets.open, &mut v.widgets.noninteractive] {
w.corner_radius = egui::CornerRadius::same(5);
@@ -208,10 +211,10 @@ fn visuals(t: Tokens) -> Visuals {
v.widgets.hovered.bg_stroke = Stroke::new(1.0, t.field_hover_border);
v.widgets.active.bg_fill = t.pressed;
v.widgets.active.weak_bg_fill = t.pressed;
v.widgets.active.bg_stroke = Stroke::new(1.0, t.accent);
v.widgets.active.bg_stroke = Stroke::new(1.0, ACCENT);
v.popup_shadow = egui::Shadow { offset: [0, 4], blur: 16, spread: 0, color: t.shadow };
v.window_shadow = egui::Shadow { offset: [0, 8], blur: 24, spread: 0, color: t.shadow };
v.text_cursor.stroke = Stroke::new(1.0, t.accent);
v.text_cursor.stroke = Stroke::new(1.0, ACCENT);
v
}
@@ -261,9 +264,9 @@ pub fn install_fonts(ctx: &Context, system: bool, cjk: u8) {
fonts.families.insert(FontFamily::Name("semibold".into()), semi);
// Keep the logo's typeface independent of UI text. System Archivo is used when available;
// releases with craft-fonts embed it so the wordmark does not depend on installation.
let archivo = find("Archivo", "SemiBold")
.map(FontData::from_static)
.or_else(|| system.then(|| figcraft_text::find_face("Archivo", "SemiBold")).flatten().map(|face| font_data(&face)));
let archivo = find("Archivo", "SemiBold").map(FontData::from_static).or_else(|| {
system.then(|| figcraft_text::find_face("Archivo", "SemiBold")).flatten().filter(|face| face.family == "Archivo").map(|face| font_data(&face))
});
let mut brand = Vec::new();
if let Some(data) = archivo {
fonts.font_data.insert("archivo".into(), Arc::new(data));
@@ -368,7 +371,7 @@ pub fn paint_wordmark(painter: &egui::Painter, left_center: egui::Pos2, size: f3
let fig = painter.layout_no_wrap("Fig".into(), font.clone(), t.text);
let fig_width = fig.size().x;
painter.galley(egui::pos2(left_center.x, left_center.y - fig.size().y / 2.0), fig, t.text);
painter.text(egui::pos2(left_center.x + fig_width, left_center.y), egui::Align2::LEFT_CENTER, "Craft", font, t.accent);
painter.text(egui::pos2(left_center.x + fig_width, left_center.y), egui::Align2::LEFT_CENTER, "Craft", font, t.accent_text);
}
/// Paint the owner's original chameleon icon from the existing app asset.
@@ -379,7 +382,7 @@ pub fn paint_app_icon(ui: &egui::Ui, rect: egui::Rect) {
Some(egui::ColorImage::from_rgba_unmultiplied([rgba.width() as usize, rgba.height() as usize], rgba.as_raw()))
});
let Some(image) = image else {
ui.painter().rect_filled(rect, egui::CornerRadius::same(5), ACCENT);
ui.painter().rect_filled(rect, egui::CornerRadius::same(5), BRAND);
crate::icons::paint(ui.painter(), rect.shrink(rect.width() * 0.22), crate::icons::Icon::Logo, ACCENT_ON);
return;
};
+4 -4
View File
@@ -9,7 +9,7 @@ use crate::FigApp;
use crate::a11y::{self, Nav, Region, Tip};
use crate::i18n::{tr, tr_noop, trf};
use crate::icons::{self, Icon};
use crate::theme::{ACCENT, Tokens, regular};
use crate::theme::{Tokens, regular};
struct Group {
key: &'static str,
@@ -145,7 +145,7 @@ fn main_toolbar(app: &mut FigApp, ui: &mut Ui, canvas: Rect, t: &Tokens) {
// The Actions button reads on while its panel is open; clicking it again closes it.
let actions_open = id == "actions" && app.ui.palette.is_some();
if actions_open {
ui.painter().rect_filled(r, CornerRadius::same(5), ACCENT);
ui.painter().rect_filled(r, CornerRadius::same(5), t.accent);
} else if resp.hovered() {
ui.painter().rect_filled(r, CornerRadius::same(5), t.hover);
}
@@ -372,7 +372,7 @@ fn tool_cell(ui: &mut Ui, t: &Tokens, r: Rect, id: impl egui::AsIdSalt, icon: Ic
});
a11y::toggle(&resp, tip, active);
let bg = if active {
ACCENT
t.accent
} else if resp.hovered() {
t.hover
} else {
@@ -395,7 +395,7 @@ fn done_button(ui: &mut Ui, t: &Tokens, x: f32, cy: f32, tip: &str) -> bool {
divider(ui, t, x, cy);
let done = Rect::from_min_size(pos2(x + 12.0, cy - 14.0), vec2(DONE_W, 28.0));
let resp = ui.interact(done, ui.id().with("tool_done"), Sense::click()).tip(tip);
ui.painter().rect_filled(done, CornerRadius::same(6), if resp.hovered() { t.accent_hover } else { ACCENT });
ui.painter().rect_filled(done, CornerRadius::same(6), if resp.hovered() { t.accent_hover } else { t.accent });
ui.painter().text(done.center(), Align2::CENTER_CENTER, tr("Done"), crate::theme::semibold(11.5), t.accent_on);
resp.clicked()
}
+7 -7
View File
@@ -587,7 +587,7 @@ fn decoration_details(app: &mut FigApp, ui: &mut Ui, styles: &[TextStyle], apply
if !auto
&& ui
.add(
egui::Label::new(egui::RichText::new(tr("Auto")).font(regular(11.0)).color(Tokens::get(ui.ctx()).accent))
egui::Label::new(egui::RichText::new(tr("Auto")).font(regular(11.0)).color(Tokens::get(ui.ctx()).accent_text))
.sense(Sense::click()),
)
.on_hover_text(tip)
@@ -713,7 +713,7 @@ fn variable_axes(app: &mut FigApp, ui: &mut Ui, ids: &[NodeId], styles: &[TextSt
}
if styles.iter().any(|s| !s.variations.is_empty()) {
ui.add_space(8.0);
let r = ui.add(egui::Label::new(egui::RichText::new(tr("Reset to style")).font(regular(11.0)).color(t.accent)).sense(Sense::click()));
let r = ui.add(egui::Label::new(egui::RichText::new(tr("Reset to style")).font(regular(11.0)).color(t.accent_text)).sense(Sense::click()));
if r.on_hover_text(tr("Back to the values the font style implies")).clicked() {
app.run("text.setVariations", json!({"ids": ids, "variations": {}, "replace": true}));
}
@@ -789,7 +789,7 @@ fn axis_slider(ui: &mut Ui, id: Id, axis: &figcraft_text::Axis, value: Option<f6
let x = x_of(v);
p.rect_filled(Rect::from_min_max(track.min, pos2(x, track.max.y)), CornerRadius::same(2), t.accent);
p.circle_filled(pos2(x, track.center().y), 6.0, Color32::WHITE);
let ring = if resp.hovered() || resp.dragged() { t.accent } else { t.border_strong };
let ring = if resp.hovered() || resp.dragged() { crate::theme::ACCENT } else { t.border_strong };
p.circle_stroke(pos2(x, track.center().y), 6.0, Stroke::new(1.0, ring));
}
if resp.double_clicked() {
@@ -899,14 +899,14 @@ fn feature_row(ui: &mut Ui, tag: &str, label: &str, on: Option<bool>, supported:
match on {
Some(true) => {
ui.painter().rect_filled(b, CornerRadius::same(3), t.accent);
icons::paint(ui.painter(), b.shrink(1.5), Icon::Check, Color32::WHITE);
icons::paint(ui.painter(), b.shrink(1.5), Icon::Check, t.accent_on);
}
Some(false) => {
ui.painter().rect_stroke(b, CornerRadius::same(3), Stroke::new(1.0, t.border_strong), StrokeKind::Inside);
}
None => {
ui.painter().rect_filled(b, CornerRadius::same(3), t.accent);
ui.painter().line_segment([pos2(b.min.x + 3.5, b.center().y), pos2(b.max.x - 3.5, b.center().y)], Stroke::new(1.5, Color32::WHITE));
ui.painter().line_segment([pos2(b.min.x + 3.5, b.center().y), pos2(b.max.x - 3.5, b.center().y)], Stroke::new(1.5, t.accent_on));
}
}
let col = if supported { t.text } else { t.text_tertiary };
@@ -1025,7 +1025,7 @@ fn lead_field(ui: &mut Ui, id: Id, glyph: LeadGlyph, value: &str, width: f32, ti
crate::a11y::text(&resp, tip, value);
ui.painter().rect_filled(rect, CornerRadius::same(5), t.field);
if editing.is_some() {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.accent), StrokeKind::Inside);
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, crate::theme::ACCENT), StrokeKind::Inside);
} else if resp.hovered() {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.field_hover_border), StrokeKind::Inside);
}
@@ -1274,7 +1274,7 @@ pub(crate) fn font_picker(ui: &mut Ui, current: Option<&str>, just_opened: bool)
if hovered {
ui.painter().rect_filled(rect, CornerRadius::same(5), t.accent);
}
let col = if hovered { Color32::WHITE } else { t.text };
let col = if hovered { t.accent_on } else { t.text };
if current.is_some_and(|c| c.eq_ignore_ascii_case(f)) {
icons::paint(
ui.painter(),
+5 -5
View File
@@ -217,7 +217,7 @@ fn number_field_impl(
let hovered = field_resp.hovered() || lead_resp.hovered() || editing.is_some();
ui.painter().rect_filled(rect, CornerRadius::same(5), t.field);
if editing.is_some() {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.accent), StrokeKind::Inside);
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, crate::theme::ACCENT), StrokeKind::Inside);
} else if hovered {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.field_hover_border), StrokeKind::Inside);
}
@@ -507,7 +507,7 @@ fn text_field_in(ui: &mut Ui, id: Id, value: &str, rect: Rect, placeholder: &str
a11y::text(&resp, name, value);
ui.painter().rect_filled(rect, CornerRadius::same(5), t.field);
if editing.is_some() {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.accent), StrokeKind::Inside);
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, crate::theme::ACCENT), StrokeKind::Inside);
} else if resp.hovered() {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.field_hover_border), StrokeKind::Inside);
}
@@ -570,7 +570,7 @@ pub fn text_input(ui: &mut Ui, id: Id, text: &mut String, width: f32, hint: &str
ui.painter().rect_filled(rect, CornerRadius::same(5), t.field);
let r = field_editor(ui, rect, id, text, hint);
if r.has_focus() {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.accent), StrokeKind::Inside);
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, crate::theme::ACCENT), StrokeKind::Inside);
} else if ui.rect_contains_pointer(rect) {
ui.painter().rect_stroke(rect, CornerRadius::same(5), Stroke::new(1.0, t.field_hover_border), StrokeKind::Inside);
}
@@ -992,7 +992,7 @@ pub fn radio(ui: &mut Ui, on: bool, label: &str) -> bool {
ui.painter().circle_filled(c, 7.0, t.accent);
ui.painter().circle_filled(c, 2.5, t.accent_on);
} else {
ui.painter().circle_stroke(c, 6.5, Stroke::new(1.0, if resp.hovered() { t.accent } else { t.border_strong }));
ui.painter().circle_stroke(c, 6.5, Stroke::new(1.0, if resp.hovered() { crate::theme::ACCENT } else { t.border_strong }));
}
ui.painter().text(pos2(rect.min.x + 22.0, rect.center().y), Align2::LEFT_CENTER, label, regular(11.0), t.text);
resp.clicked()
@@ -1046,7 +1046,7 @@ pub fn text_field_inline(ui: &mut Ui, id: Id, value: &str, rect: Rect, font: egu
match buf {
Some(mut text) => {
ui.painter().rect_filled(rect.expand(2.0), CornerRadius::same(4), t.panel);
ui.painter().rect_stroke(rect.expand(2.0), CornerRadius::same(4), Stroke::new(1.0, t.accent), StrokeKind::Inside);
ui.painter().rect_stroke(rect.expand(2.0), CornerRadius::same(4), Stroke::new(1.0, crate::theme::ACCENT), StrokeKind::Inside);
let mut child = ui.new_child(egui::UiBuilder::new().max_rect(rect));
let r = crate::bidi::single_line(&mut child, te_id, &mut text, font, rect.width());
a11y::own_focus(&r);