e1d1c392eb
Audit & Quality: - RTL: replaced 121 LTR-only utilities (text-left, pl-, left-) with logical properties - A11y: focus traps + ARIA on Modal/SlidePanel/TabbedModal, clickable divs→buttons - Theming: bg-white→bg-surface (170 instances), text-gray→semantic tokens - Performance: useMemo on filters, loading="lazy" on 24 images - CSS: prefers-reduced-motion, removed dead animations Component Splits: - PostDetailPanel: 1332→623 lines + 4 sub-components - ArtefactDetailPanel: 972→590 lines + 1 sub-component Brand Identity — Rawaj (رواج): - New name, DM Sans font, deep teal palette (#0d9488) - Custom SVG logo, forest-tinted dark mode - All emails branded with app name in subject line Design Refinement: - Dashboard: merged posts+deadlines into tabbed ActivityFeed, inline stats - Quieter: removed card lift, brand glow, gradient text, mesh backgrounds - CampaignDetail: prominent budget card, compact team avatars, Lucide icons - Consistent page titles via Header.jsx, standardized section headers - Finance page fully i18n'd (20+ hardcoded strings replaced) Budget Allocation Redesign: - Single source of truth: BudgetEntries (Campaign.budget deprecated) - Validation at all levels: main→campaign→track, expenses blocked if insufficient - Budget request workflow with CEO approval via public link - BudgetRequests table, CRUD routes, public approval page - Budget mutex for race condition prevention - Idempotent migration for existing campaign budgets Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
98 lines
3.5 KiB
React
98 lines
3.5 KiB
React
import { Check, Clock, User } from 'lucide-react'
|
|
|
|
export default function ArtefactVersionTimeline({ versions, activeVersionId, onSelectVersion, artefactType }) {
|
|
if (!versions || versions.length === 0) {
|
|
return (
|
|
<div className="text-center py-4 text-sm text-text-tertiary">
|
|
No versions found
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
{versions.map((version, idx) => {
|
|
const isActive = version.Id === activeVersionId
|
|
const isLatest = idx === versions.length - 1
|
|
|
|
return (
|
|
<button
|
|
key={version.Id}
|
|
onClick={() => onSelectVersion(version)}
|
|
className={`w-full text-start p-3 rounded-lg border transition-colors ${
|
|
isActive
|
|
? 'border-brand-primary bg-brand-primary/5'
|
|
: 'border-border hover:border-brand-primary/30 bg-surface hover:shadow-sm'
|
|
}`}
|
|
>
|
|
<div className="flex items-start gap-3">
|
|
{/* Version indicator */}
|
|
<div className={`flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold ${
|
|
isActive
|
|
? 'bg-brand-primary text-white'
|
|
: 'bg-surface-secondary text-text-secondary'
|
|
}`}>
|
|
v{version.version_number}
|
|
</div>
|
|
|
|
{/* Version details */}
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<span className={`text-sm font-medium ${isActive ? 'text-brand-primary' : 'text-text-primary'}`}>
|
|
Version {version.version_number}
|
|
</span>
|
|
{isLatest && (
|
|
<span className="text-xs px-2 py-0.5 bg-emerald-100 text-emerald-700 rounded-full font-medium">
|
|
Latest
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{version.notes && (
|
|
<p className="text-xs text-text-secondary line-clamp-2 mb-2">
|
|
{version.notes}
|
|
</p>
|
|
)}
|
|
|
|
<div className="flex items-center gap-3 text-xs text-text-tertiary">
|
|
{version.creator_name && (
|
|
<div className="flex items-center gap-1">
|
|
<User className="w-3 h-3" />
|
|
<span>{version.creator_name}</span>
|
|
</div>
|
|
)}
|
|
{version.created_at && (
|
|
<div className="flex items-center gap-1">
|
|
<Clock className="w-3 h-3" />
|
|
<span>{new Date(version.created_at).toLocaleDateString()}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Active indicator */}
|
|
{isActive && (
|
|
<div className="flex-shrink-0">
|
|
<Check className="w-5 h-5 text-brand-primary" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Thumbnail for image artefacts */}
|
|
{artefactType === 'design' && version.thumbnail && (
|
|
<div className="mt-2 ms-11">
|
|
<img
|
|
src={version.thumbnail}
|
|
alt={`Version ${version.version_number}`}
|
|
className="w-full h-20 object-cover rounded border border-border"
|
|
loading="lazy"
|
|
/>
|
|
</div>
|
|
)}
|
|
</button>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|