Zoeken...  ⌘K GitHub

VideoChapters video

Video speler met hoofdstuknavigatie.

/video-chapters
src/components/video/VideoChapters.astro
---
/**
 * VideoChapters
 * Videospeler met hoofdstuk-navigatielijst
 */
interface Props {
  videoUrl?: string;
  poster?: string;
  chapters?: { time: string; title: string }[];
}
const {
  videoUrl = 'https://www.w3schools.com/html/mov_bbb.mp4',
  poster = '',
  chapters = [
    { time: '0:00', title: 'Introductie' },
    { time: '1:15', title: 'De uitdaging' },
    { time: '3:40', title: 'Onze aanpak' },
    { time: '6:20', title: 'Resultaten & cijfers' },
    { time: '9:05', title: 'Conclusie & next steps' },
  ],
} = Astro.props;
---

<section class="vch">
  <div class="vch__inner">
    <div class="vch__player-wrap">
      <video
        class="vch__video"
        src={videoUrl}
        poster={poster || undefined}
        controls
        preload="metadata"
      ></video>
    </div>
    <aside class="vch__chapters">
      <h3 class="vch__chapters-title">Hoofdstukken</h3>
      <ol class="vch__list">
        {chapters.map((ch, i) => (
          <li class="vch__item">
            <span class="vch__num">{i + 1}</span>
            <div class="vch__info">
              <span class="vch__ch-title">{ch.title}</span>
              <span class="vch__time">{ch.time}</span>
            </div>
          </li>
        ))}
      </ol>
    </aside>
  </div>
</section>

<style>
  .vch {
    background: var(--color-primary, #0a0a0a);
    padding: 4rem 1.5rem;
  }
  .vch__inner {
    max-width: 1060px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: 1fr 280px;
    gap: 2rem;
    align-items: start;
  }
  .vch__player-wrap {
    border-radius: 12px;
    overflow: hidden;
    background: #000;
    aspect-ratio: 16/9;
  }
  .vch__video {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
  }
  .vch__chapters {
    background: #161616;
    border-radius: 12px;
    padding: 1.25rem;
    border: 1px solid #2a2a2a;
  }
  .vch__chapters-title {
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: #888;
    margin: 0 0 1rem;
  }
  .vch__list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
  }
  .vch__item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.5rem;
    border-radius: 7px;
    cursor: pointer;
    transition: background 0.15s;
  }
  .vch__item:hover {
    background: #222;
  }
  .vch__num {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: #2a2a2a;
    color: var(--color-accent, #6366f1);
    font-size: 0.72rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }
  .vch__info {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
  }
  .vch__ch-title {
    font-size: 0.85rem;
    color: #ddd;
    font-weight: 500;
    line-height: 1.3;
  }
  .vch__time {
    font-size: 0.72rem;
    color: #666;
    font-variant-numeric: tabular-nums;
  }
  @media (max-width: 720px) {
    .vch__inner { grid-template-columns: 1fr; }
  }
</style>

Props

Prop Type Default Beschrijving
videoUrl string Video URL
chapters { time: string; title: string }[] Hoofdstukken

* = verplicht