Apple gallery
100xui/apple-galleryFreeBlock
An elegant, interactive media gallery inspired by Apple's iPhone 17 landing page. Designed with smooth transitions, interactive playback controls, and a highly polished user experience.
Live preview
live · rendered by the registry
Rendered by 100xui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://100xui.com/r/apple-gallery.jsonSource
1"use client";23import React from "react";4import {5 type HTMLMotionProps,6 motion,7 useScroll,8 useTransform,9 useMotionValue,10 animate,11} from "motion/react";12import { PlayIcon, PauseIcon } from "lucide-react";1314import { Button } from "@/components/ui/button";15import { cn } from "@/lib/utils";1617const AppleGalleryContext = React.createContext<null | {18 slideCount: number;19 isPlaying: boolean;20 setActiveSlideIndex: React.Dispatch<React.SetStateAction<number>>;21 containerRef: React.RefObject<HTMLDivElement | null>;22 activeSlideIndex: number;23 targetSlideIndexRef: React.RefObject<null | number>;24 progressAnimationRef: React.RefObject<ReturnType<typeof animate> | null>;25 setIsPlaying: React.Dispatch<React.SetStateAction<boolean>>;26 scrollToSlide: (childIndex: number) => void;27 durationInSec: number;28}>(null);2930export function useAppleGallery() {31 const ctx = React.useContext(AppleGalleryContext);32 if (ctx === null) {33 throw new Error("useAppleGallery must be used within an <AppleGallery />");34 }35 return ctx;36}3738export function AppleGallery({39 children,40 durationInSec = 4,41 className,42 ...props43}: {44 children: React.ReactNode;45 durationInSec?: number;46} & React.ComponentProps<"div">) {47 const [slideCount] = React.useState(48 (49 (React.Children.toArray(children)[0] as React.ReactElement).props as {50 children: React.ReactElement[];51 }52 ).children.length53 );5455 const [isPlaying, setIsPlaying] = React.useState(false);56 const [activeSlideIndex, setActiveSlideIndex] = React.useState(0);5758 const containerRef = React.useRef<HTMLDivElement | null>(null);59 const progressAnimationRef = React.useRef<ReturnType<typeof animate> | null>(60 null61 );62 const targetSlideIndexRef = React.useRef<null | number>(activeSlideIndex);6364 const scrollToSlide = React.useCallback(65 (childIndex: number) => {66 if (containerRef.current) {67 setIsPlaying(false);68 setActiveSlideIndex(childIndex);69 targetSlideIndexRef.current = childIndex;70 progressAnimationRef.current = null;71 containerRef.current.children[childIndex].scrollIntoView({72 behavior: "smooth",73 block: "nearest",74 });75 }76 },77 [targetSlideIndexRef, setIsPlaying]78 );7980 return (81 <AppleGalleryContext.Provider82 value={{83 slideCount,84 isPlaying,85 activeSlideIndex,86 progressAnimationRef,87 setActiveSlideIndex,88 containerRef,89 scrollToSlide,90// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from 100xui
All 14 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Chat bento cardchat-bento-card | 100xui | Blocks | Free | 1 dep | |
| demosdemos | 100xui | Blocks | Free | no deps · 12 files | |
| In-page navbarin-page-navbar | 100xui | Blocks | Free | 1 dep · 2 files | |
| internalsinternals | 100xui | Blocks | Free | no deps · 4 files | |
| iPhone 3D mockupiphone-3d-mockup | 100xui | Blocks | Free | no deps | |
| Menu wheelmenu-wheel | 100xui | Blocks | Free | 1 dep | |
| Morph modalmorph-modal | 100xui | Blocks | Free | 1 dep | |
| Motion Dockmotion-dock | 100xui | Blocks | Free | 1 dep · 3 files |
