diff --git a/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.stories.tsx b/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.stories.tsx index 3a85de5..dbfb56f 100644 --- a/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.stories.tsx +++ b/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.stories.tsx @@ -16,22 +16,22 @@ type Story = StoryObj; */ export const Default: Story = { args: { - title: 'The Coldest Sunset Festival', - subText: - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus quia, nulla! Maiores et perferendis eaque, exercitationem praesentium nihil.', - ctaText: '#festival', - ctaUrl: '/', - imageAltText: 'DJ playing at a festival', - imageUrlMobile: - 'https://images.unsplash.com/photo-1493676304819-0d7a8d026dcf?w=767&h=640&fit=crop', - imageUrlTablet: - 'https://images.unsplash.com/photo-1493676304819-0d7a8d026dcf?w=1024&h=640&fit=crop', - imageUrlDesktop: - 'https://images.unsplash.com/photo-1493676304819-0d7a8d026dcf?w=1600&h=900&fit=crop', - containerClassName: 'containerClassName', - titleClassName: 'titleClassName', - subTextClassName: 'subTextClassName', - ctaClassName: 'ctaClassName', - imageClassName: 'imageClassName' + pokemonName: 'Charizard', + pokemonType: 'Fire/Flying', + pokemonHp: 180, + pokemonLevel: 55, + attackName: 'Fire Blast', + attackDamage: 120, + attackDescription: 'A powerful fire attack that may leave the target with a burn.', + imageAltText: 'Charizard breathing fire', + imageUrlSmall: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/6.png', + imageUrlMedium: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/6.png', + imageUrlLarge: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/6.png', + cardClassName: 'shadow-xl', + nameClassName: 'text-red-600', + typeClassName: 'bg-red-500', + hpClassName: 'text-red-700', + attackClassName: 'border-red-400', + imageClassName: 'hover:scale-105 transition-transform' } }; diff --git a/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.tsx b/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.tsx index ffa858a..c51e03a 100644 --- a/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.tsx +++ b/src/course/02-lessons/01-Bronze/PropsCombination/exercise/exercise.tsx @@ -2,104 +2,129 @@ import classnames from 'classnames'; /* - 1a👨🏻‍💻 group the following together: + 1a👨🏻💻 group the following together: - * image - imageAltText, imageUrlMobile, imageUrlTablet, imageUrlDesktop - * cta - ctaText, ctaUrl - * classNames - containerClassName, titleClassName, subTextClassName, ctaClassName, imageClassName + * pokemon - pokemonName, pokemonType, pokemonHp, pokemonLevel + * attack - attackName, attackDamage, attackDescription + * image - imageAltText, imageUrlSmall, imageUrlMedium, imageUrlLarge + * styling - cardClassName, nameClassName, typeClassName, hpClassName, attackClassName, imageClassName */ -interface IExerciseProps { - title: string; - subText: string; - ctaText: string; - ctaUrl: string; +interface IPokemonCardProps { + pokemonName: string; + pokemonType: string; + pokemonHp: number; + pokemonLevel: number; + attackName: string; + attackDamage: number; + attackDescription: string; imageAltText: string; - imageUrlMobile: string; - imageUrlTablet: string; - imageUrlDesktop: string; - containerClassName?: string; - titleClassName?: string; - subTextClassName?: string; - ctaClassName?: string; + imageUrlSmall: string; + imageUrlMedium: string; + imageUrlLarge: string; + cardClassName?: string; + nameClassName?: string; + typeClassName?: string; + hpClassName?: string; + attackClassName?: string; imageClassName?: string; } /* - 1b👨🏻‍💻 Update the props to match the new types defined above. + 1b👨🏻💻 Update the props to match the new grouped types defined above. */ export const Exercise = ({ - title, - subText, - ctaText, - ctaUrl, + pokemonName, + pokemonType, + pokemonHp, + pokemonLevel, + attackName, + attackDamage, + attackDescription, imageAltText, - imageUrlMobile, - imageUrlTablet, - imageUrlDesktop, - containerClassName, - titleClassName, - subTextClassName, - ctaClassName, + imageUrlSmall, + imageUrlMedium, + imageUrlLarge, + cardClassName, + nameClassName, + typeClassName, + hpClassName, + attackClassName, imageClassName -}: IExerciseProps) => { +}: IPokemonCardProps) => { /* - 2a 🤔 Could we destructure the image to be [mobile, tablet, desktop]? + 2a 🤔 Could we destructure the image to be [small, medium, large]? */ /* - 1c👨🏻‍💻 Update the props in the jsx + 1c👨🏻💻 Update the props in the jsx to use the grouped structure */ return (
- - {/* ✍🏻 picture elements are a great way to display responsive images */} - {/* ✍🏻 Using rem instead of pixels will change the image when you zoom in the page */} - {/* ✍🏻 Link: https://web.dev/learn/design/picture-element */} - - - +
+ + ⭐ Level {pokemonLevel} + +
+ + + + + {imageAltText} +

- {title} + {pokemonName}

-

- {subText} -

-
-
- + + {pokemonType} Type + + + ❤️ {pokemonHp} HP + +
+ +
- {ctaText} - +

+ ⚡ {attackName} - {attackDamage} damage +

+

{attackDescription}

+
); diff --git a/src/course/02-lessons/01-Bronze/PropsCombination/final/final.stories.tsx b/src/course/02-lessons/01-Bronze/PropsCombination/final/final.stories.tsx index fe71bb7..c4cbd86 100644 --- a/src/course/02-lessons/01-Bronze/PropsCombination/final/final.stories.tsx +++ b/src/course/02-lessons/01-Bronze/PropsCombination/final/final.stories.tsx @@ -16,27 +16,32 @@ type Story = StoryObj; */ export const Default: Story = { args: { - title: 'The Coldest Sunset Festival', - subText: - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus quia, nulla! Maiores et perferendis eaque, exercitationem praesentium nihil.', - cta: { - text: '#festival', - url: '/' + pokemon: { + name: 'Pikachu', + type: 'Electric', + hp: 120, + level: 25 + }, + attack: { + name: 'Thunderbolt', + damage: 90, + description: 'A strong electric blast that may paralyze the target.' }, image: { - alt: 'DJ playing at a festival', - images: [ - 'https://images.unsplash.com/photo-1493676304819-0d7a8d026dcf?w=767&h=640&fit=crop', - 'https://images.unsplash.com/photo-1493676304819-0d7a8d026dcf?w=1024&h=640&fit=crop', - 'https://images.unsplash.com/photo-1493676304819-0d7a8d026dcf?w=1600&h=900&fit=crop' + alt: 'Pikachu with electric sparks', + sources: [ + 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/25.png', + 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/25.png', + 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/25.png' ] }, - classNames: { - container: 'container', - title: 'title', - subText: 'subText', - cta: 'cta', - image: 'image' + styling: { + card: 'shadow-xl border-yellow-400', + name: 'text-yellow-600', + type: 'bg-yellow-500', + hp: 'text-yellow-700', + attack: 'border-yellow-400', + image: 'hover:scale-105 transition-transform' } } }; diff --git a/src/course/02-lessons/01-Bronze/PropsCombination/final/final.tsx b/src/course/02-lessons/01-Bronze/PropsCombination/final/final.tsx index cc5a54f..9227d28 100644 --- a/src/course/02-lessons/01-Bronze/PropsCombination/final/final.tsx +++ b/src/course/02-lessons/01-Bronze/PropsCombination/final/final.tsx @@ -1,84 +1,108 @@ import classnames from 'classnames'; -interface IFinalProps { - title: string; - subText: string; - cta: { - text: string; - url: string; +interface IPokemonCardProps { + pokemon: { + name: string; + type: string; + hp: number; + level: number; + }; + attack: { + name: string; + damage: number; + description: string; }; image: { alt: string; - images: string[]; + sources: string[]; }; - classNames?: { - container?: string; - title?: string; - subText?: string; - cta?: string; + styling?: { + card?: string; + name?: string; + type?: string; + hp?: string; + attack?: string; image?: string; }; } export const Final = ({ - title, - subText, - cta, + pokemon, + attack, image, - classNames -}: IFinalProps) => { - const [mobile, tablet, desktop] = image.images; + styling +}: IPokemonCardProps) => { + const [small, medium, large] = image.sources; return ( ); diff --git a/src/course/02-lessons/01-Bronze/PropsCombination/lesson.mdx b/src/course/02-lessons/01-Bronze/PropsCombination/lesson.mdx index 2115d3c..010586f 100644 --- a/src/course/02-lessons/01-Bronze/PropsCombination/lesson.mdx +++ b/src/course/02-lessons/01-Bronze/PropsCombination/lesson.mdx @@ -8,46 +8,51 @@ Props are used to pass data from one component to another. The prop combination Some benefits of this pattern include reduction of boilerplate code, improving code readability and maintainability. -Let's take a look at an example: +Let's take a look at an example with a Pokemon trading card: ```jsx -const CardComponent = ({ - title, - subText, - ctaText, - ctaUrl, +const PokemonCard = ({ + pokemonName, + pokemonType, + pokemonHp, + pokemonLevel, + attackName, + attackDamage, + attackDescription, imageAltText, - imageUrlMobile, - imageUrlTablet, - imageUrlDesktop, - containerClassName, - titleClassName, - subTextClassName, - ctaClassName, - imageClassName -}) =>
{/* Lots of imaginary code here... */}
; + imageUrlSmall, + imageUrlMedium, + imageUrlLarge, + cardClassName, + nameClassName, + typeClassName, + statsClassName, + attackClassName +}) =>
{/* Lots of Pokemon card code here... */}
; ``` -Yes... this is pretty wild but it's very common to see this in the real world. What we have going into this component is: +Yes... this is pretty wild but it's very common to see this in the real world. What we have going into this Pokemon card component is: -- image - the image sources, imageAltText -- cta - text and ctaUrl -- content - title, sub title -- classNames - all classNames +- pokemon - name, type, hp, level +- attack - name, damage, description +- image - the image sources and alt text +- styling - all className props Now look at this when it is grouped: ```jsx -const CardComponent = ({ title, subText, cta, image }) => ( -
{/* Lots of imaginary code here... */}
+const PokemonCard = ({ pokemon, attack, image, styling }) => ( +
{/* Lots of Pokemon card code here... */}
); ``` -It is now a lot simpler to understand, we know the component has a title, it also needs a cta and an image. If we then wanted to, we would add some styles in case we need to tweak the card. +It is now a lot simpler to understand, we know the component needs pokemon data, an attack, an image, and styling options. If we then wanted to, we could easily add more pokemon stats or attacks. ## Exercise -In this exercise we are going to do the same thing that we did to the card snippet above and then we have some extras to add to it so it will get you thinking about how to change the props if necessary. +In this exercise we are going to do the same thing that we did to the Pokemon card snippet above and then we have some extras to add to it so it will get you thinking about how to change the props if necessary. + +You'll be refactoring a Pokemon trading card component that currently has too many individual props into a cleaner, grouped structure. Head over to the exercise file and let's begin.