Skip to main content

Header Component

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>
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:
const headerVariants = {
  hidden: { opacity: 0, y: -50 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { 
      type: "spring", 
      stiffness: 70, 
      damping: 15, 
      delay: 0.2 
    }
  }
};

Tooltips

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>
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:
  1. Initial state: Opacity 0, translated up 50px
  2. Delay: 0.2 seconds
  3. Animation: Spring transition over ~0.5 seconds
  4. Final state: Opacity 1, original position
<motion.header
  initial="hidden"      // { opacity: 0, y: -50 }
  animate="visible"     // { opacity: 1, y: 0 }
  variants={headerVariants}
>

Icon Button Wrapper

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.

CTA Button

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.

Build docs developers (and LLMs) love