Display

Media Preview Row

A row with a 16 / 9 thumbnail whose space is reserved before the image loads: the row never jumps, and the duration is repeated as real text.

  • item
  • row
  • media
  • thumbnail

Preview

1440pxHost theme

Use it with AI

  1. 1. Copy the link.
  2. 2. Write to your agent in your own words and drop the link into the sentence.
  3. 3. The agent opens the link and installs the component from the registry.

put this in the header: https://vibeui.ru/c/item-005?lang=en

  • Building a component catalogue in one eveningРоман Тищенко · 3 дня назад · 12:40
  • Show the full instructions

    What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.

    # Install and place "item-005" (Media Preview Row) from VibeUI
    
    ## 1. Install first — do not skip, do not recreate
    Run this exact command before writing any code:
    npx shadcn@latest add https://vibeui.ru/r/item-005.json
    
    Registry item: https://vibeui.ru/r/item-005.json
    Installs to: components/vibeui/item-005.tsx (the exact path follows this project's components.json aliases).
    npm dependencies: none.
    Registry dependencies: none.
    
    Install it from the registry. Do not recreate it from the description,
    do not substitute a similar component from another library, and do not
    rewrite it to match the project's existing style.
    
    ## 2. What it is
    A row with a 16 / 9 thumbnail whose space is reserved before the image loads: the row never jumps, and the duration is repeated as real text.
    
    A list row with a 16 / 9 thumbnail, a duration badge and a two-line title. Zero dependencies, one file.
    
    ## 3. How to use it
    import { Item005 } from "@/components/vibeui/item-005"
    
    <Item005 title="Case study" badge="08:12" image="/cover.jpg" />
    
    Read the installed file for the full prop list.
    
    ## 4. Where to place it
    This is a small inline component. Put it exactly where the user asked,
    inside the existing markup. Do not create a new page, section or
    wrapper for it. If a similar control already sits in that spot,
    replace it instead of adding a second one.
    
    Placement: ___
    (The user fills this line in. If it is still blank, ask where to put it
    instead of guessing.)
    
    ## 5. Keep exactly as installed
    - the local --vibeui-item-005-* palette — do not swap it for your theme tokens
    - the aspect-ratio on the thumbnail: without it the row jumps when the image loads
    - the gradient placeholder: empty space of the same height is more honest than a collapsed row
    - the duration repeated as text: a caption drawn over the image is invisible to a screen reader
    - alt="" on the image — it is decorative, the meaning sits in the title next to it
    - clamping the title to two lines: a third one breaks the rhythm of the list
    
    ## 6. You may change
    - title and meta — the title and the author-and-date line
    - badge — the duration or another short marker
    - image — the picture URL, and the accent through the accent prop
    - the thumbnail width and the row width
    
    ## 7. Rules
    - The component renders a plain img tag: do not swap in next/image, the block must work outside Next.
    - Without the image prop the gradient stays — that is a normal state, not an error.
    - Wrap the rows in a <ul>: a lone li outside a list is invalid.
    - Do not lift the CSS variables into globals.css: the component has to stay a single file.
    
    ## 8. Verify
    - it renders with no console errors;
    - it looks like the preview on the VibeUI page you copied this from;
    - if it does not, you changed something listed in section 5 — put it back.

    For developers

    npx shadcn@latest add https://vibeui.ru/r/item-005.json
    https://vibeui.ru/r/item-005.json

    Компонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-item-005-*. Серверный: хуков нет. Превью — блок фиксированной ширины с aspect-ratio 16 / 9 и overflow:hidden; без пропа image в нём лежит градиентная заглушка, поэтому высота строки одинакова с картинкой и без неё. Метка длительности лежит поверх превью под aria-hidden и повторена во вторичной строке текстом. Название обрезается двумя строками через -webkit-line-clamp.

    Component source

    The same file your agent installs. Here in case you would rather copy it by hand.

    import type { ComponentPropsWithoutRef, CSSProperties } from "react"
    
    export type Item005Props = Omit<
      ComponentPropsWithoutRef<"li">,
      "children" | "title"
    > & {
      title?: string
      meta?: string
      badge?: string
      image?: string
      accent?: string
    }
    
    // Идея компонента: строка с медиа-превью. Место под картинку занято до её
    // загрузки: превью задано пропорцией 16 / 9 и фиксированной шириной, поэтому
    // строка не прыгает, когда файл наконец приехал. Без картинки в том же
    // прямоугольнике лежит градиентная заглушка, а не пустота — высота строки
    // одинакова в обоих случаях. Длительность лежит поверх превью и продублирована
    // текстом для скринридера: подпись на картинке ему не видна.
    const STYLES = `
    :where([data-vibeui-block="item-005"]){
    --vibeui-item-005-bg:oklch(1 0 0);
    --vibeui-item-005-fg:oklch(0.23 0.014 265);
    --vibeui-item-005-muted:oklch(0.56 0.014 265);
    --vibeui-item-005-border:oklch(0.9 0.006 265);
    --vibeui-item-005-accent:oklch(0.55 0.19 262);
    --vibeui-item-005-shade:oklch(0.2 0.02 265 / 72%);
    --vibeui-item-005-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
    }
    [data-vibeui-block="item-005"]{
    display:flex;align-items:center;gap:0.75rem;
    width:100%;max-width:24rem;box-sizing:border-box;padding:0.625rem 0.75rem;
    list-style:none;
    background:var(--vibeui-item-005-bg);
    border:1px solid var(--vibeui-item-005-border);border-radius:0.75rem;
    font-family:var(--vibeui-item-005-font);color:var(--vibeui-item-005-fg);
    }
    [data-vibeui-block="item-005"] *{box-sizing:border-box}
    /* Место под превью занято пропорцией: строка не прыгает после загрузки. */
    [data-vibeui-block="item-005"] [data-part="media"]{
    position:relative;flex:none;width:5.5rem;aspect-ratio:16 / 9;
    border-radius:0.5rem;overflow:hidden;
    background:linear-gradient(135deg,
    color-mix(in oklab,var(--vibeui-item-005-accent) 30%,white),
    color-mix(in oklab,var(--vibeui-item-005-accent) 70%,black));
    }
    [data-vibeui-block="item-005"] [data-part="media"] img{
    display:block;width:100%;height:100%;object-fit:cover;
    }
    [data-vibeui-block="item-005"] [data-part="badge"]{
    position:absolute;right:0.25rem;bottom:0.25rem;
    padding:0 0.25rem;border-radius:0.25rem;
    background:var(--vibeui-item-005-shade);color:oklch(1 0 0);
    font-size:0.625rem;font-weight:650;line-height:1.4;font-variant-numeric:tabular-nums;
    }
    [data-vibeui-block="item-005"] [data-part="text"]{flex:1 1 auto;min-width:0;display:grid;gap:0.1875rem}
    [data-vibeui-block="item-005"] [data-part="title"]{
    font-size:0.875rem;font-weight:650;line-height:1.3;
    display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
    }
    [data-vibeui-block="item-005"] [data-part="meta"]{font-size:0.75rem;line-height:1.35;color:var(--vibeui-item-005-muted)}
    @media (prefers-reduced-motion:reduce){[data-vibeui-block="item-005"] *{animation:none!important;transition:none!important}}
    `
    
    /**
     * Строка списка с медиа-превью фиксированной пропорции и меткой длительности.
     * Один файл, ноль зависимостей, собственная палитра.
     */
    export function Item005({
      title = "Как собрать каталог компонентов за вечер",
      meta = "Роман Тищенко · 3 дня назад",
      badge = "12:40",
      image,
      accent,
      className,
      style,
      ...props
    }: Item005Props) {
      const palette = {
        ...(accent ? { "--vibeui-item-005-accent": accent } : null),
        ...style,
      } as CSSProperties
    
      return (
        <>
          <style href="vibeui-item-005" precedence="medium">
            {STYLES}
          </style>
          <li
            {...props}
            data-vibeui-block="item-005"
            className={className}
            style={palette}
          >
            <span data-part="media">
              {image ? <img src={image} alt="" /> : null}
              {badge ? (
                <span data-part="badge" aria-hidden="true">
                  {badge}
                </span>
              ) : null}
            </span>
            <span data-part="text">
              <span data-part="title">{title}</span>
              <span data-part="meta">
                {meta}
                {badge ? ` · ${badge}` : null}
              </span>
            </span>
          </li>
        </>
      )
    }