Home Cover
Homepage hero of the Panda websites (the original cover): the cover photo (phone cover on phones) or the plan's looping background video, the hero video play button, the owner portrait on phones and the centered…
Anatomy
Every piece of Home Cover as it nests in code. A root holds the data and state; its parts and hooks only work inside it.
<PandaProvider>Mounted once in app/layout.tsx<HomeCover />complete widgetHomepage hero of the Panda websites (the original cover): the cover photo (phone cover on phones) or the plan's looping background video,…
</PandaProvider>Installation
- 1npm install <tarball or @pandaidx/widgets>Terminalnpm install https://github.com/pandaidx/panda-widgets/releases/download/v1.14.1/pandaidx-widgets-1.14.1.tgz
- 2import "@pandaidx/widgets/styles.css" in app/layout.tsx
- 3Wrap the site in <PandaProvider publicKey apiUrl preset theme> (app/layout.tsx)
- 4In each page (Server Component) call the widget's server loader, then render the widget with its data
- 5Allow the images: next.config images.remotePatterns [{ protocol: "https", hostname: "**" }] (listing and blog photos come from several CDNs)
Usage
// app/page.tsx: the Panda homepage hero (cover + centered search)import { HomeCover } from "@pandaidx/widgets/client"import { fetchHomeCover } from "@pandaidx/widgets/server"export default async function Home() {const cover = await fetchHomeCover({ publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL })return <HomeCover data={cover} />}
Examples
A hero in the site's own markup with the cover, video and search
// components/hero.tsx"use client"import Image from "next/image"import { HomeSearch, VideoModal, useHomeCover, type HomeCoverData } from "@pandaidx/widgets/client"export const Hero = ({ data }: { data: HomeCoverData | null }) => {const cover = useHomeCover({ data })return (<section className="relative isolate flex h-122.5 items-end justify-center overflow-hidden pb-10 sm:h-screen lg:pb-25">{cover.cover ? <Image src={cover.cover} alt="" fill priority sizes="100vw" className="-z-10 object-cover" /> : null}<div className="flex w-full flex-col items-center gap-10">{cover.videoUrl ? <VideoModal url={cover.videoUrl}><button type="button">Play</button></VideoModal> : null}{cover.showSearchBar ? <HomeSearch /> : null}</div></section>)}
API reference
HomeCover
Homepage hero of the Panda websites (the original cover): the cover photo (phone cover on phones) or the plan's looping background video, the hero video play button, the owner portrait on phones and the centered HomeSearch (websites pill design: For Sale / For Rent / Sold tabs over the pill autocomplete). Every default matches websites.
Import from @pandaidx/widgets/client · renders inside PandaProvider
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | object | — | Cover photos, videos, search switch and owner portrait (null renders nothing). |
| viewport | "mobile" | "desktop" | "desktop" | Device class of the request (user agent): mobile shows coverMobile, like websites. |
| showSearch | boolean | — | Shows the search bar (default data.showSearchBar). |
| search | object | — | HomeSearch params of the hero search (default the websites pill design): variant, tabs, initialMarket, placeholder, background, color, spacing, tone, size, buttonStyle, buttonLabel, buttonIcon, buttonTone, buttonBackground, buttonColor, searchPath, classNames, and its layout and look width, align, tabsPlacement, tabsAlign, shape, surface, border, tabStyle, tabsAttached, and the results dropdown look suggestions (images, imageShape, size, weight, itemShape, highlight, panelShape, shadow). Example (square bar, tabs left-aligned on top of it): search={{ shape: "square", align: "start", tabsAlign: "start", tabsAttached: true }}. |
| searchLayout | object | — | { position, offset } where the hero search sits: position bottom (websites) | center | top; offset its distance from that edge, a CSS length ("120px") or one per min-width breakpoint ({ base: "112px", sm: "144px", md: "208px", lg: "160px" }; a missing breakpoint keeps the smaller one; default the websites 10 spacing units, 25 from lg; ignored for center). With search.width / align / tabsPlacement this replaces any CSS on the widget markup: move or resize the hero search with these params only. |
| showPlayButton | boolean | true | Shows the play button of the hero video (data.coverVideo). |
| showAvatar | boolean | true | Shows the owner portrait on phones when there is no phone cover nor video. |
| classNames | object | — | Tailwind classes for root (cover box), media (photo/video layer), body (the wrapper that positions the play button and the search: its vertical padding IS the search offset, e.g. body: "pb-28 md:pb-52") and content (play button + search column). They win over the widget classes at every breakpoint, no ! needed; prefer searchLayout for the search position. |
| preset | "default" | "template1" | — | Preset for this widget only (defaults to the provider preset). |
| variant | "default" | "template1" | — | Deprecated alias of preset. |
| theme | object | — | Token overrides for this widget only, merged over the provider theme (same shape as PandaProvider.theme). |
Hooks
useHomeCover()inside PandaProvideruseHomeCover({ data }) → { cover, coverMobile (show it below sm, the desktop cover from sm up), backgroundVideo (looping MP4 for a <video autoPlay muted loop playsInline>), videoUrl (the hero YouTube video as a watch?v= URL for <VideoModal url>), avatar, ownerName, showSearchBar (the agent wants <HomeSearch /> or useHomeSearch over the hero), hasTopBar, empty } — data comes from fetchHomeCover (null → empty cover). Paint the photo with next/image (fill, priority, sizes="100vw"). HomeCover stays the ready-made hero. Client component only.
Server data
Loaders run in a Server Component and come from @pandaidx/widgets/server. Typed data is for a page you design yourself, rendered inside the root.
fetchHomeCover()widget loaderGET /v1/site → the hero fields (homepage.cover/coverMobile/backgroundVideo/coverVideo, the plan's video flag, coverSearch.showSearchBar, owner portrait, top bar). toHomeCoverData(site) maps a site you already loaded. Returns HomeCoverData | null → data