1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-23 00:22:19 +01:00

feat: render all steps at the same time, add thank you; first anims

This commit is contained in:
Thomas Heartman 2022-02-28 15:18:37 +01:00
parent 5456b093be
commit 355b516dae
2 changed files with 213 additions and 155 deletions

View File

@ -92,217 +92,260 @@ export const FeedbackWrapper = ({ seedData, open }) => {
console.log('send feedback here '); console.log('send feedback here ');
}; };
const step1ref = React.useRef(null);
const visuallyHidden = (stepNumber) => state.currentStep !== stepNumber;
const isHidden = (stepNumber) =>
!feedbackIsOpen || visuallyHidden(stepNumber);
const Step1 = () => { const Step1 = () => {
const hidden = isHidden(1);
const [newValue, setNewValue] = React.useState(undefined); const [newValue, setNewValue] = React.useState(undefined);
return ( return (
<form <form
className="step-1" className={visuallyHidden(1) ? styles['invisible'] : ''}
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault(); e.preventDefault();
setScore(newValue); setScore(newValue);
stepForward(); stepForward();
}} }}
aria-hidden={hidden}
> >
<p> <fieldset disabled={hidden}>
<span className="visually-hidden"> <p>
On a scale from 1 to 5 where 1 is very unsatisfied and 5 <span className="visually-hidden">
is very satisfied, On a scale from 1 to 5 where 1 is very unsatisfied
</span>{' '} and 5 is very satisfied,
How would you rate your overall satisfaction with the </span>{' '}
Unleash documentation? How would you rate your overall satisfaction with the
</p> Unleash documentation?
</p>
<div className={styles['satisfaction-input-container']}> <div className={styles['satisfaction-input-container']}>
<span <span
aria-hidden="true" aria-hidden="true"
className={styles['satisfaction-input-visual-label']} className={
> styles['satisfaction-input-visual-label']
Very unsatisfied }
</span> >
<span className={styles['satisfaction-input-inputs']}> Very unsatisfied
{[1, 2, 3, 4, 5].map((n) => ( </span>
<span key={`input-group-${n}`}> <span className={styles['satisfaction-input-inputs']}>
<input {[1, 2, 3, 4, 5].map((n) => (
className={join( <span key={`input-group-${n}`}>
'visually-hidden', <input
styles['user-satisfaction-score-input'], ref={n === 1 ? step1ref : undefined}
)} className={join(
required 'visually-hidden',
id={`user-satisfaction-score-${n}`} styles[
name="satisfaction-level" 'user-satisfaction-score-input'
type="radio" ],
value={n} )}
defaultChecked={n === state.data.score} required
onChange={(e) => { id={`user-satisfaction-score-${n}`}
const value = parseInt(e.target.value); name="satisfaction-level"
console.log('the value is', value); type="radio"
setNewValue(value); value={n}
}} defaultChecked={n === state.data.score}
/> onChange={(e) => {
<label const value = parseInt(
className={ e.target.value,
styles['user-satisfaction-score-label'] );
} console.log('the value is', value);
htmlFor={`user-satisfaction-score-${n}`} setNewValue(value);
> }}
{n} />
</label> <label
</span> className={
))} styles[
</span> 'user-satisfaction-score-label'
<span ]
aria-hidden="true" }
className={styles['satisfaction-input-visual-label']} htmlFor={`user-satisfaction-score-${n}`}
> >
Very satisfied {n}
</span> </label>
</div> </span>
<div className={styles['button-container']}> ))}
<button type="submit">Next</button> </span>
</div> <span
aria-hidden="true"
className={
styles['satisfaction-input-visual-label']
}
>
Very satisfied
</span>
</div>
<div className={styles['button-container']}>
<button type="submit">Next</button>
</div>
</fieldset>
</form> </form>
); );
}; };
const Step2 = () => { const Step2 = () => {
const hidden = isHidden(2);
const textareaId = 'feedback-comment-input'; const textareaId = 'feedback-comment-input';
const saveComment = () => const saveComment = () =>
setComment(document.getElementById(textareaId).value); setComment(document.getElementById(textareaId).value);
return ( return (
<form <form
className="step-2" className={visuallyHidden(2) ? styles['invisible'] : ''}
aria-hidden={hidden}
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault(); e.preventDefault();
saveComment(); saveComment();
stepForward(); stepForward();
}} }}
> >
<label htmlFor={textareaId}> <fieldset disabled={hidden}>
What would you like to see improved in the Unleash <label htmlFor={textareaId}>
documentation? What would you like to see improved in the Unleash
</label> documentation?
<textarea </label>
id={textareaId} <textarea
/* cols="30" */ id={textareaId}
name="" /* cols="30" */
rows="5" name=""
> rows="5"
{state.data.comment} >
</textarea> {state.data.comment}
</textarea>
<div className={styles['button-container']}> <div className={styles['button-container']}>
<button type="submit">Next</button> <button type="submit">Next</button>
<button <button
className={styles['button-secondary']} className={styles['button-secondary']}
type="button" type="button"
onClick={() => { onClick={() => {
saveComment(); saveComment();
stepForward(); stepForward();
}} }}
> >
Skip Skip
</button> </button>
<button <button
className={styles['button-secondary']} className={styles['button-secondary']}
type="button" type="button"
onClick={() => { onClick={() => {
saveComment(); saveComment();
stepBack(); stepBack();
}} }}
> >
Back Back
</button> </button>
</div> </div>
</fieldset>
</form> </form>
); );
}; };
const Step3 = () => { const Step3 = () => {
const hidden = isHidden(3);
const [value, setValue] = React.useState(); const [value, setValue] = React.useState();
return ( return (
<form <form
className="step-3" className={visuallyHidden(3) ? styles['invisible'] : ''}
aria-hidden={hidden}
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault(); e.preventDefault();
setCustomerType(value); setCustomerType(value);
submitFeedback(); submitFeedback();
}} }}
> >
<span> <fieldset disabled={hidden}>
Finally, would you mind telling us a little about yourself? <span>
What kind of customer are you? Finally, would you mind telling us a little about
</span> yourself? What kind of customer are you?
<div className={styles['customer-type-inputs']}> </span>
{[ <div className={styles['customer-type-inputs']}>
['a', 'paying', 'paying'], {[
['an', 'open source', 'opensource'], ['a', 'paying', 'paying'],
].map(([article, customerType, key]) => ( ['an', 'open source', 'opensource'],
<span key={`input-group-${key}`}> ].map(([article, customerType, key]) => (
<input <span key={`input-group-${key}`}>
id={`customer-type-${key}`} <input
className={styles['customer-type-input']} id={`customer-type-${key}`}
name="customer-type" className={styles['customer-type-input']}
type="radio" name="customer-type"
value={key} type="radio"
defaultChecked={key === state.data.customerType} value={key}
onChange={(e) => { defaultChecked={
const value = e.target.value; key === state.data.customerType
setValue(value); }
}} onChange={(e) => {
/> const value = e.target.value;
<label setValue(value);
className={styles['customer-type-label']} }}
htmlFor={`customer-type-${key}`} />
> <label
I'm {article} {customerType} customer className={styles['customer-type-label']}
</label> htmlFor={`customer-type-${key}`}
</span> >
))} I'm {article} {customerType} customer
</div> </label>
</span>
))}
</div>
<div className={styles['button-container']}> <div className={styles['button-container']}>
<button type="submit">Submit feedback</button> <button type="submit">Submit feedback</button>
<button <button
className={styles['button-secondary']} className={styles['button-secondary']}
type="button" type="button"
onClick={() => { onClick={() => {
setCustomerType(value); setCustomerType(value);
stepBack(); stepBack();
}} }}
> >
Back Back
</button> </button>
</div> </div>
</fieldset>
</form> </form>
); );
}; };
const Step4 = () => {
return <p className={styles['thank-you']}>Thank you! 🙌</p>;
};
return ( return (
<div className={styles['user-feedback-container']}> <div className={styles['user-feedback-container']}>
<p>feedback is {feedbackIsOpen ? 'open' : 'closed'}</p> <p>feedback is {feedbackIsOpen ? 'open' : 'closed'}</p>
<button <button
aria-hidden={feedbackIsOpen}
className={join( className={join(
feedbackIsOpen ? styles['hidden'] : undefined,
styles['open-feedback-button'], styles['open-feedback-button'],
styles['primary-button'], styles['primary-button'],
)} )}
disabled={feedbackIsOpen} disabled={feedbackIsOpen}
onClick={() => setFeedbackIsOpen(true)} onClick={() => {
setFeedbackIsOpen(true);
step1ref.current.focus();
}}
> >
Feedback <span>Feedback</span>
</button> </button>
<article <article
aria-hidden={!feedbackIsOpen}
/* hidden={!feedbackIsOpen} */
className={join( className={join(
styles['user-feedback'], styles['user-feedback'],
feedbackIsOpen ? '' : styles['hidden'], feedbackIsOpen ? '' : styles['invisible'],
)} )}
> >
<div className={styles['close-button-row']}> <div className={styles['close-button-row']}>
<button <button
onClick={() => setFeedbackIsOpen(false)} onClick={() => setFeedbackIsOpen(false)}
className={styles['close-button']} className={styles['close-button']}
disabled={!feedbackIsOpen}
> >
<span className="visually-hidden"> <span className="visually-hidden">
close feedback popup close feedback popup
@ -310,13 +353,10 @@ export const FeedbackWrapper = ({ seedData, open }) => {
<CloseIcon /> <CloseIcon />
</button> </button>
</div> </div>
{state.currentStep === 1 ? ( <Step1 />
<Step1 /> <Step2 />
) : state.currentStep === 2 ? ( <Step3 />
<Step2 /> <Step4 />
) : (
<Step3 />
)}
</article> </article>
</div> </div>
); );

View File

@ -2,6 +2,17 @@
--outline-style: 2px solid var(--ifm-color-primary); --outline-style: 2px solid var(--ifm-color-primary);
--row-gap: 1rem; --row-gap: 1rem;
--element-horizontal-gap: 1rem; --element-horizontal-gap: 1rem;
--animation-duration: 0.25s;
--fade-out-transition: opacity var(--animation-duration);
--fade-in-transition: opacity var(--animation-duration)
calc(var(--animation-duration) / 2);
}
@media screen and (prefers-reduced-motion: reduced) {
.user-feedback-container {
--animation-duration: 0;
}
} }
.user-feedback { .user-feedback {
@ -14,6 +25,12 @@
box-shadow: var(--ifm-global-shadow-lw); box-shadow: var(--ifm-global-shadow-lw);
padding: var(--ifm-spacing-vertical) var(--ifm-spacing-horizontal); padding: var(--ifm-spacing-vertical) var(--ifm-spacing-horizontal);
text-align: center; text-align: center;
transition: var(--fade-in-transition);
}
.user-feedback fieldset {
border: none;
padding: 0;
} }
.user-feedback > * + * { .user-feedback > * + * {
@ -30,13 +47,14 @@
max-width: 850px; max-width: 850px;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
transition: var(--fade-in-transition);
opacity: 1;
} }
.user-feedback > form > * + * { .user-feedback > form > * + * {
margin-top: var(--row-gap); margin-top: var(--row-gap);
} }
.hidden { .hidden {
display: none; display: none;
} }
@ -147,11 +165,13 @@ button.close-button {
padding-inline: calc(var(--ifm-spacing-horizontal) * 4); padding-inline: calc(var(--ifm-spacing-horizontal) * 4);
} }
.primary-button:hover, .user-feedback button[type='submit']:hover { .primary-button:hover,
.user-feedback button[type='submit']:hover {
background-color: var(--ifm-color-primary-lighter); background-color: var(--ifm-color-primary-lighter);
} }
.primary-button:hover, .user-feedback button[type='submit']:active { .primary-button:hover,
.user-feedback button[type='submit']:active {
background-color: var(--ifm-color-primary-dark); background-color: var(--ifm-color-primary-dark);
} }
@ -174,14 +194,12 @@ button.close-button {
background-color: var(--ifm-background-color); background-color: var(--ifm-background-color);
color: currentColor; color: currentColor;
border-radius: var(--ifm-global-radius); border-radius: var(--ifm-global-radius);
border: var(--ifm-global-border-width) solid border: var(--ifm-global-border-width) solid var(--ifm-color-emphasis-400);
var(--ifm-color-emphasis-400);
font-style: normal; font-style: normal;
font-family: inherit; font-family: inherit;
padding: var(--ifm-spacing-vertical) var(--ifm-spacing-horizontal); padding: var(--ifm-spacing-vertical) var(--ifm-spacing-horizontal);
} }
.customer-type-inputs { .customer-type-inputs {
display: flex; display: flex;
justify-content: center; justify-content: center;