Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bb8eafa
Add `Edit Profile` button tooltip label
ivan-ottinger Nov 8, 2024
2246bd3
Update `aria-label` of the `Edit Profile` button
ivan-ottinger Nov 8, 2024
9a0c413
Add `Open Settings` button tooltip label
ivan-ottinger Nov 8, 2024
a986cde
Update `aria-label` of the `Open Settings` button
ivan-ottinger Nov 8, 2024
97c4840
Update `aria-label` of the `Get help` button
ivan-ottinger Nov 8, 2024
2f5bd45
Add `Get help` button tooltip label
ivan-ottinger Nov 8, 2024
b73d29f
Add `Stop site` / `Start site` tooltip label to the Stop / Start site…
ivan-ottinger Nov 8, 2024
cc7f35f
Fix unit tests
ivan-ottinger Nov 8, 2024
033dc7e
Fix linting
ivan-ottinger Nov 8, 2024
791c4b0
Change `Edit Profile` to `Edit profile` and `Open Settings` to `Open …
ivan-ottinger Nov 11, 2024
47d8583
Add `Toggle sidebar` tooltip
ivan-ottinger Nov 11, 2024
8debf03
Add `Starting` tooltip text when a site is starting
ivan-ottinger Nov 11, 2024
f4b76c1
Add tooltip handling to the `CopyTextButton` component
ivan-ottinger Nov 11, 2024
a833c94
Add tooltips to "Copy to clipboard" buttons on the site Settings page
ivan-ottinger Nov 11, 2024
a1aaf56
Add tooltips to `WP admin` and `Open site` links
ivan-ottinger Nov 11, 2024
5081bbb
Add tooltip to the site screenshot on the Overview tab
ivan-ottinger Nov 11, 2024
6388a10
Fix linting errors
ivan-ottinger Nov 11, 2024
ebfcb29
Fix translators comments
ivan-ottinger Nov 11, 2024
92a323c
Update "Copy to clipboard" tooltip logic
ivan-ottinger Nov 11, 2024
c913ba0
Fix unit tests
ivan-ottinger Nov 11, 2024
108abae
Add tooltip to the `Log in` button when logged out
ivan-ottinger Nov 12, 2024
333b600
Use custom `Tooltip` component
ivan-ottinger Nov 12, 2024
172c198
Fix linting errors
ivan-ottinger Nov 12, 2024
ba4bd1a
Restore unintentionaly removed `showTooltip` prop from the `Button` c…
ivan-ottinger Nov 12, 2024
ebf326c
Refactor `Button` component return value
ivan-ottinger Nov 12, 2024
1fcd845
Handle header tooltip texts for stopped sites
ivan-ottinger Nov 13, 2024
dbf2937
Apply tooltip to Header links only when the site is running
ivan-ottinger Nov 13, 2024
3114ccd
Use `title` instead of `tooltipText` for `Get help` and `Edit profile…
ivan-ottinger Nov 14, 2024
4713347
Remove `Edit profile` tooltip
ivan-ottinger Nov 15, 2024
fe706dc
Remove `Get help` tooltip
ivan-ottinger Nov 15, 2024
9f74b5c
Remove tooltips from Header links
ivan-ottinger Nov 15, 2024
0688a7c
Remove `url` from `StoppedSiteDetails` interface
ivan-ottinger Nov 15, 2024
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Button } from '@wordpress/components';
import { useResizeObserver } from '@wordpress/compose';
import { ComponentProps, useEffect, useRef, useState } from 'react';
import { cx } from '../lib/cx';
import Tooltip from './tooltip';

