feat(website): route the OS links to per-platform install steps
Clicking macOS, Linux or Windows on the home page landed on the file-path cards, which say where config lives, not how to install. Step 1 now carries one card per OS at those anchors: brew on macOS, cargo on Linux, cargo or the prebuilt .exe on Windows. The path cards keep their own -paths anchors. The hero logo drew into a fixed inline width, so the mobile height overrides shrank the mark inside a box sized for the desktop one. An aspect-ratio lets the width follow, and the mark is now larger and centred against the title.
This commit is contained in:
@@ -12,6 +12,6 @@ export const Logo = ({ size = 180, className }: LogoProps) => (
|
||||
role="img"
|
||||
aria-label="soulseek-rs"
|
||||
className={cn('logo-mark shrink-0 bg-contain bg-no-repeat', className)}
|
||||
style={{ height: size, width: size * ASPECT }}
|
||||
style={{ height: size, aspectRatio: ASPECT }}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -20,9 +20,10 @@ interface TerminalProps {
|
||||
lines: readonly TermLine[]
|
||||
copy?: string
|
||||
className?: string
|
||||
wrap?: boolean
|
||||
}
|
||||
|
||||
export const Terminal = ({ label, lines, copy, className }: TerminalProps) => {
|
||||
export const Terminal = ({ label, lines, copy, className, wrap }: TerminalProps) => {
|
||||
const copyText =
|
||||
copy ??
|
||||
lines
|
||||
@@ -47,7 +48,11 @@ export const Terminal = ({ label, lines, copy, className }: TerminalProps) => {
|
||||
{lines.map((line, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className={cn('block whitespace-pre', LINE_TONE[line.t])}
|
||||
className={cn(
|
||||
'block',
|
||||
wrap ? 'break-all whitespace-pre-wrap' : 'whitespace-pre',
|
||||
LINE_TONE[line.t],
|
||||
)}
|
||||
>
|
||||
{line.t === 'cmd' && (
|
||||
<>
|
||||
|
||||
@@ -14,9 +14,9 @@ import { LINKS } from '@/lib/links'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const PLATFORMS: readonly { name: OsName; note: string; anchor: string }[] = [
|
||||
{ name: 'macOS', note: 'Apple Keychain', anchor: 'macos' },
|
||||
{ name: 'Linux', note: 'Secret Service', anchor: 'linux' },
|
||||
{ name: 'Windows', note: 'Credential Manager', anchor: 'windows' },
|
||||
{ name: 'macOS', note: 'brew or cargo', anchor: 'macos' },
|
||||
{ name: 'Linux', note: 'cargo install', anchor: 'linux' },
|
||||
{ name: 'Windows', note: 'cargo or .exe', anchor: 'windows' },
|
||||
]
|
||||
|
||||
const FEATURES = [
|
||||
@@ -124,8 +124,8 @@ export const Home = () => {
|
||||
<Wrap>
|
||||
<div className="flex flex-col gap-[22px]">
|
||||
<Eyebrow className="max-md:hidden">Soulseek client · terminal · Rust</Eyebrow>
|
||||
<div className="flex items-start gap-3.5 sm:gap-6 md:gap-11">
|
||||
<Logo size={172} className="mt-2 max-md:!h-28 max-sm:!h-16" />
|
||||
<div className="flex items-center gap-3.5 sm:gap-6 md:items-start md:gap-11">
|
||||
<Logo size={172} className="max-md:!h-32 md:mt-2" />
|
||||
<h1 className="text-[29px] leading-[37px] font-bold tracking-[-0.01em] text-balance sm:text-[34px] sm:leading-[42px] md:text-display md:leading-[var(--text-display--line-height)]">
|
||||
A soulseek client for the terminal. Built for agents and people who live
|
||||
there.
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Button } from '@/components/ui/button'
|
||||
import { FeatureCard } from '@/components/ui/feature-card'
|
||||
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'
|
||||
import { Callout } from '@/components/ui/panel'
|
||||
import { Terminal, type TermLine } from '@/components/ui/terminal'
|
||||
import { LINKS } from '@/lib/links'
|
||||
@@ -27,6 +28,76 @@ 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
|
||||
best: string
|
||||
lines: readonly TermLine[]
|
||||
alt: React.ReactNode
|
||||
}
|
||||
|
||||
const INSTALLS: readonly InstallRoute[] = [
|
||||
{
|
||||
id: 'macos',
|
||||
os: 'macOS',
|
||||
best: 'Homebrew',
|
||||
lines: [
|
||||
{ t: 'cmd', text: 'brew install michel/tap/soulseek-rs' },
|
||||
{ t: 'cmd', text: 'soulseek-rs' },
|
||||
],
|
||||
alt: (
|
||||
<>
|
||||
A prebuilt binary for both Apple silicon and Intel, so no Rust toolchain. With one
|
||||
installed, <Code>cargo install soulseek-rs</Code> builds it from crates.io instead.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'linux',
|
||||
os: 'Linux',
|
||||
best: 'cargo',
|
||||
lines: [
|
||||
{ t: 'cmd', text: 'cargo install soulseek-rs' },
|
||||
{ t: 'cmd', text: 'soulseek-rs' },
|
||||
],
|
||||
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
|
||||
arm64 that run on any distribution.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'windows',
|
||||
os: 'Windows',
|
||||
best: 'cargo or a prebuilt .exe',
|
||||
lines: [
|
||||
{ t: 'cmd', text: 'cargo install soulseek-rs' },
|
||||
{ t: 'cmd', text: 'soulseek-rs.exe' },
|
||||
],
|
||||
alt: (
|
||||
<>
|
||||
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{' '}
|
||||
<code>soulseek-rs.exe</code> on your PATH.
|
||||
</>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
interface PlatformNote {
|
||||
id: string
|
||||
name: string
|
||||
@@ -191,16 +262,7 @@ export const Install = () => {
|
||||
<div className="flex flex-col gap-9">
|
||||
<Step n={1} title="Install the client">
|
||||
<p className="text-secondary">
|
||||
Homebrew, on macOS or Linux. A prebuilt binary, so no Rust toolchain:
|
||||
</p>
|
||||
<Terminal
|
||||
lines={[
|
||||
{ t: 'cmd', text: 'brew install michel/tap/soulseek-rs' },
|
||||
{ t: 'cmd', text: 'soulseek-rs' },
|
||||
]}
|
||||
/>
|
||||
<p className="text-secondary">
|
||||
With a Rust toolchain from{' '}
|
||||
One command per platform. Cargo needs a Rust toolchain from{' '}
|
||||
<a
|
||||
href={LINKS.rustup}
|
||||
target="_blank"
|
||||
@@ -209,29 +271,39 @@ export const Install = () => {
|
||||
>
|
||||
rustup.rs
|
||||
</a>
|
||||
, cargo works everywhere else:
|
||||
; the other routes don’t.
|
||||
</p>
|
||||
<Terminal lines={[{ t: 'cmd', text: 'cargo install soulseek-rs' }]} />
|
||||
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
|
||||
{INSTALLS.map((route) => (
|
||||
<div
|
||||
key={route.id}
|
||||
id={route.id}
|
||||
className="flex scroll-mt-20 flex-col gap-3.5 rounded-md border border-hairline bg-panel p-[18px] sm:p-[22px]"
|
||||
>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<OsIcon name={route.os} />
|
||||
<h3 className="text-heading leading-[var(--text-heading--line-height)] font-medium">
|
||||
{route.os}
|
||||
</h3>
|
||||
</div>
|
||||
<span className="text-[11px] uppercase tracking-[var(--tracking-label)] text-secondary">
|
||||
{route.best}
|
||||
</span>
|
||||
<Terminal lines={route.lines} wrap />
|
||||
<p className="text-[12.5px] leading-5 text-secondary [&_code]:font-mono [&_code]:text-primary">
|
||||
{route.alt}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-[13px] text-muted">
|
||||
Either way the binary lands on your PATH. Run <Code>soulseek-rs</Code> in a
|
||||
terminal and the TUI opens, in a script or a pipe it wants a subcommand
|
||||
Every route puts the same binary on your PATH. Run <Code>soulseek-rs</Code> in
|
||||
a terminal and the TUI opens, in a script or a pipe it wants a subcommand
|
||||
instead.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 sm:gap-3">
|
||||
<Button href={LINKS.releases}>Prebuilt binaries</Button>
|
||||
</div>
|
||||
<p className="text-[13px] text-muted">
|
||||
No Rust toolchain? Grab a prebuilt archive for your platform from the{' '}
|
||||
<a
|
||||
href={LINKS.releases}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-link hover:text-link-hover"
|
||||
>
|
||||
releases page
|
||||
</a>
|
||||
, unpack it, and put the binary somewhere on your PATH.
|
||||
</p>
|
||||
</Step>
|
||||
|
||||
<Step n={2} title="Build from source">
|
||||
@@ -350,7 +422,7 @@ export const Install = () => {
|
||||
{PLATFORMS.map((platform) => (
|
||||
<div
|
||||
key={platform.id}
|
||||
id={platform.id}
|
||||
id={`${platform.id}-paths`}
|
||||
className="scroll-mt-20 rounded-md border border-hairline bg-panel p-[18px] sm:p-[22px]"
|
||||
>
|
||||
<h3 className="mb-4 text-heading leading-[var(--text-heading--line-height)] font-medium">
|
||||
|
||||
Reference in New Issue
Block a user