{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "sala", "type": "registry:block", "title": "sala", "description": "Bloque Concorde sala — incluye sus 13 componentes.", "dependencies": [ "react" ], "registryDependencies": [], "files": [ { "path": "bloques/sala/desktop/BidChat.tsx", "type": "registry:file", "target": "bloques/sala/desktop/BidChat.tsx", "content": "/**\n * BidChat — Sección del bloque Sala (Voyager DS)\n * Fuente: Figma VOYAGER · \"BidChat\" (panel 316×677)\n *\n * Un solo panel 316×677 (gradiente morado + glass white 8% + borde gradiente,\n * radio 16, backdrop-blur 14, sombra) que contiene TODO:\n * · Los BidMessage son el bg y van hasta arriba (su bg/borde es el del panel).\n * · BidProposal (bid actual, 280×78) montado ENCIMA, arriba al centro.\n * · ProgressBar 424×22 (rainbow, recortada al panel) sin esquinas redondeadas.\n * · Botón primary 200×48 (solo el monto) abajo; al presionarlo dispara el\n * efecto de luz del bid actual.\n */\n\n\"use client\";\n\nimport { useState } from \"react\";\nimport type { JSX } from \"react\";\nimport BidProposal from \"../../../components/BidProposal\";\nimport BidMessage from \"../../../components/BidMessage\";\nimport ProgressBar from \"../../../components/ProgressBar\";\nimport Button from \"../../../components/Button\";\nimport MobileChatPanel from \"../mobile/MobileChatPanel\";\nimport { START_COUNT, STEP as LIVE_STEP, STREAM, fmtMoney, pad, type LiveMsg, type Phase } from \"../liveData\";\n\nexport interface BidChatProps {\n className?: string;\n /** Modo en vivo — flujo completo (llegada → streaming → procesando → tabla → actividad). */\n live?: boolean;\n /** Fase del live (controlada por SalaDesktop) */\n phase?: Phase;\n /** Contador de la caja \"INICIA EN\" (controlado por SalaDesktop) */\n count?: number;\n /** Estado del streaming/final (controlado por SalaDesktop) */\n shown?: number;\n prog?: number;\n bidAmount?: number;\n bidder?: string;\n pressed?: boolean;\n flash?: number;\n /** Colores del efecto de luz del bid actual (editable). Default: primary. */\n flashColors?: string[];\n /** Tipo de efecto de luz: \"bulb\" (bombilla) o \"spin\" (gira). Default \"bulb\". */\n flashMode?: \"bulb\" | \"spin\" | \"explode\" | \"pulse\" | \"combo\" | \"shine\";\n}\n\nexport const BIDCHAT_WIDTH = 316;\nexport const BIDCHAT_HEIGHT = 677;\n// Ancho interno del panel (316 menos el borde de 1.5px a cada lado)\nconst PANEL_INNER_WIDTH = BIDCHAT_WIDTH - 3;\n\nconst USER = \"KAHTH4\";\nconst AMOUNT = \"US$ 5,079\";\n\nconst VMC_LOGO = \"VMC;\n\n// Burbuja de un mensaje del stream live (misma lógica que mobile)\nfunction LiveBubble({ m }: { m: LiveMsg }): JSX.Element {\n if (m.kind === \"vmc\") {\n return (\n \n {m.text}\n \n );\n }\n if (m.kind === \"proposal\") {\n return (\n \n {m.bidder} ha propuesto {fmtMoney(m.amount ?? 0)}\n \n );\n }\n return (\n \n Cierra en {fmtMoney(m.amount ?? 0)}\n \n );\n}\n\n// 4 bloques: propuesta (blanca/izq · naranja/live a la der) → \"Cierra en\" → VMC.\n// El 2º y 4º son \"live\" (naranja, der); los demás blancos a la izquierda.\nconst PROPOSAL_TYPES = [\"white\", \"live\", \"white\", \"live\"] as const;\nfunction buildMessages(): JSX.Element[] {\n const out: JSX.Element[] = [];\n PROPOSAL_TYPES.forEach(function block(propType, i) {\n const side = propType === \"live\" ? \"sent\" : \"received\";\n out.push(\n \n {USER} ha propuesto {AMOUNT}\n ,\n );\n out.push(\n \n Cierra en {AMOUNT}\n ,\n );\n out.push(\n \n A la una\n ,\n );\n });\n return out;\n}\n\n// Panel: morado (paint0) + glass white 8% + borde gradiente (paint1)\nconst PANEL_BG = \"linear-gradient(0deg, rgba(255,255,255,0.08), rgba(255,255,255,0.08)), linear-gradient(115deg, #5F3ED8 0%, #340091 50%, #140046 100%)\";\nconst PANEL_BORDER = \"linear-gradient(120deg, #ffffff 0%, #F4AC59 22%, #8460E5 74.5%, #ffffff 100%)\";\n\nconst STYLE_ID = \"concorde-bidchat-styles\";\nconst BIDCHAT_STYLES = `\n/* Lista de mensajes (ocupa el panel hasta arriba) · scroll oculto */\n.bidchat-list { scrollbar-width: none; -ms-overflow-style: none; }\n.bidchat-list::-webkit-scrollbar { width: 0; height: 0; display: none; }\n.bidchat-list .pbidmsg { font-size: 13px; }\n.bidchat-list .pbidmsg--sent { align-self: flex-end; }\n/* ProgressBar 424×22 sin esquinas redondeadas (recortada al panel) */\n.bidchat-prog .pprogbar { border-radius: 0; width: 424px; height: 22px; }\n/* En live la barra ocupa el ancho real del panel para que el % de llenado sea correcto */\n.bidchat-prog--full .pprogbar { width: 100%; }\n/* CTA 200×48, solo el monto */\n.bidchat-cta .pvbtn { width: 200px; padding: 0; }\n.bidchat-cta--pressed .pvbtn {\n --vbtn-angle: 135deg; --vbtn-stop-a: #d46e20; --vbtn-stop-b: #5a35c2;\n color: #d1d5dc; transform: scale(0.97) translateY(1px);\n box-shadow: rgba(0,0,0,0.22) 0 2px 5px 2px inset, rgba(0,0,0,0.12) 0 1px 3px;\n}\n\n/* ── Streaming de pujas (entran deslizando y suben) ── */\n.bidchat-stream { scrollbar-width: none; -ms-overflow-style: none; }\n.bidchat-stream::-webkit-scrollbar { width: 0; height: 0; display: none; }\n.bidchat-stream .pbidmsg { font-size: 13px; }\n.bidchat-msg { align-self: flex-start; }\n.bidchat-msg--sent { align-self: flex-end; }\n.bidchat-msg--received { animation: bidchat-in-left 150ms cubic-bezier(0.3,0,0,1) both; }\n.bidchat-msg--sent { animation: bidchat-in-right 150ms cubic-bezier(0.3,0,0,1) both; }\n@keyframes bidchat-in-left { from { opacity: 0; transform: translateX(-50px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes bidchat-in-right { from { opacity: 0; transform: translateX(50px); } to { opacity: 1; transform: translateX(0); } }\n@media (prefers-reduced-motion: reduce) { .bidchat-msg--received, .bidchat-msg--sent { animation: none; } }\n\n/* ── Llegada (welcome / extended) — mismos tamaños/posición que mobile ── */\n.bidchat-status {\n position: absolute; inset: 0; z-index: 4;\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n gap: 22px; text-align: center; padding: 24px 16px;\n}\n/* Línea superior (blanca, SIN gradiente) — igual que \".smchat__ext\" de mobile (18/700) */\n.bidchat-top {\n max-width: 100%; font-size: 18px; font-weight: 700; color: #ffffff;\n}\n/* Título grande con gradiente lila — igual que \".smchat__rp\" de mobile (30/800) */\n.bidchat-rp {\n max-width: 100%;\n font-size: 30px; font-weight: 800; line-height: 1.12; letter-spacing: -0.01em;\n background: linear-gradient(135deg, #CFBAFF 0%, #ffffff 35%, #AE8EFF 65%, #CFBAFF 100%);\n -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent;\n filter: drop-shadow(0 0 10px rgba(132,96,229,0.55)) drop-shadow(0 0 24px rgba(82,52,189,0.4));\n}\n/* dots — 84×24 */\n.bidchat-dots { display: flex; align-items: center; justify-content: center; gap: 12px; width: 84px; height: 24px; }\n.bidchat-dots span {\n border-radius: 50%; background: #fff; box-shadow: 0 0 8px rgba(174,142,255,0.85);\n animation: bidchat-dot 1.2s ease-in-out infinite both;\n}\n.bidchat-dots span:nth-child(1) { width: 10px; height: 10px; animation-delay: 0s; }\n.bidchat-dots span:nth-child(2) { width: 12px; height: 12px; animation-delay: 0.18s; }\n.bidchat-dots span:nth-child(3) { width: 8px; height: 8px; animation-delay: 0.36s; }\n@keyframes bidchat-dot {\n 0%, 80%, 100% { opacity: 0.35; transform: scale(0.65); }\n 40% { opacity: 1; transform: scale(1.15); box-shadow: 0 0 14px rgba(174,142,255,1); }\n}\n/* Caja \"INICIA EN\" — 278×78 */\n.bidchat-box {\n position: relative; box-sizing: border-box; width: 278px; max-width: 100%; height: 78px; border-radius: 20px;\n background: rgba(255,255,255,0.08); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px);\n display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 10px 24px;\n}\n.bidchat-box::before {\n content: \"\"; position: absolute; inset: 0; border-radius: inherit; padding: 1.5px;\n background: linear-gradient(120deg, #ffffff 0%, #F4AC59 22%, #8460E5 74.5%, #ffffff 100%);\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none;\n}\n.bidchat-box-label {\n font-size: 12px; font-weight: 700; letter-spacing: 0.08em;\n background: linear-gradient(135deg, #CFBAFF 0%, #ffffff 35%, #AE8EFF 65%, #CFBAFF 100%);\n -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent;\n}\n.bidchat-box-row { display: flex; align-items: center; gap: 12px; }\n.bidchat-box-row svg {\n filter:\n drop-shadow(0 0 6px rgba(207,186,255,0.95))\n drop-shadow(0 0 14px rgba(174,167,255,0.85))\n drop-shadow(0 0 26px rgba(132,96,229,0.6));\n}\n.bidchat-box-time {\n font-size: 30px; font-weight: 800; color: #ffffff; letter-spacing: 0.08em;\n font-variant-numeric: tabular-nums; text-shadow: 0 0 10px rgba(174,166,255,0.5);\n}\n@media (prefers-reduced-motion: reduce) { .bidchat-dots span { animation: none; } }\n`;\n\n// Gradiente lila común (paths exactos de los SVG \"INICIA EN\")\nconst DESK_INICIA_GRAD = (\n \n \n \n \n \n \n);\n// Timer (SVG 46×51) — reloj con gradiente lila, render 40×40\nfunction DeskClockIcon(): JSX.Element {\n return (\n \n \n {DESK_INICIA_GRAD}\n \n );\n}\n// Plus (SVG 56×56) — \"+\" con gradiente lila, render 40×40\nfunction DeskPlusIcon(): JSX.Element {\n return (\n \n \n {DESK_INICIA_GRAD}\n \n );\n}\n\nlet _stylesInjected = false;\n\nexport default function BidChat({\n className = \"\",\n live = false,\n phase = \"idle\",\n count = START_COUNT,\n shown = 0,\n prog = 40,\n bidAmount = 6559,\n bidder = \"ZAE389\",\n pressed = false,\n flash: liveFlash = 0,\n flashColors,\n flashMode = \"bulb\",\n}: BidChatProps): JSX.Element {\n const [flash, setFlash] = useState(0);\n const [bidActual, setBidActual] = useState(6559);\n const [nextBid, setNextBid] = useState(7000);\n\n const isArrival = live && (phase === \"welcome\" || phase === \"extended\");\n const isStreaming = live && phase === \"streaming\";\n // Pantallas finales (procesando/tabla/actividad/reserve/improve): overlays full-panel (sin botón)\n const isFinalPhase = live && (phase === \"processing\" || phase === \"result\" || phase === \"activity\" || phase === \"bestbid\");\n const ctaAmount = bidAmount + LIVE_STEP;\n\n if (typeof document !== \"undefined\" && !_stylesInjected) {\n if (!document.getElementById(STYLE_ID)) {\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = BIDCHAT_STYLES;\n document.head.appendChild(el);\n }\n _stylesInjected = true;\n }\n\n // Click en el botón → pujo yo: sube el bid actual y se enciende el efecto de luz\n function handleBid(): void {\n setBidActual(nextBid);\n setNextBid((n) => n + LIVE_STEP);\n setFlash((f) => f + 1);\n }\n\n return (\n \n