Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 49 additions & 38 deletions apps/ui/src/components/blueprint-selector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface BlueprintSelectorProps {
featured: FeaturedBlueprint[] | undefined;
isFeaturedLoading: boolean;
onPick: ( blueprint: PickedBlueprint ) => void;
onPickEmpty: () => void;
}

const FILE_ACCEPT = 'application/json,.json,application/zip,.zip';
Expand All @@ -34,6 +35,7 @@ export function BlueprintSelector( {
featured,
isFeaturedLoading,
onPick,
onPickEmpty,
}: BlueprintSelectorProps ) {
const connector = useConnector();
const [ uploadError, setUploadError ] = useState< string | null >( null );
Expand Down Expand Up @@ -183,7 +185,7 @@ export function BlueprintSelector( {
</section>

<section className={ styles.section }>
<h2 className={ styles.sectionTitle }>{ __( 'Featured blueprints' ) }</h2>
<h2 className={ styles.sectionTitle }>{ __( 'Choose a starting point' ) }</h2>
{ isFeaturedLoading && (
<p className={ styles.featuredHint }>{ __( 'Loading featured blueprints…' ) }</p>
) }
Expand All @@ -192,45 +194,54 @@ export function BlueprintSelector( {
{ __( 'No featured blueprints available right now.' ) }
</p>
) }
{ featured && featured.length > 0 && (
<ul className={ styles.grid }>
{ featured.map( ( item ) => (
<li key={ item.slug } className={ styles.cardWrapper }>
<button
<ul className={ styles.grid }>
<li className={ styles.cardWrapper }>
<button type="button" className={ styles.card } onClick={ onPickEmpty }>
<span className={ styles.emptySiteMedia } aria-hidden="true" />
<div className={ styles.cardBody }>
<h3 className={ styles.cardTitle }>{ __( 'Empty site' ) }</h3>
<p className={ styles.cardExcerpt }>
{ __( 'Start with a clean WordPress install and build from scratch.' ) }
</p>
</div>
</button>
</li>
{ featured?.map( ( item ) => (
<li key={ item.slug } className={ styles.cardWrapper }>
<button
type="button"
className={ styles.card }
onClick={ () => handleFeaturedClick( item ) }
>
{ item.image && (
<img className={ styles.cardImage } src={ item.image } alt="" loading="lazy" />
) }
<div className={ styles.cardBody }>
<h3 className={ styles.cardTitle }>{ item.title }</h3>
<p className={ styles.cardExcerpt }>{ item.excerpt }</p>
</div>
</button>
{ item.playgroundUrl && (
<Button
type="button"
className={ styles.card }
onClick={ () => handleFeaturedClick( item ) }
>
{ item.image && (
<img className={ styles.cardImage } src={ item.image } alt="" loading="lazy" />
variant="minimal"
tone="neutral"
size="small"
className={ styles.previewButton }
onClick={ ( event ) => handlePreviewClick( event, item ) }
aria-label={ sprintf(
// translators: %s is the blueprint title.
__( 'Preview %s in Playground' ),
item.title
) }
<div className={ styles.cardBody }>
<h3 className={ styles.cardTitle }>{ item.title }</h3>
<p className={ styles.cardExcerpt }>{ item.excerpt }</p>
</div>
</button>
{ item.playgroundUrl && (
<Button
type="button"
variant="minimal"
tone="neutral"
size="small"
className={ styles.previewButton }
onClick={ ( event ) => handlePreviewClick( event, item ) }
aria-label={ sprintf(
// translators: %s is the blueprint title.
__( 'Preview %s in Playground' ),
item.title
) }
>
<Icon icon={ external } />
<span>{ __( 'Preview' ) }</span>
</Button>
) }
</li>
) ) }
</ul>
) }
>
<Icon icon={ external } />
<span>{ __( 'Preview' ) }</span>
</Button>
) }
</li>
) ) }
</ul>
</section>
</div>
);
Expand Down
20 changes: 20 additions & 0 deletions apps/ui/src/components/blueprint-selector/style.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,26 @@
background: #f0f0f0;
}

.emptySiteMedia {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
background:
linear-gradient(
90deg,
color-mix(in srgb, var(--wpds-color-stroke-interactive-brand, #3858e9) 18%, transparent)
1px,
transparent 1px
),
linear-gradient(
color-mix(in srgb, var(--wpds-color-stroke-interactive-brand, #3858e9) 18%, transparent)
1px,
transparent 1px
),
var(--wpds-color-bg-surface-neutral, #f6f7f7);
background-size: 24px 24px;
}

.cardBody {
display: flex;
flex-direction: column;
Expand Down
9 changes: 6 additions & 3 deletions apps/ui/src/components/onboarding-layout/style.module.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
.root {
height: 100vh;
box-sizing: border-box;
min-height: 100vh;
padding-block: var(--wpds-dimension-padding-3xl);
position: relative;
}

.content {
box-sizing: border-box;
max-width: 640px;
width: 100%;
padding: var(--wpds-dimension-padding-3xl);
padding-inline: var(--wpds-dimension-padding-3xl);
}

/* `wide` variant — used by content-heavy onboarding pages like the blueprint
Expand All @@ -16,7 +19,7 @@
}

.close {
position: absolute;
position: fixed;
top: 16px;
right: 16px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,15 @@ function OnboardingBlueprintPage() {
if ( activeStep === 'select' ) {
return (
<div className={ styles.page }>
<h1 className={ styles.title }>{ __( 'Start from a Blueprint' ) }</h1>
<h1 className={ styles.title }>{ __( 'Build a new site' ) }</h1>
<p className={ styles.subtitle }>
{ __(
'Pick a featured Blueprint or drop in your own to provision plugins, content, and settings.'
) }
{ __( 'Start from scratch or choose a Blueprint to provision plugins and settings.' ) }
</p>
<BlueprintSelector
featured={ featured.data }
isFeaturedLoading={ featured.isLoading }
onPick={ handlePick }
onPickEmpty={ () => void navigate( { to: '/onboarding/create' } ) }
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function CreateSitePage() {
initialValues={ proposedName ? { name: proposedName } : undefined }
existingDomainNames={ existingDomainNames ?? [] }
onSubmit={ handleSubmit }
onCancel={ () => void navigate( { to: '/onboarding' } ) }
onCancel={ () => void navigate( { to: '/onboarding/blueprint' } ) }
isSubmitting={ createSite.isPending }
submitError={ submitError }
/>
Expand Down
12 changes: 2 additions & 10 deletions apps/ui/src/ui-classic/router/route-onboarding-home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,10 @@ function OnboardingHomePage() {
{ __( 'WordPress can power anything. What are you building?' ) }
</p>
<div className={ styles.cards }>
<Link to="/onboarding/create" className={ styles.card }>
<h3 className={ styles.cardTitle }>{ __( 'Create new' ) }</h3>
<p className={ styles.cardBody }>
{ __( 'Start fresh with a blank site and build it with AI' ) }
</p>
</Link>
<Link to="/onboarding/blueprint" className={ styles.card }>
<h3 className={ styles.cardTitle }>{ __( 'Start from a blueprint' ) }</h3>
<h3 className={ styles.cardTitle }>{ __( 'Build a new site' ) }</h3>
<p className={ styles.cardBody }>
{ __(
'Pick a featured blueprint or drop in your own to provision plugins, content, and settings.'
) }
{ __( 'Start from scratch or choose a Blueprint to provision plugins and settings.' ) }
</p>
</Link>
<Link to="/onboarding/import" className={ styles.card }>
Expand Down
1 change: 1 addition & 0 deletions apps/ui/src/ui-desks/onboarding/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ export function DeskOnboardingBlueprint() {
featured={ featured.data }
isFeaturedLoading={ featured.isLoading }
onPick={ handlePick }
onPickEmpty={ () => void navigate( { to: '/onboarding/create' } ) }
/>
</div>
</OnboardingLayout>
Expand Down