diff --git a/src/OnboardingSPA/components/Animate/stylesheet.scss b/src/OnboardingSPA/components/Animate/stylesheet.scss index 00ce8b300..3ab261adc 100644 --- a/src/OnboardingSPA/components/Animate/stylesheet.scss +++ b/src/OnboardingSPA/components/Animate/stylesheet.scss @@ -109,6 +109,25 @@ } } +@keyframes fadeInFast { + + 0% { + opacity: 0.1; + } + + 25% { + opacity: 1; + } + + 75% { + opacity: 1; + } + + 100% { + opacity: 0.1; + } +} + @-webkit-keyframes spin { 0% { diff --git a/src/OnboardingSPA/components/Button/NextButtonSiteGen/index.js b/src/OnboardingSPA/components/Button/NextButtonSiteGen/index.js index 742cb078d..145f392ea 100644 --- a/src/OnboardingSPA/components/Button/NextButtonSiteGen/index.js +++ b/src/OnboardingSPA/components/Button/NextButtonSiteGen/index.js @@ -1,11 +1,11 @@ +import classNames from 'classnames'; import { useNavigate } from 'react-router-dom'; - import { useSelect } from '@wordpress/data'; import { Button } from '@wordpress/components'; +import { Icon, chevronRight } from '@wordpress/icons'; import { store as nfdOnboardingStore } from '../../../store'; -import classNames from 'classnames'; -const NextButtonSiteGen = ( { text, className } ) => { +const NextButtonSiteGen = ( { text, className, callback = null } ) => { const navigate = useNavigate(); const { nextStep } = useSelect( ( select ) => { return { @@ -19,12 +19,19 @@ const NextButtonSiteGen = ( { text, className } ) => { className ) } onClick={ () => { + if ( callback && typeof callback === 'function' ) { + callback(); + } if ( nextStep ) { navigate( nextStep.path ); } } } > { text } + ); }; diff --git a/src/OnboardingSPA/components/Button/NextButtonSiteGen/stylesheet.scss b/src/OnboardingSPA/components/Button/NextButtonSiteGen/stylesheet.scss index 4fd7d8707..7003deaeb 100644 --- a/src/OnboardingSPA/components/Button/NextButtonSiteGen/stylesheet.scss +++ b/src/OnboardingSPA/components/Button/NextButtonSiteGen/stylesheet.scss @@ -1,15 +1,18 @@ .nfd-onboarding-button { &--site-gen-next { - display: block; - background-color: var(--nfd-onboarding-primary); - color: var(--nfd-onboarding-secondary); - text-align: center; width: 164px; height: 50px; - font-size: clamp(0.5rem, 0.3864rem + 0.5682vw, 1.75rem); + display: flex; + cursor: pointer; margin-top: 24px; - border-radius: 6px; + text-align: center; + border-radius: 8px; + align-items: center; + justify-content: center; + color: var(--nfd-onboarding-secondary); + background-color: var(--nfd-onboarding-primary); + font-size: clamp(0.5rem, 0.3864rem + 0.5682vw, 1.75rem); @media (min-width: 2600px ) { width: 250px; @@ -22,4 +25,8 @@ margin-top: 10px; } } + + &--icon { + fill: var(--nfd-onboarding-secondary); + } } diff --git a/src/OnboardingSPA/components/CardWithOptions/index.js b/src/OnboardingSPA/components/CardWithOptions/index.js new file mode 100644 index 000000000..6ac5c8fff --- /dev/null +++ b/src/OnboardingSPA/components/CardWithOptions/index.js @@ -0,0 +1,71 @@ +import { Icon, chevronRight } from '@wordpress/icons'; + +const CardWithOptions = ( { title, options, skip, callback } ) => { + const buildOptions = () => { + return options.map( ( data, idx ) => { + return ( +
{ + if ( callback && typeof callback === 'function' ) { + callback( idx + 1 ); + } + } } + onKeyDown={ () => { + if ( callback && typeof callback === 'function' ) { + callback( idx + 1 ); + } + } } + > +
+
+ { data.title } +
+
+ { data.desc } +
+
+ +
+ ); + } ); + }; + + return ( +
+
{ title }
+
{ buildOptions() }
+
{ + if ( callback && typeof callback === 'function' ) { + callback( -1 ); + } + } } + onKeyDown={ () => { + if ( callback && typeof callback === 'function' ) { + callback( -1 ); + } + } } + > + { skip } +
+
+ ); +}; + +export default CardWithOptions; diff --git a/src/OnboardingSPA/components/CardWithOptions/stylesheet.scss b/src/OnboardingSPA/components/CardWithOptions/stylesheet.scss new file mode 100644 index 000000000..3a1e8b2f9 --- /dev/null +++ b/src/OnboardingSPA/components/CardWithOptions/stylesheet.scss @@ -0,0 +1,79 @@ +$background-color: var(--nfd-onboarding-card-background); + +.nfd-sg-card { + + margin: 8px; + max-width: 90vw; + padding: 24px 12px; + border-radius: 12px; + background-color: $background-color; + width: clamp(18.75rem, 22.6136rem + 5.6818vw, 31.25rem); + box-shadow: 3px 3px 5px rgba(var(--nfd-onboarding-primary-rgb), $alpha: 0.05); + + &__title { + color: var(--nfd-onboarding-primary); + margin: 16px; + line-height: 2; + font-size: 18px; + text-align: center; + margin-bottom: 30px; + letter-spacing: 1.5px; + } + + &__data { + margin: 12px; + + &__option { + display: flex; + cursor: pointer; + margin: 16px 4px; + align-items: center; + border-radius: 4px 4px 0 0; + padding: 16px 12px 20px 12px; + justify-content: space-between; + transition: background-color 400ms ease-in-out; + + &:not(:last-child) { + border-bottom: 0.5px solid rgba(var(--nfd-onboarding-primary-rgb), 0.3); + } + + &:hover { + background-color: var(--nfd-onboarding-hover); + } + + &__left_top { + color: var(--nfd-onboarding-primary); + font-size: 16px; + font-weight: 500; + padding-bottom: 12px; + } + + &__left_bottom { + color: var(--nfd-onboarding-primary); + font-size: 14px; + font-weight: 300; + } + + &__right { + fill: var(--nfd-onboarding-primary); + transition: all 200ms ease-in-out; + + &:hover { + transform: scale(1.1); + } + } + } + } + + &__skip { + cursor: pointer; + text-align: end; + margin: 0 20px 6px 20px; + transition: color 200ms ease-in-out; + color: rgba(var(--nfd-onboarding-primary-rgb), 0.8); + + &:hover { + color: var(--nfd-onboarding-primary); + } + } +} diff --git a/src/OnboardingSPA/components/ErrorState/Step/index.js b/src/OnboardingSPA/components/ErrorState/Step/index.js index d97570176..909eda268 100644 --- a/src/OnboardingSPA/components/ErrorState/Step/index.js +++ b/src/OnboardingSPA/components/ErrorState/Step/index.js @@ -1,5 +1,5 @@ import CommonLayout from '../../Layouts/Common'; -import HeadingWithSubHeading from '../../HeadingWithSubHeading'; +import HeadingWithSubHeading from '../../Heading/HeadingWithSubHeading'; import NeedHelpTag from '../../NeedHelpTag'; const StepErrorState = ( { title, subtitle, error } ) => { diff --git a/src/OnboardingSPA/components/Heading/AIHeading/index.js b/src/OnboardingSPA/components/Heading/AIHeading/index.js new file mode 100644 index 000000000..93fd2b8d3 --- /dev/null +++ b/src/OnboardingSPA/components/Heading/AIHeading/index.js @@ -0,0 +1,10 @@ +const AIHeading = ( { title } ) => { + return ( +
+
+
{ title }
+
+ ); +}; + +export default AIHeading; diff --git a/src/OnboardingSPA/components/Heading/AIHeading/stylesheet.scss b/src/OnboardingSPA/components/Heading/AIHeading/stylesheet.scss new file mode 100644 index 000000000..51c3e5f17 --- /dev/null +++ b/src/OnboardingSPA/components/Heading/AIHeading/stylesheet.scss @@ -0,0 +1,24 @@ +.ai-heading { + + display: flex; + margin-bottom: 20px; + align-items: center; + + &--icon { + width: 50px; + margin: 4px; + height: 50px; + background-size: 200%; + background-position: center; + background-repeat: no-repeat; + background-image: var(--sitegen-ai-animation); + } + + &--title { + margin: 10px; + line-height: 1.5; + font-weight: 500; + font-size: 1.2rem; + color: var(--nfd-onboarding-primary); + } +} diff --git a/src/OnboardingSPA/components/HeadingWithSubHeading/index.js b/src/OnboardingSPA/components/Heading/HeadingWithSubHeading/index.js similarity index 100% rename from src/OnboardingSPA/components/HeadingWithSubHeading/index.js rename to src/OnboardingSPA/components/Heading/HeadingWithSubHeading/index.js diff --git a/src/OnboardingSPA/components/HeadingWithSubHeading/stylesheet.scss b/src/OnboardingSPA/components/Heading/HeadingWithSubHeading/stylesheet.scss similarity index 100% rename from src/OnboardingSPA/components/HeadingWithSubHeading/stylesheet.scss rename to src/OnboardingSPA/components/Heading/HeadingWithSubHeading/stylesheet.scss diff --git a/src/OnboardingSPA/components/Loaders/SiteGenLoader/contents.js b/src/OnboardingSPA/components/Loaders/SiteGenLoader/contents.js new file mode 100644 index 000000000..3ebb1b078 --- /dev/null +++ b/src/OnboardingSPA/components/Loaders/SiteGenLoader/contents.js @@ -0,0 +1,32 @@ +import { __ } from '@wordpress/i18n'; + +const getContents = () => { + return { + title: __( 'Building Website', 'wp-module-onboarding' ), + status: [ + { + title: __( 'Generating Website', 'wp-module-onboarding' ), + }, + { + title: __( 'Finding Font Pairings', 'wp-module-onboarding' ), + }, + { + title: __( + 'Building Custom Color Palettes', + 'wp-module-onboarding' + ), + }, + { + title: __( 'Populating Images', 'wp-module-onboarding' ), + }, + { + title: __( 'Finalizing Previews', 'wp-module-onboarding' ), + }, + { + title: __( 'Packaging Website', 'wp-module-onboarding' ), + }, + ], + }; +}; + +export default getContents; diff --git a/src/OnboardingSPA/components/Loaders/SiteGenLoader/index.js b/src/OnboardingSPA/components/Loaders/SiteGenLoader/index.js new file mode 100644 index 000000000..72a0c9a8b --- /dev/null +++ b/src/OnboardingSPA/components/Loaders/SiteGenLoader/index.js @@ -0,0 +1,64 @@ +import getContents from './contents'; +import { useSelect } from '@wordpress/data'; +import { useNavigate } from 'react-router-dom'; +import { useEffect, useState } from '@wordpress/element'; +import { store as nfdOnboardingStore } from '../../../store'; + +const SiteGenLoader = ( { autoNavigate = false } ) => { + let statusIdx = 0; + const content = getContents(); + const navigate = useNavigate(); + const [ percentage, setPercentage ] = useState( 0 ); + const [ status, setStatus ] = useState( content.status[ statusIdx ].title ); + + const { nextStep } = useSelect( ( select ) => { + return { + nextStep: select( nfdOnboardingStore ).getNextStep(), + }; + } ); + + const checkStatus = async () => { + // Make fake API Call to get the status. + if ( percentage !== 100 ) setPercentage( ( t ) => t + 10 ); + }; + + useEffect( () => { + const statusTimer = setInterval( () => { + checkStatus(); + statusIdx += 1; + if ( statusIdx === content.status.length ) statusIdx = 0; + setStatus( content.status[ statusIdx ].title ); + }, 3000 ); + return () => { + clearInterval( statusTimer ); + }; + }, [] ); + + useEffect( () => { + if ( percentage === 100 ) { + if ( nextStep && autoNavigate ) { + navigate( nextStep.path ); + } + } + }, [ percentage ] ); + + return ( +
+
{ content.title }
+
+
+
+
+
+
+
{ `${ status }...` }
+
+ ); +}; + +export default SiteGenLoader; diff --git a/src/OnboardingSPA/components/Loaders/SiteGenLoader/stylesheet.scss b/src/OnboardingSPA/components/Loaders/SiteGenLoader/stylesheet.scss new file mode 100644 index 000000000..a32bacc27 --- /dev/null +++ b/src/OnboardingSPA/components/Loaders/SiteGenLoader/stylesheet.scss @@ -0,0 +1,70 @@ +$background-color: var(--nfd-onboarding-card-background); + +.nfd-sg-loader { + + margin: 8px; + max-width: 90vw; + padding: 16px 12px; + border-radius: 12px; + background-color: $background-color; + width: clamp(18.75rem, 22.6136rem + 5.6818vw, 31.25rem); + box-shadow: 3px 3px 5px rgba(var(--nfd-onboarding-black-rgb), $alpha: 0.05); + + @media (max-width: #{ ($break-small) }) { + margin: 20px; + max-width: 80vw; + } + + &__title { + line-height: 2; + font-size: 18px; + text-align: center; + letter-spacing: 1.5px; + color: var(--nfd-onboarding-primary); + } + + &__progress { + display: flex; + margin: 20px 60px; + align-items: center; + justify-content: center; + + @media (max-width: #{ ($break-small) }) { + margin: 20px 30px; + } + + &_bars { + width: 100%; + display: flex; + position: relative; + align-items: center; + justify-content: flex-start; + + &_bg { + height: 6px; + width: 100%; + border-radius: 6px; + background-color: var(--nfd-onboarding-progress-bar-background); + } + + &_bar { + top: 0; + height: 6px; + max-width: 100%; + border-radius: 6px; + position: absolute; + transition: width 2s ease-in-out; + background-color: var(--nfd-onboarding-progress-bar-fill); + } + } + } + + &__status { + line-height: 2; + font-size: 14px; + text-align: center; + letter-spacing: 1.3px; + color: var(--nfd-onboarding-primary); + animation: fadeInFast 3s ease-out infinite; + } +} diff --git a/src/OnboardingSPA/components/Loaders/Step/index.js b/src/OnboardingSPA/components/Loaders/Step/index.js index ea84b1950..09f655d1f 100644 --- a/src/OnboardingSPA/components/Loaders/Step/index.js +++ b/src/OnboardingSPA/components/Loaders/Step/index.js @@ -1,5 +1,5 @@ import CommonLayout from '../../Layouts/Common'; -import HeadingWithSubHeading from '../../HeadingWithSubHeading'; +import HeadingWithSubHeading from '../../Heading/HeadingWithSubHeading'; import NeedHelpTag from '../../NeedHelpTag'; const StepLoader = ( { title, subtitle } ) => { diff --git a/src/OnboardingSPA/components/TextInput/contents.js b/src/OnboardingSPA/components/TextInput/TextInputSiteBuild/contents.js similarity index 100% rename from src/OnboardingSPA/components/TextInput/contents.js rename to src/OnboardingSPA/components/TextInput/TextInputSiteBuild/contents.js diff --git a/src/OnboardingSPA/components/TextInput/index.js b/src/OnboardingSPA/components/TextInput/TextInputSiteBuild/index.js similarity index 91% rename from src/OnboardingSPA/components/TextInput/index.js rename to src/OnboardingSPA/components/TextInput/TextInputSiteBuild/index.js index 6859ff853..ad2ae1dea 100644 --- a/src/OnboardingSPA/components/TextInput/index.js +++ b/src/OnboardingSPA/components/TextInput/TextInputSiteBuild/index.js @@ -1,7 +1,7 @@ import { useRef, useEffect, useState, memo } from '@wordpress/element'; import getContents from './contents'; -const TextInput = ( { +const TextInputSiteBuild = ( { title, hint, placeholder, @@ -58,5 +58,5 @@ const TextInput = ( { ); }; -const TextInputMemo = memo( TextInput ); -export default TextInputMemo; +const TextInputSiteBuildMemo = memo( TextInputSiteBuild ); +export default TextInputSiteBuildMemo; diff --git a/src/OnboardingSPA/components/TextInput/stylesheet.scss b/src/OnboardingSPA/components/TextInput/TextInputSiteBuild/stylesheet.scss similarity index 100% rename from src/OnboardingSPA/components/TextInput/stylesheet.scss rename to src/OnboardingSPA/components/TextInput/TextInputSiteBuild/stylesheet.scss diff --git a/src/OnboardingSPA/components/TextInput/TextInputSiteGen/index.js b/src/OnboardingSPA/components/TextInput/TextInputSiteGen/index.js new file mode 100644 index 000000000..c213f45ec --- /dev/null +++ b/src/OnboardingSPA/components/TextInput/TextInputSiteGen/index.js @@ -0,0 +1,86 @@ +import classNames from 'classnames'; +import { useRef, useEffect, useState, memo } from '@wordpress/element'; + +const TextInputSiteGen = ( { + hint, + height, + placeholder, + customerInput, + setCustomerInput, +} ) => { + const textareaRef = useRef( null ); + const [ inputText, setInputText ] = useState( 'nfd-sg-input-box__field' ); + + useEffect( () => { + textareaRef.current.style.height = height; + const scrollHeight = textareaRef.current.scrollHeight; + textareaRef.current.style.height = scrollHeight + 'px'; + }, [ customerInput ] ); + + const calculateDetail = ( num ) => { + const selectedButton = 'nfd-sg-input-box__info-icon--selected'; + switch ( num ) { + case 1: + if ( customerInput?.length > 30 ) return selectedButton; + break; + case 2: + if ( customerInput?.length > 60 ) return selectedButton; + break; + case 3: + if ( customerInput?.length > 100 ) return selectedButton; + } + }; + + const onTextChange = ( e ) => { + e.preventDefault(); + setCustomerInput( e.target.value ); + setInputText( 'nfd-sg-input-box__field' ); + }; + + return ( +
+