Skip to content

Commit

Permalink
A4A: Implement Hosting page v3 header. (#97162)
Browse files Browse the repository at this point in the history
* Initial header implementation.

* Implement navigation tab.

* Add Hosting content from v2.

* Move hero banner at the layout top wrapper.

* Add some gap on the header content

* Fix hovering style for selected tab.

* Hide title on scroll.

* Add new migration offer banner.

* Hide migration offer banner on scroll.

* Make the top at sticky position.

* Fix flickering with animation.

* Minor Migration offer banner improvement.

* Additional improvement and bug fixes.

* Minor optimization on compact mode on scroll.

* Address PR comments.
  • Loading branch information
jkguidaven authored Dec 11, 2024
1 parent c780b16 commit f944e0e
Show file tree
Hide file tree
Showing 12 changed files with 735 additions and 9 deletions.
120 changes: 120 additions & 0 deletions client/a8c-for-agencies/components/a4a-migration-offer-v3/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { Button } from '@wordpress/components';
import { Icon, chevronDown } from '@wordpress/icons';
import clsx from 'clsx';
import { useTranslate } from 'i18n-calypso';
import { useCallback } from 'react';
import { useDispatch } from 'calypso/state';
import { recordTracksEvent } from 'calypso/state/analytics/actions';
import { CONTACT_URL_FOR_MIGRATION_OFFER_HASH_FRAGMENT } from '../a4a-contact-support-widget';
import { A4A_MIGRATIONS_OVERVIEW_LINK } from '../sidebar-menu/lib/constants';
import SimpleList from '../simple-list';

import './style.scss';

type Props = {
isExpanded: boolean;
onToggleView: () => void;
};

const MigrationOfferV3 = ( { isExpanded, onToggleView }: Props ) => {
const translate = useTranslate();
const dispatch = useDispatch();

const onContactUsClick = useCallback(
( e: React.MouseEvent< HTMLButtonElement > ) => {
e.stopPropagation();
dispatch( recordTracksEvent( 'a4a_migration_offer_contact_us_click' ) );
},
[ dispatch ]
);

const onSeeFullTermClick = useCallback( () => {
dispatch( recordTracksEvent( 'a4a_migration_offer_see_full_terms_click' ) );
}, [ dispatch ] );

return (
<div
className={ clsx( 'a4a-migration-offer-v3', { 'is-expanded': isExpanded } ) }
onClick={ onToggleView }
role="button"
tabIndex={ 0 }
onKeyDown={ ( event ) => {
if ( event.key === 'Enter' ) {
onToggleView();
}
} }
>
<div className="a4a-migration-offer-v3__main">
<h3 className="a4a-migration-offer-v3__title">
<span>
{ translate(
'{{b}}Limited time offer:{{/b}} Migrate your sites to Pressable or WordPress.com and earn up to $10,000!',
{
components: {
b: <b />,
},
}
) }
</span>

<Button className="a4a-migration-offer-v3__view-toggle-mobile" onClick={ onToggleView }>
<Icon icon={ chevronDown } size={ 24 } />
</Button>
</h3>

{ isExpanded && (
<div className="a4a-migration-offer-v3__body">
<SimpleList
items={ [
translate(
"{{b}}WP Engine customers:{{/b}} You will receive $100 per site, up to $10,000. You will also get credited for the remaining time on your WP Engine contract, so you won't have to pay twice.",
{
components: {
b: <b />,
},
}
),
translate(
'{{b}}For any other host:{{/b}} You will receive $100 per site migrated up to a maximum of $3,000.',
{
components: {
b: <b />,
},
}
),
] }
/>

<div className="a4a-migration-offer-v3__body-actions">
<Button
variant="primary"
href={ CONTACT_URL_FOR_MIGRATION_OFFER_HASH_FRAGMENT }
onClick={ onContactUsClick }
>
{ translate( 'Contact us to learn more' ) }
</Button>

<Button
variant="secondary"
href={ A4A_MIGRATIONS_OVERVIEW_LINK }
onClick={ onSeeFullTermClick }
>
{ translate( 'See full terms ↗' ) }
</Button>

<span className="a4a-migration-offer-v3__body-actions-footnote">
{ translate( '* Offer valid until the end of 2024' ) }
</span>
</div>
</div>
) }
</div>

<Button className="a4a-migration-offer-v3__view-toggle">
<Icon icon={ chevronDown } size={ 24 } />
</Button>
</div>
);
};

export default MigrationOfferV3;
111 changes: 111 additions & 0 deletions client/a8c-for-agencies/components/a4a-migration-offer-v3/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
@import "@wordpress/base-styles/breakpoints";
@import "@wordpress/base-styles/mixins";

.a4a-migration-offer-v3 {
display: flex;
flex-direction: row;
gap: 16px;

border-radius: 4px;
background-color: var(--color-surface);
transition: padding 0.15s linear;
padding: 8px 16px;
cursor: pointer;

@include break-medium {
padding: 20px 32px;
&.is-expanded {
padding: 20px 32px 24px;
}
}
}

.theme-a8c-for-agencies .components-button.a4a-migration-offer-v3__view-toggle {
display: none;

@include break-medium {
display: block;
}
}

.a4a-migration-offer-v3__main {
flex-direction: column;
gap: 8px;
flex-grow: 1;
}

.a4a-migration-offer-v3__title {
display: flex;
flex-direction: row;
justify-content: space-between;

@include a4a-font-heading-md($font-weight: 400);

@include break-medium {
@include a4a-font-heading-lg($font-weight: 400);
margin-block-start: 10px;
margin-block-end: 8px;
}
}

.a4a-migration-offer-v3__body {
display: flex;
gap: 24px;
align-content: center;
flex-direction: column;

.simple-list {
max-width: 800px;
margin-block-start: 24px;
margin-inline-start: 16px;
}
}

.a4a-migration-offer-v3__body-actions {
display: flex;
flex-direction: column;
gap: 8px;

@include break-xlarge {
flex-direction: row;
align-items: center;
}
}

.a4a-migration-offer-v3__body-actions-footnote {
@include a4a-font-body-sm;
}

.theme-a8c-for-agencies .components-button.a4a-migration-offer-v3__view-toggle-mobile {
display: block;

@include break-medium {
display: none;
}
}

.theme-a8c-for-agencies .components-button.a4a-migration-offer-v3__view-toggle,
.theme-a8c-for-agencies .components-button.a4a-migration-offer-v3__view-toggle-mobile {
&,
&:hover,
&:focus,
&:focus-visible {
background-color: transparent;

&:not(:focus-visible) {
border: none;
box-shadow: none;
}
}

svg {
transition: transform 0.15s cubic-bezier(0.175, 0.885, 0.32, 1.275), color 0.2s ease-in;
}
}

.a4a-migration-offer-v3.is-expanded {
.components-button.a4a-migration-offer-v3__view-toggle svg,
.components-button.a4a-migration-offer-v3__view-toggle-mobile svg {
transform: rotate(180deg);
}
}
15 changes: 13 additions & 2 deletions client/a8c-for-agencies/components/layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,18 @@ type Props = {
wide?: boolean;
withBorder?: boolean;
compact?: boolean;
onScroll?: ( e: React.UIEvent< HTMLDivElement > ) => void;
};

function MainLayout( { children, className, title, wide, withBorder, sidebarNavigation }: Props ) {
function MainLayout( {
children,
className,
title,
wide,
withBorder,
sidebarNavigation,
onScroll,
}: Props ) {
const hasLayoutColumns = React.Children.toArray( children ).some(
( child ) => React.isValidElement( child ) && child.type === LayoutColumn
);
Expand All @@ -41,7 +50,9 @@ function MainLayout( { children, className, title, wide, withBorder, sidebarNavi
<DocumentHead title={ title } />
{ sidebarNavigation }

<div className={ layoutContainerClassname }>{ children }</div>
<div className={ layoutContainerClassname } onScroll={ onScroll }>
{ children }
</div>
</Main>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const marketplaceHostingContext: Callback = ( context, next ) => {
<>
<PageViewTracker title="Marketplace > Hosting" path={ context.path } />
{ isV3Enabled ? (
<HostingOverviewV3 />
<HostingOverviewV3 section={ section } />
) : (
<HostingOverview defaultMarketplaceType={ purchaseType } section={ section } />
) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { useBreakpoint } from '@automattic/viewport-react';
import clsx from 'clsx';
import { useTranslate } from 'i18n-calypso';
import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
import MigrationOfferV3 from 'calypso/a8c-for-agencies/components/a4a-migration-offer-v3';
import NavItem from 'calypso/components/section-nav/item';
import { SectionProps } from '..';

import './style.scss';

type Props = SectionProps & {
onSectionChange: ( section: 'wpcom' | 'pressable' | 'vip' ) => void;
isCompact?: boolean;
};

export function HeroSection(
{ section, onSectionChange, isCompact }: Props,
ref: React.Ref< HTMLDivElement >
) {
const translate = useTranslate();

const isLargeScreen = useBreakpoint( '>1280px' );

const [ isMigrationOfferExpanded, setIsMigrationOfferExpanded ] = useState( false );

const onToggleMigrationOfferView = useCallback( () => {
setIsMigrationOfferExpanded( ( isExpanded ) => ! isExpanded );
}, [] );

const featureTabs = useMemo(
() => [
{
key: 'wpcom',
label: isLargeScreen ? translate( 'Standard Agency Hosting' ) : translate( 'Standard' ),
subtitle: isLargeScreen && translate( 'Optimized and hassle-free hosting' ),
selected: section === 'wpcom',
onClick: () => {
onSectionChange( 'wpcom' );
},
},
{
key: 'pressable',
label: isLargeScreen ? translate( 'Premier Agency Hosting' ) : translate( 'Premier' ),
subtitle: isLargeScreen && translate( 'Best for large-scale businesses' ),
selected: section === 'pressable',
onClick: () => {
onSectionChange( 'pressable' );
},
},
{
key: 'vip',
label: translate( 'Enterprise' ),
subtitle: isLargeScreen && translate( 'WordPress for enterprise-level demands' ),
selected: section === 'vip',
onClick: () => {
onSectionChange( 'vip' );
},
},
],
[ onSectionChange, isLargeScreen, section, translate ]
);

const navItems = featureTabs.map( ( featureTab ) => {
return (
<NavItem
className="hosting-v3-hero-section__tab"
key={ featureTab.key }
selected={ featureTab.selected }
onClick={ featureTab.onClick }
>
{ featureTab.label && (
<div className="hosting-v3__nav-item-label">{ featureTab.label }</div>
) }
{ featureTab.subtitle && (
<div className="hosting-v3__nav-item-subtitle">{ featureTab.subtitle }</div>
) }
</NavItem>
);
} );

useEffect( () => {
if ( isCompact ) {
setIsMigrationOfferExpanded( false );
}
}, [ isCompact ] );

return (
<div className={ clsx( 'hosting-v3-hero-section', { 'is-compact': isCompact } ) } ref={ ref }>
<div className="hosting-v3-hero-section__content">
<div className="hosting-v3-hero-section__heading">
{ translate(
'High Performance, Highly-Secure{{br/}}Managed WordPress Hosting for Agencies',
{
components: {
br: <br />,
},
}
) }
</div>

<MigrationOfferV3
isExpanded={ isMigrationOfferExpanded }
onToggleView={ onToggleMigrationOfferView }
/>
</div>

<ul className="hosting-v3-hero-section__tabs">{ navItems }</ul>
</div>
);
}

export default forwardRef( HeroSection );
Loading

0 comments on commit f944e0e

Please sign in to comment.