Skip to content

Commit 8109717

Browse files
authored
Merge pull request #44 from topcoder-platform/TCA-299_ui-for-js-course
Tca 299 UI for js course
2 parents 795a984 + f68c31a commit 8109717

File tree

22 files changed

+299
-201
lines changed

22 files changed

+299
-201
lines changed

client/src/components/formHelpers/block-save-button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
55
function BlockSaveButton(props?: Record<string, unknown>): JSX.Element {
66
const { t } = useTranslation();
77
return (
8-
<Button block={true} bsStyle='primary' {...props} type='submit'>
8+
<Button bsStyle='primary' {...props} type='submit'>
99
{props?.children || t('buttons.save')}
1010
</Button>
1111
);

client/src/components/formHelpers/form-fields.tsx

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
Alert,
3-
Col,
43
ControlLabel,
54
FormControl,
65
FormGroup,
@@ -72,7 +71,7 @@ function FormFields(props: FormFieldsProps): JSX.Element {
7271
) : null;
7372
};
7473
return (
75-
<div>
74+
<>
7675
{formFields
7776
.filter(formField => !ignored.includes(formField.name))
7877
.map(({ name, label }) => (
@@ -85,35 +84,33 @@ function FormFields(props: FormFieldsProps): JSX.Element {
8584
name in placeholders ? placeholders[name] : '';
8685
const isURL = types[name] === 'url';
8786
return (
88-
<Col key={key} xs={12}>
89-
<FormGroup>
90-
{type === 'hidden' ? null : (
91-
<ControlLabel htmlFor={key}>{label}</ControlLabel>
92-
)}
93-
<FormControl
94-
componentClass={type === 'textarea' ? type : 'input'}
95-
id={key}
96-
name={name}
97-
onChange={onChange}
98-
placeholder={placeholder}
99-
required={required.includes(name)}
100-
rows={4}
101-
type={type}
102-
value={value as string}
103-
/>
104-
{nullOrWarning(
105-
value as string,
106-
!pristine && error,
107-
isURL,
108-
name
109-
)}
110-
</FormGroup>
111-
</Col>
87+
<FormGroup key={key} className='embedded'>
88+
{type === 'hidden' ? null : (
89+
<ControlLabel htmlFor={key}>{label}</ControlLabel>
90+
)}
91+
<FormControl
92+
componentClass={type === 'textarea' ? type : 'input'}
93+
id={key}
94+
name={name}
95+
onChange={onChange}
96+
placeholder={placeholder}
97+
required={required.includes(name)}
98+
rows={4}
99+
type={type}
100+
value={value as string}
101+
/>
102+
{nullOrWarning(
103+
value as string,
104+
!pristine && error,
105+
isURL,
106+
name
107+
)}
108+
</FormGroup>
112109
);
113110
}}
114111
</Field>
115112
))}
116-
</div>
113+
</>
117114
);
118115
}
119116

client/src/components/formHelpers/form.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
ValidatedValues,
77
FormFields,
88
BlockSaveButton,
9-
BlockSaveWrapper,
109
formatUrlValues
1110
} from '../formHelpers/index';
1211

@@ -54,15 +53,13 @@ function DynamicForm({
5453
style={{ width: '100%' }}
5554
>
5655
<FormFields formFields={formFields} options={options} />
57-
<BlockSaveWrapper>
58-
{hideButton ? null : (
59-
<BlockSaveButton
60-
disabled={(pristine && !enableSubmit) || (error as boolean)}
61-
>
62-
{buttonText ? buttonText : null}
63-
</BlockSaveButton>
64-
)}
65-
</BlockSaveWrapper>
56+
{!hideButton && (
57+
<BlockSaveButton
58+
disabled={(pristine && !enableSubmit) || (error as boolean)}
59+
>
60+
{buttonText ? buttonText : null}
61+
</BlockSaveButton>
62+
)}
6663
</form>
6764
)}
6865
</Form>

client/src/components/layouts/global.css

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,13 +491,43 @@ fieldset[disabled] .btn-primary.focus {
491491
}
492492
}
493493

