Files
tvone/app/(page)/dashboard/page.tsx
T
2026-04-18 13:21:13 +01:00

338 lines
14 KiB
TypeScript

import React from 'react';
import {
LayoutDashboard, Newspaper, Users, BarChart3,
Settings, HelpCircle, TrendingUp, Eye, Clock,
AlertCircle, ChevronRight, Edit3, Trash2, ExternalLink
} from 'lucide-react';
import Image from 'next/image';
const DashboardMain = () => {
return (
<div className="flex h-screen bg-[#F1F5F9] text-slate-900 font-sans">
{/* Sidebar Lateral - Consistente com a página de criação */}
<aside className="w-64 backdrop-blur-xl bg-white/80 border-r border-slate-200 p-6 flex flex-col">
<div className="flex items-center gap-2 mb-10 px-2">
<div className="w-10 h-10 bg-white rounded-lg flex items-center justify-center font-bold italic">
<Image src="/logo.png" alt="TVone" width={50} height={50} />
</div>
<span className="font-bold text-sm tracking-tight leading-tight uppercase">
TVone<br/><span className="text-blue-600 text-[10px]">de Notícias</span>
</span>
</div>
<nav className="flex-1 space-y-1">
<NavItem icon={<LayoutDashboard size={18}/>} label="Painel Principal" active />
<NavItem icon={<Newspaper size={18}/>} label="Meus Artigos" />
<NavItem icon={<Users size={18}/>} label="Equipa" />
<NavItem icon={<BarChart3 size={18}/>} label="Análises" />
<NavItem icon={<Settings size={18}/>} label="Definições" />
<NavItem icon={<HelpCircle size={18}/>} label="Ajuda" />
</nav>
<div className="mt-auto pt-6 border-t border-slate-200">
<div className="bg-blue-50 p-4 rounded-2xl">
<p className="text-[10px] font-bold text-blue-600 uppercase mb-1">Dica do Dia</p>
<p className="text-[11px] text-blue-800 leading-relaxed">
Artigos com mais de 3 imagens têm 40% mais retenção.
</p>
</div>
</div>
{/* Container do Fluxo de Atividade */}
<div className="mt-auto pt-6 border-t border-slate-200">
<h4 className="text-[10px] font-bold uppercase text-slate-400 mb-5 px-2 tracking-[0.15em]">
Fluxo de Atividade
</h4>
<div className="space-y-5 px-2">
<ActivityItem
name="James Wilson"
action="atualizou"
target="'Volatilidade do Mercado'"
time="Agora mesmo"
avatar="https://ui-avatars.com/api/?name=James+Wilson&background=E0F2FE&color=0369A1"
/>
<ActivityItem
name="Sarah Johnson"
action="criou"
target="'Financiamento de Startups'"
time="Há 12 min"
avatar="https://ui-avatars.com/api/?name=Sarah+Johnson&background=FEE2E2&color=B91C1C"
/>
<ActivityItem
name="Sarah Johnson"
action="criou"
target="'Tech Mercenary' em recentes"
time="Há 45 min"
avatar="https://ui-avatars.com/api/?name=Sarah+Johnson&background=FEE2E2&color=B91C1C"
/>
<ActivityItem
name="James Wilson"
action="atualizou"
target="'Volatilidade do Mercado'"
time="Há 1h"
avatar="https://ui-avatars.com/api/?name=James+Wilson&background=E0F2FE&color=0369A1"
/>
</div>
</div>
</aside>
{/* Main Content Area */}
<main className="flex-1 overflow-y-auto">
{/* Header Superior */}
{/* Header Superior - Secção do Utilizador Atualizada */}
<header className="h-16 border-b border-slate-200 bg-white/50 backdrop-blur-md sticky top-0 z-10 px-8 flex items-center justify-between">
<div className="w-1/3">
<input
type="text"
placeholder="Pesquisar artigos, autores..."
className="w-full bg-slate-100 border-none rounded-full px-4 py-1.5 text-sm focus:ring-2 focus:ring-blue-500/20 outline-none transition-all"
/>
</div>
<div className="flex items-center gap-5">
{/* Notificações (Opcional, mas completa o look) */}
<button className="relative p-2 text-slate-400 hover:text-blue-600 transition-colors">
<div className="absolute top-2 right-2.5 w-2 h-2 bg-red-500 border-2 border-white rounded-full"></div>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>
</button>
{/* Menu do Utilizador */}
<div className="flex items-center gap-3 pl-4 border-l border-slate-200 group cursor-pointer">
<div className="text-right hidden sm:block">
<p className="text-[11px] font-bold text-slate-900 leading-tight">James Wilson</p>
<p className="text-[10px] text-emerald-600 font-medium">Online</p>
</div>
<div className="relative">
{/* Container da Imagem com Efeito de Anel */}
<div className="w-9 h-9 rounded-full border-2 border-white shadow-sm overflow-hidden ring-1 ring-slate-200 group-hover:ring-blue-400 transition-all">
<img
src="https://ui-avatars.com/api/?name=James+Wilson&background=0D8ABC&color=fff"
alt="Avatar do utilizador"
className="w-full h-full object-cover"
/>
</div>
{/* Indicador de Status (Mobile) */}
<div className="absolute bottom-0 right-0 w-2.5 h-2.5 bg-emerald-500 border-2 border-white rounded-full"></div>
</div>
{/* Seta para indicar menu (Chevron) */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="14" height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
className="text-slate-400 group-hover:text-slate-600 transition-transform group-hover:translate-y-0.5"
>
<path d="m6 9 6 6 6-6"/>
</svg>
</div>
</div>
</header>
<div className="p-8 space-y-8">
{/* Métricas Principais (Grid de 4 colunas) */}
<div className="grid grid-cols-4 gap-6">
<StatCard
label="Artigos Publicados"
value="14,352"
trend="+12% este mês"
icon={<Newspaper size={20} className="text-blue-600"/>}
/>
<StatCard
label="Visualizações Totais"
value="2.1M"
trend="+5.4% vs ontem"
icon={<TrendingUp size={20} className="text-emerald-600"/>}
/>
<StatCard
label="Tempo Médio"
value="4m 32s"
trend="-2s média"
icon={<Clock size={20} className="text-orange-600"/>}
/>
<StatCard
label="Alertas Ativos"
value="3"
trend="Urgente"
icon={<AlertCircle size={20} className="text-red-600"/>}
isAlert
/>
</div>
<div className="grid grid-cols-3 gap-8">
{/* Tabela de Artigos Recentes (Coluna Dupla) */}
<div className="col-span-2 bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden">
<div className="p-6 border-b border-slate-100 flex justify-between items-center">
<h3 className="font-bold text-slate-800 text-sm uppercase tracking-wider">Artigos Recentes</h3>
<button className="text-blue-600 text-xs font-bold flex items-center gap-1 hover:underline">
Ver Todos <ChevronRight size={14}/>
</button>
</div>
<table className="w-full text-left border-collapse">
<thead className="bg-slate-50 text-[10px] uppercase font-bold text-slate-400">
<tr>
<th className="px-6 py-3">Título</th>
<th className="px-6 py-3">Estado</th>
<th className="px-6 py-3">Autor</th>
<th className="px-6 py-3">Visualizações</th>
<th className="px-6 py-3">Ações</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-50">
<TableRow
title="Volatilidade do Mercado: Impactos na Economia"
status="Publicado"
author="James Wilson"
views="1.2M"
/>
<TableRow
title="O Futuro da Inteligência Artificial em 2026"
status="Rascunho"
author="Sarah Johnson"
views="--"
/>
<TableRow
title="Novas Políticas de Sustentabilidade na UE"
status="Agendado"
author="Ricardo Silva"
views="0"
/>
</tbody>
</table>
</div>
{/* Performance por Categoria (Coluna Única) */}
<div className="bg-white rounded-2xl border border-slate-200 shadow-sm p-6">
<h3 className="font-bold text-slate-800 text-sm uppercase tracking-wider mb-6">Performance de Conteúdo</h3>
<div className="space-y-6">
<CategoryBar label="Tecnologia" percentage={85} color="bg-blue-500" />
<CategoryBar label="Negócios" percentage={62} color="bg-emerald-500" />
<CategoryBar label="Política" percentage={45} color="bg-purple-500" />
<CategoryBar label="Desporto" percentage={30} color="bg-orange-500" />
</div>
<div className="mt-8 p-4 bg-slate-50 rounded-xl">
<p className="text-[11px] text-slate-500 text-center">
O tráfego orgânico cresceu <strong>15%</strong> nos últimos 7 dias.
</p>
</div>
</div>
</div>
</div>
</main>
</div>
);
};
// --- Subcomponentes para Organização ---
const NavItem = ({ icon, label, active = false }: { icon: any, label: string, active?: boolean }) => (
<div className={`flex items-center gap-3 px-3 py-2 rounded-xl text-sm font-medium transition-all cursor-pointer ${
active ? 'bg-blue-600 text-white shadow-lg shadow-blue-200' : 'text-slate-500 hover:bg-slate-100'
}`}>
{icon}
<span className="truncate">{label}</span>
</div>
);
const StatCard = ({ label, value, trend, icon, isAlert = false }: any) => (
<div className={`p-5 rounded-2xl border bg-white shadow-sm transition-transform hover:scale-[1.02] cursor-default ${isAlert ? 'border-red-100 bg-red-50/20' : 'border-slate-200'}`}>
<div className="flex justify-between items-start mb-4">
<div className={`p-2 rounded-lg ${isAlert ? 'bg-red-100' : 'bg-slate-50'}`}>
{icon}
</div>
<span className={`text-[10px] font-bold px-2 py-0.5 rounded-full ${isAlert ? 'bg-red-500 text-white' : 'bg-emerald-50 text-emerald-600'}`}>
{trend}
</span>
</div>
<p className="text-xs text-slate-500 font-medium">{label}</p>
<h3 className="text-2xl font-bold tracking-tight">{value}</h3>
</div>
);
const TableRow = ({ title, status, author, views }: any) => (
<tr className="hover:bg-slate-50/50 transition-colors group">
<td className="px-6 py-4">
<p className="text-sm font-semibold text-slate-800 truncate max-w-[200px]">{title}</p>
</td>
<td className="px-6 py-4">
<span className={`text-[10px] font-bold px-2 py-1 rounded-md ${
status === 'Publicado' ? 'bg-emerald-50 text-emerald-600' :
status === 'Rascunho' ? 'bg-slate-100 text-slate-500' : 'bg-blue-50 text-blue-600'
}`}>
{status}
</span>
</td>
<td className="px-6 py-4 text-xs text-slate-600">{author}</td>
<td className="px-6 py-4 text-xs font-mono font-medium">{views}</td>
<td className="px-6 py-4">
<div className="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
<button className="p-1.5 hover:bg-white rounded-md border border-slate-200 text-slate-400 hover:text-blue-600 shadow-sm"><Edit3 size={14}/></button>
<button className="p-1.5 hover:bg-white rounded-md border border-slate-200 text-slate-400 hover:text-red-600 shadow-sm"><Trash2 size={14}/></button>
</div>
</td>
</tr>
);
const CategoryBar = ({ label, percentage, color }: any) => (
<div className="space-y-2">
<div className="flex justify-between text-[11px] font-bold uppercase tracking-wide">
<span>{label}</span>
<span className="text-slate-400">{percentage}%</span>
</div>
<div className="w-full h-1.5 bg-slate-100 rounded-full overflow-hidden">
<div className={`h-full ${color} rounded-full`} style={{ width: `${percentage}%` }} />
</div>
</div>
);
export default DashboardMain;
{/* Subcomponente ActivityItem (Coloque fora do componente principal) */}
const ActivityItem = ({ name, action, target, time, avatar }: {
name: string,
action: string,
target: string,
time: string,
avatar: string
}) => (
<div className="flex gap-3 items-start group">
{/* Avatar com Ring */}
<div className="relative shrink-0">
<img
src={avatar}
alt={name}
className="w-7 h-7 rounded-full border border-slate-100 shadow-sm"
/>
<div className="absolute -bottom-0.5 -right-0.5 w-2 h-2 bg-emerald-500 border-2 border-white rounded-full"></div>
</div>
{/* Texto da Atividade */}
<div className="flex flex-col gap-0.5">
<p className="text-[11px] leading-snug text-slate-600">
<span className="font-bold text-slate-900 hover:text-blue-600 cursor-pointer transition-colors">
{name}
</span>
{" "}{action}{" "}
<span className="font-medium text-slate-800 italic">{target}</span>
</p>
<span className="text-[9px] font-medium text-slate-400 uppercase tracking-tight">
{time}
</span>
</div>
</div>
);