Skip to content

Commit 7858b1e

Browse files
authored
Fix empty Studio state with a new page (#1690)
1 parent f8a7609 commit 7858b1e

File tree

9 files changed

+121
-19
lines changed

9 files changed

+121
-19
lines changed

jest.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
},
1717
],
1818
'^.+\\.m?js$': [ 'babel-jest', { presets: [ '@babel/preset-env' ] } ],
19+
"^.+\\.svg$": 'jest-transform-stub',
1920
},
2021
transformIgnorePatterns: [ 'node_modules/(?!(@php-wasm|@wp-playground)/)' ],
2122
moduleNameMapper: {

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@
150150
"fs-extra": "11.1.1",
151151
"hpagent": "1.2.0",
152152
"http-proxy": "^1.18.1",
153+
"jest-transform-stub": "^2.0.0",
153154
"lockfile": "^1.0.4",
154155
"lodash": "^4.17.21",
155156
"node-fetch": "^2.7.0",
Lines changed: 48 additions & 0 deletions
Loading
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useI18n } from '@wordpress/react-i18n';
2+
import emptyStudioIllustration from 'src/components/empty-studio/empty-studio.svg';
3+
import AddSite from 'src/modules/add-site';
4+
5+
export function EmptyStudio() {
6+
const { __ } = useI18n();
7+
8+
return (
9+
<div className="w-full h-full flex items-center app-no-drag-region">
10+
<div className="mx-auto px-[85px] flex items-center gap-[44px] max-w-[786px]">
11+
<div>
12+
<div className="text-[16px] font-semibold text-black mb-[4px]">
13+
{ __( 'Ready for a new start?' ) }
14+
</div>
15+
<p className="text-[13px] text-gray-700 mb-[32px]">
16+
{ __( "You don't have any sites right now. Add a new one to get started again." ) }
17+
</p>
18+
19+
<AddSite variant="primary" />
20+
</div>
21+
22+
<img src={ emptyStudioIllustration } alt={ __( 'Empty Studio illustration' ) } />
23+
</div>
24+
</div>
25+
);
26+
}

src/components/main-sidebar.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { __ } from '@wordpress/i18n';
22
import { RunningSites } from 'src/components/running-sites';
33
import SiteMenu from 'src/components/site-menu';
4+
import { useSiteDetails } from 'src/hooks/use-site-details';
45
import { isMac } from 'src/lib/app-globals';
56
import { cx } from 'src/lib/cx';
67
import AddSite from 'src/modules/add-site';
@@ -10,6 +11,8 @@ interface MainSidebarProps {
1011
}
1112

1213
export default function MainSidebar( { className }: MainSidebarProps ) {
14+
const { data: localSites } = useSiteDetails();
15+
1316
return (
1417
<div
1518
data-testid="main-sidebar"
@@ -20,22 +23,28 @@ export default function MainSidebar( { className }: MainSidebarProps ) {
2023
className
2124
) }
2225
>
23-
<div className="flex flex-col h-full">
24-
<div
25-
className={ cx(
26-
'flex-1 overflow-y-auto sites-scrollbar app-no-drag-region',
27-
isMac() ? 'ms-4' : 'ms-3'
28-
) }
29-
>
30-
<SiteMenu />
26+
{ ! localSites.length ? (
27+
<div className="flex h-full px-[20px] justify-center items-center app-no-drag-region text-center text-[12px] text-a8c-gray-50">
28+
{ __( 'Your sites will show up here once you create them' ) }
3129
</div>
32-
<div className="flex flex-col gap-4 pt-5 border-white border-t border-opacity-10 app-no-drag-region">
33-
<RunningSites />
34-
<div className={ cx( isMac() ? 'mx-5' : 'mx-4' ) }>
35-
<AddSite className="min-w-[168px] w-full mb-4" />
30+
) : (
31+
<div className="flex flex-col h-full">
32+
<div
33+
className={ cx(
34+
'flex-1 overflow-y-auto sites-scrollbar app-no-drag-region',
35+
isMac() ? 'ms-4' : 'ms-3'
36+
) }
37+
>
38+
<SiteMenu />
39+
</div>
40+
<div className="flex flex-col gap-4 pt-5 border-white border-t border-opacity-10 app-no-drag-region">
41+
<RunningSites />
42+
<div className={ cx( isMac() ? 'mx-5' : 'mx-4' ) }>
43+
<AddSite className="min-w-[168px] w-full mb-4" />
44+
</div>
3645
</div>
3746
</div>
38-
</div>
47+
) }
3948
</div>
4049
);
4150
}

