diff --git a/client/landing/gutenboarding/components/card/README.md b/client/landing/gutenboarding/components/card/README.md
new file mode 100644
index 00000000000000..915f90f70e057d
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/README.md
@@ -0,0 +1,104 @@
+# THIS IS TEMPORARY
+
+This is an unreleased component copied from
+[`@wordpress/components`](https://github.com/WordPress/gutenberg/tree/master/packages/components/src/card).
+
+_It should not be heavily modified, it will be replaced with the published component soon._
+
+# Card
+
+Card provides a flexible and extensible content container.
+
+## Usage
+
+```jsx
+import { Card, CardBody } from '@wordpress/components';
+
+const Example = () => (
+
+ ...
+
+);
+```
+
+## Props
+
+| Name | Type | Default | Description |
+| -------------- | --------- | -------- | ------------------------------------------------- |
+| `isBorderless` | `boolean` | `false` | Determines the border style of the card. |
+| `isElevated` | `boolean` | `false` | Determines the elevation style of the card. |
+| `size` | `string` | `medium` | Determines the amount of padding within the card. |
+
+## Sub-Components
+
+This component provides a collection of sub-component that can be used to compose various interfaces.
+
+- [``](./docs/body.md)
+- [``](./docs/divider.md)
+- [``](./docs/footer.md)
+- [``](./docs/header.md)
+- [``](./docs/media.md)
+
+### Sub-Components Example
+
+```jsx
+import {
+ Card,
+ CardBody,
+ CardDivider,
+ CardFooter,
+ CardHeader,
+ CardMedia
+} from '@wordpress/components';
+
+const Example = () => (
+
+
+ ...
+
+
+ ...
+
+
+
+ ...
+
+
+
+
+
+ ...
+
+
+);
+```
+
+### Context
+
+``'s sub-components are connected to `` using [Context](https://reactjs.org/docs/context.html). Certain props like `size` and `variant` are passed through to the sub-components.
+
+In the following example, the `` will render with a size of `small`:
+
+```jsx
+import { Card, CardBody } from '@wordpress/components';
+
+const Example = () => (
+
+ ...
+
+);
+```
+
+These sub-components are designed to be flexible. The Context props can be overridden by the sub-component(s) as required. In the following example, the last `` will render it's specified size:
+
+```jsx
+import { Card, CardBody } from '@wordpress/components';
+
+const Example = () => (
+
+ ...
+ ...
+ ...
+
+);
+```
diff --git a/client/landing/gutenboarding/components/card/body.js b/client/landing/gutenboarding/components/card/body.js
new file mode 100644
index 00000000000000..3949340c14349c
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/body.js
@@ -0,0 +1,33 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import classnames from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { BodyUI } from './styles/card-styles';
+import { useCardContext } from './context';
+
+export const defaultProps = {
+ isShady: false,
+ size: 'medium',
+};
+
+export function CardBody( props ) {
+ const { className, isShady, ...additionalProps } = props;
+ const mergedProps = { ...defaultProps, ...useCardContext(), ...props };
+ const { size } = mergedProps;
+
+ const classes = classnames(
+ 'components-card__body',
+ isShady && 'is-shady',
+ size && `is-size-${ size }`,
+ className
+ );
+
+ return ;
+}
+
+export default CardBody;
diff --git a/client/landing/gutenboarding/components/card/context.js b/client/landing/gutenboarding/components/card/context.js
new file mode 100644
index 00000000000000..9cbe600ff435b0
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/context.js
@@ -0,0 +1,7 @@
+/**
+ * External dependencies
+ */
+import { createContext, useContext } from '@wordpress/element';
+
+export const CardContext = createContext( {} );
+export const useCardContext = () => useContext( CardContext );
diff --git a/client/landing/gutenboarding/components/card/divider.js b/client/landing/gutenboarding/components/card/divider.js
new file mode 100644
index 00000000000000..d5ee214c2dffdb
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/divider.js
@@ -0,0 +1,22 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import classnames from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { DividerUI } from './styles/card-styles';
+
+export function CardDivider( props ) {
+ const { className, ...additionalProps } = props;
+
+ const classes = classnames( 'components-card__divider', className );
+
+ return (
+
+ );
+}
+
+export default CardDivider;
diff --git a/client/landing/gutenboarding/components/card/footer.js b/client/landing/gutenboarding/components/card/footer.js
new file mode 100644
index 00000000000000..e0dcc04eb27f11
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/footer.js
@@ -0,0 +1,35 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import classnames from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { FooterUI } from './styles/card-styles';
+import { useCardContext } from './context';
+
+export const defaultProps = {
+ isBorderless: false,
+ isShady: false,
+ size: 'medium',
+};
+
+export function CardFooter( props ) {
+ const { className, isShady, ...additionalProps } = props;
+ const mergedProps = { ...defaultProps, ...useCardContext(), ...props };
+ const { isBorderless, size } = mergedProps;
+
+ const classes = classnames(
+ 'components-card__footer',
+ isBorderless && 'is-borderless',
+ isShady && 'is-shady',
+ size && `is-size-${ size }`,
+ className
+ );
+
+ return ;
+}
+
+export default CardFooter;
diff --git a/client/landing/gutenboarding/components/card/header.js b/client/landing/gutenboarding/components/card/header.js
new file mode 100644
index 00000000000000..fd746a2ca29a45
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/header.js
@@ -0,0 +1,35 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import classnames from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { HeaderUI } from './styles/card-styles';
+import { useCardContext } from './context';
+
+export const defaultProps = {
+ isBorderless: false,
+ isShady: false,
+ size: 'medium',
+};
+
+export function CardHeader( props ) {
+ const { className, isShady, ...additionalProps } = props;
+ const mergedProps = { ...defaultProps, ...useCardContext(), ...props };
+ const { isBorderless, size } = mergedProps;
+
+ const classes = classnames(
+ 'components-card__header',
+ isBorderless && 'is-borderless',
+ isShady && 'is-shady',
+ size && `is-size-${ size }`,
+ className
+ );
+
+ return ;
+}
+
+export default CardHeader;
diff --git a/client/landing/gutenboarding/components/card/index.js b/client/landing/gutenboarding/components/card/index.js
new file mode 100644
index 00000000000000..ee4ed0607b7fe4
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/index.js
@@ -0,0 +1,46 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import classnames from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { CardContext } from './context';
+import { CardUI } from './styles/card-styles';
+
+export const defaultProps = {
+ isBorderless: false,
+ isElevated: false,
+ size: 'medium',
+};
+
+export function Card( props ) {
+ const { className, isBorderless, isElevated, size, ...additionalProps } = props;
+ const { Provider } = CardContext;
+
+ const contextProps = {
+ isBorderless,
+ isElevated,
+ size,
+ };
+
+ const classes = classnames(
+ 'components-card',
+ isBorderless && 'is-borderless',
+ isElevated && 'is-elevated',
+ size && `is-size-${ size }`,
+ className
+ );
+
+ return (
+
+
+
+ );
+}
+
+Card.defaultProps = defaultProps;
+
+export default Card;
diff --git a/client/landing/gutenboarding/components/card/media.js b/client/landing/gutenboarding/components/card/media.js
new file mode 100644
index 00000000000000..c473b3f051b3b2
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/media.js
@@ -0,0 +1,20 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import classnames from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { MediaUI } from './styles/card-styles';
+
+export function CardMedia( props ) {
+ const { className, ...additionalProps } = props;
+
+ const classes = classnames( 'components-card__media', className );
+
+ return ;
+}
+
+export default CardMedia;
diff --git a/client/landing/gutenboarding/components/card/styles/card-styles.js b/client/landing/gutenboarding/components/card/styles/card-styles.js
new file mode 100644
index 00000000000000..db20cd46a2a801
--- /dev/null
+++ b/client/landing/gutenboarding/components/card/styles/card-styles.js
@@ -0,0 +1,167 @@
+/**
+ * External dependencies
+ */
+import styled from '@emotion/styled';
+
+/**
+ * Internal dependencies
+ */
+import { HorizontalRule } from '@wordpress/components';
+
+export const styleProps = {
+ borderColor: color( 'lightGray.500' ),
+ borderRadius: '3px',
+ backgroundShady: color( 'lightGray.200' ),
+};
+
+const { borderColor, borderRadius, backgroundShady } = styleProps;
+
+export const CardUI = styled.div`
+ background: ${color( 'white' )};
+ box-sizing: border-box;
+ border-radius: ${borderRadius};
+ border: 1px solid ${borderColor};
+
+ ${handleBorderless};
+
+ &.is-elevated {
+ box-shadow: 0px 1px 3px 0px rgba( 0, 0, 0, 0.2 ), 0px 1px 1px 0px rgba( 0, 0, 0, 0.14 ),
+ 0px 2px 1px -1px rgba( 0, 0, 0, 0.12 );
+ }
+`;
+
+export const HeaderUI = styled.div`
+ border-bottom: 1px solid ${borderColor};
+ border-top-left-radius: ${borderRadius};
+ border-top-right-radius: ${borderRadius};
+ box-sizing: border-box;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ ${headerFooterSizes};
+ ${handleBorderless};
+ ${handleShady};
+`;
+
+export const MediaUI = styled.div`
+ box-sizing: border-box;
+ overflow: hidden;
+
+ & > img,
+ & > iframe {
+ display: block;
+ height: auto;
+ max-width: 100%;
+ width: 100%;
+ }
+
+ &:first-of-type {
+ border-top-left-radius: ${borderRadius};
+ border-top-right-radius: ${borderRadius};
+ }
+
+ &:last-of-type {
+ border-bottom-left-radius: ${borderRadius};
+ border-bottom-right-radius: ${borderRadius};
+ }
+`;
+
+export const BodyUI = styled.div`
+ box-sizing: border-box;
+
+ ${bodySize};
+ ${handleShady};
+`;
+
+export const FooterUI = styled.div`
+ border-top: 1px solid ${borderColor};
+ border-bottom-left-radius: ${borderRadius};
+ border-bottom-right-radius: ${borderRadius};
+ box-sizing: border-box;
+
+ &:first-of-type {
+ border-top: none;
+ }
+
+ ${headerFooterSizes};
+ ${handleBorderless};
+ ${handleShady};
+`;
+
+export const DividerUI = styled( HorizontalRule )`
+ all: unset;
+ border-top: 1px solid ${borderColor};
+ box-sizing: border-box;
+ display: block;
+ height: 0;
+ width: 100%;
+`;
+
+export function bodySize() {
+ return `
+ &.is-size {
+ &-large {
+ padding: 28px;
+ }
+ &-medium {
+ padding: 20px;
+ }
+ &-small {
+ padding: 12px;
+ }
+ &-extraSmall {
+ padding: 8px;
+ }
+ }
+ `;
+}
+
+export function headerFooterSizes() {
+ return `
+ &.is-size {
+ &-large {
+ padding: 20px 28px;
+ }
+ &-medium {
+ padding: 12px 20px;
+ }
+ &-small {
+ padding: 8px 12px;
+ }
+ &-extraSmall {
+ padding: 4px 8px;
+ }
+ }
+ `;
+}
+
+export function handleBorderless() {
+ return `
+ &.is-borderless {
+ border: none;
+ }
+ `;
+}
+
+export function handleShady() {
+ return `
+ &.is-shady {
+ background: ${ backgroundShady };
+ }
+ `;
+}
+
+// hack around https://github.com/WordPress/gutenberg/blob/master/packages/components/src/utils/colors.js
+function color( value ) {
+ switch ( value ) {
+ case 'lightGray.500':
+ return '#e2e4e7';
+ case 'lightGray.200':
+ return '#f3f4f5';
+ case 'white':
+ return '#fff';
+ }
+ return '#000';
+}
diff --git a/client/landing/gutenboarding/gutenboard.tsx b/client/landing/gutenboarding/gutenboard.tsx
index 9a4bc37c7691b2..a537bb35cb7937 100644
--- a/client/landing/gutenboarding/gutenboard.tsx
+++ b/client/landing/gutenboarding/gutenboard.tsx
@@ -105,7 +105,7 @@ export function Gutenboard() {
value={ [ onboardingBlock.current ] }
settings={ { templateLock: 'all' } }
>
-
+
{
const siteVertical = useSelect(
@@ -23,20 +26,23 @@ export default () => {
const homepageTemplates = templates.filter( template => template.category === 'home' );
- const [ previewedTemplate, setPreviewedTemplate ] = useState< string | null >( null );
+ const [ selectedDesign, setSelectedDesign ] = useState< string | undefined >();
return (
-
-
+
+ { homepageTemplates.map( template => (
+
setSelectedDesign( template.slug ) }
+ >
+
+
+
+
+ ) ) }
);
};
diff --git a/client/landing/gutenboarding/onboarding-block/design-selector/style.scss b/client/landing/gutenboarding/onboarding-block/design-selector/style.scss
new file mode 100644
index 00000000000000..741f4f4706fc65
--- /dev/null
+++ b/client/landing/gutenboarding/onboarding-block/design-selector/style.scss
@@ -0,0 +1,18 @@
+.design-selector {
+ display: grid;
+ grid-gap: 4.5em;
+
+ @include breakpoint( '>660px' ) {
+ // stylelint-disable unit-whitelist
+ grid-template-columns: repeat( 2, 1fr );
+ // stylelint-enable unit-whitelist
+ }
+}
+
+.design-selector__design-option {
+ transition: transform 100ms ease-in-out;
+
+ &.is-selected {
+ transform: scale( 1.1 );
+ }
+}
diff --git a/client/landing/gutenboarding/style.scss b/client/landing/gutenboarding/style.scss
index 3b59734079a330..20d2f138bc93c7 100644
--- a/client/landing/gutenboarding/style.scss
+++ b/client/landing/gutenboarding/style.scss
@@ -13,6 +13,10 @@ $admin-sidebar-width-collapsed: 0;
@import '~@wordpress/block-editor/src/style.scss';
@import '~@wordpress/format-library/src/style.scss';
+.gutenboard__edit-post-layout-content {
+ position: static;
+}
+
.wp-block {
max-width: 1100px; // Overrides default $content-width
}