The Header component is the main navigation header for the application. It displays the podcast branding, tagline, and provides links to external resources and settings.
Location
src/components/Header/Header.jsx
Import
import Header from "../Header/Header" ;
Props
This component does not accept any props.
Features
Branding Section
Displays the podcast name and tagline:
< div className = { styles . logo } >
< motion.h1 whileHover = "hover" variants = { logoVariants } >
< Link to = "/" className = { styles . logoLink } >
Nadie Sabe Nada
</ Link >
</ motion.h1 >
< p className = { styles . tagline } >
El podcast donde nada está claro, pero todo es divertido
</ p >
</ div >
Navigation Links
Provides four interactive elements:
Website External link to peralstudio.com < IconButton
href = "https://peralstudio.com"
target = "_blank"
rel = "noopener"
>
< Language />
</ IconButton >
GitHub External link to GitHub profile < IconButton
href = "https://github.com/PeralStudio"
target = "_blank"
rel = "noopener"
>
< GitHub />
</ IconButton >
Latest Episode Internal link to most recent episode < Link to = "/ultimo-episodio" className = { styles . ctaLink } >
Último Episodio
</ Link >
Settings Internal link to settings page < Link to = "/settings" >
< IconButton >
< Settings />
</ IconButton >
</ Link >
Animations
The header uses multiple Framer Motion animation variants:
Header Entrance
Logo Hover
Icon Hover
CTA Button Hover
const headerVariants = {
hidden: { opacity: 0 , y: - 50 },
visible: {
opacity: 1 ,
y: 0 ,
transition: {
type: "spring" ,
stiffness: 70 ,
damping: 15 ,
delay: 0.2
}
}
};
All interactive icons have custom tooltips:
const BootstrapTooltip = styled (({ className , ... props }) => (
< Tooltip { ... props } arrow classes = { { popper: className } } />
))(({ theme }) => ({
[ `& . ${ tooltipClasses . arrow } ` ]: {
color: "#14D993"
},
[ `& . ${ tooltipClasses . tooltip } ` ]: {
backgroundColor: "#14DB93" ,
color: "#000000" ,
fontSize: "14px" ,
fontWeight: "bold" ,
padding: "5px 10px" ,
borderRadius: "5px"
}
}));
< BootstrapTooltip
title = "Página Web"
placement = "top"
arrow
disableInteractive
TransitionComponent = { Fade }
TransitionProps = { { timeout: 600 } }
>
< motion.div whileHover = "hover" variants = { iconVariants } >
< IconButton href = "https://peralstudio.com" target = "_blank" >
< Language />
</ IconButton >
</ motion.div >
</ BootstrapTooltip >
Complete Structure
return (
< motion.header
className = { styles . header }
initial = "hidden"
animate = "visible"
variants = { headerVariants }
>
{ /* Logo and tagline */ }
< div className = { styles . logo } >
< motion.h1 whileHover = "hover" variants = { logoVariants } >
< Link to = "/" className = { styles . logoLink } >
Nadie Sabe Nada
</ Link >
</ motion.h1 >
< p className = { styles . tagline } >
El podcast donde nada está claro, pero todo es divertido
</ p >
</ div >
{ /* Navigation icons */ }
< div className = { styles . socialIcons } >
{ /* Website icon */ }
< BootstrapTooltip title = "Página Web" >
< motion.div whileHover = "hover" variants = { iconVariants } >
< IconButton href = "https://peralstudio.com" target = "_blank" >
< Language />
</ IconButton >
</ motion.div >
</ BootstrapTooltip >
{ /* GitHub icon */ }
< BootstrapTooltip title = "Github" >
< motion.div whileHover = "hover" variants = { iconVariants } >
< IconButton href = "https://github.com/PeralStudio" target = "_blank" >
< GitHub />
</ IconButton >
</ motion.div >
</ BootstrapTooltip >
{ /* Latest episode button */ }
< motion.div whileHover = "hover" variants = { ctaVariants } >
< Link to = "/ultimo-episodio" className = { styles . ctaLink } >
Último Episodio
</ Link >
</ motion.div >
{ /* Settings icon */ }
< BootstrapTooltip title = "Ajustes" >
< motion.div whileHover = "hover" variants = { iconVariants } >
< Link to = "/settings" >
< IconButton >
< Settings />
</ IconButton >
</ Link >
</ motion.div >
</ BootstrapTooltip >
</ div >
</ motion.header >
);
Material-UI Icons
The component uses Material-UI icons:
import {
GitHub ,
Language ,
Settings
} from "@mui/icons-material" ;
import { IconButton } from "@mui/material" ;
Styling
Uses CSS modules for scoped styling:
import styles from "./Header.module.css" ;
< motion.header className = { styles . header } >
< div className = { styles . logo } >
< motion.h1 >
< Link to = "/" className = { styles . logoLink } > ... </ Link >
</ motion.h1 >
< p className = { styles . tagline } > ... </ p >
</ div >
< div className = { styles . socialIcons } >
< IconButton className = { styles . iconButton } > ... </ IconButton >
</ div >
</ motion.header >
External Links
All external links use proper security attributes:
< IconButton
href = "https://peralstudio.com"
target = "_blank"
rel = "noopener" // Prevents access to window.opener
className = { styles . iconButton }
>
< Language />
</ IconButton >
The rel="noopener" attribute prevents the opened page from accessing the original page’s window object, improving security.
Responsive Design
The header is fully responsive with CSS modules handling different screen sizes. The layout adjusts based on viewport width.
Usage Example
import React from "react" ;
import Header from "./components/Header/Header" ;
import PodcastList from "./components/PodcastList/PodcastList" ;
function App () {
return (
< div className = "app" >
< Header />
< main >
< PodcastList onPlayPodcast = { handlePlay } />
</ main >
</ div >
);
}
export default App ;
Animation Timing
The header animation sequence:
Initial state : Opacity 0, translated up 50px
Delay : 0.2 seconds
Animation : Spring transition over ~0.5 seconds
Final state : Opacity 1, original position
< motion.header
initial = "hidden" // { opacity: 0, y: -50 }
animate = "visible" // { opacity: 1, y: 0 }
variants = { headerVariants }
>
Each icon is wrapped in motion.div for hover effects:
< BootstrapTooltip title = "Ajustes" >
< motion.div whileHover = "hover" variants = { iconVariants } >
< Link to = "/settings" >
< IconButton className = { styles . iconButton } >
< Settings style = { { fontSize: "26px" , marginBottom: "1px" } } />
</ IconButton >
</ Link >
</ motion.div >
</ BootstrapTooltip >
The motion wrapper enables smooth scale and rotation animations on hover.
The “Último Episodio” button has a fixed minimum width:
< motion.div
whileHover = "hover"
variants = { ctaVariants }
style = { { minWidth: "126px" } }
>
< Link to = "/ultimo-episodio" className = { styles . ctaLink } >
Último Episodio
</ Link >
</ motion.div >
This ensures consistent sizing even when text content changes.