Skip to content

Commit 9c5f69f

Browse files
committed
feat: guidelines, chart and live indicator redesign
1 parent cf44249 commit 9c5f69f

File tree

7 files changed

+635
-144
lines changed

7 files changed

+635
-144
lines changed

.cursor/rules/guidelines.mdc

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
Concise rules for building accessible, fast, delightful UIs Use MUST/SHOULD/NEVER to guide decisions
7+
8+
## Interactions
9+
10+
- Keyboard
11+
- MUST: Full keyboard support per [WAI-ARIA APG](https://wwww3org/WAI/ARIA/apg/patterns/)
12+
- MUST: Visible focus rings (`:focus-visible`; group with `:focus-within`)
13+
- MUST: Manage focus (trap, move, and return) per APG patterns
14+
- Targets & input
15+
- MUST: Hit target ≥24px (mobile ≥44px) If visual <24px, expand hit area
16+
- MUST: Mobile `<input>` font-size ≥16px or set:
17+
```html
18+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover">
19+
```
20+
- NEVER: Disable browser zoom
21+
- MUST: `touch-action: manipulation` to prevent double-tap zoom; set `-webkit-tap-highlight-color` to match design
22+
- Inputs & forms (behavior)
23+
- MUST: Hydration-safe inputs (no lost focus/value)
24+
- NEVER: Block paste in `<input>/<textarea>`
25+
- MUST: Loading buttons show spinner and keep original label
26+
- MUST: Enter submits focused text input In `<textarea>`, ⌘/Ctrl+Enter submits; Enter adds newline
27+
- MUST: Keep submit enabled until request starts; then disable, show spinner, use idempotency key
28+
- MUST: Don’t block typing; accept free text and validate after
29+
- MUST: Allow submitting incomplete forms to surface validation
30+
- MUST: Errors inline next to fields; on submit, focus first error
31+
- MUST: `autocomplete` + meaningful `name`; correct `type` and `inputmode`
32+
- SHOULD: Disable spellcheck for emails/codes/usernames
33+
- SHOULD: Placeholders end with ellipsis and show example pattern (eg, `+1 (123) 456-7890`, `sk-012345…`)
34+
- MUST: Warn on unsaved changes before navigation
35+
- MUST: Compatible with password managers & 2FA; allow pasting one-time codes
36+
- MUST: Trim values to handle text expansion trailing spaces
37+
- MUST: No dead zones on checkboxes/radios; label+control share one generous hit target
38+
- State & navigation
39+
- MUST: URL reflects state (deep-link filters/tabs/pagination/expanded panels) Prefer libs like [nuqs](https://nuqs47ngcom/)
40+
- MUST: Back/Forward restores scroll
41+
- MUST: Links are links—use `<a>/<Link>` for navigation (support Cmd/Ctrl/middle-click)
42+
- Feedback
43+
- SHOULD: Optimistic UI; reconcile on response; on failure show error and rollback or offer Undo
44+
- MUST: Confirm destructive actions or provide Undo window
45+
- MUST: Use polite `aria-live` for toasts/inline validation
46+
- SHOULD: Ellipsis (`…`) for options that open follow-ups (eg, “Rename…”)
47+
- Touch/drag/scroll
48+
- MUST: Design forgiving interactions (generous targets, clear affordances; avoid finickiness)
49+
- MUST: Delay first tooltip in a group; subsequent peers no delay
50+
- MUST: Intentional `overscroll-behavior: contain` in modals/drawers
51+
- MUST: During drag, disable text selection and set `inert` on dragged element/containers
52+
- MUST: No “dead-looking” interactive zones—if it looks clickable, it is
53+
- Autofocus
54+
- SHOULD: Autofocus on desktop when there’s a single primary input; rarely on mobile (to avoid layout shift)
55+
56+
## Animation
57+
58+
- MUST: Honor `prefers-reduced-motion` (provide reduced variant)
59+
- SHOULD: Prefer CSS > Web Animations API > JS libraries
60+
- MUST: Animate compositor-friendly props (`transform`, `opacity`); avoid layout/repaint props (`top/left/width/height`)
61+
- SHOULD: Animate only to clarify cause/effect or add deliberate delight
62+
- SHOULD: Choose easing to match the change (size/distance/trigger)
63+
- MUST: Animations are interruptible and input-driven (avoid autoplay)
64+
- MUST: Correct `transform-origin` (motion starts where it “physically” should)
65+
66+
## Layout
67+
68+
- SHOULD: Optical alignment; adjust by ±1px when perception beats geometry
69+
- MUST: Deliberate alignment to grid/baseline/edges/optical centers—no accidental placement
70+
- SHOULD: Balance icon/text lockups (stroke/weight/size/spacing/color)
71+
- MUST: Verify mobile, laptop, ultra-wide (simulate ultra-wide at 50% zoom)
72+
- MUST: Respect safe areas (use env(safe-area-inset-*))
73+
- MUST: Avoid unwanted scrollbars; fix overflows
74+
75+
## Content & Accessibility
76+
77+
- SHOULD: Inline help first; tooltips last resort
78+
- MUST: Skeletons mirror final content to avoid layout shift
79+
- MUST: `<title>` matches current context
80+
- MUST: No dead ends; always offer next step/recovery
81+
- MUST: Design empty/sparse/dense/error states
82+
- SHOULD: Curly quotes (“ ”); avoid widows/orphans
83+
- MUST: Tabular numbers for comparisons (`font-variant-numeric: tabular-nums` or a mono like Geist Mono)
84+
- MUST: Redundant status cues (not color-only); icons have text labels
85+
- MUST: Don’t ship the schema—visuals may omit labels but accessible names still exist
86+
- MUST: Use the ellipsis character `…` (not ``)
87+
- MUST: `scroll-margin-top` on headings for anchored links; include a “Skip to content” link; hierarchical `<h1–h6>`
88+
- MUST: Resilient to user-generated content (short/avg/very long)
89+
- MUST: Locale-aware dates/times/numbers/currency
90+
- MUST: Accurate names (`aria-label`), decorative elements `aria-hidden`, verify in the Accessibility Tree
91+
- MUST: Icon-only buttons have descriptive `aria-label`
92+
- MUST: Prefer native semantics (`button`, `a`, `label`, `table`) before ARIA
93+
- SHOULD: Right-clicking the nav logo surfaces brand assets
94+
- MUST: Use non-breaking spaces to glue terms: `10&nbsp;MB`, `⌘&nbsp;+&nbsp;K`, `Vercel&nbsp;SDK`
95+
96+
## Performance
97+
98+
- SHOULD: Test iOS Low Power Mode and macOS Safari
99+
- MUST: Measure reliably (disable extensions that skew runtime)
100+
- MUST: Track and minimize re-renders (React DevTools/React Scan)
101+
- MUST: Profile with CPU/network throttling
102+
- MUST: Batch layout reads/writes; avoid unnecessary reflows/repaints
103+
- MUST: Mutations (`POST/PATCH/DELETE`) target <500 ms
104+
- SHOULD: Prefer uncontrolled inputs; make controlled loops cheap (keystroke cost)
105+
- MUST: Virtualize large lists (eg, `virtua`)
106+
- MUST: Preload only above-the-fold images; lazy-load the rest
107+
- MUST: Prevent CLS from images (explicit dimensions or reserved space)
108+
109+
## Design
110+
111+
- SHOULD: Layered shadows (ambient + direct)
112+
- SHOULD: Crisp edges via semi-transparent borders + shadows
113+
- SHOULD: Nested radii: child ≤ parent; concentric
114+
- SHOULD: Hue consistency: tint borders/shadows/text toward bg hue
115+
- MUST: Accessible charts (color-blind-friendly palettes)
116+
- MUST: Meet contrast—prefer [APCA](https://apcacontrastcom/) over WCAG 2
117+
- MUST: Increase contrast on `:hover/:active/:focus`
118+
- SHOULD: Match browser UI to bg
119+
- SHOULD: Avoid gradient banding (use masks when needed)

apps/dashboard/app/(main)/websites/[id]/_components/analytics-toolbar.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import dayjs from 'dayjs';
55
import { useAtom } from 'jotai';
66
import { useCallback, useMemo } from 'react';
77
import type { DateRange as DayPickerRange } from 'react-day-picker';
8+
import { LiveUserIndicator } from '@/components/analytics';
89
import { DateRangePicker } from '@/components/date-range-picker';
910
import { Button } from '@/components/ui/button';
1011
import { useDateFilters } from '@/hooks/use-date-filters';
@@ -14,11 +15,13 @@ import { AddFilterForm } from './utils/add-filters';
1415
interface AnalyticsToolbarProps {
1516
isRefreshing: boolean;
1617
onRefresh: () => void;
18+
websiteId: string;
1719
}
1820

1921
export function AnalyticsToolbar({
2022
isRefreshing,
2123
onRefresh,
24+
websiteId,
2225
}: AnalyticsToolbarProps) {
2326
const {
2427
currentDateRange,
@@ -88,6 +91,7 @@ export function AnalyticsToolbar({
8891

8992
<div className="flex items-center gap-2">
9093
<AddFilterForm addFilter={addFilter} buttonText="Filter" />
94+
<LiveUserIndicator websiteId={websiteId} />
9195
<Button
9296
aria-label="Refresh data"
9397
className="h-8 w-8"

0 commit comments

Comments
 (0)