Fishies 0.8.2
This commit is contained in:
parent
004fbdc97e
commit
4d52068149
14 changed files with 42 additions and 184 deletions
13
src/kit.tsx
13
src/kit.tsx
|
|
@ -5,13 +5,9 @@ import FishiesImg from './FishiesImg'
|
|||
import { ICON_SIZES, iconByName, iconUrl, type IconSize, type SystemIconName } from './icons'
|
||||
import './kit.css'
|
||||
|
||||
/* fishies-ui components. Each export's first doc sentence is its Handbook entry (the build reads
|
||||
them), so a component is described once, here, next to the code that draws it. */
|
||||
|
||||
const cx = (...names: (string | false | null | undefined)[]) => names.filter(Boolean).join(' ')
|
||||
const px = (size: IconSize | number) => typeof size === 'number' ? size : ICON_SIZES[size]
|
||||
|
||||
/** A painted icon from the system set, by name, at one of the set's sizes. */
|
||||
export function SystemIcon({ name, size = 'md', fallback, className }: { name: SystemIconName; size?: IconSize | number; fallback?: ReactNode; className?: string }) {
|
||||
const [failed, setFailed] = useState(false)
|
||||
const icon = iconByName(name)
|
||||
|
|
@ -55,14 +51,12 @@ export function Chip({ tone, icon, selected, onClick, children, className }: { t
|
|||
: <span className={cx('fx-chip', selected && 'is-on', className)} style={style}>{inner}</span>
|
||||
}
|
||||
|
||||
/** A coral count bubble that sits on a tile, a dock item or a bell; a dot when the number does not matter. */
|
||||
export function Badge({ count, label }: { count?: number; label?: string }) {
|
||||
return count === undefined
|
||||
? <span className="fx-badge is-dot" role="status" aria-label={label}/>
|
||||
: <span className="fx-badge" role="status" aria-label={label}>{count > 99 ? '99+' : count}</span>
|
||||
}
|
||||
|
||||
/** A gold-rimmed capsule for a small upper-case word beside a name (Beta, New, Admin). */
|
||||
export function Tag({ children }: { children: ReactNode }) {
|
||||
return <span className="fx-tag">{children}</span>
|
||||
}
|
||||
|
|
@ -76,7 +70,6 @@ export function Card({ eyebrow, title, children, className }: { eyebrow?: string
|
|||
</article>
|
||||
}
|
||||
|
||||
/** A gold-rimmed glass panel with a title row (icon, title, actions) and a body. */
|
||||
export function Panel({ title, icon, actions, children, className, style }: { title: ReactNode; icon?: SystemIconName; actions?: ReactNode; children?: ReactNode; className?: string; style?: CSSProperties }) {
|
||||
return <section className={cx('fx-panel', className)} style={style}>
|
||||
<header className="fx-panel-head">{icon && <SystemIcon name={icon} size={30}/>}<h2>{title}</h2>{actions}</header>
|
||||
|
|
@ -104,7 +97,6 @@ export function Window({ title, icon, onClose, onMinimize, closeLabel = 'Close',
|
|||
|
||||
export type TabItem = { id: string; label: string; icon?: SystemIconName }
|
||||
|
||||
/** A row of pill tabs in a sunken track; the chosen one is gold. */
|
||||
export function Tabs({ items, value, onChange, label }: { items: readonly TabItem[]; value: string; onChange: (id: string) => void; label: string }) {
|
||||
const move = (from: number, step: number) => onChange(items[(from + step + items.length) % items.length]!.id)
|
||||
return <div className="fx-tabs" role="tablist" aria-label={label}>
|
||||
|
|
@ -120,7 +112,6 @@ export function List({ children, label }: { children: ReactNode; label?: string
|
|||
return <ul className="fx-list" aria-label={label}>{children}</ul>
|
||||
}
|
||||
|
||||
/** One row of a list; a button when it does something, a link when it goes somewhere. */
|
||||
export function ListRow({ icon, title, detail, end, onClick, href, selected }: { icon?: SystemIconName; title: ReactNode; detail?: ReactNode; end?: ReactNode; onClick?: () => void; href?: string; selected?: boolean }) {
|
||||
const inner = <>{icon && <SystemIcon name={icon} size={36}/>}<span className="fx-row-text"><b>{title}</b>{detail && <small>{detail}</small>}</span>{end !== undefined && <span className="fx-row-end">{end}</span>}</>
|
||||
return <li>{href ? <a className={cx('fx-row', selected && 'is-on')} href={href}>{inner}</a>
|
||||
|
|
@ -128,7 +119,6 @@ export function ListRow({ icon, title, detail, end, onClick, href, selected }: {
|
|||
: <div className={cx('fx-row', selected && 'is-on')}>{inner}</div>}</li>
|
||||
}
|
||||
|
||||
/** A labelled text field in a sunken pill, with an optional hint under it. */
|
||||
export function Field({ label, hint, className, ...input }: { label: string; hint?: string } & InputHTMLAttributes<HTMLInputElement>) {
|
||||
const id = useId()
|
||||
return <label className={cx('fx-field', className)} htmlFor={id}>
|
||||
|
|
@ -138,7 +128,6 @@ export function Field({ label, hint, className, ...input }: { label: string; hin
|
|||
</label>
|
||||
}
|
||||
|
||||
/** An on and off switch with a pearl knob; gold when on. */
|
||||
export function Toggle({ label, checked, onChange, disabled }: { label: ReactNode; checked: boolean; onChange: (checked: boolean) => void; disabled?: boolean }) {
|
||||
return <label className="fx-toggle">
|
||||
<input type="checkbox" role="switch" checked={checked} disabled={disabled} onChange={event => onChange(event.target.checked)}/>
|
||||
|
|
@ -161,7 +150,6 @@ export function Tooltip({ title, icon, text, rows, children, open }: { title: Re
|
|||
</span>
|
||||
}
|
||||
|
||||
/** A notice that slides in at the edge: an icon in a coloured bubble, a title, a line and a close. */
|
||||
export function Toast({ title, children, icon, tone, onClose, closeLabel = 'Close' }: { title: ReactNode; children?: ReactNode; icon?: SystemIconName; tone?: string; onClose?: () => void; closeLabel?: string }) {
|
||||
return <div className="fx-toast" role="status" style={tone ? { '--tone': tone } as CSSProperties : undefined}>
|
||||
{icon && <span className="fx-toast-art"><SystemIcon name={icon} size={32}/></span>}
|
||||
|
|
@ -186,7 +174,6 @@ export function DockTile({ icon, title, hue, badge, open, onClick }: { icon: Sys
|
|||
</button>
|
||||
}
|
||||
|
||||
/** A dock: a gold-rimmed glass shelf of icons; the app in front wears a gold bar, open ones a dot. */
|
||||
export function Dock({ children, label }: { children: ReactNode; label: string }) {
|
||||
return <nav className="fx-dock" aria-label={label}>{children}</nav>
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue