feat(learn): add catalog (#65596)

Co-authored-by: jdwilkin4 <jwilkin4@hotmail.com>
This commit is contained in:
Ahmad Abdolsaheb
2026-02-11 15:04:30 +03:00
committed by GitHub
parent 0ed5f0d7f1
commit e37faff9e6
132 changed files with 4303 additions and 1284 deletions
+5 -3
View File
@@ -10,8 +10,9 @@ import {
LangCodes
} from '@freecodecamp/shared/config/i18n';
import {
catalogSuperBlocks,
SuperBlocks
SuperBlocks,
superBlockStages,
SuperBlockStage
} from '@freecodecamp/shared/config/curriculum';
import intro from './locales/english/intro.json';
@@ -85,13 +86,14 @@ describe('Locale tests:', () => {
describe('Intro file structure tests:', () => {
const typedIntro = intro as unknown as Intro;
const superblocks = Object.values(SuperBlocks);
const catalogSuperBlocks = superBlockStages[SuperBlockStage.Catalog];
for (const superBlock of superblocks) {
test(`superBlock ${superBlock} has required properties`, () => {
expect(typeof typedIntro[superBlock].title).toBe('string');
// catalog superblocks should have a summary
if (catalogSuperBlocks.includes(superBlock)) {
expect(typedIntro[superBlock].intro).toBeInstanceOf(Array);
expect(typedIntro[superBlock].summary).toBeInstanceOf(Array);
}
expect(typedIntro[superBlock].intro).toBeInstanceOf(Array);
File diff suppressed because it is too large Load Diff
+22 -1
View File
@@ -204,6 +204,10 @@
],
"cta": "Start Learning Now (it's free)"
},
"catalog": {
"heading": "Explore Course Catalog",
"seeAll": "See All Courses"
},
"certification-heading": "Earn free verified certifications in:",
"core-certs-heading": "Recommended curriculum:",
"learn-english-heading": "Learn English for Developers:",
@@ -710,7 +714,8 @@
"exam": "Exam",
"warm-up": "Warm-up",
"learn": "Learn",
"practice": "Practice"
"practice": "Practice",
"video": "Video"
},
"archive": {
"title": "Archived Coursework",
@@ -1257,6 +1262,7 @@
"college-algebra-with-python-v8-cert": "College Algebra with Python Certification",
"foundational-c-sharp-with-microsoft": "Foundational C# with Microsoft",
"foundational-c-sharp-with-microsoft-cert": "Foundational C# with Microsoft Certification",
"learn-python-for-beginners": "Learn Python for Beginners",
"a2-english-for-developers": "A2 English for Developers",
"a2-english-for-developers-cert": "A2 English for Developers Certification (Beta)",
"b1-english-for-developers": "B1 English for Developers",
@@ -1429,6 +1435,21 @@
"beginner": "Beginner",
"intermediate": "Intermediate",
"advanced": "Advanced"
},
"duration": "{{duration}} hours",
"no-results": "No courses found. Try adjusting your filters to see more results.",
"topic": {
"html": "HTML",
"css": "CSS",
"js": "JavaScript",
"react": "React",
"python": "Python",
"data-analysis": "Data Analysis",
"machine-learning": "Machine Learning",
"d3": "D3",
"api": "APIs",
"information-security": "Information Security",
"computer-fundamentals": "Computer Fundamentals"
}
}
}
+25
View File
@@ -56,6 +56,31 @@ const iconMap = {
[SuperBlocks.SemanticHtml]: Code,
[SuperBlocks.FullStackOpen]: Code,
[SuperBlocks.DevPlayground]: Code,
[SuperBlocks.HtmlFormsAndTables]: ResponsiveDesign,
[SuperBlocks.LabSurveyForm]: Code,
[SuperBlocks.HtmlAndAccessibility]: ResponsiveDesign,
[SuperBlocks.ComputerBasics]: Code,
[SuperBlocks.BasicCss]: Code,
[SuperBlocks.DesignForDevelopers]: Code,
[SuperBlocks.AbsoluteAndRelativeUnits]: Code,
[SuperBlocks.PseudoClassesAndElements]: Code,
[SuperBlocks.CssColors]: Code,
[SuperBlocks.StylingForms]: Code,
[SuperBlocks.CssBoxModel]: Code,
[SuperBlocks.CssFlexbox]: Code,
[SuperBlocks.LabPageOfPlayingCards]: Code,
[SuperBlocks.CssTypography]: Code,
[SuperBlocks.CssAndAccessibility]: ResponsiveDesign,
[SuperBlocks.CssPositioning]: Code,
[SuperBlocks.AttributeSelectors]: Code,
[SuperBlocks.LabBookInventoryApp]: Code,
[SuperBlocks.ResponsiveDesign]: ResponsiveDesign,
[SuperBlocks.LabTechnicalDocumentationPage]: Code,
[SuperBlocks.CssVariables]: Code,
[SuperBlocks.CssGrid]: Code,
[SuperBlocks.LabProductLandingPage]: Code,
[SuperBlocks.CssAnimations]: Code,
[SuperBlocks.LearnPythonForBeginners]: PythonIcon,
[SuperBlocks.RespWebDesignV9]: ResponsiveDesign,
[SuperBlocks.JsV9]: JavaScriptIcon,
[SuperBlocks.FrontEndDevLibsV9]: ReactIcon,
+5 -1
View File
@@ -94,7 +94,11 @@ function Map({ forLanding = false }: MapProps) {
showUpcomingChanges
})
// remove legacy superblocks from main maps - shown in archive map only
.filter(stage => stage !== SuperBlockStage.Legacy)
.filter(
stage =>
stage !== SuperBlockStage.Legacy &&
stage !== SuperBlockStage.Catalog
)
.map(stage => {
const superblocks = superBlockStages[stage];
if (superblocks.length === 0) {
+61
View File
@@ -0,0 +1,61 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faClock, faStairs } from '@fortawesome/free-solid-svg-icons';
import { useTranslation } from 'react-i18next';
import { Link } from './helpers';
interface CatalogItemProps {
superBlock: string;
level: string;
hours: number;
topic: string;
showAllSummaries?: boolean;
}
const CatalogItem: React.FC<CatalogItemProps> = ({
superBlock,
level,
hours,
topic,
showAllSummaries = false
}) => {
const { t } = useTranslation();
const { title, summary } = t(`intro:${superBlock}`, {
returnObjects: true
}) as {
title: string;
summary: string[];
};
return (
<Link to={`/learn/${superBlock}`} key={superBlock} className='catalog-item'>
<div className='catalog-item-top'>
<div className={`block-label block-label-${topic}`}>
{t(`curriculum.catalog.topic.${topic}`)}
</div>
<h3>{title}</h3>
{showAllSummaries ? (
summary.map((text, i) => <p key={i}>{text}</p>)
) : summary && summary.length > 0 ? (
<p>{summary[0]}</p>
) : null}
</div>
<div className='catalog-item-bottom'>
<div>
<FontAwesomeIcon icon={faStairs} />
&nbsp; {t(`curriculum.catalog.levels.${level}`)}
</div>
<div>
<FontAwesomeIcon icon={faClock} />
&nbsp;{' '}
{showAllSummaries
? t('curriculum.catalog.duration', { duration: hours })
: `${hours} hours`}
</div>
</div>
</Link>
);
};
export default CatalogItem;
@@ -22,6 +22,7 @@ const Faq = (): JSX.Element => {
xs={12}
className='faq-section'
>
<Spacer size='l' />
<h2 className='big-heading'>{t('landing.faq')}</h2>
<Spacer size='xs' />
{faqItems.map((faq, i) => (
@@ -0,0 +1,73 @@
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Col, Row, Container } from '@freecodecamp/ui';
import { Link } from '../../helpers';
import { catalog } from '@freecodecamp/shared/config/catalog';
import { SuperBlocks } from '@freecodecamp/shared/config/curriculum';
import CatalogItem from '../../catalog-item';
import '../landing.css';
import LinkButton from '../../../assets/icons/link-button';
const LandingCatalog = (): JSX.Element => {
const { t } = useTranslation();
const featuredCourses = useMemo(() => {
// Get featured courses: Learn Python for Beginners, Computer Basics, Basic HTML
const featuredSuperBlocks = [
SuperBlocks.LearnPythonForBeginners,
SuperBlocks.ComputerBasics,
SuperBlocks.BasicHtml
];
const courses = catalog.filter(course =>
featuredSuperBlocks.includes(course.superBlock)
);
// Sort by the order in featuredSuperBlocks
return courses.sort(
(a, b) =>
featuredSuperBlocks.indexOf(a.superBlock) -
featuredSuperBlocks.indexOf(b.superBlock)
);
}, []);
return (
<div className='landing-catalog landing-catalog-container'>
<Container>
<Row>
<Col xs={12}>
<h2 className='big-heading text-center'>
{t('landing.catalog.heading')}
</h2>
</Col>
</Row>
</Container>
<Container fluid={true} className='landing-catalog-container'>
<Col md={10} mdOffset={1} sm={12} xs={12}>
<section className='landing-catalog-wrap'>
{featuredCourses.map(course => {
const { superBlock, level, hours, topic } = course;
return (
<CatalogItem
key={superBlock}
superBlock={superBlock}
level={level}
hours={hours}
topic={topic}
showAllSummaries={false}
/>
);
})}
<Link to='/catalog' className='catalog-item catalog-item-see-all'>
<h3>{t('landing.catalog.seeAll')}</h3>
<LinkButton />
</Link>
</section>
</Col>
</Container>
</div>
);
};
LandingCatalog.displayName = 'LandingCatalog';
export default LandingCatalog;
+25
View File
@@ -455,3 +455,28 @@ figcaption.caption {
font-weight: normal;
text-align: center;
}
/* Landing Catalog Styles */
.landing-catalog-container {
background-color: var(--primary-background);
padding-top: 3rem;
padding-bottom: 3rem;
}
.landing-catalog-wrap {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
width: 100%;
gap: 2rem;
}
.landing-catalog .catalog-item.catalog-item-see-all {
display: flex;
align-items: center;
justify-content: center;
min-height: 280px;
text-align: center;
fill: var(--secondary-color);
flex-direction: row;
gap: 10px;
}
+65 -4
View File
@@ -1,22 +1,83 @@
.catalog-wrap {
display: flex;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
width: 100%;
gap: 2rem;
justify-content: space-evenly;
}
.catalog-filters {
display: flex;
gap: 1rem;
justify-content: flex-start;
flex-wrap: wrap;
margin-bottom: 1rem;
}
.catalog-filters .dropdown {
min-width: 250px;
}
.catalog-filters .dropdown-menu {
max-height: 300px;
overflow-y: auto;
}
.catalog-filters .dropdown-item {
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
}
.catalog-filters button {
display: flex;
width: 100%;
align-items: center;
}
.catalog-filters .dropdown-menu .dropdown-item input[type='checkbox'] {
flex-shrink: 0;
}
.filter-checkbox {
cursor: pointer;
width: 18px;
height: 18px;
margin: 0 0.5rem 0 0;
vertical-align: middle;
flex-shrink: 0;
}
.catalog-item-top {
display: flex;
flex-direction: column;
gap: 10px;
}
.catalog-item {
text-decoration: none;
padding: 1rem;
background-color: var(--primary-background);
width: 400px;
min-height: 300px;
display: flex;
flex-direction: column;
justify-content: space-between;
border: 1px solid var(--background-quaternary);
max-width: 400px;
}
.catalog-item h3 {
margin: 0;
}
.catalog-item-bottom {
display: flex;
justify-content: space-between;
align-items: flex-end;
color: var(--quaternary-color);
font-size: 0.9rem;
}
.catalog-item p {
margin-bottom: 0.9rem;
}
+146 -35
View File
@@ -1,55 +1,166 @@
import React from 'react';
import React, { useState, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Col, Spacer } from '@freecodecamp/ui';
import { ButtonLink } from '../components/helpers';
import { Col, Spacer, Dropdown, MenuItem, Alert } from '@freecodecamp/ui';
import { catalog } from '@freecodecamp/shared/config/catalog';
import { showUpcomingChanges } from '../../config/env.json';
import FourOhFour from '../components/FourOhFour';
import CatalogItem from '../components/catalog-item';
import './catalog.css';
const CatalogPage = () => {
const { t } = useTranslation();
const [selectedLevels, setSelectedLevels] = useState<string[]>(['all']);
const [selectedTopics, setSelectedTopics] = useState<string[]>(['all']);
// Extract unique levels and topics from catalog
const uniqueLevels = useMemo(() => {
const levels = [...new Set(catalog.map(item => item.level))];
return levels.sort();
}, []);
const uniqueTopics = useMemo(() => {
const topics = [...new Set(catalog.map(item => item.topic))];
return topics.sort();
}, []);
// Handle level filter change
const handleLevelChange = (level: string) => {
if (level === 'all') {
setSelectedLevels(['all']);
} else {
setSelectedLevels(prev => {
const filtered = prev.filter(l => l !== 'all');
if (filtered.includes(level)) {
const updated = filtered.filter(l => l !== level);
return updated.length === 0 ? ['all'] : updated;
} else {
return [...filtered, level];
}
});
}
};
// Handle topic filter change
const handleTopicChange = (topic: string) => {
if (topic === 'all') {
setSelectedTopics(['all']);
} else {
setSelectedTopics(prev => {
const filtered = prev.filter(t => t !== 'all');
if (filtered.includes(topic)) {
const updated = filtered.filter(t => t !== topic);
return updated.length === 0 ? ['all'] : updated;
} else {
return [...filtered, topic];
}
});
}
};
const filteredCatalog = useMemo(() => {
return catalog.filter(course => {
const levelMatch =
selectedLevels.includes('all') || selectedLevels.includes(course.level);
const topicMatch =
selectedTopics.includes('all') || selectedTopics.includes(course.topic);
return levelMatch && topicMatch;
});
}, [selectedLevels, selectedTopics]);
return showUpcomingChanges ? (
<main>
<Spacer size='l' />
<h1 className='text-center'>{t('curriculum.catalog.title')}</h1>
<Spacer size='l' />
<Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
<section className='catalog-wrap'>
{catalog.map(course => {
const { superBlock, level, hours } = course;
<div className='catalog-filters'>
<Dropdown block={true}>
<Dropdown.Toggle id='level-filter-dropdown'>
Level:{' '}
{selectedLevels.includes('all')
? 'All'
: `${selectedLevels.length} selected`}
</Dropdown.Toggle>
<Dropdown.Menu>
<MenuItem onClick={() => handleLevelChange('all')}>
<input
type='checkbox'
checked={selectedLevels.includes('all')}
onChange={() => {}}
className='filter-checkbox'
/>
All
</MenuItem>
{uniqueLevels.map(level => (
<MenuItem key={level} onClick={() => handleLevelChange(level)}>
<input
type='checkbox'
checked={selectedLevels.includes(level)}
onChange={() => {}}
className='filter-checkbox'
/>
{t(`curriculum.catalog.levels.${level}`)}
</MenuItem>
))}
</Dropdown.Menu>
</Dropdown>
<Dropdown block={true}>
<Dropdown.Toggle id='topic-filter-dropdown'>
Topic:{' '}
{selectedTopics.includes('all')
? 'All'
: `${selectedTopics.length} selected`}
</Dropdown.Toggle>
<Dropdown.Menu>
<MenuItem onClick={() => handleTopicChange('all')}>
<input
type='checkbox'
checked={selectedTopics.includes('all')}
onChange={() => {}}
className='filter-checkbox'
/>
All
</MenuItem>
{uniqueTopics.map(topic => (
<MenuItem key={topic} onClick={() => handleTopicChange(topic)}>
<input
type='checkbox'
checked={selectedTopics.includes(topic)}
onChange={() => {}}
className='filter-checkbox'
/>
{t(`curriculum.catalog.topic.${topic}`)}
</MenuItem>
))}
</Dropdown.Menu>
</Dropdown>
</div>
</Col>
<Spacer size='m' />
<Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
{filteredCatalog.length === 0 ? (
<Alert variant='info'>{t('curriculum.catalog.no-results')}</Alert>
) : (
<section className='catalog-wrap'>
{filteredCatalog.map(course => {
const { superBlock, level, hours, topic } = course;
const { title, summary } = t(`intro:${superBlock}`, {
returnObjects: true
}) as {
title: string;
summary: string[];
};
return (
<div className='catalog-item' key={superBlock}>
<div className='catalog-item-top'>
<h2>{title}</h2>
<hr />
{summary.map((text, i) => (
<p key={i}>{text}</p>
))}
</div>
<div className='catalog-item-bottom'>
<div>
{t(`curriculum.catalog.levels.${level}`)} &bull; {hours}{' '}
hours
</div>
<ButtonLink href={`/learn/${superBlock}`}>
{t('buttons.go-to-course')}
</ButtonLink>
</div>
</div>
);
})}
</section>
return (
<CatalogItem
key={superBlock}
superBlock={superBlock}
level={level}
hours={hours}
topic={topic}
showAllSummaries={true}
/>
);
})}
</section>
)}
</Col>
<Spacer size='l' />
</main>
+3
View File
@@ -6,9 +6,11 @@ import { Loader } from '../components/helpers';
import LandingTop from '../components/landing/components/landing-top';
import Testimonials from '../components/landing/components/testimonials';
import Certifications from '../components/landing/components/certifications';
import LandingCatalog from '../components/landing/components/landing-catalog';
import Faq from '../components/landing/components/faq';
import Benefits from '../components/landing/components/benefits';
import { useClaimableCertsNotification } from '../components/helpers/use-claimable-certs-notification';
import { showUpcomingChanges } from '../../config/env.json';
import '../components/landing/landing.css';
@@ -22,6 +24,7 @@ const Landing = () => (
<Benefits />
<Testimonials />
<Certifications />
{showUpcomingChanges && <LandingCatalog />}
<Faq />
</main>
);
@@ -0,0 +1,9 @@
---
title: Absolute and Relative Units
superBlock: absolute-and-relative-units
certification: absolute-and-relative-units
---
## Absolute and Relative Units
Understand when to use absolute and relative CSS units to build flexible layouts.
@@ -0,0 +1,9 @@
---
title: Attribute Selectors
superBlock: attribute-selectors
certification: attribute-selectors
---
## Attribute Selectors
Target elements precisely with CSS attribute selectors.
@@ -0,0 +1,9 @@
---
title: Basic CSS
superBlock: basic-css
certification: basic-css
---
## Basic CSS
Learn core CSS concepts and start styling real-world layouts.
@@ -0,0 +1,9 @@
---
title: Computer Basics
superBlock: computer-basics
certification: computer-basics
---
## Computer Basics
Build a foundation in computer, internet, and tooling basics for web development.
@@ -0,0 +1,9 @@
---
title: Accessibility
superBlock: css-and-accessibility
certification: css-and-accessibility
---
## CSS and Accessibility
Apply CSS techniques that support accessible and inclusive interfaces.
@@ -0,0 +1,9 @@
---
title: Animations
superBlock: css-animations
certification: css-animations
---
## CSS Animations
Create engaging UI motion with accessible CSS animations.
@@ -0,0 +1,9 @@
---
title: The Box Model
superBlock: css-box-model
certification: css-box-model
---
## CSS Box Model
Master the CSS box model, spacing, and layout effects for precise designs.
@@ -0,0 +1,9 @@
---
title: Colors
superBlock: css-colors
certification: css-colors
---
## CSS Colors
Work with CSS color formats and build cohesive color palettes.
@@ -0,0 +1,9 @@
---
title: Flexbox
superBlock: css-flexbox
certification: css-flexbox
---
## CSS Flexbox
Build responsive layouts using the Flexbox model and alignment tools.
+9
View File
@@ -0,0 +1,9 @@
---
title: Grid
superBlock: css-grid
certification: css-grid
---
## CSS Grid
Design complex layouts using the CSS Grid system.
@@ -0,0 +1,9 @@
---
title: Positioning
superBlock: css-positioning
certification: css-positioning
---
## CSS Positioning
Use positioning and floats to control layout and element flow.
@@ -0,0 +1,9 @@
---
title: Typography
superBlock: css-typography
certification: css-typography
---
## CSS Typography
Learn how to style text for readability, hierarchy, and visual balance.
@@ -0,0 +1,9 @@
---
title: Variables
superBlock: css-variables
certification: css-variables
---
## CSS Variables
Use CSS variables to build reusable, theme-friendly styles.
@@ -0,0 +1,9 @@
---
title: Design
superBlock: design-for-developers
certification: design-for-developers
---
## Design for Developers
Explore UI design fundamentals and user-centered design principles for developers.
@@ -0,0 +1,9 @@
---
title: Accessibility
superBlock: html-and-accessibility
certification: html-and-accessibility
---
## HTML and Accessibility
Learn how to write inclusive HTML using accessibility best practices and ARIA.
@@ -0,0 +1,9 @@
---
title: HTML Forms and Tables
superBlock: html-forms-and-tables
certification: html-forms-and-tables
---
## Introduction to HTML Forms and Tables
Learn how to build accessible forms and data tables with semantic HTML.
@@ -0,0 +1,9 @@
---
title: Build a Book Inventory App
superBlock: lab-book-inventory-app
certification: lab-book-inventory-app
---
## Build a Book Inventory App
Build a structured layout for managing a book inventory.
@@ -0,0 +1,9 @@
---
title: Build a Page of Playing Cards
superBlock: lab-page-of-playing-cards
certification: lab-page-of-playing-cards
---
## Build a Page of Playing Cards
Create a multi-card layout to practice flexible CSS composition.
@@ -0,0 +1,9 @@
---
title: Build a Product Landing Page
superBlock: lab-product-landing-page
certification: lab-product-landing-page
---
## Build a Product Landing Page
Build a complete landing page and apply layout, typography, and responsive design.
@@ -0,0 +1,9 @@
---
title: Build a Survey Form
superBlock: lab-survey-form
certification: lab-survey-form
---
## Build a Survey Form
Create a complete survey form while practicing HTML structure and accessible form controls.
@@ -0,0 +1,9 @@
---
title: Build a Technical Documentation Page
superBlock: lab-technical-documentation-page
certification: lab-technical-documentation-page
---
## Build a Technical Documentation Page
Create a documentation page and practice responsive structure and layout.
@@ -0,0 +1,9 @@
---
title: Learn Python for Beginners
superBlock: learn-python-for-beginners
certification: learn-python-for-beginners
---
## Introduction to Learn Python for Beginners
Learn the fundamentals of Python programming from the ground up. Python is one of the most popular programming languages today and is great for beginners.
@@ -0,0 +1,9 @@
---
title: Pseudo Classes and Elements
superBlock: pseudo-classes-and-elements
certification: pseudo-classes-and-elements
---
## Pseudo Classes and Elements
Use pseudo-classes and pseudo-elements to create richer, more interactive styles.
@@ -0,0 +1,9 @@
---
title: Responsive Design
superBlock: responsive-design
certification: responsive-design
---
## Responsive Design
Learn responsive design principles and build layouts that adapt to any screen.
@@ -0,0 +1,9 @@
---
title: Styling Forms
superBlock: styling-forms
certification: styling-forms
---
## Styling Forms
Apply CSS techniques to create clean, usable form layouts.
@@ -96,20 +96,27 @@ function SuperBlockIntro({
const { t } = useTranslation();
const superBlockIntroObj: {
title: string;
intro: string[];
intro: string[] | string;
note: string;
} = t(`intro:${superBlock}`, { returnObjects: true }) as {
title: string;
intro: string[];
intro: string[] | string;
note: string;
};
const {
title: i18nSuperBlock,
intro: superBlockIntroText,
intro: introRaw,
note: superBlockNoteText
} = superBlockIntroObj;
// Ensure intro is always an array
const superBlockIntroText = Array.isArray(introRaw)
? introRaw
: typeof introRaw === 'string'
? [introRaw]
: [''];
const IntroTopDefault = ({ fsd }: { fsd: boolean }) => (
<>
{archivedSuperBlocks.includes(superBlock) && <ArchivedWarning />}
+7 -1
View File
@@ -13,8 +13,9 @@
}
.block-label {
align-self: center;
align-self: start;
height: fit-content;
width: fit-content;
padding: 1px 6px 2px;
font-size: 0.85rem;
border: 1px solid;
@@ -27,26 +28,31 @@
background-color: var(--tertiary-background);
}
.block-label-html,
.block-label-lecture {
border-color: var(--yellow-color);
color: var(--yellow-color);
}
.block-label-css,
.block-label-workshop {
border-color: var(--highlight-color);
color: var(--highlight-color);
}
.block-label-python,
.block-label-lab {
border-color: var(--success-color);
color: var(--success-color);
}
.block-label-javascript,
.block-label-review {
border-color: var(--purple-color);
color: var(--purple-color);
}
.block-label-computer-fundamentals,
.block-label-quiz {
border-color: var(--danger-color);
color: var(--danger-color);
@@ -1,58 +0,0 @@
---
id: 669aff9f5488f1bea056416d
title: Step 1
challengeType: 0
dashedName: step-1
demoType: onLoad
---
# --description--
In this workshop, you will practice working with semantic HTML by building a blog page dedicated to Mr. Whiskers the cat.
To begin the project, add the `<!DOCTYPE html>`, and an `html` element with a `lang` attribute of `en`.
Remember that you learned how to build a basic HTML boilerplate like this in the previous module.
```html
<!DOCTYPE html>
<html lang="en">
<!--all other elements go here-->
</html>
```
# --hints--
You should have the `<!DOCTYPE html>`.
```js
assert.match(code, /<!DOCTYPE\s+html>/i);
```
You should have an opening `html` tag with the language set to english.
```js
assert.match(code, /<html\s+lang\s*=\s*('|")en\1\s*>/gi);
```
You should have a closing `html` tag.
```js
assert.match(code, /<\/html>/i);
```
Your `DOCTYPE` should come before the `html` element.
```js
assert.match(code, /<!DOCTYPE\s+html>[.\n\s]*<html\s+lang\s*=\s*('|")en\1\s*>/im)
```
# --seed--
## --seed-contents--
```html
--fcc-editable-region--
--fcc-editable-region--
```
@@ -1,43 +0,0 @@
---
id: 669fc7e141e4703748c558bf
title: Step 2
challengeType: 0
dashedName: step-2
---
# --description--
Inside the `html` element, add a `head` element.
# --hints--
You should have an opening `head` tag.
```js
assert.match(code, /<head>/i);
```
You should have a closing `head` tag.
```js
assert.match(code, /<\/head>/i);
```
Your opening `head` tag should come before the closing `head` tag.
```js
assert.match(code, /<head>[.\n\s]*<\/head>/im)
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
--fcc-editable-region--
--fcc-editable-region--
</html>
```
@@ -1,87 +0,0 @@
---
id: 669fc938d38e6e38ace9251e
title: Step 3
challengeType: 0
dashedName: step-3
---
# --description--
Inside your `head` element, nest a `meta` element with the `charset` attribute set to the value `"UTF-8"`.
Below that `meta` element, add a `title` element.
The `title` element's text should be `Mr. Whiskers' Blog`.
# --hints--
You should have a `meta` element.
```js
assert.isNotNull(document.querySelector("meta"));
```
The `meta` element is a void element, it should not have an end tag `</meta>`.
```js
assert.notMatch(code, /<\/meta>/i);
```
Your `meta` tag should have a `charset` attribute.
```js
assert.match(code, /<meta\s+charset\s*/i);
```
Your `charset` attribute should have a value of `"UTF-8"`.
```js
assert.match(code, /charset\s*=\s*('|")UTF-8\1/i);
```
Your `meta` element should be nested inside your `head` element.
```js
const meta = document.querySelector('head > meta');
assert.strictEqual(meta?.parentElement?.tagName, 'HEAD');
```
You should have an opening `title` tag.
```js
assert.match(code, /<title>/i);
```
You should have a closing `title` tag.
```js
assert.match(code, /<\/title>/i);
```
Your `title` element should be nested in your `head` element.
```js
assert.match(code, /<head>.*\s*<title>.*<\/title>.*\s*<\/head>/si);
```
Your `title` element should have the text `Mr. Whiskers' Blog`. You may need to check your spelling.
```js
const titleText = document.querySelector('title')?.innerText
assert.strictEqual(titleText, "Mr. Whiskers' Blog");
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
--fcc-editable-region--
<head>
</head>
--fcc-editable-region--
</html>
```
@@ -1,69 +0,0 @@
---
id: 669fcb06c3034a39f5431a38
title: Step 4
challengeType: 0
dashedName: step-4
---
# --description--
To prepare creating some actual content, add a `body` element below the `head` element.
# --hints--
You should have an opening `<body>` tag.
```js
assert.match(code, /<body>/i);
```
You should have a closing `</body>` tag.
```js
assert.match(code, /<\/body>/i);
```
You should not change your `head` element. Make sure you did not delete your closing tag.
```js
assert.match(code, /<head>/i);
assert.match(code, /<\/head>/i);
```
Your `body` element should come after your `head` element.
```js
assert.match(code, /<\/head>[.\n\s]*<body>/im)
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
--fcc-editable-region--
<head>
<title>Mr. Whiskers' Blog</title>
<meta charset="UTF-8" />
</head>
--fcc-editable-region--
</html>
```
# --solutions--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Mr. Whiskers' Blog</title>
<meta charset="UTF-8" />
</head>
<body></body>
</html>
```
@@ -1,60 +0,0 @@
---
id: 5dc174fcf86c76b9248c6eb2
title: Step 1
challengeType: 0
dashedName: step-1
demoType: onLoad
---
# --description--
In this workshop, you will continue working with basic HTML elements like headings, paragraphs, and lists by building a cat photo app.
Begin the workshop by adding an `h1` element with the text of `CatPhotoApp`.
# --hints--
The text `CatPhotoApp` should be present in the code. You may want to check your spelling.
```js
assert.match(code, /catphotoapp/i);
```
Your `h1` element should have an opening tag. Opening tags have this syntax: `<elementName>`.
```js
assert.exists(document.querySelector('h1'));
```
Your `h1` tags should be in lowercase. By convention, all HTML tags are written in lowercase.
```js
assert.notMatch(code, /<\/?H1>/);
```
Your `h1` element should have a closing tag. Closing tags have this syntax: `</elementName>`.
```js
assert.match(code, /<\/h1\>/);
```
Your `h1` element's text should be `CatPhotoApp`. You have either omitted the text, have a typo, or it is not between the `h1` element's opening and closing tags.
```js
assert.equal(document.querySelector('h1')?.innerText.toLowerCase(), 'catphotoapp');
```
# --seed--
## --seed-contents--
```html
<html>
<body>
--fcc-editable-region--
--fcc-editable-region--
</body>
</html>
```
@@ -1,86 +0,0 @@
---
id: 5dc1798ff86c76b9248c6eb3
title: Step 2
challengeType: 0
dashedName: step-2
---
# --description--
Below the `h1` element, add an `h2` element with this text:
`Cat Photos`
# --hints--
Your `h1` element should have an opening tag. Opening tags have this syntax: `<elementName>`.
```js
assert.exists(document.querySelector('h1'));
```
Your `h1` element should have a closing tag. Closing tags have this syntax: `</elementName>`.
```js
assert.match(code, /<\/h1\>/);
```
You should only have one `h1` element. Remove the extra.
```js
assert.lengthOf(document.querySelectorAll('h1'), 1);
```
Your `h1` element's text should be 'CatPhotoApp'. You have either omitted the text or have a typo.
```js
assert.equal(document.querySelector('h1')?.innerText.toLowerCase(), 'catphotoapp');
```
Your `h2` tags should be in lowercase. By convention, all HTML tags are written in lowercase.
```js
assert.notMatch(code, /<\/?H2>/);
```
Your `h2` element should have an opening tag. Opening tags have this syntax: `<elementName>`.
```js
assert.exists(document.querySelector('h2'));
```
Your `h2` element should have a closing tag. Closing tags have a `/` just after the `<` character.
```js
assert.match(code, /<\/h2\>/);
```
Your `h2` element's text should be `Cat Photos`. Only place the text `Cat Photos` between the opening and closing `h2` tags.
```js
assert.equal(document.querySelector('h2')?.innerText.toLowerCase(), 'cat photos');
```
Your `h2` element should be below the `h1` element. The `h1` element has greater importance and must be above the `h2` element.
```js
const collection = [...document.querySelectorAll('h1,h2')].map(
(node) => node.nodeName
);
assert.isBelow(collection.indexOf('H1'), collection.indexOf('H2'));
```
# --seed--
## --seed-contents--
```html
<html>
<body>
--fcc-editable-region--
<h1>CatPhotoApp</h1>
--fcc-editable-region--
</body>
</html>
```
@@ -1,66 +0,0 @@
---
id: 5dc17d3bf86c76b9248c6eb4
title: Step 3
challengeType: 0
dashedName: step-3
---
# --description--
Create a `p` element below your `h2` element and give it the following text:
`Everyone loves cute cats online!`
# --hints--
Your `p` element should have an opening tag. Opening tags have the following syntax: `<elementName>`.
```js
assert.exists(document.querySelector('p'));
```
Your `p` tags should be in lowercase. By convention, all HTML tags are written in lowercase.
```js
assert.notMatch(code, /<\/?P>/);
```
Your `p` element should have a closing tag. Closing tags have a `/` just after the `<` character.
```js
assert.match(code, /<\/p\>/);
```
Your `p` element's text should be `Everyone loves cute cats online!` You have either omitted the text or have a typo.
```js
const extraSpacesRemoved = document
.querySelector('p')
?.innerText.replace(/\s+/g, ' ');
assert.match(extraSpacesRemoved, /everyone loves cute cats online!$/i);
```
Your `p` element should be below the `h2` element. You have them in the wrong order.
```js
const collection = [...document.querySelectorAll('h2,p')].map(
(node) => node.nodeName
);
assert.isBelow(collection.indexOf('H2'), collection.indexOf('P'));
```
# --seed--
## --seed-contents--
```html
<html>
<body>
<h1>CatPhotoApp</h1>
--fcc-editable-region--
<h2>Cat Photos</h2>
--fcc-editable-region--
</body>
</html>
```
@@ -1,88 +0,0 @@
---
id: 5dc17dc8f86c76b9248c6eb5
title: Step 4
challengeType: 0
dashedName: step-4
---
# --description--
Commenting allows you to leave messages without affecting the browser display. It also allows you to make code inactive. A comment in HTML starts with `<!--`, contains any number of lines of text, and ends with `-->`.
Here is an example of a comment with the `TODO: Remove h1`:
```html
<!-- TODO: Remove h1 -->
```
Add a comment above the `p` element with this text:
`TODO: Add link to cat photos`
# --hints--
Your comment should start with `<!--`. You are missing one or more of the characters that define the start of a comment.
```js
assert.match(code, /<!--/);
```
Your comment should end with `-->`. You are missing one or more of the characters that define the end of a comment.
```js
assert.match(code, /-->/);
```
Your code should not have extra opening/closing comment characters. You have an extra `<!--` or `-->` displaying in the browser.
```js
const noSpaces = code.replace(/\s/g, '');
assert.isBelow(noSpaces.match(/<!--/g)?.length, 2)
assert.isBelow(noSpaces.match(/-->/g)?.length, 2);
```
Your comment should be above the `p` element. You have them in the wrong order.
```js
assert.match(
code.replace(/\s/g, ''),
/<!--(.*?)--><p>everyonelovescutecatsonline!<\/p>/i
);
```
Your comment should contain the text `TODO: Add link to cat photos`.
```js
assert.match(code, /<!--\s*todo:\s+add\s+link\s+to\s+cat\s+photos\s*-->/i);
```
# --seed--
## --seed-contents--
```html
<html>
<body>
<h1>CatPhotoApp</h1>
<h2>Cat Photos</h2>
--fcc-editable-region--
<p>Everyone loves cute cats online!</p>
--fcc-editable-region--
</body>
</html>
```
# --solutions--
```html
<html>
<body>
<h1>CatPhotoApp</h1>
<h2>Cat Photos</h2>
<!-- TODO: Add link to cat photos -->
<p>Everyone loves cute cats online!</p>
</body>
</html>
```
@@ -1,335 +0,0 @@
---
id: 66ebd4ae2812430bb883c787
title: Build an Event Hub
challengeType: 25
dashedName: lab-event-hub
demoType: onClick
---
# --description--
In this lab you will utilize the semantic HTML elements to create the structure of a web page. You'll add content and images to make it look like a real event hub.
Fulfill the user stories below and get all the tests to pass to complete the lab.
**User Stories:**
1. You should have a `header` element.
1. Inside the `header` element, you should have an `h1` element that contains the text `Event Hub`, and a `nav` element.
1. Inside the `nav` element, you should have an unordered list of two items containing links to different sections of the page. The first item should have the text `Upcoming Events`, and the second item should have the text `Past Events`.
1. Each link should be represented by an `a` element with an `href` attribute that links to the corresponding section of the page, `#upcoming-events` and `#past-events` respectively.
1. You should have a `main` element that contains the different sections of the page.
1. Inside the `main` element, you should have two `section` elements.
1. The first `section` element should have an `id` attribute with the value `upcoming-events`
1. Inside the `#upcoming-events` section, you should have:
- An `h2` element with the text `Upcoming Events`.
- Two `article` elements. Each article should represent an event, and it should have :
- An `h3` element for the event title.
- A `p` element for the event description. You can add a date at the bottom if you like.
1. The second `section` element should have an `id` attribute with the value `past-events`.
1. Inside the `#past-events` section, you should have:
- An `h2` element with the text `Past Events`.
- Two `article` elements. Each article element should represent a past event, and it should have:
- An `h3` element for the event title,
- A `p` element for the event description. You can add a date at the bottom if you like.
- An image element with the `src` attribute pointing to an image file and the `alt` attribute with a description of the image.
**Note:** You can use any text for the event descriptions and dates. You can use the following image URLs for the images if you like:
- `https://cdn.freecodecamp.org/curriculum/labs/past-event1.jpg`.
- `https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg`.
# --hints--
You should have a `header` element.
```js
assert.isNotNull(document.querySelector("header"));
```
Your `header` element should come after the opening `body` tag.
```js
assert.equal(document.querySelector("body")?.firstElementChild?.tagName, "HEADER");
```
Inside the `header` element, you should have an `h1` element that contains the text `Event Hub`.
```js
const h1Element = document.querySelector('header h1');
assert.strictEqual(h1Element?.innerText, "Event Hub");
```
Inside the `header` element, after the `h1` element, you should have a `nav` element.
```js
assert.isNotNull(document.querySelector("header>h1+nav"));
```
Your `nav` element should contain an unordered list of two items.
```js
const liElements = document.querySelectorAll('header nav>ul>li');
assert.isNotNull('header nav>ul');
assert.strictEqual(liElements.length, 2);
```
The first item in the unordered list should be a link.
```js
const firstLink = document.querySelectorAll('header nav ul li a')[0];
assert.exists(firstLink);
```
The second item in the unordered list should be a link.
```js
const secondLink = document.querySelectorAll('header nav ul li a')[1];
assert.exists(secondLink);
```
The text of the first item in the unordered list should be `Upcoming Events`.
```js
const firstLink = document.querySelectorAll('header nav>ul>li>a')[0];
assert.strictEqual(firstLink.innerText, "Upcoming Events");
```
The first item in the unordered list should have the `href` set to `#upcoming-events`.
```js
const anchorElement = document.querySelectorAll("header nav>ul>li>a")[0];
const hrefAttribute = anchorElement?.getAttribute("href");
assert.strictEqual(hrefAttribute, "#upcoming-events");
```
The text of the second item in the unordered list should be `Past Events`.
```js
const secondLink = document.querySelectorAll('header nav>ul>li>a')[1];
assert.strictEqual(secondLink.innerText, "Past Events");
```
The second item in the unordered list should have the `href` set to `#past-events`.
```js
const anchorElement = document.querySelectorAll("header nav>ul>li>a")[1];
const hrefAttribute = anchorElement?.getAttribute("href");
assert.strictEqual(hrefAttribute, "#past-events");
```
You should have a `main` element after the `header` element closing tag.
```js
const mainElement = document.querySelector("body>header+main");
assert.isNotNull(mainElement);
```
Inside the `main` element, you should have two `section` elements.
```js
const sectionElements = document.querySelectorAll('body>header+main>section');
assert.strictEqual(sectionElements.length, 2);
```
Your first `section` element should have an `id` attribute with the value `upcoming-events`.
```js
const firstSection = document.querySelectorAll('body>header+main>section')[0];
const idAttribute = firstSection?.getAttribute("id");
assert.strictEqual(idAttribute, "upcoming-events");
```
Your second `section` element should have an `id` attribute with the value `past-events`.
```js
const secondSection = document.querySelectorAll('body>header+main>section')[1];
const idAttribute = secondSection?.getAttribute("id");
assert.strictEqual(idAttribute, "past-events");
```
Inside the `#upcoming-events` section, you should have an `h2` element with the text `Upcoming Events`.
```js
const h2Element = document.querySelector('#upcoming-events h2');
assert.strictEqual(h2Element?.innerText, "Upcoming Events");
```
Inside the `#upcoming-events` section, you should have two `article` elements below the `h2` element.
```js
const articleElements = document.querySelectorAll('#upcoming-events h2 ~ article');
assert.strictEqual(articleElements.length, 2);
```
Both of the `article` elements inside the `#upcoming-events` section should have an `h3` element for the event title.
```js
const h3Elements = document.querySelectorAll('#upcoming-events article h3');
assert.strictEqual(h3Elements.length, 2);
```
Both of the `article` elements inside the `#upcoming-events` section should have a paragraph element for the event description.
```js
const articles = document.querySelectorAll('#upcoming-events article');
assert.isNotEmpty(articles);
articles.forEach(article => {
assert.isAtLeast(article.querySelectorAll('h3 ~ p').length, 1);
});
```
Inside the `#past-events` section, you should have an `h2` element with the text `Past Events`.
```js
const h2Element = document.querySelector('#past-events h2');
assert.strictEqual(h2Element?.innerText, "Past Events");
```
Inside the `#past-events` section, you should have two `article` elements below the `h2` element.
```js
const articleElements = document.querySelectorAll('#past-events h2 ~ article');
assert.strictEqual(articleElements.length, 2);
```
Both of the `article` elements inside the `#past-events` section should have an `h3` element for the event title.
```js
const h3Elements = document.querySelectorAll('#past-events article h3');
assert.strictEqual(h3Elements.length, 2);
```
Both of the `article` elements inside the `#past-events` section should have a paragraph element for the event description.
```js
const articles = document.querySelectorAll('#past-events article');
assert.isNotEmpty(articles);
articles.forEach(article => {
assert.isAtLeast(article.querySelectorAll('h3 ~ p').length, 1);
});
```
Both of the `article` elements inside the `#past-events` section should have an image element.
```js
const imgElements = document.querySelectorAll('#past-events article img');
assert.strictEqual(imgElements.length, 2);
```
Both of the image elements inside the `#past-events` section should have the `src` attribute pointing to an image file.
```js
const imgElements = document.querySelectorAll('#past-events article img');
assert.strictEqual(imgElements.length, 2);
for (let img of imgElements) {
assert.exists(img.getAttribute("src"));
}
```
Both of the image elements inside the `#past-events` section should have the `alt` attribute with a description of the image.
```js
const imgElements = document.querySelectorAll('#past-events article img');
assert.strictEqual(imgElements.length, 2);
for (let img of imgElements) {
assert.exists(img.getAttribute("alt"));
}
```
Each `h3` element should have the event title.
```js
const eventTitles = document.querySelectorAll('h3');
assert.isNotEmpty(eventTitles);
eventTitles.forEach((eventTitle => assert.isNotEmpty(eventTitle.innerText)));
```
Each `p` element should have the event description.
```js
const eventDescriptions = document.querySelectorAll('p');
assert.isNotEmpty(eventDescriptions);
eventDescriptions.forEach((eventDescription => assert.isNotEmpty(eventDescription.innerText)));
```
# --seed--
## --seed-contents--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Event Hub</title>
</head>
<body>
</body>
</html>
```
# --solutions--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Hub</title>
</head>
<body>
<header>
<h1>Event Hub</h1>
<nav>
<ul>
<li><a href="#upcoming-events">Upcoming Events</a></li>
<li><a href="#past-events">Past Events</a></li>
</ul>
</nav>
</header>
<main>
<section id="upcoming-events">
<h2>Upcoming Events</h2>
<article>
<h3>AI & Machine Learning Conference 2024</h3>
<p>Join us for a deep dive into the latest advancements in artificial intelligence and machine learning. Industry leaders will share insights and case studies on how AI is transforming various sectors.</p>
<p>Date: August 10, 2024</p>
</article>
<article>
<h3>Web Development Bootcamp</h3>
<p>A hands-on workshop designed for developers looking to enhance their skills in modern web technologies including React, Node.js, and GraphQL. Perfect for both beginners and experienced developers.</p>
<p>Date: September 5, 2024</p>
</article>
</section>
<section id="past-events">
<h2>Past Events</h2>
<article>
<h3>Cybersecurity Summit 2024</h3>
<p>An event focusing on the latest trends and threats in cybersecurity. Experts discussed strategies for protecting data and ensuring privacy in an increasingly digital world.</p>
<p>Date: June 15, 2024</p>
<img src="https://cdn.freecodecamp.org/curriculum/labs/past-event1.jpg" alt="Image from Cybersecurity Summit 2024">
</article>
<article>
<h3>Blockchain Expo 2024</h3>
<p>A comprehensive event covering the future of blockchain technology. Topics included decentralized finance (DeFi), smart contracts, and the impact of blockchain on various industries.</p>
<p>Date: July 20, 2024</p>
<img src="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg" alt="Image from Blockchain Expo 2024">
</article>
</section>
</main>
</body>
</html>
```
@@ -0,0 +1,37 @@
---
id: a9f9c5bf295034800d6c77ad
title: Building a Better Calculator
challengeType: 11
videoId: lOltMrA6kuY
dashedName: building-a-better-calculator-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to build an improved calculator program using if statements.
# --questions--
## --text--
Which of the following built-in functions is used to convert a string to a float?
## --answers--
`floats()`
---
`floating_point()`
---
`float()`
---
`fl()`
## --video-solution--
3
@@ -0,0 +1,57 @@
---
id: 58d5d031e969765037c1bebb
title: Functions
challengeType: 11
videoId: QN3UNoJVS9g
dashedName: functions-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to define and call a function.
# --questions--
## --text--
Which of the following is the correct way to call a function?
## --answers--
```python
def sayhi():
print("Hello World")
sayhi()()
```
---
```python
def sayhi():
print("Hello World")
()sayhi()
```
---
```python
def sayhi():
print("Hello World")
sayhi
```
---
```python
def sayhi():
print("Hello World")
sayhi()
```
## --video-solution--
4
@@ -0,0 +1,37 @@
---
id: 8314d0bbddb0aa027a144705
title: If Statements and Comparisons
challengeType: 11
videoId: frb0CCrS9X8
dashedName: if-statements-and-comparisons-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn about comparison operators.
# --questions--
## --text--
Which of the following operators is used to check if one number is greater than or equal to another number?
## --answers--
`<`
---
`<=`
---
`>`
---
`>=`
## --video-solution--
4
@@ -0,0 +1,47 @@
---
id: 08854a2c6f052efa1e5270d2
title: If Statements
challengeType: 11
videoId: lruoyNlItfg
dashedName: if-statements-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to use if statements to control the flow of your Python programs based on conditions.
# --questions--
## --text--
What will be the output for the following code?
```python
is_male = True
is_tall = True
if is_male or is_tall:
print("You are a male")
else:
print("You are not a male")
```
## --answers--
`"You are not a male"`
---
`"You are a male"`
---
`"You are not a male" and "You are a male"`
---
`None`
## --video-solution--
2
@@ -0,0 +1,44 @@
---
id: c6c9dae4017830e187eeaf42
title: Return Statement
challengeType: 11
videoId: Gx3VTsaMCHU
dashedName: return-statement-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to use the return statement in functions.
# --questions--
## --text--
What will be the output for the following code?
```python
def cube(num):
num*num*num
print(cube(3))
```
## --answers--
`None`
---
`Undefined`
---
`3`
---
`27`
## --video-solution--
1
@@ -0,0 +1,54 @@
---
id: 62baa9d28e8723f635a0093e
title: Drawing a Shape
challengeType: 11
videoId: vcNZZSeyZkY
dashedName: drawing-a-shape-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to print a basic shape to the console using `print` statements.
# --questions--
## --text--
Which of the following is the correct way to print a triangle to the console?
## --answers--
```python
print(" /| / | / | /___|")
```
---
```python
print( /|)
print( / |)
print( / |)
print(/___|)
```
---
```python
print(" /|")
print(" / |")
print(" / |")
print("/___|")
```
---
```python
print(" /|")
print(" / |")
print(" / |")
print("/___|")
```
## --video-solution--
4
@@ -0,0 +1,37 @@
---
id: 8ad37ddb7a23050f71cc9cc9
title: Working with Numbers
challengeType: 11
videoId: C7sxe5GAArQ
dashedName: working-with-numbers-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to work with basic arithmetic operations and built-in number functions.
# --questions--
## --text--
Which of the following built-in functions is used to return the base number raised to a power?
## --answers--
`base()`
---
`power()`
---
`pow()`
---
`exp()`
## --video-solution--
3
@@ -0,0 +1,49 @@
---
id: 0e2f4bd857b1edc70bfcd1f9
title: Working with Strings
challengeType: 11
videoId: OrejgL7kP3M
dashedName: working-with-strings-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn about string concatenation, indexing, and useful string methods.
# --questions--
## --text--
Which of the following is the correct way to access the first character of a string?
## --answers--
```python
phrase = "Giraffe Academy"
print(phrase[1])
```
---
```python
phrase = "Giraffe Academy"
print(phrase[0])
```
---
```python
phrase = "Giraffe Academy"
print(phrase[-1])
```
---
```python
phrase = "Giraffe Academy"
print(phrase[2])
```
## --video-solution--
2
@@ -0,0 +1,37 @@
---
id: 155ca30775751b78a860a79b
title: Getting Input from Users
challengeType: 11
videoId: C0L4cnqKqDw
dashedName: getting-input-from-users-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to get input from the user.
# --questions--
## --text--
Which of the following built-in functions is used to get input from the user?
## --answers--
`input()`
---
`os.stdin()`
---
`stdin()`
---
`prompt()`
## --video-solution--
1
@@ -0,0 +1,37 @@
---
id: 315017f4457c19d45c2be034
title: Variables and Data Types
challengeType: 11
videoId: sIw317W39X0
dashedName: variables-and-data-types-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn about the different data types in Python including integers, strings and booleans.
# --questions--
## --text--
What is a boolean?
## --answers--
It is a data type that represents an `undefined` value.
---
It is a data type that represents a sequence of characters.
---
It is a data type that represents `True` or `False`.
---
It is a data type that represents a float.
## --video-solution--
3
@@ -0,0 +1,43 @@
---
id: 24a45b3960b3aa68dff2cd9e
title: List Functions
challengeType: 11
videoId: _5FQ5f3RW5U
dashedName: list-functions-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to work with useful methods including the `append()`, `index()`, `clear()`, `sort()`, and `reverse()` methods.
# --questions--
## --text--
What will be the output for the following code?
```python
friends = ["Kevin", "Karen", "Jim", "Oscar", "Toby"]
print(friends.index("Oscar"))
```
## --answers--
4
---
1
---
2
---
3
## --video-solution--
4
@@ -0,0 +1,42 @@
---
id: 39a400e9163c5a0b33587e18
title: Lists
challengeType: 11
videoId: DtMPzGOHZ2M
dashedName: lists-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn about lists, list indexing, slicing, and basic list operations.
# --questions--
## --text--
What will be the output for the following code?
```python
friends = ["Kevin", "Karen", "Jim"]
print(friends[-1])
```
## --answers--
`"Kevin"`
---
`"Jim"`
---
`"Karen"`
---
`Error`
## --video-solution--
2
@@ -0,0 +1,45 @@
---
id: 5ed596ba3306cf2c1a94bb92
title: Tuples
challengeType: 11
videoId: g6fwjiEFG-Y
dashedName: tuples-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn about tuples in Python and how they differ from lists.
# --questions--
## --text--
Which of the following is the correct way to create a tuple?
## --answers--
```python
coordinates = [4, 5]
```
---
```python
coordinates = (4, 5)
```
---
```python
coordinates = <4, 5>
```
---
```python
coordinates = /4, 5/
```
## --video-solution--
2
@@ -0,0 +1,37 @@
---
id: a0339c4075344cbfc2cd939c
title: Classes and Objects
challengeType: 11
videoId: fR3dh5_MPJs
dashedName: classes-and-objects-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to create classes and objects in Python to write object-oriented programs.
# --questions--
## --text--
What is the role of `def __init__(self):` inside of a class?
## --answers--
It represents a function for calling the method.
---
It specifies the type of the class.
---
It allows a class to inherit methods from another class.
---
It represents an initializer method.
## --video-solution--
4
@@ -0,0 +1,37 @@
---
id: 697fe5c032baa3841ab62a64
title: Inheritance
challengeType: 11
videoId: uHdNSULVpgY
dashedName: inheritance-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn about inheritance in object oriented programming.
# --questions--
## --text--
What is inheritance in object oriented programming?
## --answers--
This is when a class reuses code from a function.
---
This is when a class creates a copy of another class.
---
This is when a class inherits properties and behaviors from another class.
---
This is when a class hides its methods and variables from other classes.
## --video-solution--
3
@@ -0,0 +1,37 @@
---
id: 697fe6c932baa3841ab62a65
title: Python Interpreter
challengeType: 11
videoId: -c1vFEsIod4
dashedName: python-interpreter-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to work with the Python interpreter.
# --questions--
## --text--
What is the Python interpreter?
## --answers--
This is a program that writes Python code for you.
---
This is a tool that compiles Python into Java or C++.
---
This is a library that stores Python functions.
---
This is a program that reads and executes Python code.
## --video-solution--
4
@@ -0,0 +1,69 @@
---
id: 697fe3cb32baa3841ab62a63
title: Object Functions
challengeType: 11
videoId: 3Mla2uUDSu8
dashedName: object-functions-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to work with functions inside of classes.
# --questions--
## --text--
Which of the following is the correct way to create a function inside of a class?
## --answers--
```python
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self.function):
return f"Hello, my name is {self.name} and I am {self.age} years old."
```
---
```python
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hello, my name is {self.name} and I am {self.age} years old."
```
---
```python
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
self.pass
```
---
```python
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
greet = (self):
return f"Hello, my name is {self.name} and I am {self.age} years old."
```
## --video-solution--
2
@@ -0,0 +1,37 @@
---
id: 9afe5e8141b13e9f1d59d46e
title: Building a Multiple Choice Quiz
challengeType: 11
videoId: GJMmSaB8RN0
dashedName: building-a-multiple-choice-quiz-learn-python-full-course-for-beginners
---
# --description--
In this video, you will practice what you have learned about classes and objects by building a multiple choice quiz.
# --questions--
## --text--
Which of the following is the correct way to import the `Question` class from the `Question` module?
## --answers--
`Question import`
---
`from Question`
---
`from Question import Question`
---
`import Question.py`
## --video-solution--
3
@@ -0,0 +1,37 @@
---
id: 71ac60e6488b40e997219f15
title: Comments
challengeType: 11
videoId: CY-CMJIt1z8
dashedName: comments-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to write comments in Python to document your code and make it more readable.
# --questions--
## --text--
Which of the following is a single line comment in Python?
## --answers--
`# This program is cool`
---
`> This program is cool`
---
`''' This program is cool`
---
`// This program is cool`
## --video-solution--
1
@@ -0,0 +1,37 @@
---
id: 2ccc34bd3f7bb4ae97a67ea3
title: Modules and pip
challengeType: 11
videoId: HJ-dHUXmpcg
dashedName: modules-and-pip-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to use modules and pip to extend Python's functionality with external packages.
# --questions--
## --text--
What is pip used for?
## --answers--
It is used to sort python modules.
---
It is used to explain python modules.
---
It is used to install python modules.
---
It is used to lint Python programs.
## --video-solution--
3
@@ -0,0 +1,37 @@
---
id: 04e25c4fdc9ee0e71a844fd6
title: Reading Files
challengeType: 11
videoId: enOW7u6LWyg
dashedName: reading-files-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to read files in Python and process their contents.
# --questions--
## --text--
What is the role of the `"r"` in the `open()` function?
## --answers--
It specifies the range mode.
---
It specifies the rename mode.
---
It specifies the random access mode.
---
It specifies the read mode.
## --video-solution--
4
@@ -0,0 +1,45 @@
---
id: 2a486e3e521b79b874fb5e9a
title: Try/Except
challengeType: 11
videoId: 1tkhMom_SZw
dashedName: try-except-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to handle exceptions using try/except blocks to make your programs more robust.
# --questions--
## --text--
What will be the result for the following code if the user provides the string `"random"`?
```python
try:
number = int(input("Enter a number: "))
print(number)
except:
print("Invalid Input")
```
## --answers--
Nothing will be output to the console.
---
The string `"random"` will be output to the console.
---
The string `"Invalid Input"` will be output to the console.
---
The program will crash.
## --video-solution--
3
@@ -0,0 +1,37 @@
---
id: bfab38e6a6c1165f7774514d
title: Writing to Files
challengeType: 11
videoId: QR95sRxsehY
dashedName: writing-to-files-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to write data to files in Python.
# --questions--
## --text--
What is the role of the `"a"` in the `open()` function?
## --answers--
It specifies the append mode.
---
It specifies the alternate mode.
---
It specifies the access mode.
---
It specifies the apply mode.
## --video-solution--
1
@@ -0,0 +1,47 @@
---
id: 28119f9dc5f93e3ac5d7c58a
title: 2D Lists and Nested Loops
challengeType: 11
videoId: 2lKgjX3gzmM
dashedName: 2d-lists-and-nested-loops-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to create 2D lists and use nested loops to work with multi-dimensional data structures.
# --questions--
## --text--
What will be the output for the following code?
```python
number_grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(number_grid[2][1])
```
## --answers--
8
---
7
---
9
---
1
## --video-solution--
1
@@ -0,0 +1,105 @@
---
id: 3625fbc38b9428ae98d98f23
title: Dictionaries
challengeType: 11
videoId: FBfYADu3CIo
dashedName: dictionaries-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to work with dictionaries in Python to store key-value pairs.
# --questions--
## --text--
Which of the following will correctly output the string `"March"` to the console?
## --answers--
```python
month_conversions = {
"Jan": "January",
"Feb": "February",
"Mar": "March",
"Apr": "April",
"May": "May",
"Jun": "June",
"Jul": "July",
"Aug": "August",
"Sep": "September",
"Oct": "October",
"Nov": "November",
"Dec": "December"
}
print(month_conversions<"Mar">)
```
---
```python
month_conversions = {
"Jan": "January",
"Feb": "February",
"Mar": "March",
"Apr": "April",
"May": "May",
"Jun": "June",
"Jul": "July",
"Aug": "August",
"Sep": "September",
"Oct": "October",
"Nov": "November",
"Dec": "December"
}
print(month_conversions("Mar"))
```
---
```python
month_conversions = {
"Jan": "January",
"Feb": "February",
"Mar": "March",
"Apr": "April",
"May": "May",
"Jun": "June",
"Jul": "July",
"Aug": "August",
"Sep": "September",
"Oct": "October",
"Nov": "November",
"Dec": "December"
}
print(month_conversions["March"])
```
---
```python
month_conversions = {
"Jan": "January",
"Feb": "February",
"Mar": "March",
"Apr": "April",
"May": "May",
"Jun": "June",
"Jul": "July",
"Aug": "August",
"Sep": "September",
"Oct": "October",
"Nov": "November",
"Dec": "December"
}
print(month_conversions["Mar"])
```
## --video-solution--
4
@@ -0,0 +1,37 @@
---
id: a4cfb218d22efcfa7cc49d80
title: Exponent Functions
challengeType: 11
videoId: KLDvy0wFFX4
dashedName: exponent-functions-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to write a function that calculates exponents and powers in Python.
# --questions--
## --text--
What does the `range()` function in Python do?
## --answers--
It returns a number from a list.
---
It creates a list of random numbers.
---
It generates a sequence of integers between a starting and stopping point.
---
It generates a sequence of floats between a starting and stopping point.
## --video-solution--
3
@@ -0,0 +1,49 @@
---
id: 030401977064585ddd4c7746
title: For Loops
challengeType: 11
videoId: x13V1UMMQeI
dashedName: for-loops-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to use for loops to iterate over sequences like lists and ranges.
# --questions--
## --text--
Which of the following is the correct way to iterate over each letter in the string `"Giraffe Academy"`?
## --answers--
```python
for (letter) in "Giraffe Academy":
print(letter)
```
---
```python
for key, letter in "Giraffe Academy":
print(letter)
```
---
```python
for letter in "Giraffe Academy":
print(letter)
```
---
```python
for letter, value in "Giraffe Academy":
print(letter)
```
## --video-solution--
3
@@ -0,0 +1,45 @@
---
id: d4876f74547b26d5c330423e
title: Building a Guessing Game
challengeType: 11
videoId: sHyQCBFRoug
dashedName: building-a-guessing-game-learn-python-full-course-for-beginners
---
# --description--
In this video, you will build a guessing game that uses loops and conditionals.
# --questions--
## --text--
What does the condition `guess != secret_word` mean in this code?
```python
secret_word = "giraffe"
guess = ""
while guess != secret_word:
guess = input("Enter guess: ")
```
## --answers--
If `guess` is not equal to `secret_word`.
---
If `guess` is equal to `secret_word`.
---
If `guess` is greater than `secret_word`.
---
If `guess` is less than `secret_word`.
## --video-solution--
1
@@ -0,0 +1,37 @@
---
id: 703bcd12c0edae7773eeec64
title: Building a Translator
challengeType: 11
videoId: 3Sa5rwlKdGQ
dashedName: building-a-translator-learn-python-full-course-for-beginners
---
# --description--
In this video, you will build a simple translator program using dictionaries and user input.
# --questions--
## --text--
Which of the following methods is used to check if all characters in a string are uppercase?
## --answers--
`upper()`
---
`isupper()`
---
`toupper()`
---
`hasupper()`
## --video-solution--
2
@@ -0,0 +1,83 @@
---
id: 474c23ec0df6e7af920e0526
title: While Loop
challengeType: 11
videoId: s6yz4Ew8dwQ
dashedName: while-loop-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to work with while loops to repeat code blocks as long as a condition is `True`.
# --questions--
## --text--
What will be the output for the following code?
```python
i = 1
while i <= 10:
print(i)
i += 1
print("Done with loop")
```
## --answers--
```md
1
3
5
7
9
Done with loop
```
---
```md
1
2
3
4
5
6
7
8
9
10
Done with loop
```
---
```md
2
4
6
8
10
Done with loop
```
---
```md
1
2
3
4
5
6
7
8
9
Done with loop
```
## --video-solution--
2
@@ -0,0 +1,37 @@
---
id: 8ca3a380a75d00443d9e09bd
title: Hello World Program
challengeType: 11
videoId: H2WnzGCeydQ
dashedName: hello-world-program-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to write your first program in Python.
# --questions--
## --text--
Which of the following is the correct way to print `"Hello World"` to the console?
## --answers--
`print("Hello World")`
---
`printf("Hello World")`
---
`prints("Hello World")`
---
`printing("Hello World")`
## --video-solution--
1
@@ -0,0 +1,37 @@
---
id: edeae16d4bf9505165740c75
title: Installing Python and PyCharm
challengeType: 11
videoId: RgGQJDOms1M
dashedName: installing-python-and-pycharm-learn-python-full-course-for-beginners
---
# --description--
In this video, you will learn how to install Python and PyCharm onto your computer.
# --questions--
## --text--
What is PyCharm used for?
## --answers--
It is a programming language similar to Python used for developing mobile apps.
---
It is a Python library used for data analysis.
---
It is an IDE used to run Python programs.
---
It is an operating system designed for developers.
## --video-solution--
3
@@ -0,0 +1,37 @@
---
id: 05b8c9b04c6df84636956fab
title: Introduction
challengeType: 11
videoId: EgQZWE8in68
dashedName: introduction-learn-python-full-course-for-beginners
---
# --description--
In this video, instructor Mike Dane explains why you should learn Python.
# --questions--
## --text--
What is one reason to learn Python?
## --answers--
It is required to be learned before any other programming language.
---
It is one of the most popular programming languages used in the industry.
---
It is the fastest programming language for all types of applications.
---
It is only useful for complex gaming applications.
## --video-solution--
2
@@ -0,0 +1,37 @@
---
id: 6ec8578710ffa3471b74888e
title: Building a Basic Calculator
challengeType: 11
videoId: vA10XU1O3QQ
dashedName: building-a-basic-calculator-learn-python-full-course-for-beginners
---
# --description--
In this video, you will build a basic calculator program that can perform addition, subtraction, multiplication, and division operations.
# --questions--
## --text--
Which function is used to convert a string to an integer?
## --answers--
`convert()`
---
`str()`
---
`integer()`
---
`int()`
## --video-solution--
4
@@ -0,0 +1,49 @@
---
id: 024ffa91a50a44335be33ee7
title: Mad Libs Game
challengeType: 11
videoId: XRmMTKa-xlc
dashedName: mad-libs-game-learn-python-full-course-for-beginners
---
# --description--
In this video, you will create a Mad Libs game that takes user input and creates funny stories.
# --questions--
## --text--
Which of the following is the correct way to get input from a user and print the result to the console?
## --answers--
```python
color = input("Enter a color: ")
print(Roses are + color)
```
---
```python
color = input("Enter a color: ")
print("Roses are " + "color")
```
---
```python
color = input("Enter a color: ")
print("Roses are " + color)
```
---
```python
color = prompt("Enter a color: ")
print("Roses are " + color)
```
## --video-solution--
3
@@ -1,224 +0,0 @@
---
id: 668f08ea07b99b1f4a91acab
title: Build a Recipe Page
challengeType: 25
dashedName: build-a-recipe-page
demoType: onClick
---
# --description--
Fulfill the user stories below and get all the tests to pass to complete the lab.
**User Stories:**
1. You should have a `!DOCTYPE html` declaration.
1. You should have an `html` element with `lang` set to `en`.
1. You should have a `head` element containing a `title` element with the name of your recipe, and a `meta` element with a `charset` attribute set to `UTF-8`.
1. You should have a `body` element.
1. You should have an `h1` element with the name of your recipe.
1. You should have a `p` element that introduces the recipe below the `h1`.
1. You should have one `h2` element with the text `Ingredients` for the ingredients section.
1. You should have an unordered list (`ul` element) with at least four list items (`li` elements) that lists your ingredients below the first `h2` element.
1. You should have a second `h2` element with the text `Instructions` for the instructions section.
1. You should have an ordered list (`ol` element) with at least four list items that lists the recipe steps in order, below the second `h2`.
1. You should have one `img` element with a `src` attribute set to a valid image, you can use `https://cdn.freecodecamp.org/curriculum/labs/recipe.jpg` if you would like, and an `alt` attribute describing the image.
# --hints--
Your recipe page should have a `!DOCTYPE html` declaration.
```js
assert.match(code, /<!DOCTYPE html>/i);
```
You should have an `html` element with `lang` set to `en`.
```js
assert.match(code, /<html\s+lang\s*=\s*('|")en\1\s*>[\s\S]*<\/\s*html\s*>/gi);
```
You should have a `head` element within the `html` element.
```js
assert.match(code, /<html[\s\S]*>[\s\S]*<\s*head\s*>[\s\S]*<\/\s*head\s*>[\s\S]*<\/\s*html\s*>/i);
```
You should have `title` element within your `head` element.
```js
assert.match(code, /<\s*head\s*>[\s\S]*<\s*title\s*>[\s\S]*<\/\s*title\s*>[\s\S]*<\/\s*head\s*>/i);
```
Your `title` element should have your recipe title.
```js
assert.isAbove(document.querySelector('title')?.innerText.trim().length, 0);
```
You should have a `meta` element within your `head` element.
```js
assert.match(code, /<\s*head\s*>[\s\S]*<\s*meta[\s\S]*>[\s\S]*<\/\s*head\s*>/i);
```
Your `meta` element should have its `charset` attribute set to `UTF-8`.
```js
assert.match(code, /<\s*meta[\s\S]+?charset\s*=\s*('|")UTF-8\1/i);
```
You should have a `body` element within your `html` element.
```js
assert.match(code, /<\s*html[\s\S]*>[\s\S]*<\s*head\s*>[\s\S]*<\/\s*head\s*>[\s\S]*<\s*body\s*>[\s\S]*<\/\s*body\s*>[\s\S]*<\/\s*html\s*>/i);
```
You should have an `h1` element with the name of your recipe.
```js
assert.isAbove(document.querySelector('h1')?.innerText.length, 0);
```
You should only have one `h1` element.
```js
assert.lengthOf(document.querySelectorAll('h1'), 1);
```
You should have a `p` element below your `h1` element.
```js
assert.strictEqual(document.querySelector('h1')?.nextElementSibling, document.querySelector('p'));
```
Your first `p` element should describe your recipe.
```js
assert.isNotEmpty(document.querySelector('p')?.textContent?.trim());
```
Your first `h2` element should have the text `Ingredients`.
```js
assert.equal(document.querySelectorAll('h2')[0]?.innerText, 'Ingredients');
```
You should have an unordered list element below your first `h2` element.
```js
assert.strictEqual(document.querySelector('ul')?.previousElementSibling.tagName, 'H2');
```
You should have at least four list item elements in your unordered list with the ingredients.
```js
const els = document.querySelectorAll('ul > li');
assert.isAbove(els.length, 3);
els.forEach(el => assert.isAbove(el.innerText.trim().length, 0))
```
Your second `h2` element should have the text `Instructions`.
```js
assert.equal(document.querySelectorAll('h2')[1]?.innerText, 'Instructions');
```
You should have an ordered list element below your second `h2` element.
```js
assert.strictEqual(document.querySelectorAll('h2')?.[1]?.nextElementSibling?.tagName, "OL");
```
You should have at least four list item elements in your ordered list with the instructions.
```js
const els = document.querySelectorAll('ol > li');
assert.isAbove(els.length, 3);
els.forEach(el => assert.isAbove(el.innerText.trim().length, 0))
```
You should have at least one `img` element.
```js
assert.exists(document.querySelector('img'));
```
All your `img` elements should have a valid `src` attribute and value.
```js
const img = document.querySelector('img');
const rawSrc = img?.getAttribute('src');
const resolvedSrc = img?.src;
const re = new RegExp(window.location.href, "ig");
assert.isAbove(rawSrc?.trim().length, 0, "The 'src' attribute must be explicitly set.");
assert.notMatch(resolvedSrc, re, "The 'src' should not start with the current page URL");
img.onload = () => {
console.log('Image loaded successfully.');
};
img.onerror = (error) => {
console.error('Image failed to load:', error);
assert.fail("Your image's URL should be valid."); // Make the test instafail
};
if (img.complete) {
img.onload && img.onload();
};
```
All your `img` elements should have an `alt` attribute to describe the image.
```js
assert.isAbove(document.querySelector('img')?.alt.length, 0);
```
# --seed--
## --seed-contents--
```html
```
# --solutions--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Chocolate chip cookies recipe</title>
</head>
<body>
<h1>Chocolate Chip Cookies</h1>
<p>Welcome to the ultimate guide for making mini chocolate chip cookies! These bite-sized treats are perfect for
satisfying your sweet tooth without overindulging. Follow this simple recipe to create delicious,
crispy-on-the-outside, chewy-on-the-inside mini chocolate chip cookies that everyone will love.</p>
<img src="https://cdn.freecodecamp.org/curriculum/labs/recipe.jpg" alt="Ingredients for baking: three eggs, a bowl of flour, a glass of milk, and a whisk arranged on a wooden table.">
<h2>Ingredients</h2>
<ul>
<li>1 cup all-purpose flour</li>
<li>1/2 teaspoon baking soda</li>
<li>1/4 cup unsalted butter, softened</li>
<li>1/4 cup granulated sugar</li>
<li>1/2 teaspoon vanilla extract</li>
<li>1/2 cup mini chocolate chips</li>
</ul>
<h2>Instructions</h2>
<ol>
<li>Preheat your oven to 350°F (175°C) and line a baking sheet with parchment paper.</li>
<li>In a bowl, whisk together the flour and baking soda.</li>
<li>In another bowl, beat the butter, sugar, and vanilla extract until creamy.</li>
<li>Gradually add the dry ingredients to the wet mixture, then fold in the mini chocolate chips.</li>
<li>Drop small spoonfuls of dough onto the baking sheet.</li>
<li>Bake for 8-10 minutes, then let cool before enjoying!</li>
</ol>
</body>
</html>
```
+1 -2
View File
@@ -6,7 +6,6 @@ const {
} = require('@freecodecamp/shared/config/challenge-types');
const {
chapterBasedSuperBlocks,
catalogSuperBlocks,
languageSuperBlocks,
SuperBlocks
} = require('@freecodecamp/shared/config/curriculum');
@@ -135,7 +134,7 @@ const schema = Joi.object().keys({
block: Joi.string().regex(slugRE).required(),
blockId: Joi.objectId(),
blockLabel: Joi.when('superBlock', {
is: [...chapterBasedSuperBlocks, ...catalogSuperBlocks],
is: [...chapterBasedSuperBlocks],
then: Joi.valid(
'workshop',
'lab',
+24 -1
View File
@@ -33,7 +33,30 @@ const superblocks = [
'college-algebra-with-python',
'project-euler',
'2022/responsive-web-design',
'the-odin-project'
'the-odin-project',
'lab-survey-form',
'html-and-accessibility',
'computer-basics',
'basic-css',
'design-for-developers',
'absolute-and-relative-units',
'pseudo-classes-and-elements',
'css-colors',
'styling-forms',
'css-box-model',
'css-flexbox',
'lab-page-of-playing-cards',
'css-typography',
'css-and-accessibility',
'css-positioning',
'attribute-selectors',
'lab-book-inventory-app',
'responsive-design',
'lab-technical-documentation-page',
'css-variables',
'css-grid',
'lab-product-landing-page',
'css-animations'
];
const schema = Joi.object().keys(
+26 -1
View File
@@ -202,7 +202,32 @@ export const superBlockNames = {
'python-v9': SuperBlocks.PythonV9,
'relational-databases-v9': SuperBlocks.RelationalDbV9,
'back-end-development-and-apis-v9': SuperBlocks.BackEndDevApisV9,
'full-stack-developer-v9': SuperBlocks.FullStackDeveloperV9
'full-stack-developer-v9': SuperBlocks.FullStackDeveloperV9,
'html-forms-and-tables': SuperBlocks.HtmlFormsAndTables,
'learn-python-for-beginners': SuperBlocks.LearnPythonForBeginners,
'lab-survey-form': SuperBlocks.LabSurveyForm,
'html-and-accessibility': SuperBlocks.HtmlAndAccessibility,
'computer-basics': SuperBlocks.ComputerBasics,
'basic-css': SuperBlocks.BasicCss,
'design-for-developers': SuperBlocks.DesignForDevelopers,
'absolute-and-relative-units': SuperBlocks.AbsoluteAndRelativeUnits,
'pseudo-classes-and-elements': SuperBlocks.PseudoClassesAndElements,
'css-colors': SuperBlocks.CssColors,
'styling-forms': SuperBlocks.StylingForms,
'css-box-model': SuperBlocks.CssBoxModel,
'css-flexbox': SuperBlocks.CssFlexbox,
'lab-page-of-playing-cards': SuperBlocks.LabPageOfPlayingCards,
'css-typography': SuperBlocks.CssTypography,
'css-and-accessibility': SuperBlocks.CssAndAccessibility,
'css-positioning': SuperBlocks.CssPositioning,
'attribute-selectors': SuperBlocks.AttributeSelectors,
'lab-book-inventory-app': SuperBlocks.LabBookInventoryApp,
'responsive-design': SuperBlocks.ResponsiveDesign,
'lab-technical-documentation-page': SuperBlocks.LabTechnicalDocumentationPage,
'css-variables': SuperBlocks.CssVariables,
'css-grid': SuperBlocks.CssGrid,
'lab-product-landing-page': SuperBlocks.LabProductLandingPage,
'css-animations': SuperBlocks.CssAnimations
};
export const superBlockToFilename = Object.entries(superBlockNames).reduce(
@@ -1,28 +0,0 @@
{
"name": "Build a Cat Blog Page",
"blockLabel": "workshop",
"blockLayout": "challenge-grid",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"hasEditableBoundaries": true,
"dashedName": "cat-blog-page",
"challengeOrder": [
{
"id": "669aff9f5488f1bea056416d",
"title": "Step 1"
},
{
"id": "669fc7e141e4703748c558bf",
"title": "Step 2"
},
{
"id": "669fc938d38e6e38ace9251e",
"title": "Step 3"
},
{
"id": "669fcb06c3034a39f5431a38",
"title": "Step 4"
}
],
"helpCategory": "HTML-CSS"
}
@@ -1,28 +0,0 @@
{
"name": "Build a Cat Photo App",
"blockLabel": "workshop",
"blockLayout": "challenge-grid",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"hasEditableBoundaries": true,
"dashedName": "cat-photo-app",
"challengeOrder": [
{
"id": "5dc174fcf86c76b9248c6eb2",
"title": "Step 1"
},
{
"id": "5dc1798ff86c76b9248c6eb3",
"title": "Step 2"
},
{
"id": "5dc17d3bf86c76b9248c6eb4",
"title": "Step 3"
},
{
"id": "5dc17dc8f86c76b9248c6eb5",
"title": "Step 4"
}
],
"helpCategory": "HTML-CSS"
}
@@ -1,12 +0,0 @@
{
"name": "Build an Event Hub",
"blockLabel": "lab",
"blockLayout": "link",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"dashedName": "event-hub",
"challengeOrder": [
{ "id": "66ebd4ae2812430bb883c787", "title": "Build an Event Hub" }
],
"helpCategory": "HTML-CSS"
}
@@ -0,0 +1,30 @@
{
"name": "Control Flow and Functions",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-control-flow-functions",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "58d5d031e969765037c1bebb",
"title": "Functions"
},
{
"id": "c6c9dae4017830e187eeaf42",
"title": "Return Statement"
},
{
"id": "08854a2c6f052efa1e5270d2",
"title": "If Statements"
},
{
"id": "8314d0bbddb0aa027a144705",
"title": "If Statements and Comparisons"
},
{
"id": "a9f9c5bf295034800d6c77ad",
"title": "Building a Better Calculator"
}
]
}
@@ -0,0 +1,30 @@
{
"name": "Core Primitives: Variables, Types, Basic I/O",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-core-primitives",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "62baa9d28e8723f635a0093e",
"title": "Drawing a Shape"
},
{
"id": "315017f4457c19d45c2be034",
"title": "Variables and Data Types"
},
{
"id": "0e2f4bd857b1edc70bfcd1f9",
"title": "Working with Strings"
},
{
"id": "8ad37ddb7a23050f71cc9cc9",
"title": "Working with Numbers"
},
{
"id": "155ca30775751b78a860a79b",
"title": "Getting Input from Users"
}
]
}
@@ -0,0 +1,22 @@
{
"name": "Data Structures: Lists and Tuples",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-data-structures",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "39a400e9163c5a0b33587e18",
"title": "Lists"
},
{
"id": "24a45b3960b3aa68dff2cd9e",
"title": "List Functions"
},
{
"id": "5ed596ba3306cf2c1a94bb92",
"title": "Tuples"
}
]
}
@@ -0,0 +1,30 @@
{
"name": "Object Oriented Programming",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-oop",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "a0339c4075344cbfc2cd939c",
"title": "Classes and Objects"
},
{
"id": "9afe5e8141b13e9f1d59d46e",
"title": "Building a Multiple Choice Quiz"
},
{
"id": "697fe3cb32baa3841ab62a63",
"title": "Object Functions"
},
{
"id": "697fe5c032baa3841ab62a64",
"title": "Inheritance"
},
{
"id": "697fe6c932baa3841ab62a65",
"title": "Python Interpreter"
}
]
}
@@ -0,0 +1,30 @@
{
"name": "Practical Python: Errors, Files and Modules",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-practical-errors-files",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "71ac60e6488b40e997219f15",
"title": "Comments"
},
{
"id": "2a486e3e521b79b874fb5e9a",
"title": "Try/Except"
},
{
"id": "04e25c4fdc9ee0e71a844fd6",
"title": "Reading Files"
},
{
"id": "bfab38e6a6c1165f7774514d",
"title": "Writing to Files"
},
{
"id": "2ccc34bd3f7bb4ae97a67ea3",
"title": "Modules and pip"
}
]
}
@@ -0,0 +1,38 @@
{
"name": "Dictionaries and Loops",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-projects-loops",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "3625fbc38b9428ae98d98f23",
"title": "Dictionaries"
},
{
"id": "474c23ec0df6e7af920e0526",
"title": "While Loop"
},
{
"id": "d4876f74547b26d5c330423e",
"title": "Building a Guessing Game"
},
{
"id": "030401977064585ddd4c7746",
"title": "For Loops"
},
{
"id": "a4cfb218d22efcfa7cc49d80",
"title": "Exponent Functions"
},
{
"id": "28119f9dc5f93e3ac5d7c58a",
"title": "2D Lists and Nested Loops"
},
{
"id": "703bcd12c0edae7773eeec64",
"title": "Building a Translator"
}
]
}
@@ -0,0 +1,22 @@
{
"name": "Setup & First Steps",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-setup-first-steps",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "05b8c9b04c6df84636956fab",
"title": "Introduction"
},
{
"id": "edeae16d4bf9505165740c75",
"title": "Installing Python and PyCharm"
},
{
"id": "8ca3a380a75d00443d9e09bd",
"title": "Hello World Program"
}
]
}
@@ -0,0 +1,18 @@
{
"name": "Small Projects: Using Basics",
"blockLabel": "lecture",
"blockLayout": "challenge-list",
"isUpcomingChange": false,
"dashedName": "learn-python-small-projects-basics",
"helpCategory": "Python",
"challengeOrder": [
{
"id": "6ec8578710ffa3471b74888e",
"title": "Building a Basic Calculator"
},
{
"id": "024ffa91a50a44335be33ee7",
"title": "Mad Libs Game"
}
]
}
@@ -1,15 +0,0 @@
{
"name": "Build a Recipe Page",
"blockLabel": "lab",
"blockLayout": "link",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"dashedName": "recipe-page",
"challengeOrder": [
{
"id": "668f08ea07b99b1f4a91acab",
"title": "Build a Recipe Page"
}
],
"helpCategory": "HTML-CSS"
}
+26 -1
View File
@@ -36,7 +36,32 @@
"python-v9",
"relational-databases-v9",
"back-end-development-and-apis-v9",
"full-stack-developer-v9"
"full-stack-developer-v9",
"html-forms-and-tables",
"learn-python-for-beginners",
"lab-survey-form",
"html-and-accessibility",
"computer-basics",
"basic-css",
"design-for-developers",
"absolute-and-relative-units",
"pseudo-classes-and-elements",
"css-colors",
"styling-forms",
"css-box-model",
"css-flexbox",
"lab-page-of-playing-cards",
"css-typography",
"css-and-accessibility",
"css-positioning",
"attribute-selectors",
"lab-book-inventory-app",
"responsive-design",
"lab-technical-documentation-page",
"css-variables",
"css-grid",
"lab-product-landing-page",
"css-animations"
],
"certifications": [
"a2-english-for-developers",

Some files were not shown because too many files have changed in this diff Show More