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 { ExtLink } from '@/components/ui/ext-link'
import { FeatureCard } from '@/components/ui/feature-card'
import { Code } from '@/components/ui/inline-code'
import { Cols, Eyebrow, PageHead, Prose, Section, SectionHead } from '@/components/ui/layout'
@@ -138,14 +139,7 @@ export const Community = () => {
<p>
Format and Clippy run clean on every push, and unit tests plus an end-to-end
suite against{' '}
<a
href={LINKS.soulfind}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
soulfind
</a>{' '}
<ExtLink href={LINKS.soulfind}>soulfind</ExtLink>{' '}
run in CI, so a green checkmark means it built and talked to a server.
</p>
<p>
+10 -50
View File
@@ -1,5 +1,6 @@
import { Button } from '@/components/ui/button'
import { FeatureCard } from '@/components/ui/feature-card'
import { ExtLink } from '@/components/ui/ext-link'
import { Code } from '@/components/ui/inline-code'
import { Cols, PageHead, Prose, Section, SectionHead } from '@/components/ui/layout'
import { OsIcon, type OsName } from '@/components/ui/os-icon'
@@ -28,17 +29,6 @@ const LIB_LINES: TermLine[] = LIB_SRC.split('\n').map((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 {
id: string
os: OsName
@@ -75,7 +65,7 @@ const INSTALLS: readonly InstallRoute[] = [
alt: (
<>
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.
</>
),
@@ -92,7 +82,7 @@ const INSTALLS: readonly InstallRoute[] = [
<>
Cargo needs the MSVC build tools. To skip both, take 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.
</>
),
@@ -257,15 +247,7 @@ const Steps = () => (
<Step n={1} title="Install the client">
<p className="text-secondary">
One command per platform. Cargo needs a Rust toolchain from{' '}
<a
href={LINKS.rustup}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
rustup.rs
</a>
; the other routes don&rsquo;t.
<ExtLink href={LINKS.rustup}>rustup.rs</ExtLink>; the other routes don&rsquo;t.
</p>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
{INSTALLS.map((route) => (
@@ -320,15 +302,7 @@ const Steps = () => (
<p className="text-[13px] text-muted">
You&rsquo;ll find the binary at <Code>target/release/soulseek-rs</Code>.
Prebuilt archives for tagged releases are on the{' '}
<a
href={LINKS.releases}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover"
>
releases page
</a>
.
<ExtLink href={LINKS.releases}>releases page</ExtLink>.
</p>
</Step>
@@ -347,25 +321,9 @@ const Steps = () => (
/>
<Terminal label="src/main.rs" lines={LIB_LINES} copy={LIB_SRC} />
<p className="text-[13px] text-muted">
Full API reference on{' '}
<a
href={LINKS.docsrs}
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.
Full API reference on <ExtLink href={LINKS.docsrs}>docs.rs</ExtLink>. The lib API
changes between majors, so check the{' '}
<ExtLink href={LINKS.changelog}>changelog</ExtLink> when you upgrade.
</p>
</Step>
</div>
@@ -534,6 +492,8 @@ const Uninstall = () => (
{ t: 'cm', text: '# while the binary is still there' },
{ t: 'cmd', text: 'soulseek-rs completions 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: 'cm', text: '# config and state: searches, downloads, rooms, messages' },
{