/**
* Sourced from https://stackoverflow.com/a/76616671/378228 to address
Expand All @@ -13,6 +14,7 @@ type MappedOmit< T, K extends PropertyKey > = { [ P in keyof T as Exclude< P, K
export type ButtonProps = MappedOmit< ComponentProps< typeof Button >, 'variant' > & {
variant?: ButtonVariant;
truncate?: boolean;
tooltipText?: string;
};

type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'outlined' | 'link' | 'icon';
Expand Down Expand Up @@ -117,6 +119,7 @@ export default function ButtonComponent( {
truncate,
children,
showTooltip,
tooltipText,
...props
}: ButtonProps ) {
const [ isTruncated, setIsTruncated ] = useState( false );
Expand All @@ -128,7 +131,8 @@ export default function ButtonComponent( {
}
setIsTruncated( element.current.offsetWidth < element.current.scrollWidth );
}, [ sizes, truncate ] );
return (

const buttonContent = (
<Button
{ ...props }
variant={ sansCustomValues( variant ) }
Expand All @@ -154,4 +158,6 @@ export default function ButtonComponent( {
: children }
</Button>
);

return tooltipText ? <Tooltip text={ tooltipText }>{ buttonContent }</Tooltip> : buttonContent;
}
46 changes: 29 additions & 17 deletions src/components/content-tab-overview.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as Sentry from '@sentry/electron/renderer';
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import {
archive,
code,
Expand All @@ -24,6 +24,7 @@ import { isMac } from '../lib/app-globals';
import { cx } from '../lib/cx';
import { getIpcApi } from '../lib/get-ipc-api';
import { ButtonsSection, ButtonsSectionProps } from './buttons-section';
import Tooltip from './tooltip';

interface ContentTabOverviewProps {
selectedSite: SiteDetails;
Expand Down Expand Up @@ -257,25 +258,36 @@ export function ContentTabOverview( { selectedSite }: ContentTabOverviewProps )
</div>
) }
{ ! loading && siteRunning && (
<button
aria-label={ __( 'Open site' ) }
className={ 'relative group focus-visible:outline-a8c-blueberry' }
onClick={ () => getIpcApi().openSiteURL( selectedSite.id, '', { autoLogin: false } ) }
<Tooltip
text={ sprintf(
/* translators: siteUrl is the site URL */
__( 'Open %(siteUrl)s' ),
{ siteUrl: selectedSite.url }
) }
placement="top"
>
<div
className={
'opacity-0 group-hover:opacity-90 group-hover:bg-white group-focus:opacity-90 group-focus:bg-white duration-300 absolute size-full flex justify-center items-center bg-white text-a8c-blueberry'
<button
aria-label={ __( 'Open site' ) }
className={ 'relative group focus-visible:outline-a8c-blueberry' }
onClick={ () =>
getIpcApi().openSiteURL( selectedSite.id, '', { autoLogin: false } )
}
>
{ __( 'Open site' ) }
<Icon
icon={ external }
className="ltr:ml-0.5 rtl:mr-0.5 rtl:scale-x-[-1] fill-a8c-blueberry"
size={ 14 }
/>
</div>
{ thumbnailImage }
</button>
<div
className={
'opacity-0 group-hover:opacity-90 group-hover:bg-white group-focus:opacity-90 group-focus:bg-white duration-300 absolute size-full flex justify-center items-center bg-white text-a8c-blueberry'
}
>
{ __( 'Open site' ) }
<Icon
icon={ external }
className="ltr:ml-0.5 rtl:mr-0.5 rtl:scale-x-[-1] fill-a8c-blueberry"
size={ 14 }
/>
</div>
{ thumbnailImage }
</button>
</Tooltip>
) }
{ ! loading && ! siteRunning && thumbnailImage }
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/copy-text-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export function CopyTextButton( {
showCopied && '[&.is-link]:text-[#2145e6]',
className
) }
aria-label={ label || __( 'copy to clipboard' ) }
aria-label={ label || __( 'Copy to clipboard' ) }
tooltipText={ __( 'Copy to clipboard' ) }
onClick={ onClick }
variant={ variant }
>
Expand Down
70 changes: 40 additions & 30 deletions src/components/site-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useImportExport } from '../hooks/use-import-export';
import { useSiteDetails } from '../hooks/use-site-details';
import { isMac } from '../lib/app-globals';
import { cx } from '../lib/cx';
import Tooltip from './tooltip';

