{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "homepage", "type": "registry:block", "title": "homepage", "description": "Bloque Concorde homepage — incluye sus 6 componentes.", "dependencies": [ "react" ], "registryDependencies": [], "files": [ { "path": "bloques/homepage/desktop/AuctioneerSection.tsx", "type": "registry:file", "target": "bloques/homepage/desktop/AuctioneerSection.tsx", "content": "\"use client\";\n\n/**\n * AuctioneerSection — Bloque/sección de Concorde (Voyager DS)\n *\n * Card de subastador (766 × 352): cabecera con nombre + nº de ofertas, logo\n * central (slot) y \"Ir al Perfil\", sobre una fila de 4 OfferCards.\n * Compuesta 100% con componentes Concorde: OfferCard · BadgeStatus · ProfileButton.\n */\n\nimport type { JSX, ReactNode } from \"react\";\nimport OfferCard from \"../../../components/OfferCard\";\nimport BadgeStatus from \"../../../components/BadgeStatus\";\nimport ProfileButton from \"../../../components/ProfileButton\";\nimport CardTitle from \"../../../components/CardTitle\";\n\nexport type AuctioneerBadge = \"none\" | \"live\" | \"proxima\";\n\nexport interface AuctioneerOffer {\n name: string;\n year: string | number;\n price: string;\n imageSrc?: string;\n badge?: AuctioneerBadge;\n}\n\nexport interface AuctioneerSectionProps {\n /** Nombre del subastador */\n name?: string;\n /** Etiqueta de ofertas (p.ej. \"10 Ofertas\") */\n offersLabel?: string;\n /** Logo central (slot) — por defecto un placeholder */\n logo?: ReactNode;\n /** Las 4 ofertas (cards) */\n offers?: AuctioneerOffer[];\n onProfile?: () => void;\n className?: string;\n}\n\nexport const AUCTIONEER_WIDTH = 766;\nexport const AUCTIONEER_HEIGHT = 352;\n\nconst DEFAULT_OFFERS: AuctioneerOffer[] = [\n { name: \"Audi Q3\", year: 2026, price: \"US$ 9,999\", imageSrc: \"/demo/bronco.jpg\" },\n { name: \"Audi Q3\", year: 2026, price: \"US$ 9,999\", imageSrc: \"/demo/bronco.jpg\", badge: \"live\" },\n { name: \"Audi Q3\", year: 2026, price: \"US$ 9,999\", imageSrc: \"/demo/bronco.jpg\" },\n { name: \"Audi Q3\", year: 2026, price: \"US$ 9,999\", imageSrc: \"/demo/bronco.jpg\", badge: \"proxima\" },\n];\n\nfunction badgeFor(badge: AuctioneerBadge | undefined): JSX.Element | undefined {\n if (badge === \"live\") return ;\n if (badge === \"proxima\") return ;\n return undefined;\n}\n\nexport default function AuctioneerSection({\n name = \"SANTANDER CONSUMER\",\n offersLabel = \"10 Ofertas\",\n logo,\n offers = DEFAULT_OFFERS,\n onProfile,\n className = \"\",\n}: AuctioneerSectionProps): JSX.Element {\n return (\n \n {/* Cabecera */}\n
\n {/* Izquierda: CardTitle (nombre + ofertas + corchetes naranjas) */}\n \n\n {/* Centro: logo (slot opcional) */}\n {logo ?
{logo}
: null}\n\n {/* Derecha: Ir al Perfil */}\n Ir al Perfil\n
\n\n {/* Fila de ofertas */}\n
\n {offers.map(function renderOffer(o, i) {\n return (\n \n );\n })}\n
\n \n );\n}\n" }, { "path": "bloques/homepage/desktop/CategoriesSection.tsx", "type": "registry:file", "target": "bloques/homepage/desktop/CategoriesSection.tsx", "content": "\"use client\";\n\n/**\n * CategoriesSection — Bloque/sección de Concorde (Voyager DS)\n *\n * Card de 2 columnas (766 × 184):\n * · Izquierda \"TIPO DE OFERTA\" → 2 OfferType (NEGOCIABLE · EN VIVO)\n * · Derecha \"CATEGORÍAS\" → 4 CategoryCard\n * Separadas por un divisor vertical. Compuesta 100% con componentes Concorde:\n * CardTitle · OfferType · CategoryCard.\n */\n\nimport type { JSX } from \"react\";\nimport CardTitle from \"../../../components/CardTitle\";\nimport OfferType from \"../../../components/OfferType\";\nimport CategoryCard from \"../../../components/CategoryCard\";\n\nexport const CATEGORIES_WIDTH = 766;\nexport const CATEGORIES_HEIGHT = 184;\n\nexport interface CategoriesSectionProps {\n onNegotiable?: () => void;\n onLive?: () => void;\n onCategory?: (category: string) => void;\n className?: string;\n}\n\nconst colStyle = { display: \"flex\", flexDirection: \"column\" as const, alignItems: \"flex-start\" as const, justifyContent: \"space-between\" as const, height: 143, gap: 8 };\n\nexport default function CategoriesSection({\n onNegotiable,\n onLive,\n onCategory,\n className = \"\",\n}: CategoriesSectionProps): JSX.Element {\n return (\n \n {/* Columna izquierda: TIPO DE OFERTA */}\n
\n \n
\n \n \n
\n
\n\n {/* Divisor vertical */}\n
\n\n {/* Columna derecha: CATEGORÍAS */}\n
\n \n
\n \n \n \n \n
\n
\n \n );\n}\n" }, { "path": "bloques/homepage/desktop/dimensions.ts", "type": "registry:file", "target": "bloques/homepage/desktop/dimensions.ts", "content": "/**\n * Dimensiones del bloque Homepage (desktop) — módulo plano sin \"use client\".\n * Los Server Components y los Viewers pueden importar estas constantes\n * sin cruzar la barrera \"use client\" → undefined → NaN.\n */\n\nexport const HOMEPAGE_WIDTH = 798;\nexport const HOMEPAGE_HEIGHT = 1104;\n" }, { "path": "bloques/homepage/desktop/Homepage.tsx", "type": "registry:file", "target": "bloques/homepage/desktop/Homepage.tsx", "content": "/**\n * Homepage — Bloque de Concorde (Voyager DS)\n *\n * Bloque = composición de varios componentes. Por ahora es solo el lienzo\n * base: un fondo blanco de 798 × 1104. Iremos montando las secciones encima.\n */\n\nimport type { JSX } from \"react\";\nimport AuctioneerSection from \"./AuctioneerSection\";\nimport CategoriesSection from \"./CategoriesSection\";\n\nexport interface HomepageProps {\n className?: string;\n}\n\nimport { HOMEPAGE_WIDTH, HOMEPAGE_HEIGHT } from \"./dimensions\";\nexport { HOMEPAGE_WIDTH, HOMEPAGE_HEIGHT } from \"./dimensions\";\n\nexport default function Homepage({ className = \"\" }: HomepageProps): JSX.Element {\n return (\n \n {/* Principal Banner 766 × 272 · 16px arriba del Secondary, centrado */}\n \n PRINCIPAL BANNER\n
\n\n {/* Secondary Banner 766 × 100 · 16px arriba de Categorías, centrado */}\n \n SECONDARY BANNER\n \n\n {/* Sección Categorías 766 × 184 · 16px arriba del Subastador, centrada */}\n
\n \n
\n\n {/* Sección Subastador 766 × 352 · 16px arriba del banner, centrada */}\n
\n \n
\n\n {/* Banner 768 × 100 · a 32px del bottom, centrado horizontalmente */}\n \n BANNER · 766 × 100\n \n \n );\n}\n" }, { "path": "bloques/homepage/mobile/dimensions.ts", "type": "registry:file", "target": "bloques/homepage/mobile/dimensions.ts", "content": "/**\n * Dimensiones del bloque HomepageMobile — módulo plano sin \"use client\".\n */\n\nexport const HOMEPAGE_MOBILE_WIDTH = 420;\nexport const HOMEPAGE_MOBILE_HEIGHT = 1800;\n" }, { "path": "bloques/homepage/mobile/HomepageMobile.tsx", "type": "registry:file", "target": "bloques/homepage/mobile/HomepageMobile.tsx", "content": "/**\n * HomepageMobile — Bloque de Concorde (Voyager DS)\n *\n * Página de inicio · mobile (420 de ancho). Por ahora:\n * · Header 420×64 (logo de la marca a la izquierda + «Ingresa»)\n * · Banner 388×598 (placeholder, a 16px de margen)\n * Iremos montando las demás secciones encima.\n */\n\n\"use client\";\n\nimport { useState } from \"react\";\nimport type { JSX } from \"react\";\nimport AppHeader from \"../../header/desktop/Header\";\nimport CardTitle from \"../../../components/CardTitle\";\nimport OfferType from \"../../../components/OfferType\";\nimport CategoryCard from \"../../../components/CategoryCard\";\nimport OfferCard from \"../../../components/OfferCard\";\nimport BadgeStatus from \"../../../components/BadgeStatus\";\nimport ProfileButton from \"../../../components/ProfileButton\";\nimport SidebarMobile, { SidebarMenuButton } from \"../../sidebar/mobile/SidebarMobile\";\n\nimport { HOMEPAGE_MOBILE_WIDTH, HOMEPAGE_MOBILE_HEIGHT } from \"./dimensions\";\nexport { HOMEPAGE_MOBILE_WIDTH, HOMEPAGE_MOBILE_HEIGHT } from \"./dimensions\";\n\n// Card blanca de sección (388 de ancho, sombra estándar del homepage)\nconst SECTION_CARD = {\n width: 388,\n boxSizing: \"border-box\" as const,\n background: \"#ffffff\",\n borderRadius: 8,\n boxShadow: \"rgba(0,0,0,0.1) 0px 0px 16px 4px\",\n padding: 16,\n};\n\n// Overrides: OfferType llena su columna (2-up) y CategoryCard a 86 para que\n// las 4 entren en la fila.\nconst HM_STYLES = `\n.poftype.hm-oftype { width: 100%; box-sizing: border-box; }\n.pcatcard.hm-cat { width: 86px; }\n`;\n\nexport interface HomepageMobileProps {\n className?: string;\n /** Alto del marco para previsualizaciones (px). En producción se omite. Ver `SidebarMobile`. */\n frameHeight?: number;\n}\n\nexport default function HomepageMobile({ className = \"\", frameHeight }: HomepageMobileProps): JSX.Element {\n const [menuOpen, setMenuOpen] = useState(false);\n\n const page = (\n \n {/* Header 420×64 · hamburguesa + logo de la marca a la izquierda */}\n \n setMenuOpen(true)} expanded={menuOpen} />\n \"VMC\n \n }\n />\n\n