feat: Actualizar CDC Brief con branding GLM y ajustes UX finales
This commit is contained in:
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
+145
-171
File diff suppressed because one or more lines are too long
Vendored
+1
-10
@@ -1,10 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="GLM"><rect width="64" height="64" rx="14" fill="#FFFFFF"/><rect x="7" y="20" width="50" height="24" rx="4" fill="#4F758B"/><path d="M29 20h13v17c0 3-2.5 5.5-5.5 5.5H29V20Z" fill="#6CC24A"/><path d="M28 20h4v24h-4z" fill="#6CC24A"/><path d="M24 28h4v16h-4z" fill="#6CC24A"/></svg>
|
||||||
<defs>
|
|
||||||
<linearGradient id="g" x1="8" y1="8" x2="56" y2="56" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop offset="0" stop-color="#6D7CFF"/>
|
|
||||||
<stop offset="1" stop-color="#2FE6FF"/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<rect x="6" y="6" width="52" height="52" rx="16" fill="url(#g)"/>
|
|
||||||
<path d="M34.6 15.5L20.8 34.5H30l-0.9 14 14.1-19.2h-9.1l0.5-13.8Z" fill="white"/>
|
|
||||||
</svg>
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 363 B |
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Vendored
+9
-4
@@ -1,12 +1,17 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<link rel="icon" type="image/svg+xml" href="/brief/favicon.svg" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="icon" type="image/png" href="glm-logo.png?v=5" />
|
||||||
|
<link rel="shortcut icon" type="image/png" href="glm-logo.png?v=5" />
|
||||||
|
<link rel="apple-touch-icon" href="glm-logo.png?v=5" />
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>CDC Brief GLM</title>
|
<title>CDC Brief | GLM</title>
|
||||||
<script type="module" crossorigin src="/brief/assets/index-BjRIMN2B.js"></script>
|
<script type="module" crossorigin src="/brief/assets/index-DT0rQidg.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/brief/assets/index-D-Qs_b2T.css">
|
<link rel="stylesheet" crossorigin href="/brief/assets/index-B-WJR2cH.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
+7
-2
@@ -1,10 +1,15 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="icon" type="image/png" href="glm-logo.png?v=5" />
|
||||||
|
<link rel="shortcut icon" type="image/png" href="glm-logo.png?v=5" />
|
||||||
|
<link rel="apple-touch-icon" href="glm-logo.png?v=5" />
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>CDC Brief GLM</title>
|
<title>CDC Brief | GLM</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
+1
-10
@@ -1,10 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="GLM"><rect width="64" height="64" rx="14" fill="#FFFFFF"/><rect x="7" y="20" width="50" height="24" rx="4" fill="#4F758B"/><path d="M29 20h13v17c0 3-2.5 5.5-5.5 5.5H29V20Z" fill="#6CC24A"/><path d="M28 20h4v24h-4z" fill="#6CC24A"/><path d="M24 28h4v16h-4z" fill="#6CC24A"/></svg>
|
||||||
<defs>
|
|
||||||
<linearGradient id="g" x1="8" y1="8" x2="56" y2="56" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop offset="0" stop-color="#6D7CFF"/>
|
|
||||||
<stop offset="1" stop-color="#2FE6FF"/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<rect x="6" y="6" width="52" height="52" rx="16" fill="url(#g)"/>
|
|
||||||
<path d="M34.6 15.5L20.8 34.5H30l-0.9 14 14.1-19.2h-9.1l0.5-13.8Z" fill="white"/>
|
|
||||||
</svg>
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 363 B |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
+20
-104
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { motion, AnimatePresence } from 'motion/react';
|
import { motion, AnimatePresence } from 'motion/react';
|
||||||
import { FileText, Loader2, ShieldCheck, Sparkles, Workflow } from 'lucide-react';
|
import { Loader2 } from 'lucide-react';
|
||||||
import { onAuthStateChanged, signInWithPopup, signOut, User } from 'firebase/auth';
|
import { onAuthStateChanged, signInWithPopup, signOut, User } from 'firebase/auth';
|
||||||
|
|
||||||
import { Header } from './components/Header';
|
import { Header } from './components/Header';
|
||||||
@@ -209,7 +209,7 @@ Verifica que la URL esté correcta en el entorno y que el endpoint esté activo
|
|||||||
|
|
||||||
if (authLoading) {
|
if (authLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen items-center justify-center bg-[#060816] text-zinc-200">
|
<div className="flex min-h-screen items-center justify-center bg-[#F7FAF8] text-[#4F758B]">
|
||||||
Cargando acceso...
|
Cargando acceso...
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -226,112 +226,30 @@ Verifica que la URL esté correcta en el entorno y que el endpoint esté activo
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex min-h-screen flex-col overflow-x-hidden bg-[#060816] text-zinc-100 font-sans selection:bg-indigo-500/30">
|
<div className="glm-app relative flex min-h-screen flex-col overflow-x-hidden bg-[#F4F7F5] font-['Plus_Jakarta_Sans',sans-serif] text-[#4A4A4A] selection:bg-[#6CC24A]/20">
|
||||||
|
{/* Subtle mesh background */}
|
||||||
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||||
<div className="absolute left-[-10%] top-[-15%] h-[34rem] w-[34rem] rounded-full bg-indigo-600/18 blur-3xl" />
|
<div className="absolute left-[-10%] top-[-10%] h-[32rem] w-[32rem] rounded-full bg-[#EEF6E8]/60 blur-[90px]" />
|
||||||
<div className="absolute right-[-8%] top-[8%] h-[30rem] w-[30rem] rounded-full bg-cyan-400/12 blur-3xl" />
|
<div className="absolute right-[-8%] top-[15%] h-[28rem] w-[28rem] rounded-full bg-[#D6E8F4]/60 blur-[90px]" />
|
||||||
<div className="absolute bottom-[-18%] left-[20%] h-[28rem] w-[28rem] rounded-full bg-fuchsia-500/10 blur-3xl" />
|
|
||||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.03)_1px,transparent_1px)] bg-[size:42px_42px] opacity-[0.06]" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Header isConnected={isConnected} onLogout={handleLogout} />
|
<Header isConnected={isConnected} onLogout={handleLogout} />
|
||||||
|
|
||||||
<main className="relative flex-1">
|
<main className="relative flex-1">
|
||||||
<div className="mx-auto flex w-full max-w-7xl flex-col gap-6 px-4 py-6 pb-8 sm:px-6 lg:px-8">
|
<div className="mx-auto w-full max-w-6xl px-4 py-6 pb-10 sm:px-6 lg:px-8 flex flex-col gap-5">
|
||||||
<section className="overflow-hidden rounded-[32px] border border-white/10 bg-white/5 shadow-[0_30px_80px_rgba(0,0,0,0.35)] backdrop-blur-xl">
|
|
||||||
<div className="grid gap-0 lg:grid-cols-[1.5fr_1fr]">
|
|
||||||
<div className="relative p-6 sm:p-7 lg:p-8">
|
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(99,102,241,0.22),transparent_38%),radial-gradient(circle_at_bottom_right,rgba(34,211,238,0.14),transparent_36%)]" />
|
|
||||||
<div className="relative">
|
|
||||||
<div className="mb-4 inline-flex items-center gap-2 rounded-full border border-indigo-400/25 bg-indigo-500/10 px-3 py-1 text-xs font-semibold uppercase tracking-[0.22em] text-indigo-200">
|
|
||||||
<Sparkles className="h-3.5 w-3.5" /> Portal inteligente de briefs
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 className="max-w-3xl text-3xl font-semibold tracking-tight text-white sm:text-4xl">
|
|
||||||
Carga el brief en un flujo claro, visual y mucho más profesional.
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<p className="mt-4 max-w-2xl text-sm leading-7 text-zinc-300 sm:text-base">
|
|
||||||
La interfaz guía al usuario paso por paso, reduce errores de carga y organiza audio, imágenes, archivos, piezas gráficas y referencias para construir un brief listo para revisión interna.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="mt-6 flex flex-wrap gap-3">
|
|
||||||
{[
|
|
||||||
{ icon: ShieldCheck, label: 'Validaciones obligatorias' },
|
|
||||||
{ icon: Workflow, label: 'Proceso guiado por pasos' },
|
|
||||||
{ icon: FileText, label: 'Entrega estructurada al flujo' },
|
|
||||||
].map(({ icon: Icon, label }) => (
|
|
||||||
<div
|
|
||||||
key={label}
|
|
||||||
className="inline-flex items-center gap-2 rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-zinc-200"
|
|
||||||
>
|
|
||||||
<Icon className="h-4 w-4 text-indigo-300" />
|
|
||||||
<span>{label}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="border-t border-white/10 bg-black/20 p-6 sm:p-7 lg:border-l lg:border-t-0 lg:p-8">
|
|
||||||
<div className="rounded-[28px] border border-white/10 bg-black/25 p-5">
|
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">
|
|
||||||
Resumen del sistema
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="mt-4 space-y-4">
|
|
||||||
{[
|
|
||||||
'La nota de voz, las imágenes y los PDFs sí se analizan automáticamente.',
|
|
||||||
'Word, Excel, PowerPoint y otros adjuntos se guardan en la carpeta del proyecto.',
|
|
||||||
'Los enlaces online se registran para alimentar el brief final.',
|
|
||||||
'El usuario no necesita usar el portal como chat libre: todo queda guiado.',
|
|
||||||
].map((item) => (
|
|
||||||
<div key={item} className="flex items-start gap-3">
|
|
||||||
<div className="mt-1 h-2.5 w-2.5 rounded-full bg-indigo-400 shadow-[0_0_18px_rgba(129,140,248,0.7)]" />
|
|
||||||
<p className="text-sm leading-6 text-zinc-300">{item}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="rounded-[30px] border border-white/10 bg-black/20 p-4 shadow-[0_24px_60px_rgba(0,0,0,0.28)] backdrop-blur-xl sm:p-5">
|
|
||||||
<div className="mb-4 flex flex-wrap items-center justify-between gap-3">
|
|
||||||
<div>
|
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">
|
|
||||||
Carga guiada
|
|
||||||
</p>
|
|
||||||
<h3 className="mt-1 text-lg font-semibold text-white sm:text-xl">
|
|
||||||
Completa el brief y envía la solicitud
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{/* Brief Input Section */}
|
||||||
|
<section className="overflow-hidden rounded-[28px] border border-white/60 bg-white/80 shadow-[0_8px_40px_rgba(79,117,139,0.10)] backdrop-blur-xl">
|
||||||
<InputArea
|
<InputArea
|
||||||
onSendMessage={handleSendMessage}
|
onSendMessage={handleSendMessage}
|
||||||
isProcessing={isProcessing}
|
isProcessing={isProcessing}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-[30px] border border-white/10 bg-black/20 p-4 shadow-[0_24px_60px_rgba(0,0,0,0.28)] backdrop-blur-xl sm:p-5">
|
{/* Response Section — only show when there's content */}
|
||||||
<div className="mb-4 flex flex-wrap items-center justify-between gap-3">
|
{(messages.length > 0 || isProcessing) && (
|
||||||
<div>
|
<section className="overflow-hidden rounded-[28px] border border-white/60 bg-white/80 p-5 shadow-[0_8px_40px_rgba(79,117,139,0.10)] backdrop-blur-xl sm:p-6">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">
|
<p className="mb-4 text-xs font-bold uppercase tracking-[0.22em] text-[#6B8FA3]">Respuesta del portal</p>
|
||||||
Respuesta del portal
|
|
||||||
</p>
|
|
||||||
<h3 className="mt-1 text-lg font-semibold text-white sm:text-xl">
|
|
||||||
Resultado de la solicitud
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="min-h-[220px] rounded-[24px] border border-white/10 bg-white/[0.03] p-4 sm:p-5 lg:p-6">
|
|
||||||
{messages.length === 0 && !isProcessing && (
|
|
||||||
<div className="flex min-h-[150px] items-center justify-center rounded-[22px] border border-dashed border-white/10 bg-black/10 px-5 text-center text-sm leading-6 text-zinc-500">
|
|
||||||
Cuando envíes la solicitud, aquí aparecerá la respuesta del flujo y el enlace de Drive.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<AnimatePresence initial={false}>
|
<AnimatePresence initial={false}>
|
||||||
{messages.map((message) => (
|
{messages.map((message) => (
|
||||||
@@ -344,18 +262,16 @@ Verifica que la URL esté correcta en el entorno y que el endpoint esté activo
|
|||||||
initial={{ opacity: 0, y: 10 }}
|
initial={{ opacity: 0, y: 10 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
exit={{ opacity: 0, scale: 0.9 }}
|
exit={{ opacity: 0, scale: 0.9 }}
|
||||||
className="mb-4 flex w-fit items-center gap-3 rounded-2xl border border-white/10 bg-white/5 px-4 py-3"
|
className="flex w-fit items-center gap-3 rounded-2xl border border-[#D0D0D0]/60 bg-white px-4 py-3 shadow-sm"
|
||||||
>
|
>
|
||||||
<Loader2 className="h-4 w-4 animate-spin text-indigo-400" />
|
<Loader2 className="h-4 w-4 animate-spin text-[#6CC24A]" />
|
||||||
<span className="text-sm font-medium text-zinc-300">
|
<span className="text-sm font-medium text-[#4A4A4A]">Procesando la solicitud...</span>
|
||||||
Procesando la solicitud...
|
|
||||||
</span>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div ref={messagesEndRef} className="h-2" />
|
<div ref={messagesEndRef} className="h-1" />
|
||||||
</div>
|
</section>
|
||||||
</section>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+31
-38
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { LogOut, Sparkles, Zap } from 'lucide-react';
|
import { LogOut } from 'lucide-react';
|
||||||
import { cn } from '../lib/utils';
|
import { cn } from '../lib/utils';
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
@@ -7,55 +7,48 @@ interface HeaderProps {
|
|||||||
onLogout: () => void;
|
onLogout: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logoSrc = `${import.meta.env.BASE_URL}glm-logo.png`;
|
||||||
|
|
||||||
export const Header: React.FC<HeaderProps> = ({ isConnected, onLogout }) => {
|
export const Header: React.FC<HeaderProps> = ({ isConnected, onLogout }) => {
|
||||||
return (
|
return (
|
||||||
<header className="relative z-50 border-b border-white/10 bg-black/25 px-4 py-4 backdrop-blur-2xl sm:px-6 lg:px-8">
|
<header className="sticky top-0 z-50 border-b border-[#D0D0D0]/60 bg-white/90 backdrop-blur-2xl shadow-[0_4px_24px_rgba(79,117,139,0.07)]">
|
||||||
<div className="mx-auto flex w-full max-w-7xl items-center justify-between gap-4">
|
<div className="mx-auto flex w-full max-w-7xl items-center justify-between gap-4 px-5 py-3 sm:px-8">
|
||||||
<div className="flex min-w-0 items-center gap-3 sm:gap-4">
|
|
||||||
<div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-[linear-gradient(135deg,#6366f1_0%,#2563eb_50%,#06b6d4_100%)] shadow-[0_18px_40px_rgba(79,70,229,0.38)]">
|
{/* Left: Logo + Title */}
|
||||||
<Zap className="h-5 w-5 text-white" />
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="flex h-14 w-14 items-center justify-center overflow-hidden rounded-[18px] border border-slate-200/80 bg-white p-1.5 shadow-[0_4px_14px_rgba(79,117,139,0.10)]">
|
||||||
|
<img src={logoSrc} alt="GLM" className="h-full w-full object-contain" />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div className="min-w-0">
|
<h1 className="text-base font-bold tracking-tight text-[#4F758B] sm:text-lg">
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
Portal Brief CDC
|
||||||
<h1 className="truncate text-lg font-semibold tracking-tight text-white sm:text-xl">
|
</h1>
|
||||||
Portal Brief CDC
|
<div className="mt-0.5 flex items-center gap-2">
|
||||||
</h1>
|
<span className={cn(
|
||||||
<span className="hidden rounded-full border border-white/10 bg-white/5 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.24em] text-zinc-400 sm:inline-flex">
|
'relative flex h-2 w-2 shrink-0'
|
||||||
Experiencia guiada
|
)}>
|
||||||
|
{isConnected && (
|
||||||
|
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[#6CC24A] opacity-60" />
|
||||||
|
)}
|
||||||
|
<span className={cn(
|
||||||
|
'relative inline-flex h-2 w-2 rounded-full',
|
||||||
|
isConnected ? 'bg-[#6CC24A]' : 'bg-red-400'
|
||||||
|
)} />
|
||||||
|
</span>
|
||||||
|
<span className="text-[11px] font-medium text-slate-400">
|
||||||
|
{isConnected ? 'Conectado' : 'Sin conexión'} · GomezLee Marketing
|
||||||
</span>
|
</span>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-2 sm:gap-3">
|
|
||||||
<div className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-2.5 py-1 text-xs text-zinc-300">
|
|
||||||
<span className="relative flex h-2.5 w-2.5">
|
|
||||||
{isConnected && (
|
|
||||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-70" />
|
|
||||||
)}
|
|
||||||
<span
|
|
||||||
className={cn(
|
|
||||||
'relative inline-flex h-2.5 w-2.5 rounded-full',
|
|
||||||
isConnected ? 'bg-emerald-400' : 'bg-red-400'
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
{isConnected ? 'Conectado al flujo' : 'Sin conexión'}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="hidden items-center gap-2 rounded-full border border-indigo-400/20 bg-indigo-500/10 px-2.5 py-1 text-xs text-indigo-200 sm:inline-flex">
|
|
||||||
<Sparkles className="h-3.5 w-3.5" />
|
|
||||||
Flujo validado
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Right: Logout */}
|
||||||
<button
|
<button
|
||||||
onClick={onLogout}
|
onClick={onLogout}
|
||||||
className="inline-flex items-center gap-2 rounded-2xl border border-white/10 bg-white/5 px-4 py-2.5 text-sm font-medium text-zinc-200 transition hover:border-white/20 hover:bg-white/10 hover:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50"
|
className="group inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-medium text-[#4F758B] shadow-sm transition-all hover:border-rose-200 hover:bg-rose-50 hover:text-rose-600 focus:outline-none focus:ring-2 focus:ring-[#6CC24A]/30"
|
||||||
aria-label="Cerrar sesión"
|
aria-label="Cerrar sesión"
|
||||||
>
|
>
|
||||||
<LogOut className="h-4 w-4" />
|
<LogOut className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
|
||||||
<span className="hidden sm:inline">Cerrar sesión</span>
|
<span className="hidden sm:inline">Cerrar sesión</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+310
-570
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { motion } from 'motion/react';
|
import { motion } from 'motion/react';
|
||||||
import { Chrome, ShieldCheck, Sparkles } from 'lucide-react';
|
import { Loader2 } from 'lucide-react';
|
||||||
|
|
||||||
interface LoginScreenProps {
|
interface LoginScreenProps {
|
||||||
onLogin: () => void;
|
onLogin: () => void;
|
||||||
@@ -8,60 +8,101 @@ interface LoginScreenProps {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logoSrc = `${import.meta.env.BASE_URL}glm-logo.png`;
|
||||||
|
|
||||||
export const LoginScreen: React.FC<LoginScreenProps> = ({ onLogin, isLoading, error }) => {
|
export const LoginScreen: React.FC<LoginScreenProps> = ({ onLogin, isLoading, error }) => {
|
||||||
return (
|
return (
|
||||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-[#060816] px-4 text-zinc-100">
|
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-[#F4F7F5] px-4 py-12 select-none">
|
||||||
|
{/* Premium Tech Grid Background */}
|
||||||
|
<div className="absolute inset-0 premium-grid-bg opacity-75 pointer-events-none" />
|
||||||
|
|
||||||
|
{/* Dynamic Animated Mesh Gradients */}
|
||||||
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||||
<div className="absolute left-[-10%] top-[-15%] h-[34rem] w-[34rem] rounded-full bg-indigo-600/18 blur-3xl" />
|
<motion.div
|
||||||
<div className="absolute right-[-8%] top-[8%] h-[30rem] w-[30rem] rounded-full bg-cyan-400/12 blur-3xl" />
|
animate={{ x: [0, 45, -25, 0], y: [0, -60, 40, 0], scale: [1, 1.15, 0.95, 1] }}
|
||||||
<div className="absolute bottom-[-18%] left-[20%] h-[28rem] w-[28rem] rounded-full bg-fuchsia-500/10 blur-3xl" />
|
transition={{ duration: 22, repeat: Infinity, ease: 'easeInOut' }}
|
||||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.03)_1px,transparent_1px)] bg-[size:42px_42px] opacity-[0.06]" />
|
className="absolute left-[-8%] top-[-12%] h-[36rem] w-[36rem] rounded-full bg-[#EEF6E8]/70 blur-[90px]"
|
||||||
|
/>
|
||||||
|
<motion.div
|
||||||
|
animate={{ x: [0, -35, 45, 0], y: [0, 50, -40, 0], scale: [1, 0.95, 1.1, 1] }}
|
||||||
|
transition={{ duration: 26, repeat: Infinity, ease: 'easeInOut' }}
|
||||||
|
className="absolute right-[-6%] top-[8%] h-[32rem] w-[32rem] rounded-full bg-[#D6E8F4]/70 blur-[100px]"
|
||||||
|
/>
|
||||||
|
<motion.div
|
||||||
|
animate={{ x: [0, 30, -30, 0], y: [0, 40, -40, 0], scale: [1, 1.05, 0.95, 1] }}
|
||||||
|
transition={{ duration: 18, repeat: Infinity, ease: 'easeInOut' }}
|
||||||
|
className="absolute bottom-[-15%] left-[20%] h-[30rem] w-[30rem] rounded-full bg-white/70 blur-[90px]"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Login Card */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 18, scale: 0.98 }}
|
initial={{ opacity: 0, y: 32, scale: 0.97 }}
|
||||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
className="relative w-full max-w-xl rounded-[32px] border border-white/10 bg-white/5 p-8 shadow-[0_30px_80px_rgba(0,0,0,0.35)] backdrop-blur-xl"
|
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="relative w-full max-w-[400px] overflow-hidden rounded-[32px] border border-white/50 bg-white/75 px-10 py-12 shadow-[0_32px_96px_rgba(79,117,139,0.14)] backdrop-blur-2xl font-['Plus_Jakarta_Sans',sans-serif]"
|
||||||
>
|
>
|
||||||
<div className="mb-4 inline-flex items-center gap-2 rounded-full border border-indigo-400/25 bg-indigo-500/10 px-3 py-1 text-xs font-semibold uppercase tracking-[0.22em] text-indigo-200">
|
{/* Top gradient bar */}
|
||||||
<Sparkles className="h-3.5 w-3.5" />
|
<div className="absolute top-0 inset-x-0 h-[4px] bg-gradient-to-r from-[#6CC24A] via-[#5B7F95] to-[#4F758B]" />
|
||||||
Acceso corporativo
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 className="text-3xl font-semibold tracking-tight text-white sm:text-4xl">
|
{/* Centered content */}
|
||||||
Portal Brief CDC
|
<div className="flex flex-col items-center text-center">
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p className="mt-4 text-sm leading-7 text-zinc-300 sm:text-base">
|
{/* Logo */}
|
||||||
Inicia sesión con tu cuenta corporativa de Google para acceder al portal.
|
<div className="flex h-24 w-24 items-center justify-center overflow-hidden rounded-[24px] border border-slate-200/60 bg-white p-3 shadow-[0_8px_28px_rgba(79,117,139,0.12)]">
|
||||||
</p>
|
<img src={logoSrc} alt="GLM Logo" className="h-full w-full object-contain" />
|
||||||
|
|
||||||
<div className="mt-6 rounded-2xl border border-white/10 bg-black/20 p-4">
|
|
||||||
<div className="flex items-start gap-3">
|
|
||||||
<ShieldCheck className="mt-0.5 h-5 w-5 text-indigo-300" />
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-semibold text-white">Acceso restringido</p>
|
|
||||||
<p className="mt-1 text-sm leading-6 text-zinc-400">
|
|
||||||
Solo usuarios autorizados de la empresa podrán continuar.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Title — full gradient, no black */}
|
||||||
|
<h1 className="mt-8 text-[2rem] font-bold tracking-tight leading-tight">
|
||||||
|
<span className="bg-gradient-to-r from-[#4F758B] via-[#5B7F95] to-[#6B8FA3] bg-clip-text text-transparent">
|
||||||
|
Portal Brief CDC
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{/* Subtle tagline */}
|
||||||
|
<p className="mt-2.5 text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">
|
||||||
|
GomezLee Marketing
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Error */}
|
||||||
|
{error && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: -10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="mt-6 w-full rounded-xl border border-rose-100 bg-rose-50/50 px-4 py-3 text-xs leading-relaxed text-rose-600 flex items-start gap-2.5"
|
||||||
|
>
|
||||||
|
<div className="mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-rose-500 animate-pulse" />
|
||||||
|
<span>{error}</span>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Google Login Button */}
|
||||||
|
<button
|
||||||
|
onClick={onLogin}
|
||||||
|
disabled={isLoading}
|
||||||
|
className="shimmer-btn group mt-10 relative flex w-full items-center justify-center gap-3 rounded-2xl bg-gradient-to-r from-[#4F758B] to-[#5B7F95] px-6 py-4 text-sm font-semibold text-white shadow-[0_12px_28px_rgba(79,117,139,0.2)] transition-all duration-300 hover:from-[#456A7F] hover:to-[#4F758B] hover:shadow-[0_16px_36px_rgba(79,117,139,0.3)] active:scale-[0.99] disabled:pointer-events-none disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<Loader2 className="h-5 w-5 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<svg
|
||||||
|
className="h-5 w-5 shrink-0 transition-transform duration-300 group-hover:scale-110"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4" />
|
||||||
|
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853" />
|
||||||
|
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.06H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.94l2.85-2.22.81-.63z" fill="#FBBC05" />
|
||||||
|
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.06l3.66 2.84c.87-2.6 3.3-4.52 6.16-4.52z" fill="#EA4335" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
<span className="tracking-wide">
|
||||||
|
{isLoading ? 'Abriendo Google...' : 'Continuar con Google'}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
|
||||||
<div className="mt-4 rounded-2xl border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm text-red-200">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={onLogin}
|
|
||||||
disabled={isLoading}
|
|
||||||
className="mt-6 inline-flex w-full items-center justify-center gap-3 rounded-2xl bg-[linear-gradient(135deg,#6366f1_0%,#2563eb_50%,#06b6d4_100%)] px-5 py-4 text-sm font-semibold text-white shadow-[0_18px_40px_rgba(79,70,229,0.38)] transition hover:opacity-95 disabled:cursor-not-allowed disabled:opacity-60"
|
|
||||||
>
|
|
||||||
<Chrome className="h-4 w-4" />
|
|
||||||
{isLoading ? 'Abriendo Google...' : 'Continuar con Google'}
|
|
||||||
</button>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { motion } from 'motion/react';
|
import { motion } from 'motion/react';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { AlertCircle, Check, CheckCheck, Copy, ExternalLink, FileText, Music, ShieldCheck, X } from 'lucide-react';
|
import { AlertCircle, Check, CheckCheck, Copy, ExternalLink, FileText, Music, Pause, Play, ShieldCheck, X } from 'lucide-react';
|
||||||
import { Message, Attachment } from '../types';
|
import { Message, Attachment } from '../types';
|
||||||
import { cn } from '../lib/utils';
|
import { cn } from '../lib/utils';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
@@ -24,47 +24,48 @@ const formatDuration = (seconds: number) => {
|
|||||||
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
|
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAttachmentLabel = (attachment: Attachment) => {
|
||||||
|
if (attachment.type === 'image') return 'Imagen de referencia';
|
||||||
|
if (attachment.type === 'audio') return 'Nota de voz';
|
||||||
|
if (attachment.category === 'campaign') return 'Campaña / gráfico';
|
||||||
|
if (attachment.type === 'document') return 'Documento';
|
||||||
|
return 'Archivo adjunto';
|
||||||
|
};
|
||||||
|
|
||||||
const AttachmentPreview = ({ attachment }: { attachment: Attachment }) => {
|
const AttachmentPreview = ({ attachment }: { attachment: Attachment }) => {
|
||||||
|
const fileSizeKb = `${(attachment.file.size / 1024).toFixed(1)} KB`;
|
||||||
|
const label = getAttachmentLabel(attachment);
|
||||||
|
|
||||||
if (attachment.type === 'image') {
|
if (attachment.type === 'image') {
|
||||||
return (
|
return (
|
||||||
<div className="group relative max-w-[320px] overflow-hidden rounded-2xl border border-white/10 bg-black/20">
|
<div className="glm-message-attachment flex w-full max-w-[320px] items-center gap-3 rounded-2xl border border-[#D0D0D0]/70 bg-white/95 px-3 py-3 text-[#4A4A4A] shadow-[0_8px_22px_rgba(79,117,139,0.10)]">
|
||||||
<img
|
<div className="h-14 w-14 shrink-0 overflow-hidden rounded-xl border border-[#D0D0D0]/65 bg-[#F9FBFC]">
|
||||||
src={attachment.url}
|
<img
|
||||||
alt={attachment.file.name}
|
src={attachment.url}
|
||||||
className="h-full w-full object-cover transition duration-300 group-hover:scale-[1.02]"
|
alt={attachment.file.name}
|
||||||
/>
|
className="h-full w-full object-cover"
|
||||||
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/80 to-transparent px-3 py-2 text-[11px] font-medium text-white/90">
|
/>
|
||||||
<div className="truncate">{attachment.file.name}</div>
|
</div>
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
|
<p className="truncate text-sm font-semibold text-[#2E4052]">{attachment.file.name}</p>
|
||||||
|
<p className="truncate text-xs font-medium text-[#6B8FA3]">{label}</p>
|
||||||
|
<p className="mt-0.5 text-[11px] text-[#8EA1B3]">{fileSizeKb}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachment.type === 'audio') {
|
const Icon = attachment.type === 'audio' ? Music : FileText;
|
||||||
return (
|
|
||||||
<div className="flex w-full max-w-[420px] flex-col gap-3 rounded-2xl border border-white/10 bg-white/5 px-3 py-3">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="flex h-11 w-11 items-center justify-center rounded-xl bg-black/25">
|
|
||||||
<Music className="h-4 w-4 text-indigo-200" />
|
|
||||||
</div>
|
|
||||||
<div className="min-w-0 flex-1">
|
|
||||||
<p className="truncate text-sm font-medium text-white/90">{attachment.file.name}</p>
|
|
||||||
<p className="text-[11px] text-zinc-400">{(attachment.file.size / 1024).toFixed(1)} KB</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<audio controls src={attachment.url} className="h-9 w-full rounded-xl" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full max-w-[360px] items-center gap-3 rounded-2xl border border-white/10 bg-white/5 px-3 py-3">
|
<div className="glm-message-attachment flex w-full max-w-[320px] items-center gap-3 rounded-2xl border border-[#D0D0D0]/70 bg-white/95 px-3 py-3 text-[#4A4A4A] shadow-[0_8px_22px_rgba(79,117,139,0.10)]">
|
||||||
<div className="flex h-11 w-11 items-center justify-center rounded-xl bg-black/25">
|
<div className="flex h-14 w-14 shrink-0 items-center justify-center rounded-xl border border-[#D0D0D0]/60 bg-[#F7FAF8]">
|
||||||
<FileText className="h-4 w-4 text-indigo-200" />
|
<Icon className="h-5 w-5 text-[#4F758B]" />
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<p className="truncate text-sm font-medium text-white/90">{attachment.file.name}</p>
|
<p className="truncate text-sm font-semibold text-[#2E4052]">{attachment.file.name}</p>
|
||||||
<p className="text-[11px] text-zinc-400">{(attachment.file.size / 1024).toFixed(1)} KB</p>
|
<p className="truncate text-xs font-medium text-[#6B8FA3]">{label}</p>
|
||||||
|
<p className="mt-0.5 text-[11px] text-[#8EA1B3]">{fileSizeKb}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -118,7 +119,7 @@ const DriveLinkCard = ({ url, onClose }: { url: string; onClose: () => void }) =
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
className="inline-flex items-center gap-2 rounded-xl bg-white px-4 py-2.5 text-sm font-semibold text-slate-950 transition hover:bg-zinc-200"
|
className="inline-flex items-center gap-2 rounded-xl border border-white/10 bg-white px-4 py-2.5 text-sm font-semibold text-[#4F758B] transition hover:bg-[#F8FBF6]"
|
||||||
>
|
>
|
||||||
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
||||||
{copied ? 'Copiado' : 'Copiar'}
|
{copied ? 'Copiado' : 'Copiar'}
|
||||||
@@ -269,38 +270,35 @@ export const MessageBubble: React.FC<MessageBubbleProps> = ({ message }) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{message.audio && (
|
{message.audio && (
|
||||||
<div className="mb-4 rounded-2xl bg-black/20 p-3 pr-4">
|
<div className="glm-message-audio mb-4 rounded-2xl border border-[#D0D0D0]/70 bg-white/95 p-3 pr-4 shadow-[0_8px_22px_rgba(79,117,139,0.10)]">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={togglePlay}
|
onClick={togglePlay}
|
||||||
className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-white/15 transition hover:bg-white/25"
|
className="glm-message-audio-toggle flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-[#4F758B] text-white shadow-[0_8px_18px_rgba(79,117,139,0.24)] transition hover:bg-[#5B7F95]"
|
||||||
aria-label={isPlaying ? 'Pausar audio' : 'Reproducir audio'}
|
aria-label={isPlaying ? 'Pausar audio' : 'Reproducir audio'}
|
||||||
>
|
>
|
||||||
{isPlaying ? (
|
{isPlaying ? (
|
||||||
<div className="flex h-3.5 w-3.5 gap-1">
|
<Pause className="h-5 w-5" fill="currentColor" />
|
||||||
<div className="h-full w-1 rounded-sm bg-white" />
|
|
||||||
<div className="h-full w-1 rounded-sm bg-white" />
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="ml-0.5 h-0 w-0 border-b-[7px] border-l-[10px] border-t-[7px] border-b-transparent border-l-white border-t-transparent" />
|
<Play className="ml-0.5 h-5 w-5" fill="currentColor" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div className="mb-1.5 flex items-center justify-between gap-3">
|
<div className="mb-1.5 flex items-center justify-between gap-3">
|
||||||
<span className="text-xs font-semibold text-white/80">
|
<span className="text-xs font-semibold text-[#4F758B]">
|
||||||
{isPlaying ? 'Reproduciendo' : 'Nota de voz'}
|
{isPlaying ? 'Reproduciendo' : 'Nota de voz'}
|
||||||
</span>
|
</span>
|
||||||
<span className="shrink-0 text-xs font-mono opacity-80">
|
<span className="shrink-0 text-xs font-mono text-[#6B8FA3]">
|
||||||
{formatDuration(audioCurrentTime)} / {formatDuration(effectiveAudioDuration)}
|
{formatDuration(audioCurrentTime)} / {formatDuration(effectiveAudioDuration)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative h-5">
|
<div className="relative h-5">
|
||||||
<div className="absolute left-0 right-0 top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-white/15" />
|
<div className="absolute left-0 right-0 top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-[#6CC24A]/20" />
|
||||||
<div
|
<div
|
||||||
className="absolute left-0 top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-white/70"
|
className="absolute left-0 top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-[#6CC24A]/70"
|
||||||
style={{ width: `${audioProgress}%` }}
|
style={{ width: `${audioProgress}%` }}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -32,25 +32,25 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, w
|
|||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm"
|
className="fixed inset-0 z-50 bg-[#2C3E45]/35 backdrop-blur-sm"
|
||||||
/>
|
/>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
animate={{ opacity: 1, scale: 1, y: 0 }}
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
exit={{ opacity: 0, scale: 0.95, y: 20 }}
|
exit={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-50 w-full max-w-md bg-zinc-900 border border-white/10 rounded-2xl shadow-2xl overflow-hidden"
|
className="fixed left-1/2 top-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-3xl border border-[#D0D0D0]/70 bg-white shadow-2xl"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between p-6 border-b border-white/5">
|
<div className="flex items-center justify-between border-b border-[#D0D0D0]/70 p-6">
|
||||||
<h2 className="text-xl font-semibold text-white">Configuración de conexión</h2>
|
<h2 className="text-xl font-semibold text-[#4F758B]">Configuración de conexión</h2>
|
||||||
<button onClick={onClose} className="p-2 rounded-full hover:bg-white/5 text-zinc-400 hover:text-white transition-colors">
|
<button onClick={onClose} className="rounded-full p-2 text-[#6B8FA3] transition-colors hover:bg-[#EEF6E8] hover:text-[#4F758B]">
|
||||||
<X className="w-5 h-5" />
|
<X className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-6 space-y-6">
|
<div className="space-y-6 p-6">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium text-zinc-300 flex items-center gap-2">
|
<label className="flex items-center gap-2 text-sm font-medium text-[#4F758B]">
|
||||||
<LinkIcon className="w-4 h-4 text-indigo-400" />
|
<LinkIcon className="h-4 w-4 text-[#6CC24A]" />
|
||||||
Webhook URL
|
Webhook URL
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -58,26 +58,26 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, w
|
|||||||
value={url}
|
value={url}
|
||||||
onChange={(e) => setUrl(e.target.value)}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
placeholder="https://tu-endpoint.com/webhook"
|
placeholder="https://tu-endpoint.com/webhook"
|
||||||
className="w-full bg-black/50 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-zinc-600 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 transition-all font-mono text-sm"
|
className="w-full rounded-xl border border-[#D0D0D0]/80 bg-[#F9FBFC] px-4 py-3 font-mono text-sm text-[#4A4A4A] placeholder:text-[#9AA8B0] transition-all focus:border-[#6CC24A] focus:outline-none focus:ring-2 focus:ring-[#6CC24A]/25"
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-zinc-500 mt-2">
|
<p className="mt-2 text-xs text-[#6B8FA3]">
|
||||||
Endpoint donde se enviarán la nota de voz, imágenes, documentos y enlaces mediante una solicitud POST.
|
Endpoint donde se enviarán la nota de voz, imágenes, documentos y enlaces mediante una solicitud POST.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-6 border-t border-white/5 bg-black/20 flex justify-end gap-3">
|
<div className="flex justify-end gap-3 border-t border-[#D0D0D0]/70 bg-[#F9FBFC] p-6">
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="px-5 py-2.5 rounded-xl text-sm font-medium text-zinc-300 hover:text-white hover:bg-white/5 transition-colors"
|
className="rounded-xl px-5 py-2.5 text-sm font-medium text-[#6B8FA3] transition-colors hover:bg-white hover:text-[#4F758B]"
|
||||||
>
|
>
|
||||||
Cancelar
|
Cancelar
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
className="px-5 py-2.5 rounded-xl text-sm font-medium bg-indigo-600 text-white hover:bg-indigo-500 transition-colors flex items-center gap-2 shadow-lg shadow-indigo-500/20"
|
className="flex items-center gap-2 rounded-xl bg-[#4F758B] px-5 py-2.5 text-sm font-medium text-white shadow-lg shadow-[#4F758B]/20 transition-colors hover:bg-[#456A7F]"
|
||||||
>
|
>
|
||||||
<Save className="w-4 h-4" />
|
<Save className="h-4 w-4" />
|
||||||
Guardar
|
Guardar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+275
-54
@@ -2,12 +2,22 @@
|
|||||||
@plugin "@tailwindcss/typography";
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
color-scheme: dark;
|
color-scheme: light;
|
||||||
|
--glm-blue: #4F758B;
|
||||||
|
--glm-blue-mid: #5B7F95;
|
||||||
|
--glm-steel: #6B8FA3;
|
||||||
|
--glm-green: #6CC24A;
|
||||||
|
--glm-green-soft: #EEF6E8;
|
||||||
|
--glm-blue-soft: #D6E8F4;
|
||||||
|
--glm-text: #4A4A4A;
|
||||||
|
--glm-border: #D0D0D0;
|
||||||
|
--glm-page: #F7FAF8;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
background: var(--glm-page);
|
||||||
}
|
}
|
||||||
|
|
||||||
body,
|
body,
|
||||||
@@ -17,11 +27,156 @@ body,
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background: #060816;
|
background: var(--glm-page);
|
||||||
font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
font-family: Arial, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
font-family: Arial, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GLM light skin: keeps all behavior intact and only remaps the previous dark UI colors. */
|
||||||
|
.glm-app .border-white\/10,
|
||||||
|
.glm-app .border-white\/5,
|
||||||
|
.glm-app .border-indigo-400\/20,
|
||||||
|
.glm-app .border-indigo-400\/25,
|
||||||
|
.glm-app .border-indigo-400\/30,
|
||||||
|
.glm-app .border-indigo-300\/25 {
|
||||||
|
border-color: rgba(208, 208, 208, 0.72) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .bg-black\/10,
|
||||||
|
.glm-app .bg-black\/20,
|
||||||
|
.glm-app .bg-black\/25,
|
||||||
|
.glm-app .bg-white\/5,
|
||||||
|
.glm-app .bg-white\/10,
|
||||||
|
.glm-app .bg-white\/\[0\.03\],
|
||||||
|
.glm-app .bg-white\/\[0\.04\] {
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .bg-black\/30,
|
||||||
|
.glm-app .bg-black\/35,
|
||||||
|
.glm-app .bg-black\/40,
|
||||||
|
.glm-app .bg-black\/50 {
|
||||||
|
background-color: #F9FBFC !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .text-zinc-100,
|
||||||
|
.glm-app .text-zinc-200,
|
||||||
|
.glm-app .text-zinc-300 {
|
||||||
|
color: var(--glm-text) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .text-zinc-400,
|
||||||
|
.glm-app .text-zinc-500,
|
||||||
|
.glm-app .text-zinc-600 {
|
||||||
|
color: var(--glm-steel) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .text-white,
|
||||||
|
.glm-app .text-white\/80,
|
||||||
|
.glm-app .text-white\/90,
|
||||||
|
.glm-app .text-indigo-100,
|
||||||
|
.glm-app .text-indigo-100\/80,
|
||||||
|
.glm-app .text-indigo-200 {
|
||||||
|
color: var(--glm-blue) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .text-indigo-300,
|
||||||
|
.glm-app .text-indigo-400,
|
||||||
|
.glm-app .text-emerald-300,
|
||||||
|
.glm-app .text-emerald-400 {
|
||||||
|
color: var(--glm-green) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .text-amber-300 {
|
||||||
|
color: #FF8C00 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,#6366f1"],
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,rgba(79,70,229"],
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,#6366f1_0%,#2563eb_50%,#06b6d4"],
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,#6366f1_0%,#2563eb_100%"] {
|
||||||
|
background: var(--glm-blue) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
box-shadow: 0 16px 34px rgba(79, 117, 139, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,#6366f1"] *,
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,rgba(79,70,229"] *,
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,#6366f1_0%,#2563eb_50%,#06b6d4"] *,
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,#6366f1_0%,#2563eb_100%"] * {
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="bg-[linear-gradient(90deg,#6366f1"] {
|
||||||
|
background: linear-gradient(90deg, var(--glm-green) 0%, var(--glm-blue) 100%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="bg-[linear-gradient(180deg,rgba(99,102,241"],
|
||||||
|
.glm-app [class*="bg-[linear-gradient(145deg,rgba(99,102,241"] {
|
||||||
|
background: #F8FBF6 !important;
|
||||||
|
border-color: rgba(108, 194, 74, 0.38) !important;
|
||||||
|
box-shadow: 0 14px 34px rgba(108, 194, 74, 0.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="bg-indigo-500/10"],
|
||||||
|
.glm-app .bg-indigo-500\/10,
|
||||||
|
.glm-app .bg-emerald-500\/10,
|
||||||
|
.glm-app .bg-emerald-500\/15 {
|
||||||
|
background-color: var(--glm-green-soft) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .bg-indigo-300,
|
||||||
|
.glm-app .bg-indigo-400,
|
||||||
|
.glm-app .bg-emerald-400 {
|
||||||
|
background-color: var(--glm-green) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .bg-zinc-600 {
|
||||||
|
background-color: var(--glm-border) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="min-h-[178px]"] {
|
||||||
|
min-height: 132px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="shadow-[0_28px_80px"],
|
||||||
|
.glm-app [class*="shadow-[0_24px_60px"],
|
||||||
|
.glm-app [class*="shadow-[0_30px_80px"],
|
||||||
|
.glm-app [class*="shadow-[0_16px_40px"] {
|
||||||
|
box-shadow: 0 18px 50px rgba(79, 117, 139, 0.11) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .prose-invert {
|
||||||
|
--tw-prose-body: var(--glm-text);
|
||||||
|
--tw-prose-headings: var(--glm-blue);
|
||||||
|
--tw-prose-lead: var(--glm-text);
|
||||||
|
--tw-prose-links: var(--glm-blue);
|
||||||
|
--tw-prose-bold: var(--glm-blue);
|
||||||
|
--tw-prose-counters: var(--glm-steel);
|
||||||
|
--tw-prose-bullets: var(--glm-green);
|
||||||
|
--tw-prose-hr: var(--glm-border);
|
||||||
|
--tw-prose-quotes: var(--glm-blue);
|
||||||
|
--tw-prose-quote-borders: var(--glm-green);
|
||||||
|
--tw-prose-captions: var(--glm-steel);
|
||||||
|
--tw-prose-code: var(--glm-blue);
|
||||||
|
--tw-prose-pre-code: var(--glm-text);
|
||||||
|
--tw-prose-pre-bg: #F9FBFC;
|
||||||
|
--tw-prose-th-borders: var(--glm-border);
|
||||||
|
--tw-prose-td-borders: var(--glm-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .prose pre {
|
||||||
|
border: 1px solid rgba(208, 208, 208, 0.7) !important;
|
||||||
|
background: #F9FBFC !important;
|
||||||
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.scrollbar-hide::-webkit-scrollbar {
|
.scrollbar-hide::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -42,59 +197,17 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.scrollbar-thin::-webkit-scrollbar-thumb {
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
background: rgba(255, 255, 255, 0.12);
|
background: rgba(79, 117, 139, 0.22);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
||||||
background: rgba(255, 255, 255, 0.22);
|
background: rgba(79, 117, 139, 0.36);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer components {
|
|
||||||
.audio-preview-range {
|
|
||||||
height: 20px;
|
|
||||||
appearance: none;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-preview-range::-webkit-slider-runnable-track {
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: rgba(255, 255, 255, 0.16);
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-preview-range::-webkit-slider-thumb {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin-top: -5px;
|
|
||||||
border: 3px solid #ffffff;
|
|
||||||
border-radius: 999px;
|
|
||||||
appearance: none;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
background: #67e8f9;
|
|
||||||
box-shadow: 0 0 0 5px rgba(103, 232, 249, 0.16), 0 8px 18px rgba(0, 0, 0, 0.32);
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-preview-range::-moz-range-track {
|
|
||||||
height: 6px;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: rgba(255, 255, 255, 0.16);
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-preview-range::-moz-range-thumb {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
border: 3px solid #ffffff;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: #67e8f9;
|
|
||||||
box-shadow: 0 0 0 5px rgba(103, 232, 249, 0.16), 0 8px 18px rgba(0, 0, 0, 0.32);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
|
.audio-preview-range,
|
||||||
.message-audio-range {
|
.message-audio-range {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
@@ -102,12 +215,14 @@ body {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audio-preview-range::-webkit-slider-runnable-track,
|
||||||
.message-audio-range::-webkit-slider-runnable-track {
|
.message-audio-range::-webkit-slider-runnable-track {
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: transparent;
|
background: rgba(108, 194, 74, 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audio-preview-range::-webkit-slider-thumb,
|
||||||
.message-audio-range::-webkit-slider-thumb {
|
.message-audio-range::-webkit-slider-thumb {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
@@ -116,23 +231,129 @@ body {
|
|||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
background: #67e8f9;
|
background: var(--glm-green);
|
||||||
box-shadow: 0 0 0 5px rgba(103, 232, 249, 0.16), 0 8px 18px rgba(0, 0, 0, 0.32);
|
box-shadow: 0 0 0 5px rgba(108, 194, 74, 0.16), 0 8px 18px rgba(79, 117, 139, 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audio-preview-range::-moz-range-track,
|
||||||
.message-audio-range::-moz-range-track {
|
.message-audio-range::-moz-range-track {
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: transparent;
|
background: rgba(108, 194, 74, 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audio-preview-range::-moz-range-thumb,
|
||||||
.message-audio-range::-moz-range-thumb {
|
.message-audio-range::-moz-range-thumb {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border: 3px solid #ffffff;
|
border: 3px solid #ffffff;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: #67e8f9;
|
background: var(--glm-green);
|
||||||
box-shadow: 0 0 0 5px rgba(103, 232, 249, 0.16), 0 8px 18px rgba(0, 0, 0, 0.32);
|
box-shadow: 0 0 0 5px rgba(108, 194, 74, 0.16), 0 8px 18px rgba(79, 117, 139, 0.18);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.glm-app [class*="bg-[linear-gradient(135deg,rgba(99,102,241"] {
|
||||||
|
background: var(--glm-green-soft) !important;
|
||||||
|
border-color: rgba(108, 194, 74, 0.36) !important;
|
||||||
|
box-shadow: 0 16px 38px rgba(108, 194, 74, 0.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Redesign Premium Utilities */
|
||||||
|
.premium-grid-bg {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, rgba(108, 194, 74, 0.06) 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, rgba(108, 194, 74, 0.06) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
mask-image: radial-gradient(ellipse at center, black 40%, transparent 80%);
|
||||||
|
-webkit-mask-image: radial-gradient(ellipse at center, black 40%, transparent 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shimmer-btn {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shimmer-btn::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(255, 255, 255, 0) 0%,
|
||||||
|
rgba(255, 255, 255, 0.22) 30%,
|
||||||
|
rgba(255, 255, 255, 0.35) 50%,
|
||||||
|
rgba(255, 255, 255, 0.22) 70%,
|
||||||
|
rgba(255, 255, 255, 0) 100%
|
||||||
|
);
|
||||||
|
animation: shimmer 3s infinite ease-in-out;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep the audio preview play/pause glyph visible after the GLM light-skin color remap. */
|
||||||
|
.glm-app .glm-audio-preview-toggle svg {
|
||||||
|
color: #ffffff !important;
|
||||||
|
stroke: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-audio-preview-toggle svg.fill-current {
|
||||||
|
fill: #ffffff !important;
|
||||||
|
}
|
||||||
|
/* Keep the final review submit button readable against the GLM blue background. */
|
||||||
|
.glm-app .glm-submit-final,
|
||||||
|
.glm-app .glm-submit-final * {
|
||||||
|
color: #ffffff !important;
|
||||||
|
stroke: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-submit-final svg.fill-current {
|
||||||
|
fill: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Response portal attachment polish: keep uploaded files compact and readable inside the GLM message bubble. */
|
||||||
|
.glm-app .glm-message-attachment,
|
||||||
|
.glm-app .glm-message-attachment * {
|
||||||
|
color: #4A4A4A !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-message-attachment p:first-of-type {
|
||||||
|
color: #2E4052 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-message-attachment p:not(:first-of-type) {
|
||||||
|
color: #6B8FA3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-message-attachment svg {
|
||||||
|
color: #4F758B !important;
|
||||||
|
stroke: #4F758B !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-message-audio span:first-of-type {
|
||||||
|
color: #4F758B !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-message-audio span:last-of-type {
|
||||||
|
color: #6B8FA3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glm-app .glm-message-audio-toggle,
|
||||||
|
.glm-app .glm-message-audio-toggle * {
|
||||||
|
color: #ffffff !important;
|
||||||
|
fill: #ffffff !important;
|
||||||
|
stroke: #ffffff !important;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user