mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-03-07 18:01:40 -05:00
feat:(client): show-workshop-independent-lower-jaw (#64137)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -14,6 +14,22 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#learn-app-wrapper .editor-pane {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#learn-app-wrapper .editor-pane-code {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
#learn-app-wrapper .editor-pane > .independent-lower-jaw {
|
||||
flex: 0 0 auto;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
#learn-app-wrapper .reflex-container.vertical {
|
||||
min-height: 0;
|
||||
flex-grow: 1;
|
||||
|
||||
@@ -314,9 +314,14 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
|
||||
name='editorPane'
|
||||
{...resizeProps}
|
||||
data-playwright-test-label='editor-pane'
|
||||
className='editor-pane'
|
||||
>
|
||||
{!isEmpty(challengeFiles) && (
|
||||
<ReflexContainer key='codePane' orientation='horizontal'>
|
||||
<ReflexContainer
|
||||
key='codePane'
|
||||
orientation='horizontal'
|
||||
className='editor-pane-code'
|
||||
>
|
||||
<ReflexElement
|
||||
name='codePane'
|
||||
{...(displayEditorConsole && { flex: codePane.flex })}
|
||||
|
||||
@@ -314,13 +314,9 @@ function ShowClassic({
|
||||
|
||||
// AB testing Pre-fetch in the Spanish locale
|
||||
const isPreFetchEnabled = useFeature('prefetch_ab_test').on;
|
||||
const isIndependentLowerJawEnabled = useFeature('independent-lower-jaw').on;
|
||||
|
||||
// Independent lower jaw is only enabled for the urriculum outline workshop
|
||||
const showIndependentLowerJaw =
|
||||
block === 'workshop-curriculum-outline' &&
|
||||
isIndependentLowerJawEnabled &&
|
||||
!isMobile;
|
||||
// Independent lower jaw is only enabled for desktop workshops.
|
||||
const showIndependentLowerJaw = hasEditableBoundaries && !isMobile;
|
||||
|
||||
useEffect(() => {
|
||||
if (isPreFetchEnabled && envData.clientLocale === 'espanol') {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
.independent-lower-jaw {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
flex: 0 0 auto;
|
||||
position: relative;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
.independent-lower-jaw .hint-container {
|
||||
@@ -13,7 +11,24 @@
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
margin: 12px;
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
width: 95%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
margin-bottom: 12px;
|
||||
border: 1px solid var(--background-secondary);
|
||||
opacity: 0;
|
||||
animation: jaw-hint-fade-in 0.3s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes jaw-hint-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.independent-lower-jaw .btn-cta {
|
||||
|
||||
@@ -51,6 +51,10 @@ export function IndependentLowerJaw({
|
||||
const hint = firstFailedTest?.message;
|
||||
const [showHint, setShowHint] = React.useState(false);
|
||||
const [showSubmissionHint, setShowSubmissionHint] = React.useState(true);
|
||||
const signInLinkRef = React.useRef<HTMLAnchorElement>(null);
|
||||
const submitButtonRef = React.useRef<HTMLButtonElement>(null);
|
||||
const [wasCheckButtonClicked, setWasCheckButtonClicked] =
|
||||
React.useState(false);
|
||||
|
||||
const isChallengeComplete = tests.every(test => test.pass);
|
||||
|
||||
@@ -58,27 +62,60 @@ export function IndependentLowerJaw({
|
||||
setShowHint(!!hint);
|
||||
}, [hint]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isChallengeComplete || !wasCheckButtonClicked) return;
|
||||
|
||||
const focusTarget = isSignedIn
|
||||
? submitButtonRef.current
|
||||
: signInLinkRef.current;
|
||||
focusTarget?.focus();
|
||||
setWasCheckButtonClicked(false);
|
||||
}, [isChallengeComplete, isSignedIn, wasCheckButtonClicked]);
|
||||
|
||||
const handleCheckButtonClick = () => {
|
||||
setWasCheckButtonClicked(true);
|
||||
executeChallenge();
|
||||
};
|
||||
|
||||
const isMacOS = navigator.userAgent.includes('Mac OS');
|
||||
const checkButtonText = isMacOS ? t('command-enter') : t('ctrl-enter');
|
||||
const checkButtonText = isMacOS
|
||||
? t('buttons.command-enter')
|
||||
: t('buttons.ctrl-enter');
|
||||
|
||||
return (
|
||||
<div className='independent-lower-jaw' tabIndex={-1}>
|
||||
<div
|
||||
className='independent-lower-jaw'
|
||||
data-playwright-test-label='independentLowerJaw-container'
|
||||
tabIndex={-1}
|
||||
>
|
||||
{showHint && hint && (
|
||||
<div className='hint-container'>
|
||||
<div
|
||||
className='hint-container'
|
||||
data-playwright-test-label='independentLowerJaw-failing-hint'
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: hint }} />
|
||||
<button className={'tooltip'} onClick={() => setShowHint(false)}>
|
||||
<button
|
||||
className={'tooltip'}
|
||||
data-playwright-test-label='independentLowerJaw-hint-close-button'
|
||||
onClick={() => setShowHint(false)}
|
||||
>
|
||||
×<span className='tooltiptext'> {t('buttons.close')}</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{isChallengeComplete && showSubmissionHint && (
|
||||
<div className='hint-container'>
|
||||
<div
|
||||
className='hint-container'
|
||||
data-playwright-test-label='independentLowerJaw-submission-hint'
|
||||
>
|
||||
<div>
|
||||
<p>{t('learn.congratulations-code-passes')}</p>
|
||||
{!isSignedIn && (
|
||||
<a
|
||||
href={`${apiLocation}/signin`}
|
||||
className='btn-cta btn btn-block'
|
||||
data-playwright-test-label='independentLowerJaw-signin-link'
|
||||
ref={signInLinkRef}
|
||||
onClick={() => {
|
||||
callGA({
|
||||
event: 'sign_in'
|
||||
@@ -91,6 +128,7 @@ export function IndependentLowerJaw({
|
||||
</div>
|
||||
<button
|
||||
className={'tooltip'}
|
||||
data-playwright-test-label='independentLowerJaw-submission-hint-close-button'
|
||||
onClick={() => setShowSubmissionHint(false)}
|
||||
>
|
||||
×<span className='tooltiptext'> {t('buttons.close')}</span>
|
||||
@@ -104,7 +142,10 @@ export function IndependentLowerJaw({
|
||||
<Button
|
||||
block
|
||||
className={`${isSignedIn && 'btn-cta'} tooltip`}
|
||||
id='independent-lower-jaw-submit-button'
|
||||
data-playwright-test-label='independentLowerJaw-submit-button'
|
||||
onClick={() => submitChallenge()}
|
||||
ref={submitButtonRef}
|
||||
>
|
||||
{t('buttons.submit-continue')}
|
||||
<span className='tooltiptext left-tooltip '>
|
||||
@@ -115,7 +156,8 @@ export function IndependentLowerJaw({
|
||||
<button
|
||||
type='button'
|
||||
className='btn-cta tooltip'
|
||||
onClick={() => executeChallenge()}
|
||||
data-playwright-test-label='independentLowerJaw-check-button'
|
||||
onClick={handleCheckButtonClick}
|
||||
>
|
||||
{t('buttons.check-code')}
|
||||
<span className='tooltiptext left-tooltip '>
|
||||
@@ -128,6 +170,7 @@ export function IndependentLowerJaw({
|
||||
<button
|
||||
type='button'
|
||||
className='icon-botton tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-reset-button'
|
||||
onClick={openResetModal}
|
||||
>
|
||||
<Reset />
|
||||
@@ -136,6 +179,7 @@ export function IndependentLowerJaw({
|
||||
<button
|
||||
type='button'
|
||||
className='icon-botton tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-help-button'
|
||||
onClick={openHelpModal}
|
||||
>
|
||||
<Help />
|
||||
|
||||
Reference in New Issue
Block a user