diff --git a/CHANGELOG.md b/CHANGELOG.md index 14e70afb4b..ed7017c840 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Features +- Implemented hover tooltips for menu ([PR 2938](https://github.com/input-output-hk/daedalus/pull/2938)) - Improved UI regarding the Hardware Wallet public key export error ([PR 2922](https://github.com/input-output-hk/daedalus/pull/2922)) - Added ASCII name to token header when metadata name is missing ([PR 2904](https://github.com/input-output-hk/daedalus/pull/2904)) - Improved IPC by reducing the amount of messages from periodic events ([PR 2892](https://github.com/input-output-hk/daedalus/pull/2892)) diff --git a/source/renderer/app/components/sidebar/SidebarCategory.messages.ts b/source/renderer/app/components/sidebar/SidebarCategory.messages.ts new file mode 100644 index 0000000000..8e683e9616 --- /dev/null +++ b/source/renderer/app/components/sidebar/SidebarCategory.messages.ts @@ -0,0 +1,24 @@ +import { defineMessages } from 'react-intl'; + +export const messages = defineMessages({ + wallets: { + id: 'sidebar.categoryTooltip.wallets', + defaultMessage: '!!!Wallets', + description: 'Text for the tooltip of wallets category', + }, + staking: { + id: 'sidebar.categoryTooltip.staking', + defaultMessage: '!!!Staking', + description: 'Text for the tooltip of staking category', + }, + settings: { + id: 'sidebar.categoryTooltip.settings', + defaultMessage: '!!!Settings', + description: 'Text for the tooltip of settings category', + }, + voting: { + id: 'sidebar.categoryTooltip.voting', + defaultMessage: '!!!Voting', + description: 'Text for the tooltip of voting category', + }, +}); diff --git a/source/renderer/app/components/sidebar/SidebarCategory.tsx b/source/renderer/app/components/sidebar/SidebarCategory.tsx index a4412b1cde..cd5fa92a55 100644 --- a/source/renderer/app/components/sidebar/SidebarCategory.tsx +++ b/source/renderer/app/components/sidebar/SidebarCategory.tsx @@ -1,42 +1,53 @@ -import React, { Component } from 'react'; -// @ts-ignore ts-migrate(2305) FIXME: Module '"react"' has no exported member 'Node'. -import type { Node } from 'react'; +import React from 'react'; import SVGInline from 'react-svg-inline'; import { observer } from 'mobx-react'; import classNames from 'classnames'; import { camelCase } from 'lodash'; +import { PopOver } from 'react-polymorph/lib/components/PopOver'; +import { injectIntl } from 'react-intl'; import type { SidebarCategoryInfo } from '../../config/sidebarConfig'; import styles from './SidebarCategory.scss'; +import { messages } from './SidebarCategory.messages'; +import type { Intl } from '../../types/i18nTypes'; +import { TOOLTIP_DELAY } from '../../config/timingConfig'; type Props = { category: SidebarCategoryInfo; + intl: Intl; isActive: boolean; onClick: (...args: Array) => any; - content?: Node; + content?: React.ReactNode; }; -@observer -class SidebarCategory extends Component { - render() { - const { category, isActive, onClick, content } = this.props; - const { name, icon, route } = category; - const className = camelCase(name); - const componentStyles = classNames( - styles.component, - className, - styles[className], - { - [styles.active]: isActive, - } - ); - const iconClassName = classNames(styles.icon, styles[`${className}Icon`]); - return ( +function SidebarCategory({ + category, + intl, + isActive, + onClick, + content, +}: Props) { + const { name, icon, route, tooltipTextId } = category; + const className = camelCase(name); + const componentStyles = classNames( + styles.component, + className, + styles[className], + isActive && styles.active + ); + const iconClassName = classNames(styles.icon, styles[`${className}Icon`]); + return ( + - ); - } + + ); } -export default SidebarCategory; +export default injectIntl(observer(SidebarCategory)); diff --git a/source/renderer/app/components/staking/stake-pools/hooks/useInViewPort.tsx b/source/renderer/app/components/staking/stake-pools/hooks/useInViewPort.tsx index 17a38b30ef..30a466ae89 100644 --- a/source/renderer/app/components/staking/stake-pools/hooks/useInViewPort.tsx +++ b/source/renderer/app/components/staking/stake-pools/hooks/useInViewPort.tsx @@ -11,7 +11,7 @@ export const useInViewPort = () => { }) ); - // React will call the ref callback twice. Once when the component mounts, and call it with again when it unmounts. + // React will call the ref callback twice. Once when the component mounts and again when it unmounts. // https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node const setTargetRef = useCallback((target: HTMLElement) => { if (targetRef.current) { diff --git a/source/renderer/app/components/widgets/NewsFeedIcon.scss b/source/renderer/app/components/widgets/NewsFeedIcon.scss index d737e47e72..71c824550d 100644 --- a/source/renderer/app/components/widgets/NewsFeedIcon.scss +++ b/source/renderer/app/components/widgets/NewsFeedIcon.scss @@ -3,21 +3,7 @@ right: 29px; top: 20px; - &.notificationDot { - @extend .dot; - - &:after { - background: var( - --theme-news-feed-icon-red-dot-background-color - ) !important; - } - } - - &.updateDot { - @extend .dot; - } - - .icon { + .button { border-radius: 50%; cursor: pointer; display: block; @@ -25,6 +11,30 @@ position: relative; width: 44px; + &:hover { + background-color: var( + --theme-news-feed-icon-toggle-hover-background-color + ); + } + + &.notificationDot { + @extend .dot; + + &:after { + background: var(--theme-news-feed-icon-red-dot-background-color); + } + } + + &.updateDot { + @extend .dot; + + &:after { + background: var(--theme-news-feed-icon-green-dot-background-color); + } + } + } + + .icon { svg { height: 22px; left: 11px; @@ -36,18 +46,11 @@ stroke: var(--theme-news-feed-icon-color); } } - - &:hover { - background-color: var( - --theme-news-feed-icon-toggle-hover-background-color - ); - } } } .dot { &:after { - background: var(--theme-news-feed-icon-green-dot-background-color); border-radius: 12.5px; content: ''; display: block; @@ -59,3 +62,7 @@ width: 8px; } } + +.tooltip { + white-space: nowrap; +} diff --git a/source/renderer/app/components/widgets/NewsFeedIcon.tsx b/source/renderer/app/components/widgets/NewsFeedIcon.tsx index 70f9f971ee..83794383c6 100644 --- a/source/renderer/app/components/widgets/NewsFeedIcon.tsx +++ b/source/renderer/app/components/widgets/NewsFeedIcon.tsx @@ -1,33 +1,60 @@ -import React, { Component } from 'react'; +import React from 'react'; import SVGInline from 'react-svg-inline'; import classNames from 'classnames'; +import { PopOver } from 'react-polymorph/lib/components/PopOver'; +import { defineMessages, injectIntl } from 'react-intl'; import newsFeedIcon from '../../assets/images/top-bar/news-feed-icon.inline.svg'; import styles from './NewsFeedIcon.scss'; +import type { Intl } from '../../types/i18nTypes'; +import { TOOLTIP_DELAY } from '../../config/timingConfig'; type Props = { + intl: Intl; onNewsFeedIconClick: (...args: Array) => any; newsFeedIconClass?: string; hasNotification: boolean; hasUpdate: boolean; }; -export default class NewsFeedIcon extends Component { - render() { - const { - onNewsFeedIconClick, - newsFeedIconClass, - hasNotification, - hasUpdate, - } = this.props; - const componentClasses = classNames([ - styles.component, - hasNotification && !hasUpdate ? styles.notificationDot : null, - hasUpdate ? styles.updateDot : null, - newsFeedIconClass, - ]); - return ( - - ); - } + +const messages = defineMessages({ + iconTooltip: { + id: 'news.newsfeed.iconTooltip', + defaultMessage: '!!!Newsfeed', + description: 'Newsfeed', + }, +}); + +function NewsFeedIcon({ + intl, + onNewsFeedIconClick, + newsFeedIconClass, + hasNotification, + hasUpdate, +}: Props) { + const buttonClasses = classNames([ + styles.button, + hasNotification && !hasUpdate && styles.notificationDot, + hasUpdate && styles.updateDot, + newsFeedIconClass, + ]); + return ( +
+ + {intl.formatMessage(messages.iconTooltip)} + + } + > + + +
+ ); } + +export default injectIntl(NewsFeedIcon); diff --git a/source/renderer/app/components/widgets/NodeSyncStatusIcon.tsx b/source/renderer/app/components/widgets/NodeSyncStatusIcon.tsx index f60a313d46..edadca28dd 100644 --- a/source/renderer/app/components/widgets/NodeSyncStatusIcon.tsx +++ b/source/renderer/app/components/widgets/NodeSyncStatusIcon.tsx @@ -7,6 +7,7 @@ import { formattedNumber } from '../../utils/formatters'; import spinnerIcon from '../../assets/images/top-bar/node-sync-spinner.inline.svg'; import syncedIcon from '../../assets/images/top-bar/node-sync-synced.inline.svg'; import styles from './NodeSyncStatusIcon.scss'; +import { TOOLTIP_DELAY } from '../../config/timingConfig'; const messages = defineMessages({ blocksSynced: { @@ -32,13 +33,15 @@ export default class NodeSyncStatusIcon extends Component { const statusIcon = isSynced ? syncedIcon : spinnerIcon; const componentClasses = classNames([ styles.component, - isSynced ? null : styles.syncing, - hasTadaIcon ? styles.hasTadaIcon : null, + !isSynced && styles.syncing, + hasTadaIcon && styles.hasTadaIcon, ]); const percentage = syncPercentage.toFixed(syncPercentage === 100 ? 0 : 2); return (
{ const { isDiscreetMode, toggleDiscreetMode } = useDiscreetModeFeature(); - const [visible, setVisible] = useState(false); return ( -
setVisible(true)} - onMouseLeave={() => setVisible(false)} - > +
+ {intl.formatMessage(messages[isDiscreetMode ? 'off' : 'on'])} {` `} diff --git a/source/renderer/app/i18n/locales/defaultMessages.json b/source/renderer/app/i18n/locales/defaultMessages.json index 95bf5045f1..afc1637c08 100644 --- a/source/renderer/app/i18n/locales/defaultMessages.json +++ b/source/renderer/app/i18n/locales/defaultMessages.json @@ -3789,6 +3789,67 @@ ], "path": "source/renderer/app/components/settings/menu/SettingsMenu.messages.json" }, + { + "descriptors": [ + { + "defaultMessage": "!!!Wallets", + "description": "Text for the tooltip of wallets category", + "end": { + "column": 3, + "line": 8 + }, + "file": "source/renderer/app/components/sidebar/SidebarCategory.messages.ts", + "id": "sidebar.categoryTooltip.wallets", + "start": { + "column": 11, + "line": 4 + } + }, + { + "defaultMessage": "!!!Staking", + "description": "Text for the tooltip of staking category", + "end": { + "column": 3, + "line": 13 + }, + "file": "source/renderer/app/components/sidebar/SidebarCategory.messages.ts", + "id": "sidebar.categoryTooltip.staking", + "start": { + "column": 11, + "line": 9 + } + }, + { + "defaultMessage": "!!!Settings", + "description": "Text for the tooltip of settings category", + "end": { + "column": 3, + "line": 18 + }, + "file": "source/renderer/app/components/sidebar/SidebarCategory.messages.ts", + "id": "sidebar.categoryTooltip.settings", + "start": { + "column": 12, + "line": 14 + } + }, + { + "defaultMessage": "!!!Voting", + "description": "Text for the tooltip of voting category", + "end": { + "column": 3, + "line": 23 + }, + "file": "source/renderer/app/components/sidebar/SidebarCategory.messages.ts", + "id": "sidebar.categoryTooltip.voting", + "start": { + "column": 10, + "line": 19 + } + } + ], + "path": "source/renderer/app/components/sidebar/SidebarCategory.messages.json" + }, { "descriptors": [ { @@ -17670,6 +17731,25 @@ ], "path": "source/renderer/app/components/widgets/forms/ProfileSettingsForm.json" }, + { + "descriptors": [ + { + "defaultMessage": "!!!Newsfeed", + "description": "Newsfeed", + "end": { + "column": 3, + "line": 24 + }, + "file": "source/renderer/app/components/widgets/NewsFeedIcon.tsx", + "id": "news.newsfeed.iconTooltip", + "start": { + "column": 15, + "line": 20 + } + } + ], + "path": "source/renderer/app/components/widgets/NewsFeedIcon.json" + }, { "descriptors": [ { @@ -17677,13 +17757,13 @@ "description": "Label for the blocks synced info overlay on node sync status icon.", "end": { "column": 3, - "line": 17 + "line": 18 }, "file": "source/renderer/app/components/widgets/NodeSyncStatusIcon.tsx", "id": "cardano.node.sync.status.blocksSynced", "start": { "column": 16, - "line": 12 + "line": 13 } } ], diff --git a/source/renderer/app/i18n/locales/en-US.json b/source/renderer/app/i18n/locales/en-US.json index e62d0e2320..d041e7adf3 100755 --- a/source/renderer/app/i18n/locales/en-US.json +++ b/source/renderer/app/i18n/locales/en-US.json @@ -249,6 +249,7 @@ "loading.screen.validatingChunk": "Verifying on-disk blockchain state", "loading.screen.validatingChunkDescription": "Verifying the integrity of the blockchain calculating hashes", "news.newsfeed.empty": "Newsfeed is empty", + "news.newsfeed.iconTooltip": "Newsfeed", "news.newsfeed.noFetch": "Trying to fetch the newsfeed...", "news.newsfeed.title": "Newsfeed", "noDiskSpace.error.overlayContent": "Daedalus requires at least {diskSpaceRequired} of hard drive space to operate. Your computer is missing {diskSpaceMissing} of available space. Please delete some files to increase available hard drive space to continue using Daedalus.

It is recommended to have at least 15% of hard drive space available ({diskSpaceRecommended} in your case) for normal and stable operation of the operating system and installed programs. We strongly recommend that you free up at least that amount of space from your hard drive.", @@ -382,6 +383,10 @@ "settings.wallets.currency.poweredBy.label": "Powered by ", "settings.wallets.currency.selectLabel": "Select currency", "settings.wallets.currency.titleLabel": "Display ada balances in other currency", + "sidebar.categoryTooltip.settings": "Settings", + "sidebar.categoryTooltip.staking": "Staking", + "sidebar.categoryTooltip.voting": "Voting", + "sidebar.categoryTooltip.wallets": "Wallets", "sidebar.wallets.addWallet": "Add wallet", "sidebar.wallets.search.placeholder": "Filter", "sidebar.wallets.sortByBalanceButton": "Balance", diff --git a/source/renderer/app/i18n/locales/ja-JP.json b/source/renderer/app/i18n/locales/ja-JP.json index 0221e1e76e..753ebd5330 100755 --- a/source/renderer/app/i18n/locales/ja-JP.json +++ b/source/renderer/app/i18n/locales/ja-JP.json @@ -147,9 +147,9 @@ "dapp.transaction.request.transactionFee.label": "トランザクション手数料", "dapp.transaction.request.walletsDropdown.addWalletLabel": "+ ウォレット追加", "dapp.transaction.request.walletsDropdown.placeholder": "ウォレットを選択してください", - "discreetMode.discreetToggle.description": "設定で自動ディスクリートモードに切り替えられます。", - "discreetMode.discreetToggle.off": "ディスクリートモードオフ.", - "discreetMode.discreetToggle.on": "ディスクリートモードオン.", + "discreetMode.discreetToggle.description": "設定で自動ディスクリートモードに切り替えられます", + "discreetMode.discreetToggle.off": "ディスクリートモードオフ。", + "discreetMode.discreetToggle.on": "ディスクリートモードオン。", "environment.apiName.cardano": "Cardano", "environment.currency.ada": "ADA", "environment.network.alonzo_purple": "Alonzo Purple", @@ -249,6 +249,7 @@ "loading.screen.validatingChunk": "ディスクのブロックチェーンステータスの検証", "loading.screen.validatingChunkDescription": "ブロックチェーンのハッシュ計算の整合性を検証します", "news.newsfeed.empty": "Newsfeed is empty", + "news.newsfeed.iconTooltip": "ニュースフィード", "news.newsfeed.noFetch": "ニュースフィードを読み込んでいます...", "news.newsfeed.title": "ニュースフィード", "noDiskSpace.error.overlayContent": "Daedalusを動作させるには、ハードディスクに{diskSpaceRequired}以上の空き容量が必要です。ご使用のコンピューターには空き容量が{diskSpaceMissing}不足しています。Daedalusのご利用を続けるためには、ファイルをいくつか削除して空き容量を増やしてください。

オペレーティングシステムとインストール済みプログラムを正常かつ安定した状態で動作させるには、ハードディスクに少なくとも15%(ご使用のコンピューターの場合は{diskSpaceRecommended})の空き容量が必要です。ハードディスクにこれ以上の空き容量を確保してください。", @@ -382,6 +383,10 @@ "settings.wallets.currency.poweredBy.label": "提供:", "settings.wallets.currency.selectLabel": "通貨を選択してください", "settings.wallets.currency.titleLabel": "ADA残高を別の通貨で表示する", + "sidebar.categoryTooltip.settings": "設定", + "sidebar.categoryTooltip.staking": "ステーキング", + "sidebar.categoryTooltip.voting": "投票", + "sidebar.categoryTooltip.wallets": "ウォレット", "sidebar.wallets.addWallet": "ウォレット追加", "sidebar.wallets.search.placeholder": "フィルター", "sidebar.wallets.sortByBalanceButton": "残高", diff --git a/storybook/stories/navigation/SidebarCategory.stories.tsx b/storybook/stories/navigation/SidebarCategory.stories.tsx index aed711ea4c..ea9ccb3ced 100644 --- a/storybook/stories/navigation/SidebarCategory.stories.tsx +++ b/storybook/stories/navigation/SidebarCategory.stories.tsx @@ -10,6 +10,7 @@ const category = { name: 'Wallets', icon: walletsIcon, route: 'WALLETS', + tooltipTextId: 'wallets', }; storiesOf('Navigation|Sidebar', module) .addDecorator((story) => {story()}) // ====== Stories ======