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:
parent
7bb981b58e
commit
456366006e
11 changed files with 17 additions and 22 deletions
|
|
@ -32,7 +32,7 @@ export function AvatarUpload() {
|
||||||
<div className="flex flex-col items-center gap-2">
|
<div className="flex flex-col items-center gap-2">
|
||||||
<label
|
<label
|
||||||
htmlFor={id}
|
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')}
|
{t('avatar.change')}
|
||||||
<input
|
<input
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export function PublishForm({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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
|
<TextField
|
||||||
label={t('publishForm.title')}
|
label={t('publishForm.title')}
|
||||||
value={title}
|
value={title}
|
||||||
|
|
@ -56,7 +56,7 @@ export function PublishForm({
|
||||||
value={description}
|
value={description}
|
||||||
onChange={(e) => setDescription(e.target.value.slice(0, MAX_DESCRIPTION))}
|
onChange={(e) => setDescription(e.target.value.slice(0, MAX_DESCRIPTION))}
|
||||||
rows={3}
|
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>
|
<span className="self-end text-xs text-frost">{t('publishForm.counter', { count: description.length })}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export function LinkDeviceForm() {
|
||||||
<label htmlFor="device-code" className="text-sm text-frost">
|
<label htmlFor="device-code" className="text-sm text-frost">
|
||||||
{t('form.codeLabel')}
|
{t('form.codeLabel')}
|
||||||
</label>
|
</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 aria-hidden="true" className="font-code text-ice">
|
||||||
%
|
%
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
padding: 0.85rem 1.4rem;
|
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-weight: 700;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--color-abyss);
|
color: var(--color-abyss);
|
||||||
|
|
@ -71,7 +72,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
padding: 1.1rem 2rem;
|
padding: 1.1rem 2rem;
|
||||||
border-radius: 0.6rem;
|
border-radius: var(--radius-ctl, 10px);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
color: var(--color-snow);
|
color: var(--color-snow);
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ export function CopyToSlot({ listingId }: { listingId: string }) {
|
||||||
</Notice>
|
</Notice>
|
||||||
) : null}
|
) : null}
|
||||||
{error ? <Notice tone="error">{error}</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) => (
|
{SLOTS.map((slot) => (
|
||||||
<button
|
<button
|
||||||
key={slot}
|
key={slot}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ export function ThemeEditor({ initial, intro }: { initial: ThemeEntry; intro?: R
|
||||||
<input
|
<input
|
||||||
value={draft.name}
|
value={draft.name}
|
||||||
onChange={(e) => set({ ...draft, name: e.target.value, id: nameToId(e.target.value) })}
|
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>
|
</label>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ export function ColorField({ label, value, onChange }: Props) {
|
||||||
onChange={(e) => setEditing({ value, text: e.target.value })}
|
onChange={(e) => setEditing({ value, text: e.target.value })}
|
||||||
onBlur={commitText}
|
onBlur={commitText}
|
||||||
onKeyDown={(e) => e.key === 'Enter' && 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>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@
|
||||||
--text-hero: 3.8125rem;
|
--text-hero: 3.8125rem;
|
||||||
--text-hero--line-height: 1.05;
|
--text-hero--line-height: 1.05;
|
||||||
--radius-panel: 10px;
|
--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);
|
/* The page accent follows the active ClickGui theme (useActiveTheme sets it on :root);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react'
|
import type { ButtonHTMLAttributes } from 'react'
|
||||||
import { Link, type LinkProps } from 'react-router'
|
import { Link, type LinkProps } from 'react-router'
|
||||||
|
|
||||||
type Variant = 'primary' | 'quiet' | 'danger'
|
type Variant = 'primary' | 'quiet' | 'danger'
|
||||||
|
|
||||||
const BASE =
|
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> = {
|
const VARIANTS: Record<Variant, string> = {
|
||||||
primary: 'bg-ice text-abyss hover:bg-ice/90',
|
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 }) {
|
export function ButtonLink({ variant = 'primary', className = '', ...rest }: LinkProps & { variant?: Variant }) {
|
||||||
return <Link className={`${BASE} ${VARIANTS[variant]} ${className}`} {...rest} />
|
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} />
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import type { ReactNode } from 'react'
|
||||||
export function Notice({ tone, children }: { tone: 'info' | 'error'; children: ReactNode }) {
|
export function Notice({ tone, children }: { tone: 'info' | 'error'; children: ReactNode }) {
|
||||||
const styles = tone === 'error' ? 'border-ember/60 text-ember' : 'border-shoal text-frost'
|
const styles = tone === 'error' ? 'border-ember/60 text-ember' : 'border-shoal text-frost'
|
||||||
return (
|
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}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export function TextField({
|
||||||
id={id}
|
id={id}
|
||||||
aria-invalid={error ? true : undefined}
|
aria-invalid={error ? true : undefined}
|
||||||
aria-describedby={describedBy}
|
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}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
{error ? (
|
{error ? (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue