style: reskin NovaSpark en las 7 apps

Del look editorial (verde #1B4332, esquinas a 0, botones en mayusculas)
al sistema NovaSpark: primario azul #2563EB, detalle naranja #F97316,
fondo #F8FAFC con tarjetas blancas rounded-xl + shadow-sm, chips
rounded-full semanticos, focus ring azul, transiciones 100-200ms.
Incluye headers de tabla en los PDFs (cotizador y estado de cuenta).
This commit is contained in:
2026-09-03 02:35:34 +00:00
parent 89fcd1c579
commit 599dce2629
78 changed files with 842 additions and 828 deletions

View File

@@ -5,9 +5,11 @@ import { ConfiguracionCuenta } from './components/ConfiguracionCuenta'
export default function App() {
return (
<div className="flex min-h-screen flex-col">
<header className="px-6 pt-20 pb-16 sm:px-12 lg:px-24">
<p className="text-xs font-bold tracking-widest text-accent uppercase">FRASA Desarrollos</p>
<h1 className="mt-4 text-4xl font-light text-neutral-900 sm:text-5xl">
<header className="border-b border-[#E5E7EB] bg-white px-6 pt-20 pb-16 sm:px-12 lg:px-24">
<p className="text-xs font-semibold tracking-wider text-accent uppercase">
FRASA Desarrollos <span aria-hidden="true" className="text-[#F97316]">●</span>
</p>
<h1 className="mt-4 text-4xl font-light text-[#111827] sm:text-5xl">
Ecosistema comercial
</h1>
</header>
@@ -25,7 +27,7 @@ export default function App() {
</main>
<footer className="px-6 pt-24 pb-10 sm:px-12 lg:px-24">
<p className="text-xs text-neutral-400">Consult (AS) Technology</p>
<p className="text-xs text-[#64748B]">Consult (AS) Technology</p>
</footer>
</div>
)

View File

@@ -2,9 +2,9 @@ import { useEffect, useState, type FormEvent } from 'react'
import { ErrorLogin, getSesion, login, logout, type UsuarioSesion } from '../services/auth'
import { getMe, getUsuariosMonday, guardarVinculoMonday, type UsuarioMonday } from '../services/api'
const labelEstilo = 'block text-xs font-bold tracking-widest text-neutral-500 uppercase'
const labelEstilo = 'block text-xs font-medium text-[#4B5563]'
const inputEstilo =
'mt-2 w-full border border-neutral-200 bg-white px-3 py-2 text-sm text-neutral-900 focus:border-neutral-900'
'mt-2 w-full rounded-lg border border-[#D1D5DB] bg-white px-3 py-2.5 text-sm text-[#111827] transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20'
/**
* Sección "Configuración de cuenta": login inline y, con sesión, el vínculo
@@ -95,14 +95,17 @@ export function ConfiguracionCuenta() {
perfil?.mondayUserId != null ? (usuarios?.find((u) => u.id === perfil.mondayUserId) ?? null) : null
return (
<section aria-labelledby="titulo-cuenta" className="mt-24 border-t border-neutral-200 pt-16">
<h2 id="titulo-cuenta" className="text-xs font-bold tracking-widest text-accent uppercase">
<section aria-labelledby="titulo-cuenta" className="mt-24 border-t border-[#E5E7EB] pt-16">
<h2 id="titulo-cuenta" className="text-xs font-semibold uppercase tracking-wider text-[#64748B]">
Configuración de cuenta
</h2>
{!conSesion ? (
<form onSubmit={(e) => void entrar(e)} className="mt-8 max-w-sm">
<p className="text-sm leading-relaxed text-neutral-500">
<form
onSubmit={(e) => void entrar(e)}
className="mt-8 max-w-sm rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm"
>
<p className="text-sm leading-relaxed text-[#64748B]">
Inicia sesión para vincular tu usuario de Monday.
</p>
<div className="mt-6">
@@ -134,55 +137,55 @@ export function ConfiguracionCuenta() {
/>
</div>
{errorLogin && (
<p role="alert" className="mt-4 text-xs text-red-700">
<p role="alert" className="mt-4 text-sm text-red-600">
{errorLogin}
</p>
)}
<button
type="submit"
disabled={entrando}
className="mt-6 bg-accent px-5 py-2.5 text-xs font-bold tracking-widest text-white uppercase transition-colors duration-150 hover:bg-neutral-900 disabled:opacity-50"
className="mt-6 rounded-lg bg-accent px-5 py-2.5 text-sm font-medium text-white shadow-sm transition-all duration-100 ease-out hover:bg-accent-hover disabled:opacity-50"
>
{entrando ? 'Entrando…' : 'Entrar'}
</button>
</form>
) : (
<div className="mt-8 max-w-md">
{cargandoPerfil && <p className="text-sm text-neutral-500">Cargando tu perfil…</p>}
<div className="mt-8 max-w-md rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm">
{cargandoPerfil && <p className="text-sm text-[#64748B]">Cargando tu perfil…</p>}
{perfil && (
<>
<p className="text-sm text-neutral-900">
<p className="text-sm text-[#111827]">
Sesión: <span className="font-medium">{perfil.nombre}</span>
</p>
<p className="mt-2 text-sm text-neutral-500">
<p className="mt-2 text-sm text-[#64748B]">
Vínculo Monday actual:{' '}
{perfil.mondayUserId === null ? (
<span className="text-neutral-400">sin vincular</span>
<span className="text-[#94A3B8]">sin vincular</span>
) : vinculado ? (
<span className="text-neutral-900">
<span className="text-[#111827]">
{vinculado.nombre} ({vinculado.email})
</span>
) : (
<span className="text-neutral-900">ID {perfil.mondayUserId}</span>
<span className="text-[#111827]">ID {perfil.mondayUserId}</span>
)}
</p>
{errorUsuarios ? (
<div className="mt-6">
<p role="alert" className="text-xs text-red-700">
<p role="alert" className="text-sm text-red-600">
{errorUsuarios}
</p>
<button
type="button"
onClick={cargarUsuarios}
className="mt-3 border border-neutral-900 bg-transparent px-4 py-2 text-xs font-bold tracking-widest text-neutral-900 uppercase transition-colors duration-150 hover:bg-neutral-900 hover:text-white"
className="mt-3 rounded-lg border border-[#D1D5DB] bg-white px-4 py-2.5 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
>
Reintentar
</button>
</div>
) : usuarios === null ? (
<p className="mt-6 text-sm text-neutral-500">Cargando usuarios de Monday…</p>
<p className="mt-6 text-sm text-[#64748B]">Cargando usuarios de Monday…</p>
) : (
<div className="mt-6">
<label htmlFor="cuenta-monday" className={labelEstilo}>
@@ -206,7 +209,7 @@ export function ConfiguracionCuenta() {
type="button"
disabled={guardando}
onClick={() => void guardar(seleccion === '' ? null : Number(seleccion))}
className="bg-accent px-5 py-2.5 text-xs font-bold tracking-widest text-white uppercase transition-colors duration-150 hover:bg-neutral-900 disabled:opacity-50"
className="rounded-lg bg-accent px-5 py-2.5 text-sm font-medium text-white shadow-sm transition-all duration-100 ease-out hover:bg-accent-hover disabled:opacity-50"
>
{guardando ? 'Guardando…' : 'Guardar'}
</button>
@@ -215,7 +218,7 @@ export function ConfiguracionCuenta() {
type="button"
disabled={guardando}
onClick={() => void guardar(null)}
className="border border-red-300 bg-white px-5 py-2.5 text-xs font-bold tracking-widest text-red-700 uppercase transition-colors duration-150 hover:bg-red-50 disabled:opacity-50"
className="rounded-lg border border-red-300 bg-white px-5 py-2.5 text-sm font-medium text-red-600 transition-all duration-100 ease-out hover:bg-red-50 disabled:opacity-50"
>
Desvincular
</button>
@@ -225,12 +228,12 @@ export function ConfiguracionCuenta() {
)}
{aviso && (
<p role="status" className="mt-4 text-xs font-bold tracking-widest text-accent uppercase">
<p role="status" className="mt-4 text-sm font-medium text-green-600">
{aviso}
</p>
)}
{errorGuardar && (
<p role="alert" className="mt-4 text-xs text-red-700">
<p role="alert" className="mt-4 text-sm text-red-600">
{errorGuardar}
</p>
)}
@@ -240,7 +243,7 @@ export function ConfiguracionCuenta() {
<button
type="button"
onClick={cerrarSesion}
className="mt-8 border border-neutral-900 bg-transparent px-4 py-2 text-xs font-bold tracking-widest text-neutral-900 uppercase transition-colors duration-150 hover:bg-neutral-900 hover:text-white"
className="mt-8 rounded-lg border border-[#D1D5DB] bg-white px-4 py-2.5 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
>
Cerrar sesión
</button>

View File

@@ -10,11 +10,11 @@ export function TarjetaModulo({ modulo }: Props) {
<li>
<a
href={modulo.url}
className="group flex h-full flex-col border border-neutral-200 bg-white p-8 transition-colors duration-150 hover:border-neutral-900"
className="group flex h-full flex-col rounded-xl border border-[#E5E7EB] bg-white p-8 shadow-sm transition-all duration-200 ease-in-out hover:shadow-md"
>
<h2 className="text-2xl font-light text-neutral-900">{modulo.nombre}</h2>
<p className="mt-3 text-sm leading-relaxed text-neutral-500">{modulo.descripcion}</p>
<span className="mt-auto pt-8 text-xs font-bold tracking-widest text-accent uppercase">
<h2 className="text-2xl font-light text-[#111827]">{modulo.nombre}</h2>
<p className="mt-3 text-sm leading-relaxed text-[#64748B]">{modulo.descripcion}</p>
<span className="mt-auto pt-8 text-sm font-medium text-accent transition-colors duration-100 ease-out group-hover:text-accent-hover">
Entrar <span aria-hidden="true">&rarr;</span>
</span>
</a>

View File

@@ -2,26 +2,18 @@
@theme {
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--color-accent: #1B4332;
--color-accent-hover: #132f23;
--radius-xs: 0;
--radius-sm: 0;
--radius-md: 0;
--radius-lg: 0;
--radius-xl: 0;
--radius-2xl: 0;
--radius-3xl: 0;
--radius-4xl: 0;
--color-accent: #2563EB;
--color-accent-hover: #1D4ED8;
}
@layer base {
body {
@apply bg-white text-neutral-900 antialiased;
@apply bg-[#F8FAFC] text-[#111827] antialiased;
}
/* Foco visible accesible: outline en color de acento */
/* Foco visible accesible: anillo azul en elementos interactivos */
:focus-visible {
outline: 2px solid #1B4332;
outline-offset: 2px;
outline: none;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
}
}