494-
.button-group .btn:not(:last-child) {
494+
.button-group {
495+
margin-bottom: -10px;
496+
}
497+
.button-group .btn {
495498
margin-bottom: 10px;
496499
}
497500
strong {
498501
color: var(--secondary-color);
499502
}
500503

504+
.form-group.embedded {
505+
border: 1px solid var(--tc-black-40);
506+
padding: 8px 10px 2px;
507+
border-radius: 4px;
508+
position: relative;
509+
max-width: 320px;
510+
}
511+
512+
.form-group.embedded .control-label {
513+
display: block;
514+
font-size: 11px;
515+
font-family: 'Roboto';
516+
line-height: 10px;
517+
color: var(--tc-turq-160);
518+
margin-bottom: 4px;
519+
}
520+
521+
.form-group.embedded .form-control {
522+
border: 0 none;
523+
padding: 0;
524+
height: 22px;
525+
font-size: 14px;
526+
line-height: 22px;
527+
font-family: 'Roboto';
528+
color: var(--tc-black-100);
529+
}
530+
501531
.form-control {
502532
color: var(--primary-color);
503533
outline: none;

client/src/components/layouts/learn.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@
2424
#learn-app-wrapper .reflex-container.horizontal > .reflex-splitter {
2525
height: 5px;
2626
}
27+
28+
#learn-app-wrapper .reflex-container > .reflex-element:first-child:last-child {
29+
flex: 1 1 auto !important;
30+
}

client/src/components/layouts/prism.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
pre[class*='language-'].line-numbers.line-numbers {
2+
border-radius: 8px;
3+
font-size: 14px;
4+
line-height: 22px;
5+
}
6+
17
code .token.operator {
28
background: none;
39
}
@@ -7,6 +13,10 @@ pre[class*='language-'] {
713
background: var(--primary-background);
814
}
915

16+
.line-numbers > p {
17+
color: var(--tc-black-100);
18+
}
19+
1020
.default pre[class*='language-']::selection,
1121
.default pre[class*='language-'] ::selection,
1222
.default code[class*='language-']::selection,

client/src/components/layouts/variables.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
--tc-link-blue-light: #5fb7ee;
3838
--tc-black: #000;
3939
--tc-black-100: #2a2a2a;
40+
--tc-black-60: #7f7f7f;
41+
--tc-black-40: #aaaaaa;
4042
--tc-black-20: #d4d4d4;
4143
--tc-black-10: #e9e9e9;
4244
--tc-black-5: #f4f4f4;

client/src/templates/Challenges/classic/action-row.tsx

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import EditorTabs from './editor-tabs';
88
interface ActionRowProps {
99
block: string;
1010
hasNotes: boolean;
11+
hasPreview: boolean;
1112
isMultifileCertProject: boolean;
1213
showInstructions: boolean;
1314
showConsole: boolean;
@@ -25,10 +26,10 @@ const mapDispatchToProps = {
2526

2627
const ActionRow = ({
2728
hasNotes,
29+
hasPreview,
2830
togglePane,
2931
showNotes,
3032
showPreview,
31-
isMultifileCertProject,
3233
showInstructions,
3334
showConsole,
3435
superBlock,
@@ -44,17 +45,15 @@ const ActionRow = ({
4445
</div>
4546
)}
4647
<div className='tabs-row'>
47-
{isMultifileCertProject && (
48-
<button
49-
aria-expanded={showInstructions ? 'true' : 'false'}
50-
className={
51-
showInstructions ? 'btn-tab-primary' : 'btn-tab-primary--outline'
52-
}
53-
onClick={() => togglePane('showInstructions')}
54-
>
55-
Instructions
56-
</button>
57-
)}
48+
<button
49+
aria-expanded={showInstructions ? 'true' : 'false'}
50+
className={
51+
showInstructions ? 'btn-tab-primary' : 'btn-tab-primary--outline'
52+
}
53+
onClick={() => togglePane('showInstructions')}
54+
>
55+
Instructions
56+
</button>
5857
<EditorTabs />
5958
<button
6059
aria-expanded={showConsole ? 'true' : 'false'}
@@ -76,15 +75,17 @@ const ActionRow = ({
7675
{t('learn.editor-tabs.notes')}
7776
</button>
7877
)}
79-
<button
80-
aria-expanded={showPreview ? 'true' : 'false'}
81-
className={
82-
showPreview ? 'btn-tab-primary' : 'btn-tab-primary--outline'
83-
}
84-
onClick={() => togglePane('showPreview')}
85-
>
86-
{t('learn.editor-tabs.preview')}
87-
</button>
78+
{hasPreview && (
79+
<button
80+
aria-expanded={showPreview ? 'true' : 'false'}
81+
className={
82+
showPreview ? 'btn-tab-primary' : 'btn-tab-primary--outline'
83+
}
84+
onClick={() => togglePane('showPreview')}
85+
>
86+
{t('learn.editor-tabs.preview')}
87+
</button>
88+
)}
8889
</div>
8990
</div>
9091
);

client/src/templates/Challenges/classic/desktop-layout.tsx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ interface DesktopLayoutProps {
3434
resizeProps: ResizeProps;
3535
superBlock: string;
3636
testOutput: ReactElement;
37+
visibleEditors: { [key: string]: boolean };
3738
}
3839

3940
const reflexProps = {
@@ -85,20 +86,20 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
8586
notes,
8687
preview,
8788
hasEditableBoundaries,
88-
superBlock
89+
superBlock,
90+
visibleEditors
8991
} = props;
9092

9193
const challengeFile = getChallengeFile();
9294
const projectBasedChallenge = hasEditableBoundaries;
9395
const isMultifileCertProject =
9496
challengeType === challengeTypes.multifileCertProject;
95-
const displayPreview =
96-
projectBasedChallenge || isMultifileCertProject
97-
? showPreview && hasPreview
98-
: hasPreview;
97+
const displayPreview = showPreview && hasPreview;
9998
const displayNotes = projectBasedChallenge ? showNotes && hasNotes : false;
100-
const displayConsole =
101-
projectBasedChallenge || isMultifileCertProject ? showConsole : true;
99+
const displayConsole = showConsole;
100+
const displayEditor = Object.entries(visibleEditors).some(
101+
([, visible]) => visible
102+
);
102103
const {
103104
codePane,
104105
editorPane,
@@ -110,33 +111,32 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
110111

111112
return (
112113
<div className='desktop-layout'>
113-
{(projectBasedChallenge || isMultifileCertProject) && (
114-
<ActionRow
115-
block={block}
116-
hasNotes={hasNotes}
117-
isMultifileCertProject={isMultifileCertProject}
118-
showConsole={showConsole}
119-
showNotes={showNotes}
120-
showInstructions={showInstructions}
121-
showPreview={showPreview}
122-
superBlock={superBlock}
123-
showBreadcrumbs={false}
124-
togglePane={togglePane}
125-
/>
126-
)}
114+
<ActionRow
115+
block={block}
116+
hasNotes={hasNotes}
117+
isMultifileCertProject={isMultifileCertProject}
118+
showConsole={showConsole}
119+
showNotes={showNotes}
120+
showInstructions={showInstructions}
121+
hasPreview={hasPreview}
122+
showPreview={showPreview}
123+
superBlock={superBlock}
124+
showBreadcrumbs={false}
125+
togglePane={togglePane}
126+
/>
127127
<div className='editor-row'>
128128
<ReflexContainer orientation='vertical'>
129129
{!projectBasedChallenge && showInstructions && (
130130
<ReflexElement flex={instructionPane.flex} {...resizeProps}>
131131
{instructions}
132132
</ReflexElement>
133133
)}
134-
{!projectBasedChallenge && (
134+
{!projectBasedChallenge && displayEditor && (
135135
<ReflexSplitter propagate={true} {...resizeProps} />
136136
)}
137137

138-
<ReflexElement flex={editorPane.flex} {...resizeProps}>
139-
{challengeFile && (
138+
{challengeFile && displayEditor && (
139+
<ReflexElement flex={editorPane.flex} {...resizeProps}>
140140
<ReflexContainer
141141
key={challengeFile.fileKey}
142142
orientation='horizontal'
@@ -157,8 +157,8 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => {
157157
</ReflexElement>
158158
)}
159159
</ReflexContainer>
160-
)}
161-
</ReflexElement>
160+
</ReflexElement>
161+
)}
162162

163163
{(displayPreview || displayConsole) && (
164164
<ReflexSplitter propagate={true} {...resizeProps} />

client/src/templates/Challenges/classic/editor.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,9 @@ const Editor = (props: EditorProps): JSX.Element => {
573573
attemptRef.current.attempts++;
574574
}
575575

576-
const tryToSubmitChallenge = debounce(props.submitChallenge, 2000);
576+
const tryToSubmitChallenge = debounce(props.submitChallenge, 2000, {
577+
leading: true
578+
});
577579

578580
function createLowerJaw(outputNode: HTMLElement, callback?: () => void) {
579581
const { output } = props;

0 commit comments

Comments
 (0)