1import type { ProjectScript, ResolvedKeybindingsConfig } from "@t3tools/contracts";
2import { SettingsIcon } from "lucide-react";
3import { shortcutLabelForCommand } from "../../keybindings";
4import { commandForProjectScript } from "../../projectScripts";
5import { ScriptIcon } from "../projectScriptEditor";
6import { Button } from "../ui/button";
7import { SettingsRow } from "./settingsLayout";
8
9export function ProjectActionsList({
10 scripts,
11 keybindings,
12 disabled,
13 onEdit,
14}: {
15 scripts: readonly ProjectScript[];
16 keybindings: ResolvedKeybindingsConfig;
17 disabled: boolean;
18 onEdit: (script: ProjectScript) => void;
19}) {
20 if (scripts.length === 0)
21 return (
22 <p className="px-3 py-2 text-base text-muted-foreground sm:px-4 sm:text-sm">
23 No actions configured.
24 </p>
25 );
26 return scripts.map((script) => {
27 const shortcutLabel = shortcutLabelForCommand(keybindings, commandForProjectScript(script.id));
28 return (
29 <SettingsRow
30 key={script.id}
31 className="group py-2"
32 title={
33 <span className="flex min-w-0 items-center gap-2">
34 <ScriptIcon icon={script.icon} className="size-4 shrink-0 text-muted-foreground" />
35 <span className="min-w-0 truncate">{script.name}</span>
36 {script.runOnWorktreeCreate ? (
37 <span className="shrink-0 rounded-sm border border-border/60 px-1.5 py-px text-2xs font-normal text-muted-foreground">
38 setup
39 </span>
40 ) : null}
41 {script.runOnSettle ? (
42 <span className="shrink-0 rounded-sm border border-border/60 px-1.5 py-px text-2xs font-normal text-muted-foreground">
43 on settle
44 </span>
45 ) : null}
46 {script.previewUrl ? (
47 <span className="shrink-0 rounded-sm border border-border/60 px-1.5 py-px text-2xs font-normal text-muted-foreground max-sm:hidden">
48 preview · desktop only
49 </span>
50 ) : null}
51 </span>
52 }
53 description={<code className="block max-w-full truncate font-mono">{script.command}</code>}
54 control={
55 <>
56 {shortcutLabel ? (
57 <span className="text-xs text-muted-foreground">{shortcutLabel}</span>
58 ) : null}
59 <span className="flex shrink-0 opacity-0 group-focus-within:opacity-100 group-hover:opacity-100">
60 <Button
61 size="icon-xs"
62 variant="ghost-muted"
63 aria-label={`Edit ${script.name}`}
64 disabled={disabled}
65 onClick={() => onEdit(script)}
66 >
67 <SettingsIcon className="size-3.5" />
68 </Button>
69 </span>
70 </>
71 }
72 />
73 );
74 });
75}