veza/apps/web/src/components/studio/projects-manager/ProjectsManagerCard.tsx
senke 4318d1f49c fix(a11y): Sprint 7 — semantic HTML and accessibility deep-dive
S7.1: Replace div onClick with semantic button in DialogTrigger.tsx
S7.2: Replace role="button" divs with native <button> elements in 12 files
      (PlaylistCard, TrackCard, ConversationItem, NotificationMenuItem,
       AudioPlayerTrackInfo, SearchPageResults, ProjectsManagerAddCard,
       ProjectsManagerCard, GearInventoryGrid, UploadModal, dropdown.tsx,
       LibraryPageGrid)
S7.3: Add focus-visible:ring-2 to 14 form inputs with outline-none across
      9 modal files (CreateGroupModal, DataExportModal, EditPlaylistModal,
      AddToPlaylistModal, BanUserModal, RefundRequestModal, FlashSaleModal,
      TipStreamerModal, CreatePostModal)
S7.4: Add semantic landmarks — <section> in DashboardPage, <article> in
      PostCard and CourseCard

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 10:34:39 +01:00

98 lines
3.4 KiB
TypeScript

import { Card } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { MoreVertical } from 'lucide-react';
import type { Project } from '@/services/projectService';
interface ProjectsManagerCardProps {
project: Project;
onOpen: () => void;
onOptionsClick: () => void;
}
export function ProjectsManagerCard({
project,
onOpen,
onOptionsClick,
}: ProjectsManagerCardProps) {
const badgeVariant =
project.daw === 'Ableton'
? 'cyan'
: project.daw === 'FL Studio'
? 'gold'
: 'magenta';
return (
<Card
variant="glass"
className="group cursor-pointer hover:border-primary/50 transition-colors duration-[var(--sumi-duration-normal)]"
onClick={onOpen}
>
<div className="flex justify-between items-start mb-4">
<Badge label={project.daw} variant={badgeVariant} />
<button
type="button"
onClick={(e) => {
e.stopPropagation();
onOptionsClick();
}}
className="appearance-none bg-transparent border-0 p-0 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded"
aria-label="Project options"
>
<MoreVertical className="w-4 h-4 text-muted-foreground hover:text-foreground transition-colors" />
</button>
</div>
<h3 className="text-xl font-bold text-foreground mb-1 group-hover:text-foreground transition-colors truncate tracking-tight">
{project.name}
</h3>
<p className="text-xs text-muted-foreground mb-4 font-mono">
Last edited {project.modified}
</p>
<div className="grid grid-cols-2 gap-2 mb-4">
<div className="bg-muted/50 p-2 rounded-lg text-center border border-border">
<div className="text-xs text-muted-foreground uppercase font-bold">
BPM
</div>
<div className="font-bold text-foreground">{project.bpm}</div>
</div>
<div className="bg-muted/50 p-2 rounded-lg text-center border border-border">
<div className="text-xs text-muted-foreground uppercase font-bold">
Key
</div>
<div className="font-bold text-foreground">{project.key}</div>
</div>
</div>
<div className="mb-4">
<div className="flex justify-between text-xs mb-1">
<span className="text-muted-foreground font-bold">
{project.status}
</span>
<span className="text-muted-foreground">{project.progress}%</span>
</div>
<div className="h-1.5 bg-muted rounded-full overflow-hidden">
<div
className="h-full bg-primary"
style={{ width: `${project.progress}%` }}
/>
</div>
</div>
<div className="flex justify-between items-center pt-4 border-t border-border">
<div className="flex -space-x-2">
<div className="w-6 h-6 rounded-full bg-muted border border-border" />
{project.collaborators > 0 && (
<div className="w-6 h-6 rounded-full bg-card border border-border flex items-center justify-center text-xs text-foreground">
+{project.collaborators}
</div>
)}
</div>
<Button variant="ghost" size="sm" className="text-xs h-8">
OPEN
</Button>
</div>
</Card>
);
}