mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-09-24 23:01:18 +08:00
feat(client, curriculum): add support for blockLayout property (#56101)
Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>
This commit is contained in:
@@ -74,6 +74,7 @@ exports.createPages = async function createPages({
|
||||
challenge {
|
||||
block
|
||||
blockType
|
||||
blockLayout
|
||||
certification
|
||||
challengeType
|
||||
dashedName
|
||||
@@ -260,6 +261,7 @@ exports.createSchemaCustomization = ({ actions }) => {
|
||||
}
|
||||
type Challenge {
|
||||
blockType: String
|
||||
blockLayout: String
|
||||
challengeFiles: [FileContents]
|
||||
explanation: String
|
||||
notes: String
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { HandlerProps } from 'react-reflex';
|
||||
import { SuperBlocks } from '../../../shared/config/curriculum';
|
||||
import { BlockTypes } from '../../../shared/config/blocks';
|
||||
import { BlockLayouts, BlockTypes } from '../../../shared/config/blocks';
|
||||
import { Themes } from '../components/settings/theme';
|
||||
import { type CertTitle } from '../../config/cert-and-project-map';
|
||||
|
||||
@@ -167,6 +167,7 @@ export type ChallengeNode = {
|
||||
challenge: {
|
||||
block: string;
|
||||
blockType: BlockTypes;
|
||||
blockLayout: BlockLayouts;
|
||||
certification: string;
|
||||
challengeOrder: number;
|
||||
challengeType: number;
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ChallengeNode, CompletedChallenge } from '../../../redux/prop-types';
|
||||
import { playTone } from '../../../utils/tone';
|
||||
import { makeExpandedBlockSelector, toggleBlock } from '../redux';
|
||||
import { isGridBased, isProjectBased } from '../../../utils/curriculum-layout';
|
||||
import { BlockTypes } from '../../../../../shared/config/blocks';
|
||||
import { BlockLayouts, BlockTypes } from '../../../../../shared/config/blocks';
|
||||
import Challenges from './challenges';
|
||||
import BlockLabel from './block-label';
|
||||
|
||||
@@ -151,7 +151,12 @@ class Block extends Component<BlockProps> {
|
||||
</div>
|
||||
);
|
||||
|
||||
const Block = (
|
||||
/**
|
||||
* ChallengeListBlock displays challenges in a list.
|
||||
* This layout is used in backend blocks, The Odin Project blocks, and blocks in legacy certification.
|
||||
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#basic-javascript
|
||||
*/
|
||||
const ChallengeListBlock = (
|
||||
<>
|
||||
{' '}
|
||||
<ScrollableAnchor id={block}>
|
||||
@@ -209,7 +214,12 @@ class Block extends Component<BlockProps> {
|
||||
</>
|
||||
);
|
||||
|
||||
const ProjectBlock = (
|
||||
/**
|
||||
* ProjectListBlock displays a list of certification projects.
|
||||
* This layout is used in legacy certifications.
|
||||
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#javascript-algorithms-and-data-structures-projects
|
||||
*/
|
||||
const ProjectListBlock = (
|
||||
<>
|
||||
<ScrollableAnchor id={block}>
|
||||
<div className='block'>
|
||||
@@ -247,7 +257,12 @@ class Block extends Component<BlockProps> {
|
||||
return `${percentageCompleted}% ${t('learn.completed')}`;
|
||||
};
|
||||
|
||||
const GridBlock = (
|
||||
/**
|
||||
* ChallengeGridBlock displays challenges in a grid.
|
||||
* This layout is used for step-based blocks.
|
||||
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#learn-html-by-building-a-cat-photo-app
|
||||
*/
|
||||
const ChallengeGridBlock = (
|
||||
<>
|
||||
{' '}
|
||||
<ScrollableAnchor id={block}>
|
||||
@@ -304,7 +319,12 @@ class Block extends Component<BlockProps> {
|
||||
</>
|
||||
);
|
||||
|
||||
const GridProjectBlock = (
|
||||
/**
|
||||
* LinkBlock displays the block as a single link.
|
||||
* This layout is used if the block has a single challenge.
|
||||
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#build-a-survey-form-project
|
||||
*/
|
||||
const LinkBlock = (
|
||||
<ScrollableAnchor id={block}>
|
||||
<div className='block block-grid grid-project-block'>
|
||||
<div className='tags-wrapper'>
|
||||
@@ -346,14 +366,24 @@ class Block extends Component<BlockProps> {
|
||||
</ScrollableAnchor>
|
||||
);
|
||||
|
||||
const blockrenderer = () => {
|
||||
if (isProjectBlock) return isGridBlock ? GridProjectBlock : ProjectBlock;
|
||||
return isGridBlock ? GridBlock : Block;
|
||||
const blockRenderer = () => {
|
||||
const blockLayout = challenges[0].blockLayout;
|
||||
|
||||
// `blockLayout` property isn't available in all challenges
|
||||
if (!blockLayout) {
|
||||
if (isProjectBlock) return isGridBlock ? LinkBlock : ProjectListBlock;
|
||||
return isGridBlock ? ChallengeGridBlock : ChallengeListBlock;
|
||||
}
|
||||
|
||||
if (blockLayout === BlockLayouts.ChallengeGrid) return ChallengeGridBlock;
|
||||
if (blockLayout === BlockLayouts.ChallengeList) return ChallengeListBlock;
|
||||
if (blockLayout === BlockLayouts.Link) return LinkBlock;
|
||||
if (blockLayout === BlockLayouts.ProjectList) return ProjectListBlock;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{blockrenderer()}
|
||||
{blockRenderer()}
|
||||
{isGridBlock && !isProjectBlock ? null : <Spacer size='medium' />}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -305,6 +305,7 @@ export const query = graphql`
|
||||
order
|
||||
superBlock
|
||||
dashedName
|
||||
blockLayout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +287,7 @@ function generateChallengeCreator(lang, englishPath, i18nPath) {
|
||||
|
||||
challenge.block = meta.dashedName;
|
||||
challenge.blockType = meta.blockType;
|
||||
challenge.blockLayout = meta.blockLayout;
|
||||
challenge.hasEditableBoundaries = !!meta.hasEditableBoundaries;
|
||||
challenge.order = meta.order;
|
||||
// const superOrder = getSuperOrder(meta.superBlock);
|
||||
|
||||
@@ -132,6 +132,15 @@ const schema = Joi.object()
|
||||
).required(),
|
||||
otherwise: Joi.valid(null)
|
||||
}),
|
||||
blockLayout: Joi.when('superBlock', {
|
||||
is: [SuperBlocks.FrontEndDevelopment],
|
||||
then: Joi.valid(
|
||||
'challenge-list',
|
||||
'challenge-grid',
|
||||
'link',
|
||||
'project-list'
|
||||
)
|
||||
}),
|
||||
challengeOrder: Joi.number(),
|
||||
certification: Joi.string().regex(slugWithSlashRE),
|
||||
challengeType: Joi.number().min(0).max(23).required(),
|
||||
|
||||
@@ -129,6 +129,15 @@ const schema = Joi.object()
|
||||
).required(),
|
||||
otherwise: Joi.valid(null)
|
||||
}),
|
||||
blockLayout: Joi.when('superBlock', {
|
||||
is: [SuperBlocks.FrontEndDevelopment],
|
||||
then: Joi.valid(
|
||||
'challenge-list',
|
||||
'challenge-grid',
|
||||
'link',
|
||||
'project-list'
|
||||
)
|
||||
}),
|
||||
challengeOrder: Joi.number(),
|
||||
certification: Joi.string().regex(slugWithSlashRE),
|
||||
challengeType: Joi.number().min(0).max(23).required(),
|
||||
|
||||
@@ -7,6 +7,12 @@ const schema = Joi.object()
|
||||
.keys({
|
||||
name: Joi.string().required(),
|
||||
blockType: Joi.valid('workshop', 'lab', 'lecture', 'quiz', 'exam'),
|
||||
blockLayout: Joi.valid(
|
||||
'challenge-list',
|
||||
'challenge-grid',
|
||||
'link',
|
||||
'project-list'
|
||||
),
|
||||
isUpcomingChange: Joi.boolean().required(),
|
||||
dashedName: Joi.string().regex(slugRE).required(),
|
||||
superBlock: Joi.string().regex(slugWithSlashRE).required(),
|
||||
|
||||
@@ -6,3 +6,33 @@ export enum BlockTypes {
|
||||
quiz = 'quiz',
|
||||
exam = 'exam'
|
||||
}
|
||||
|
||||
export enum BlockLayouts {
|
||||
/**
|
||||
* ChallengeList displays challenges in a list.
|
||||
* This layout is used in backend blocks, The Odin Project blocks, and blocks in legacy certification.
|
||||
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#basic-javascript
|
||||
*/
|
||||
ChallengeList = 'challenge-list',
|
||||
|
||||
/**
|
||||
* ChallengeGrid displays challenges in a grid.
|
||||
* This layout is used for step-based blocks.
|
||||
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#learn-html-by-building-a-cat-photo-app
|
||||
*/
|
||||
ChallengeGrid = 'challenge-grid',
|
||||
|
||||
/**
|
||||
* Link displays the block as a single link.
|
||||
* This layout is used if the block has a single challenge.
|
||||
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#build-a-survey-form-project
|
||||
*/
|
||||
Link = 'link',
|
||||
|
||||
/**
|
||||
* ProjectList displays a list of certification projects.
|
||||
* This layout is used in legacy certifications.
|
||||
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#javascript-algorithms-and-data-structures-projects
|
||||
*/
|
||||
ProjectList = 'project-list'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user