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:
parent
5456b093be
commit
355b516dae
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user