refactor(design): lock the border-radius ladder, one radius per role (#1607)
Seven radii were in circulation (4/5/6/8/12/16px + pill) with no rule for which went where; one toolbar row on /transactions mixed four shape languages. This locks a 4-tier ladder (design.md convention 16): - pill: interactive toolbar controls (buttons, chips, pickers, segmented controls, toolbar search, count nubs) - rounded-xl (12px): overlay tier: page panel, dialogs, slide-overs - rounded-lg (8px): cards, form fields, popover/menu content, boxes - rounded-sm (4px): nested leaves (menu items, checkboxes, kbd/code nubs) Changes: - New SegmentedControl primitive (pill-in-pill tablist, h-8) replaces the hand-rolled bg-muted/70 tablist copied across 11 files - New ToolbarSearch primitive (pill, h-8) adopted on 9 page toolbars; dialog/picker searches keep the rounded-lg Input - dialog.tsx 8px -> 12px, matching SettingsModal/slide-over/CommandPalette - ContextPicker chips at the shared h-8 toolbar height - ~300 rounded-md / bare rounded call sites remapped by role; auth icon tiles and the mobile nav sheet come down from 16px to 12px - rounded-md, bare rounded, rounded-2xl and rounded-[Npx] are dead vocabulary, enforced by a new off-ladder-radius check in check:guards Verified: lint 0 errors, 14422 unit tests pass, check:guards green, tsc clean on all changed files, sandbox screenshots of transactions/ bookkeeping/granskning toolbars and the Ny verifikation dialog. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Fable 5
parent
18c20e68e6
commit
9686b54b41
@@ -265,7 +265,7 @@ export default function DimensionCombobox({
|
||||
{isOpen && !disabled && (
|
||||
<div
|
||||
ref={listRef}
|
||||
className="absolute z-50 top-full left-0 mt-1 min-w-[16rem] w-[max(100%,20rem)] max-h-[300px] overflow-y-auto rounded-md border border-input bg-card shadow-md"
|
||||
className="absolute z-50 top-full left-0 mt-1 min-w-[16rem] w-[max(100%,20rem)] max-h-[300px] overflow-y-auto rounded-lg border border-input bg-card shadow-md"
|
||||
>
|
||||
{loadState === 'loading' && (
|
||||
<div className="flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground">
|
||||
|
||||
@@ -6,6 +6,8 @@ import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { SegmentedControl } from '@/components/ui/segmented-control'
|
||||
import { ToolbarSearch } from '@/components/ui/toolbar-search'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { TH_CLASS, TD_CLASS, QUIET_LINK_CLASS } from '@/components/ui/dry-table'
|
||||
@@ -368,40 +370,30 @@ export default function DimensionsManager() {
|
||||
muted value count, search, and the actions far right. */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<div className="inline-flex shrink-0 gap-0.5 rounded-lg bg-muted/70 p-[3px]" role="tablist">
|
||||
{dimensions.map((dim) => (
|
||||
<button
|
||||
key={dim.id}
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected={activeDimId === dim.id}
|
||||
onClick={() => {
|
||||
setActiveDimId(dim.id)
|
||||
setSearchTerm('')
|
||||
}}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1.5 rounded-md px-3.5 py-[5px] text-[12.5px] transition-colors duration-150',
|
||||
activeDimId === dim.id
|
||||
? 'border border-border bg-card font-medium text-foreground'
|
||||
: 'text-muted-foreground hover:text-foreground',
|
||||
)}
|
||||
>
|
||||
{dim.name}
|
||||
{dim.values.length > 0 && (
|
||||
<span className="text-muted-foreground tabular-nums">{dim.values.length}</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="relative min-w-[180px] max-w-xs flex-1">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder={t('search_placeholder')}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="h-9 pl-10"
|
||||
/>
|
||||
</div>
|
||||
<SegmentedControl
|
||||
value={activeDimId ?? ''}
|
||||
onChange={(id) => {
|
||||
setActiveDimId(id)
|
||||
setSearchTerm('')
|
||||
}}
|
||||
options={dimensions.map((dim) => ({
|
||||
value: dim.id,
|
||||
label: (
|
||||
<>
|
||||
{dim.name}
|
||||
{dim.values.length > 0 && (
|
||||
<span className="text-muted-foreground tabular-nums">{dim.values.length}</span>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
}))}
|
||||
/>
|
||||
<ToolbarSearch
|
||||
placeholder={t('search_placeholder')}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
containerClassName="min-w-[180px] max-w-xs flex-1"
|
||||
/>
|
||||
<div className="ml-auto flex items-center gap-4">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user