({
p,
isBm,
toggleBm,
onOpen,
}: {
p: Project;
isBm: boolean;
toggleBm: (id: string) => void;
onOpen: (p: Project) => void;
})
| 4 | import RunnableBadge from "./RunnableBadge"; |
| 5 | |
| 6 | export default function ProjectCard({ |
| 7 | p, |
| 8 | isBm, |
| 9 | toggleBm, |
| 10 | onOpen, |
| 11 | }: { |
| 12 | p: Project; |
| 13 | isBm: boolean; |
| 14 | toggleBm: (id: string) => void; |
| 15 | onOpen: (p: Project) => void; |
| 16 | }) { |
| 17 | return ( |
| 18 | <div className="s-card" onClick={() => onOpen(p)}> |
| 19 | <div className="s-card-emoji">{p.emoji}</div> |
| 20 | <div className="s-card-h"> |
| 21 | <h3 className="s-card-name">{p.name}</h3> |
| 22 | <button |
| 23 | className={`s-card-bm ${isBm ? "on" : ""}`} |
| 24 | onClick={(e) => { |
| 25 | e.stopPropagation(); |
| 26 | toggleBm(p.id); |
| 27 | }} |
| 28 | aria-label={isBm ? "Remove bookmark" : "Add bookmark"} |
| 29 | > |
| 30 | {isBm ? "★" : "☆"} |
| 31 | </button> |
| 32 | </div> |
| 33 | <p className="s-card-blurb">{p.blurb}</p> |
| 34 | <div className="s-card-meta"> |
| 35 | <span className="s-meta-pill">{p.lines} lines</span> |
| 36 | <span className="s-meta-pill dep">{p.deps}</span> |
| 37 | {p.playground && <RunnableBadge size="sm" />} |
| 38 | </div> |
| 39 | </div> |
| 40 | ); |
| 41 | } |
nothing calls this directly
no test coverage detected