stories
kibo-ui-registry/storiesFreeComponent
A composable Stories component - a carousel of individual video cards like you'd see on Facebook.
Live preview
live · rendered by the registry
Rendered by Kibo UI Registry on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://www.kibo-ui.com/r/stories.jsonSource
1"use client";23import type {4 ComponentProps,5 HTMLAttributes,6 VideoHTMLAttributes,7} from "react";8import { useEffect, useRef } from "react";9import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";10import {11 Carousel,12 CarouselContent,13 CarouselItem,14} from "@/components/ui/carousel";15import { cn } from "@/lib/utils";1617export type StoriesProps = ComponentProps<typeof Carousel>;1819export const Stories = ({ className, opts, ...props }: StoriesProps) => (20 <Carousel21 className={cn("w-full", className)}22 opts={{23 align: "start",24 loop: false,25 dragFree: true,26 ...opts,27 }}28 {...props}29 />30);3132export type StoriesContentProps = ComponentProps<typeof CarouselContent>;3334export const StoriesContent = ({35 className,36 ...props37}: StoriesContentProps) => (38 <CarouselContent className={cn("-ml-2 gap-2", className)} {...props} />39);4041export type StoryProps = HTMLAttributes<HTMLDivElement>;4243export const Story = ({ className, ...props }: StoryProps) => (44 <CarouselItem className={cn("basis-0 pl-2 md:pl-4", className)}>45 <div46 className={cn(47 "group relative overflow-hidden rounded-xl bg-muted/40",48 "cursor-pointer transition-all duration-200",49 "hover:scale-[1.02] hover:shadow-lg",50 "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",51 className52 )}53 role="button"54 tabIndex={0}55 {...props}56 />57 </CarouselItem>58);5960export type StoryVideoProps = VideoHTMLAttributes<HTMLVideoElement>;6162const tRegex = /t=(\d+(?:\.\d+)?)/;6364export const StoryVideo = ({ className, ...props }: StoryVideoProps) => {65 const videoRef = useRef<HTMLVideoElement>(null);66 const initialTimeRef = useRef<number>(0);6768 // Parse the initial time from the src attribute (e.g., #t=20)69 useEffect(() => {70 const src = (props.src ?? "") as string;71 let initialTime = 0;72 if (typeof src === "string") {73 const hashIndex = src.indexOf("#");74 if (hashIndex !== -1) {75 const hash = src.slice(hashIndex + 1);76 // Look for t=number or t=start,end77 const tMatch = hash.match(tRegex);78 if (tMatch) {79 initialTime = Number.parseFloat(tMatch[1]);80 }81 }82 }83 initialTimeRef.current = initialTime;84 }, [props.src]);8586 const handleMouseOver = () => {87 videoRef.current?.play();88 };8990 const handleMouseOut = () => {91 if (videoRef.current) {92// … truncated
What it pulls in
Other registry items
Files it writes
More from Kibo UI Registry
All 41 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| announcementannouncement | Kibo UI Registry | Components | Free | no deps | |
| avatar-stackavatar-stack | Kibo UI Registry | Components | Free | no deps | |
| bannerbanner | Kibo UI Registry | Components | Free | 2 deps | |
| calendarcalendar | Kibo UI Registry | Components | Free | 3 deps | |
| choiceboxchoicebox | Kibo UI Registry | Components | Free | 2 deps | |
| code-blockcode-block | Kibo UI Registry | Components | Free | 5 deps · 2 files | |
| color-pickercolor-picker | Kibo UI Registry | Components | Free | 3 deps | |
| comboboxcombobox | Kibo UI Registry | Components | Free | 2 deps |
