feat(install): add Windows PowerShell installer and copy buttons on site

Add install.ps1 mirroring install.sh for Windows: arch detection,
release zip download, binary extraction, user PATH update.

- copy install.ps1 to site public/ at build time (copy-install.mjs)
- serve /install.ps1 with text/plain Content-Type (vercel.json)
- add PowerShell one-liner to install page and README
- bump install.ps1 default version in bump_version.sh
- add CopyButton component next to every install command line
This commit is contained in:
Christian Visintin
2026-06-07 23:04:39 +02:00
parent d070825dd7
commit f92cb93755
9 changed files with 292 additions and 18 deletions

View File

@@ -0,0 +1,54 @@
---
interface Props {
text: string;
class?: string;
}
const { text, class: className } = Astro.props;
---
<button
type="button"
class:list={[
"copy-btn rounded p-1.5 text-overlay transition-colors hover:bg-mantle hover:text-text",
className,
]}
data-copy={text}
aria-label="Copy command to clipboard"
title="Copy"
>
<svg class="copy-icon h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
<svg class="check-icon hidden h-4 w-4 text-green" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M20 6 9 17l-5-5"></path>
</svg>
</button>
<script>
const RESET_DELAY_MS = 1500;
const handleCopy = async (button: HTMLElement) => {
const text = button.getAttribute("data-copy") ?? "";
try {
await navigator.clipboard.writeText(text);
} catch {
return;
}
const copyIcon = button.querySelector(".copy-icon");
const checkIcon = button.querySelector(".check-icon");
copyIcon?.classList.add("hidden");
checkIcon?.classList.remove("hidden");
window.setTimeout(() => {
copyIcon?.classList.remove("hidden");
checkIcon?.classList.add("hidden");
}, RESET_DELAY_MS);
};
document.addEventListener("click", (event) => {
const button = (event.target as HTMLElement)?.closest<HTMLElement>(".copy-btn");
if (button) {
handleCopy(button);
}
});
</script>

View File

@@ -1,4 +1,6 @@
---
import CopyButton from "./CopyButton.astro";
interface Method { id: string; label: string; cmd: string; }
interface Props { methods: Method[]; }
const { methods } = Astro.props;
@@ -14,11 +16,10 @@ const { methods } = Astro.props;
))}
</div>
{methods.map((m, i) => (
<pre
class="install-panel m-0 overflow-auto bg-base px-4 py-4 text-sm text-text"
data-id={m.id}
hidden={i !== 0}
><code>{m.cmd}</code></pre>
<div class="install-panel relative" data-id={m.id} hidden={i !== 0}>
<pre class="m-0 overflow-auto bg-base px-4 py-4 pr-12 text-sm text-text"><code>{m.cmd}</code></pre>
<CopyButton text={m.cmd} class="absolute right-2 top-2" />
</div>
))}
</div>
<script is:inline>

View File

@@ -3,9 +3,11 @@ import Base from "../layouts/Base.astro";
import Nav from "../components/Nav.astro";
import Footer from "../components/Footer.astro";
import InstallTabs from "../components/InstallTabs.astro";
import CopyButton from "../components/CopyButton.astro";
import { DOCS_URL } from "../consts";
const script = "curl --proto '=https' --tlsv1.2 -sSLf https://termscp.rs/install.sh | sh";
const psScript = "irm https://termscp.rs/install.ps1 | iex";
const methods = [
{ id: "cargo", label: "Cargo", cmd: "cargo install termscp --locked" },
@@ -28,10 +30,24 @@ const methods = [
<div class="flex items-center gap-2 border-b border-line px-3 py-2 text-xs text-overlay">
<span class="text-green">$</span> Linux · macOS · BSD
</div>
<pre class="m-0 overflow-auto bg-base px-4 py-4 text-sm text-text"><code>{script}</code></pre>
<div class="relative">
<pre class="m-0 overflow-auto bg-base px-4 py-4 pr-12 text-sm text-text"><code>{script}</code></pre>
<CopyButton text={script} class="absolute right-2 top-2" />
</div>
</div>
<p class="mt-2 text-xs text-overlay">Requires <span class="text-text">curl</span>. macOS uses Homebrew if available, otherwise builds from source.</p>
<div class="mt-6 rounded-lg border border-line bg-mantle p-1">
<div class="flex items-center gap-2 border-b border-line px-3 py-2 text-xs text-overlay">
<span class="text-green">&gt;</span> Windows (PowerShell)
</div>
<div class="relative">
<pre class="m-0 overflow-auto bg-base px-4 py-4 pr-12 text-sm text-text"><code>{psScript}</code></pre>
<CopyButton text={psScript} class="absolute right-2 top-2" />
</div>
</div>
<p class="mt-2 text-xs text-overlay">Downloads the latest release and adds <span class="text-text">termscp</span> to your user PATH.</p>
<h2 class="mt-10 mb-3 text-lg text-text">Package managers</h2>
<InstallTabs methods={methods} />