{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "badgestatus", "type": "registry:component", "title": "BadgeStatus", "description": "Componente Concorde BadgeStatus — un solo archivo, BadgeStatus.tsx.", "dependencies": [ "react" ], "registryDependencies": [], "files": [ { "path": "components/BadgeStatus.tsx", "type": "registry:file", "target": "components/BadgeStatus.tsx", "content": "\"use client\";\r\n\r\n/**\r\n * BadgeStatus — Generado por Concorde\r\n * Fuente: https://voyager-ds.vercel.app/preview/components/pase1\r\n * Generado: 2026-05-28\r\n *\r\n * Pill badge de estado de subasta: EN VIVO (animated dot) · PRÓXIMA (blinking clock)\r\n */\r\n\r\nimport type { JSX } from \"react\";\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\nexport type BadgeStatusVariant = \"live\" | \"proxima\";\r\n\r\nexport interface BadgeStatusProps {\r\n variant: BadgeStatusVariant;\r\n /** Override de label / contenido editable (default: \"EN VIVO\" / \"PRÓXIMA\") */\r\n label?: string;\r\n /** Muestra el dot (live) / reloj (proxima). false = solo el texto. Default true. */\r\n icon?: boolean;\r\n className?: string;\r\n}\r\n\r\n// ─── Self-contained CSS ───────────────────────────────────────────────────────\r\n\r\nconst STYLE_ID = \"concorde-badgestatus-styles\";\r\n\r\nconst BADGESTATUS_STYLES = `\r\n/* Pulso del punto EN VIVO — frames exactos del SVG: On (6px, opacidad 1) ↔ On-1 (4px, 0.28) */\r\n@keyframes badgestatus-live-pulse {\r\n 0%, 100% { opacity: 1; transform: scale(1); }\r\n 50% { opacity: 0.28; transform: scale(0.67); }\r\n}\r\n\r\n/* Parpadeo del reloj PRÓXIMA — On (sólido) ↔ Off (0.28) */\r\n@keyframes badgestatus-clock-blink {\r\n 0%, 100% { opacity: 1; transform: scale(1); }\r\n 50% { opacity: 0.28; transform: scale(0.85); }\r\n}\r\n\r\n/* ── Base pill ── */\r\n.badgestatus {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 5px;\r\n padding: 3px 8px 3px 6px;\r\n border-radius: 9999px;\r\n font-family: var(--vmc-font-display, 'Plus Jakarta Sans', system-ui, sans-serif);\r\n font-size: 9px;\r\n font-weight: 700;\r\n letter-spacing: 0.07em;\r\n text-transform: uppercase;\r\n white-space: nowrap;\r\n backdrop-filter: blur(6px);\r\n -webkit-backdrop-filter: blur(6px);\r\n color: oklch(1 0 0);\r\n border: 1px solid transparent;\r\n user-select: none;\r\n}\r\n\r\n/* ── EN VIVO — sync EXACTO SVG (1310:11895 / 11904) ──\r\n bg naranja diagonal + borde gradiente cálido + ring naranja */\r\n.badgestatus--live {\r\n background-image:\r\n linear-gradient(135deg, #ff9639 0%, #ef852e 40%, #be3d00 100%),\r\n linear-gradient(135deg, #ffbc83 0%, rgba(255,255,255,0.45) 40%, #da6c1e 75%, #ffbc83 100%);\r\n background-origin: padding-box, border-box;\r\n background-clip: padding-box, border-box;\r\n box-shadow:\r\n rgba(239, 133, 46, 0.45) 0px 2px 10px,\r\n rgba(255, 255, 255, 0.14) 0px 1px 0px inset;\r\n}\r\n\r\n/* ── PRÓXIMA — sync EXACTO SVG (1310:11797 / 11799) ──\r\n bg morado diagonal + borde gradiente lila + glow morado #200068 */\r\n.badgestatus--proxima {\r\n background-image:\r\n linear-gradient(135deg, #8460e5 0%, #3b1782 100%),\r\n linear-gradient(135deg, #8776ff 0%, rgba(255,255,255,0.4) 38%, #532bc7 68%, #8776ff 100%);\r\n background-origin: padding-box, border-box;\r\n background-clip: padding-box, border-box;\r\n box-shadow:\r\n rgba(32, 0, 104, 0.5) 0px 2px 10px,\r\n rgba(255, 255, 255, 0.1) 0px 1px 0px inset;\r\n}\r\n\r\n/* ── Pulsing dot (live) ── */\r\n.badgestatus-dot {\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 9999px;\r\n background: #ffffff;\r\n flex-shrink: 0;\r\n animation: badgestatus-live-pulse 1.4s ease-in-out infinite;\r\n position: relative;\r\n}\r\n\r\n/* ── Blinking clock (proxima) ── */\r\n.badgestatus-clock {\r\n flex-shrink: 0;\r\n display: inline-flex;\r\n align-items: center;\r\n animation: badgestatus-clock-blink 1.4s ease-in-out infinite;\r\n}\r\n\r\n/* ── Reduced motion ── */\r\n@media (prefers-reduced-motion: reduce) {\r\n .badgestatus-dot { animation: none; }\r\n .badgestatus-clock { animation: none; }\r\n}\r\n`;\r\n\r\nlet _stylesInjected = false;\r\n\r\n// ─── Clock SVG (Próxima) ──────────────────────────────────────────────────────\r\n\r\nfunction ClockIcon(): JSX.Element {\r\n return (\r\n \r\n \r\n \r\n \r\n );\r\n}\r\n\r\n// ─── Component ────────────────────────────────────────────────────────────────\r\n\r\nconst LABEL_DEFAULTS: Record = {\r\n live: \"EN VIVO\",\r\n proxima: \"PRÓXIMA\",\r\n};\r\n\r\nexport default function BadgeStatus({\r\n variant,\r\n label,\r\n icon = true,\r\n className = \"\",\r\n}: BadgeStatusProps): JSX.Element {\r\n if (typeof document !== \"undefined\" && !_stylesInjected) {\r\n if (!document.getElementById(STYLE_ID)) {\r\n const el = document.createElement(\"style\");\r\n el.id = STYLE_ID;\r\n el.textContent = BADGESTATUS_STYLES;\r\n document.head.appendChild(el);\r\n }\r\n _stylesInjected = true;\r\n }\r\n\r\n const displayLabel = label ?? LABEL_DEFAULTS[variant];\r\n\r\n const classes = [\r\n \"badgestatus\",\r\n `badgestatus--${variant}`,\r\n className,\r\n ].filter(Boolean).join(\" \");\r\n\r\n return (\r\n <>\r\n \r\n \r\n {icon && variant === \"live\" ? (\r\n \r\n ) : null}\r\n {icon && variant === \"proxima\" ? (\r\n \r\n \r\n \r\n ) : null}\r\n {displayLabel}\r\n \r\n \r\n );\r\n}\r\n" } ] }