Restyle full application from Barclays to Oliver Agency brand

Replace entire Barclays colour palette (navy #1A2142, lime #C3FB5A, violet
#7A0FF9) with Oliver brand tokens: black #1A1A1A, gold #FFCB05, orange
#FF5C00, azure #0487B6, sky #5DF5EA, grey #EFEFEF, green #09821F.

- Switch font from Inter/Barclays Effra to Arial (system font)
- Add new Oliver logo asset (BAR-ModComms-logo-v4.png)
- Sidebar: black background, new logo, azure active state
- Hero: orange "Intelligent Review" text, hide AI-Powered tagline
- Hide ChecksOverview on Home page per Oliver design
- Toast notification: orange background with black text
- All tables: sky headers, alternating white/grey rows
- Campaign badges: gold "In Progress", green "Completed"
- Analytics: grey KPI cards, sky accent on Key Insight, oliver trend colours
- All buttons: azure fill, pill-shaped (rounded-full)
- All tabs/toggles/dropdowns: azure accent colour
- Update HTML title to "Mod Comms - Intelligent Review"
- Default border radius set to 10px

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-03-03 10:16:26 +00:00
parent 44fa8ba527
commit 4302b9391a
29 changed files with 652 additions and 671 deletions

View file

@ -49,9 +49,9 @@ const App: React.FC = () => {
// Show loading spinner during MSAL authentication interactions
if (inProgress !== InteractionStatus.None) {
return (
<div className="fixed inset-0 bg-primary-blue flex items-center justify-center">
<div className="fixed inset-0 bg-oliver-black flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<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">
<svg className="animate-spin h-12 w-12 text-oliver-azure" 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>
@ -932,7 +932,8 @@ const AppContent: React.FC<{ msalInstance: any }> = ({ msalInstance }) => {
return (
<>
<Hero onGetStarted={() => handleNavigate('Campaigns')} />
<ChecksOverview />
{/* Hidden per Oliver design — client may want it back */}
{/* <ChecksOverview /> */}
</>
);
}
@ -941,9 +942,9 @@ const AppContent: React.FC<{ msalInstance: any }> = ({ msalInstance }) => {
// Show loading spinner while user profile is loading
if (isUserLoading) {
return (
<div className="fixed inset-0 bg-primary-blue flex items-center justify-center">
<div className="fixed inset-0 bg-oliver-black flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<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">
<svg className="animate-spin h-12 w-12 text-oliver-azure" 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>
@ -954,7 +955,7 @@ const AppContent: React.FC<{ msalInstance: any }> = ({ msalInstance }) => {
}
// Determine background color based on view to avoid grey bar on Home view
const mainBgColor = currentView === 'Home' ? 'bg-white' : 'bg-grey-100';
const mainBgColor = currentView === 'Home' ? 'bg-white' : 'bg-oliver-grey';
// Get user info from MSAL for sidebar display
const userInfo = getUserInfo(msalInstance);
@ -982,15 +983,15 @@ const AppContent: React.FC<{ msalInstance: any }> = ({ msalInstance }) => {
{/* Model fallback notification toast */}
{notification && (
<div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-50 flex items-start gap-3 bg-gray-800 text-white text-sm px-5 py-3.5 rounded-xl shadow-2xl max-w-md w-full mx-4 animate-fade-in">
<svg className="w-5 h-5 text-yellow-400 shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-50 flex items-start gap-3 bg-oliver-orange text-oliver-black text-sm px-5 py-3.5 rounded-xl shadow-2xl max-w-md w-full mx-4 animate-fade-in">
<svg className="w-5 h-5 text-oliver-black shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
</svg>
<div className="flex-1">
<p className="font-semibold text-yellow-300 mb-0.5">AI Model Notice</p>
<p className="text-gray-200 leading-snug">{notification}</p>
<p className="font-semibold text-oliver-black mb-0.5">AI Model Notice</p>
<p className="text-oliver-black leading-snug">{notification}</p>
</div>
<button onClick={() => setNotification(null)} className="text-gray-400 hover:text-white shrink-0">
<button onClick={() => setNotification(null)} className="text-oliver-black/60 hover:text-oliver-black shrink-0">
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>

View file

@ -25,21 +25,21 @@ export const AgencyFilterBar: React.FC<AgencyFilterBarProps> = ({ selectedAgency
return (
<div className="bg-white border-b border-grey-300 px-6 py-3 flex items-center gap-3 flex-shrink-0">
<label className="text-sm font-medium text-primary-blue whitespace-nowrap">
<label className="text-sm font-medium text-oliver-black whitespace-nowrap">
Filter by Agency:
</label>
<div className="relative max-w-xs">
<select
value={selectedAgencyId || ''}
onChange={(e) => onAgencyChange(e.target.value || null)}
className="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 min-w-[200px]"
className="bg-white border-2 border-oliver-azure text-oliver-black py-1.5 pl-3 pr-8 rounded-[10px] text-sm focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none min-w-[200px]"
>
<option value="">All Agencies</option>
{agencies.map(a => (
<option key={a.id} value={a.id}>{a.name}</option>
))}
</select>
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-active-blue pointer-events-none" />
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-oliver-azure pointer-events-none" />
</div>
</div>
);

View file

@ -24,9 +24,9 @@ const TrendIndicator: React.FC<{ trend: 'up' | 'down' | 'stable' }> = ({ trend }
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-error"><DownArrow/> Declining</div>;
return <div className="flex items-center gap-1.5 text-oliver-orange"><DownArrow/> Declining</div>;
}
return <div className="flex items-center gap-1.5 text-grey-700"><StableLine/> Stable</div>;
return <div className="flex items-center gap-1.5 text-oliver-black"><StableLine/> Stable</div>;
};
export const Analytics: React.FC<{ agencyId?: string; isAdmin?: boolean }> = ({ agencyId, isAdmin }) => {
@ -82,8 +82,8 @@ export const Analytics: React.FC<{ agencyId?: string; isAdmin?: boolean }> = ({
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-white">
<header className="mb-8">
<h1 className="text-3xl lg:text-4xl font-semibold 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>
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">Performance analytics</h1>
<p className="text-base lg:text-lg text-oliver-black mt-1">Overall usage and performance statistics for the tool.</p>
</header>
{/* Stats Cards */}
@ -92,13 +92,13 @@ export const Analytics: React.FC<{ agencyId?: string; isAdmin?: boolean }> = ({
{stats.map((stat) => {
const Icon = stat.icon;
return (
<div key={stat.name} className="bg-white rounded-[10px] p-6 flex items-start shadow-sm transition-all hover:shadow-lg">
<div className="p-3 rounded-full bg-white text-black-title mr-4 flex-shrink-0">
<div key={stat.name} className="bg-oliver-grey rounded-[10px] p-6 flex items-start border-2 border-grey-300 transition-all hover:shadow-lg">
<div className="p-3 rounded-full bg-white text-oliver-black mr-4 flex-shrink-0">
<Icon className="h-9 w-9" />
</div>
<div>
<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>
<p className="text-sm font-medium text-oliver-black">{stat.name}</p>
<p className="text-3xl font-bold text-oliver-black mt-1">{stat.value}</p>
</div>
</div>
);
@ -109,18 +109,18 @@ export const Analytics: React.FC<{ agencyId?: string; isAdmin?: boolean }> = ({
{/* Per-Agency Breakdown (admin only) */}
{isAdmin && agencyAnalytics.length > 0 && (
<section className="mt-10">
<h2 className="text-2xl font-semibold text-primary-blue mb-4">Agency performance</h2>
<h2 className="text-2xl font-semibold text-oliver-black mb-4">Agency performance</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">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proofs Reviewed</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">Failed</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Errors</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Legal Review</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proofs Reviewed</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Pass Rate</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Failed</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Errors</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Legal Review</th>
</tr>
</thead>
<tbody className="divide-y divide-grey-300">
@ -136,23 +136,23 @@ export const Analytics: React.FC<{ agencyId?: string; isAdmin?: boolean }> = ({
? 'bg-blue-50'
: index % 2 === 0
? 'bg-white'
: 'bg-grey-100'
: 'bg-oliver-grey'
}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-black-title">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">
{agency.agency_name}
{isSelected && <span className="ml-2 text-xs text-primary-blue font-normal">(selected)</span>}
{isSelected && <span className="ml-2 text-xs text-oliver-black font-normal">(selected)</span>}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{agency.total_reviews}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-black-title">
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{agency.total_reviews}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-oliver-black">
<div className="flex items-center">
<span className={`h-2.5 w-2.5 rounded-full mr-3 ${rate >= 80 ? 'bg-success' : rate < 70 ? 'bg-error' : 'bg-warning'}`}></span>
{rate}%
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{agency.failed}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{agency.errors}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{agency.legal_review}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{agency.failed}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{agency.errors}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{agency.legal_review}</td>
</tr>
);
})}
@ -165,14 +165,14 @@ export const Analytics: React.FC<{ agencyId?: string; isAdmin?: boolean }> = ({
{/* AI Performance Summary */}
<section className="mt-10">
<h2 className="text-2xl font-semibold 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">
<h2 className="text-2xl font-semibold text-oliver-black mb-4">AI performance summary</h2>
<div className="bg-white border-2 border-oliver-sky border-l-4 text-oliver-black p-6 rounded-[10px] shadow-md flex items-start gap-4" style={{ borderLeftColor: '#5DF5EA' }}>
<div className="flex-shrink-0">
<LightbulbIcon className="h-7 w-7 text-electric-violet" />
<LightbulbIcon className="h-7 w-7 text-oliver-orange" />
</div>
<div>
<p className="font-semibold text-primary-blue">Key Insight (Last 7 Days):</p>
<p className="mt-1 text-black-title">
<p className="font-semibold text-oliver-black">Key Insight (Last 7 Days):</p>
<p className="mt-1 text-oliver-black">
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>
@ -181,29 +181,29 @@ export const Analytics: React.FC<{ agencyId?: string; isAdmin?: boolean }> = ({
{/* Agent Performance Table */}
<section className="mt-10">
<h2 className="text-2xl font-semibold text-primary-blue mb-4">Agent performance (last 7 days)</h2>
<h2 className="text-2xl font-semibold text-oliver-black 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">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<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>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Agent Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Pass Rate</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Avg. Issues per Proof</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Performance Trend</th>
</tr>
</thead>
<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`}>
<tr key={agent.name} className={index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">{agent.name}</td>
<td className={`px-6 py-4 whitespace-nowrap text-sm font-semibold text-oliver-black`}>
<div className="flex items-center">
<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>
<span className={`h-2.5 w-2.5 rounded-full mr-3 ${agent.passRate >= 80 ? 'bg-oliver-green' : agent.passRate < 70 ? 'bg-oliver-gold' : 'bg-oliver-orange'}`}></span>
{agent.passRate}%
</div>
</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 text-oliver-black">{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

@ -128,7 +128,7 @@ export const AssetPreview: React.FC<AssetPreviewProps> = ({ file, previewUrl, fi
style={{ minHeight: '300px', maxHeight: 'calc(100vh - 9rem)' }}
>
<DocumentIcon className="h-20 w-20 text-gray-400 mb-4" />
<p className="text-lg font-semibold text-primary-blue break-all">{displayName}</p>
<p className="text-lg font-semibold text-oliver-black break-all">{displayName}</p>
<p className="text-sm text-gray-500">{fileType}</p>
<p className="text-sm text-gray-500 mt-2">No preview available for this file type.</p>
</div>

View file

@ -23,40 +23,40 @@ 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">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<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>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Agent Flagged</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">User Comments</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody className="divide-y divide-grey-300">
{items.length > 0 ? items.map((item, index) => (
<tr
key={item.id}
className={`hover:bg-info-light cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
className={`hover:bg-oliver-grey cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'}`}
onClick={() => onNavigate(item)}
title={`Click to view Version ${item.version} of ${item.proofName}`}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-active-blue">{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">
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-oliver-azure">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.submitAgency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.agentFlagged}</td>
<td className="px-6 py-4 text-sm text-oliver-black">
<div className="max-w-xs break-words" title={item.comments}>
{item.comments || <span className="italic text-grey-700">No comment</span>}
{item.comments || <span className="italic text-oliver-black/60">No comment</span>}
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{formatDate(item.timestamp)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{formatDate(item.timestamp)}</td>
</tr>
)) : (
<tr>
<td colSpan={7} className="text-center py-10 text-grey-700">
<td colSpan={7} className="text-center py-10 text-oliver-black/60">
There are currently no flagged items to audit.
</td>
</tr>
@ -69,42 +69,42 @@ 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">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<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>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Agent</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Agent Issue</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">User Comments</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody className="divide-y divide-grey-300">
{items.length > 0 ? items.map((item, index) => (
<tr
key={item.id}
className={`hover:bg-info-light cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
className={`hover:bg-oliver-grey cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'}`}
onClick={() => onNavigate(item)}
title={`Click to view Version ${item.version} of ${item.proofName}`}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-active-blue">{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">
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-oliver-azure">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.submitAgency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.agent}</td>
<td className="px-6 py-4 text-sm text-oliver-black">
<div className="max-w-xs break-words" title={item.issue}>{item.issue}</div>
</td>
<td className="px-6 py-4 text-sm text-black-title">
<td className="px-6 py-4 text-sm text-oliver-black">
<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-black-title">{formatDate(item.timestamp)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{formatDate(item.timestamp)}</td>
</tr>
)) : (
<tr>
<td colSpan={8} className="text-center py-10 text-grey-700">
<td colSpan={8} className="text-center py-10 text-oliver-black/60">
There are currently no resolved items to audit.
</td>
</tr>
@ -117,38 +117,38 @@ 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">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<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>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Version</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Submitter</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Submit Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Error Summary</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody className="divide-y divide-grey-300">
{items.length > 0 ? items.map((item, index) => (
<tr
key={item.id}
className={`hover:bg-info-light cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
className={`hover:bg-oliver-grey cursor-pointer ${index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'}`}
onClick={() => onNavigate(item)}
title={`Click to view Version ${item.version} of ${item.proofName}`}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-active-blue">{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">
<td className="px-6 py-4 whitespace-nowrap text-sm font-semibold text-oliver-azure">{item.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">Version {item.version}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.submitter}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{item.submitAgency}</td>
<td className="px-6 py-4 text-sm text-oliver-black">
<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-black-title">{formatDate(item.timestamp)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{formatDate(item.timestamp)}</td>
</tr>
)) : (
<tr>
<td colSpan={6} className="text-center py-10 text-grey-700">
<td colSpan={6} className="text-center py-10 text-oliver-black/60">
There are currently no analysis errors to audit.
</td>
</tr>
@ -165,8 +165,8 @@ export const Auditing: React.FC<AuditingProps> = ({ flaggedItems, resolvedItems,
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-white">
<header className="mb-8">
<h1 className="text-3xl lg:text-4xl font-semibold 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>
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">Auditing</h1>
<p className="text-base lg:text-lg text-oliver-black mt-1">Review and investigate all user-flagged feedback.</p>
</header>
<div className="mb-6 border-b border-grey-300">
@ -175,8 +175,8 @@ export const Auditing: React.FC<AuditingProps> = ({ flaggedItems, resolvedItems,
onClick={() => setActiveTab('Flags')}
className={`whitespace-nowrap py-3 px-1 border-b-2 font-semibold text-sm transition-colors ${
activeTab === 'Flags'
? 'border-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
? 'border-oliver-azure text-oliver-azure'
: 'border-transparent text-oliver-black hover:text-oliver-azure 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-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
? 'border-oliver-azure text-oliver-azure'
: 'border-transparent text-oliver-black hover:text-oliver-azure 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-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
? 'border-oliver-azure text-oliver-azure'
: 'border-transparent text-oliver-black hover:text-oliver-azure hover:border-grey-300'
}`}
aria-current={activeTab === 'Errors' ? 'page' : undefined}
>

View file

@ -232,16 +232,16 @@ const StatusBadge: React.FC<{ status: string }> = ({ status }) => {
let colorClasses = '';
switch (status) {
case 'In Progress':
colorClasses = 'bg-warning text-black-title';
colorClasses = 'bg-oliver-gold text-oliver-black';
break;
case 'Completed':
colorClasses = 'bg-success text-white';
colorClasses = 'bg-oliver-green text-white';
break;
case 'Needs Review':
colorClasses = 'bg-warning-light text-black-title';
colorClasses = 'bg-warning-light text-oliver-black';
break;
default:
colorClasses = 'bg-grey-100 text-black-title';
colorClasses = 'bg-oliver-grey text-oliver-black';
}
return (
<span className={`px-2.5 py-0.5 text-xs font-semibold rounded-full ${colorClasses}`}>
@ -260,10 +260,10 @@ const OverallStatusBadge: React.FC<{ status: OverallStatus }> = ({ status }) =>
colorClasses = 'bg-error text-white';
break;
case 'Requires Manual Legal Review':
colorClasses = 'bg-warning text-black-title';
colorClasses = 'bg-warning text-oliver-black';
break;
case 'Analysis Error':
colorClasses = 'bg-grey-300 text-black-title';
colorClasses = 'bg-grey-300 text-oliver-black';
break;
}
@ -379,17 +379,17 @@ const CampaignList: React.FC<{
}, [filteredAndSortedCampaigns]);
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-active-blue 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-oliver-azure appearance-none cursor-pointer';
let colorClasses = '';
switch (status) {
case 'In Progress':
colorClasses = 'bg-warning text-black-title';
colorClasses = 'bg-oliver-gold text-oliver-black';
break;
case 'Completed':
colorClasses = 'bg-success text-white';
colorClasses = 'bg-oliver-green text-white';
break;
default:
colorClasses = 'bg-grey-100 text-black-title';
colorClasses = 'bg-oliver-grey text-oliver-black';
}
return `${baseClasses} ${colorClasses}`;
};
@ -468,22 +468,22 @@ 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-semibold text-primary-blue">Campaigns</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">Manage your campaigns and proof collections.</p>
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">Campaigns</h1>
<p className="text-base lg:text-lg text-oliver-black 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-black-title whitespace-nowrap">Show Completed</label>
<label htmlFor="show-completed" className="text-sm font-medium text-oliver-black whitespace-nowrap">Show Completed</label>
<ToggleSwitch enabled={showCompleted} onChange={setShowCompleted} />
</div>
<div className="flex items-center gap-2">
<label htmlFor="my-campaigns" className="text-sm font-medium text-black-title whitespace-nowrap">My Campaigns Only</label>
<label htmlFor="my-campaigns" className="text-sm font-medium text-oliver-black whitespace-nowrap">My Campaigns Only</label>
<ToggleSwitch enabled={showMyCampaignsOnly} onChange={setShowMyCampaignsOnly} />
</div>
{!readOnly && (
<button
onClick={onOpenModal}
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"
className="flex items-center gap-2 bg-oliver-azure text-white font-semibold py-2.5 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors duration-300"
>
<PlusIcon className="h-5 w-5" />
Create New Campaign
@ -496,14 +496,14 @@ const CampaignList: React.FC<{
<section>
{/* Bulk Actions Bar */}
{!readOnly && selectedCampaigns.size > 0 && (
<div className="mb-4 bg-info-light border border-active-blue rounded-[10px] p-3 flex items-center justify-between">
<div className="mb-4 bg-oliver-grey border border-oliver-azure rounded-[10px] p-3 flex items-center justify-between">
<div className="flex items-center gap-4">
<span className="text-sm font-medium text-active-blue">
<span className="text-sm font-medium text-oliver-azure">
{selectedCampaigns.size} campaign{selectedCampaigns.size !== 1 ? 's' : ''} selected
</span>
<button
onClick={() => setSelectedCampaigns(new Set())}
className="text-sm text-active-blue hover:text-primary-blue underline"
className="text-sm text-oliver-azure hover:text-oliver-black underline"
>
Clear selection
</button>
@ -522,7 +522,7 @@ const CampaignList: React.FC<{
<div className="bg-white rounded-[10px] shadow-md overflow-hidden border border-grey-300">
<div className="overflow-x-auto">
<table className="min-w-full">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
{!readOnly && (
<th scope="col" className="px-4 py-3 text-left">
@ -533,7 +533,7 @@ const CampaignList: React.FC<{
if (el) el.indeterminate = isIndeterminate;
}}
onChange={handleSelectAll}
className="h-4 w-4 text-active-blue border-grey-300 rounded focus:ring-active-blue cursor-pointer"
className="h-4 w-4 text-oliver-azure border-grey-300 rounded focus:ring-oliver-azure cursor-pointer"
aria-label="Select all campaigns"
/>
</th>
@ -550,12 +550,12 @@ const CampaignList: React.FC<{
<th
key={key}
scope="col"
className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider cursor-pointer select-none hover:text-active-blue"
className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider cursor-pointer select-none hover:text-oliver-azure"
onClick={() => handleSort(key)}
>
<span className="inline-flex items-center gap-1">
{label}
<span className={`text-[10px] leading-none ${sortKey === key ? 'text-active-blue' : 'text-grey-700'}`}>
<span className={`text-[10px] leading-none ${sortKey === key ? 'text-oliver-azure' : 'text-oliver-black/60'}`}>
{sortKey === key ? (sortDirection === 'asc' ? '\u25B2' : '\u25BC') : '\u25B4\u25BE'}
</span>
</span>
@ -563,7 +563,7 @@ const CampaignList: React.FC<{
))}
{!readOnly && <th scope="col" className="relative px-4 py-3"><span className="sr-only">Actions</span></th>}
</tr>
<tr className="bg-grey-100">
<tr className="bg-oliver-grey">
{!readOnly && <td className="px-4 py-1"></td>}
{(['name', 'proofs', 'status', 'agencyLead', 'agency', 'brandGuidelines', 'lastModified'] as SortKey[]).map((key) => (
<td key={key} className="px-6 py-1">
@ -573,7 +573,7 @@ const CampaignList: React.FC<{
onChange={(e) => handleColumnFilterChange(key, e.target.value)}
onClick={(e) => e.stopPropagation()}
placeholder="Filter..."
className="w-full text-xs py-1 px-2 border border-grey-300 rounded bg-white focus:outline-none focus:border-active-blue focus:ring-1 focus:ring-active-blue"
className="w-full text-xs py-1 px-2 border border-grey-300 rounded bg-white focus:outline-none focus:border-oliver-azure focus:ring-1 focus:ring-oliver-azure"
/>
</td>
))}
@ -586,7 +586,7 @@ const CampaignList: React.FC<{
return (
<tr
key={campaign.name}
className={`hover:bg-info-light cursor-pointer ${isSelected ? 'bg-info-light' : index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}`}
className={`hover:bg-oliver-grey cursor-pointer ${isSelected ? 'bg-oliver-grey' : index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'}`}
onClick={() => onSelectCampaign(campaign.name)}
>
{!readOnly && (
@ -596,13 +596,13 @@ const CampaignList: React.FC<{
checked={isSelected}
onChange={() => {}} // Handled by onClick
onClick={(e) => handleSelectCampaign(campaign.name, e)}
className="h-4 w-4 text-active-blue border-grey-300 rounded focus:ring-active-blue cursor-pointer"
className="h-4 w-4 text-oliver-azure border-grey-300 rounded focus:ring-oliver-azure cursor-pointer"
aria-label={`Select ${campaign.name}`}
/>
</td>
)}
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">{campaign.name}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{campaign.proofs}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">{campaign.name}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{campaign.proofs}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm w-40">
<div className="relative">
<select
@ -616,19 +616,19 @@ 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-black-title" />
<ChevronDownIcon className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 h-full w-4 text-oliver-black" />
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{campaign.agencyLead}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{campaign.agency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{campaign.brandGuidelines}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{formatDate(campaign.lastModified)}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{campaign.agencyLead}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{campaign.agency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{campaign.brandGuidelines}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{formatDate(campaign.lastModified)}</td>
{!readOnly && (
<td className="px-4 py-4 whitespace-nowrap text-sm text-right">
<button
onClick={(e) => handleSingleDelete(campaign, e)}
disabled={isDeleting}
className="p-2 text-grey-700 rounded-full hover:bg-error-light hover:text-error transition-colors disabled:opacity-50"
className="p-2 text-oliver-black/60 rounded-full hover:bg-error-light hover:text-error transition-colors disabled:opacity-50"
title={`Delete ${campaign.name}`}
aria-label={`Delete ${campaign.name}`}
>
@ -754,12 +754,12 @@ const UploadProofModal: React.FC<{
{/* Header */}
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 border-b border-grey-300 flex justify-between items-start">
<div>
<h3 className="text-2xl font-bold text-primary-blue" id="modal-title">Upload New Proof</h3>
<p className="text-sm text-grey-900 mt-1">Drag and drop your proof below to start AI analysis.</p>
<h3 className="text-2xl font-bold text-oliver-black" id="modal-title">Upload New Proof</h3>
<p className="text-sm text-oliver-black mt-1">Drag and drop your proof below to start AI analysis.</p>
</div>
<button
onClick={onClose}
className="rounded-full p-2 text-grey-700 hover:bg-grey-100 hover:text-black-title transition-colors"
className="rounded-full p-2 text-oliver-black/60 hover:bg-oliver-grey hover:text-oliver-black transition-colors"
>
<XIcon className="h-6 w-6" />
</button>
@ -771,10 +771,10 @@ const UploadProofModal: React.FC<{
<div className="space-y-6">
{/* Proof Name */}
<div>
<label htmlFor="proof-name" className="block text-sm font-bold text-primary-blue mb-2">Proof Name</label>
<label htmlFor="proof-name" className="block text-sm font-bold text-oliver-black mb-2">Proof Name</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<DocumentIcon className="h-5 w-5 text-grey-700" />
<DocumentIcon className="h-5 w-5 text-oliver-black/60" />
</div>
<input
id="proof-name"
@ -783,13 +783,13 @@ const UploadProofModal: React.FC<{
onChange={(e) => setProofName(e.target.value)}
placeholder="e.g., Q4 Hero Instagram Post"
disabled={isLoading}
className="w-full rounded-[10px] border-2 border-grey-700 shadow-sm focus:border-active-blue focus:ring-active-blue p-3 pl-10 bg-white transition-all text-black-title"
className="w-full rounded-[10px] border-2 border-oliver-azure shadow-sm focus:border-oliver-azure focus:ring-oliver-azure p-3 pl-10 bg-white transition-all text-oliver-black"
required
/>
</div>
{isNewVersion && (
<p className="text-xs text-active-blue mt-2 p-2 bg-info-light rounded-[10px] flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-active-blue"></span>
<p className="text-xs text-oliver-azure mt-2 p-2 bg-oliver-grey rounded-[10px] flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-oliver-azure"></span>
A proof with this name already exists. This will be uploaded as a new version.
</p>
)}
@ -798,60 +798,60 @@ const UploadProofModal: React.FC<{
{/* Dropdowns Grid */}
<div className="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-2">
<div>
<label htmlFor="proof-channel" className="block text-sm font-bold text-primary-blue mb-2">Channel</label>
<label htmlFor="proof-channel" className="block text-sm font-bold text-oliver-black mb-2">Channel</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<ChannelIcon className="h-5 w-5 text-grey-700" />
<ChannelIcon className="h-5 w-5 text-oliver-black/60" />
</div>
<select
id="proof-channel"
value={channel}
onChange={(e) => setChannel(e.target.value)}
disabled={isLoading}
className="w-full rounded-[10px] border-2 border-grey-700 shadow-sm focus:border-active-blue focus:ring-active-blue p-3 pl-10 bg-white transition-all text-black-title appearance-none"
className="w-full rounded-[10px] border-2 border-oliver-azure shadow-sm focus:border-oliver-azure focus:ring-oliver-azure p-3 pl-10 bg-white transition-all text-oliver-black appearance-none"
required
>
<option value="" disabled>Select Channel</option>
{availableChannels.map(opt => <option key={opt} value={opt}>{opt}</option>)}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-grey-700">
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-oliver-black/60">
<ChevronDownIcon className="h-4 w-4" />
</div>
</div>
</div>
<div>
<label htmlFor="proof-sub-channel" className="block text-sm font-bold text-primary-blue mb-2">Sub-Channel</label>
<label htmlFor="proof-sub-channel" className="block text-sm font-bold text-oliver-black mb-2">Sub-Channel</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<TagIcon className="h-5 w-5 text-grey-700" />
<TagIcon className="h-5 w-5 text-oliver-black/60" />
</div>
<select
id="proof-sub-channel"
value={subChannel}
onChange={(e) => setSubChannel(e.target.value)}
disabled={isLoading || !channel}
className="w-full rounded-[10px] border-2 border-grey-700 shadow-sm focus:border-active-blue focus:ring-active-blue p-3 pl-10 bg-white transition-all text-black-title appearance-none disabled:bg-grey-100 disabled:text-grey-700"
className="w-full rounded-[10px] border-2 border-oliver-azure shadow-sm focus:border-oliver-azure focus:ring-oliver-azure p-3 pl-10 bg-white transition-all text-oliver-black appearance-none disabled:bg-oliver-grey disabled:text-oliver-black/60"
required
>
<option value="" disabled>Select Sub-Channel</option>
{availableSubChannels.map(opt => <option key={opt} value={opt}>{opt}</option>)}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-grey-700">
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-oliver-black/60">
<ChevronDownIcon className="h-4 w-4" />
</div>
</div>
</div>
<div className="sm:col-span-2">
<label htmlFor="proof-type" className="block text-sm font-bold text-primary-blue mb-2">Proof Type</label>
<label htmlFor="proof-type" className="block text-sm font-bold text-oliver-black mb-2">Proof Type</label>
<div className="relative">
<select
id="proof-type"
value={proofType}
onChange={(e) => setProofType(e.target.value)}
disabled={isLoading || !subChannel || availableProofTypes.length === 0}
className="w-full rounded-[10px] border-2 border-grey-700 shadow-sm focus:border-active-blue focus:ring-active-blue p-3 bg-white transition-all text-black-title appearance-none disabled:bg-grey-100 disabled:text-grey-700"
className="w-full rounded-[10px] border-2 border-oliver-azure shadow-sm focus:border-oliver-azure focus:ring-oliver-azure p-3 bg-white transition-all text-oliver-black appearance-none disabled:bg-oliver-grey disabled:text-oliver-black/60"
required={showProofType}
>
<option value="" disabled>
@ -864,7 +864,7 @@ const UploadProofModal: React.FC<{
</option>
{availableProofTypes.map(opt => <option key={opt} value={opt}>{opt}</option>)}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-grey-700">
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-oliver-black/60">
<ChevronDownIcon className="h-4 w-4" />
</div>
</div>
@ -873,7 +873,7 @@ const UploadProofModal: React.FC<{
{/* Drag & Drop Zone */}
<div>
<label className="block text-sm font-bold text-primary-blue mb-2">Proof File</label>
<label className="block text-sm font-bold text-oliver-black mb-2">Proof File</label>
<div
onDragOver={handleDragOver}
onDrop={handleDrop}
@ -895,23 +895,23 @@ const UploadProofModal: React.FC<{
<div className="text-center space-y-2 pointer-events-none">
{!file ? (
<>
<div className="mx-auto h-16 w-16 bg-grey-100 text-grey-700 rounded-full flex items-center justify-center group-hover:scale-110 group-hover:text-success group-hover:bg-success-light transition-all duration-300">
<div className="mx-auto h-16 w-16 bg-oliver-grey text-oliver-black/60 rounded-full flex items-center justify-center group-hover:scale-110 group-hover:text-success group-hover:bg-success-light transition-all duration-300">
<UploadIcon className="h-8 w-8" />
</div>
<div className="text-sm text-black-title">
<div className="text-sm text-oliver-black">
<span className="font-bold text-success">Click to upload</span> or drag and drop
</div>
<p className="text-xs text-grey-700">SVG, PNG, JPG or GIF (max. 800x400px)</p>
<p className="text-xs text-oliver-black/60">SVG, PNG, JPG or GIF (max. 800x400px)</p>
</>
) : (
<>
<div className="mx-auto h-16 w-16 bg-success-light text-success rounded-full flex items-center justify-center scale-110 shadow-sm">
<CheckCircleIcon className="h-8 w-8" />
</div>
<div className="text-sm font-bold text-black-title truncate max-w-xs mx-auto">
<div className="text-sm font-bold text-oliver-black truncate max-w-xs mx-auto">
{file.name}
</div>
<p className="text-xs text-grey-900">Ready for analysis</p>
<p className="text-xs text-oliver-black">Ready for analysis</p>
</>
)}
</div>
@ -921,19 +921,19 @@ const UploadProofModal: React.FC<{
</div>
{/* Footer */}
<div className="bg-grey-100 px-4 py-4 sm:px-6 border-t border-grey-300 flex flex-col-reverse sm:flex-row sm:justify-end gap-3">
<div className="bg-oliver-grey px-4 py-4 sm:px-6 border-t border-grey-300 flex flex-col-reverse sm:flex-row sm:justify-end gap-3">
<button
type="button"
onClick={onClose}
disabled={isLoading}
className="w-full sm:w-auto border-2 border-active-blue text-active-blue font-semibold py-2.5 px-6 rounded-full hover:bg-active-blue hover:text-white transition-colors duration-300 disabled:opacity-50"
className="w-full sm:w-auto border-2 border-oliver-azure text-oliver-azure font-semibold py-2.5 px-6 rounded-full hover:bg-oliver-azure hover:text-white transition-colors duration-300 disabled:opacity-50"
>
Cancel
</button>
<button
type="submit"
disabled={isSubmitDisabled}
className="w-full sm:w-auto flex items-center justify-center bg-active-blue text-white font-bold py-2.5 px-6 rounded-full hover:bg-active-blue/90 shadow-lg shadow-active-blue/20 transition-all duration-300 disabled:bg-grey-300 disabled:text-grey-700 disabled:shadow-none disabled:cursor-not-allowed"
className="w-full sm:w-auto flex items-center justify-center bg-oliver-azure text-white font-bold py-2.5 px-6 rounded-full hover:bg-oliver-azure/90 shadow-lg shadow-oliver-azure/20 transition-all duration-300 disabled:bg-gray-300 disabled:text-oliver-black/60 disabled:shadow-none disabled:cursor-not-allowed"
>
{isLoading ? (
<>
@ -967,11 +967,11 @@ const LoadingCell: React.FC<{ progress: { completed: number; total: number } }>
<div className="flex flex-col items-center justify-center h-full px-2 text-center w-full">
<div className="w-full bg-grey-300 rounded-full h-1.5 mb-1.5">
<div
className="bg-active-blue h-1.5 rounded-full"
className="bg-oliver-azure h-1.5 rounded-full"
style={{ width: `${percent}%`, transition: 'width 0.3s ease-in-out' }}
></div>
</div>
<span className="text-xs text-black-title truncate w-full">{statusText} ({percent}%)</span>
<span className="text-xs text-oliver-black truncate w-full">{statusText} ({percent}%)</span>
</div>
);
};
@ -995,15 +995,15 @@ const DeleteConfirmationModal: React.FC<{
className="bg-white rounded-[10px] shadow-xl p-6 sm:p-8 w-full max-w-md transform transition-all"
onClick={e => e.stopPropagation()}
>
<h3 className="text-xl font-bold text-primary-blue">Confirm Deletion</h3>
<p className="text-black-title my-4">
<h3 className="text-xl font-bold text-oliver-black">Confirm Deletion</h3>
<p className="text-oliver-black my-4">
Are you sure you want to permanently delete the proof "{proofName}"? This action cannot be undone.
</p>
<div className="mt-6 flex justify-end gap-3">
<button
type="button"
onClick={onClose}
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"
className="border-2 border-oliver-azure text-oliver-azure font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure hover:text-white transition-colors"
>
Cancel
</button>
@ -1053,8 +1053,8 @@ const AnalysisErrorModal: React.FC<{
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" />
</div>
<div>
<h3 className="text-xl font-bold text-primary-blue">Analysis Error</h3>
<p className="text-sm text-grey-700 mt-0.5">{proofName}</p>
<h3 className="text-xl font-bold text-oliver-black">Analysis Error</h3>
<p className="text-sm text-oliver-black/60 mt-0.5">{proofName}</p>
</div>
</div>
@ -1067,11 +1067,11 @@ const AnalysisErrorModal: React.FC<{
{failedAgents.length > 0 && (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-grey-700">Agent Details</h4>
<h4 className="text-sm font-semibold text-oliver-black/60">Agent Details</h4>
{failedAgents.map(agent => (
<div key={agent.label} className="bg-grey-100 rounded-lg p-3">
<p className="text-sm font-medium text-primary-blue">{agent.label}</p>
<p className="text-sm text-grey-700 mt-1">{agent.review.feedback}</p>
<div key={agent.label} className="bg-oliver-grey rounded-lg p-3">
<p className="text-sm font-medium text-oliver-black">{agent.label}</p>
<p className="text-sm text-oliver-black/60 mt-1">{agent.review.feedback}</p>
</div>
))}
</div>
@ -1081,7 +1081,7 @@ const AnalysisErrorModal: React.FC<{
<button
type="button"
onClick={onClose}
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"
className="border-2 border-oliver-azure text-oliver-azure font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure hover:text-white transition-colors"
>
Close
</button>
@ -1113,8 +1113,8 @@ const CampaignDeleteConfirmationModal: React.FC<{
className="bg-white rounded-[10px] shadow-xl p-6 sm:p-8 w-full max-w-md transform transition-all"
onClick={e => e.stopPropagation()}
>
<h3 className="text-xl font-bold text-primary-blue">Confirm Deletion</h3>
<p className="text-black-title my-4">
<h3 className="text-xl font-bold text-oliver-black">Confirm Deletion</h3>
<p className="text-oliver-black my-4">
{isBulk ? (
<>Are you sure you want to permanently delete <strong>{selectedCount} selected campaign{selectedCount !== 1 ? 's' : ''}</strong>? All associated proofs will also be deleted. This action cannot be undone.</>
) : (
@ -1125,7 +1125,7 @@ const CampaignDeleteConfirmationModal: React.FC<{
<button
type="button"
onClick={onClose}
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"
className="border-2 border-oliver-azure text-oliver-azure font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure hover:text-white transition-colors"
>
Cancel
</button>
@ -1282,15 +1282,15 @@ const CampaignDetail: React.FC<{
<div className="flex items-center gap-4">
<button
onClick={onBack}
className="p-2 text-grey-700 rounded-full hover:bg-grey-300 hover:text-primary-blue transition-colors duration-200"
className="p-2 text-oliver-black/60 rounded-full hover:bg-grey-300 hover:text-oliver-black transition-colors duration-200"
title="Back to campaigns"
aria-label="Back to campaigns list"
>
<ArrowLeftIcon className="h-6 w-6" />
</button>
<div>
<h1 className="text-3xl lg:text-4xl font-semibold text-primary-blue">{campaignName}</h1>
<p className="text-base lg:text-lg text-grey-900 mt-1">Proof overview and compliance status.</p>
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">{campaignName}</h1>
<p className="text-base lg:text-lg text-oliver-black mt-1">Proof overview and compliance status.</p>
</div>
</div>
</header>
@ -1319,7 +1319,7 @@ const CampaignDetail: React.FC<{
<button
onClick={() => handleExportPDF(proofs.filter(p => p.status === 'completed'), `${campaignName} - Campaign Report`)}
disabled={isExporting || proofs.filter(p => p.status === 'completed').length === 0}
className="flex items-center gap-2 bg-white text-active-blue font-semibold py-2 px-4 rounded-full border-2 border-active-blue hover:bg-active-blue hover:text-white transition-colors duration-300 disabled:bg-grey-300 disabled:text-grey-700 disabled:border-grey-300 disabled:cursor-wait"
className="flex items-center gap-2 bg-white text-oliver-azure font-semibold py-2 px-4 rounded-full border-2 border-oliver-azure hover:bg-oliver-azure hover:text-white transition-colors duration-300 disabled:bg-gray-300 disabled:text-oliver-black/60 disabled:border-grey-300 disabled:cursor-wait"
>
{isExporting ? <SpinnerIcon className="h-5 w-5 custom-spinner" /> : <ExportIcon className="h-5 w-5" />}
{isExporting ? 'Exporting...' : 'Export Campaign Report'}
@ -1327,7 +1327,7 @@ const CampaignDetail: React.FC<{
{!readOnly && (
<button
onClick={() => setIsUploadFormVisible(true)}
className="flex items-center gap-2 bg-active-blue text-white font-semibold py-2 px-4 rounded-full hover:bg-active-blue/90 transition-colors duration-300"
className="flex items-center gap-2 bg-oliver-azure text-white font-semibold py-2 px-4 rounded-full hover:bg-oliver-azure/90 transition-colors duration-300"
>
<PlusIcon className="h-5 w-5" />
Upload New Proof
@ -1338,14 +1338,14 @@ const CampaignDetail: React.FC<{
<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-grey-300">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<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">Workfront #</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Sub-Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Proof Type</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Overall Status</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Workfront #</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Sub-Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Type</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Overall Status</th>
<th scope="col" className="relative px-6 py-3"><span className="sr-only">Actions</span></th>
</tr>
</thead>
@ -1353,18 +1353,18 @@ const CampaignDetail: React.FC<{
{proofs.map((proof, index) => {
if (proof.status === 'analyzing') {
return (
<tr key={proof.tempId} className="bg-grey-100 opacity-80">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">{proof.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-grey-700 italic">Pending</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.proofType || 'N/A'}</td>
<tr key={proof.tempId} className="bg-oliver-grey opacity-80">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">{proof.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black/60 italic">Pending</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.proofType || 'N/A'}</td>
<td className="px-6 py-4" colSpan={2}>
{proof.analysisProgress ?
<LoadingCell progress={proof.analysisProgress} /> :
<div className="flex justify-center items-center h-full">
<SpinnerIcon className="h-5 w-5 text-active-blue custom-spinner" />
<span className="ml-2 text-sm text-grey-900">Preparing...</span>
<SpinnerIcon className="h-5 w-5 text-oliver-azure custom-spinner" />
<span className="ml-2 text-sm text-oliver-black">Preparing...</span>
</div>
}
</td>
@ -1375,11 +1375,11 @@ const CampaignDetail: React.FC<{
if (proof.status === 'error') {
return (
<tr key={proof.tempId} className="bg-error-light">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">{proof.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-grey-700 italic">Failed</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.proofType || 'N/A'}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">{proof.proofName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black/60 italic">Failed</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.proofType || 'N/A'}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-error font-semibold" colSpan={2}>
<div className="flex items-center justify-between">
<button
@ -1390,7 +1390,7 @@ const CampaignDetail: React.FC<{
</button>
<button
onClick={() => onRetryAnalysis(campaignName, proof.tempId || proof._id)}
className="flex items-center gap-1.5 text-xs font-semibold text-active-blue hover:text-primary-blue whitespace-nowrap px-3 py-1.5 rounded-full bg-active-blue/10 hover:bg-active-blue/20 transition-colors"
className="flex items-center gap-1.5 text-xs font-semibold text-oliver-azure hover:text-oliver-black whitespace-nowrap px-3 py-1.5 rounded-full bg-oliver-azure/10 hover:bg-oliver-azure/20 transition-colors"
>
<ArrowPathIcon className="h-4 w-4" />
Retry
@ -1410,21 +1410,21 @@ const CampaignDetail: React.FC<{
return (
<tr
key={latestVersion.workfrontId || index}
className={`${index % 2 === 0 ? 'bg-white' : 'bg-grey-100'} ${isClickable ? "hover:bg-info-light cursor-pointer" : ""}`}
className={`${index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'} ${isClickable ? "hover:bg-oliver-grey cursor-pointer" : ""}`}
onClick={() => isClickable && onSelectProof(proof)}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">
{proof.proofName}
{isVersioned && (
<span className="ml-2 bg-grey-300 text-black-title text-xs font-bold px-2 py-0.5 rounded-full">
<span className="ml-2 bg-grey-300 text-oliver-black text-xs font-bold px-2 py-0.5 rounded-full">
V{latestVersion.version}
</span>
)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{latestVersion.workfrontId}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-primary-blue">{proof.proofType || 'N/A'}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{latestVersion.workfrontId}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{proof.proofType || 'N/A'}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
<OverallStatusBadge status={latestVersion.overallStatus} />
</td>
@ -1433,7 +1433,7 @@ const CampaignDetail: React.FC<{
{!readOnly && (
<button
onClick={(e) => handleNewVersionClick(e, proof)}
className="p-2 text-grey-700 rounded-full hover:bg-info-light hover:text-active-blue transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
className="p-2 text-oliver-black/60 rounded-full hover:bg-oliver-grey hover:text-oliver-azure transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
title={`Upload new version for ${proof.proofName}`}
disabled={isUploading || isExporting}
>
@ -1446,7 +1446,7 @@ const CampaignDetail: React.FC<{
handleExportPDF([proof], `${campaignName} - ${proof.proofName} Report`);
}}
disabled={isExporting}
className="p-2 text-grey-700 rounded-full hover:bg-success-light hover:text-success transition-colors disabled:opacity-50 disabled:cursor-wait"
className="p-2 text-oliver-black/60 rounded-full hover:bg-success-light hover:text-success transition-colors disabled:opacity-50 disabled:cursor-wait"
title={`Export PDF for ${proof.proofName}`}
>
<PDFIcon className="h-5 w-5" />
@ -1458,7 +1458,7 @@ const CampaignDetail: React.FC<{
setProofToDelete(proof);
}}
disabled={isExporting}
className="p-2 text-grey-700 rounded-full hover:bg-error-light hover:text-error transition-colors disabled:opacity-50"
className="p-2 text-oliver-black/60 rounded-full hover:bg-error-light hover:text-error transition-colors disabled:opacity-50"
title={`Delete ${proof.proofName}`}
>
<TrashIcon className="h-5 w-5" />
@ -1676,15 +1676,15 @@ const ProofDetailView: React.FC<{
<div className="flex items-center gap-4">
<button
onClick={onBack}
className="p-2 text-grey-700 rounded-full hover:bg-grey-300 hover:text-primary-blue transition-colors duration-200"
className="p-2 text-oliver-black/60 rounded-full hover:bg-grey-300 hover:text-oliver-black transition-colors duration-200"
title="Back to campaign details"
aria-label="Back to campaign details"
>
<ArrowLeftIcon className="h-6 w-6" />
</button>
<div>
<h1 className="text-3xl lg:text-4xl font-semibold text-primary-blue">{proof.proofName}</h1>
<div className="flex items-center gap-2 mt-2 text-sm text-grey-700 font-medium">
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">{proof.proofName}</h1>
<div className="flex items-center gap-2 mt-2 text-sm text-oliver-black/60 font-medium">
<span>{proof.channel}</span>
<span className="text-grey-300">&bull;</span>
<span>{proof.subChannel}</span>
@ -1703,7 +1703,7 @@ const ProofDetailView: React.FC<{
<div className="lg:col-span-1">
<div className="sticky top-8 flex flex-col gap-y-6">
<div>
<h2 className="text-2xl font-semibold text-primary-blue mb-4">
<h2 className="text-2xl font-semibold text-oliver-black mb-4">
Proof Preview
</h2>
<ProofPreview
@ -1715,14 +1715,14 @@ const ProofDetailView: React.FC<{
<div>
<div className="flex items-center justify-between mb-3 gap-2">
<h3 className="text-xl font-semibold text-primary-blue flex items-center gap-2">
<HistoryIcon className="h-6 w-6 text-active-blue"/>
<h3 className="text-xl font-semibold text-oliver-black flex items-center gap-2">
<HistoryIcon className="h-6 w-6 text-oliver-azure"/>
Version History
</h3>
<div className="flex items-center gap-2">
<button
onClick={handleDownload}
className="flex items-center gap-2 text-sm bg-active-blue text-white font-semibold py-1.5 px-3 rounded-full border border-transparent hover:bg-active-blue/90 transition-colors duration-200"
className="flex items-center gap-2 text-sm bg-oliver-azure text-white font-semibold py-1.5 px-3 rounded-full border border-transparent hover:bg-oliver-azure/90 transition-colors duration-200"
title={`Download Version ${selectedVersion.version}`}
>
<DownloadIcon className="h-4 w-4" />
@ -1731,7 +1731,7 @@ const ProofDetailView: React.FC<{
<button
onClick={handleDownloadReport}
disabled={isExporting}
className="flex items-center gap-2 text-sm bg-white text-active-blue font-semibold py-1.5 px-3 rounded-full border-2 border-active-blue hover:bg-active-blue hover:text-white transition-colors duration-200 disabled:bg-grey-300 disabled:text-grey-700 disabled:border-grey-300 disabled:cursor-wait"
className="flex items-center gap-2 text-sm bg-white text-oliver-azure font-semibold py-1.5 px-3 rounded-full border-2 border-oliver-azure hover:bg-oliver-azure hover:text-white transition-colors duration-200 disabled:bg-gray-300 disabled:text-oliver-black/60 disabled:border-grey-300 disabled:cursor-wait"
title={`Download Report for Version ${selectedVersion.version}`}
>
{isExporting ? (
@ -1750,7 +1750,7 @@ const ProofDetailView: React.FC<{
<button
onClick={handleUploadClick}
disabled={isUploadingNewVersion}
className="flex items-center gap-2 text-sm bg-white text-active-blue font-semibold py-1.5 px-3 rounded-full border-2 border-active-blue hover:bg-active-blue hover:text-white transition-colors duration-200 disabled:bg-grey-300 disabled:text-grey-700 disabled:border-grey-300 disabled:cursor-wait"
className="flex items-center gap-2 text-sm bg-white text-oliver-azure font-semibold py-1.5 px-3 rounded-full border-2 border-oliver-azure hover:bg-oliver-azure hover:text-white transition-colors duration-200 disabled:bg-gray-300 disabled:text-oliver-black/60 disabled:border-grey-300 disabled:cursor-wait"
title="Upload a new version of this proof"
>
{isUploadingNewVersion ? (
@ -1785,15 +1785,15 @@ const ProofDetailView: React.FC<{
onClick={() => setSelectedVersionIndex(index)}
className={`w-full text-left p-3 rounded-[10px] border-2 transition-all ${
isActive
? 'bg-info-light border-active-blue shadow-sm'
: 'bg-white border-grey-300 hover:border-active-blue/50 hover:bg-grey-100'
? 'bg-oliver-grey border-oliver-azure shadow-sm'
: 'bg-white border-grey-300 hover:border-oliver-azure/50 hover:bg-oliver-grey'
}`}
>
<div className="flex justify-between items-center">
<p className={`font-bold ${isActive ? 'text-primary-blue' : 'text-black-title'}`}>Version {version.version}</p>
<p className="text-xs text-grey-700">{version.timestamp}</p>
<p className={`font-bold ${isActive ? 'text-oliver-black' : 'text-oliver-black'}`}>Version {version.version}</p>
<p className="text-xs text-oliver-black/60">{version.timestamp}</p>
</div>
<p className="text-sm text-grey-900 mt-1">Workfront ID: {version.workfrontId}</p>
<p className="text-sm text-oliver-black mt-1">Workfront ID: {version.workfrontId}</p>
</button>
);
})}
@ -1806,8 +1806,8 @@ const ProofDetailView: React.FC<{
<div className="mb-6 bg-warning-light border border-warning rounded-[10px] p-4 flex items-start gap-3">
<ExclamationTriangleIcon className="w-5 h-5 text-warning flex-shrink-0 mt-0.5" />
<div>
<p className="font-semibold text-black-title">Identical File Detected</p>
<p className="text-sm text-grey-900 mt-1">
<p className="font-semibold text-oliver-black">Identical File Detected</p>
<p className="text-sm text-oliver-black mt-1">
This file is exactly the same as the previous version.
The analysis results shown are from the new analysis,
but no changes were made to the creative.

View file

@ -46,14 +46,14 @@ export const ChecksOverview: React.FC = () => {
<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-lime text-primary-blue text-xs font-bold uppercase tracking-widest mb-4 shadow-sm">
<div className="inline-flex items-center px-4 py-1.5 rounded-full bg-white border border-oliver-sky text-oliver-black 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-semibold text-primary-blue tracking-tight mb-4">
<h2 className="text-3xl md:text-4xl font-semibold text-oliver-black tracking-tight mb-4">
Orchestrated by AI
</h2>
<p className="text-lg text-black-title leading-relaxed">
<p className="text-lg text-oliver-black leading-relaxed">
A central Lead Agent coordinates specialized experts to review every aspect of your content in parallel.
</p>
</div>
@ -62,17 +62,17 @@ export const ChecksOverview: React.FC = () => {
{/* 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-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">
<div className="flex-1 relative bg-oliver-black rounded-[20px] p-6 shadow-2xl shadow-oliver-black/20 border border-white/10 text-center transition-all duration-500 hover:-translate-y-2 hover:shadow-oliver-black/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-primary-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-oliver-black/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-cyan-brand font-bold text-xs uppercase tracking-widest mb-4">Orchestrator</p>
<p className="text-oliver-azure font-bold text-xs uppercase tracking-widest mb-4">Orchestrator</p>
<p className="text-slate-300 text-sm leading-relaxed">
Synthesises feedback & coordinates analysis across all specialist agents.
</p>
@ -80,11 +80,11 @@ 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-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="hidden lg:flex absolute top-1/2 -right-4 w-8 h-8 bg-oliver-black rounded-full border-4 border-oliver-sky/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-primary-blue rounded-full border-4 border-lime/50 items-center justify-center z-30 -translate-x-1/2 shadow-sm">
<div className="lg:hidden absolute -bottom-4 left-1/2 w-8 h-8 bg-oliver-black rounded-full border-4 border-oliver-sky/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>
@ -93,8 +93,8 @@ 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="#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" />
<path d="M0,100 C50,100 50,30 100,30" fill="none" stroke="#5DF5EA" strokeWidth="2" strokeDasharray="6 6" />
<path d="M0,100 C50,100 50,170 100,170" fill="none" stroke="#5DF5EA" strokeWidth="2" strokeDasharray="6 6" />
{/* Animated pulses on paths */}
<circle r="3" fill="#09821F">
@ -107,7 +107,7 @@ export const ChecksOverview: React.FC = () => {
</div>
{/* Mobile Connector Spacer */}
<div className="lg:hidden h-8 w-0.5 bg-lime my-3"></div>
<div className="lg:hidden h-8 w-0.5 bg-oliver-sky 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">
@ -117,16 +117,16 @@ export const ChecksOverview: React.FC = () => {
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-lime/10 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-oliver-sky/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-success-light to-lime/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-oliver-sky/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-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-lime/30 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-oliver-sky/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-[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`}>
@ -134,13 +134,13 @@ export const ChecksOverview: React.FC = () => {
</div>
<div className="flex-1">
<h4 className="text-base font-bold text-black-title group-hover:text-primary-blue transition-colors duration-300 mb-0.5">
<h4 className="text-base font-bold text-oliver-black group-hover:text-oliver-black transition-colors duration-300 mb-0.5">
{agent.name}
</h4>
<p className="text-[10px] font-extrabold text-grey-700 uppercase tracking-wider mb-1 group-hover:text-success transition-colors duration-300">
<p className="text-[10px] font-extrabold text-oliver-black/60 uppercase tracking-wider mb-1 group-hover:text-success transition-colors duration-300">
{agent.role}
</p>
<p className="text-xs text-black-title leading-relaxed group-hover:text-black-title">
<p className="text-xs text-oliver-black leading-relaxed group-hover:text-oliver-black">
{agent.description}
</p>
</div>

View file

@ -24,11 +24,11 @@ export const CopyGenAI: React.FC = () => {
};
return (
<div className="flex h-full bg-grey-100">
<div className="flex h-full bg-oliver-grey">
{/* Conversation History Sidebar */}
<aside className="w-80 flex-shrink-0 bg-gray-100 border-r border-gray-200 flex flex-col">
<div className="p-4 border-b border-gray-200">
<button className="w-full flex items-center justify-center gap-2 bg-active-blue text-white font-semibold py-2.5 px-4 rounded-lg hover:bg-primary-blue transition-colors duration-300">
<button className="w-full flex items-center justify-center gap-2 bg-oliver-azure text-white font-semibold py-2.5 px-4 rounded-lg hover:bg-oliver-azure transition-colors duration-300">
<PlusIcon className="h-5 w-5" />
Start new conversation
</button>
@ -41,7 +41,7 @@ export const CopyGenAI: React.FC = () => {
onClick={() => setActiveConversationId(convo.id)}
className={`w-full flex items-center gap-3 px-3 py-2.5 text-left text-sm font-medium rounded-md transition-colors duration-200 ${
activeConversationId === convo.id
? 'bg-active-blue/10 text-active-blue'
? 'bg-oliver-azure/10 text-oliver-azure'
: 'text-gray-700 hover:bg-gray-200'
}`}
>
@ -71,7 +71,7 @@ export const CopyGenAI: React.FC = () => {
{/* Message Display */}
<div className="flex-1 flex flex-col items-center justify-center p-8">
<div className="text-center">
<h1 className="text-3xl font-bold text-primary-blue">CopyGenAI</h1>
<h1 className="text-3xl font-bold text-oliver-black">CopyGenAI</h1>
<p className="mt-2 text-gray-600">How can I help you today?</p>
</div>
</div>
@ -89,13 +89,13 @@ export const CopyGenAI: React.FC = () => {
handleSendMessage(e);
}
}}
className="w-full p-3 pr-14 border border-gray-300 rounded-lg resize-none focus:ring-2 focus:ring-active-blue focus:border-active-blue transition"
className="w-full p-3 pr-14 border border-gray-300 rounded-lg resize-none focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure transition"
placeholder="Type your message here..."
rows={1}
/>
<button
type="submit"
className="absolute right-3 top-1/2 -translate-y-1/2 p-2 rounded-full text-white bg-active-blue hover:bg-primary-blue disabled:bg-gray-400 transition-colors"
className="absolute right-3 top-1/2 -translate-y-1/2 p-2 rounded-full text-white bg-oliver-azure hover:bg-oliver-azure disabled:bg-gray-400 transition-colors"
disabled={!message.trim()}
aria-label="Send message"
>

View file

@ -93,31 +93,31 @@ export const CreateCampaignModal: React.FC<CreateCampaignModalProps> = ({ isOpen
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-6">
<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">
<h2 className="text-2xl font-bold text-oliver-black">Create New Campaign</h2>
<button onClick={onClose} className="p-1 rounded-full text-oliver-black/60 hover:bg-oliver-grey hover:text-oliver-black 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-black-title">Campaign Name</label>
<label htmlFor="campaign-name" className="block text-sm font-medium text-oliver-black">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-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
className="mt-1 block w-full p-2 border-2 border-oliver-azure rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black"
required
/>
</div>
<div>
<label htmlFor="brand-guidelines" className="block text-sm font-medium text-black-title">Brand Guidelines</label>
<label htmlFor="brand-guidelines" className="block text-sm font-medium text-oliver-black">Brand Guidelines</label>
<select
id="brand-guidelines"
value={selectedBrandGuideline}
onChange={(e) => setSelectedBrandGuideline(e.target.value)}
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"
className="mt-1 block w-full p-2 border-2 border-oliver-azure rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black"
required
>
<option value="" disabled>Select brand guidelines</option>
@ -127,13 +127,13 @@ export const CreateCampaignModal: React.FC<CreateCampaignModalProps> = ({ isOpen
</select>
</div>
<div>
<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>
<label htmlFor="workfront-id" className="block text-sm font-medium text-oliver-black">Workfront Campaign ID <span className="text-oliver-black/60 font-normal">(Optional)</span></label>
<input
type="text"
id="workfront-id"
value={workfrontId}
onChange={handleWorkfrontIdChange}
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'}`}
className={`mt-1 block w-full p-2 border-2 rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black placeholder:text-oliver-black/60 ${error ? 'border-error focus:border-error focus:ring-error' : 'border-oliver-azure'}`}
placeholder="#WF_12345"
aria-invalid={!!error}
aria-describedby="workfront-id-error"
@ -141,33 +141,33 @@ export const CreateCampaignModal: React.FC<CreateCampaignModalProps> = ({ isOpen
{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-black-title">Client Lead</label>
<label htmlFor="client-lead" className="block text-sm font-medium text-oliver-black">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-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
className="mt-1 block w-full p-2 border-2 border-oliver-azure rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-black-title">Agency</label>
<label className="block text-sm font-medium text-oliver-black">Agency</label>
<input
type="text"
value={user?.agencyName ?? ''}
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"
className="mt-1 block w-full p-2 border-2 border-grey-300 rounded-[10px] shadow-sm bg-oliver-grey text-oliver-black cursor-not-allowed"
disabled
/>
</div>
<div>
<label htmlFor="agency-lead" className="block text-sm font-medium text-black-title">Agency Lead</label>
<label htmlFor="agency-lead" className="block text-sm font-medium text-oliver-black">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-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
className="mt-1 block w-full p-2 border-2 border-oliver-azure rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black"
required
/>
</div>
@ -176,13 +176,13 @@ export const CreateCampaignModal: React.FC<CreateCampaignModalProps> = ({ isOpen
<button
type="button"
onClick={onClose}
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"
className="border-2 border-oliver-azure text-oliver-azure font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure hover:text-white transition-colors duration-300"
>
Cancel
</button>
<button
type="submit"
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"
className="bg-oliver-azure text-white font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
disabled={isFormInvalid || !!error}
>
Create Campaign

View file

@ -79,32 +79,32 @@ export const CreateProjectModal: React.FC<CreateProjectModalProps> = ({ isOpen,
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-primary-blue">Create New Project</h2>
<button onClick={onClose} className="p-1 rounded-full text-grey-700 hover:bg-grey-100 hover:text-black-title transition-colors">
<h2 className="text-2xl font-bold text-oliver-black">Create New Project</h2>
<button onClick={onClose} className="p-1 rounded-full text-oliver-black/60 hover:bg-oliver-grey hover:text-oliver-black transition-colors">
<XIcon className="h-6 w-6" />
</button>
</div>
<form onSubmit={handleSubmit} noValidate>
<div className="space-y-4">
<div>
<label htmlFor="project-name" className="block text-sm font-medium text-black-title">Project Name</label>
<label htmlFor="project-name" className="block text-sm font-medium text-oliver-black">Project Name</label>
<input
type="text"
id="project-name"
value={name}
onChange={(e) => setName(e.target.value)}
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"
className="mt-1 block w-full p-2 border-2 border-oliver-azure rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black"
required
/>
</div>
<div>
<label htmlFor="workfront-id" className="block text-sm font-medium text-black-title">Workfront Project ID</label>
<label htmlFor="workfront-id" className="block text-sm font-medium text-oliver-black">Workfront Project ID</label>
<input
type="text"
id="workfront-id"
value={workfrontId}
onChange={handleWorkfrontIdChange}
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'}`}
className={`mt-1 block w-full p-2 border-2 rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black placeholder:text-oliver-black/60 ${error ? 'border-error focus:border-error focus:ring-error' : 'border-oliver-azure'}`}
placeholder="#WF_12345"
required
aria-invalid={!!error}
@ -113,31 +113,31 @@ export const CreateProjectModal: React.FC<CreateProjectModalProps> = ({ isOpen,
{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-black-title">Client Lead</label>
<label htmlFor="client-lead" className="block text-sm font-medium text-oliver-black">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-2 border-grey-700 rounded-[10px] shadow-sm focus:ring-active-blue focus:border-active-blue transition bg-white text-black-title"
className="mt-1 block w-full p-2 border-2 border-oliver-azure rounded-[10px] shadow-sm focus:ring-oliver-azure focus:border-oliver-azure transition bg-white text-oliver-black"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-black-title">Agency</label>
<label className="block text-sm font-medium text-oliver-black">Agency</label>
<input
type="text"
value={user?.agencyName ?? ''}
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"
className="mt-1 block w-full p-2 border-2 border-grey-300 rounded-[10px] shadow-sm bg-oliver-grey text-oliver-black cursor-not-allowed"
disabled
/>
</div>
<div>
<label className="block text-sm font-medium text-black-title">Agency Lead</label>
<label className="block text-sm font-medium text-oliver-black">Agency Lead</label>
<input
type="text"
value={user?.name ?? ''}
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"
className="mt-1 block w-full p-2 border-2 border-grey-300 rounded-[10px] shadow-sm bg-oliver-grey text-oliver-black cursor-not-allowed"
disabled
/>
</div>
@ -146,13 +146,13 @@ export const CreateProjectModal: React.FC<CreateProjectModalProps> = ({ isOpen,
<button
type="button"
onClick={onClose}
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"
className="border-2 border-oliver-azure text-oliver-azure font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure hover:text-white transition-colors duration-300"
>
Cancel
</button>
<button
type="submit"
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"
className="bg-oliver-azure text-white font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
disabled={isFormInvalid || !!error}
>
Create Project

View file

@ -113,7 +113,7 @@ const RagStatusBadge: React.FC<{ status: RagStatus; isLarge?: boolean }> = ({ st
iconColor = 'text-error';
break;
case 'Amber':
colorClasses = 'bg-warning-light border-warning text-black-title';
colorClasses = 'bg-warning-light border-warning text-oliver-black';
iconColor = 'text-warning';
break;
case 'Green':
@ -121,8 +121,8 @@ const RagStatusBadge: React.FC<{ status: RagStatus; isLarge?: boolean }> = ({ st
iconColor = 'text-success';
break;
case 'Error':
colorClasses = 'bg-grey-100 border-grey-300 text-grey-900';
iconColor = 'text-grey-700';
colorClasses = 'bg-oliver-grey border-grey-300 text-oliver-black';
iconColor = 'text-oliver-black/60';
break;
}
@ -165,20 +165,20 @@ const ResolveIssueModal: React.FC<{
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-primary-blue mb-2">Resolve Issue</h3>
<p className="text-black-title mb-6">Please provide a reason for manually resolving this issue.</p>
<h3 className="text-2xl font-bold text-oliver-black mb-2">Resolve Issue</h3>
<p className="text-oliver-black 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">
<div className="my-6 p-4 bg-oliver-grey border border-grey-300 rounded-[10px] text-oliver-black italic text-sm">
"{issueText}"
</div>
<form onSubmit={handleSubmit}>
<label htmlFor="resolution-reason" className="block text-sm font-bold text-black-title mb-2">Reason for resolution</label>
<label htmlFor="resolution-reason" className="block text-sm font-bold text-oliver-black mb-2">Reason for resolution</label>
<textarea
id="resolution-reason"
value={reason}
onChange={(e) => setReason(e.target.value)}
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"
className="w-full p-4 border-2 border-oliver-azure rounded-[10px] focus:ring-2 focus:ring-oliver-azure/50 focus:border-oliver-azure transition-all bg-oliver-grey focus:bg-white resize-none text-oliver-black"
rows={4}
placeholder="e.g. 'Legal team has approved this exception via email...'"
required
@ -187,13 +187,13 @@ const ResolveIssueModal: React.FC<{
<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"
className="px-6 py-2.5 rounded-full border-2 border-oliver-azure text-oliver-azure font-semibold hover:bg-oliver-azure hover:text-white transition-colors"
>
Cancel
</button>
<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"
className="px-6 py-2.5 rounded-full bg-oliver-azure text-white font-bold shadow-lg shadow-oliver-azure/30 hover:bg-oliver-azure/90 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
disabled={!reason.trim()}
>
Submit Resolution
@ -239,15 +239,15 @@ const FlagIssueModal: React.FC<{
{showSuccess ? (
<div className="text-center py-8">
<CheckCircleIcon className="h-12 w-12 text-success mx-auto mb-4" />
<h3 className="text-xl font-bold text-primary-blue mb-2">Flag Submitted</h3>
<h3 className="text-xl font-bold text-oliver-black mb-2">Flag Submitted</h3>
<p className="text-slate-500">Thank you for your feedback on the {agentName}'s review. This has been logged for auditing.</p>
</div>
) : (
<>
<div className="flex justify-between items-start mb-6">
<div>
<h3 className="text-2xl font-bold text-primary-blue">Flag Feedback</h3>
<p className="text-slate-500 text-sm mt-1">Reporting incorrect feedback from <span className="font-semibold text-active-blue">{agentName}</span></p>
<h3 className="text-2xl font-bold text-oliver-black">Flag Feedback</h3>
<p className="text-slate-500 text-sm mt-1">Reporting incorrect feedback from <span className="font-semibold text-oliver-azure">{agentName}</span></p>
</div>
<button onClick={onClose} className="p-2 rounded-full hover:bg-slate-100 text-slate-400 hover:text-slate-600 transition-colors">
<XIcon className="h-6 w-6" />
@ -555,7 +555,7 @@ const SubReviewCard: React.FC<{
{issue.status === 'actionable' ? (
<button
onClick={() => handleOpenModal(actualIndex)}
className="flex-shrink-0 opacity-0 group-hover/issue:opacity-100 focus:opacity-100 text-xs font-semibold text-active-blue hover:text-primary-blue bg-cyan-brand/10 hover:bg-cyan-brand/20 px-2.5 py-1 rounded-lg transition-all"
className="flex-shrink-0 opacity-0 group-hover/issue:opacity-100 focus:opacity-100 text-xs font-semibold text-oliver-azure hover:text-oliver-black bg-oliver-azure/10 hover:bg-oliver-azure/20 px-2.5 py-1 rounded-lg transition-all"
>
Mark Resolved
</button>
@ -570,7 +570,7 @@ const SubReviewCard: React.FC<{
</span>
<button
onClick={() => handleReopen(actualIndex)}
className="text-xs font-semibold text-slate-400 hover:text-primary-blue bg-slate-100 hover:bg-slate-200 px-2.5 py-1 rounded-lg transition-all"
className="text-xs font-semibold text-slate-400 hover:text-oliver-black bg-slate-100 hover:bg-slate-200 px-2.5 py-1 rounded-lg transition-all"
>
Re-open
</button>
@ -630,7 +630,7 @@ const SubReviewCard: React.FC<{
{issue.status === 'actionable' ? (
<button
onClick={() => handleOpenModal(actualIndex)}
className="flex-shrink-0 opacity-0 group-hover/issue:opacity-100 focus:opacity-100 text-xs font-semibold text-active-blue hover:text-primary-blue bg-cyan-brand/10 hover:bg-cyan-brand/20 px-2.5 py-1 rounded-lg transition-all"
className="flex-shrink-0 opacity-0 group-hover/issue:opacity-100 focus:opacity-100 text-xs font-semibold text-oliver-azure hover:text-oliver-black bg-oliver-azure/10 hover:bg-oliver-azure/20 px-2.5 py-1 rounded-lg transition-all"
>
Mark Resolved
</button>
@ -645,7 +645,7 @@ const SubReviewCard: React.FC<{
</span>
<button
onClick={() => handleReopen(actualIndex)}
className="text-xs font-semibold text-slate-400 hover:text-primary-blue bg-slate-100 hover:bg-slate-200 px-2.5 py-1 rounded-lg transition-all"
className="text-xs font-semibold text-slate-400 hover:text-oliver-black bg-slate-100 hover:bg-slate-200 px-2.5 py-1 rounded-lg transition-all"
>
Re-open
</button>
@ -691,7 +691,7 @@ const SubReviewCard: React.FC<{
{issue.status === 'actionable' ? (
<button
onClick={() => handleOpenModal(index)}
className="flex-shrink-0 opacity-0 group-hover/issue:opacity-100 focus:opacity-100 text-xs font-semibold text-active-blue hover:text-primary-blue bg-cyan-brand/10 hover:bg-cyan-brand/20 px-2.5 py-1 rounded-lg transition-all"
className="flex-shrink-0 opacity-0 group-hover/issue:opacity-100 focus:opacity-100 text-xs font-semibold text-oliver-azure hover:text-oliver-black bg-oliver-azure/10 hover:bg-oliver-azure/20 px-2.5 py-1 rounded-lg transition-all"
>
Mark Resolved
</button>
@ -706,7 +706,7 @@ const SubReviewCard: React.FC<{
</span>
<button
onClick={() => handleReopen(index)}
className="text-xs font-semibold text-slate-400 hover:text-primary-blue bg-slate-100 hover:bg-slate-200 px-2.5 py-1 rounded-lg transition-all"
className="text-xs font-semibold text-slate-400 hover:text-oliver-black bg-slate-100 hover:bg-slate-200 px-2.5 py-1 rounded-lg transition-all"
>
Re-open
</button>
@ -734,8 +734,8 @@ const SubReviewCard: React.FC<{
const LeadAgentSummary: React.FC<{ status: OverallStatus, summary: string, onFlag: () => void; isFlagged?: boolean; }> = ({ status, summary, onFlag, isFlagged }) => {
const isPassed = status === 'Passed';
let themeStyles = 'from-sky-50 to-white border-sky-100 text-primary-blue';
let iconBg = 'bg-sky-100 text-active-blue';
let themeStyles = 'from-sky-50 to-white border-sky-100 text-oliver-black';
let iconBg = 'bg-sky-100 text-oliver-azure';
let icon = <InformationCircleIcon className="h-8 w-8" />;
let blobColor = 'bg-sky-400';

View file

@ -3,9 +3,9 @@ import { EagleIcon } from './icons/EagleIcon';
export const Header: React.FC = () => {
return (
<header className="bg-primary-blue p-4 shadow-md">
<header className="bg-oliver-black p-4 shadow-md">
<div className="max-w-7xl mx-auto flex items-center">
<EagleIcon className="h-10 w-10 text-cyan-brand" />
<EagleIcon className="h-10 w-10 text-oliver-azure" />
<h1 className="text-xl sm:text-2xl font-bold text-white ml-3">
AI Proof Reviewer
</h1>

View file

@ -17,25 +17,21 @@ export const Hero: React.FC<HeroProps> = ({ onGetStarted }) => {
<div className="relative overflow-hidden bg-white min-h-[350px] sm:min-h-[400px] md:min-h-[500px] flex items-center">
<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="text-teal-brand text-xs font-bold uppercase tracking-widest mb-6">
AI-Powered Compliance
</div>
<h1 className="text-5xl md:text-7xl font-semibold text-teal-brand leading-tight mb-6">
<h1 className="text-5xl md:text-7xl font-semibold text-oliver-black leading-tight mb-6">
Mod Comms <br/>
<span className="text-electric-violet">
<span className="text-oliver-orange">
Intelligent Review
</span>
</h1>
<p className="text-lg md:text-xl text-teal-brand mb-10 leading-relaxed max-w-2xl">
<p className="text-lg md:text-xl text-oliver-black mb-10 leading-relaxed max-w-2xl">
Streamline your creative approval process. Mod Comms analyses your proofs against guidelines and best practice in seconds, not days.
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button
onClick={onGetStarted}
className="group inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-active-blue rounded-full hover:bg-active-blue/90 transition-all duration-300"
className="group inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-oliver-azure rounded-full hover:bg-oliver-azure/90 transition-all duration-300"
>
Start Analysis
<ArrowRightIcon className="ml-2 h-5 w-5 transform group-hover:translate-x-1 transition-transform" />

View file

@ -27,7 +27,7 @@ const StatusBadge: React.FC<{ status: string }> = ({ status }) => {
partial: 'partial parse',
};
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${colors[status] || 'bg-grey-100 text-grey-700'}`}>
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${colors[status] || 'bg-oliver-grey text-oliver-black/60'}`}>
{labels[status] || status}
</span>
);
@ -275,13 +275,13 @@ export const KnowledgeBase: React.FC = () => {
if (diffResult && selectedKb) {
return (
<div className="p-8 max-w-6xl mx-auto w-full">
<button onClick={handleBackFromDiff} className="flex items-center gap-2 text-active-blue hover:underline mb-6 text-sm font-medium">
<button onClick={handleBackFromDiff} className="flex items-center gap-2 text-oliver-azure hover:underline mb-6 text-sm font-medium">
<ArrowLeftIcon className="h-4 w-4" /> Back to Version History
</button>
<div className="mb-6">
<h1 className="text-2xl font-bold text-primary-blue">{selectedKb.display_name} - Diff</h1>
<p className="text-grey-700 mt-1">
<h1 className="text-2xl font-bold text-oliver-black">{selectedKb.display_name} - Diff</h1>
<p className="text-oliver-black/60 mt-1">
Version {diffResult.version_a} vs Version {diffResult.version_b}
<span className="ml-4 text-green-600 font-medium">+{diffResult.additions}</span>
<span className="ml-2 text-red-600 font-medium">-{diffResult.deletions}</span>
@ -299,10 +299,10 @@ export const KnowledgeBase: React.FC = () => {
''
}`}
>
<span className="w-12 text-right pr-2 text-grey-700 select-none border-r border-grey-200 flex-shrink-0 py-0.5">
<span className="w-12 text-right pr-2 text-oliver-black/60 select-none border-r border-grey-200 flex-shrink-0 py-0.5">
{line.line_number_old || ''}
</span>
<span className="w-12 text-right pr-2 text-grey-700 select-none border-r border-grey-200 flex-shrink-0 py-0.5">
<span className="w-12 text-right pr-2 text-oliver-black/60 select-none border-r border-grey-200 flex-shrink-0 py-0.5">
{line.line_number_new || ''}
</span>
<span className={`w-6 text-center flex-shrink-0 py-0.5 ${
@ -325,15 +325,15 @@ export const KnowledgeBase: React.FC = () => {
if (viewingSpec) {
return (
<div className="p-8 max-w-6xl mx-auto w-full">
<button onClick={() => setViewingSpec(null)} className="flex items-center gap-2 text-active-blue hover:underline mb-6 text-sm font-medium">
<button onClick={() => setViewingSpec(null)} className="flex items-center gap-2 text-oliver-azure hover:underline mb-6 text-sm font-medium">
<ArrowLeftIcon className="h-4 w-4" /> Back to Version History
</button>
<div className="mb-6">
<h1 className="text-2xl font-bold text-primary-blue">
<h1 className="text-2xl font-bold text-oliver-black">
{selectedKb?.display_name} - Version {viewingSpec.version_number}
</h1>
<p className="text-grey-700 mt-1">
<p className="text-oliver-black/60 mt-1">
{formatDate(viewingSpec.created_at)} | {viewingSpec.char_count.toLocaleString()} chars
{viewingSpec.generated_by_name && <span> | Generated by {viewingSpec.generated_by_name}</span>}
{viewingSpec.is_active && <span className="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">Active</span>}
@ -341,7 +341,7 @@ export const KnowledgeBase: React.FC = () => {
</div>
<div className="bg-white rounded-xl border border-grey-300 p-6 overflow-x-auto max-h-[70vh] overflow-y-auto">
<pre className="whitespace-pre-wrap text-sm text-black-title font-mono leading-relaxed">{viewingSpec.content}</pre>
<pre className="whitespace-pre-wrap text-sm text-oliver-black font-mono leading-relaxed">{viewingSpec.content}</pre>
</div>
</div>
);
@ -353,25 +353,25 @@ export const KnowledgeBase: React.FC = () => {
return (
<div className="p-8 max-w-6xl mx-auto w-full">
<button onClick={handleBack} className="flex items-center gap-2 text-active-blue hover:underline mb-6 text-sm font-medium">
<button onClick={handleBack} className="flex items-center gap-2 text-oliver-azure hover:underline mb-6 text-sm font-medium">
<ArrowLeftIcon className="h-4 w-4" /> Back to Knowledge Bases
</button>
<div className="mb-6">
<h1 className="text-2xl font-bold text-primary-blue">{selectedKb.display_name}</h1>
{selectedKb.description && <p className="text-grey-700 mt-1">{selectedKb.description}</p>}
<h1 className="text-2xl font-bold text-oliver-black">{selectedKb.display_name}</h1>
{selectedKb.description && <p className="text-oliver-black/60 mt-1">{selectedKb.description}</p>}
</div>
{/* Tabs */}
<div className="flex gap-1 mb-6 bg-grey-100 p-1 rounded-xl w-fit">
<div className="flex gap-1 mb-6 bg-oliver-grey p-1 rounded-xl w-fit">
{(['documents', 'versions'] as const).map(tab => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`px-5 py-2 rounded-lg text-sm font-medium transition-all duration-200 ${
activeTab === tab
? 'bg-white text-primary-blue shadow-sm'
: 'text-grey-700 hover:text-primary-blue'
? 'bg-white text-oliver-black shadow-sm'
: 'text-oliver-black/60 hover:text-oliver-black'
}`}
>
{tab === 'documents' ? 'Source Documents' : 'Version History'}
@ -387,12 +387,12 @@ export const KnowledgeBase: React.FC = () => {
onDragLeave={handleDragLeave}
onDrop={handleDrop}
className={`border-2 border-dashed rounded-xl p-8 mb-6 text-center transition-colors ${
isDragging ? 'border-active-blue bg-active-blue/5' : 'border-grey-300 hover:border-active-blue/50'
isDragging ? 'border-oliver-azure bg-oliver-azure/5' : 'border-grey-300 hover:border-oliver-azure/50'
}`}
>
<UploadIcon className="h-10 w-10 mx-auto text-grey-700 mb-3" />
<p className="text-grey-700 mb-2">Drag & drop files here, or</p>
<label className="inline-flex items-center gap-2 bg-active-blue text-white font-semibold py-2 px-6 rounded-full hover:bg-active-blue/90 transition-colors cursor-pointer">
<UploadIcon className="h-10 w-10 mx-auto text-oliver-black/60 mb-3" />
<p className="text-oliver-black/60 mb-2">Drag & drop files here, or</p>
<label className="inline-flex items-center gap-2 bg-oliver-azure text-white font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors cursor-pointer">
{uploading ? <SpinnerIcon className="h-4 w-4 animate-spin" /> : null}
{uploading ? 'Uploading...' : 'Browse Files'}
<input
@ -404,7 +404,7 @@ export const KnowledgeBase: React.FC = () => {
disabled={uploading}
/>
</label>
<p className="text-xs text-grey-700 mt-2">PDF, DOCX, PPTX, XLSX, HTML, TXT, MD, PNG, JPG, WebP</p>
<p className="text-xs text-oliver-black/60 mt-2">PDF, DOCX, PPTX, XLSX, HTML, TXT, MD, PNG, JPG, WebP</p>
</div>
{/* Process button + job status */}
@ -412,12 +412,12 @@ export const KnowledgeBase: React.FC = () => {
<button
onClick={handleProcess}
disabled={!!isJobRunning || selectedKb.source_documents.length === 0}
className="bg-active-blue text-white font-semibold py-2.5 px-8 rounded-full hover:bg-active-blue/90 transition-colors disabled:bg-grey-700 disabled:cursor-not-allowed"
className="bg-oliver-azure text-white font-semibold py-2.5 px-8 rounded-full hover:bg-oliver-azure/90 transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed"
>
{isJobRunning ? 'Processing...' : 'Process Documents'}
</button>
{selectedKb.active_spec_version && (
<span className="text-sm text-grey-700">
<span className="text-sm text-oliver-black/60">
Active spec: v{selectedKb.active_spec_version} ({selectedKb.active_spec_char_count?.toLocaleString()} chars)
</span>
)}
@ -427,8 +427,8 @@ export const KnowledgeBase: React.FC = () => {
{isJobRunning && activeJob && (
<div className="bg-blue-50 border border-blue-200 rounded-xl p-4 mb-6">
<div className="flex items-center gap-3 mb-2">
<SpinnerIcon className="h-5 w-5 text-active-blue animate-spin" />
<span className="font-medium text-primary-blue">
<SpinnerIcon className="h-5 w-5 text-oliver-azure animate-spin" />
<span className="font-medium text-oliver-black">
{activeJob.status === 'parsing_documents' ? 'Parsing documents...' :
activeJob.status === 'distilling' ? 'Distilling spec with AI...' :
'Starting...'}
@ -437,12 +437,12 @@ export const KnowledgeBase: React.FC = () => {
{activeJob.status === 'parsing_documents' && (
<div className="w-full bg-blue-100 rounded-full h-2">
<div
className="bg-active-blue h-2 rounded-full transition-all duration-500"
className="bg-oliver-azure h-2 rounded-full transition-all duration-500"
style={{ width: `${activeJob.total_documents > 0 ? (activeJob.parsed_documents / activeJob.total_documents) * 100 : 0}%` }}
/>
</div>
)}
<p className="text-sm text-grey-700 mt-1">
<p className="text-sm text-oliver-black/60 mt-1">
{activeJob.parsed_documents} / {activeJob.total_documents} documents parsed
</p>
</div>
@ -455,7 +455,7 @@ export const KnowledgeBase: React.FC = () => {
? 'bg-green-50 border-green-200 text-green-800'
: selectedKb.latest_job.status === 'failed'
? 'bg-red-50 border-red-200 text-red-800'
: 'bg-grey-100 border-grey-300 text-grey-700'
: 'bg-oliver-grey border-grey-300 text-oliver-black/60'
}`}>
Last processing: <StatusBadge status={selectedKb.latest_job.status} />
{selectedKb.latest_job.completed_at && <span className="ml-2">{formatDate(selectedKb.latest_job.completed_at)}</span>}
@ -468,7 +468,7 @@ export const KnowledgeBase: React.FC = () => {
<div className="bg-white rounded-xl border border-grey-300 overflow-hidden">
<table className="w-full text-sm">
<thead>
<tr className="bg-grey-100 text-left text-grey-700">
<tr className="bg-oliver-grey text-left text-oliver-black/60">
<th className="px-4 py-3 font-medium">Filename</th>
<th className="px-4 py-3 font-medium">Size</th>
<th className="px-4 py-3 font-medium">Uploaded</th>
@ -481,15 +481,15 @@ export const KnowledgeBase: React.FC = () => {
{selectedKb.source_documents.map(doc => (
<React.Fragment key={doc.id}>
<tr className="hover:bg-grey-50 transition-colors">
<td className="px-4 py-3 font-medium text-primary-blue">{doc.filename}</td>
<td className="px-4 py-3 text-grey-700">{formatBytes(doc.file_size_bytes)}</td>
<td className="px-4 py-3 text-grey-700">{formatDate(doc.created_at)}</td>
<td className="px-4 py-3 text-grey-700">{doc.uploaded_by_name || '-'}</td>
<td className="px-4 py-3 font-medium text-oliver-black">{doc.filename}</td>
<td className="px-4 py-3 text-oliver-black/60">{formatBytes(doc.file_size_bytes)}</td>
<td className="px-4 py-3 text-oliver-black/60">{formatDate(doc.created_at)}</td>
<td className="px-4 py-3 text-oliver-black/60">{doc.uploaded_by_name || '-'}</td>
<td className="px-4 py-3"><StatusBadge status={doc.parse_status} /></td>
<td className="px-4 py-3">
<button
onClick={() => handleRemoveDoc(doc.id)}
className="text-grey-700 hover:text-error transition-colors"
className="text-oliver-black/60 hover:text-error transition-colors"
title="Remove document"
>
<TrashIcon className="h-4 w-4" />
@ -511,7 +511,7 @@ export const KnowledgeBase: React.FC = () => {
</table>
</div>
) : (
<div className="text-center py-12 text-grey-700 bg-grey-100 rounded-xl">
<div className="text-center py-12 text-oliver-black/60 bg-oliver-grey rounded-xl">
No source documents uploaded yet.
</div>
)}
@ -524,7 +524,7 @@ export const KnowledgeBase: React.FC = () => {
<div className="mb-4">
<button
onClick={handleCompare}
className="bg-active-blue text-white font-semibold py-2 px-6 rounded-full hover:bg-active-blue/90 transition-colors"
className="bg-oliver-azure text-white font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors"
>
Compare Selected Versions
</button>
@ -535,7 +535,7 @@ export const KnowledgeBase: React.FC = () => {
<div className="bg-white rounded-xl border border-grey-300 overflow-hidden">
<table className="w-full text-sm">
<thead>
<tr className="bg-grey-100 text-left text-grey-700">
<tr className="bg-oliver-grey text-left text-oliver-black/60">
<th className="px-4 py-3 font-medium w-10">
<span className="sr-only">Compare</span>
</th>
@ -555,27 +555,27 @@ export const KnowledgeBase: React.FC = () => {
type="checkbox"
checked={selectedForDiff.includes(v.id)}
onChange={() => handleDiffToggle(v.id)}
className="h-4 w-4 rounded border-grey-300 text-active-blue focus:ring-active-blue"
className="h-4 w-4 rounded border-grey-300 text-oliver-azure focus:ring-oliver-azure"
/>
</td>
<td className="px-4 py-3 font-medium text-primary-blue">v{v.version_number}</td>
<td className="px-4 py-3 text-grey-700">{formatDate(v.created_at)}</td>
<td className="px-4 py-3 text-grey-700">{v.generated_by_name || '-'}</td>
<td className="px-4 py-3 text-grey-700">{v.char_count.toLocaleString()}</td>
<td className="px-4 py-3 font-medium text-oliver-black">v{v.version_number}</td>
<td className="px-4 py-3 text-oliver-black/60">{formatDate(v.created_at)}</td>
<td className="px-4 py-3 text-oliver-black/60">{v.generated_by_name || '-'}</td>
<td className="px-4 py-3 text-oliver-black/60">{v.char_count.toLocaleString()}</td>
<td className="px-4 py-3">
{v.is_active ? (
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Active
</span>
) : (
<span className="text-grey-700 text-xs">Inactive</span>
<span className="text-oliver-black/60 text-xs">Inactive</span>
)}
</td>
<td className="px-4 py-3">
<div className="flex items-center gap-2">
<button
onClick={() => handleViewSpec(v.id)}
className="text-active-blue hover:underline text-xs font-medium"
className="text-oliver-azure hover:underline text-xs font-medium"
>
View
</button>
@ -595,7 +595,7 @@ export const KnowledgeBase: React.FC = () => {
</table>
</div>
) : (
<div className="text-center py-12 text-grey-700 bg-grey-100 rounded-xl">
<div className="text-center py-12 text-oliver-black/60 bg-oliver-grey rounded-xl">
No spec versions generated yet.
</div>
)}
@ -609,7 +609,7 @@ export const KnowledgeBase: React.FC = () => {
if (loading) {
return (
<div className="p-8 flex items-center justify-center min-h-[400px]">
<SpinnerIcon className="h-8 w-8 text-active-blue animate-spin" />
<SpinnerIcon className="h-8 w-8 text-oliver-azure animate-spin" />
</div>
);
}
@ -617,8 +617,8 @@ export const KnowledgeBase: React.FC = () => {
return (
<div className="p-8 max-w-6xl mx-auto w-full">
<div className="mb-8">
<h1 className="text-2xl font-bold text-primary-blue">Knowledge Base</h1>
<p className="text-grey-700 mt-1">Manage the AI agent knowledge bases. Upload source documents, process them, and version the resulting specs.</p>
<h1 className="text-2xl font-bold text-oliver-black">Knowledge Base</h1>
<p className="text-oliver-black/60 mt-1">Manage the AI agent knowledge bases. Upload source documents, process them, and version the resulting specs.</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
@ -632,22 +632,22 @@ export const KnowledgeBase: React.FC = () => {
<button
key={kb.id}
onClick={() => handleSelectKb(kb)}
className={`text-left p-6 rounded-xl border-2 ${statusColor} hover:border-active-blue hover:shadow-md transition-all duration-200 group`}
className={`text-left p-6 rounded-xl border-2 ${statusColor} hover:border-oliver-azure hover:shadow-md transition-all duration-200 group`}
>
<h3 className="text-lg font-semibold text-primary-blue group-hover:text-active-blue transition-colors">
<h3 className="text-lg font-semibold text-oliver-black group-hover:text-oliver-azure transition-colors">
{kb.display_name}
</h3>
{kb.description && (
<p className="text-sm text-grey-700 mt-1 line-clamp-2">{kb.description}</p>
<p className="text-sm text-oliver-black/60 mt-1 line-clamp-2">{kb.description}</p>
)}
<div className="mt-4 space-y-1 text-sm text-grey-700">
<div className="mt-4 space-y-1 text-sm text-oliver-black/60">
<div className="flex justify-between">
<span>Source Documents</span>
<span className="font-medium text-primary-blue">{kb.source_document_count}</span>
<span className="font-medium text-oliver-black">{kb.source_document_count}</span>
</div>
<div className="flex justify-between">
<span>Active Spec</span>
<span className="font-medium text-primary-blue">
<span className="font-medium text-oliver-black">
{kb.active_spec_version ? `v${kb.active_spec_version}` : 'None'}
</span>
</div>
@ -658,7 +658,7 @@ export const KnowledgeBase: React.FC = () => {
</div>
)}
{kb.latest_job_completed_at && (
<div className="text-xs text-grey-700 text-right">
<div className="text-xs text-oliver-black/60 text-right">
{formatDate(kb.latest_job_completed_at)}
</div>
)}

View file

@ -6,15 +6,15 @@ export const LoadingVisual: React.FC = () => {
<div className="flex flex-col items-center justify-center text-center py-20 px-6 min-h-[600px]">
<div className="relative flex items-center justify-center w-48 h-48">
{/* Pulsing circles */}
<div className="absolute w-full h-full rounded-full bg-active-blue/20 animate-slow-ping"></div>
<div className="absolute w-3/4 h-3/4 rounded-full bg-active-blue/30 animate-slow-ping [animation-delay:-1s]"></div>
<div className="absolute w-full h-full rounded-full bg-oliver-azure/20 animate-slow-ping"></div>
<div className="absolute w-3/4 h-3/4 rounded-full bg-oliver-azure/30 animate-slow-ping [animation-delay:-1s]"></div>
{/* Central Icon */}
<div className="relative bg-white backdrop-blur-sm rounded-full p-6 border border-gray-200 shadow-lg flex items-center justify-center w-28 h-28">
<BarclaysLogo className="h-16 w-16 text-active-blue" />
<BarclaysLogo className="h-16 w-16 text-oliver-azure" />
</div>
</div>
<h2 className="text-2xl font-bold text-primary-blue mt-12">
<h2 className="text-2xl font-bold text-oliver-black mt-12">
Finalizing your report...
</h2>
<p className="text-gray-500 mt-2 max-w-md">

View file

@ -62,7 +62,7 @@ const SupportModal: React.FC<{
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-start mb-4">
<h3 className="text-xl font-bold text-primary-blue">Contact Support</h3>
<h3 className="text-xl font-bold text-oliver-black">Contact Support</h3>
<button onClick={onClose} className="-mt-2 -mr-2 p-2 rounded-full hover:bg-gray-200 transition-colors">
<XIcon className="h-6 w-6 text-gray-600" />
</button>
@ -78,7 +78,7 @@ const SupportModal: React.FC<{
<textarea
value={query}
onChange={(e) => setQuery(e.target.value)}
className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-active-blue focus:border-active-blue transition"
className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure transition"
rows={5}
placeholder="Type your message here..."
required
@ -95,7 +95,7 @@ const SupportModal: React.FC<{
</button>
<button
type="submit"
className="bg-active-blue text-white font-semibold py-2 px-4 rounded-md hover:bg-primary-blue transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed flex items-center gap-2"
className="bg-oliver-azure text-white font-semibold py-2 px-4 rounded-md hover:bg-oliver-azure transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed flex items-center gap-2"
disabled={!query.trim() || isSubmitting}
>
{isSubmitting ? (
@ -163,10 +163,10 @@ export const Login: React.FC = () => {
{/* Modern Glassy Background */}
<div className="absolute inset-0 overflow-hidden pointer-events-none">
{/* Top Left Blob */}
<div className="absolute -top-[20%] -left-[10%] w-[70%] h-[70%] rounded-full bg-gradient-to-br from-active-blue/30 to-purple-600/30 blur-[120px] animate-pulse" style={{ animationDuration: '8s' }}></div>
<div className="absolute -top-[20%] -left-[10%] w-[70%] h-[70%] rounded-full bg-gradient-to-br from-oliver-azure/30 to-purple-600/30 blur-[120px] animate-pulse" style={{ animationDuration: '8s' }}></div>
{/* Bottom Right Blob */}
<div className="absolute -bottom-[20%] -right-[10%] w-[70%] h-[70%] rounded-full bg-gradient-to-tl from-cyan-brand/30 to-emerald-500/30 blur-[120px] animate-pulse" style={{ animationDuration: '10s', animationDelay: '1s' }}></div>
<div className="absolute -bottom-[20%] -right-[10%] w-[70%] h-[70%] rounded-full bg-gradient-to-tl from-oliver-azure/30 to-emerald-500/30 blur-[120px] animate-pulse" style={{ animationDuration: '10s', animationDelay: '1s' }}></div>
{/* Noise Texture */}
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-20 mix-blend-soft-light"></div>
@ -175,10 +175,10 @@ export const Login: React.FC = () => {
{/* Login Card */}
<div className="relative z-10 bg-white/90 backdrop-blur-xl p-8 sm:p-12 shadow-2xl rounded-3xl w-full max-w-md flex flex-col items-center text-center border border-white/50 ring-1 ring-white/50">
<div className="mb-8 transform transition-transform hover:scale-105 duration-300">
<BarclaysLogo className="h-12 w-auto text-primary-blue" />
<BarclaysLogo className="h-12 w-auto text-oliver-black" />
</div>
<h1 className="text-3xl font-extrabold text-primary-blue mb-2 tracking-tight">Mod Comms</h1>
<h1 className="text-3xl font-extrabold text-oliver-black mb-2 tracking-tight">Mod Comms</h1>
<p className="text-slate-500 mb-8 font-medium">Proof Review &amp; Compliance Platform</p>
<div className="w-full space-y-6">
@ -204,7 +204,7 @@ export const Login: React.FC = () => {
className="w-full flex items-center justify-center gap-3 bg-white hover:bg-gray-50 text-slate-700 font-bold py-4 px-6 rounded-xl border border-gray-200 shadow-lg shadow-gray-200/50 hover:shadow-xl hover:border-gray-300 transition-all duration-300 group disabled:opacity-70 disabled:cursor-wait transform hover:-translate-y-0.5"
>
{isLoggingIn ? (
<svg className="animate-spin h-5 w-5 text-active-blue" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<svg className="animate-spin h-5 w-5 text-oliver-azure" 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>
@ -221,7 +221,7 @@ export const Login: React.FC = () => {
<button
type="button"
onClick={() => setIsSupportModalOpen(true)}
className="text-sm text-slate-500 hover:text-active-blue transition-colors font-medium"
className="text-sm text-slate-500 hover:text-oliver-azure transition-colors font-medium"
>
Having trouble signing in? Contact Support
</button>

View file

@ -92,18 +92,18 @@ export const Profile: React.FC<ProfileProps> = ({ onLogout, msalInstance }) => {
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-white">
<header className="mb-8">
<h1 className="text-3xl lg:text-4xl font-semibold text-primary-blue">Your Profile</h1>
<p className="text-base lg:text-lg text-grey-700 mt-1">View your account details and manage settings.</p>
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">Your Profile</h1>
<p className="text-base lg:text-lg text-oliver-black/60 mt-1">View your account details and manage settings.</p>
</header>
<div className="max-w-3xl">
<section className="p-6 sm:p-8">
<h2 className="text-2xl font-semibold text-primary-blue mb-6">Account Information</h2>
<h2 className="text-2xl font-semibold text-oliver-black mb-6">Account Information</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-5">
{Object.entries(userDetails).map(([key, value]) => (
<div key={key}>
<p className="text-sm font-semibold text-grey-700 tracking-wide uppercase">{key}</p>
<p className="text-lg text-black-title mt-1">{value}</p>
<p className="text-sm font-semibold text-oliver-black/60 tracking-wide uppercase">{key}</p>
<p className="text-lg text-oliver-black mt-1">{value}</p>
</div>
))}
</div>
@ -118,7 +118,7 @@ export const Profile: React.FC<ProfileProps> = ({ onLogout, msalInstance }) => {
</button>
<button
onClick={handleToggleQuestionForm}
className="flex items-center justify-center gap-2 text-active-blue hover:text-active-blue/80 bg-transparent font-semibold py-2 px-4 rounded-md transition-colors duration-300"
className="flex items-center justify-center gap-2 text-oliver-azure hover:text-oliver-azure/80 bg-transparent font-semibold py-2 px-4 rounded-md transition-colors duration-300"
>
<QuestionMarkIcon className="h-5 w-5" />
Got a question?
@ -128,9 +128,9 @@ export const Profile: React.FC<ProfileProps> = ({ onLogout, msalInstance }) => {
{isQuestionFormVisible && (
<section className="mt-8 p-6 sm:p-8">
<h2 className="text-2xl font-semibold text-primary-blue mb-4">Ask a Question</h2>
<h2 className="text-2xl font-semibold text-oliver-black mb-4">Ask a Question</h2>
<form onSubmit={handleSubmitQuestion}>
<p className="text-grey-700 mb-4">Your question will be sent to the OLIVER Agency support team.</p>
<p className="text-oliver-black/60 mb-4">Your question will be sent to the OLIVER Agency support team.</p>
{submitStatus && (
<div className={`mb-4 p-3 rounded-md ${submitStatus.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'}`}>
{submitStatus.message}
@ -139,7 +139,7 @@ export const Profile: React.FC<ProfileProps> = ({ onLogout, msalInstance }) => {
<textarea
value={question}
onChange={(e) => setQuestion(e.target.value)}
className="w-full p-3 border border-grey-300 rounded-md focus:ring-2 focus:ring-active-blue focus:border-active-blue transition text-black-title"
className="w-full p-3 border border-grey-300 rounded-md focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure transition text-oliver-black"
placeholder="Type your question here..."
rows={5}
required
@ -148,7 +148,7 @@ export const Profile: React.FC<ProfileProps> = ({ onLogout, msalInstance }) => {
<div className="mt-4 flex justify-end">
<button
type="submit"
className="bg-active-blue text-white font-semibold py-2 px-5 rounded-md hover:bg-primary-blue transition-colors duration-300 disabled:bg-grey-300 disabled:cursor-not-allowed flex items-center gap-2"
className="bg-oliver-azure text-white font-semibold py-2 px-5 rounded-md hover:bg-oliver-azure transition-colors duration-300 disabled:bg-gray-300 disabled:cursor-not-allowed flex items-center gap-2"
disabled={!question.trim() || isSubmitting}
>
{isSubmitting ? (

View file

@ -157,16 +157,16 @@ const StatusBadge: React.FC<{ status: string }> = ({ status }) => {
let colorClasses = '';
switch (status) {
case 'In Progress':
colorClasses = 'bg-warning text-black-title';
colorClasses = 'bg-warning text-oliver-black';
break;
case 'Completed':
colorClasses = 'bg-success text-white';
break;
case 'Needs Review':
colorClasses = 'bg-warning-light text-black-title';
colorClasses = 'bg-warning-light text-oliver-black';
break;
default:
colorClasses = 'bg-grey-100 text-black-title';
colorClasses = 'bg-oliver-grey text-oliver-black';
}
return (
<span className={`px-2.5 py-0.5 text-xs font-semibold rounded-full ${colorClasses}`}>
@ -185,7 +185,7 @@ const OverallStatusBadge: React.FC<{ status: 'Passed' | 'Failed' | 'Analysis Err
colorClasses = 'bg-error text-white';
break;
case 'Analysis Error':
colorClasses = 'bg-grey-300 text-black-title';
colorClasses = 'bg-grey-300 text-oliver-black';
break;
}
@ -209,37 +209,37 @@ const ProjectList: React.FC<{
const filteredProjects = showCompleted ? projects : projects.filter(p => p.status !== 'Completed');
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-active-blue 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-oliver-azure appearance-none cursor-pointer';
let colorClasses = '';
switch (status) {
case 'In Progress':
colorClasses = 'bg-warning text-black-title';
colorClasses = 'bg-warning text-oliver-black';
break;
case 'Completed':
colorClasses = 'bg-success text-white';
break;
default:
colorClasses = 'bg-grey-100 text-black-title';
colorClasses = 'bg-oliver-grey text-oliver-black';
}
return `${baseClasses} ${colorClasses}`;
};
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-grey-100">
<div className="p-4 sm:p-6 lg:p-8 h-full bg-oliver-grey">
<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-primary-blue">Projects</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">Manage your campaigns and proof collections.</p>
<h1 className="text-3xl lg:text-4xl font-bold text-oliver-black">Projects</h1>
<p className="text-base lg:text-lg text-oliver-black 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-black-title whitespace-nowrap">Show Completed</label>
<label htmlFor="show-completed" className="text-sm font-medium text-oliver-black whitespace-nowrap">Show Completed</label>
<ToggleSwitch enabled={showCompleted} onChange={setShowCompleted} />
</div>
<button
onClick={onOpenModal}
className="flex items-center gap-2 bg-active-blue text-white font-semibold py-2 px-4 rounded-full hover:bg-primary-blue transition-colors duration-300"
className="flex items-center gap-2 bg-oliver-azure text-white font-semibold py-2 px-4 rounded-full hover:bg-oliver-azure transition-colors duration-300"
>
<PlusIcon className="h-5 w-5" />
Create New Project
@ -252,22 +252,22 @@ const ProjectList: React.FC<{
<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-grey-300">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Project 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="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Project Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proofs</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Status</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Created By</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Owning Agency</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Last Modified</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-grey-300">
{filteredProjects.map((project) => {
return (
<tr key={project.name} className="hover:bg-info-light cursor-pointer even:bg-grey-100" onClick={() => onSelectProject(project.name)}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">{project.name}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{project.assets}</td>
<tr key={project.name} className="hover:bg-oliver-grey cursor-pointer even:bg-oliver-grey" onClick={() => onSelectProject(project.name)}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">{project.name}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{project.assets}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm w-40">
<div className="relative">
<select
@ -280,12 +280,12 @@ const ProjectList: 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-black-title" />
<ChevronDownIcon className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 h-full w-4 text-oliver-black" />
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{project.agencyLead}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{project.agency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{project.lastModified}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{project.agencyLead}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{project.agency}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{project.lastModified}</td>
</tr>
);
})}
@ -345,11 +345,11 @@ const ProjectAssetUpload: React.FC<{
return (
<section className="bg-white rounded-[10px] shadow-md p-6 border border-grey-300 mb-8">
<h2 className="text-xl font-bold text-primary-blue mb-4">Upload New Proof</h2>
<h2 className="text-xl font-bold text-oliver-black mb-4">Upload New Proof</h2>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="asset-name" className="flex items-center text-sm font-medium text-black-title mb-1">
<DocumentIcon className="h-5 w-5 mr-2 text-active-blue shrink-0" />
<label htmlFor="asset-name" className="flex items-center text-sm font-medium text-oliver-black mb-1">
<DocumentIcon className="h-5 w-5 mr-2 text-oliver-azure shrink-0" />
Proof Name
</label>
<input
@ -359,11 +359,11 @@ const ProjectAssetUpload: React.FC<{
onChange={(e) => setAssetName(e.target.value)}
placeholder="e.g., Q4 Hero Instagram Post"
disabled={isLoading}
className="w-full bg-white border border-grey-300 rounded-[10px] py-2 px-3 text-black-title focus:outline-none focus:ring-2 focus:ring-active-blue disabled:bg-grey-100"
className="w-full bg-white border border-grey-300 rounded-[10px] py-2 px-3 text-oliver-black focus:outline-none focus:ring-2 focus:ring-oliver-azure disabled:bg-oliver-grey"
required
/>
{isNewVersion && (
<p className="text-xs text-active-blue mt-2 p-2 bg-info-light rounded-[10px]">
<p className="text-xs text-oliver-azure mt-2 p-2 bg-oliver-grey rounded-[10px]">
A proof with this name already exists. This will be uploaded as a new version.
</p>
)}
@ -371,8 +371,8 @@ const ProjectAssetUpload: React.FC<{
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Channel Dropdown */}
<div>
<label htmlFor="asset-channel" className="flex items-center text-sm font-medium text-black-title mb-1">
<ChannelIcon className="h-5 w-5 mr-2 text-active-blue shrink-0" />
<label htmlFor="asset-channel" className="flex items-center text-sm font-medium text-oliver-black mb-1">
<ChannelIcon className="h-5 w-5 mr-2 text-oliver-azure shrink-0" />
Channel
</label>
<div className="relative">
@ -381,21 +381,21 @@ const ProjectAssetUpload: React.FC<{
value={channel}
onChange={(e) => setChannel(e.target.value)}
disabled={isLoading}
className="w-full bg-white border border-grey-300 rounded-[10px] py-2 pl-3 pr-10 text-black-title focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none disabled:bg-grey-100"
className="w-full bg-white border border-grey-300 rounded-[10px] py-2 pl-3 pr-10 text-oliver-black focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none disabled:bg-oliver-grey"
required
>
<option value="" disabled>Select Channel</option>
{availableChannels.map(opt => <option key={opt} value={opt}>{opt}</option>)}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-grey-700">
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-oliver-black/60">
<ChevronDownIcon className="h-4 w-4" />
</div>
</div>
</div>
{/* Sub-Channel Dropdown */}
<div>
<label htmlFor="asset-sub-channel" className="flex items-center text-sm font-medium text-black-title mb-1">
<TagIcon className="h-5 w-5 mr-2 text-active-blue shrink-0" />
<label htmlFor="asset-sub-channel" className="flex items-center text-sm font-medium text-oliver-black mb-1">
<TagIcon className="h-5 w-5 mr-2 text-oliver-azure shrink-0" />
Sub-Channel
</label>
<div className="relative">
@ -404,13 +404,13 @@ const ProjectAssetUpload: React.FC<{
value={subChannel}
onChange={(e) => setSubChannel(e.target.value)}
disabled={isLoading || !channel}
className="w-full bg-white border border-grey-300 rounded-[10px] py-2 pl-3 pr-10 text-black-title focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none disabled:bg-grey-100 disabled:text-grey-700"
className="w-full bg-white border border-grey-300 rounded-[10px] py-2 pl-3 pr-10 text-oliver-black focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none disabled:bg-oliver-grey disabled:text-oliver-black/60"
required
>
<option value="" disabled>Select Sub-Channel</option>
{availableSubChannels.map(opt => <option key={opt} value={opt}>{opt}</option>)}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-grey-700">
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-oliver-black/60">
<ChevronDownIcon className="h-4 w-4" />
</div>
</div>
@ -418,27 +418,27 @@ const ProjectAssetUpload: React.FC<{
</div>
<div>
<label className="block text-sm font-medium text-black-title mb-1">Proof File</label>
<label className="block text-sm font-medium text-oliver-black mb-1">Proof File</label>
<div className="mt-1 flex justify-center px-6 pt-5 pb-6 border-2 border-grey-300 border-dashed rounded-[10px]">
<div className="space-y-1 text-center">
<UploadIcon className="mx-auto h-12 w-12 text-grey-700" />
<div className="flex text-sm text-black-title">
<label htmlFor="file-upload" className="relative cursor-pointer bg-white rounded-[10px] font-medium text-active-blue hover:text-primary-blue focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-active-blue">
<UploadIcon className="mx-auto h-12 w-12 text-oliver-black/60" />
<div className="flex text-sm text-oliver-black">
<label htmlFor="file-upload" className="relative cursor-pointer bg-white rounded-[10px] font-medium text-oliver-azure hover:text-oliver-black focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-oliver-azure">
<span>Upload a file</span>
<input id="file-upload" name="file-upload" type="file" className="sr-only" ref={fileInputRef} onChange={handleFileChange} disabled={isLoading} accept="image/png, image/jpeg, image/webp, image/gif, video/mp4, application/pdf" />
</label>
<p className="pl-1">or drag and drop</p>
</div>
{file ? <p className="text-sm font-semibold text-primary-blue mt-2">{file.name}</p> : <p className="text-xs text-grey-900">PNG, JPG, GIF, WEBP, MP4, PDF</p>}
{file ? <p className="text-sm font-semibold text-oliver-black mt-2">{file.name}</p> : <p className="text-xs text-oliver-black">PNG, JPG, GIF, WEBP, MP4, PDF</p>}
</div>
</div>
</div>
<div className="flex justify-end pt-2 gap-3">
<button type="button" onClick={onCancel} disabled={isLoading} className="bg-grey-300 text-black-title font-semibold py-2.5 px-5 rounded-full hover:bg-grey-700 hover:text-white transition-colors duration-300 disabled:opacity-50">
<button type="button" onClick={onCancel} disabled={isLoading} className="bg-grey-300 text-oliver-black font-semibold py-2.5 px-5 rounded-full hover:bg-gray-500 hover:text-white transition-colors duration-300 disabled:opacity-50">
Cancel
</button>
<button type="submit" disabled={isSubmitDisabled} className="flex items-center justify-center bg-active-blue text-white font-bold py-2.5 px-5 rounded-full hover:bg-primary-blue transition-all duration-300 disabled:bg-grey-700 disabled:cursor-not-allowed">
<button type="submit" disabled={isSubmitDisabled} className="flex items-center justify-center bg-oliver-azure text-white font-bold py-2.5 px-5 rounded-full hover:bg-oliver-azure transition-all duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed">
{isLoading ? (
<>
<svg className="animate-spin -ml-1 mr-3 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
@ -472,11 +472,11 @@ const LoadingCell: React.FC<{ progress: { completed: number; total: number } }>
<div className="flex flex-col items-center justify-center h-full px-2 text-center w-full">
<div className="w-full bg-grey-300 rounded-full h-1.5 mb-1.5">
<div
className="bg-active-blue h-1.5 rounded-full"
className="bg-oliver-azure h-1.5 rounded-full"
style={{ width: `${percent}%`, transition: 'width 0.3s ease-in-out' }}
></div>
</div>
<span className="text-xs text-black-title truncate w-full">{statusText} ({percent}%)</span>
<span className="text-xs text-oliver-black truncate w-full">{statusText} ({percent}%)</span>
</div>
);
};
@ -514,8 +514,8 @@ const AnalysisErrorModal: React.FC<{
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" />
</div>
<div>
<h3 className="text-xl font-bold text-primary-blue">Analysis Error</h3>
<p className="text-sm text-grey-700 mt-0.5">{assetName}</p>
<h3 className="text-xl font-bold text-oliver-black">Analysis Error</h3>
<p className="text-sm text-oliver-black/60 mt-0.5">{assetName}</p>
</div>
</div>
@ -528,11 +528,11 @@ const AnalysisErrorModal: React.FC<{
{failedAgents.length > 0 && (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-grey-700">Agent Details</h4>
<h4 className="text-sm font-semibold text-oliver-black/60">Agent Details</h4>
{failedAgents.map(agent => (
<div key={agent.label} className="bg-grey-100 rounded-lg p-3">
<p className="text-sm font-medium text-primary-blue">{agent.label}</p>
<p className="text-sm text-grey-700 mt-1">{agent.review.feedback}</p>
<div key={agent.label} className="bg-oliver-grey rounded-lg p-3">
<p className="text-sm font-medium text-oliver-black">{agent.label}</p>
<p className="text-sm text-oliver-black/60 mt-1">{agent.review.feedback}</p>
</div>
))}
</div>
@ -542,7 +542,7 @@ const AnalysisErrorModal: React.FC<{
<button
type="button"
onClick={onClose}
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"
className="border-2 border-oliver-azure text-oliver-azure font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure hover:text-white transition-colors"
>
Close
</button>
@ -571,15 +571,15 @@ const DeleteConfirmationModal: React.FC<{
className="bg-white rounded-[10px] shadow-xl p-6 sm:p-8 w-full max-w-md transform transition-all"
onClick={e => e.stopPropagation()}
>
<h3 className="text-xl font-bold text-primary-blue">Confirm Deletion</h3>
<p className="text-black-title my-4">
<h3 className="text-xl font-bold text-oliver-black">Confirm Deletion</h3>
<p className="text-oliver-black my-4">
Are you sure you want to permanently delete the proof "{assetName}"? This action cannot be undone.
</p>
<div className="mt-6 flex justify-end gap-3">
<button
type="button"
onClick={onClose}
className="bg-grey-300 text-black-title font-semibold py-2 px-4 rounded-full hover:bg-grey-700 hover:text-white transition-colors"
className="bg-grey-300 text-oliver-black font-semibold py-2 px-4 rounded-full hover:bg-gray-500 hover:text-white transition-colors"
>
Cancel
</button>
@ -649,7 +649,7 @@ const ProjectDetail: React.FC<{
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-grey-100">
<div className="p-4 sm:p-6 lg:p-8 h-full bg-oliver-grey">
<DeleteConfirmationModal
isOpen={!!assetToDelete}
onClose={() => setAssetToDelete(null)}
@ -677,15 +677,15 @@ const ProjectDetail: React.FC<{
<div className="flex items-center gap-4">
<button
onClick={onBack}
className="p-2 text-grey-700 rounded-full hover:bg-grey-300 hover:text-primary-blue transition-colors duration-200"
className="p-2 text-oliver-black/60 rounded-full hover:bg-grey-300 hover:text-oliver-black transition-colors duration-200"
title="Back to projects"
aria-label="Back to projects list"
>
<ArrowLeftIcon className="h-6 w-6" />
</button>
<div>
<h1 className="text-3xl lg:text-4xl font-bold text-primary-blue">{projectName}</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">Proof overview and compliance status.</p>
<h1 className="text-3xl lg:text-4xl font-bold text-oliver-black">{projectName}</h1>
<p className="text-base lg:text-lg text-oliver-black mt-1">Proof overview and compliance status.</p>
</div>
</div>
</header>
@ -708,14 +708,14 @@ const ProjectDetail: React.FC<{
<div className="mb-6 flex justify-end gap-3">
<button
onClick={() => console.log('Download all proofs clicked')}
className="flex items-center gap-2 bg-white text-active-blue font-semibold py-2 px-4 rounded-full border-2 border-active-blue hover:bg-active-blue/10 transition-colors duration-300"
className="flex items-center gap-2 bg-white text-oliver-azure font-semibold py-2 px-4 rounded-full border-2 border-oliver-azure hover:bg-oliver-azure/10 transition-colors duration-300"
>
<DownloadIcon className="h-5 w-5" />
Download All Proofs
</button>
<button
onClick={() => setIsUploadFormVisible(true)}
className="flex items-center gap-2 bg-active-blue text-white font-semibold py-2 px-4 rounded-full hover:bg-primary-blue transition-colors duration-300"
className="flex items-center gap-2 bg-oliver-azure text-white font-semibold py-2 px-4 rounded-full hover:bg-oliver-azure transition-colors duration-300"
>
<PlusIcon className="h-5 w-5" />
Upload New Proof
@ -725,13 +725,13 @@ const ProjectDetail: React.FC<{
<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-grey-300">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<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">Workfront #</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Sub-Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Overall Status</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Proof Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Workfront #</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Sub-Channel</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Overall Status</th>
<th scope="col" className="relative px-6 py-3"><span className="sr-only">Actions</span></th>
</tr>
</thead>
@ -739,17 +739,17 @@ const ProjectDetail: React.FC<{
{assets.map((asset, index) => {
if (asset.status === 'analyzing') {
return (
<tr key={asset.tempId} className="bg-grey-100 opacity-80">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">{asset.assetName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-grey-700 italic">Pending</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{asset.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{asset.subChannel}</td>
<tr key={asset.tempId} className="bg-oliver-grey opacity-80">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">{asset.assetName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black/60 italic">Pending</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{asset.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{asset.subChannel}</td>
<td className="px-6 py-4" colSpan={2}>
{asset.analysisProgress ?
<LoadingCell progress={asset.analysisProgress} /> :
<div className="flex justify-center items-center h-full">
<SpinnerIcon className="h-5 w-5 text-active-blue custom-spinner" />
<span className="ml-2 text-sm text-black-title">Preparing...</span>
<SpinnerIcon className="h-5 w-5 text-oliver-azure custom-spinner" />
<span className="ml-2 text-sm text-oliver-black">Preparing...</span>
</div>
}
</td>
@ -760,10 +760,10 @@ const ProjectDetail: React.FC<{
if (asset.status === 'error') {
return (
<tr key={asset.tempId} className="bg-error-light">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">{asset.assetName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-grey-700 italic">Failed</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{asset.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{asset.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">{asset.assetName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black/60 italic">Failed</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{asset.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{asset.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-error font-semibold" colSpan={2}>
<div className="flex items-center justify-between">
<button
@ -774,7 +774,7 @@ const ProjectDetail: React.FC<{
</button>
<button
onClick={() => onRetryAnalysis(projectName, asset.tempId || asset._id)}
className="flex items-center gap-1.5 text-xs font-semibold text-active-blue hover:text-primary-blue whitespace-nowrap px-3 py-1.5 rounded-full bg-active-blue/10 hover:bg-active-blue/20 transition-colors"
className="flex items-center gap-1.5 text-xs font-semibold text-oliver-azure hover:text-oliver-black whitespace-nowrap px-3 py-1.5 rounded-full bg-oliver-azure/10 hover:bg-oliver-azure/20 transition-colors"
>
<ArrowPathIcon className="h-4 w-4" />
Retry
@ -794,20 +794,20 @@ const ProjectDetail: React.FC<{
return (
<tr
key={latestVersion.workfrontId || index}
className={isClickable ? "hover:bg-info-light cursor-pointer even:bg-grey-100" : "even:bg-grey-100"}
className={isClickable ? "hover:bg-oliver-grey cursor-pointer even:bg-oliver-grey" : "even:bg-oliver-grey"}
onClick={() => isClickable && onSelectAsset(asset)}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-primary-blue">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-oliver-black">
{asset.assetName}
{isVersioned && (
<span className="ml-2 bg-grey-300 text-black-title text-xs font-bold px-2 py-0.5 rounded-full">
<span className="ml-2 bg-grey-300 text-oliver-black text-xs font-bold px-2 py-0.5 rounded-full">
V{latestVersion.version}
</span>
)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{latestVersion.workfrontId}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{asset.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">{asset.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{latestVersion.workfrontId}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{asset.channel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">{asset.subChannel}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
<OverallStatusBadge status={latestVersion.overallStatus} />
</td>
@ -815,7 +815,7 @@ const ProjectDetail: React.FC<{
<div className="flex items-center justify-end gap-1">
<button
onClick={(e) => handleNewVersionClick(e, asset)}
className="p-2 text-grey-700 rounded-full hover:bg-info-light hover:text-active-blue transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
className="p-2 text-oliver-black/60 rounded-full hover:bg-oliver-grey hover:text-oliver-azure transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
title={`Upload new version of ${asset.assetName}`}
disabled={isUploading}
>
@ -823,7 +823,7 @@ const ProjectDetail: React.FC<{
</button>
<button
onClick={(e) => { e.stopPropagation(); console.log('Download proof clicked'); }}
className="p-2 text-grey-700 rounded-full hover:bg-success-light hover:text-success transition-colors"
className="p-2 text-oliver-black/60 rounded-full hover:bg-success-light hover:text-success transition-colors"
title={`Download ${asset.assetName}`}
>
<DownloadIcon className="h-5 w-5" />
@ -833,7 +833,7 @@ const ProjectDetail: React.FC<{
e.stopPropagation();
setAssetToDelete(asset);
}}
className="p-2 text-grey-700 rounded-full hover:bg-error-light hover:text-error transition-colors"
className="p-2 text-oliver-black/60 rounded-full hover:bg-error-light hover:text-error transition-colors"
title={`Delete ${asset.assetName}`}
>
<TrashIcon className="h-5 w-5" />
@ -923,20 +923,20 @@ const AssetDetailView: React.FC<{
}
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-grey-100">
<div className="p-4 sm:p-6 lg:p-8 h-full bg-oliver-grey">
<header className="mb-8">
<div className="flex items-center gap-4">
<button
onClick={onBack}
className="p-2 text-grey-700 rounded-full hover:bg-grey-300 hover:text-primary-blue transition-colors duration-200"
className="p-2 text-oliver-black/60 rounded-full hover:bg-grey-300 hover:text-oliver-black transition-colors duration-200"
title="Back to project details"
aria-label="Back to project details"
>
<ArrowLeftIcon className="h-6 w-6" />
</button>
<div>
<h1 className="text-3xl lg:text-4xl font-bold text-primary-blue">{asset.assetName}</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">Detailed AI feedback report.</p>
<h1 className="text-3xl lg:text-4xl font-bold text-oliver-black">{asset.assetName}</h1>
<p className="text-base lg:text-lg text-oliver-black mt-1">Detailed AI feedback report.</p>
</div>
</div>
</header>
@ -945,7 +945,7 @@ const AssetDetailView: React.FC<{
<div className="lg:col-span-1">
<div className="sticky top-8 flex flex-col gap-y-6">
<div>
<h2 className="text-2xl font-bold text-primary-blue mb-4">
<h2 className="text-2xl font-bold text-oliver-black mb-4">
Proof Preview
</h2>
<AssetPreview
@ -956,14 +956,14 @@ const AssetDetailView: React.FC<{
<div>
<div className="flex items-center justify-between mb-3 gap-2">
<h3 className="text-xl font-bold text-primary-blue flex items-center gap-2">
<HistoryIcon className="h-6 w-6 text-active-blue"/>
<h3 className="text-xl font-bold text-oliver-black flex items-center gap-2">
<HistoryIcon className="h-6 w-6 text-oliver-azure"/>
Version History
</h3>
<div className="flex items-center gap-2">
<button
onClick={() => console.log('Download version clicked')}
className="flex items-center gap-2 text-sm bg-active-blue text-white font-semibold py-1.5 px-3 rounded-full border border-transparent hover:bg-primary-blue transition-colors duration-200"
className="flex items-center gap-2 text-sm bg-oliver-azure text-white font-semibold py-1.5 px-3 rounded-full border border-transparent hover:bg-oliver-azure transition-colors duration-200"
title={`Download Version ${selectedVersion.version}`}
>
<DownloadIcon className="h-4 w-4" />
@ -972,7 +972,7 @@ const AssetDetailView: React.FC<{
<button
onClick={handleUploadClick}
disabled={isUploadingNewVersion}
className="flex items-center gap-2 text-sm bg-white text-active-blue font-semibold py-1.5 px-3 rounded-full border-2 border-active-blue hover:bg-active-blue/10 transition-colors duration-200 disabled:bg-grey-300 disabled:text-grey-700 disabled:cursor-wait"
className="flex items-center gap-2 text-sm bg-white text-oliver-azure font-semibold py-1.5 px-3 rounded-full border-2 border-oliver-azure hover:bg-oliver-azure/10 transition-colors duration-200 disabled:bg-gray-300 disabled:text-oliver-black/60 disabled:cursor-wait"
title="Upload a new version of this proof"
>
{isUploadingNewVersion ? (
@ -1006,15 +1006,15 @@ const AssetDetailView: React.FC<{
onClick={() => setSelectedVersionIndex(index)}
className={`w-full text-left p-3 rounded-[10px] border-2 transition-all ${
isActive
? 'bg-info-light border-active-blue shadow-sm'
: 'bg-white border-grey-300 hover:border-active-blue/50 hover:bg-grey-100'
? 'bg-oliver-grey border-oliver-azure shadow-sm'
: 'bg-white border-grey-300 hover:border-oliver-azure/50 hover:bg-oliver-grey'
}`}
>
<div className="flex justify-between items-center">
<p className={`font-bold ${isActive ? 'text-primary-blue' : 'text-black-title'}`}>Version {version.version}</p>
<p className="text-xs text-grey-700">{version.timestamp}</p>
<p className={`font-bold ${isActive ? 'text-oliver-black' : 'text-oliver-black'}`}>Version {version.version}</p>
<p className="text-xs text-oliver-black/60">{version.timestamp}</p>
</div>
<p className="text-sm text-black-title mt-1">Workfront ID: {version.workfrontId}</p>
<p className="text-sm text-oliver-black mt-1">Workfront ID: {version.workfrontId}</p>
</button>
);
})}

View file

@ -128,7 +128,7 @@ export const ProofPreview: React.FC<ProofPreviewProps> = ({ file, previewUrl, fi
style={{ minHeight: '300px', maxHeight: 'calc(100vh - 9rem)' }}
>
<DocumentIcon className="h-20 w-20 text-gray-400 mb-4" />
<p className="text-lg font-semibold text-primary-blue break-all">{displayName}</p>
<p className="text-lg font-semibold text-oliver-black break-all">{displayName}</p>
<p className="text-sm text-gray-500">{fileType}</p>
<p className="text-sm text-gray-500 mt-2">No preview available for this file type.</p>
</div>

View file

@ -39,7 +39,7 @@ export const ProofTypeManager: React.FC<ProofTypeManagerProps> = ({
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-primary-blue mb-2">Proof Type Manager</h2>
<h2 className="text-xl font-bold text-oliver-black mb-2">Proof Type Manager</h2>
<p className="text-sm text-gray-500 mb-4">Assign and manage specific proof types for each sub-channel.</p>
<div className="mb-4">
@ -51,7 +51,7 @@ export const ProofTypeManager: React.FC<ProofTypeManagerProps> = ({
id="subchannel-select"
value={selectedSubChannel}
onChange={(e) => setSelectedSubChannel(e.target.value)}
className="w-full bg-white border border-gray-300 rounded-md py-2 pl-3 pr-10 text-gray-900 focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none disabled:bg-gray-100"
className="w-full bg-white border border-gray-300 rounded-md py-2 pl-3 pr-10 text-gray-900 focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none disabled:bg-gray-100"
disabled={disabled}
>
{subChannels.map(sc => (
@ -70,12 +70,12 @@ export const ProofTypeManager: React.FC<ProofTypeManagerProps> = ({
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
placeholder="New Proof Type..."
className="flex-grow p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-active-blue focus:border-active-blue transition disabled:bg-gray-100 disabled:cursor-not-allowed"
className="flex-grow p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure transition disabled:bg-gray-100 disabled:cursor-not-allowed"
disabled={disabled || !selectedSubChannel}
/>
<button
type="submit"
className="bg-active-blue text-white font-semibold py-2 px-4 rounded-md hover:bg-primary-blue transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
className="bg-oliver-azure text-white font-semibold py-2 px-4 rounded-md hover:bg-oliver-azure transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
disabled={!newItem.trim() || disabled || !selectedSubChannel}
>
Add

View file

@ -36,7 +36,7 @@ export const AssetUpload: React.FC<AssetUploadProps> = ({ onFileUpload, isLoadin
onClick={handleClick}
disabled={isDisabled}
title={isUploadDisabled ? "Please complete all selections above" : "Upload a proof for review"}
className="w-full bg-cyan-brand text-primary-blue font-bold py-3 px-6 rounded-full hover:bg-white transition-all duration-300 disabled:bg-gray-500 disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center"
className="w-full bg-oliver-azure text-oliver-black font-bold py-3 px-6 rounded-full hover:bg-white transition-all duration-300 disabled:bg-gray-500 disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center"
>
{isLoading ? (
<>

View file

@ -29,7 +29,7 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ title, items, onAdd, on
return (
<div className="p-6 flex flex-col h-full">
<h2 className="text-xl font-semibold text-primary-blue mb-4">{title}</h2>
<h2 className="text-xl font-semibold text-oliver-black mb-4">{title}</h2>
<form onSubmit={handleSubmit} className="flex gap-2 mb-4">
<input
@ -37,12 +37,12 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ title, items, onAdd, on
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
placeholder={placeholder || `New ${title.slice(0, -1)}...`}
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"
className="flex-grow p-2 border-2 border-oliver-azure rounded-[10px] focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure transition disabled:bg-oliver-grey disabled:cursor-not-allowed text-oliver-black"
disabled={disabled}
/>
<button
type="submit"
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"
className="bg-oliver-azure text-white font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
disabled={!newItem.trim() || disabled}
>
Add
@ -55,12 +55,12 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ title, items, onAdd, on
{items.map((item) => (
<li
key={item}
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"
className="flex items-center justify-between bg-oliver-grey p-2.5 rounded-[10px] border border-grey-300 group hover:border-oliver-azure/30 transition-colors"
>
<span className="text-black-title">{item}</span>
<span className="text-oliver-black">{item}</span>
<button
onClick={() => onRemove(item)}
className={`text-grey-700 hover:text-error transition-opacity ${disabled ? 'opacity-0 cursor-not-allowed' : 'opacity-0 group-hover:opacity-100'}`}
className={`text-oliver-black/60 hover:text-error transition-opacity ${disabled ? 'opacity-0 cursor-not-allowed' : 'opacity-0 group-hover:opacity-100'}`}
title={`Remove ${item}`}
disabled={disabled}
>
@ -70,7 +70,7 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ title, items, onAdd, on
))}
</ul>
) : (
<div className="text-center py-8 text-grey-700 bg-grey-100 rounded-[10px]">
<div className="text-center py-8 text-oliver-black/60 bg-oliver-grey rounded-[10px]">
No items found.
</div>
)}
@ -158,49 +158,49 @@ const UsersTab: React.FC = () => {
<div className="space-y-8">
{/* Add User Section */}
<div className="p-6">
<h3 className="text-lg font-semibold text-primary-blue mb-4 flex items-center gap-2">
<PlusIcon className="h-5 w-5 text-active-blue" />
<h3 className="text-lg font-semibold text-oliver-black mb-4 flex items-center gap-2">
<PlusIcon className="h-5 w-5 text-oliver-azure" />
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-black-title mb-1">Name</label>
<label className="block text-xs font-medium text-oliver-black mb-1">Name</label>
<input
type="text"
value={newName}
onChange={(e) => setNewName(e.target.value)}
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"
className="w-full p-2 border-2 border-oliver-azure rounded-[10px] focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure text-oliver-black"
placeholder="e.g. John Smith"
required
/>
</div>
<div>
<label className="block text-xs font-medium text-black-title mb-1">Email</label>
<label className="block text-xs font-medium text-oliver-black mb-1">Email</label>
<input
type="email"
value={newEmail}
onChange={(e) => setNewEmail(e.target.value)}
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"
className="w-full p-2 border-2 border-oliver-azure rounded-[10px] focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure text-oliver-black"
placeholder="user@example.com"
required
/>
</div>
<div>
<label className="block text-xs font-medium text-black-title mb-1">Agency</label>
<label className="block text-xs font-medium text-oliver-black mb-1">Agency</label>
<div className="relative">
<select
value={newAgency}
onChange={(e) => setNewAgency(e.target.value)}
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"
className="w-full p-2 border-2 border-oliver-azure rounded-[10px] focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure appearance-none text-oliver-black"
>
{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-grey-700 pointer-events-none" />
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-oliver-black/60 pointer-events-none" />
</div>
</div>
<button
type="submit"
className="bg-active-blue text-white font-semibold py-2 px-6 rounded-full hover:bg-active-blue/90 transition-colors"
className="bg-oliver-azure text-white font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors"
>
Add User
</button>
@ -211,46 +211,46 @@ const UsersTab: React.FC = () => {
<div className="overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<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="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Name</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Email</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-bold text-oliver-black 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="divide-y divide-grey-300">
{users.map((user, index) => (
<tr key={user.id} className={index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}>
<tr key={user.id} className={index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'}>
<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-info-light flex items-center justify-center text-active-blue">
<div className="flex-shrink-0 h-8 w-8 rounded-full bg-oliver-grey flex items-center justify-center text-oliver-azure">
<UserIcon className="h-4 w-4" />
</div>
<div className="ml-4">
<div className="text-sm font-medium text-black-title">{user.name}</div>
<div className="text-sm font-medium text-oliver-black">{user.name}</div>
</div>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">
{user.email}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">
<div className="relative max-w-xs">
<select
value={user.agency}
onChange={(e) => handleAgencyChange(user.id, e.target.value)}
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"
className="w-full bg-white border-2 border-oliver-azure text-oliver-black py-1.5 pl-3 pr-8 rounded-[10px] text-sm focus:outline-none focus:ring-2 focus:ring-oliver-azure 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-active-blue pointer-events-none" />
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-oliver-azure pointer-events-none" />
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
onClick={() => handleDeleteUser(user.id)}
className="text-grey-700 hover:text-error transition-colors"
className="text-oliver-black/60 hover:text-error transition-colors"
title="Remove User"
>
<TrashIcon className="h-5 w-5" />
@ -321,12 +321,12 @@ export const Settings: React.FC<SettingsProps> = ({
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-white flex flex-col">
<header className="mb-6 flex-shrink-0">
<h1 className="text-3xl lg:text-4xl font-semibold text-primary-blue">Settings</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">Settings</h1>
<p className="text-base lg:text-lg text-oliver-black mt-1">
Configure application defaults and user access.
</p>
{readOnly && (
<div className="mt-3 inline-flex items-center gap-2 bg-info-light border border-active-blue text-active-blue text-sm font-medium px-4 py-2 rounded-[10px]">
<div className="mt-3 inline-flex items-center gap-2 bg-oliver-grey border border-oliver-azure text-oliver-azure text-sm font-medium px-4 py-2 rounded-[10px]">
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" /><path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
View-only mode
</div>
@ -350,8 +350,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-active-blue text-active-blue'
: 'border-transparent text-black-title hover:text-active-blue hover:border-grey-300'
? 'border-oliver-azure text-oliver-azure'
: 'border-transparent text-oliver-black hover:text-oliver-azure hover:border-grey-300'
}
`}
aria-current={activeTab === tab.id ? 'page' : undefined}
@ -393,17 +393,17 @@ export const Settings: React.FC<SettingsProps> = ({
{activeTab === 'SubChannels' && (
<div className="max-w-3xl space-y-4">
<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>
<label className="block text-sm font-medium text-oliver-black mb-2">Select Parent Channel</label>
<div className="relative">
<select
value={selectedChannel}
onChange={(e) => setSelectedChannel(e.target.value)}
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'}`}
className={`w-full p-2 border-2 rounded-[10px] focus:ring-2 focus:ring-oliver-azure appearance-none text-oliver-black ${selectedChannel ? 'bg-oliver-grey border-oliver-azure' : 'border-oliver-azure'}`}
>
<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-active-blue pointer-events-none"/>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-oliver-azure pointer-events-none"/>
</div>
</div>
@ -422,7 +422,7 @@ export const Settings: React.FC<SettingsProps> = ({
<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-[10px] border border-grey-300 shadow-sm">
<label className="block text-sm font-medium text-black-title mb-2">Select Channel</label>
<label className="block text-sm font-medium text-oliver-black mb-2">Select Channel</label>
<div className="relative">
<select
value={selectedChannel}
@ -430,22 +430,22 @@ export const Settings: React.FC<SettingsProps> = ({
setSelectedChannel(e.target.value);
setSelectedSubChannel('');
}}
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'}`}
className={`w-full p-2 border-2 rounded-[10px] focus:ring-2 focus:ring-oliver-azure appearance-none text-oliver-black ${selectedChannel ? 'bg-oliver-grey border-oliver-azure' : 'border-oliver-azure'}`}
>
<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-active-blue pointer-events-none"/>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-oliver-azure pointer-events-none"/>
</div>
</div>
<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>
<label className="block text-sm font-medium text-oliver-black mb-2">Select Sub-Channel</label>
<div className="relative">
<select
value={selectedSubChannel}
onChange={(e) => setSelectedSubChannel(e.target.value)}
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'}`}
className={`w-full p-2 border-2 rounded-[10px] focus:ring-2 focus:ring-oliver-azure appearance-none text-oliver-black disabled:bg-oliver-grey disabled:border-grey-300 ${selectedSubChannel ? 'bg-oliver-grey border-oliver-azure' : 'border-oliver-azure'}`}
disabled={!selectedChannel}
>
<option value="" disabled>Select Sub-Channel</option>
@ -453,7 +453,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-active-blue pointer-events-none"/>
<ChevronDownIcon className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-oliver-azure pointer-events-none"/>
</div>
</div>
</div>

View file

@ -1,6 +1,5 @@
import React from 'react';
import { BarclaysLogo } from './icons/BarclaysLogo';
import { DashboardIcon } from './icons/DashboardIcon';
import { AnalyticsIcon } from './icons/AnalyticsIcon';
import { SettingsIcon } from './icons/SettingsIcon';
@ -36,19 +35,10 @@ interface SidebarProps {
export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userName, userEmail, userRole }) => {
return (
<aside className="w-72 flex-shrink-0 bg-primary-blue text-slate-200 flex flex-col border-r border-white/10 font-sans">
<aside className="w-72 flex-shrink-0 bg-oliver-black text-slate-200 flex flex-col font-sans">
{/* Brand Header */}
<div className="py-6 px-8 border-b border-white/10 flex flex-col items-center text-center">
<BarclaysLogo className="h-10 w-auto text-cyan-brand mb-2" />
<span className="text-lg font-bold tracking-tight text-white leading-tight">
Mod Comms
</span>
<span className="text-xs text-lime uppercase tracking-widest font-semibold">
Compliance AI
</span>
<span className="text-xs text-grey-700 tracking-wider mt-0.5">
powered by <span className="font-bold">OLIVER</span>
</span>
<img src="/BAR-ModComms-logo-v4.png" alt="Mod Comms AI" className="h-12 w-auto" />
</div>
{/* Navigation */}
@ -63,7 +53,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userNa
onClick={() => onNavigate(item.name)}
className={`group w-full flex items-center pl-8 pr-4 py-3.5 text-left text-sm font-medium transition-all duration-300 ease-in-out ${
isActive
? 'bg-white text-primary-blue shadow-lg rounded-r-[10px] rounded-l-none'
? 'bg-oliver-azure text-white shadow-lg rounded-r-[10px] rounded-l-none'
: 'text-slate-300 hover:bg-white/10 hover:text-white rounded-[10px]'
}`}
aria-current={isActive ? 'page' : undefined}
@ -76,7 +66,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userNa
</nav>
{/* User Profile Snippet */}
<div className="p-4 border-t border-white/10 bg-primary-blue/80">
<div className="p-4 border-t border-white/10 bg-oliver-black/80">
<button
onClick={() => onNavigate('Profile')}
className={`group w-full flex items-center gap-3 p-3 rounded-[10px] text-left transition-all duration-200 ${
@ -85,7 +75,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ activeItem, onNavigate, userNa
: 'hover:bg-white/10'
}`}
>
<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">
<div className="w-10 h-10 rounded-full bg-oliver-azure flex items-center justify-center ring-2 ring-white/20 group-hover:ring-oliver-azure/50 transition-all">
<UserIcon className="h-5 w-5 text-white" />
</div>
<div className="overflow-hidden">

View file

@ -35,7 +35,7 @@ const StatusInfo: React.FC<StatusInfoProps> = ({ status, isHeroVariant = false }
complete: 'text-success',
issues: 'text-warning',
error: 'text-error',
pending: 'text-grey-700'
pending: 'text-oliver-black/60'
};
switch (status) {
@ -80,18 +80,18 @@ export const StatusDashboard: React.FC<StatusDashboardProps> = ({ status, varian
case 'error':
return `${defaultBase} bg-error-light border-error`;
default: // 'pending' or 'in-progress'
return `${defaultBase} bg-grey-100 border-grey-300`;
return `${defaultBase} bg-oliver-grey border-grey-300`;
}
}
};
return (
<div className={isHeroVariant ? '' : "mb-12"}>
<h3 className={`text-2xl font-bold text-center mb-8 ${isHeroVariant ? 'text-white' : 'text-primary-blue'}`}>Review Progress</h3>
<h3 className={`text-2xl font-bold text-center mb-8 ${isHeroVariant ? 'text-white' : 'text-oliver-black'}`}>Review Progress</h3>
<div className={`grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 ${isHeroVariant ? 'gap-4' : 'gap-6'}`}>
{AGENT_NAMES.map((agentName) => {
const agentStatus = status[agentName] || 'pending';
const iconColor = isHeroVariant ? 'text-cyan-brand' : 'text-active-blue';
const iconColor = isHeroVariant ? 'text-oliver-azure' : 'text-oliver-azure';
const Icon = agentIcons[agentName];
return (
@ -100,11 +100,11 @@ export const StatusDashboard: React.FC<StatusDashboardProps> = ({ status, varian
<div className="mb-3 h-8 w-8 flex items-center justify-center">
<Icon className={`h-8 w-8 ${iconColor}`} />
</div>
<h4 className={`text-base font-bold ${isHeroVariant ? 'text-white' : 'text-primary-blue'}`}>{agentName}</h4>
<h4 className={`text-base font-bold ${isHeroVariant ? 'text-white' : 'text-oliver-black'}`}>{agentName}</h4>
</div>
<div className="font-semibold text-xs mt-2 h-6 flex items-center justify-center">
{agentStatus === 'in-progress' ? (
<div className={`flex items-center ${isHeroVariant ? 'text-white/80' : 'text-grey-700'}`}>
<div className={`flex items-center ${isHeroVariant ? 'text-white/80' : 'text-oliver-black/60'}`}>
<SpinnerIcon className="h-4 w-4 mr-2 custom-spinner" />
<span>Analysing...</span>
</div>

View file

@ -9,8 +9,8 @@ export const ToggleSwitch: React.FC<ToggleSwitchProps> = ({ enabled, onChange })
return (
<button
type="button"
className={`relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-active-blue focus:ring-offset-2 ${
enabled ? 'bg-active-blue' : 'bg-gray-300'
className={`relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-oliver-azure focus:ring-offset-2 ${
enabled ? 'bg-oliver-azure' : 'bg-gray-300'
}`}
role="switch"
aria-checked={enabled}

View file

@ -195,11 +195,11 @@ export const UserManagement: React.FC = () => {
return (
<div className="p-8 flex items-center justify-center h-full">
<div className="flex flex-col items-center gap-3">
<svg className="animate-spin h-8 w-8 text-active-blue" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<svg className="animate-spin h-8 w-8 text-oliver-azure" 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" />
<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" />
</svg>
<p className="text-grey-700 text-sm">Loading user management...</p>
<p className="text-oliver-black/60 text-sm">Loading user management...</p>
</div>
</div>
);
@ -208,8 +208,8 @@ export const UserManagement: React.FC = () => {
return (
<div className="p-4 sm:p-6 lg:p-8 h-full bg-white overflow-y-auto">
<header className="mb-6">
<h1 className="text-3xl lg:text-4xl font-semibold text-primary-blue">User Management</h1>
<p className="text-base lg:text-lg text-primary-blue mt-1">
<h1 className="text-3xl lg:text-4xl font-semibold text-oliver-black">User Management</h1>
<p className="text-base lg:text-lg text-oliver-black mt-1">
{isSuperAdmin
? 'Manage user roles and agency assignments. Users are provisioned automatically via Azure AD.'
: 'View user roles and agency assignments.'}
@ -232,34 +232,34 @@ export const UserManagement: React.FC = () => {
{/* Users Table */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-primary-blue mb-4">Users ({users.length})</h2>
<h2 className="text-xl font-semibold text-oliver-black mb-4">Users ({users.length})</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">
<thead className="bg-lime">
<thead className="bg-oliver-sky">
<tr>
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Name</th>
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Email</th>
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Role</th>
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Agency</th>
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Created</th>
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider w-20"></th>
<th className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Name</th>
<th className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Email</th>
<th className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Role</th>
<th className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Agency</th>
<th className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Created</th>
<th className="px-6 py-3 text-left text-xs font-bold text-oliver-black uppercase tracking-wider w-20"></th>
</tr>
</thead>
<tbody className="divide-y divide-grey-300">
{users.map((user, index) => (
<tr key={user.id} className={index % 2 === 0 ? 'bg-white' : 'bg-grey-100'}>
<tr key={user.id} className={index % 2 === 0 ? 'bg-white' : 'bg-oliver-grey'}>
<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-info-light flex items-center justify-center text-active-blue">
<div className="flex-shrink-0 h-8 w-8 rounded-full bg-oliver-grey flex items-center justify-center text-oliver-azure">
<UserIcon className="h-4 w-4" />
</div>
<div className="ml-3">
<div className="text-sm font-medium text-black-title">{user.name}</div>
<div className="text-sm font-medium text-oliver-black">{user.name}</div>
</div>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-black-title">
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black">
{user.email}
</td>
<td className="px-6 py-4 whitespace-nowrap">
@ -268,16 +268,16 @@ export const UserManagement: React.FC = () => {
<select
value={user.role}
onChange={(e) => handleRoleChange(user.id, e.target.value)}
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"
className="w-full bg-white border-2 border-oliver-azure text-oliver-black py-1.5 pl-3 pr-8 rounded-[10px] text-sm focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none"
>
{ROLE_OPTIONS.map(r => (
<option key={r.value} value={r.value}>{r.label}</option>
))}
</select>
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-active-blue pointer-events-none" />
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-oliver-azure pointer-events-none" />
</div>
) : (
<span className="text-sm text-black-title">{formatRoleLabel(user.role)}</span>
<span className="text-sm text-oliver-black">{formatRoleLabel(user.role)}</span>
)}
</td>
<td className="px-6 py-4 whitespace-nowrap">
@ -286,22 +286,22 @@ export const UserManagement: React.FC = () => {
<select
value={user.agency_id || ''}
onChange={(e) => handleAgencyChange(user.id, e.target.value || null)}
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"
className="w-full bg-white border-2 border-oliver-azure text-oliver-black py-1.5 pl-3 pr-8 rounded-[10px] text-sm focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none"
>
<option value="">None (Unassigned)</option>
{agencies.map(a => (
<option key={a.id} value={a.id}>{a.name}</option>
))}
</select>
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-active-blue pointer-events-none" />
<ChevronDownIcon className="absolute right-2 top-1/2 -translate-y-1/2 h-3 w-3 text-oliver-azure pointer-events-none" />
</div>
) : (
<span className="text-sm text-black-title">
<span className="text-sm text-oliver-black">
{user.agency || 'Unassigned'}
</span>
)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-grey-700">
<td className="px-6 py-4 whitespace-nowrap text-sm text-oliver-black/60">
{formatDate(user.created_at)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm">
@ -309,7 +309,7 @@ export const UserManagement: React.FC = () => {
<button
onClick={() => handleOpenHistory(user)}
title="View change history"
className="p-1 text-grey-700 hover:text-active-blue transition-colors rounded-full hover:bg-info-light"
className="p-1 text-oliver-black/60 hover:text-oliver-azure transition-colors rounded-full hover:bg-oliver-grey"
>
<ClockIcon className="h-4 w-4" />
</button>
@ -327,7 +327,7 @@ export const UserManagement: React.FC = () => {
))}
{users.length === 0 && (
<tr>
<td colSpan={6} className="px-6 py-8 text-center text-grey-700">
<td colSpan={6} className="px-6 py-8 text-center text-oliver-black/60">
No users found.
</td>
</tr>
@ -354,13 +354,13 @@ export const UserManagement: React.FC = () => {
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<h3 className="text-lg font-semibold text-black-title">Confirm Super Admin Assignment</h3>
<h3 className="text-lg font-semibold text-oliver-black">Confirm Super Admin Assignment</h3>
</div>
<p className="text-sm text-grey-700 mb-4">
You are about to grant Super Admin privileges to <strong className="text-black-title">{pendingSuperAdminUser.userName}</strong>. This gives full system access including user management. This action should only be performed intentionally.
<p className="text-sm text-oliver-black/60 mb-4">
You are about to grant Super Admin privileges to <strong className="text-oliver-black">{pendingSuperAdminUser.userName}</strong>. This gives full system access including user management. This action should only be performed intentionally.
</p>
<p className="text-sm text-grey-700 mb-2">
To confirm, type <strong className="text-black-title">make this user super admin</strong> below:
<p className="text-sm text-oliver-black/60 mb-2">
To confirm, type <strong className="text-oliver-black">make this user super admin</strong> below:
</p>
<input
type="text"
@ -373,10 +373,10 @@ export const UserManagement: React.FC = () => {
onDrop={(e) => e.preventDefault()}
onDragOver={(e) => e.preventDefault()}
placeholder="Type the phrase above..."
className={`w-full p-2 border-2 rounded-[10px] text-sm text-black-title focus:outline-none focus:ring-2 transition ${
className={`w-full p-2 border-2 rounded-[10px] text-sm text-oliver-black focus:outline-none focus:ring-2 transition ${
confirmationError
? 'border-error focus:ring-error'
: 'border-grey-700 focus:ring-active-blue focus:border-active-blue'
: 'border-oliver-azure focus:ring-oliver-azure focus:border-oliver-azure'
}`}
autoFocus
/>
@ -386,14 +386,14 @@ export const UserManagement: React.FC = () => {
<div className="flex justify-end gap-3 mt-5">
<button
onClick={handleCancelSuperAdmin}
className="px-4 py-2 text-sm font-medium text-grey-700 hover:text-black-title border border-grey-300 rounded-full hover:bg-grey-100 transition-colors"
className="px-4 py-2 text-sm font-medium text-oliver-black/60 hover:text-oliver-black border border-grey-300 rounded-full hover:bg-oliver-grey transition-colors"
>
Cancel
</button>
<button
onClick={handleConfirmSuperAdmin}
disabled={confirmationText !== 'make this user super admin'}
className="px-4 py-2 text-sm font-medium text-white bg-active-blue rounded-full hover:bg-active-blue/90 transition-colors disabled:bg-grey-700 disabled:cursor-not-allowed"
className="px-4 py-2 text-sm font-medium text-white bg-oliver-azure rounded-full hover:bg-oliver-azure/90 transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed"
>
Confirm
</button>
@ -413,12 +413,12 @@ export const UserManagement: React.FC = () => {
onClick={(e) => e.stopPropagation()}
>
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-black-title">
<h3 className="text-lg font-semibold text-oliver-black">
Change History &mdash; {historyUser.name}
</h3>
<button
onClick={handleCloseHistory}
className="p-1 text-grey-700 hover:text-black-title transition-colors"
className="p-1 text-oliver-black/60 hover:text-oliver-black transition-colors"
>
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
@ -428,32 +428,32 @@ export const UserManagement: React.FC = () => {
<div className="overflow-y-auto flex-1">
{historyLoading ? (
<div className="flex items-center justify-center py-8">
<svg className="animate-spin h-6 w-6 text-active-blue" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<svg className="animate-spin h-6 w-6 text-oliver-azure" 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" />
<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" />
</svg>
</div>
) : historyEntries.length === 0 ? (
<p className="text-center py-8 text-grey-700">No change history recorded.</p>
<p className="text-center py-8 text-oliver-black/60">No change history recorded.</p>
) : (
<table className="min-w-full">
<thead className="bg-grey-100 sticky top-0">
<thead className="bg-oliver-grey sticky top-0">
<tr>
<th className="px-4 py-2 text-left text-xs font-bold text-black-title uppercase tracking-wider">Date</th>
<th className="px-4 py-2 text-left text-xs font-bold text-black-title uppercase tracking-wider">Change</th>
<th className="px-4 py-2 text-left text-xs font-bold text-black-title uppercase tracking-wider">Changed by</th>
<th className="px-4 py-2 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Date</th>
<th className="px-4 py-2 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Change</th>
<th className="px-4 py-2 text-left text-xs font-bold text-oliver-black uppercase tracking-wider">Changed by</th>
</tr>
</thead>
<tbody className="divide-y divide-grey-300">
{historyEntries.map((entry) => (
<tr key={entry.id}>
<td className="px-4 py-3 whitespace-nowrap text-sm text-grey-700">
<td className="px-4 py-3 whitespace-nowrap text-sm text-oliver-black/60">
{formatHistoryDate(entry.created_at)}
</td>
<td className="px-4 py-3 text-sm text-black-title">
<td className="px-4 py-3 text-sm text-oliver-black">
{formatChangeDescription(entry)}
</td>
<td className="px-4 py-3 whitespace-nowrap text-sm text-grey-700">
<td className="px-4 py-3 whitespace-nowrap text-sm text-oliver-black/60">
{entry.changed_by_name || 'System'}
</td>
</tr>
@ -468,7 +468,7 @@ export const UserManagement: React.FC = () => {
{/* Agency Management */}
<section>
<h2 className="text-xl font-semibold text-primary-blue mb-4">Agencies ({agencies.length})</h2>
<h2 className="text-xl font-semibold text-oliver-black mb-4">Agencies ({agencies.length})</h2>
<div className="max-w-xl">
{isSuperAdmin && (
<form onSubmit={handleCreateAgency} className="flex gap-2 mb-4">
@ -477,12 +477,12 @@ export const UserManagement: React.FC = () => {
value={newAgencyName}
onChange={(e) => setNewAgencyName(e.target.value)}
placeholder="New agency name..."
className="flex-grow p-2 border-2 border-grey-700 rounded-[10px] focus:ring-2 focus:ring-active-blue focus:border-active-blue transition text-black-title"
className="flex-grow p-2 border-2 border-oliver-azure rounded-[10px] focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure transition text-oliver-black"
/>
<button
type="submit"
disabled={!newAgencyName.trim() || isCreatingAgency}
className="bg-active-blue text-white font-semibold py-2 px-6 rounded-full hover:bg-active-blue/90 transition-colors disabled:bg-grey-700 disabled:cursor-not-allowed flex items-center gap-2"
className="bg-oliver-azure text-white font-semibold py-2 px-6 rounded-full hover:bg-oliver-azure/90 transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed flex items-center gap-2"
>
<PlusIcon className="h-4 w-4" />
Add
@ -494,16 +494,16 @@ export const UserManagement: React.FC = () => {
{agencies.map(agency => (
<div
key={agency.id}
className="flex items-center justify-between bg-grey-100 p-3 rounded-[10px] border border-grey-300"
className="flex items-center justify-between bg-oliver-grey p-3 rounded-[10px] border border-grey-300"
>
<span className="text-black-title font-medium">{agency.name}</span>
<span className="text-xs text-grey-700">
<span className="text-oliver-black font-medium">{agency.name}</span>
<span className="text-xs text-oliver-black/60">
{users.filter(u => u.agency_id === agency.id).length} user(s)
</span>
</div>
))}
{agencies.length === 0 && (
<div className="text-center py-6 text-grey-700 bg-grey-100 rounded-[10px]">
<div className="text-center py-6 text-oliver-black/60 bg-oliver-grey rounded-[10px]">
No agencies created yet.
</div>
)}

View file

@ -78,7 +78,7 @@ const ConfirmationComponent: React.FC<{
<select
value={channel}
onChange={e => setChannel(e.target.value)}
className="w-full bg-white border border-gray-300 rounded-md py-2 px-3 text-gray-900 focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none"
className="w-full bg-white border border-gray-300 rounded-md py-2 px-3 text-gray-900 focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none"
>
<option value="" disabled>Select Channel</option>
{availableChannels.map(opt => <option key={opt} value={opt}>{opt}</option>)}
@ -91,7 +91,7 @@ const ConfirmationComponent: React.FC<{
value={subChannel}
onChange={e => setSubChannel(e.target.value)}
disabled={!channel}
className="w-full bg-white border border-gray-300 rounded-md py-2 px-3 text-gray-900 focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none disabled:bg-gray-100"
className="w-full bg-white border border-gray-300 rounded-md py-2 px-3 text-gray-900 focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none disabled:bg-gray-100"
>
<option value="" disabled>Select Sub-Channel</option>
{availableSubChannels.map(opt => <option key={opt} value={opt}>{opt}</option>)}
@ -104,7 +104,7 @@ const ConfirmationComponent: React.FC<{
<select
value={proofType}
onChange={e => setProofType(e.target.value)}
className="w-full bg-white border border-gray-300 rounded-md py-2 px-3 text-gray-900 focus:outline-none focus:ring-2 focus:ring-active-blue appearance-none"
className="w-full bg-white border border-gray-300 rounded-md py-2 px-3 text-gray-900 focus:outline-none focus:ring-2 focus:ring-oliver-azure appearance-none"
>
<option value="" disabled>Select Proof Type</option>
{availableProofTypes.map(opt => <option key={opt} value={opt}>{opt}</option>)}
@ -115,7 +115,7 @@ const ConfirmationComponent: React.FC<{
<button
onClick={handleSubmit}
disabled={isSubmitDisabled}
className="w-full bg-active-blue text-white font-bold py-2 px-4 rounded-md hover:bg-primary-blue transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed"
className="w-full bg-oliver-azure text-white font-bold py-2 px-4 rounded-md hover:bg-oliver-azure transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed"
>
Confirm &amp; Analyse
</button>
@ -127,12 +127,12 @@ const ConfirmationComponent: React.FC<{
const MessageBubble: React.FC<{ sender: 'user' | 'agent'; children: React.ReactNode }> = ({ sender, children }) => {
const isUser = sender === 'user';
const bubbleClasses = isUser
? 'bg-active-blue text-white'
? 'bg-oliver-azure text-white'
: 'bg-white text-gray-800 border border-gray-200';
const alignmentClasses = isUser ? 'items-end' : 'items-start';
const avatar = isUser
? <div className="w-8 h-8 rounded-full bg-primary-blue flex items-center justify-center ring-2 ring-white"><UserIcon className="h-5 w-5 text-white"/></div>
: <div className="w-8 h-8 rounded-full bg-cyan-brand flex items-center justify-center ring-2 ring-white"><LeadAgentIcon className="h-5 w-5 text-primary-blue"/></div>;
? <div className="w-8 h-8 rounded-full bg-oliver-black flex items-center justify-center ring-2 ring-white"><UserIcon className="h-5 w-5 text-white"/></div>
: <div className="w-8 h-8 rounded-full bg-oliver-azure flex items-center justify-center ring-2 ring-white"><LeadAgentIcon className="h-5 w-5 text-oliver-black"/></div>;
const isConfirmation = React.isValidElement(children) && children.type === ConfirmationComponent;
@ -247,9 +247,9 @@ export const WIPReviewer: React.FC<WIPReviewerProps> = ({ dropdownOptions, msalI
};
return (
<div className="flex flex-col h-full bg-grey-100">
<div className="flex flex-col h-full bg-oliver-grey">
<header className="p-4 border-b border-gray-200 bg-white/80 backdrop-blur-sm flex-shrink-0">
<h1 className="text-xl font-bold text-primary-blue text-center">WIP Reviewer</h1>
<h1 className="text-xl font-bold text-oliver-black text-center">WIP Reviewer</h1>
</header>
{/* Message Display Area */}
@ -303,7 +303,7 @@ export const WIPReviewer: React.FC<WIPReviewerProps> = ({ dropdownOptions, msalI
type="button"
onClick={() => fileInputRef.current?.click()}
disabled={isLoading}
className="p-2 text-gray-500 hover:text-active-blue rounded-full transition-colors disabled:opacity-50"
className="p-2 text-gray-500 hover:text-oliver-azure rounded-full transition-colors disabled:opacity-50"
aria-label="Attach file"
>
<PaperClipIcon className="h-6 w-6"/>
@ -317,14 +317,14 @@ export const WIPReviewer: React.FC<WIPReviewerProps> = ({ dropdownOptions, msalI
handleSendMessage(e);
}
}}
className="w-full p-2.5 mx-2 border border-gray-300 rounded-lg resize-none focus:ring-2 focus:ring-active-blue focus:border-active-blue transition"
className="w-full p-2.5 mx-2 border border-gray-300 rounded-lg resize-none focus:ring-2 focus:ring-oliver-azure focus:border-oliver-azure transition"
placeholder="Type your message..."
rows={1}
disabled={isLoading}
/>
<button
type="submit"
className="p-2.5 rounded-full text-white bg-active-blue hover:bg-primary-blue disabled:bg-gray-400 transition-colors"
className="p-2.5 rounded-full text-white bg-oliver-azure hover:bg-oliver-azure disabled:bg-gray-400 transition-colors"
disabled={!userInput.trim() || isLoading}
aria-label="Send message"
>

View file

@ -4,44 +4,38 @@
<meta charset="UTF-8" />
<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 as fallback for Barclays Effra (proprietary font not available as web font) -->
<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">
<title>Mod Comms - Intelligent Review</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
// Barclays Effra is the brand font but is proprietary; Inter is the web fallback
'sans': ['Barclays Effra', 'Inter', 'Arial', 'sans-serif'],
'sans': ['Arial', 'sans-serif'],
},
borderRadius: {
DEFAULT: '10px',
},
colors: {
// Primary Brand Colors
'primary-blue': '#1A2142',
'active-blue': '#006DE3',
'electric-violet': '#7A0FF9',
'lime': '#C3FB5A',
'cyan-brand': '#00AEEF',
'teal-brand': '#01A1A2',
// Oliver Brand Colors
'oliver-black': '#1A1A1A',
'oliver-gold': '#FFCB05',
'oliver-orange': '#FF5C00',
'oliver-azure': '#0487B6',
'oliver-sky': '#5DF5EA',
'oliver-grey': '#EFEFEF',
'oliver-green': '#09821F',
// Functional Colors
'grey-100': '#F6F6F6',
'grey-300': '#E2E2E2',
'grey-700': '#8E8E8E',
'grey-900': '#515151',
'black-title': '#272727',
// Status Colors
'info-light': '#E7F0FB',
// Keep functional status colours for RAG system
'success': '#09821F',
'success-light': '#E9F4EA',
'warning': '#FFBA00',
'warning': '#FFCB05',
'warning-light': '#FFF8E7',
'error': '#E3000F',
'error-light': '#FDE7E9',
// Keep grey scale for borders
'grey-300': '#E2E2E2',
},
animation: {
'slow-ping': 'ping 2s cubic-bezier(0, 0, 0.2, 1) infinite',

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB