fix(website): give Homebrew users an uninstall command, share the link markup

The macOS install route recommends Homebrew, but the uninstall section only
ever offered `cargo uninstall`, so anyone who followed the recommended route
had no documented way to remove the binary. Adds `brew uninstall`.

install.tsx also had ReleasesLink defined to wrap an external anchor, then
inlined that same anchor four more times anyway - including one that rebuilt
the releases link by hand, byte for byte, 290 lines below the component that
already rendered it. ExtLink takes the href and covers all six sites here and
in community.tsx. Rendered markup is unchanged.
This commit is contained in:
Michel de Graaf
2026-07-26 16:17:22 +02:00
parent 2a051c7064
commit 8482c47149
3 changed files with 27 additions and 58 deletions
+15
View File
@@ -0,0 +1,15 @@
interface ExtLinkProps {
href: string
children: React.ReactNode
}
export const ExtLink = ({ href, children }: ExtLinkProps) => (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
{children}
</a>
)
+2 -8
View File
@@ -1,4 +1,5 @@
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { ExtLink } from '@/components/ui/ext-link'
import { FeatureCard } from '@/components/ui/feature-card' import { FeatureCard } from '@/components/ui/feature-card'
import { Code } from '@/components/ui/inline-code' import { Code } from '@/components/ui/inline-code'
import { Cols, Eyebrow, PageHead, Prose, Section, SectionHead } from '@/components/ui/layout' import { Cols, Eyebrow, PageHead, Prose, Section, SectionHead } from '@/components/ui/layout'
@@ -138,14 +139,7 @@ export const Community = () => {
<p> <p>
Format and Clippy run clean on every push, and unit tests plus an end-to-end Format and Clippy run clean on every push, and unit tests plus an end-to-end
suite against{' '} suite against{' '}
<a <ExtLink href={LINKS.soulfind}>soulfind</ExtLink>{' '}
href={LINKS.soulfind}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
soulfind
</a>{' '}
run in CI, so a green checkmark means it built and talked to a server. run in CI, so a green checkmark means it built and talked to a server.
</p> </p>
<p> <p>
+10 -50
View File
@@ -1,5 +1,6 @@
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { FeatureCard } from '@/components/ui/feature-card' import { FeatureCard } from '@/components/ui/feature-card'
import { ExtLink } from '@/components/ui/ext-link'
import { Code } from '@/components/ui/inline-code' import { Code } from '@/components/ui/inline-code'
import { Cols, PageHead, Prose, Section, SectionHead } from '@/components/ui/layout' import { Cols, PageHead, Prose, Section, SectionHead } from '@/components/ui/layout'
import { OsIcon, type OsName } from '@/components/ui/os-icon' import { OsIcon, type OsName } from '@/components/ui/os-icon'
@@ -28,17 +29,6 @@ const LIB_LINES: TermLine[] = LIB_SRC.split('\n').map((text) => ({
text, text,
})) }))
const ReleasesLink = ({ children }: { children: React.ReactNode }) => (
<a
href={LINKS.releases}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
{children}
</a>
)
interface InstallRoute { interface InstallRoute {
id: string id: string
os: OsName os: OsName
@@ -75,7 +65,7 @@ const INSTALLS: readonly InstallRoute[] = [
alt: ( alt: (
<> <>
Homebrew on Linux works the same as on macOS. Without either, the{' '} Homebrew on Linux works the same as on macOS. Without either, the{' '}
<ReleasesLink>releases page</ReleasesLink> has static musl archives for x86-64 and <ExtLink href={LINKS.releases}>releases page</ExtLink> has static musl archives for x86-64 and
arm64 that run on any distribution. arm64 that run on any distribution.
</> </>
), ),
@@ -92,7 +82,7 @@ const INSTALLS: readonly InstallRoute[] = [
<> <>
Cargo needs the MSVC build tools. To skip both, take the{' '} Cargo needs the MSVC build tools. To skip both, take the{' '}
<code>pc-windows-msvc</code> zip from the{' '} <code>pc-windows-msvc</code> zip from the{' '}
<ReleasesLink>releases page</ReleasesLink>, unpack it, and put{' '} <ExtLink href={LINKS.releases}>releases page</ExtLink>, unpack it, and put{' '}
<code>soulseek-rs.exe</code> on your PATH. <code>soulseek-rs.exe</code> on your PATH.
</> </>
), ),
@@ -257,15 +247,7 @@ const Steps = () => (
<Step n={1} title="Install the client"> <Step n={1} title="Install the client">
<p className="text-secondary"> <p className="text-secondary">
One command per platform. Cargo needs a Rust toolchain from{' '} One command per platform. Cargo needs a Rust toolchain from{' '}
<a <ExtLink href={LINKS.rustup}>rustup.rs</ExtLink>; the other routes don&rsquo;t.
href={LINKS.rustup}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
rustup.rs
</a>
; the other routes don&rsquo;t.
</p> </p>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3"> <div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
{INSTALLS.map((route) => ( {INSTALLS.map((route) => (
@@ -320,15 +302,7 @@ const Steps = () => (
<p className="text-[13px] text-muted"> <p className="text-[13px] text-muted">
You&rsquo;ll find the binary at <Code>target/release/soulseek-rs</Code>. You&rsquo;ll find the binary at <Code>target/release/soulseek-rs</Code>.
Prebuilt archives for tagged releases are on the{' '} Prebuilt archives for tagged releases are on the{' '}
<a <ExtLink href={LINKS.releases}>releases page</ExtLink>.
href={LINKS.releases}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
releases page
</a>
.
</p> </p>
</Step> </Step>
@@ -347,25 +321,9 @@ const Steps = () => (
/> />
<Terminal label="src/main.rs" lines={LIB_LINES} copy={LIB_SRC} /> <Terminal label="src/main.rs" lines={LIB_LINES} copy={LIB_SRC} />
<p className="text-[13px] text-muted"> <p className="text-[13px] text-muted">
Full API reference on{' '} Full API reference on <ExtLink href={LINKS.docsrs}>docs.rs</ExtLink>. The lib API
<a changes between majors, so check the{' '}
href={LINKS.docsrs} <ExtLink href={LINKS.changelog}>changelog</ExtLink> when you upgrade.
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
docs.rs
</a>
. The lib API changes between majors, so check the{' '}
<a
href={LINKS.changelog}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
changelog
</a>{' '}
when you upgrade.
</p> </p>
</Step> </Step>
</div> </div>
@@ -534,6 +492,8 @@ const Uninstall = () => (
{ t: 'cm', text: '# while the binary is still there' }, { t: 'cm', text: '# while the binary is still there' },
{ t: 'cmd', text: 'soulseek-rs completions uninstall' }, { t: 'cmd', text: 'soulseek-rs completions uninstall' },
{ t: 'cmd', text: 'soulseek-rs skills uninstall' }, { t: 'cmd', text: 'soulseek-rs skills uninstall' },
{ t: 'cm', text: '# whichever way you installed it' },
{ t: 'cmd', text: 'brew uninstall soulseek-rs' },
{ t: 'cmd', text: 'cargo uninstall soulseek-rs' }, { t: 'cmd', text: 'cargo uninstall soulseek-rs' },
{ t: 'cm', text: '# config and state: searches, downloads, rooms, messages' }, { t: 'cm', text: '# config and state: searches, downloads, rooms, messages' },
{ {