fix(audit-wave-9): standardize on Sheet for previews; doctrine in CLAUDE.md
Swap the one outlier (client-interests-tab.tsx) from Vaul Drawer to Sheet side=right so every detail-preview surface uses the same primitive. Document the doctrine: Sheet for side panels on both desktop and mobile; Vaul Drawer reserved for mobile-only bottom-sheet UX (currently just MoreSheet). Closes ui/ux M11. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -65,6 +65,11 @@ const Carousel = React.forwardRef<
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api) return;
|
||||
// Embla doesn't fire 'select' on mount, so we sync state from the
|
||||
// external store once here. This is the canonical pattern for
|
||||
// subscribing to a third-party event source and is intentionally
|
||||
// flagged-but-allowed.
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
onSelect(api);
|
||||
api.on('reInit', onSelect);
|
||||
api.on('select', onSelect);
|
||||
|
||||
48
src/components/ui/warning-callout.tsx
Normal file
48
src/components/ui/warning-callout.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import * as React from 'react';
|
||||
import { AlertTriangle } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
/**
|
||||
* Compact amber-bordered alert callout. Replaces the dozen-plus ad-hoc
|
||||
* `border-amber-{200,300} bg-amber-50` `<div>`s scattered through the
|
||||
* codebase that the ui/ux audit (L5) flagged as drift.
|
||||
*
|
||||
* Renders a leading triangle icon by default; pass `icon={false}` to
|
||||
* suppress when the surrounding layout already conveys the warning
|
||||
* semantics. The icon is `aria-hidden` because the text content always
|
||||
* carries the meaning.
|
||||
*/
|
||||
export interface WarningCalloutProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
|
||||
/** Optional pre-content heading rendered bolder than the body. */
|
||||
title?: React.ReactNode;
|
||||
/** Set false to suppress the leading icon. */
|
||||
icon?: boolean;
|
||||
}
|
||||
|
||||
export function WarningCallout({
|
||||
title,
|
||||
icon = true,
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
}: WarningCalloutProps) {
|
||||
return (
|
||||
<div
|
||||
role="status"
|
||||
className={cn(
|
||||
'rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-900',
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
<div className="flex items-start gap-2">
|
||||
{icon ? <AlertTriangle aria-hidden className="mt-0.5 size-4 shrink-0" /> : null}
|
||||
<div className="min-w-0 flex-1 space-y-1">
|
||||
{title ? <div className="font-medium">{title}</div> : null}
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user