Implement Barclays design system UI update

- Update Tailwind config with new color tokens (primary-blue, active-blue,
  electric-violet, lime, grey-100/300/700/900, success, warning, error)
- Add Inter font from Google Fonts as Barclays Effra alternative
- Update Sidebar with primary-blue background and white active state
- Update Hero with electric-violet accent and pill-shaped buttons
- Update all tables with lime (#C3FB5A) header backgrounds
- Implement alternating row colors (white/grey-100) on tables
- Update status badges: In Progress (amber), Completed (green)
- Update tabs with active-blue underline styling
- Apply 10px border radius to cards and containers
- Update button styling to pill-shaped with active-blue
- Update input/dropdown borders to grey-700 with 2px
- Update selected state highlighting to info-light (#E7F0FB)
- Update FeedbackReport RAG status colors to new design system

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
michael 2026-01-27 13:50:46 -06:00
parent e5a841716e
commit 532d7541d6
11 changed files with 369 additions and 338 deletions

View file

@ -854,9 +854,9 @@ const App: React.FC = () => {
// Show loading spinner during MSAL authentication interactions
if (inProgress !== InteractionStatus.None) {
return (
<div className="fixed inset-0 bg-[#0f172a] flex items-center justify-center">
<div className="fixed inset-0 bg-primary-blue flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<svg className="animate-spin h-12 w-12 text-brand-accent" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<svg className="animate-spin h-12 w-12 text-active-blue" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
@ -871,7 +871,7 @@ const App: React.FC = () => {
}
// Determine background color based on view to avoid grey bar on Home view
const mainBgColor = currentView === 'Home' ? 'bg-white' : 'bg-brand-gray';
const mainBgColor = currentView === 'Home' ? 'bg-white' : 'bg-grey-100';
// Get user info from MSAL for sidebar display
const userInfo = getUserInfo(msalInstance);

View file

@ -21,12 +21,12 @@ const StableLine = () => <svg xmlns="http://www.w3.org/2000/svg" fill="none" vie
const TrendIndicator: React.FC<{ trend: 'up' | 'down' | 'stable' }> = ({ trend }) => {
if (trend === 'up') {
return <div className="flex items-center gap-1.5 text-green-600"><UpArrow/> Improving</div>;
return <div className="flex items-center gap-1.5 text-success"><UpArrow/> Improving</div>;
}
if (trend === 'down') {
return <div className="flex items-center gap-1.5 text-red-600"><DownArrow/> Declining</div>;
return <div className="flex items-center gap-1.5 text-error"><DownArrow/> Declining</div>;
}
return <div className="flex items-center gap-1.5 text-gray-500"><StableLine/> Stable</div>;
return <div className="flex items-center gap-1.5 text-grey-700"><StableLine/> Stable</div>;
};
export const Analytics: React.FC = () => {
@ -65,10 +65,10 @@ export const Analytics: React.FC = () => {
];
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-brand-gray">
<div className="p-4 sm:p-6 lg:p-8 h-full bg-grey-100">
<header className="mb-8">
<h1 className="text-3xl lg:text-4xl font-bold text-brand-dark-blue">Performance Analytics</h1>
<p className="text-base lg:text-lg text-gray-600 mt-1">Overall usage and performance statistics for the tool.</p>
<h1 className="text-3xl lg:text-4xl font-bold text-primary-blue">Performance Analytics</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">Overall usage and performance statistics for the tool.</p>
</header>
{/* Stats Cards */}
@ -77,13 +77,13 @@ export const Analytics: React.FC = () => {
{stats.map((stat) => {
const Icon = stat.icon;
return (
<div key={stat.name} className="bg-white rounded-lg shadow-md p-6 flex items-start border border-gray-200 transition-all hover:shadow-xl hover:border-brand-accent">
<div className="p-3 rounded-full bg-brand-light-blue/20 text-brand-accent mr-4 flex-shrink-0">
<Icon className="h-7 w-7" />
<div key={stat.name} className="bg-grey-100 rounded-[10px] p-6 flex items-start border-2 border-grey-300 transition-all hover:shadow-lg hover:border-active-blue">
<div className="p-3 rounded-full bg-white text-black-title mr-4 flex-shrink-0">
<Icon className="h-9 w-9" />
</div>
<div>
<p className="text-sm font-medium text-gray-500">{stat.name}</p>
<p className="text-3xl font-bold text-brand-dark-blue mt-1">{stat.value}</p>
<p className="text-sm font-medium text-grey-900">{stat.name}</p>
<p className="text-3xl font-bold text-black-title mt-1">{stat.value}</p>
</div>
</div>
);
@ -93,45 +93,45 @@ export const Analytics: React.FC = () => {
{/* AI Performance Summary */}
<section className="mt-10">
<h2 className="text-2xl font-bold text-brand-dark-blue mb-4">AI Performance Summary</h2>
<div className="bg-blue-50 border-l-4 border-brand-accent text-brand-dark-blue p-6 rounded-r-lg shadow-md flex items-start gap-4">
<h2 className="text-2xl font-bold text-primary-blue mb-4">AI Performance Summary</h2>
<div className="bg-white border-2 border-electric-violet text-black-title p-6 rounded-[10px] shadow-md flex items-start gap-4">
<div className="flex-shrink-0">
<LightbulbIcon className="h-7 w-7 text-brand-accent" />
<LightbulbIcon className="h-7 w-7 text-electric-violet" />
</div>
<div>
<p className="font-semibold">Key Insight (Last 7 Days):</p>
<p className="mt-1">
<p className="font-semibold text-primary-blue">Key Insight (Last 7 Days):</p>
<p className="mt-1 text-black-title">
A sharp decline in Best Practice adherence has been noted, primarily driven by proofs from the <strong>Barclays Q4 Social</strong> campaign. The Brand Guardian agent also shows a declining performance trend, suggesting a potential need for updated brand guideline training or proof review.
</p>
</div>
</div>
</section>
{/* Agent Performance Table */}
<section className="mt-10">
<h2 className="text-2xl font-bold text-brand-dark-blue mb-4">Agent Performance (Last 7 Days)</h2>
<div className="bg-white rounded-lg shadow-md overflow-hidden border border-gray-200">
<h2 className="text-2xl font-bold text-primary-blue mb-4">Agent Performance (Last 7 Days)</h2>
<div className="bg-white rounded-[10px] shadow-md overflow-hidden border border-grey-300">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full">
<thead className="bg-lime">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Agent Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Pass Rate</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Avg. Issues per Proof</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Performance Trend</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Agent Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Pass Rate</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Avg. Issues per Proof</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Performance Trend</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{agentPerformance.map((agent) => (
<tr key={agent.name} className="hover:bg-gray-50">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-brand-dark-blue">{agent.name}</td>
<td className={`px-6 py-4 whitespace-nowrap text-sm font-semibold`}>
<tbody className="divide-y divide-grey-300">
{agentPerformance.map((agent, index) => (
<tr key={agent.name} className={index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-black-title">{agent.name}</td>
<td className={`px-6 py-4 whitespace-nowrap text-sm font-semibold text-black-title`}>
<div className="flex items-center">
<span className={`h-2.5 w-2.5 rounded-full mr-3 ${agent.passRate >= 80 ? 'bg-green-500' : agent.passRate < 70 ? 'bg-red-500' : 'bg-yellow-500'}`}></span>
<span className={`h-2.5 w-2.5 rounded-full mr-3 ${agent.passRate >= 80 ? 'bg-success' : agent.passRate < 70 ? 'bg-error' : 'bg-warning'}`}></span>
{agent.passRate}%
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{agent.avgIssues}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{agent.avgIssues}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<TrendIndicator trend={agent.trend as 'up' | 'down' | 'stable'} />
</td>

View file

@ -22,41 +22,41 @@ const formatDate = (isoString: string) => {
const FlagsTable: React.FC<{ items: FlaggedItem[], onNavigate: AuditingProps['onNavigate'] }> = ({ items, onNavigate }) => (
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full">
<thead className="bg-lime">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Agent Flagged</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">User Comments</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Date</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Agent Flagged</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">User Comments</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{items.length > 0 ? items.map((item) => (
<tbody className="divide-y divide-grey-300">
{items.length > 0 ? items.map((item, index) => (
<tr
key={item.id}
className="hover:bg-gray-100 cursor-pointer"
className={`hover:bg-info-light cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
onClick={() => onNavigate(item)}
title={`Click to view Version ${item.version} of ${item.proofName}`}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-brand-dark-blue">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.submitAgency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.agentFlagged}</td>
<td className="px-6 py-4 text-sm text-gray-700">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-black-title">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.submitAgency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.agentFlagged}</td>
<td className="px-6 py-4 text-sm text-black-title">
<div className="max-w-xs break-words" title={item.comments}>
{item.comments || <span className="italic text-gray-400">No comment</span>}
{item.comments || <span className="italic text-grey-700">No comment</span>}
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{formatDate(item.timestamp)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{formatDate(item.timestamp)}</td>
</tr>
)) : (
<tr>
<td colSpan={7} className="text-center py-10 text-gray-500">
<td colSpan={7} className="text-center py-10 text-grey-700">
There are currently no flagged items to audit.
</td>
</tr>
@ -68,43 +68,43 @@ const FlagsTable: React.FC<{ items: FlaggedItem[], onNavigate: AuditingProps['on
const ResolutionsTable: React.FC<{ items: ResolvedItem[], onNavigate: AuditingProps['onNavigate'] }> = ({ items, onNavigate }) => (
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full">
<thead className="bg-lime">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Agent</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Agent Issue</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">User Comments</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Date</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Agent</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Agent Issue</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">User Comments</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{items.length > 0 ? items.map((item) => (
<tbody className="divide-y divide-grey-300">
{items.length > 0 ? items.map((item, index) => (
<tr
key={item.id}
className="hover:bg-gray-100 cursor-pointer"
className={`hover:bg-info-light cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
onClick={() => onNavigate(item)}
title={`Click to view Version ${item.version} of ${item.proofName}`}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-brand-dark-blue">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.submitAgency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.agent}</td>
<td className="px-6 py-4 text-sm text-gray-700">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-black-title">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.submitAgency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.agent}</td>
<td className="px-6 py-4 text-sm text-black-title">
<div className="max-w-xs break-words" title={item.issue}>{item.issue}</div>
</td>
<td className="px-6 py-4 text-sm text-gray-700">
<td className="px-6 py-4 text-sm text-black-title">
<div className="max-w-xs break-words" title={item.resolution}>{item.resolution}</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{formatDate(item.timestamp)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{formatDate(item.timestamp)}</td>
</tr>
)) : (
<tr>
<td colSpan={8} className="text-center py-10 text-gray-500">
<td colSpan={8} className="text-center py-10 text-grey-700">
There are currently no resolved items to audit.
</td>
</tr>
@ -116,39 +116,39 @@ const ResolutionsTable: React.FC<{ items: ResolvedItem[], onNavigate: AuditingPr
const ErrorsTable: React.FC<{ items: ErrorItem[], onNavigate: AuditingProps['onNavigate'] }> = ({ items, onNavigate }) => (
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full">
<thead className="bg-lime">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Error Summary</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Date</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Error Summary</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{items.length > 0 ? items.map((item) => (
<tbody className="divide-y divide-grey-300">
{items.length > 0 ? items.map((item, index) => (
<tr
key={item.id}
className="hover:bg-gray-100 cursor-pointer"
className={`hover:bg-info-light cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
onClick={() => onNavigate(item)}
title={`Click to view Version ${item.version} of ${item.proofName}`}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-brand-dark-blue">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{item.submitAgency}</td>
<td className="px-6 py-4 text-sm text-gray-700">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-black-title">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{item.submitAgency}</td>
<td className="px-6 py-4 text-sm text-black-title">
<div className="max-w-md break-words" title={item.errorSummary}>
{item.errorSummary}
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{formatDate(item.timestamp)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{formatDate(item.timestamp)}</td>
</tr>
)) : (
<tr>
<td colSpan={6} className="text-center py-10 text-gray-500">
<td colSpan={6} className="text-center py-10 text-grey-700">
There are currently no analysis errors to audit.
</td>
</tr>
@ -163,20 +163,20 @@ export const Auditing: React.FC<AuditingProps> = ({ flaggedItems, resolvedItems,
const [activeTab, setActiveTab] = useState<'Flags' | 'Resolutions' | 'Errors'>('Flags');
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-brand-gray">
<div className="p-4 sm:p-6 lg:p-8 h-full bg-grey-100">
<header className="mb-8">
<h1 className="text-3xl lg:text-4xl font-bold text-brand-dark-blue">Auditing</h1>
<p className="text-base lg:text-lg text-gray-600 mt-1">Review and investigate all user-flagged feedback.</p>
<h1 className="text-3xl lg:text-4xl font-bold text-primary-blue">Auditing</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">Review and investigate all user-flagged feedback.</p>
</header>
<div className="mb-6 border-b border-gray-200">
<div className="mb-6 border-b border-grey-300">
<nav className="-mb-px flex space-x-6" aria-label="Tabs">
<button
onClick={() => setActiveTab('Flags')}
className={`whitespace-nowrap py-3 px-1 border-b-2 font-semibold text-sm transition-colors ${
activeTab === 'Flags'
? 'border-brand-accent text-brand-accent'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
? 'border-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
}`}
aria-current={activeTab === 'Flags' ? 'page' : undefined}
>
@ -186,8 +186,8 @@ export const Auditing: React.FC<AuditingProps> = ({ flaggedItems, resolvedItems,
onClick={() => setActiveTab('Resolutions')}
className={`whitespace-nowrap py-3 px-1 border-b-2 font-semibold text-sm transition-colors ${
activeTab === 'Resolutions'
? 'border-brand-accent text-brand-accent'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
? 'border-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
}`}
aria-current={activeTab === 'Resolutions' ? 'page' : undefined}
>
@ -197,8 +197,8 @@ export const Auditing: React.FC<AuditingProps> = ({ flaggedItems, resolvedItems,
onClick={() => setActiveTab('Errors')}
className={`whitespace-nowrap py-3 px-1 border-b-2 font-semibold text-sm transition-colors ${
activeTab === 'Errors'
? 'border-brand-accent text-brand-accent'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
? 'border-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
}`}
aria-current={activeTab === 'Errors' ? 'page' : undefined}
>
@ -208,7 +208,7 @@ export const Auditing: React.FC<AuditingProps> = ({ flaggedItems, resolvedItems,
</div>
<section>
<div className="bg-white rounded-lg shadow-md overflow-hidden border border-gray-200">
<div className="bg-white rounded-[10px] shadow-md overflow-hidden border border-grey-300">
{activeTab === 'Flags' && <FlagsTable items={flaggedItems} onNavigate={onNavigate} />}
{activeTab === 'Resolutions' && <ResolutionsTable items={resolvedItems} onNavigate={onNavigate} />}
{activeTab === 'Errors' && <ErrorsTable items={errorItems} onNavigate={onNavigate} />}

View file

@ -226,16 +226,16 @@ const StatusBadge: React.FC<{ status: string }> = ({ status }) => {
let colorClasses = '';
switch (status) {
case 'In Progress':
colorClasses = 'bg-blue-100 text-blue-800';
colorClasses = 'bg-warning text-black-title';
break;
case 'Completed':
colorClasses = 'bg-green-100 text-green-800';
colorClasses = 'bg-success text-white';
break;
case 'Needs Review':
colorClasses = 'bg-yellow-100 text-yellow-800';
colorClasses = 'bg-warning-light text-black-title';
break;
default:
colorClasses = 'bg-gray-100 text-gray-800';
colorClasses = 'bg-grey-100 text-black-title';
}
return (
<span className={`px-2.5 py-0.5 text-xs font-semibold rounded-full ${colorClasses}`}>
@ -248,19 +248,19 @@ const OverallStatusBadge: React.FC<{ status: OverallStatus }> = ({ status }) =>
let colorClasses = '';
switch (status) {
case 'Passed':
colorClasses = 'bg-green-100 text-green-800';
colorClasses = 'bg-success text-white';
break;
case 'Failed':
colorClasses = 'bg-red-100 text-red-800';
colorClasses = 'bg-error text-white';
break;
case 'Requires Manual Legal Review':
colorClasses = 'bg-purple-100 text-purple-800';
colorClasses = 'bg-warning text-black-title';
break;
case 'Analysis Error':
colorClasses = 'bg-gray-200 text-gray-800';
colorClasses = 'bg-grey-300 text-black-title';
break;
}
return (
<span className={`inline-flex items-center px-3 py-1 text-sm font-bold rounded-full ${colorClasses}`}>
{status}
@ -299,17 +299,17 @@ const CampaignList: React.FC<{
}, [filteredCampaigns]);
const getStatusSelectClasses = (status: string) => {
let baseClasses = 'w-full text-center px-2.5 py-0.5 text-xs font-semibold rounded-full border border-transparent focus:outline-none focus:ring-2 focus:ring-brand-accent appearance-none cursor-pointer';
let baseClasses = 'w-full text-center px-2.5 py-0.5 text-xs font-semibold rounded-full border border-transparent focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none cursor-pointer';
let colorClasses = '';
switch (status) {
case 'In Progress':
colorClasses = 'bg-blue-100 text-blue-800';
colorClasses = 'bg-warning text-black-title';
break;
case 'Completed':
colorClasses = 'bg-green-100 text-green-800';
colorClasses = 'bg-success text-white';
break;
default:
colorClasses = 'bg-gray-100 text-gray-800';
colorClasses = 'bg-grey-100 text-black-title';
}
return `${baseClasses} ${colorClasses}`;
};
@ -364,7 +364,7 @@ const CampaignList: React.FC<{
const isIndeterminate = selectedCampaigns.size > 0 && selectedCampaigns.size < filteredCampaigns.length;
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-brand-gray">
<div className="p-4 sm:p-6 lg:p-8 h-full bg-grey-100">
<CampaignDeleteConfirmationModal
isOpen={!!campaignToDelete}
onClose={() => setCampaignToDelete(null)}
@ -388,17 +388,17 @@ const CampaignList: React.FC<{
<header className="mb-8">
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div>
<h1 className="text-3xl lg:text-4xl font-bold text-brand-dark-blue">Campaigns</h1>
<p className="text-base lg:text-lg text-gray-600 mt-1">Manage your campaigns and proof collections.</p>
<h1 className="text-3xl lg:text-4xl font-bold text-primary-blue">Campaigns</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">Manage your campaigns and proof collections.</p>
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
<label htmlFor="show-completed" className="text-sm font-medium text-gray-700 whitespace-nowrap">Show Completed</label>
<label htmlFor="show-completed" className="text-sm font-medium text-black-title whitespace-nowrap">Show Completed</label>
<ToggleSwitch enabled={showCompleted} onChange={setShowCompleted} />
</div>
<button
onClick={onOpenModal}
className="flex items-center gap-2 bg-brand-accent text-white font-semibold py-2 px-4 rounded-lg hover:bg-brand-dark-blue transition-colors duration-300"
className="flex items-center gap-2 bg-active-blue text-white font-semibold py-2.5 px-6 rounded-full hover:bg-active-blue/90 transition-colors duration-300"
>
<PlusIcon className="h-5 w-5" />
Create New Campaign
@ -410,14 +410,14 @@ const CampaignList: React.FC<{
<section>
{/* Bulk Actions Bar */}
{selectedCampaigns.size > 0 && (
<div className="mb-4 bg-blue-50 border border-blue-200 rounded-lg p-3 flex items-center justify-between">
<div className="mb-4 bg-info-light border border-active-blue rounded-[10px] p-3 flex items-center justify-between">
<div className="flex items-center gap-4">
<span className="text-sm font-medium text-blue-800">
<span className="text-sm font-medium text-active-blue">
{selectedCampaigns.size} campaign{selectedCampaigns.size !== 1 ? 's' : ''} selected
</span>
<button
onClick={() => setSelectedCampaigns(new Set())}
className="text-sm text-blue-600 hover:text-blue-800 underline"
className="text-sm text-active-blue hover:text-primary-blue underline"
>
Clear selection
</button>
@ -425,7 +425,7 @@ const CampaignList: React.FC<{
<button
onClick={() => setShowBulkDeleteModal(true)}
disabled={isDeleting}
className="flex items-center gap-2 bg-red-600 text-white font-semibold py-1.5 px-3 rounded-lg hover:bg-red-700 transition-colors duration-300 disabled:opacity-50 disabled:cursor-not-allowed"
className="flex items-center gap-2 bg-error text-white font-semibold py-1.5 px-4 rounded-full hover:bg-error/90 transition-colors duration-300 disabled:opacity-50 disabled:cursor-not-allowed"
>
<TrashIcon className="h-4 w-4" />
Delete Selected
@ -433,10 +433,10 @@ const CampaignList: React.FC<{
</div>
)}
<div className="bg-white rounded-lg shadow-md overflow-hidden border border-gray-200">
<div className="bg-white rounded-[10px] shadow-md overflow-hidden border border-grey-300">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full">
<thead className="bg-lime">
<tr>
<th scope="col" className="px-4 py-3 text-left">
<input
@ -446,26 +446,26 @@ const CampaignList: React.FC<{
if (el) el.indeterminate = isIndeterminate;
}}
onChange={handleSelectAll}
className="h-4 w-4 text-brand-accent border-gray-300 rounded focus:ring-brand-accent cursor-pointer"
className="h-4 w-4 text-active-blue border-grey-300 rounded focus:ring-active-blue cursor-pointer"
aria-label="Select all campaigns"
/>
</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Campaign Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Proofs</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Status</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Created By</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Owning Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Last Modified</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Campaign Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proofs</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Status</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Created By</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Owning Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Last Modified</th>
<th scope="col" className="relative px-4 py-3"><span className="sr-only">Actions</span></th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{filteredCampaigns.map((campaign) => {
<tbody className="divide-y divide-grey-300">
{filteredCampaigns.map((campaign, index) => {
const isSelected = selectedCampaigns.has(campaign.name);
return (
<tr
key={campaign.name}
className={`hover:bg-gray-100 cursor-pointer ${isSelected ? 'bg-blue-50' : ''}`}
className={`hover:bg-info-light cursor-pointer ${isSelected ? 'bg-info-light' : index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
onClick={() => onSelectCampaign(campaign.name)}
>
<td className="px-4 py-4 whitespace-nowrap">
@ -474,12 +474,12 @@ const CampaignList: React.FC<{
checked={isSelected}
onChange={() => {}} // Handled by onClick
onClick={(e) => handleSelectCampaign(campaign.name, e)}
className="h-4 w-4 text-brand-accent border-gray-300 rounded focus:ring-brand-accent cursor-pointer"
className="h-4 w-4 text-active-blue border-grey-300 rounded focus:ring-active-blue cursor-pointer"
aria-label={`Select ${campaign.name}`}
/>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-brand-dark-blue">{campaign.name}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{campaign.proofs}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-black-title">{campaign.name}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{campaign.proofs}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm w-40">
<div className="relative">
<select
@ -492,17 +492,17 @@ const CampaignList: React.FC<{
<option value="In Progress">In Progress</option>
<option value="Completed">Completed</option>
</select>
<ChevronDownIcon className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 h-full w-4 text-gray-500" />
<ChevronDownIcon className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 h-full w-4 text-black-title" />
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{campaign.agencyLead}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{campaign.agency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">{formatDate(campaign.lastModified)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{campaign.agencyLead}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{campaign.agency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{formatDate(campaign.lastModified)}</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-right">
<button
onClick={(e) => handleSingleDelete(campaign, e)}
disabled={isDeleting}
className="p-2 text-gray-400 rounded-full hover:bg-red-100 hover:text-red-600 transition-colors disabled:opacity-50"
className="p-2 text-grey-700 rounded-full hover:bg-error-light hover:text-error transition-colors disabled:opacity-50"
title={`Delete ${campaign.name}`}
aria-label={`Delete ${campaign.name}`}
>

View file

@ -41,43 +41,43 @@ const specialistAgents: CheckDetail[] = [
export const ChecksOverview: React.FC = () => {
return (
<div className="relative bg-gradient-to-br from-emerald-50 via-white to-emerald-50/30 py-12 sm:py-16 w-full">
<div className="relative bg-gradient-to-br from-lime/20 via-white to-lime/10 py-12 sm:py-16 w-full">
{/* Decorative Background */}
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-0 left-1/4 w-[800px] h-[800px] bg-emerald-200/30 rounded-full blur-3xl -translate-y-1/2 mix-blend-multiply"></div>
<div className="absolute bottom-0 right-0 w-[600px] h-[600px] bg-green-200/30 rounded-full blur-3xl translate-y-1/3 mix-blend-multiply"></div>
<div className="absolute top-0 left-1/4 w-[800px] h-[800px] bg-lime/30 rounded-full blur-3xl -translate-y-1/2 mix-blend-multiply"></div>
<div className="absolute bottom-0 right-0 w-[600px] h-[600px] bg-success-light rounded-full blur-3xl translate-y-1/3 mix-blend-multiply"></div>
</div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
{/* Header */}
<div className="max-w-3xl mx-auto text-center mb-12">
<div className="inline-flex items-center px-4 py-1.5 rounded-full bg-white border border-emerald-200 text-emerald-700 text-xs font-bold uppercase tracking-widest mb-4 shadow-sm">
<span className="w-2 h-2 rounded-full bg-emerald-500 mr-2 animate-pulse"></span>
<div className="inline-flex items-center px-4 py-1.5 rounded-full bg-white border border-lime text-primary-blue text-xs font-bold uppercase tracking-widest mb-4 shadow-sm">
<span className="w-2 h-2 rounded-full bg-success mr-2 animate-pulse"></span>
Intelligent Workflow
</div>
<h2 className="text-3xl md:text-4xl font-extrabold text-brand-dark-blue tracking-tight mb-4">
<h2 className="text-3xl md:text-4xl font-extrabold text-primary-blue tracking-tight mb-4">
Orchestrated by AI
</h2>
<p className="text-lg text-slate-600 leading-relaxed">
<p className="text-lg text-black-title leading-relaxed">
A central Lead Agent coordinates specialized experts to review every aspect of your content in parallel.
</p>
</div>
<div className="flex flex-col lg:flex-row items-center justify-center lg:items-stretch gap-0 lg:gap-0">
{/* 1. LEAD AGENT CARD (Left) */}
<div className="w-full max-w-md lg:w-[380px] relative z-20 group/lead flex flex-col">
<div className="flex-1 relative bg-[#001f5a] rounded-3xl p-6 shadow-2xl shadow-blue-900/20 border border-white/10 text-center transition-all duration-500 hover:-translate-y-2 hover:shadow-blue-900/40 overflow-hidden flex flex-col items-center justify-center">
<div className="flex-1 relative bg-primary-blue rounded-[20px] p-6 shadow-2xl shadow-primary-blue/20 border border-white/10 text-center transition-all duration-500 hover:-translate-y-2 hover:shadow-primary-blue/40 overflow-hidden flex flex-col items-center justify-center">
{/* Animated Gradient bg */}
<div className="absolute top-[-50%] left-[-50%] w-[200%] h-[200%] bg-gradient-to-b from-transparent via-white/5 to-transparent rotate-45 transition-transform duration-[3s] group-hover/lead:translate-y-10"></div>
<div className="relative z-10">
<div className="h-20 w-20 mx-auto rounded-2xl bg-white/10 border border-white/20 backdrop-blur-md flex items-center justify-center mb-4 shadow-lg shadow-brand-dark-blue/30 group-hover/lead:scale-110 transition-all duration-500">
<div className="h-20 w-20 mx-auto rounded-2xl bg-white/10 border border-white/20 backdrop-blur-md flex items-center justify-center mb-4 shadow-lg shadow-primary-blue/30 group-hover/lead:scale-110 transition-all duration-500">
<LeadAgentIcon className="h-10 w-10 text-white" />
</div>
<h3 className="text-2xl font-bold text-white mb-2">Lead Agent</h3>
<p className="text-brand-light-blue font-bold text-xs uppercase tracking-widest mb-4">Orchestrator</p>
<p className="text-cyan-brand font-bold text-xs uppercase tracking-widest mb-4">Orchestrator</p>
<p className="text-slate-300 text-sm leading-relaxed">
Synthesizes feedback & coordinates analysis across all specialist agents.
</p>
@ -85,12 +85,12 @@ export const ChecksOverview: React.FC = () => {
</div>
{/* Connection Node (Desktop) */}
<div className="hidden lg:flex absolute top-1/2 -right-4 w-8 h-8 bg-[#001f5a] rounded-full border-4 border-emerald-50 items-center justify-center z-30 -translate-y-1/2 shadow-sm translate-x-1/2">
<div className="w-2.5 h-2.5 bg-emerald-400 rounded-full animate-pulse"></div>
<div className="hidden lg:flex absolute top-1/2 -right-4 w-8 h-8 bg-primary-blue rounded-full border-4 border-lime/50 items-center justify-center z-30 -translate-y-1/2 shadow-sm translate-x-1/2">
<div className="w-2.5 h-2.5 bg-success rounded-full animate-pulse"></div>
</div>
{/* Connection Node (Mobile) */}
<div className="lg:hidden absolute -bottom-4 left-1/2 w-8 h-8 bg-[#001f5a] rounded-full border-4 border-emerald-50 items-center justify-center z-30 -translate-x-1/2 shadow-sm">
<div className="w-2.5 h-2.5 bg-emerald-400 rounded-full animate-pulse"></div>
<div className="lg:hidden absolute -bottom-4 left-1/2 w-8 h-8 bg-primary-blue rounded-full border-4 border-lime/50 items-center justify-center z-30 -translate-x-1/2 shadow-sm">
<div className="w-2.5 h-2.5 bg-success rounded-full animate-pulse"></div>
</div>
</div>
@ -98,54 +98,54 @@ export const ChecksOverview: React.FC = () => {
<div className="hidden lg:block w-24 relative z-10 self-center h-48">
<svg className="absolute inset-0 w-full h-full overflow-visible" viewBox="0 0 100 200" preserveAspectRatio="none">
{/* Connecting paths */}
<path d="M0,100 C50,100 50,30 100,30" fill="none" stroke="#6ee7b7" strokeWidth="2" strokeDasharray="6 6" />
<path d="M0,100 C50,100 50,170 100,170" fill="none" stroke="#6ee7b7" strokeWidth="2" strokeDasharray="6 6" />
<path d="M0,100 C50,100 50,30 100,30" fill="none" stroke="#C3FB5A" strokeWidth="2" strokeDasharray="6 6" />
<path d="M0,100 C50,100 50,170 100,170" fill="none" stroke="#C3FB5A" strokeWidth="2" strokeDasharray="6 6" />
{/* Animated pulses on paths */}
<circle r="3" fill="#10b981">
<circle r="3" fill="#09821F">
<animateMotion dur="2s" repeatCount="indefinite" path="M0,100 C50,100 50,30 100,30" />
</circle>
<circle r="3" fill="#10b981">
<circle r="3" fill="#09821F">
<animateMotion dur="2s" repeatCount="indefinite" begin="1s" path="M0,100 C50,100 50,170 100,170" />
</circle>
</svg>
</div>
{/* Mobile Connector Spacer */}
<div className="lg:hidden h-8 w-0.5 bg-emerald-300 my-3"></div>
<div className="lg:hidden h-8 w-0.5 bg-lime my-3"></div>
{/* 3. SPECIALIST AGENTS (Right) */}
<div className="flex-1 grid grid-cols-1 md:grid-cols-2 gap-4 w-full max-w-4xl pl-0 lg:pl-4">
{specialistAgents.map((agent, index) => (
<div
key={agent.name}
className="group relative rounded-2xl p-5 border border-emerald-100 shadow-sm transition-all duration-500 hover:shadow-xl hover:shadow-emerald-900/5 hover:-translate-y-2 hover:border-emerald-200 overflow-hidden bg-white"
<div
key={agent.name}
className="group relative rounded-[10px] p-5 border border-grey-300 shadow-sm transition-all duration-500 hover:shadow-xl hover:shadow-success/10 hover:-translate-y-2 hover:border-success overflow-hidden bg-white"
>
{/* Base Gradient */}
<div className="absolute inset-0 bg-gradient-to-br from-white via-white to-emerald-50/30 opacity-100 transition-opacity duration-500 group-hover:opacity-0"></div>
<div className="absolute inset-0 bg-gradient-to-br from-white via-white to-lime/10 opacity-100 transition-opacity duration-500 group-hover:opacity-0"></div>
{/* Hover Gradient - Interactive Green */}
<div className="absolute inset-0 bg-gradient-to-br from-white via-emerald-50 to-emerald-100/20 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="absolute inset-0 bg-gradient-to-br from-white via-success-light to-lime/20 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
{/* Animated Shine/Sweep Effect */}
<div className="absolute top-[-50%] left-[-50%] w-[200%] h-[200%] bg-gradient-to-b from-transparent via-emerald-500/5 to-transparent rotate-45 translate-y-12 transition-transform duration-1000 group-hover:translate-y-[-10%] pointer-events-none"></div>
<div className="absolute top-[-50%] left-[-50%] w-[200%] h-[200%] bg-gradient-to-b from-transparent via-success/5 to-transparent rotate-45 translate-y-12 transition-transform duration-1000 group-hover:translate-y-[-10%] pointer-events-none"></div>
{/* Glassy Highlight */}
<div className="absolute -top-24 -right-24 w-48 h-48 bg-gradient-to-br from-emerald-400/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none"></div>
<div className="absolute -top-24 -right-24 w-48 h-48 bg-gradient-to-br from-lime/30 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none"></div>
<div className="relative z-10 flex items-start gap-4">
<div className={`flex-shrink-0 w-12 h-12 rounded-2xl flex items-center justify-center transition-all duration-300 group-hover:scale-110 group-hover:shadow-md bg-emerald-50 text-emerald-600 group-hover:bg-emerald-600 group-hover:text-white`}>
<div className={`flex-shrink-0 w-12 h-12 rounded-[10px] flex items-center justify-center transition-all duration-300 group-hover:scale-110 group-hover:shadow-md bg-success-light text-success group-hover:bg-success group-hover:text-white`}>
{React.cloneElement(agent.icon as React.ReactElement, { className: "h-6 w-6 transition-colors duration-300" })}
</div>
<div className="flex-1">
<h4 className="text-base font-bold text-slate-800 group-hover:text-emerald-900 transition-colors duration-300 mb-0.5">
<h4 className="text-base font-bold text-black-title group-hover:text-primary-blue transition-colors duration-300 mb-0.5">
{agent.name}
</h4>
<p className="text-[10px] font-extrabold text-slate-400 uppercase tracking-wider mb-1 group-hover:text-emerald-600 transition-colors duration-300">
<p className="text-[10px] font-extrabold text-grey-700 uppercase tracking-wider mb-1 group-hover:text-success transition-colors duration-300">
{agent.role}
</p>
<p className="text-xs text-slate-600 leading-relaxed group-hover:text-slate-700">
<p className="text-xs text-black-title leading-relaxed group-hover:text-black-title">
{agent.description}
</p>
</div>

View file

@ -87,35 +87,35 @@ export const CreateCampaignModal: React.FC<CreateCampaignModalProps> = ({ isOpen
role="dialog"
>
<div
className="bg-white rounded-lg shadow-xl p-6 sm:p-8 w-full max-w-lg transform transition-all"
className="bg-white rounded-[10px] shadow-xl p-6 sm:p-8 w-full max-w-lg transform transition-all"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-brand-dark-blue">Create New Campaign</h2>
<button onClick={onClose} className="p-1 rounded-full text-gray-500 hover:bg-gray-200 hover:text-gray-800 transition-colors">
<h2 className="text-2xl font-bold text-primary-blue">Create New Campaign</h2>
<button onClick={onClose} className="p-1 rounded-full text-grey-700 hover:bg-grey-100 hover:text-black-title transition-colors">
<XIcon className="h-6 w-6" />
</button>
</div>
<form onSubmit={handleSubmit} noValidate>
<div className="space-y-4">
<div>
<label htmlFor="campaign-name" className="block text-sm font-medium text-gray-700">Campaign Name</label>
<label htmlFor="campaign-name" className="block text-sm font-medium text-black-title">Campaign Name</label>
<input
type="text"
id="campaign-name"
value={name}
onChange={(e) => setName(e.target.value)}
className="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-brand-accent focus:border-brand-accent transition bg-white text-gray-900"
className="mt-1 block w-full p-2 border-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
required
/>
</div>
<div>
<label htmlFor="brand-guidelines" className="block text-sm font-medium text-gray-700">Brand Guidelines</label>
<label htmlFor="brand-guidelines" className="block text-sm font-medium text-black-title">Brand Guidelines</label>
<select
id="brand-guidelines"
value={selectedBrandGuideline}
onChange={(e) => setSelectedBrandGuideline(e.target.value)}
className="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-brand-accent focus:border-brand-accent transition bg-white text-gray-900"
className="mt-1 block w-full p-2 border-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
required
>
<option value="" disabled>Select brand guidelines</option>
@ -125,47 +125,47 @@ export const CreateCampaignModal: React.FC<CreateCampaignModalProps> = ({ isOpen
</select>
</div>
<div>
<label htmlFor="workfront-id" className="block text-sm font-medium text-gray-700">Workfront Campaign ID <span className="text-gray-400 font-normal">(Optional)</span></label>
<label htmlFor="workfront-id" className="block text-sm font-medium text-black-title">Workfront Campaign ID <span className="text-grey-700 font-normal">(Optional)</span></label>
<input
type="text"
id="workfront-id"
value={workfrontId}
onChange={handleWorkfrontIdChange}
className={`mt-1 block w-full p-2 border rounded-md shadow-sm focus:ring-brand-accent focus:border-brand-accent transition bg-white text-gray-900 placeholder:text-gray-400 ${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : 'border-gray-300'}`}
className={`mt-1 block w-full p-2 border-2 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title placeholder:text-grey-700 ${error ? 'border-error focus:border-error focus:ring-error' : 'border-grey-700'}`}
placeholder="#WF_12345"
aria-invalid={!!error}
aria-describedby="workfront-id-error"
/>
{error && <p id="workfront-id-error" className="mt-1 text-sm text-red-600">{error}</p>}
{error && <p id="workfront-id-error" className="mt-1 text-sm text-error">{error}</p>}
</div>
<div>
<label htmlFor="client-lead" className="block text-sm font-medium text-gray-700">Client Lead</label>
<label htmlFor="client-lead" className="block text-sm font-medium text-black-title">Client Lead</label>
<input
type="text"
id="client-lead"
value={clientLead}
onChange={(e) => setClientLead(e.target.value)}
className="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-brand-accent focus:border-brand-accent transition bg-white text-gray-900"
className="mt-1 block w-full p-2 border-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Agency</label>
<label className="block text-sm font-medium text-black-title">Agency</label>
<input
type="text"
value="OLIVER Agency"
className="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm bg-gray-100 text-gray-600 cursor-not-allowed"
className="mt-1 block w-full p-2 border-2 border-grey-300 rounded-[10px] shadow-sm bg-grey-100 text-grey-900 cursor-not-allowed"
disabled
/>
</div>
<div>
<label htmlFor="agency-lead" className="block text-sm font-medium text-gray-700">Agency Lead</label>
<label htmlFor="agency-lead" className="block text-sm font-medium text-black-title">Agency Lead</label>
<input
type="text"
id="agency-lead"
value={agencyLead}
onChange={(e) => setAgencyLead(e.target.value)}
className="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-brand-accent focus:border-brand-accent transition bg-white text-gray-900"
className="mt-1 block w-full p-2 border-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
required
/>
</div>
@ -174,13 +174,13 @@ export const CreateCampaignModal: React.FC<CreateCampaignModalProps> = ({ isOpen
<button
type="button"
onClick={onClose}
className="bg-gray-200 text-gray-800 font-semibold py-2 px-4 rounded-md hover:bg-gray-300 transition-colors duration-300"
className="border-2 border-active-blue text-active-blue font-semibold py-2 px-6 rounded-full hover:bg-active-blue hover:text-white transition-colors duration-300"
>
Cancel
</button>
<button
type="submit"
className="bg-brand-accent text-white font-semibold py-2 px-4 rounded-md hover:bg-brand-dark-blue transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
className="bg-active-blue text-white font-semibold py-2 px-6 rounded-full hover:bg-active-blue/90 transition-colors duration-300 disabled:bg-grey-700 disabled:cursor-not-allowed"
disabled={isFormInvalid || !!error}
>
Create Campaign

View file

@ -77,27 +77,27 @@ const formatFeedbackText = (text: string): React.ReactNode => {
const RagStatusBadge: React.FC<{ status: RagStatus; isLarge?: boolean }> = ({ status, isLarge = false }) => {
let colorClasses = '';
let iconColor = '';
switch (status) {
case 'Red':
colorClasses = 'bg-red-50 border-red-200 text-red-800 shadow-red-100';
iconColor = 'text-red-600';
colorClasses = 'bg-error-light border-error text-error';
iconColor = 'text-error';
break;
case 'Amber':
colorClasses = 'bg-amber-50 border-amber-200 text-amber-800 shadow-amber-100';
iconColor = 'text-amber-600';
colorClasses = 'bg-warning-light border-warning text-black-title';
iconColor = 'text-warning';
break;
case 'Green':
colorClasses = 'bg-emerald-50 border-emerald-200 text-emerald-800 shadow-emerald-100';
iconColor = 'text-emerald-600';
colorClasses = 'bg-success-light border-success text-success';
iconColor = 'text-success';
break;
case 'Error':
colorClasses = 'bg-slate-50 border-slate-200 text-slate-700 shadow-slate-100';
iconColor = 'text-slate-500';
colorClasses = 'bg-grey-100 border-grey-300 text-grey-900';
iconColor = 'text-grey-700';
break;
}
const sizeClasses = isLarge ? 'px-4 py-1.5 text-sm rounded-xl border shadow-sm' : 'px-2.5 py-1 text-xs rounded-lg border shadow-sm';
const sizeClasses = isLarge ? 'px-4 py-1.5 text-sm rounded-[10px] border shadow-sm' : 'px-2.5 py-1 text-xs rounded-[10px] border shadow-sm';
return (
<div className={`inline-flex items-center font-bold tracking-wide ${sizeClasses} ${colorClasses} backdrop-blur-sm`}>
@ -128,43 +128,43 @@ const ResolveIssueModal: React.FC<{
};
return (
<div
<div
className="fixed inset-0 bg-slate-900/60 backdrop-blur-sm flex items-center justify-center z-50 transition-all duration-300"
onClick={onClose}
>
<div
className="bg-white rounded-2xl shadow-2xl p-8 w-full max-w-lg transform transition-all border border-white/20 ring-1 ring-black/5"
<div
className="bg-white rounded-[10px] shadow-2xl p-8 w-full max-w-lg transform transition-all border border-grey-300"
onClick={(e) => e.stopPropagation()}
>
<h3 className="text-2xl font-bold text-brand-dark-blue mb-2">Resolve Issue</h3>
<p className="text-slate-600 mb-6">Please provide a reason for manually resolving this issue.</p>
<div className="my-6 p-4 bg-slate-50 border border-slate-200 rounded-xl text-slate-700 italic text-sm">
<h3 className="text-2xl font-bold text-primary-blue mb-2">Resolve Issue</h3>
<p className="text-black-title mb-6">Please provide a reason for manually resolving this issue.</p>
<div className="my-6 p-4 bg-grey-100 border border-grey-300 rounded-[10px] text-black-title italic text-sm">
"{issueText}"
</div>
<form onSubmit={handleSubmit}>
<label htmlFor="resolution-reason" className="block text-sm font-bold text-slate-700 mb-2">Reason for resolution</label>
<label htmlFor="resolution-reason" className="block text-sm font-bold text-black-title mb-2">Reason for resolution</label>
<textarea
id="resolution-reason"
value={reason}
onChange={(e) => setReason(e.target.value)}
className="w-full p-4 border border-slate-200 rounded-xl focus:ring-2 focus:ring-brand-accent/50 focus:border-brand-accent transition-all bg-slate-50 focus:bg-white resize-none"
className="w-full p-4 border-2 border-grey-700 rounded-[10px] focus:ring-2 focus:ring-active-blue/50 focus:border-active-blue transition-all bg-grey-100 focus:bg-white resize-none text-black-title"
rows={4}
placeholder="e.g. 'Legal team has approved this exception via email...'"
required
/>
<div className="mt-8 flex justify-end gap-3">
<button
type="button"
onClick={onClose}
className="px-5 py-2.5 rounded-xl text-slate-600 font-semibold hover:bg-slate-100 transition-colors"
<button
type="button"
onClick={onClose}
className="px-6 py-2.5 rounded-full border-2 border-active-blue text-active-blue font-semibold hover:bg-active-blue hover:text-white transition-colors"
>
Cancel
</button>
<button
type="submit"
className="px-5 py-2.5 rounded-xl bg-brand-accent text-white font-bold shadow-lg shadow-brand-accent/30 hover:bg-brand-light-blue transition-all disabled:opacity-50 disabled:cursor-not-allowed"
<button
type="submit"
className="px-6 py-2.5 rounded-full bg-active-blue text-white font-bold shadow-lg shadow-active-blue/30 hover:bg-active-blue/90 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
disabled={!reason.trim()}
>
Submit Resolution

View file

@ -14,42 +14,42 @@ const ArrowRightIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (
export const Hero: React.FC<HeroProps> = ({ onGetStarted }) => {
return (
<div className="relative overflow-hidden bg-slate-900 min-h-[350px] sm:min-h-[400px] md:min-h-[500px] flex items-center">
<div className="relative overflow-hidden bg-primary-blue min-h-[350px] sm:min-h-[400px] md:min-h-[500px] flex items-center">
{/* Abstract background elements */}
<div className="absolute top-[-20%] right-[-10%] w-[600px] h-[600px] rounded-full bg-brand-accent/20 blur-3xl pointer-events-none"></div>
<div className="absolute bottom-[-20%] left-[-10%] w-[500px] h-[500px] rounded-full bg-brand-dark-blue/40 blur-3xl pointer-events-none"></div>
<div className="absolute top-[-20%] right-[-10%] w-[600px] h-[600px] rounded-full bg-active-blue/20 blur-3xl pointer-events-none"></div>
<div className="absolute bottom-[-20%] left-[-10%] w-[500px] h-[500px] rounded-full bg-electric-violet/20 blur-3xl pointer-events-none"></div>
{/* Grid Pattern Overlay */}
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-20 pointer-events-none"></div>
<div className="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 py-16 md:py-24 relative z-10 w-full">
<div className="max-w-3xl">
<div className="inline-flex items-center px-3 py-1 rounded-full bg-brand-accent/10 border border-brand-accent/20 text-brand-light-blue text-xs font-bold uppercase tracking-widest mb-6">
<span className="w-2 h-2 rounded-full bg-brand-light-blue mr-2 animate-pulse"></span>
<div className="inline-flex items-center px-3 py-1 rounded-full bg-active-blue/10 border border-active-blue/20 text-cyan-brand text-xs font-bold uppercase tracking-widest mb-6">
<span className="w-2 h-2 rounded-full bg-cyan-brand mr-2 animate-pulse"></span>
AI-Powered Compliance
</div>
<h1 className="text-5xl md:text-7xl font-extrabold text-white leading-tight mb-6">
Mod Comms <br/>
<span className="text-transparent bg-clip-text bg-gradient-to-r from-brand-light-blue to-white">
<span className="text-electric-violet">
Intelligent Review
</span>
</h1>
<p className="text-lg md:text-xl text-slate-300 mb-10 leading-relaxed max-w-2xl">
Streamline your creative approval process. Mod Comms analyses your assets against guidelines and best practice in seconds, not days.
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button
<button
onClick={onGetStarted}
className="group inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-brand-accent rounded-xl shadow-lg shadow-brand-accent/30 hover:bg-white hover:text-brand-dark-blue transition-all duration-300"
className="group inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-active-blue rounded-full shadow-lg shadow-active-blue/30 hover:bg-active-blue/90 transition-all duration-300"
>
Start Analysis
<ArrowRightIcon className="ml-2 h-5 w-5 transform group-hover:translate-x-1 transition-transform" />
</button>
<button
className="inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-white/5 border border-white/10 rounded-xl hover:bg-white/10 transition-all duration-300 backdrop-blur-sm"
<button
className="inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-white/5 border-2 border-white/20 rounded-full hover:bg-white/10 transition-all duration-300 backdrop-blur-sm"
>
View Documentation
</button>

View file

@ -30,21 +30,21 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ title, items, onAdd, on
};
return (
<div className="bg-white rounded-lg shadow-md p-6 border border-gray-200 flex flex-col h-full">
<h2 className="text-xl font-bold text-brand-dark-blue mb-4">{title}</h2>
<div className="bg-white rounded-[10px] shadow-md p-6 border border-grey-300 flex flex-col h-full">
<h2 className="text-xl font-bold text-primary-blue mb-4">{title}</h2>
<form onSubmit={handleSubmit} className="flex gap-2 mb-4">
<input
type="text"
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
placeholder={placeholder || `New ${title.slice(0, -1)}...`}
className="flex-grow p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent focus:border-brand-accent transition disabled:bg-gray-100 disabled:cursor-not-allowed"
className="flex-grow p-2 border-2 border-grey-700 rounded-[10px] focus:ring-2 focus:ring-active-blue focus:border-active-blue transition disabled:bg-grey-100 disabled:cursor-not-allowed text-black-title"
disabled={disabled}
/>
<button
type="submit"
className="bg-brand-accent text-white font-semibold py-2 px-4 rounded-md hover:bg-brand-dark-blue transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
className="bg-active-blue text-white font-semibold py-2 px-6 rounded-full hover:bg-active-blue/90 transition-colors duration-300 disabled:bg-grey-700 disabled:cursor-not-allowed"
disabled={!newItem.trim() || disabled}
>
Add
@ -57,12 +57,12 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ title, items, onAdd, on
{items.map((item) => (
<li
key={item}
className="flex items-center justify-between bg-gray-50 p-2.5 rounded-md border border-gray-200 group hover:border-brand-accent/30 transition-colors"
className="flex items-center justify-between bg-grey-100 p-2.5 rounded-[10px] border border-grey-300 group hover:border-active-blue/30 transition-colors"
>
<span className="text-gray-800">{item}</span>
<span className="text-black-title">{item}</span>
<button
onClick={() => onRemove(item)}
className={`text-gray-400 hover:text-red-600 transition-opacity ${disabled ? 'opacity-0 cursor-not-allowed' : 'opacity-0 group-hover:opacity-100'}`}
className={`text-grey-700 hover:text-error transition-opacity ${disabled ? 'opacity-0 cursor-not-allowed' : 'opacity-0 group-hover:opacity-100'}`}
title={`Remove ${item}`}
disabled={disabled}
>
@ -72,7 +72,7 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ title, items, onAdd, on
))}
</ul>
) : (
<div className="text-center py-8 text-gray-500 bg-gray-50 rounded-md">
<div className="text-center py-8 text-grey-700 bg-grey-100 rounded-[10px]">
No items found.
</div>
)}
@ -159,50 +159,50 @@ const UsersTab: React.FC = () => {
return (
<div className="space-y-8">
{/* Add User Section */}
<div className="bg-white rounded-lg shadow-md p-6 border border-gray-200">
<h3 className="text-lg font-bold text-brand-dark-blue mb-4 flex items-center gap-2">
<PlusIcon className="h-5 w-5 text-brand-accent" />
<div className="bg-white rounded-[10px] shadow-md p-6 border border-grey-300">
<h3 className="text-lg font-bold text-primary-blue mb-4 flex items-center gap-2">
<PlusIcon className="h-5 w-5 text-active-blue" />
Add New User
</h3>
<form onSubmit={handleAddUser} className="grid grid-cols-1 md:grid-cols-4 gap-4 items-end">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">Name</label>
<label className="block text-xs font-medium text-black-title mb-1">Name</label>
<input
type="text"
value={newName}
onChange={(e) => setNewName(e.target.value)}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent focus:border-brand-accent"
className="w-full p-2 border-2 border-grey-700 rounded-[10px] focus:ring-2 focus:ring-active-blue focus:border-active-blue text-black-title"
placeholder="e.g. John Smith"
required
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">Email</label>
<label className="block text-xs font-medium text-black-title mb-1">Email</label>
<input
type="email"
value={newEmail}
onChange={(e) => setNewEmail(e.target.value)}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent focus:border-brand-accent"
className="w-full p-2 border-2 border-grey-700 rounded-[10px] focus:ring-2 focus:ring-active-blue focus:border-active-blue text-black-title"
placeholder="user@example.com"
required
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">Agency</label>
<label className="block text-xs font-medium text-black-title mb-1">Agency</label>
<div className="relative">
<select
value={newAgency}
onChange={(e) => setNewAgency(e.target.value)}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent focus:border-brand-accent appearance-none"
className="w-full p-2 border-2 border-grey-700 rounded-[10px] focus:ring-2 focus:ring-active-blue focus:border-active-blue appearance-none text-black-title"
>
{agencies.map(a => <option key={a} value={a}>{a}</option>)}
</select>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-500 pointer-events-none" />
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-grey-700 pointer-events-none" />
</div>
</div>
<button
type="submit"
className="bg-brand-accent text-white font-semibold py-2 px-4 rounded-md hover:bg-brand-dark-blue transition-colors"
className="bg-active-blue text-white font-semibold py-2 px-6 rounded-full hover:bg-active-blue/90 transition-colors"
>
Add User
</button>
@ -210,49 +210,49 @@ const UsersTab: React.FC = () => {
</div>
{/* User List */}
<div className="bg-white rounded-lg shadow-md overflow-hidden border border-gray-200">
<div className="bg-white rounded-[10px] shadow-md overflow-hidden border border-grey-300">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<table className="min-w-full">
<thead className="bg-lime">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Email</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">Assigned Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Email</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Assigned Agency</th>
<th scope="col" className="relative px-6 py-3"><span className="sr-only">Actions</span></th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{users.map((user) => (
<tr key={user.id} className="hover:bg-gray-50">
<tbody className="divide-y divide-grey-300">
{users.map((user, index) => (
<tr key={user.id} className={index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}>
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center">
<div className="flex-shrink-0 h-8 w-8 rounded-full bg-brand-light-blue/20 flex items-center justify-center text-brand-accent">
<div className="flex-shrink-0 h-8 w-8 rounded-full bg-info-light flex items-center justify-center text-active-blue">
<UserIcon className="h-4 w-4" />
</div>
<div className="ml-4">
<div className="text-sm font-medium text-gray-900">{user.name}</div>
<div className="text-sm font-medium text-black-title">{user.name}</div>
</div>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">
{user.email}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">
<div className="relative max-w-xs">
<select
value={user.agency}
onChange={(e) => handleAgencyChange(user.id, e.target.value)}
className="w-full bg-white border border-gray-300 text-gray-700 py-1.5 pl-3 pr-8 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-brand-accent appearance-none"
className="w-full bg-white border-2 border-active-blue text-black-title py-1.5 pl-3 pr-8 rounded-[10px] text-sm focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none"
>
{agencies.map(a => <option key={a} value={a}>{a}</option>)}
</select>
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-gray-500 pointer-events-none" />
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-active-blue pointer-events-none" />
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
<button
onClick={() => handleDeleteUser(user.id)}
className="text-gray-400 hover:text-red-600 transition-colors"
className="text-grey-700 hover:text-error transition-colors"
title="Remove User"
>
<TrashIcon className="h-5 w-5" />
@ -321,17 +321,17 @@ export const Settings: React.FC<SettingsProps> = ({
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-brand-gray flex flex-col">
<div className="p-4 sm:p-6 lg:p-8 h-full bg-grey-100 flex flex-col">
<header className="mb-6 flex-shrink-0">
<h1 className="text-3xl lg:text-4xl font-bold text-brand-dark-blue">Settings</h1>
<p className="text-base lg:text-lg text-gray-600 mt-1">
<h1 className="text-3xl lg:text-4xl font-bold text-primary-blue">Settings</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">
Configure application defaults and user access.
</p>
</header>
<div className="flex-1 flex flex-col min-h-0">
{/* Tabs Header */}
<div className="border-b border-gray-200 bg-white px-4 rounded-t-lg shadow-sm flex-shrink-0">
<div className="border-b border-grey-300 bg-white px-4 rounded-t-[10px] shadow-sm flex-shrink-0">
<nav className="-mb-px flex space-x-8 overflow-x-auto" aria-label="Tabs">
{[
{ id: 'Campaigns', label: 'Campaigns' },
@ -347,8 +347,8 @@ export const Settings: React.FC<SettingsProps> = ({
className={`
whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors
${activeTab === tab.id
? 'border-brand-accent text-brand-accent'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
? 'border-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
}
`}
aria-current={activeTab === tab.id ? 'page' : undefined}
@ -387,18 +387,18 @@ export const Settings: React.FC<SettingsProps> = ({
{activeTab === 'SubChannels' && (
<div className="max-w-3xl space-y-4">
<div className="bg-white p-4 rounded-lg border border-gray-200 shadow-sm">
<label className="block text-sm font-medium text-gray-700 mb-2">Select Parent Channel</label>
<div className="bg-white p-4 rounded-[10px] border border-grey-300 shadow-sm">
<label className="block text-sm font-medium text-black-title mb-2">Select Parent Channel</label>
<div className="relative">
<select
value={selectedChannel}
onChange={(e) => setSelectedChannel(e.target.value)}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent appearance-none"
className={`w-full p-2 border-2 rounded-[10px] focus:ring-2 focus:ring-active-blue appearance-none text-black-title ${selectedChannel ? 'bg-info-light border-active-blue' : 'border-active-blue'}`}
>
<option value="" disabled>Select Channel</option>
{Object.keys(options.channels).map(c => <option key={c} value={c}>{c}</option>)}
</select>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-500 pointer-events-none"/>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-active-blue pointer-events-none"/>
</div>
</div>
@ -416,8 +416,8 @@ export const Settings: React.FC<SettingsProps> = ({
{activeTab === 'ProofTypes' && (
<div className="max-w-3xl space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="bg-white p-4 rounded-lg border border-gray-200 shadow-sm">
<label className="block text-sm font-medium text-gray-700 mb-2">Select Channel</label>
<div className="bg-white p-4 rounded-[10px] border border-grey-300 shadow-sm">
<label className="block text-sm font-medium text-black-title mb-2">Select Channel</label>
<div className="relative">
<select
value={selectedChannel}
@ -425,22 +425,22 @@ export const Settings: React.FC<SettingsProps> = ({
setSelectedChannel(e.target.value);
setSelectedSubChannel('');
}}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent appearance-none"
className={`w-full p-2 border-2 rounded-[10px] focus:ring-2 focus:ring-active-blue appearance-none text-black-title ${selectedChannel ? 'bg-info-light border-active-blue' : 'border-active-blue'}`}
>
<option value="" disabled>Select Channel</option>
{Object.keys(options.channels).map(c => <option key={c} value={c}>{c}</option>)}
</select>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-500 pointer-events-none"/>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-active-blue pointer-events-none"/>
</div>
</div>
<div className="bg-white p-4 rounded-lg border border-gray-200 shadow-sm">
<label className="block text-sm font-medium text-gray-700 mb-2">Select Sub-Channel</label>
<div className="bg-white p-4 rounded-[10px] border border-grey-300 shadow-sm">
<label className="block text-sm font-medium text-black-title mb-2">Select Sub-Channel</label>
<div className="relative">
<select
value={selectedSubChannel}
onChange={(e) => setSelectedSubChannel(e.target.value)}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent appearance-none disabled:bg-gray-100"
className={`w-full p-2 border-2 rounded-[10px] focus:ring-2 focus:ring-active-blue appearance-none text-black-title disabled:bg-grey-100 disabled:border-grey-300 ${selectedSubChannel ? 'bg-info-light border-active-blue' : 'border-active-blue'}`}
disabled={!selectedChannel}
>
<option value="" disabled>Select Sub-Channel</option>
@ -448,7 +448,7 @@ export const Settings: React.FC<SettingsProps> = ({
<option key={sc} value={sc}>{sc}</option>
))}
</select>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-500 pointer-events-none"/>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-active-blue pointer-events-none"/>
</div>
</div>
</div>
@ -456,8 +456,8 @@ export const Settings: React.FC<SettingsProps> = ({
<ManagementCard
title={selectedSubChannel ? `Proof Types for ${selectedSubChannel}` : "Proof Types"}
items={
(selectedChannel && selectedSubChannel)
? (options.channels[selectedChannel][selectedSubChannel] || [])
(selectedChannel && selectedSubChannel)
? (options.channels[selectedChannel][selectedSubChannel] || [])
: []
}
onAdd={(val) => onAddProofType(selectedChannel, selectedSubChannel, val)}
@ -474,39 +474,39 @@ export const Settings: React.FC<SettingsProps> = ({
{activeTab === 'Beta' && (
<div className="max-w-3xl space-y-6">
<div className="bg-white rounded-lg shadow-md p-6 border border-gray-200">
<h2 className="text-xl font-bold text-brand-dark-blue mb-2 flex items-center gap-2">
<div className="bg-white rounded-[10px] shadow-md p-6 border border-grey-300">
<h2 className="text-xl font-bold text-primary-blue mb-2 flex items-center gap-2">
<span className="relative flex h-3 w-3">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-brand-accent opacity-75"></span>
<span className="relative inline-flex rounded-full h-3 w-3 bg-brand-accent"></span>
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-electric-violet opacity-75"></span>
<span className="relative inline-flex rounded-full h-3 w-3 bg-electric-violet"></span>
</span>
Beta Features
</h2>
<p className="text-gray-600 mb-6">
<p className="text-black-title mb-6">
Explore experimental features currently in development. These tools are functional but may change over time.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<button
<button
onClick={() => onNavigate('WIP Reviewer')}
className="flex flex-col items-start p-4 rounded-lg border border-gray-200 hover:border-brand-accent hover:bg-blue-50/50 transition-all duration-300 group text-left"
className="flex flex-col items-start p-4 rounded-[10px] border border-grey-300 hover:border-active-blue hover:bg-info-light transition-all duration-300 group text-left"
>
<div className="p-2 rounded-md bg-brand-light-blue/10 text-brand-accent mb-3 group-hover:scale-110 transition-transform">
<div className="p-2 rounded-[10px] bg-info-light text-active-blue mb-3 group-hover:scale-110 transition-transform">
<ClipboardIcon className="h-6 w-6" />
</div>
<h3 className="font-bold text-brand-dark-blue mb-1">WIP Reviewer</h3>
<p className="text-sm text-gray-500">Early-stage feedback on assets before they are finalized.</p>
<h3 className="font-bold text-primary-blue mb-1">WIP Reviewer</h3>
<p className="text-sm text-grey-900">Early-stage feedback on assets before they are finalized.</p>
</button>
<button
<button
onClick={() => onNavigate('CopyGenAI')}
className="flex flex-col items-start p-4 rounded-lg border border-gray-200 hover:border-brand-accent hover:bg-blue-50/50 transition-all duration-300 group text-left"
className="flex flex-col items-start p-4 rounded-[10px] border border-grey-300 hover:border-electric-violet hover:bg-info-light transition-all duration-300 group text-left"
>
<div className="p-2 rounded-md bg-purple-100 text-purple-600 mb-3 group-hover:scale-110 transition-transform">
<div className="p-2 rounded-[10px] bg-electric-violet/10 text-electric-violet mb-3 group-hover:scale-110 transition-transform">
<CopyGenAIIcon className="h-6 w-6" />
</div>
<h3 className="font-bold text-brand-dark-blue mb-1">CopyGenAI</h3>
<p className="text-sm text-gray-500">Generate and refine marketing copy with AI assistance.</p>
<h3 className="font-bold text-primary-blue mb-1">CopyGenAI</h3>
<p className="text-sm text-grey-900">Generate and refine marketing copy with AI assistance.</p>
</button>
</div>
</div>

View file

@ -27,15 +27,15 @@ interface SidebarProps {
export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userName, userEmail }) => {
return (
<aside className="w-72 flex-shrink-0 bg-[#0f172a] text-slate-200 flex flex-col border-r border-slate-800 font-sans">
<aside className="w-72 flex-shrink-0 bg-primary-blue text-slate-200 flex flex-col border-r border-white/10 font-sans">
{/* Brand Header */}
<div className="h-24 flex items-center px-8 border-b border-slate-800/60">
<BarclaysLogo className="h-8 w-auto text-white" />
<div className="h-24 flex items-center px-8 border-b border-white/10">
<BarclaysLogo className="h-8 w-auto text-cyan-brand" />
<div className="ml-3 flex flex-col">
<span className="text-lg font-bold tracking-tight text-white leading-tight">
Mod Comms
</span>
<span className="text-xs text-slate-400 uppercase tracking-widest font-semibold">
<span className="text-xs text-electric-violet uppercase tracking-widest font-semibold">
Compliance AI
</span>
</div>
@ -53,11 +53,11 @@ export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userNa
key={item.name}
onClick={() => !isComingSoon && onNavigate(item.name)}
className={`group w-full flex items-center px-4 py-3.5 text-left text-sm font-medium rounded-xl transition-all duration-300 ease-in-out ${
isActive
? 'bg-gradient-to-r from-brand-accent to-brand-light-blue text-white shadow-lg shadow-brand-accent/20'
isActive
? 'bg-white text-primary-blue shadow-lg'
: isComingSoon
? 'text-slate-600 cursor-not-allowed'
: 'text-slate-400 hover:bg-white/5 hover:text-white'
: 'text-slate-300 hover:bg-white/10 hover:text-white'
}`}
aria-current={isActive ? 'page' : undefined}
disabled={isComingSoon}
@ -65,7 +65,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userNa
<Icon className={`h-5 w-5 mr-4 transition-transform duration-300 ${isActive ? 'scale-110' : 'group-hover:scale-110'}`} />
<span className="flex-1 tracking-wide">{item.name}</span>
{isActive && (
<div className="w-1.5 h-1.5 rounded-full bg-white/80 shadow-glow"></div>
<div className="w-1.5 h-1.5 rounded-full bg-active-blue"></div>
)}
</button>
);
@ -73,16 +73,16 @@ export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userNa
</nav>
{/* User Profile Snippet */}
<div className="p-4 border-t border-slate-800/60 bg-[#0b1120]">
<div className="p-4 border-t border-white/10 bg-primary-blue/80">
<button
onClick={() => onNavigate('Profile')}
className={`group w-full flex items-center gap-3 p-3 rounded-xl text-left transition-all duration-200 ${
activeItem === 'Profile'
? 'bg-slate-800'
: 'hover:bg-slate-800'
? 'bg-white/10'
: 'hover:bg-white/10'
}`}
>
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-brand-dark-blue to-brand-accent flex items-center justify-center ring-2 ring-white/10 group-hover:ring-brand-light-blue/50 transition-all">
<div className="w-10 h-10 rounded-full bg-active-blue flex items-center justify-center ring-2 ring-white/20 group-hover:ring-active-blue/50 transition-all">
<UserIcon className="h-5 w-5 text-white" />
</div>
<div className="overflow-hidden">

View file

@ -5,17 +5,48 @@
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Barclays Mod Comms</title>
<!-- Google Fonts - Inter (Barclays Effra alternative) -->
<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=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'Arial', 'sans-serif'],
},
colors: {
'brand-dark-blue': '#001f5a',
'brand-light-blue': '#00a3e0',
'brand-accent': '#0070c0',
'brand-gray': '#f4f6f8',
'sidebar-bg': '#1f2937',
// Legacy colors (kept for backwards compatibility during migration)
'brand-dark-blue': '#1A2142',
'brand-light-blue': '#00AEEF',
'brand-accent': '#006DE3',
'brand-gray': '#F6F6F6',
'sidebar-bg': '#1A2142',
// Primary Brand Colors
'primary-blue': '#1A2142',
'active-blue': '#006DE3',
'electric-violet': '#7A0FF9',
'lime': '#C3FB5A',
'cyan-brand': '#00AEEF',
// Functional Colors
'grey-100': '#F6F6F6',
'grey-300': '#E2E2E2',
'grey-700': '#8E8E8E',
'grey-900': '#515151',
'black-title': '#272727',
// Status Colors
'info-light': '#E7F0FB',
'success': '#09821F',
'success-light': '#E9F4EA',
'warning': '#FFBA00',
'warning-light': '#FFF8E7',
'error': '#E3000F',
'error-light': '#FDE7E9',
},
animation: {
'slow-ping': 'ping 2s cubic-bezier(0, 0, 0.2, 1) infinite',