diff --git a/globals.d.ts b/globals.d.ts index 25867239f9..d5697e7fc1 100644 --- a/globals.d.ts +++ b/globals.d.ts @@ -1,5 +1,6 @@ declare module '*.svg'; declare module '*.module.css'; declare module '*.module.scss'; +declare module '*.png'; // this makes the wp or window.wp global variable available in the eyes of TypeScript declare var wp; diff --git a/src/DonationForms/FormDesigns/MultiStepFormDesign/MultiStepFormDesign.php b/src/DonationForms/FormDesigns/MultiStepFormDesign/MultiStepFormDesign.php index 217a6b406f..02b16e44f3 100644 --- a/src/DonationForms/FormDesigns/MultiStepFormDesign/MultiStepFormDesign.php +++ b/src/DonationForms/FormDesigns/MultiStepFormDesign/MultiStepFormDesign.php @@ -9,8 +9,16 @@ */ class MultiStepFormDesign extends FormDesign { + /** + * @since 3.0.0 + */ protected $isMultiStep = true; + /** + * @unreleased + */ + protected $includeHeaderInMultiStep = true; + /** * @since 3.0.0 */ diff --git a/src/DonationForms/FormDesigns/TwoPanelStepsFormLayout/TwoPanelStepsFormLayout.php b/src/DonationForms/FormDesigns/TwoPanelStepsFormLayout/TwoPanelStepsFormLayout.php new file mode 100644 index 0000000000..5e2e302d1c --- /dev/null +++ b/src/DonationForms/FormDesigns/TwoPanelStepsFormLayout/TwoPanelStepsFormLayout.php @@ -0,0 +1,37 @@ +registerDesign(ClassicFormDesign::class); $formDesignRegistrar->registerDesign(MultiStepFormDesign::class); + $formDesignRegistrar->registerDesign(TwoPanelStepsFormLayout::class); } catch (Exception $e) { Log::error('Error registering form designs', [ 'message' => $e->getMessage(), diff --git a/src/DonationForms/ViewModels/DonationFormViewModel.php b/src/DonationForms/ViewModels/DonationFormViewModel.php index 617ce83e5e..4df7b6fdec 100644 --- a/src/DonationForms/ViewModels/DonationFormViewModel.php +++ b/src/DonationForms/ViewModels/DonationFormViewModel.php @@ -193,6 +193,7 @@ private function formStatsData(): array } /** + * @unreleased added includeHeaderInMultiStep to form design export * @since 3.0.0 */ public function exports(): array @@ -227,6 +228,7 @@ public function exports(): array 'id' => $formDesign::id(), 'name' => $formDesign::name(), 'isMultiStep' => $formDesign->isMultiStep(), + 'includeHeaderInMultiStep' => $formDesign->shouldIncludeHeaderInMultiStep(), ] : null, ]), 'previewMode' => $this->previewMode, diff --git a/src/DonationForms/resources/app/DonationFormApp.tsx b/src/DonationForms/resources/app/DonationFormApp.tsx index 85a4c55346..768adc4875 100644 --- a/src/DonationForms/resources/app/DonationFormApp.tsx +++ b/src/DonationForms/resources/app/DonationFormApp.tsx @@ -58,6 +58,7 @@ function App({form}: { form: DonationForm }) { return ( + {!form.design?.includeHeaderInMultiStep && form.settings.showHeader &&
} diff --git a/src/DonationForms/resources/app/form/Header.tsx b/src/DonationForms/resources/app/form/Header.tsx index c8c0e33742..5e1b478786 100644 --- a/src/DonationForms/resources/app/form/Header.tsx +++ b/src/DonationForms/resources/app/form/Header.tsx @@ -3,6 +3,7 @@ import {withTemplateWrapper} from '../templates'; import type {GoalType} from '@givewp/forms/propTypes'; import amountFormatter from '@givewp/forms/app/utilities/amountFormatter'; import DonationFormErrorBoundary from '@givewp/forms/app/errors/boundaries/DonationFormErrorBoundary'; +import type {Form as DonationForm} from '@givewp/forms/types'; const formTemplates = window.givewp.form.templates; @@ -16,7 +17,7 @@ const HeaderImageTemplate = withTemplateWrapper(formTemplates.layouts.headerImag /** * @since 3.0.0 */ -export default function Header({form}) { +export default function Header({form}: {form: DonationForm}) { const formatGoalAmount = useCallback((amount: number) => { return amountFormatter(form.currency, { maximumFractionDigits: 0, @@ -26,6 +27,7 @@ export default function Header({form}) { return ( form.settings?.designSettingsImageUrl && ( { }; /** + * @unreleased updated to use includeHeaderInMultiStep * @since 3.0.0 */ export default function MultiStepForm({form}: {form: Form}) { - const steps = convertSectionsToSteps(form.nodes, form.settings?.showHeader); + const shouldIncludeHeaderInSteps = form.design?.includeHeaderInMultiStep && form.settings?.showHeader; + const steps = convertSectionsToSteps(form.nodes, shouldIncludeHeaderInSteps); - if (form.settings?.showHeader) { + if (shouldIncludeHeaderInSteps) { steps.unshift({ id: 0, title: null, diff --git a/src/DonationForms/resources/app/store/form-settings/index.tsx b/src/DonationForms/resources/app/store/form-settings/index.tsx index 7f47db2c47..eca6f13f12 100644 --- a/src/DonationForms/resources/app/store/form-settings/index.tsx +++ b/src/DonationForms/resources/app/store/form-settings/index.tsx @@ -12,6 +12,7 @@ type PropTypes = { donateButtonCaption: string; multiStepNextButtonText: string; multiStepFirstButtonText: string; + showHeader: boolean; }; children: ReactNode; }; diff --git a/src/DonationForms/resources/propTypes.ts b/src/DonationForms/resources/propTypes.ts index fc0a93e110..997154d582 100644 --- a/src/DonationForms/resources/propTypes.ts +++ b/src/DonationForms/resources/propTypes.ts @@ -179,6 +179,7 @@ export interface HeaderProps { Title: FC; Description: FC; Goal: FC; + isMultiStep: boolean } export interface HeaderImageProps { diff --git a/src/DonationForms/resources/registrars/templates/layouts/Header.tsx b/src/DonationForms/resources/registrars/templates/layouts/Header.tsx index 2a5ec11848..3d1d347405 100644 --- a/src/DonationForms/resources/registrars/templates/layouts/Header.tsx +++ b/src/DonationForms/resources/registrars/templates/layouts/Header.tsx @@ -1,15 +1,21 @@ import type {HeaderProps} from '@givewp/forms/propTypes'; +import cx from 'classnames'; /** * @since 3.5.0 add HeaderImage * @since 3.0.0 */ -export default function Header({HeaderImage, Title, Description, Goal}: HeaderProps) { - const {designSettingsImageStyle, designSettingsImageUrl} = window.givewp.form.hooks.useDonationFormSettings(); +export default function Header({ HeaderImage, Title, Description, Goal, isMultiStep }: HeaderProps) { + const { designSettingsImageStyle, designSettingsImageUrl } = window.givewp.form.hooks.useDonationFormSettings(); if (!designSettingsImageUrl) { return ( -
+
<Description /> <Goal /> @@ -19,7 +25,12 @@ export default function Header({HeaderImage, Title, Description, Goal}: HeaderPr return ( <div - className={`givewp-layouts-header__templates-ms givewp-layouts-header__templates-ms--${designSettingsImageStyle}`} + className={cx({ + 'givewp-layouts-header__templates': !isMultiStep, + [`givewp-layouts-header__templates--${designSettingsImageStyle}`]: !isMultiStep, + 'givewp-layouts-header__templates-ms': isMultiStep, + [`givewp-layouts-header__templates-ms--${designSettingsImageStyle}`]: isMultiStep + })} > <HeaderImageTemplates imagePosition={designSettingsImageStyle} @@ -32,7 +43,7 @@ export default function Header({HeaderImage, Title, Description, Goal}: HeaderPr ); } -function HeaderImageTemplates({imagePosition, HeaderImage, Title, Description, Goal}) { +function HeaderImageTemplates({ imagePosition, HeaderImage, Title, Description, Goal }) { switch (imagePosition) { case 'background': return ( diff --git a/src/DonationForms/resources/styles/design-settings/image.scss b/src/DonationForms/resources/styles/design-settings/image.scss index d287d8200d..d241545567 100644 --- a/src/DonationForms/resources/styles/design-settings/image.scss +++ b/src/DonationForms/resources/styles/design-settings/image.scss @@ -25,8 +25,8 @@ img { object-fit: cover; min-width: 100%; - border-top-left-radius: 0.5rem; - border-top-right-radius: 0.5rem; + border-top-left-radius: var(--givewp-rounded-8); + border-top-right-radius: var(--givewp-rounded-8); } } } @@ -98,7 +98,7 @@ } .givewp-layouts-goal { - margin-top: -1.35rem; + margin-top: -1.25rem; } } } @@ -107,8 +107,9 @@ } /* Multi Step */ -.givewp-donation-form__steps-body { +.givewp-donation-form__steps-body, .givewp-donation-form > .givewp-layouts-header { padding: 0; + background: #fff; .givewp-layouts-multiStepForm, .givewp-layouts-header__templates-ms { padding: 2rem 2rem 0 2rem; @@ -125,13 +126,6 @@ } } - .givewp-layouts-headerTitle { - color: var(--givewp-grey-900); - } - - .givewp-layouts-headerDescription { - color: var(--givewp-grey-700); - } .givewp-layouts-header__templates-ms { .givewp-layouts-headerImage { @@ -140,11 +134,19 @@ img { object-fit: cover; min-width: 100%; - border-top-left-radius: 0.5rem; - border-top-right-radius: 0.5rem; + border-top-left-radius: var(--givewp-rounded-8); + border-top-right-radius: var(--givewp-rounded-8); } } + .givewp-layouts-headerTitle { + color: var(--givewp-grey-900); + } + + .givewp-layouts-headerDescription { + color: var(--givewp-grey-700); + } + &--background { padding: 0; @@ -167,7 +169,7 @@ } - div:not(.givewp-layouts-headerImage), aside { + div:not(.givewp-layouts-headerImage, .givewp-layouts-header__content), aside { position: relative; z-index: 999; } @@ -205,7 +207,7 @@ .givewp-layouts-headerImage { img { border-radius: var(--givewp-rounded-4); - + max-height: 320px; } } diff --git a/src/DonationForms/resources/types.ts b/src/DonationForms/resources/types.ts index f760d30730..16e0594ec7 100644 --- a/src/DonationForms/resources/types.ts +++ b/src/DonationForms/resources/types.ts @@ -231,6 +231,7 @@ export interface Form extends Group { id: string; name: string; isMultiStep: boolean; + includeHeaderInMultiStep: boolean; }; nodes: Section[]; currencySwitcherSettings?: CurrencySwitcherSetting[]; diff --git a/src/FormBuilder/resources/js/form-builder/src/components/onboarding/DesignSelector/images/two-panel-steps-design-screenshot.png b/src/FormBuilder/resources/js/form-builder/src/components/onboarding/DesignSelector/images/two-panel-steps-design-screenshot.png new file mode 100644 index 0000000000..58827de91f Binary files /dev/null and b/src/FormBuilder/resources/js/form-builder/src/components/onboarding/DesignSelector/images/two-panel-steps-design-screenshot.png differ diff --git a/src/FormBuilder/resources/js/form-builder/src/components/onboarding/DesignSelector/index.tsx b/src/FormBuilder/resources/js/form-builder/src/components/onboarding/DesignSelector/index.tsx index 97330b89e9..9768256a99 100644 --- a/src/FormBuilder/resources/js/form-builder/src/components/onboarding/DesignSelector/index.tsx +++ b/src/FormBuilder/resources/js/form-builder/src/components/onboarding/DesignSelector/index.tsx @@ -4,13 +4,16 @@ import {ShepherdTourContext} from 'react-shepherd'; import {__} from '@wordpress/i18n'; import DesignCard from './components/DesignCard'; -// @ts-ignore import classDesignScreenshot from './images/classic-design-screenshot.png'; - -// @ts-ignore import multiStepDesignScreenshot from './images/multi-step-design-screenshot.png'; +import twoPanelStepsDesignScreenshot from './images/two-panel-steps-design-screenshot.png'; + import {setFormSettings, useFormStateDispatch} from '@givewp/form-builder/stores/form-state'; +/** + * @unreleased Added Two-Panel (Steps) design option + * @since 3.0.0 + */ export default ({onContinue}) => { const tour = useContext(ShepherdTourContext); @@ -66,6 +69,17 @@ export default ({onContinue}) => { 'give' )} /> + <DesignCard + selected={selectedDesign === 'two-panel-steps'} + onSelected={() => onDesignSelected('two-panel-steps')} + image={twoPanelStepsDesignScreenshot} + alt={__('Two-Panel (Steps) form design', 'give')} + title={__('Two-Panel (Steps)', 'give')} + description={__( + 'This has a side-by-side layout which breaks the sections of the donation process into steps.', + 'give' + )} + /> </div> <Button diff --git a/src/FormBuilder/resources/js/form-builder/src/containers/BlockEditorInterfaceSkeletonContainer.tsx b/src/FormBuilder/resources/js/form-builder/src/containers/BlockEditorInterfaceSkeletonContainer.tsx index 8a67cdf606..bbaf078708 100644 --- a/src/FormBuilder/resources/js/form-builder/src/containers/BlockEditorInterfaceSkeletonContainer.tsx +++ b/src/FormBuilder/resources/js/form-builder/src/containers/BlockEditorInterfaceSkeletonContainer.tsx @@ -40,6 +40,7 @@ const DesignEditorSkeleton = () => { content={<DesignPreview />} sidebar={!!showSidebar && <DesignSidebar toggleShowSidebar={toggleShowSidebar} />} notices={<NoticesContainer />} + className="givewp-form-builder__design-tab" /> ); }; diff --git a/src/FormBuilder/resources/js/form-builder/src/styles/_block-editor.scss b/src/FormBuilder/resources/js/form-builder/src/styles/_block-editor.scss index 1e5d3e548f..50524e8383 100644 --- a/src/FormBuilder/resources/js/form-builder/src/styles/_block-editor.scss +++ b/src/FormBuilder/resources/js/form-builder/src/styles/_block-editor.scss @@ -34,15 +34,15 @@ } .interface-interface-skeleton__content { - width: 100%; - margin: auto; + width: 720px; + margin: 0 auto auto; padding: 100px 0; /* Leave room for toolbar above first block. */ flex-grow: unset; box-sizing: border-box; - #form-blocks-canvas { - width: 720px; - margin: 0 auto; + .givewp-form-builder__design-tab & { + width: 100%; + max-width: 1200px; } @media screen and (max-width: 782px) { diff --git a/src/FormBuilder/resources/js/form-builder/src/styles/_onboarding.scss b/src/FormBuilder/resources/js/form-builder/src/styles/_onboarding.scss index 891233a5f7..d70a71eb7d 100644 --- a/src/FormBuilder/resources/js/form-builder/src/styles/_onboarding.scss +++ b/src/FormBuilder/resources/js/form-builder/src/styles/_onboarding.scss @@ -69,7 +69,7 @@ .components-modal__content { margin: 0; - width: 45rem; + width: min-content; padding: var(--givewp-spacing-6); p { @@ -86,6 +86,7 @@ .givewp-design-selector--header { font-size: 1rem; + text-align: center; h3 { font-size: 1.5rem; @@ -103,7 +104,7 @@ .givewp-design-selector--cards { display: grid; grid-auto-flow: column; - column-gap: var(--givewp-spacing-10); + column-gap: var(--givewp-spacing-6); } .givewp-design-selector--card { @@ -152,7 +153,9 @@ } .givewp-design-selector--button { + align-self: flex-end; width: 100%; + max-width: 22.5rem; justify-content: center; padding: var(--givewp-spacing-3) var(--givewp-spacing-8); min-height: var(--givewp-spacing-12); diff --git a/src/Framework/FormDesigns/FormDesign.php b/src/Framework/FormDesigns/FormDesign.php index b6fd026194..a71eedcde0 100644 --- a/src/Framework/FormDesigns/FormDesign.php +++ b/src/Framework/FormDesigns/FormDesign.php @@ -7,11 +7,19 @@ /** * The FormDesign is meant to be extended to create custom GiveWP form designs. * + * @unreleased added $includeHeaderInMultiStep property * @since 3.0.0 */ abstract class FormDesign implements FormDesignInterface { + /** + * @var bool + */ protected $isMultiStep = false; + /** + * @var bool + */ + protected $includeHeaderInMultiStep = false; /** * The unique identifier of the design @@ -71,4 +79,12 @@ public function isMultiStep(): bool { return $this->isMultiStep; } + + /** + * @unreleased + */ + public function shouldIncludeHeaderInMultiStep(): bool + { + return $this->includeHeaderInMultiStep; + } } diff --git a/tests/Unit/DonationForms/ViewModels/DonationFormViewModelTest.php b/tests/Unit/DonationForms/ViewModels/DonationFormViewModelTest.php index e292276d68..3ee5411209 100644 --- a/tests/Unit/DonationForms/ViewModels/DonationFormViewModelTest.php +++ b/tests/Unit/DonationForms/ViewModels/DonationFormViewModelTest.php @@ -20,7 +20,7 @@ class DonationFormViewModelTest extends TestCase use RefreshDatabase; /** - * @since 3.0.0 update form export data + * @unreleased added includeHeaderInMultiStep to form design exports * @since 3.0.0 */ public function testExportsShouldReturnExpectedArrayOfData() @@ -74,6 +74,7 @@ public function testExportsShouldReturnExpectedArrayOfData() 'id' => $formDesign::id(), 'name' => $formDesign::name(), 'isMultiStep' => $formDesign->isMultiStep(), + 'includeHeaderInMultiStep' => $formDesign->shouldIncludeHeaderInMultiStep(), ], ]), 'previewMode' => false diff --git a/wordpress-scripts-webpack.config.js b/wordpress-scripts-webpack.config.js index 37e155e4ef..452e0cf8aa 100644 --- a/wordpress-scripts-webpack.config.js +++ b/wordpress-scripts-webpack.config.js @@ -51,6 +51,7 @@ module.exports = { classicFormDesignCss: srcPath('DonationForms/FormDesigns/ClassicFormDesign/css/main.scss'), classicFormDesignJs: srcPath('DonationForms/FormDesigns/ClassicFormDesign/js/main.ts'), multiStepFormDesignCss: srcPath('DonationForms/FormDesigns/MultiStepFormDesign/css/main.scss'), + twoPanelStepsFormLayoutCss: srcPath('DonationForms/FormDesigns/TwoPanelStepsFormLayout/css/main.scss'), donationConfirmationReceiptApp: srcPath('DonationForms/resources/receipt/DonationConfirmationReceiptApp.tsx'), baseFormDesignCss: srcPath('DonationForms/resources/styles/base.scss'), formBuilderApp: srcPath('FormBuilder/resources/js/form-builder/src/index.tsx'),