Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The system employs a **bimodal elevation strategy**:

- **Avatars**: `size-8` (32px) `rounded-full`, `overflow-hidden`, `shrink-0`; the size is overridable per call site via `class` (e.g. `class="size-6"` / `size-10"`). Fallback is a paired step of the warm-gray ramp — `bg-[--accent-gray-soft-active]` fill + `text-[--accent-gray-deep]` `font-medium` initials, centered and `select-none`. (The old `bg-muted`/`text-muted-foreground` was too light to read as a present circle and the cool muted-foreground initials looked murky; the ramp pair gives a deliberate placeholder, not an empty/disabled blob.) Still neutral — no per-identity accent tint. Status dots/badges are composed at the call site and need a 2px knockout border matching the surface behind the avatar.
- **Badges**: 4px radius (`rounded-sm`). Default uses `secondary/secondary-foreground` with `border-border`. Secondary uses `accent/foreground`. Destructive, success, and warning map to global status tokens. Outline uses `background/border/foreground`. Supports `size="sm"` (`text-[11px] px-2`) alongside default.
- **BadgeCount**: Circular numeric counter. `rounded-full`, `h-[18px] min-w-[18px] px-1`, `text-[11px] font-medium`. Uses the same base/status mapping as Badge. Values above 99 display as "99+".
- **BadgeCount**: Circular numeric counter. `rounded-full`, `h-[18px] min-w-[18px] px-1`, `text-[11px] font-medium`. Solid tones: `default` neutral, `destructive` red alert, `warning` yellow (waiting on the user), `brand` scheme brand (new, not alarming). Values above 99 display as "99+".
- **Buttons**:
- Default / Primary: 8px radius, charcoal fill (`--btn-primary`) with hover/press ramps on the pseudo-element shell. This is the standard high-emphasis action; `default` and `primary` are visual aliases.
- Outline / Secondary: 8px radius, transparent rest state with a 1px inset ring, gray hover fill, and shell-only press scale. `outline` and `secondary` are visual aliases.
Expand Down
6 changes: 4 additions & 2 deletions skills/web/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,10 @@ recurring failures to avoid:
*footprint* (e.g. matching an adjacent control's size so two rows carry comparable weight), borrow
only the size (`flex items-center justify-center` at whatever size fits) — never the primitive's
border/bg. See `reference.md` § Dirty → clean for the full case (`ActionCard`'s icon slot).
- **`BadgeCount`:** `destructive` red dot pinned to an icon corner = alert/unread; `default`
neutral count rides a tab/filter/segment; a flat list row uses a plain muted numeral, no bubble.
- **`BadgeCount`:** tone by meaning, loudest first: `destructive` red = something failed or
needs fixing, `warning` yellow = something waits on the user, `brand` = new-for-you without
alarm; `default` neutral count rides a tab/filter/segment; a flat list row uses a plain muted
numeral, no bubble. A count summarizing mixed items takes its most urgent item's tone.
- **`Tooltip`:** always the `@felinic/ui` `Tooltip`. A hand-rolled or legacy tooltip is a bug.
- **An empty state keeps the populated skeleton — it is the same page with no rows yet.** The
worst empty-state failure is letting "there's no data" rearrange the page into a *different*
Expand Down
7 changes: 5 additions & 2 deletions skills/web/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ already in our system, or like an AI improvising its own house style?"
| Clickable low-emphasis text w/ hover chip | `TextButton` (ghost @ `size="text"`) | a `<span @click>` with a hand-rolled hover |
| High-emphasis CTA | `<Button>` (charcoal default) | `variant="brand"` purple unless it's a true brand CTA |
| Destructive action | `<Button variant="destructive">` (filled) | `variant="ghost"` + `text-destructive` |
| Count / unread / overflow badge | `BadgeCount` (`destructive` alert · `default` neutral) | a hand-built rounded-full number pill |
| Count / unread / overflow badge | `BadgeCount` (`destructive` alert · `warning` waiting · `brand` new · `default` neutral) | a hand-built rounded-full number pill |
| Empty surface | `Empty` (+ framed) | bare centered muted `<p>` |
| Status that aligns to a section title | `Badge` (gives the status a box edge) | a loose dot + text floating with nothing to align to |
| Create / edit form | the New Task `Dialog` shape (§ Form recipe) | a bespoke per-page form layout; `sm` footer buttons |
Expand All @@ -678,7 +678,10 @@ look "compact" (or inflated to look "important"). Size each for a reason, not by
in-field **14px** (`size-3.5`); text/badge rung **12px** (`size-3`). Pick the rung; don't
free-set sizes.
- `BadgeCount`: `destructive` is the red alert dot pinned to an **icon corner**
(`absolute -right-1.5 -top-1.5`) for unread/needs-attention; `default` is a neutral count
(`absolute -right-1.5 -top-1.5`) for a failure or something that needs fixing; `warning`
(yellow, dark numeral) counts items waiting on the user; `brand` counts plain new items
(unread replies) so they are spotted without reading as an alert. Keep red scarce: a count
over mixed items takes its most urgent item's tone (red > yellow > brand). `default` is a neutral count
that rides a tab/filter/segment label; in a flat list row, a count is calmer as a plain
muted numeral (`text-caption tabular-nums text-muted-foreground`), no bubble. Overflow caps
at `:max` (default 99 → `99+`).
Expand Down
12 changes: 10 additions & 2 deletions src/components/badge/BadgeCount.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ import { cn } from '#/lib/utils'
// fills with a high-contrast numeral instead:
// default — neutral solid that flips with the theme (foreground/background),
// always crisp, for a plain "N items" count.
// destructive — the saturated red alert dot (red-fill + white) for unread /
// attention-worthy counts; the canonical notification bubble.
// destructive — the saturated red alert dot (red-fill + white): something failed
// or needs fixing; the loudest rung, keep it for real alerts.
// warning — the yellow solid (warning + its dark solid foreground): something
// is waiting on the user.
// brand — the scheme's brand solid (brand + white): a plain "new for you"
// count that should be spotted without reading as an alert.
// Pick the tone by what the count means, so a summary of mixed items can speak
// for its most urgent one (red > yellow > brand).
// (No soft variant — if a count should whisper, it usually shouldn't be a bubble at
// all but a plain muted numeral in the row.)
const badgeCountVariants = cva(
Expand All @@ -29,6 +35,8 @@ const badgeCountVariants = cva(
variant: {
default: 'bg-foreground text-background',
destructive: 'bg-accent-red-fill text-accent-red-foreground',
warning: 'bg-warning text-warning-solid-foreground',
brand: 'bg-brand text-brand-foreground',
},
},
defaultVariants: {
Expand Down
Loading