diff --git a/src/components/fields/Checkbox.tsx b/src/components/fields/Checkbox.tsx index 20ca31646..e420d5ed6 100644 --- a/src/components/fields/Checkbox.tsx +++ b/src/components/fields/Checkbox.tsx @@ -1,9 +1,11 @@ import type { FC, ReactNode } from 'react'; +import { Tooltip } from './Tooltip'; export interface ICheckbox { name: string; label: string; helpText?: ReactNode | string; + tooltip?: ReactNode | string; checked: boolean; disabled?: boolean; onChange: (evt: React.ChangeEvent) => void; @@ -33,6 +35,7 @@ export const Checkbox: FC = (props: ICheckbox) => { } > {props.label} + {props.tooltip && } diff --git a/src/components/fields/Tooltip.test.tsx b/src/components/fields/Tooltip.test.tsx new file mode 100644 index 000000000..863847eec --- /dev/null +++ b/src/components/fields/Tooltip.test.tsx @@ -0,0 +1,28 @@ +import { fireEvent, render, screen } from '@testing-library/react'; + +import * as TestRenderer from 'react-test-renderer'; + +import { type ITooltip, Tooltip } from './Tooltip'; + +describe('components/fields/Tooltip.tsx', () => { + const props: ITooltip = { + tooltip: 'This is some tooltip text', + }; + + it('should render', () => { + const tree = TestRenderer.create(); + expect(tree).toMatchSnapshot(); + }); + + it('should display on mouse enter / leave', () => { + render(); + + const tooltipElement = screen.getByTitle('tooltip'); + + fireEvent.mouseEnter(tooltipElement); + expect(tooltipElement).toMatchSnapshot(); + + fireEvent.mouseLeave(tooltipElement); + expect(tooltipElement).toMatchSnapshot(); + }); +}); diff --git a/src/components/fields/Tooltip.tsx b/src/components/fields/Tooltip.tsx new file mode 100644 index 000000000..3a9232fa9 --- /dev/null +++ b/src/components/fields/Tooltip.tsx @@ -0,0 +1,28 @@ +import { QuestionIcon } from '@primer/octicons-react'; +import { type FC, type ReactNode, useState } from 'react'; + +export interface ITooltip { + tooltip: ReactNode | string; +} + +export const Tooltip: FC = (props: ITooltip) => { + const [showTooltip, setShowTooltip] = useState(false); + + return ( + setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + > + + {showTooltip && ( +
+
+ {props.tooltip} +
+
+ )} +
+ ); +}; diff --git a/src/components/fields/__snapshots__/Tooltip.test.tsx.snap b/src/components/fields/__snapshots__/Tooltip.test.tsx.snap new file mode 100644 index 000000000..c2ed6592f --- /dev/null +++ b/src/components/fields/__snapshots__/Tooltip.test.tsx.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/fields/Tooltip.tsx should display on mouse enter / leave 1`] = ` + + +
+
+ This is some tooltip text +
+
+
+`; + +exports[`components/fields/Tooltip.tsx should display on mouse enter / leave 2`] = ` + + + +`; + +exports[`components/fields/Tooltip.tsx should render 1`] = ` + + + +`; diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx index 25a975eb7..28228dfcf 100644 --- a/src/routes/Settings.tsx +++ b/src/routes/Settings.tsx @@ -142,6 +142,19 @@ export const SettingsRoute: FC = () => { updateSetting('detailedNotifications', evt.target.checked) } disabled={!repoScope} + tooltip={ +
+
+ Enrich notifications with author or last commenter profile + information, state and GitHub-like colors. +
+
+ ⚠️ Users with a large number of unread notifications may{' '} + experience rate limiting under certain circumstances. Disable + this setting if you experience this. +
+
+ } /> Detailed notifications (requires repo scope) + + + @@ -175,6 +194,25 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = ` style="" > Detailed notifications + + +