From 60ffb5592cf5ca9468fc8d0a2d01a894d4df446b Mon Sep 17 00:00:00 2001 From: Mega Yu Date: Tue, 14 Apr 2026 08:58:49 +0800 Subject: [PATCH] enhance(ui): add tooltips to various buttons for improved accessibility --- src/main/frontend/components/container.cljs | 16 ++-- src/main/frontend/components/header.cljs | 91 ++++++++++--------- src/main/frontend/components/repo.cljs | 23 ++--- .../frontend/components/right_sidebar.cljs | 41 +++++---- .../frontend/components/window_controls.cljs | 42 +++++---- src/main/frontend/ui.cljs | 13 ++- 6 files changed, 124 insertions(+), 102 deletions(-) diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index aa94ce494b..c4d09d1233 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -263,13 +263,15 @@ handbooks-open? (state/sub :ui/handbooks-open?)] [:<> [:div.cp__sidebar-help-btn - [:div.inner - {:title (t :help.shortcuts/desc) - :on-click #(state/toggle! :ui/help-open?)} - [:svg.scale-125 {:stroke "currentColor", :fill "none", :stroke-linejoin "round", :width "24", :view-box "0 0 24 24", :xmlns "http://www.w3.org/2000/svg", :stroke-linecap "round", :stroke-width "2", :class "icon icon-tabler icon-tabler-help-small", :height "24"} - [:path {:stroke "none", :d "M0 0h24v24H0z", :fill "none"}] - [:path {:d "M12 16v.01"}] - [:path {:d "M12 13a2 2 0 0 0 .914 -3.782a1.98 1.98 0 0 0 -2.414 .483"}]]]] + (ui/tooltip + [:div.inner + {:on-click #(state/toggle! :ui/help-open?)} + [:svg.scale-125 {:stroke "currentColor", :fill "none", :stroke-linejoin "round", :width "24", :view-box "0 0 24 24", :xmlns "http://www.w3.org/2000/svg", :stroke-linecap "round", :stroke-width "2", :class "icon icon-tabler icon-tabler-help-small", :height "24"} + [:path {:stroke "none", :d "M0 0h24v24H0z", :fill "none"}] + [:path {:d "M12 16v.01"}] + [:path {:d "M12 13a2 2 0 0 0 .914 -3.782a1.98 1.98 0 0 0 -2.414 .483"}]]] + (t :help.shortcuts/desc) + {:root-props {:delay-duration 100}})] (when help-open? (help-menu-popup)) diff --git a/src/main/frontend/components/header.cljs b/src/main/frontend/components/header.cljs index 67e4aaa564..53cde3a706 100644 --- a/src/main/frontend/components/header.cljs +++ b/src/main/frontend/components/header.cljs @@ -97,9 +97,9 @@ [{:keys [on-click]}] (ui/with-shortcut :ui/toggle-left-sidebar "bottom" [:button.#left-menu.cp__header-left-menu.button.icon - {:title (t :header/toggle-left-sidebar) - :on-click on-click} - (ui/icon "menu-2" {:size ui/icon-size})])) + {:on-click on-click} + (ui/icon "menu-2" {:size ui/icon-size})] + (t :header/toggle-left-sidebar))) (defn bug-report-url [] (let [ua (.-userAgent js/navigator) @@ -195,50 +195,54 @@ (concat page-menu-and-hr) (remove nil?)))] - (shui/button-ghost-icon :dots - {:title (t :header/more) - :class "toolbar-dots-btn" - :on-pointer-down (fn [^js e] - (shui/popup-show! (.-target e) - (fn [{:keys [id]}] - (for [{:keys [hr item title options icon]} (items)] - (let [on-click' (:on-click options) - href (:href options)] - (if hr - (shui/dropdown-menu-separator) - (shui/dropdown-menu-item - (assoc options - :on-click (fn [^js e] - (when on-click' - (when-not (false? (on-click' e)) - (shui/popup-hide! id))))) - (or item - (if href - [:a.flex.items-center.w-full - {:href href :on-click #(shui/popup-hide! id) - :style {:color "inherit"}} - [:span.flex.items-center.gap-1.w-full - icon [:div title]]] - [:span.flex.items-center.gap-1.w-full - icon [:div title]]))))))) - {:align "end" - :as-dropdown? true - :content-props {:class "w-64" - :align-offset -32}}))}))) + (ui/tooltip + (shui/button-ghost-icon + :dots {:class "toolbar-dots-btn" + :on-pointer-down (fn [^js e] + (shui/popup-show! (.-target e) + (fn [{:keys [id]}] + (for [{:keys [hr item title options icon]} (items)] + (let [on-click' (:on-click options) + href (:href options)] + (if hr + (shui/dropdown-menu-separator) + (shui/dropdown-menu-item + (assoc options + :on-click (fn [^js e] + (when on-click' + (when-not (false? (on-click' e)) + (shui/popup-hide! id))))) + (or item + (if href + [:a.flex.items-center.w-full + {:href href :on-click #(shui/popup-hide! id) + :style {:color "inherit"}} + [:span.flex.items-center.gap-1.w-full + icon [:div title]]] + [:span.flex.items-center.gap-1.w-full + icon [:div title]]))))))) + {:align "end" + :as-dropdown? true + :content-props {:class "w-64" + :align-offset -32}}))}) + (t :header/more) + {:trigger-props {:as-child true}}))) (rum/defc back-and-forward < {:key-fn #(identity "nav-history-buttons")} [] [:div.flex.flex-row (ui/with-shortcut :go/backward "bottom" - (shui/button-ghost-icon :arrow-left - {:title (t :header/go-back) :on-click #(js/window.history.back) - :class "it navigation nav-left"})) + (shui/button-ghost-icon + :arrow-left {:on-click #(js/window.history.back) + :class "it navigation nav-left"}) + (t :header/go-back)) (ui/with-shortcut :go/forward "bottom" - (shui/button-ghost-icon :arrow-right - {:title (t :header/go-forward) :on-click #(js/window.history.forward) - :class "it navigation nav-right"}))]) + (shui/button-ghost-icon + :arrow-right {:on-click #(js/window.history.forward) + :class "it navigation nav-right"}) + (t :header/go-forward))]) (rum/defc updater-tips-new-version [t] @@ -406,19 +410,20 @@ (when-not (or (state/home?) custom-home-page?) (ui/with-shortcut :go/backward "bottom" [:button.it.navigation.nav-left.button.icon.opacity-70 - {:title (t :header/go-back) :on-click #(js/window.history.back)} - (ui/icon "chevron-left" {:size 26})])) + {:on-click #(js/window.history.back)} + (ui/icon "chevron-left" {:size 26})] + (t :header/go-back))) ;; search button for non-mobile (when current-repo (ui/with-shortcut :go/search "right" [:button.button.icon#search-button {:data-keep-selection true - :title (t :header/search) :on-click #(do (when (or (mobile-util/native-android?) (mobile-util/native-iphone?)) (state/set-left-sidebar-open! false)) (state/pub-event! [:go/search]))} - (ui/icon "search" {:size ui/icon-size})])))]] + (ui/icon "search" {:size ui/icon-size})] + (t :header/search))))]] [:div.r.flex.drag-region.justify-between.items-center.gap-2.overflow-x-hidden.w-full [:div.flex.flex-1 diff --git a/src/main/frontend/components/repo.cljs b/src/main/frontend/components/repo.cljs index 462391a083..bbc3aa632d 100644 --- a/src/main/frontend/components/repo.cljs +++ b/src/main/frontend/components/repo.cljs @@ -401,17 +401,18 @@ (db/get-short-repo-name repo-name) (t :graph.switch/select-prompt))] [:div.cp__graphs-selector.flex.items-center.justify-between - [:a.item.flex.items-center.gap-1.select-none - {:title current-repo - :on-click (fn [^js e] - (shui/popup-show! (.closest (.-target e) "a") - (fn [{:keys [id]}] (repos-dropdown-content {:contentid id})) - {:as-dropdown? true - :content-props {:class "repos-list"} - :align :start}))} - [:span.thumb (shui/tabler-icon (if remote? "cloud" "topology-star") {:size 16})] - [:strong short-repo-name] - (shui/tabler-icon "selector" {:size 18})]])) + (ui/tooltip + [:a.item.flex.items-center.gap-1.select-none + {:on-click (fn [^js e] + (shui/popup-show! (.closest (.-target e) "a") + (fn [{:keys [id]}] (repos-dropdown-content {:contentid id})) + {:as-dropdown? true + :content-props {:class "repos-list"} + :align :start}))} + [:span.thumb (shui/tabler-icon (if remote? "cloud" "topology-star") {:size 16})] + [:strong short-repo-name] + (shui/tabler-icon "selector" {:size 18})] + current-repo)])) ;; Update invalid-graph-name-warning if characters change (def multiplatform-reserved-chars ":\\*\\?\"<>|\\#\\\\") diff --git a/src/main/frontend/components/right_sidebar.cljs b/src/main/frontend/components/right_sidebar.cljs index 23546d8421..c4c75fe15a 100644 --- a/src/main/frontend/components/right_sidebar.cljs +++ b/src/main/frontend/components/right_sidebar.cljs @@ -32,9 +32,9 @@ (when-not (util/sm-breakpoint?) (ui/with-shortcut :ui/toggle-right-sidebar "left" (shui/button-ghost-icon :layout-sidebar-right - {:title (t :sidebar.right/toggle) - :class "toggle-right-sidebar" - :on-click ui-handler/toggle-right-sidebar!})))) + {:class "toggle-right-sidebar" + :on-click ui-handler/toggle-right-sidebar!}) + (t :sidebar.right/toggle)))) (rum/defc block-cp < rum/reactive [repo idx block] @@ -257,23 +257,26 @@ [:div.ml-1.font-medium.text-sm.overflow-hidden.whitespace-nowrap title]] [:.item-actions.flex.items-center - (shui/button - {:title (t :sidebar.right/more) - :class "px-2 py-2 h-8 w-8 text-muted-foreground" - :variant :ghost - :on-click #(shui/popup-show! - (.-target %) - (actions-menu-content db-id idx block-type collapsed? block-count) - {:as-dropdown? true - :content-props {:on-click (fn [] (shui/popup-hide!))}})} - (ui/icon "dots")) + (ui/tooltip + (shui/button + {:class "px-2 py-2 h-8 w-8 text-muted-foreground" + :variant :ghost + :on-click #(shui/popup-show! + (.-target %) + (actions-menu-content db-id idx block-type collapsed? block-count) + {:as-dropdown? true + :content-props {:on-click (fn [] (shui/popup-hide!))}})} + (ui/icon "dots")) + (t :sidebar.right/more)) - (shui/button - {:title (t :sidebar.right/close) - :variant :ghost - :class "px-2 py-2 h-8 w-8 text-muted-foreground" - :on-click #(state/sidebar-remove-block! idx)} - (ui/icon "x"))]] + (ui/tooltip + (shui/button + {:variant :ghost + :class "px-2 py-2 h-8 w-8 text-muted-foreground" + :on-click #(state/sidebar-remove-block! idx)} + (ui/icon "x")) + (t :sidebar.right/close))] + ] [:div {:role "region" :id (str "sidebar-panel-content-" idx) diff --git a/src/main/frontend/components/window_controls.cljs b/src/main/frontend/components/window_controls.cljs index e4f881de06..48b536f175 100644 --- a/src/main/frontend/components/window_controls.cljs +++ b/src/main/frontend/components/window_controls.cljs @@ -12,25 +12,29 @@ fullscreen? (state/sub :electron/window-fullscreen?)] [:div.window-controls.flex (if fullscreen? - [:button.button.icon.fullscreen-toggle - {:title (t :window/exit-fullscreen) - :on-click window-handler/toggle-fullscreen!} - (ui/icon "arrows-minimize")] + (ui/tooltip + [:button.button.icon.fullscreen-toggle + {:on-click window-handler/toggle-fullscreen!} + (ui/icon "arrows-minimize")] + (t :window/exit-fullscreen)) [:<> - [:button.button.icon.minimize - {:title (t :window/minimize) - :on-click window-handler/minimize!} - (svg/window-minimize)] + (ui/tooltip + [:button.button.icon.minimize + {:on-click window-handler/minimize!} + (svg/window-minimize)] + (t :window/minimize)) - [:button.button.icon.maximize-toggle - {:title (if maximized? (t :window/restore) (t :window/maximize)) - :class (if maximized? "restore" "maximize") - :on-click window-handler/toggle-maximized!} - (if maximized? - (svg/window-restore) - (svg/window-maximize))] + (ui/tooltip + [:button.button.icon.maximize-toggle + {:class (if maximized? "restore" "maximize") + :on-click window-handler/toggle-maximized!} + (if maximized? + (svg/window-restore) + (svg/window-maximize))] + (if maximized? (t :window/restore) (t :window/maximize))) - [:button.button.icon.close - {:title (t :window/close) - :on-click window-handler/close!} - (svg/window-close)]])])) + (ui/tooltip + [:button.button.icon.close + {:on-click window-handler/close!} + (svg/window-close)] + (t :window/close))])])) diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index 0f88af719a..0fa1ba602a 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -866,12 +866,19 @@ (rum/defc with-shortcut < rum/reactive < {:key-fn (fn [key pos] (str "shortcut-" key pos))} - [shortcut-key _position content] + [shortcut-key _position content & [title]] (let [shortcut-tooltip? (state/sub :ui/shortcut-tooltip?) - enabled-tooltip? (state/enable-tooltip?)] + enabled-tooltip? (state/enable-tooltip?) + binding (when shortcut-key (shortcut-dh/shortcut-binding shortcut-key)) + first-binding (when (and binding (not (false? binding))) (first binding))] (if (and enabled-tooltip? shortcut-tooltip?) (tooltip content - [:div.text-sm.font-medium (keyboard-shortcut-from-config shortcut-key)] + (if title + [:div.flex.flex-col.items-start.gap-1 + [:span.text-xs.opacity-80 title] + (when first-binding + (shui/shortcut first-binding {:glow? false}))] + (keyboard-shortcut-from-config shortcut-key)) {:trigger-props {:as-child true}}) content)))