From 21249605fbb44c9f0adf1b891379affdca158023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 5 Oct 2026 13:37:34 -0400 Subject: [PATCH] Refactor: share iconAction for borderless 16 DIP icon buttons datetimeIconButton moves to icon_button.go as iconAction(c, icon, label) and replaces the identical copies in Dialog close, PasswordInput toggle and AppShell collapse. Hover and press now set Text on every caller, including the date and time pickers, which kept TextMuted on hover. Image retry (bordered, danger ink), TagsInput remove (14 DIP icon, no press state) and Tag close (12 DIP icon, fade) are different buttons and stay as they are. --- app_shell.go | 12 +----------- calendar.go | 9 +++++---- date_picker.go | 6 ++++-- datetime.go | 15 --------------- datetime_grid.go | 7 ++++--- dialog.go | 17 +---------------- icon_button.go | 18 ++++++++++++++++++ password_input.go | 16 +--------------- time_picker.go | 3 ++- 9 files changed, 36 insertions(+), 67 deletions(-) diff --git a/app_shell.go b/app_shell.go index cce3dea..bd3476d 100644 --- a/app_shell.go +++ b/app_shell.go @@ -6,7 +6,6 @@ import ( "github.com/egoist/mygo/ui" "mujicaui/icons" - "mujicaui/internal" "mujicaui/theme" ) @@ -100,16 +99,7 @@ func appShellSidebar(c *ui.Context, collapsed bool, opts AppShellOptions) bool { if collapsed { label = msg(c, "app_shell.expand") } - b := ui.ButtonBase(c).Size(theme.MinHitSize, theme.MinHitSize).Radius(theme.ControlRadius). - Label(label).Tooltip(label).TextColor(k.TextMuted) - internal.Ring(b, k.Focus, theme.ControlRadius) - if b.Pressed() { - b.Background(k.Selection).TextColor(k.Text) - } else if b.Hovered() { - b.Background(k.SurfaceHover).TextColor(k.Text) - } - b.Children(func() { ui.Icon(c, icons.Must("panel-left")).Size(16, 16) }) - pressed = b.Clicked() + pressed = iconAction(c, icons.Must("panel-left"), label).Tooltip(label).Clicked() }) if !collapsed { ScrollArea(c, nil, ScrollAreaOptions{}, opts.Sidebar).Grow(1).MinHeight(0) diff --git a/calendar.go b/calendar.go index 2a8e691..8b04255 100644 --- a/calendar.go +++ b/calendar.go @@ -8,6 +8,7 @@ import ( "github.com/egoist/mygo/ui" + "mujicaui/icons" "mujicaui/internal" "mujicaui/theme" ) @@ -132,18 +133,18 @@ func calendarMonth(c *ui.Context, cursor *Date, cfg calendarConfig) (picked, hov } root.Children(func() { ui.Row(c).AlignItems(ui.Center).Gap(d.Unit()).Children(func() { - if datetimeIconButton(c, "chevrons-left", msg(c, "calendar.prev_year")).Clicked() { + if iconAction(c, icons.Must("chevrons-left"), msg(c, "calendar.prev_year")).Clicked() { move(cur.AddMonths(-12), -1, false) } - if datetimeIconButton(c, "chevron-left", msg(c, "calendar.prev_month")).Clicked() { + if iconAction(c, icons.Must("chevron-left"), msg(c, "calendar.prev_month")).Clicked() { move(cur.AddMonths(-1), -1, false) } ui.Text(c, title).Font(theme.SerifFont).FontSize(FontSize(c, theme.BodySize+2)).Bold(). TextColor(k.Text).Grow(1).TextAlign(ui.Center).SingleLine() - if datetimeIconButton(c, "chevron-right", msg(c, "calendar.next_month")).Clicked() { + if iconAction(c, icons.Must("chevron-right"), msg(c, "calendar.next_month")).Clicked() { move(cur.AddMonths(1), 1, false) } - if datetimeIconButton(c, "chevrons-right", msg(c, "calendar.next_year")).Clicked() { + if iconAction(c, icons.Must("chevrons-right"), msg(c, "calendar.next_year")).Clicked() { move(cur.AddMonths(12), 1, false) } }) diff --git a/date_picker.go b/date_picker.go index 57ae24a..a284907 100644 --- a/date_picker.go +++ b/date_picker.go @@ -7,6 +7,8 @@ import ( "time" "github.com/egoist/mygo/ui" + + "mujicaui/icons" ) // DatePickerOptions configure a DatePicker. @@ -121,10 +123,10 @@ func DatePicker(c *ui.Context, value *Date, opts DatePickerOptions) DateTimeResu if opts.ReadOnly { return } - if opts.Clearable && !value.IsZero() && datetimeIconButton(c, "x", msg(c, "calendar.clear")).Clicked() { + if opts.Clearable && !value.IsZero() && iconAction(c, icons.Must("x"), msg(c, "calendar.clear")).Clicked() { commit(Date{}, "clear") } - if datetimeIconButton(c, "calendar", msg(c, "date_picker.open")).Role(ui.RolePopUpButton).Clicked() { + if iconAction(c, icons.Must("calendar"), msg(c, "date_picker.open")).Role(ui.RolePopUpButton).Clicked() { if *open { *open = false } else { diff --git a/datetime.go b/datetime.go index 2fff036..f33ae70 100644 --- a/datetime.go +++ b/datetime.go @@ -122,21 +122,6 @@ func datetimeDayLabel(c *ui.Context, d Date) string { return fmt.Sprintf(msg(c, "calendar.day_label"), wd, datetimeMonthName(c, d.Month), d.Day, d.Year) } -// datetimeIconButton is a square, borderless button showing icon, named label. -func datetimeIconButton(c *ui.Context, icon, label string) *ui.Element { - k := Tokens(c) - b := ui.ButtonBase(c).Size(theme.MinHitSize, theme.MinHitSize).Radius(theme.ControlRadius).Label(label) - internal.Ring(b, k.Focus, theme.ControlRadius) - switch { - case b.Pressed(): - b.Background(k.Selection) - case b.Hovered(): - b.Background(k.SurfaceHover) - } - b.TextColor(k.TextMuted).Children(func() { ui.Icon(c, icons.Must(icon)).Size(16, 16) }) - return b -} - // datetimeField styles row as a single-line field: solid fill and fine border. func datetimeField(c *ui.Context, row *ui.Element, invalid, readOnly bool) *ui.Element { k := Tokens(c) diff --git a/datetime_grid.go b/datetime_grid.go index f4e3136..2229abb 100644 --- a/datetime_grid.go +++ b/datetime_grid.go @@ -3,6 +3,7 @@ package mujica import ( "github.com/egoist/mygo/ui" + "mujicaui/icons" "mujicaui/internal" "mujicaui/theme" ) @@ -36,12 +37,12 @@ func datetimeGrid(c *ui.Context, cursor *int, cfg datetimeGridConfig) (picked in start, _ := cfg.pageOf(*cursor) ui.Row(c).AlignItems(ui.Center).Gap(d.Unit()).BorderWidth(0, 0, theme.BorderWidth, 0).BorderColor(k.Border). PaddingY(d.Unit()).Children(func() { - if datetimeIconButton(c, "chevron-left", cfg.prev).Clicked() { + if iconAction(c, icons.Must("chevron-left"), cfg.prev).Clicked() { *cursor, *keyed = *cursor-cfg.page, false } ui.Text(c, cfg.title(start)).Font(theme.SerifFont).FontSize(FontSize(c, theme.BodySize+2)).Bold(). TextColor(k.Text).Grow(1).TextAlign(ui.Center).SingleLine() - if datetimeIconButton(c, "chevron-right", cfg.next).Clicked() { + if iconAction(c, icons.Must("chevron-right"), cfg.next).Clicked() { *cursor, *keyed = *cursor+cfg.page, false } }) @@ -182,7 +183,7 @@ func datetimeGridPicker(c *ui.Context, f datetimeGridField, cfg datetimeGridConf if !f.readOnly && (t.Clicked() || !*open && t.Shortcut(0, ui.KeyDown)) { *open, *cursor = !*open, f.home } - if f.clearable && f.hasValue && !f.readOnly && datetimeIconButton(c, "x", msg(c, "calendar.clear")).Clicked() { + if f.clearable && f.hasValue && !f.readOnly && iconAction(c, icons.Must("x"), msg(c, "calendar.clear")).Clicked() { cleared = true } }) diff --git a/dialog.go b/dialog.go index dab5c77..f242804 100644 --- a/dialog.go +++ b/dialog.go @@ -117,7 +117,7 @@ func dialogHeader(c *ui.Context, title string, decorated, closable bool, closeKe ui.Row(c).Gap(u * 3).AlignItems(ui.Start).Children(func() { ui.Text(c, title).Font(theme.SerifFont).FontSize(FontSize(c, theme.H3Size)).FontWeight(600).Grow(1) if closable { - clicked = dialogCloseButton(c, msg(c, closeKey)).Clicked() + clicked = iconAction(c, icons.Must("x"), msg(c, closeKey)).Margin(-4, -4, 0, 0).Clicked() } }) if decorated { @@ -137,21 +137,6 @@ func dialogRule(c *ui.Context, ink ui.Color) { }) } -// dialogCloseButton is the 28 DIP icon button closing a panel. -func dialogCloseButton(c *ui.Context, label string) *ui.Element { - k := Tokens(c) - b := ui.ButtonBase(c).Size(theme.MinHitSize, theme.MinHitSize).Radius(theme.ControlRadius).Label(label).Margin(-4, -4, 0, 0) - internal.Ring(b, k.Focus, theme.ControlRadius) - b.TextColor(k.TextMuted) - if b.Pressed() { - b.Background(k.Selection).TextColor(k.Text) - } else if b.Hovered() { - b.Background(k.SurfaceHover).TextColor(k.Text) - } - b.Children(func() { ui.Icon(c, icons.Must("x")).Size(16, 16) }) - return b -} - // dialogActions lays out a dialog footer. func dialogActions(c *ui.Context, actions func()) { u := Density(c).Unit() diff --git a/icon_button.go b/icon_button.go index 5de2c78..306c238 100644 --- a/icon_button.go +++ b/icon_button.go @@ -2,6 +2,9 @@ package mujica import ( "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" ) // IconButtonOptions configure an IconButton. @@ -31,3 +34,18 @@ func IconButton(c *ui.Context, icon *ui.SVG, label string, opts IconButtonOption } return b.Tooltip(tip) } + +// iconAction is a square, borderless button showing icon, named label. +func iconAction(c *ui.Context, icon *ui.SVG, label string) *ui.Element { + k := Tokens(c) + b := ui.ButtonBase(c).Size(theme.MinHitSize, theme.MinHitSize).Radius(theme.ControlRadius).Label(label).TextColor(k.TextMuted) + internal.Ring(b, k.Focus, theme.ControlRadius) + switch { + case b.Pressed(): + b.Background(k.Selection).TextColor(k.Text) + case b.Hovered(): + b.Background(k.SurfaceHover).TextColor(k.Text) + } + b.Children(func() { ui.Icon(c, icon).Size(16, 16) }) + return b +} diff --git a/password_input.go b/password_input.go index f71816c..2c2e585 100644 --- a/password_input.go +++ b/password_input.go @@ -6,8 +6,6 @@ import ( "github.com/egoist/mygo/ui" "mujicaui/icons" - "mujicaui/internal" - "mujicaui/theme" ) // PasswordInputOptions configure a PasswordInput. @@ -55,21 +53,9 @@ func PasswordInput(c *ui.Context, value *string, opts PasswordInputOptions) Inpu // passwordInputToggle builds the show or hide button and reports a click. func passwordInputToggle(c *ui.Context, shown bool) bool { - k := Tokens(c) name, icon := msg(c, "password_input.show"), "eye" if shown { name, icon = msg(c, "password_input.hide"), "eye-off" } - b := ui.ButtonBase(c).Size(theme.MinHitSize, theme.MinHitSize).Radius(theme.ControlRadius).Label(name).Tooltip(name) - internal.Ring(b, k.Focus, theme.ControlRadius) - fg := k.TextMuted - if b.Pressed() { - b.Background(k.Selection) - fg = k.Text - } else if b.Hovered() { - b.Background(k.SurfaceHover) - fg = k.Text - } - b.Children(func() { ui.Icon(c, icons.Must(icon)).Size(16, 16).TextColor(fg) }) - return b.Clicked() + return iconAction(c, icons.Must(icon), name).Tooltip(name).Clicked() } diff --git a/time_picker.go b/time_picker.go index 5ab13b3..d0d0eb3 100644 --- a/time_picker.go +++ b/time_picker.go @@ -8,6 +8,7 @@ import ( "github.com/egoist/mygo/ui" + "mujicaui/icons" "mujicaui/internal" "mujicaui/theme" ) @@ -221,7 +222,7 @@ func timeEditor(c *ui.Context, draft *TimeOfDay, cfg timeConfig) (field *ui.Elem if cfg.readOnly { return } - b := datetimeIconButton(c, "clock", msg(c, "time_picker.open")).Role(ui.RolePopUpButton) + b := iconAction(c, icons.Must("clock"), msg(c, "time_picker.open")).Role(ui.RolePopUpButton) if b.Clicked() { *open, *fresh = !*open, true }