src/components/site-content-tabs.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ContentTabImportExport } from 'src/components/content-tab-import-export
55
import { ContentTabOverview } from 'src/components/content-tab-overview';
66
import { ContentTabPreviews } from 'src/components/content-tab-previews';
77
import { ContentTabSettings } from 'src/components/content-tab-settings';
8+
import { EmptyStudio } from 'src/components/empty-studio';
89
import Header from 'src/components/header';
910
import { SiteLoadingIndicator } from 'src/components/site-loading-indicator';
1011
import { MIN_WIDTH_CLASS_TO_MEASURE } from 'src/constants';
@@ -15,11 +16,15 @@ import { cx } from 'src/lib/cx';
1516
import { ContentTabSync } from 'src/modules/sync';
1617

1718
export function SiteContentTabs() {
18-
const { selectedSite } = useSiteDetails();
19+
const { selectedSite, data: localSites } = useSiteDetails();
1920
const { importState } = useImportExport();
2021
const { tabs, selectedTab, setSelectedTab } = useContentTabs();
2122
const { __ } = useI18n();
2223

24+
if ( ! localSites.length ) {
25+
return <EmptyStudio />;
26+
}
27+
2328
if ( ! selectedSite ) {
2429
return (
2530
<div className="w-full h-full flex items-center justify-center app-no-drag-region">

src/components/tests/site-content-tabs.test.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ describe( 'SiteContentTabs', () => {
5656
( useSiteDetails as jest.Mock ).mockReturnValue( {
5757
selectedSite,
5858
snapshots: [],
59+
data: [ selectedSite ],
5960
loadingServer: {},
6061
} );
6162
await act( async () => renderWithProvider( <SiteContentTabs /> ) );
@@ -71,6 +72,7 @@ describe( 'SiteContentTabs', () => {
7172
( useSiteDetails as jest.Mock ).mockReturnValue( {
7273
selectedSite,
7374
snapshots: [],
75+
data: [ selectedSite ],
7476
loadingServer: {},
7577
} );
7678
await act( async () => renderWithProvider( <SiteContentTabs /> ) );
@@ -81,7 +83,7 @@ describe( 'SiteContentTabs', () => {
8183
expect( screen.queryByRole( 'tab', { name: 'Assistant', selected: false } ) ).toBeVisible();
8284
expect( screen.queryByRole( 'tab', { name: 'Backup', selected: false } ) ).toBeNull();
8385
} );
84-
it( 'should render a "No Site" screen if selected site is absent', async () => {
86+
it( 'should render a "No Site" screen if all sites are removed', async () => {
8587
( useSiteDetails as jest.Mock ).mockReturnValue( {
8688
undefined,
8789
snapshots: [],
@@ -95,6 +97,8 @@ describe( 'SiteContentTabs', () => {
9597
expect( screen.queryByRole( 'tab', { name: 'Launchpad' } ) ).toBeNull();
9698
expect( screen.queryByRole( 'tab', { name: 'Publish' } ) ).toBeNull();
9799
expect( screen.queryByRole( 'tab', { name: 'Export' } ) ).toBeNull();
98-
expect( screen.getByText( 'Select a site to view details.' ) ).toBeVisible();
100+
expect(
101+
screen.getByText( "You don't have any sites right now. Add a new one to get started again." )
102+
).toBeVisible();
99103
} );
100104
} );

src/modules/add-site/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Navigator, useNavigator } from '@wordpress/components';
33
import { sprintf } from '@wordpress/i18n';
44
import { useI18n } from '@wordpress/react-i18n';
55
import { FormEvent, useCallback, useEffect, useMemo, useState } from 'react';
6-
import Button from 'src/components/button';
6+
import Button, { ButtonVariant } from 'src/components/button';
77
import { FullscreenModal } from 'src/components/fullscreen-modal';
88
import { useAddSite } from 'src/hooks/use-add-site';
99
import { useFeatureFlags } from 'src/hooks/use-feature-flags';
@@ -27,6 +27,7 @@ import Stepper from './components/stepper';
2727

2828
interface AddSiteProps {
2929
className?: string;
30+
variant?: ButtonVariant;
3031
}
3132

3233
type BlueprintsData = ReturnType< typeof useGetBlueprints >[ 'data' ];
@@ -190,7 +191,7 @@ function NavigationContent( props: NavigationContentProps ) {
190191
);
191192
}
192193

193-
export default function AddSite( { className }: AddSiteProps ) {
194+
export default function AddSite( { className, variant = 'outlined' }: AddSiteProps ) {
194195
const { __ } = useI18n();
195196
const { enableBlueprints } = useFeatureFlags();
196197
const [ showModal, setShowModal ] = useState( false );
@@ -353,7 +354,7 @@ export default function AddSite( { className }: AddSiteProps ) {
353354
</Navigator>
354355
</FullscreenModal>
355356
<Button
356-
variant="outlined"
357+
variant={ variant }
357358
className={ className }
358359
onClick={ openModal }
359360
disabled={ isAnySiteProcessing }

0 commit comments

Comments
 (0)