interface SiteMenuProps {
className?: string;
Expand Down Expand Up @@ -57,43 +58,52 @@ function ButtonToRun( { running, id, name }: Pick< SiteDetails, 'running' | 'id'
/>
</svg>
);

const tooltipText = loadingServer[ id ]
? __( 'Starting' )
: running
? __( 'Stop site' )
: __( 'Start site' );

return (
<button
aria-disabled={ loadingServer[ id ] }
onClick={ () => {
if ( loadingServer[ id ] ) {
return;
}
return running ? stopServer( id ) : startServer( id );
} }
className="w-7 h-8 rounded-tr rounded-br group grid focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-a8c-blueberry"
aria-label={ sprintf( running ? __( 'stop %s site' ) : __( 'start %s site' ), name ) }
>
{ /* Circle */ }
<div
className={ cx(
'w-2.5 h-2.5 transition-opacity group-hover:opacity-0 group-focus-visible:opacity-0 border-[0.5px]',
'row-start-1 col-start-1 place-self-center',
classCircle,
loadingServer[ id ] && 'animate-pulse border-[#00BA3775] bg-[#1ED15A75] duration-100',
running && 'border-[#00BA37] bg-[#1ED15A] duration-100',
! running && ! loadingServer[ id ] && 'border-[#ffffff19] bg-[#ffffff26]'
) }
<Tooltip text={ tooltipText }>
<button
aria-disabled={ loadingServer[ id ] }
onClick={ () => {
if ( loadingServer[ id ] ) {
return;
}
return running ? stopServer( id ) : startServer( id );
} }
className="w-7 h-8 rounded-tr rounded-br group grid focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-a8c-blueberry"
aria-label={ sprintf( running ? __( 'stop %s site' ) : __( 'start %s site' ), name ) }
>
&nbsp;
</div>
{ /* Shapes on hover */ }
{ ! loadingServer[ id ] && (
{ /* Circle */ }
<div
className={ cx(
'opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100',
'row-start-1 col-start-1 place-self-center'
'w-2.5 h-2.5 transition-opacity group-hover:opacity-0 group-focus-visible:opacity-0 border-[0.5px]',
'row-start-1 col-start-1 place-self-center',
classCircle,
loadingServer[ id ] && 'animate-pulse border-[#00BA3775] bg-[#1ED15A75] duration-100',
running && 'border-[#00BA37] bg-[#1ED15A] duration-100',
! running && ! loadingServer[ id ] && 'border-[#ffffff19] bg-[#ffffff26]'
) }
>
{ running ? rectangle : triangle }
&nbsp;
</div>
) }
</button>
{ /* Shapes on hover */ }
{ ! loadingServer[ id ] && (
<div
className={ cx(
'opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100',
'row-start-1 col-start-1 place-self-center'
) }
>
{ running ? rectangle : triangle }
</div>
) }
</button>
</Tooltip>
);
}
function SiteItem( { site }: { site: SiteDetails } ) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/tests/copy-text-button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe( 'CopyTextButton', () => {

test( 'the button is present, and not the confirmation', () => {
render( <CopyTextButton text="Sample Text" copyConfirmation="Copied!" /> );
expect( screen.getByRole( 'button', { name: 'copy to clipboard' } ) ).toBeVisible();
expect( screen.getByRole( 'button', { name: 'Copy to clipboard' } ) ).toBeVisible();
expect( screen.queryByRole( 'alert' ) ).toBe( null );
} );

Expand All @@ -27,7 +27,7 @@ describe( 'CopyTextButton', () => {
const mockCopyText = jest.fn();
( getIpcApi as jest.Mock ).mockReturnValue( { copyText: mockCopyText } );
render( <CopyTextButton text="Sample Text" copyConfirmation="Copied!" /> );
expect( screen.getByRole( 'button', { name: 'copy to clipboard' } ) ).toBeVisible();
expect( screen.getByRole( 'button', { name: 'Copy to clipboard' } ) ).toBeVisible();
await user.click( screen.getByRole( 'button' ) );
expect( screen.getByRole( 'alert' ) ).toHaveTextContent( 'Copied!' );
expect( mockCopyText ).toHaveBeenCalledWith( 'Sample Text' );
Expand Down
10 changes: 5 additions & 5 deletions src/components/tests/topbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ describe( 'TopBar', () => {
const authenticate = jest.fn();
( useAuth as jest.Mock ).mockReturnValue( { isAuthenticated: false, authenticate } );
await act( async () => render( <TopBar onToggleSidebar={ jest.fn() } /> ) );
expect( screen.queryByRole( 'button', { name: 'Account' } ) ).not.toBeInTheDocument();
expect( screen.getByRole( 'button', { name: 'Log in' } ) ).toBeVisible();
expect( screen.queryByRole( 'button', { name: 'Open settings' } ) ).not.toBeInTheDocument();
expect( screen.getByRole( 'button', { name: 'Open settings to log in' } ) ).toBeVisible();
} );

it( 'Test authenticated TopBar does not have the log in button and it has the settings and account buttons', async () => {
( useAuth as jest.Mock ).mockReturnValue( { isAuthenticated: true } );
await act( async () => render( <TopBar onToggleSidebar={ jest.fn() } /> ) );
expect( screen.queryByRole( 'button', { name: 'Log in' } ) ).not.toBeInTheDocument();
expect( screen.getByRole( 'button', { name: 'Account' } ) ).toBeVisible();
expect( screen.getByRole( 'button', { name: 'Open settings' } ) ).toBeVisible();
} );

it( 'shows offline indicator', async () => {
Expand All @@ -58,7 +58,7 @@ describe( 'TopBar', () => {

render( <TopBar onToggleSidebar={ jest.fn() } /> );

const helpIconButton = screen.getByRole( 'button', { name: 'Help' } );
const helpIconButton = screen.getByRole( 'button', { name: 'Get help' } );
await user.click( helpIconButton );
await waitFor( () =>
expect( mockOpenURL ).toHaveBeenCalledWith(
Expand All @@ -75,7 +75,7 @@ describe( 'TopBar', () => {

render( <TopBar onToggleSidebar={ onToggleSidebar } /> );

const toggleButton = screen.getByRole( 'button', { name: 'Toggle Sidebar' } );
const toggleButton = screen.getByRole( 'button', { name: 'Toggle sidebar' } );
await user.click( toggleButton );

expect( onToggleSidebar ).toHaveBeenCalledTimes( 1 );
Expand Down
11 changes: 7 additions & 4 deletions src/components/top-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ function Authentication() {
return (
<Button
onClick={ () => getIpcApi().showUserSettings() }
aria-label={ __( 'Account' ) }
aria-label={ __( 'Open settings' ) }
tooltipText={ __( 'Open settings' ) }
variant="icon"
className="text-white hover:!text-white !px-1 py-1 !h-6 gap-2"
>
Expand All @@ -66,7 +67,8 @@ function Authentication() {
return (
<Button
onClick={ () => getIpcApi().showUserSettings() }
aria-label={ __( 'Log in' ) }
aria-label={ __( 'Open settings to log in' ) }
tooltipText={ __( 'Open settings to log in' ) }
className="flex gap-x-2 justify-between w-full text-white rounded !px-0 !py-0 h-auto active:!text-white hover:!text-white hover:underline items-center"
>
<WordPressLogo />
Expand All @@ -88,7 +90,8 @@ export default function TopBar( { onToggleSidebar }: TopBarProps ) {
className="app-no-drag-region"
onClick={ onToggleSidebar }
variant="icon"
aria-label={ __( 'Toggle Sidebar' ) }
aria-label={ __( 'Toggle sidebar' ) }
tooltipText={ __( 'Toggle sidebar' ) }
>
<Icon className="text-white" icon={ drawerLeft } size={ 24 } />
</Button>
Expand All @@ -98,7 +101,7 @@ export default function TopBar( { onToggleSidebar }: TopBarProps ) {

<div className="app-no-drag-region flex items-center space-x-4">
<Authentication />
<Button onClick={ openDocs } aria-label={ __( 'Help' ) } variant="icon">
<Button onClick={ openDocs } aria-label={ __( 'Get help' ) } variant="icon">
<Icon className="text-white" size={ 24 } icon={ help } />
</Button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/user-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const UserInfo = ( {
<div className="flex w-full items-center gap-3">
<Button
onClick={ () => getIpcApi().openURL( WPCOM_PROFILE_URL ) }
aria-label={ __( 'Profile link' ) }
aria-label={ __( 'Edit profile' ) }
variant="icon"
>
<Gravatar detailedDefaultImage size={ 32 } isBlack />
Expand Down