(props: { latestVersion: string; channel: UpdateChannel })
| 142 | // ── NpmUpdateCard (npm-installed CLI: copyable command) ─────────────────── |
| 143 | |
| 144 | function NpmUpdateCard(props: { latestVersion: string; channel: UpdateChannel }) { |
| 145 | const command = `npm i -g executor@${props.channel}`; |
| 146 | const [copied, setCopied] = useState(false); |
| 147 | |
| 148 | const handleCopy = useCallback(() => { |
| 149 | void copyToClipboard(command).then((ok) => { |
| 150 | if (!ok) { |
| 151 | toast.error("Failed to copy to clipboard"); |
| 152 | return; |
| 153 | } |
| 154 | setCopied(true); |
| 155 | setTimeout(() => setCopied(false), 1500); |
| 156 | }); |
| 157 | }, [command]); |
| 158 | |
| 159 | return ( |
| 160 | <UpdateCardShell version={props.latestVersion}> |
| 161 | <Button |
| 162 | type="button" |
| 163 | variant="outline" |
| 164 | onClick={handleCopy} |
| 165 | className="mt-2.5 flex w-full items-center justify-between gap-2 rounded-lg border-border/60 bg-background/50 px-2.5 py-1.5 text-left hover:bg-background/80" |
| 166 | > |
| 167 | <code className="truncate font-mono text-xs text-sidebar-foreground">{command}</code> |
| 168 | <span className="shrink-0 text-muted-foreground transition-colors group-hover:text-foreground"> |
| 169 | {copied ? ( |
| 170 | <svg viewBox="0 0 16 16" fill="none" className="size-3 text-primary"> |
| 171 | <path |
| 172 | d="M3 8.5l3.5 3.5L13 4" |
| 173 | stroke="currentColor" |
| 174 | strokeWidth="1.4" |
| 175 | strokeLinecap="round" |
| 176 | strokeLinejoin="round" |
| 177 | /> |
| 178 | </svg> |
| 179 | ) : ( |
| 180 | <svg viewBox="0 0 16 16" fill="none" className="size-3"> |
| 181 | <rect |
| 182 | x="5" |
| 183 | y="5" |
| 184 | width="8" |
| 185 | height="8" |
| 186 | rx="1.5" |
| 187 | stroke="currentColor" |
| 188 | strokeWidth="1.2" |
| 189 | /> |
| 190 | <path |
| 191 | d="M3 11V3.5A.5.5 0 013.5 3H11" |
| 192 | stroke="currentColor" |
| 193 | strokeWidth="1.2" |
| 194 | strokeLinecap="round" |
| 195 | /> |
| 196 | </svg> |
| 197 | )} |
| 198 | </span> |
| 199 | </Button> |
| 200 | </UpdateCardShell> |
| 201 | ); |
nothing calls this directly
no test coverage detected