feat(website): drop the tmux bar from the hero demo

The demo is the client, not the terminal it happens to run in. Removing the
bar takes the tmux window list, session name, host and clock with it, plus
the three --tmux-* tokens that existed only to paint it.

The scale floor goes too: the terminal now shrinks to whatever width it is
given instead of stopping at half size and scrolling sideways, which makes
useFitScale's minScale parameter and the media query feeding it dead weight.
This commit is contained in:
Michel de Graaf
2026-07-25 00:20:46 +02:00
parent 723700753a
commit 8b8383afdf
5 changed files with 8 additions and 78 deletions
+1 -27
View File
@@ -1,7 +1,7 @@
import { VERSION } from '@/lib/links' import { VERSION } from '@/lib/links'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { CLOCK, DATE, HOST, SESSION, SHORTCUTS, WINDOWS } from './data' import { SHORTCUTS } from './data'
interface TuiPaneProps { interface TuiPaneProps {
title: string title: string
@@ -54,32 +54,6 @@ export const MacWindow = ({ children }: { children: React.ReactNode }) => (
</div> </div>
) )
export const TmuxBar = () => (
<div className="flex h-[26px] items-center border-b border-[color-mix(in_srgb,var(--color-dust)_25%,transparent)] bg-[var(--tmux-bg)] text-[12.5px] text-[var(--color-phosphor)]">
<span className="flex h-full items-center bg-[var(--color-phosphor)] px-2.5 font-bold text-[var(--tmux-bg)]">
{SESSION}
</span>
{WINDOWS.map((w) => (
<span
key={w.n}
className={cn(
'flex h-full items-center gap-1.5 px-3',
w.active === true
? 'bg-[var(--tmux-hl)] font-bold text-[var(--tmux-hl-fg)]'
: 'text-[var(--color-phosphor)]',
)}
>
{w.n} <span className="opacity-55">›</span> {w.name}
</span>
))}
<span className="ml-auto flex gap-4 px-3 text-[var(--color-paper)]">
<span className="bg-[var(--tmux-hl)] px-2 font-semibold text-[var(--tmux-hl-fg)]">
{DATE} · {CLOCK}
</span>
<span className="font-bold">{HOST}</span>
</span>
</div>
)
export interface StatusCounts { export interface StatusCounts {
active: number active: number
-18
View File
@@ -41,26 +41,8 @@ export interface TransferRow {
rateMbps?: number rateMbps?: number
} }
interface TmuxWindow {
n: number
name: string
active?: boolean
}
export const HOST = 'michels-macbook-pro-m4'
export const CLOCK = '01:45 PM'
export const DATE = '2026-07-24'
export const SESSION = 'develop'
export const SHARE = '/Users/micheldegraaf/Downloads/Soulseek' export const SHARE = '/Users/micheldegraaf/Downloads/Soulseek'
export const WINDOWS: readonly TmuxWindow[] = [
{ n: 1, name: 'fish #' },
{ n: 2, name: 'fish #' },
{ n: 3, name: 'fish #' },
{ n: 4, name: 'fish #-' },
{ n: 5, name: 'fish *', active: true },
]
export const SEARCHES: readonly SearchRow[] = [ export const SEARCHES: readonly SearchRow[] = [
{ id: 's1', query: 'public domain field recordings', results: 606, status: 'Done' }, { id: 's1', query: 'public domain field recordings', results: 606, status: 'Done' },
{ id: 's2', query: 'creative commons ambient', results: 33, status: 'Done' }, { id: 's2', query: 'creative commons ambient', results: 33, status: 'Done' },
+4 -18
View File
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react' import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react'
import { MacWindow, ShortcutBar, StatusLine, TmuxBar, type StatusCounts } from './chrome' import { MacWindow, ShortcutBar, StatusLine, type StatusCounts } from './chrome'
import { import {
RESULTS, RESULTS,
SEARCHES, SEARCHES,
@@ -362,22 +362,9 @@ export const HeroTerminal = () => {
setPhase('interactive') setPhase('interactive')
} }
// Below 820px, stop shrinking at half size and let the wrapper scroll. // No floor: the terminal shrinks to whatever width it is given rather than
const [minScale, setMinScale] = useState(() => // holding a minimum size and scrolling sideways.
matches('(max-width: 820px)') ? 0.5 : 0, const { wrapRef, innerRef, scale, height, ready } = useFitScale(DESIGN_WIDTH)
)
useEffect(() => {
const query = window.matchMedia('(max-width: 820px)')
const sync = (event: MediaQueryListEvent) => {
setMinScale(event.matches ? 0.5 : 0)
}
query.addEventListener('change', sync)
return () => {
query.removeEventListener('change', sync)
}
}, [])
const { wrapRef, innerRef, scale, height, ready } = useFitScale(DESIGN_WIDTH, minScale)
const shownSearches = searches.map((search, i) => const shownSearches = searches.map((search, i) =>
i === 0 && phase === 'searching' ? { ...search, status: '⋯', results: '—' } : search, i === 0 && phase === 'searching' ? { ...search, status: '⋯', results: '—' } : search,
@@ -401,7 +388,6 @@ export const HeroTerminal = () => {
}} }}
> >
<MacWindow> <MacWindow>
<TmuxBar />
{/* {/*
role="application" is the ARIA escape hatch for a widget that role="application" is the ARIA escape hatch for a widget that
handles its own keys: it stops screen readers intercepting handles its own keys: it stops screen readers intercepting
+3 -6
View File
@@ -15,11 +15,8 @@ interface FitScale {
* looking like a terminal. So it renders at native width and gets a CSS * looking like a terminal. So it renders at native width and gets a CSS
* transform, and the wrapper is told the resulting height so the page below * transform, and the wrapper is told the resulting height so the page below
* does not sit under it. * does not sit under it.
*
* `minScale` stops the shrink at a floor on small screens — past that the
* wrapper scrolls sideways instead, which beats unreadable 4px text.
*/ */
export const useFitScale = (designWidth: number, minScale: number): FitScale => { export const useFitScale = (designWidth: number): FitScale => {
const wrapRef = useRef<HTMLDivElement>(null) const wrapRef = useRef<HTMLDivElement>(null)
const innerRef = useRef<HTMLDivElement>(null) const innerRef = useRef<HTMLDivElement>(null)
const [{ scale, height }, setState] = useState({ scale: 0, height: 0 }) const [{ scale, height }, setState] = useState({ scale: 0, height: 0 })
@@ -36,7 +33,7 @@ export const useFitScale = (designWidth: number, minScale: number): FitScale =>
const width = wrap.clientWidth const width = wrap.clientWidth
if (width === 0) return if (width === 0) return
const next = Math.max(minScale, Math.min(1, width / designWidth)) const next = Math.min(1, width / designWidth)
const nextHeight = inner.offsetHeight * next const nextHeight = inner.offsetHeight * next
if (nextHeight === 0) return if (nextHeight === 0) return
@@ -58,7 +55,7 @@ export const useFitScale = (designWidth: number, minScale: number): FitScale =>
return () => { return () => {
observer.disconnect() observer.disconnect()
} }
}, [designWidth, minScale]) }, [designWidth])
return { wrapRef, innerRef, scale, height, ready: scale > 0 } return { wrapRef, innerRef, scale, height, ready: scale > 0 }
} }
-9
View File
@@ -150,11 +150,6 @@
--tui-track: #2a2622; --tui-track: #2a2622;
--tui-bezel: #000000; --tui-bezel: #000000;
/* tmux's own status bar. Emulator chrome, so it does not follow the theme. */
--tmux-bg: #0e0c0a;
--tmux-hl: #b9a6e8;
--tmux-hl-fg: #1a1526;
color-scheme: dark; color-scheme: dark;
} }
@@ -223,10 +218,6 @@
* is what the Rust client does. Those names do not flip with the theme, so on * is what the Rust client does. Those names do not flip with the theme, so on
* manila they would leave paper-on-paper. Light mode re-cuts the same names * manila they would leave paper-on-paper. Light mode re-cuts the same names
* darker, scoped to the terminal's content. * darker, scoped to the terminal's content.
*
* Deliberately not applied to the tmux bar above it: that is the emulator's
* own chrome, it keeps its near-black background in both themes, and needs
* the bright phosphor to stay legible against it.
*/ */
[data-theme='light'] .tui-content { [data-theme='light'] .tui-content {
--color-paper: #14110f; --color-paper: #14110f;