feat(frontend): unify control radius on one token

Buttons and inputs in the kit used rounded-md (6px) while the landing CTAs
hard-coded 0.6rem (9.6px), so a form row could mix three different corners.
Add --radius-ctl (10px, matching --radius-panel), point every interactive
control at it via rounded-ctl and make the CTAs consume the same variable.

Drop the unused ButtonAnchor helper.
This commit is contained in:
loki5512344 2026-09-28 13:16:59 +02:00
parent 7bb981b58e
commit 456366006e
Signed by: boba
GPG key ID: 253067914055423B
11 changed files with 17 additions and 22 deletions

View file

@ -32,7 +32,7 @@ export function AvatarUpload() {
<div className="flex flex-col items-center gap-2">
<label
htmlFor={id}
className="cursor-pointer rounded-md border border-shoal px-3 py-1.5 text-sm text-snow hover:border-frost"
className="cursor-pointer rounded-ctl border border-shoal px-3 py-1.5 text-sm text-snow hover:border-frost"
>
{t('avatar.change')}
<input

View file

@ -39,7 +39,7 @@ export function PublishForm({
}
return (
<div className="flex flex-col gap-3 rounded-md border border-shoal bg-abyss/60 p-3">
<div className="flex flex-col gap-3 rounded-ctl border border-shoal bg-abyss/60 p-3">
<TextField
label={t('publishForm.title')}
value={title}
@ -56,7 +56,7 @@ export function PublishForm({
value={description}
onChange={(e) => setDescription(e.target.value.slice(0, MAX_DESCRIPTION))}
rows={3}
className="rounded-md border border-shoal bg-abyss px-3 py-2 text-snow focus:border-ice"
className="rounded-ctl border border-shoal bg-abyss px-3 py-2 text-snow focus:border-ice"
/>
<span className="self-end text-xs text-frost">{t('publishForm.counter', { count: description.length })}</span>
</div>

View file

@ -33,7 +33,7 @@ export function LinkDeviceForm() {
<label htmlFor="device-code" className="text-sm text-frost">
{t('form.codeLabel')}
</label>
<div className="flex items-center gap-2 rounded-md border border-shoal bg-abyss px-3 py-2 focus-within:border-ice">
<div className="flex items-center gap-2 rounded-ctl border border-shoal bg-abyss px-3 py-2 focus-within:border-ice">
<span aria-hidden="true" className="font-code text-ice">
%
</span>

View file

@ -44,7 +44,8 @@
align-items: center;
gap: 0.6rem;
padding: 0.85rem 1.4rem;
border-radius: 0.6rem;
/* Same corner as every control on the site (kit buttons, inputs, panels). */
border-radius: var(--radius-ctl, 10px);
font-weight: 700;
font-size: 1rem;
color: var(--color-abyss);
@ -71,7 +72,7 @@
justify-content: center;
gap: 0.6rem;
padding: 1.1rem 2rem;
border-radius: 0.6rem;
border-radius: var(--radius-ctl, 10px);
font-weight: 600;
font-size: 1.125rem;
color: var(--color-snow);

View file

@ -56,7 +56,7 @@ export function CopyToSlot({ listingId }: { listingId: string }) {
</Notice>
) : null}
{error ? <Notice tone="error">{error}</Notice> : null}
<div role="group" aria-label={t('copy.heading')} className="inline-flex overflow-hidden rounded-md border border-shoal">
<div role="group" aria-label={t('copy.heading')} className="inline-flex overflow-hidden rounded-ctl border border-shoal">
{SLOTS.map((slot) => (
<button
key={slot}

View file

@ -103,7 +103,7 @@ export function ThemeEditor({ initial, intro }: { initial: ThemeEntry; intro?: R
<input
value={draft.name}
onChange={(e) => set({ ...draft, name: e.target.value, id: nameToId(e.target.value) })}
className="rounded-md border border-white/15 bg-black/40 px-3 py-2 text-snow"
className="rounded-ctl border border-white/15 bg-black/40 px-3 py-2 text-snow"
/>
</label>

View file

@ -60,7 +60,7 @@ export function ColorField({ label, value, onChange }: Props) {
onChange={(e) => setEditing({ value, text: e.target.value })}
onBlur={commitText}
onKeyDown={(e) => e.key === 'Enter' && commitText()}
className="lv-hex-input w-[6.25rem] shrink-0 rounded-md border border-white/15 bg-black/40 px-2 py-1 font-code text-xs text-snow"
className="lv-hex-input w-[6.25rem] shrink-0 rounded-ctl border border-white/15 bg-black/40 px-2 py-1 font-code text-xs text-snow"
/>
</span>
</span>

View file

@ -19,6 +19,9 @@
--text-hero: 3.8125rem;
--text-hero--line-height: 1.05;
--radius-panel: 10px;
/* Buttons, inputs and their containers. The landing CTAs hard-code the same value, so one
control cannot land at 6px while its neighbour in the same row lands at 10px. */
--radius-ctl: 10px;
}
/* The page accent follows the active ClickGui theme (useActiveTheme sets it on :root);

View file

@ -1,10 +1,10 @@
import type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react'
import type { ButtonHTMLAttributes } from 'react'
import { Link, type LinkProps } from 'react-router'
type Variant = 'primary' | 'quiet' | 'danger'
const BASE =
'inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-semibold transition-colors'
'inline-flex items-center justify-center gap-2 rounded-ctl px-4 py-2 text-sm font-semibold transition-colors'
const VARIANTS: Record<Variant, string> = {
primary: 'bg-ice text-abyss hover:bg-ice/90',
@ -35,12 +35,3 @@ export function Button({
export function ButtonLink({ variant = 'primary', className = '', ...rest }: LinkProps & { variant?: Variant }) {
return <Link className={`${BASE} ${VARIANTS[variant]} ${className}`} {...rest} />
}
/** Like ButtonLink but escapes to a plain <a> for external/href CTAs (e.g. GitHub downloads). */
export function ButtonAnchor({
variant = 'primary',
className = '',
...rest
}: AnchorHTMLAttributes<HTMLAnchorElement> & { variant?: Variant }) {
return <a className={`${BASE} ${VARIANTS[variant]} ${className}`} {...rest} />
}

View file

@ -3,7 +3,7 @@ import type { ReactNode } from 'react'
export function Notice({ tone, children }: { tone: 'info' | 'error'; children: ReactNode }) {
const styles = tone === 'error' ? 'border-ember/60 text-ember' : 'border-shoal text-frost'
return (
<div role={tone === 'error' ? 'alert' : 'status'} className={`rounded-md border px-3 py-2 text-sm ${styles}`}>
<div role={tone === 'error' ? 'alert' : 'status'} className={`rounded-ctl border px-3 py-2 text-sm ${styles}`}>
{children}
</div>
)

View file

@ -18,7 +18,7 @@ export function TextField({
id={id}
aria-invalid={error ? true : undefined}
aria-describedby={describedBy}
className="rounded-md border border-shoal bg-abyss px-3 py-2 text-snow placeholder:text-frost/60 focus:border-ice aria-invalid:border-ember"
className="rounded-ctl border border-shoal bg-abyss px-3 py-2 text-snow placeholder:text-frost/60 focus:border-ice aria-invalid:border-ember"
{...rest}
/>
{error ? (