diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 415de15b4a5..794cb283578 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -1727,7 +1727,10 @@ "intro": ["For this lab, you will create a video compilation web page."] }, "bzfv": { "title": "8", "intro": [] }, - "snuv": { "title": "9", "intro": [] }, + "review-basic-html": { + "title": "Basic HTML Review", + "intro": ["Review the basic HTML topics."] + }, "quiz-basic-html": { "title": "Basic HTML Quiz", "intro": [ diff --git a/client/src/pages/learn/front-end-development/review-basic-html/index.md b/client/src/pages/learn/front-end-development/review-basic-html/index.md new file mode 100644 index 00000000000..859531a8ee9 --- /dev/null +++ b/client/src/pages/learn/front-end-development/review-basic-html/index.md @@ -0,0 +1,9 @@ +--- +title: Introduction to the Basic HTML Review +block: review-basic-html +superBlock: front-end-development +--- + +## Introduction to the Basic HTML Review + +Review the basic HTML topics. diff --git a/client/src/templates/Challenges/generic/show.tsx b/client/src/templates/Challenges/generic/show.tsx new file mode 100644 index 00000000000..d40de1a1501 --- /dev/null +++ b/client/src/templates/Challenges/generic/show.tsx @@ -0,0 +1,260 @@ +import { graphql } from 'gatsby'; +import React, { useEffect, useRef, useState } from 'react'; +import Helmet from 'react-helmet'; +import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { Container, Col, Row, Button } from '@freecodecamp/ui'; + +// Local Utilities +import Spacer from '../../../components/helpers/spacer'; +import LearnLayout from '../../../components/layouts/learn'; +import { ChallengeNode, ChallengeMeta, Test } from '../../../redux/prop-types'; +import ChallengeDescription from '../components/challenge-description'; +import Hotkeys from '../components/hotkeys'; +import ChallengeTitle from '../components/challenge-title'; +import VideoPlayer from '../components/video-player'; +import CompletionModal from '../components/completion-modal'; +import Assignments from '../components/assignments'; +import { + challengeMounted, + updateChallengeMeta, + openModal, + updateSolutionFormValues, + initTests +} from '../redux/actions'; +import { isChallengeCompletedSelector } from '../redux/selectors'; +import { BlockTypes } from '../../../../../shared/config/blocks'; + +// Redux Setup +const mapStateToProps = (state: unknown) => ({ + isChallengeCompleted: isChallengeCompletedSelector(state) as boolean +}); + +const mapDispatchToProps = { + initTests, + updateChallengeMeta, + challengeMounted, + updateSolutionFormValues, + openCompletionModal: () => openModal('completion') +}; + +// Types +interface ShowQuizProps { + challengeMounted: (arg0: string) => void; + data: { challengeNode: ChallengeNode }; + description: string; + initTests: (xs: Test[]) => void; + isChallengeCompleted: boolean; + openCompletionModal: () => void; + pageContext: { + challengeMeta: ChallengeMeta; + }; + updateChallengeMeta: (arg0: ChallengeMeta) => void; + updateSolutionFormValues: () => void; +} + +const ShowGeneric = ({ + challengeMounted, + data: { + challengeNode: { + challenge: { + assignments, + bilibiliIds, + block, + blockType, + description, + challengeType, + fields: { tests }, + helpCategory, + instructions, + title, + translationPending, + superBlock, + videoId, + videoLocaleIds + } + } + }, + pageContext: { challengeMeta }, + initTests, + updateChallengeMeta, + openCompletionModal, + isChallengeCompleted +}: ShowQuizProps) => { + const { t } = useTranslation(); + const { nextChallengePath, prevChallengePath } = challengeMeta; + const container = useRef(null); + + const blockNameTitle = `${t( + `intro:${superBlock}.blocks.${block}.title` + )} - ${title}`; + + useEffect(() => { + initTests(tests); + updateChallengeMeta({ + ...challengeMeta, + title, + challengeType, + helpCategory + }); + challengeMounted(challengeMeta.id); + container.current?.focus(); + // This effect should be run once on mount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + updateChallengeMeta({ + ...challengeMeta, + title, + challengeType, + helpCategory + }); + challengeMounted(challengeMeta.id); + }, [ + title, + challengeMeta, + challengeType, + helpCategory, + challengeMounted, + updateChallengeMeta + ]); + + // video + const [videoIsLoaded, setVideoIsLoaded] = useState(false); + + const handleVideoIsLoaded = () => { + setVideoIsLoaded(true); + }; + + // assignments + const [assignmentsCompleted, setAssignmentsCompleted] = useState(0); + const allAssignmentsCompleted = assignmentsCompleted === assignments.length; + + const handleAssignmentChange = ( + event: React.ChangeEvent + ) => { + const isCompleted = event.target.checked; // extract value before target is nullified + setAssignmentsCompleted(a => (isCompleted ? a + 1 : a - 1)); + }; + + // submit + const handleSubmit = () => { + if (assignments.length == 0 || allAssignmentsCompleted) { + openCompletionModal(); + } + }; + + return ( + + + + + + + + {title} + + + + {description && ( + + )} + + + + {videoId && ( + + )} + + + + {instructions && ( + + )} + + + + {assignments.length > 0 && ( + + )} + + + + + + + + + + + ); +}; + +ShowGeneric.displayName = 'ShowGeneric'; + +export default connect(mapStateToProps, mapDispatchToProps)(ShowGeneric); + +export const query = graphql` + query GenericChallenge($id: String!) { + challengeNode(id: { eq: $id }) { + challenge { + assignments + bilibiliIds { + aid + bvid + cid + } + block + blockType + challengeType + description + helpCategory + instructions + fields { + blockName + slug + tests { + text + testString + } + } + superBlock + title + translationPending + videoId + videoId + videoLocaleIds { + espanol + italian + portuguese + } + } + } + } +`; diff --git a/client/utils/gatsby/challenge-page-creator.js b/client/utils/gatsby/challenge-page-creator.js index 3359b592560..b2572d77823 100644 --- a/client/utils/gatsby/challenge-page-creator.js +++ b/client/utils/gatsby/challenge-page-creator.js @@ -61,6 +61,11 @@ const fillInTheBlank = path.resolve( '../../src/templates/Challenges/fill-in-the-blank/show.tsx' ); +const generic = path.resolve( + __dirname, + '../../src/templates/Challenges/generic/show.tsx' +); + const views = { backend, classic, @@ -73,8 +78,8 @@ const views = { exam, msTrophy, dialogue, - fillInTheBlank - // quiz: Quiz + fillInTheBlank, + generic }; function getIsFirstStepInBlock(id, edges) { diff --git a/curriculum/challenges/_meta/review-basic-html/meta.json b/curriculum/challenges/_meta/review-basic-html/meta.json new file mode 100644 index 00000000000..1536ac136ae --- /dev/null +++ b/curriculum/challenges/_meta/review-basic-html/meta.json @@ -0,0 +1,10 @@ +{ + "name": "Basic HTML Review", + "isUpcomingChange": true, + "dashedName": "review-basic-html", + "order": 9, + "superBlock": "front-end-development", + "challengeOrder": [{ "id": "67072fc183c7ca6c588feb4d", "title": "Basic HTML Review" }], + "helpCategory": "HTML-CSS", + "blockType": "review" +} diff --git a/curriculum/challenges/english/25-front-end-development/review-basic-html/67072fc183c7ca6c588feb4d.md b/curriculum/challenges/english/25-front-end-development/review-basic-html/67072fc183c7ca6c588feb4d.md new file mode 100644 index 00000000000..b4d1afc3264 --- /dev/null +++ b/curriculum/challenges/english/25-front-end-development/review-basic-html/67072fc183c7ca6c588feb4d.md @@ -0,0 +1,61 @@ +--- +id: 67072fc183c7ca6c588feb4d +title: Basic HTML Review +challengeType: 24 +dashedName: basic-html-review +--- + +# --description-- + +Review the concepts below to prepare for the upcoming quiz. + +## HTML Basics + +- **Role of HTML**: Foundation of web structure. +- **Block-level vs. inline elements**: Understanding `div` and `span`. +- **Attributes**: Adding metadata and behavior to elements. + +## Identifiers and Grouping + +- **IDs**: Unique element identifiers. +- **Classes**: Grouping elements for styling and behavior. + +## Special Characters and Linking + +- **HTML entities**: Using special characters like `&` and `<`. +- **`` element**: Linking to external stylesheets. +- **`