Merge pull request #1685 from symonbaikov/codex/icon-button-tooltips

feat: add tooltips for icon buttons

Conflicts came from the branch predating the Pro banner work and the deleted
API key step. Resolved by keeping master's `onEdit` on the user actions popup
and wrapping it in the tooltip, and by leaving `ApiKeyStep.jsx` deleted.

The `switchToView` key is dropped in favour of one complete string per view.
Interpolating a view name into "Switch to {{view}} view" required
`t('common.' + view).toLowerCase()` at the call site, and lowercasing a
translated string is wrong wherever case carries meaning: German capitalises
nouns, and Turkish turns I into a dotless ı. The five replacements need no
interpolation and no lowercasing.
This commit is contained in:
Daniel Hiller
2026-09-17 00:41:33 +02:00
38 changed files with 639 additions and 255 deletions
@@ -6,7 +6,9 @@
import React, { useCallback } from 'react';
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { Icon } from 'semantic-ui-react';
import { Tooltip } from '../../../../lib/custom-ui';
import { usePopup } from '../../../../lib/popup';
import selectors from '../../../../selectors';
@@ -17,12 +19,18 @@ import SelectOrderStep from './SelectOrderStep';
import styles from './RightSide.module.scss';
const TOOLTIP_BY_VIEW = {
[HomeViews.GRID_PROJECTS]: 'action.switchToGridProjectsView',
[HomeViews.GROUPED_PROJECTS]: 'action.switchToGroupedProjectsView',
};
const RightSide = React.memo(() => {
const currentView = useSelector(selectors.selectHomeView); // TODO: rename?
const currentOrder = useSelector(selectors.selectProjectsOrder); // TODO: rename?
const isHiddenVisible = useSelector(selectors.selectIsHiddenProjectsVisible);
const dispatch = useDispatch();
const [t] = useTranslation();
const handleSelectViewClick = useCallback(
({ currentTarget: { value: view } }) => {
@@ -47,34 +55,41 @@ const RightSide = React.memo(() => {
return (
<>
<div className={styles.action}>
<button
type="button"
className={classNames(styles.button)}
onClick={handleToggleHiddenClick}
<Tooltip
content={t(isHiddenVisible ? 'action.hideHiddenProjects' : 'common.showHiddenProjects')}
>
<Icon fitted name={isHiddenVisible ? 'eye slash' : 'eye'} />
</button>
<button
type="button"
className={classNames(styles.button)}
onClick={handleToggleHiddenClick}
>
<Icon fitted name={isHiddenVisible ? 'eye slash' : 'eye'} />
</button>
</Tooltip>
</div>
<div className={styles.action}>
<SelectOrderPopup value={currentOrder} onSelect={handleOrderSelect}>
<button type="button" className={styles.button}>
<Icon fitted name={ProjectOrderIcons[currentOrder]} />
</button>
<Tooltip content={t('common.selectOrder', { context: 'title' })}>
<button type="button" className={styles.button}>
<Icon fitted name={ProjectOrderIcons[currentOrder]} />
</button>
</Tooltip>
</SelectOrderPopup>
</div>
<div className={styles.action}>
<div className={styles.buttonGroup}>
{[HomeViews.GRID_PROJECTS, HomeViews.GROUPED_PROJECTS].map((view) => (
<button
key={view}
type="button"
value={view}
disabled={view === currentView}
className={styles.button}
onClick={handleSelectViewClick}
>
<Icon fitted name={HomeViewIcons[view]} />
</button>
<Tooltip key={view} content={t(TOOLTIP_BY_VIEW[view])} disabled={view === currentView}>
<button
type="button"
value={view}
disabled={view === currentView}
className={styles.button}
onClick={handleSelectViewClick}
>
<Icon fitted name={HomeViewIcons[view]} />
</button>
</Tooltip>
))}
</div>
</div>