MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / ArtifactCard

Function ArtifactCard

packages/react/src/pages/artifacts.tsx:79–164  ·  view source on GitHub ↗

* One artifact, as a gallery card. * * The whole card is the link — the preview is the biggest, most obvious target, * and a title-only hit area would waste it. The row actions therefore cannot be * nested inside it (a button inside an anchor is invalid, and the click would * navigate through t

(props: {
  readonly artifact: ArtifactSummary;
  readonly onRename: (title: string) => void;
  readonly onRemove: () => void;
})

Source from the content-addressed store, hash-verified

77 * one focus stop, with the actions as their own stops after it.
78 */
79function ArtifactCard(props: {
80 readonly artifact: ArtifactSummary;
81 readonly onRename: (title: string) => void;
82 readonly onRemove: () => void;
83}) {
84 const { artifact } = props;
85 return (
86 <div
87 data-slot="artifact-card"
88 className="group/artifact-card relative isolate flex flex-col overflow-hidden rounded-lg border border-border bg-card transition-colors duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] focus-within:border-input hover:border-input"
89 >
90 {/* 16:10 preview, on its own plane, separated by the same hairline the
91 rest of the console uses. */}
92 <div className="relative aspect-[16/10] overflow-hidden border-b border-border bg-muted/40">
93 <ArtifactPreview artifactId={artifact.id} preview={artifact.preview} />
94 </div>
95
96 <div className="flex min-w-0 flex-col gap-1 px-4 py-3">
97 <h3 className="truncate text-sm font-medium text-foreground">
98 <Link
99 to="/{-$orgSlug}/artifacts/$artifactId"
100 params={{ artifactId: artifact.id }}
101 aria-label={`Open artifact ${artifact.title}`}
102 className="outline-none after:absolute after:inset-0 after:content-[''] focus-visible:underline"
103 onClick={() => trackEvent("artifact_opened", { surface: "list" })}
104 >
105 {artifact.title}
106 </Link>
107 </h3>
108 {artifact.description ? (
109 <p className="line-clamp-2 text-xs leading-relaxed text-muted-foreground">
110 {artifact.description}
111 </p>
112 ) : null}
113 <span className="mt-1 font-mono text-[11px] text-muted-foreground">
114 {formatRelativeTime(artifact.updatedAt)}
115 </span>
116 </div>
117
118 {/* Above the link overlay, so these stay clickable. Revealed on hover or
119 focus, and pinned open while their own dialog is. */}
120 <div className="absolute right-2 top-2 z-10 flex items-center gap-1 opacity-0 transition-opacity duration-150 focus-within:opacity-100 group-hover/artifact-card:opacity-100 has-[[data-state=open]]:opacity-100">
121 <RenameArtifactDialog
122 currentTitle={artifact.title}
123 onRename={props.onRename}
124 trigger={
125 <Button
126 type="button"
127 variant="secondary"
128 size="xs"
129 className="bg-card text-muted-foreground hover:text-foreground"
130 >
131 Rename
132 </Button>
133 }
134 />
135 <AlertDialog>
136 <AlertDialogTrigger asChild>

Callers

nothing calls this directly

Calls 2

trackEventFunction · 0.90
formatRelativeTimeFunction · 0.90

Tested by

no test coverage detected