Fondo pagina, carte e `secondary` stavano dentro tre punti di luminosità:
carta e fondo avevano un rapporto di contrasto di 1.04, cioè erano lo stesso
bianco. Le carte non si leggevano come carte, e l'unica cosa che le staccava
era `shadow-card` — 6% di nero, che su un telefono al sole non esiste. Da qui
l'impressione che fondo, barra ed elementi fossero «tre bianchi».
La rampa dei neutri è ridistanziata: fondo 0.93, carta 1.0, `secondary` 0.90.
Carta e fondo passano a 1.23, un elemento dentro una carta sta a 1.35 dalla
carta ed è più scuro di essa, come nelle liste raggruppate di iOS. 0.93 è il
fondo più scuro possibile senza toccare altro: il limite lo impone
`text-accent` appoggiato sul fondo, che a 0.92 scenderebbe sotto 4.5.
Due colori vanno corretti di conseguenza, altrimenti la modifica peggiora la
leggibilità: l'accento scende a 0.54 (a 0.58 come testo faceva 4.07 sul nuovo
fondo; ora fa 4.62, e migliora anche il bianco che ci sta sopra, da 4.65 a
5.51) e `muted-foreground` a 0.48. Verificati convertendo le oklch in sRGB e
calcolando i rapporti, non a occhio.
`--destructive` e `--ring` erano *lo stesso identico colore* dell'accento:
«elimina», «selezionato» e «ho il focus qui» davano il medesimo segnale. Il
distruttivo resta rosso ma più scuro e cupo, il focus viene dal neutro.
Le ombre passano da una a tre quote: `shadow-card` per il contenuto,
`shadow-chrome` per barra, drawer e toast (più profonda, più il filo chiaro sul
bordo alto), `shadow-alza` neutra per l'hover — `premi` metteva un alone rosso
sotto ogni riga di classifica.
La barra ora usa `vetro`: fondo al 62% invece dell'85%, così ci si vede
attraverso, più tre ombre interne che sono il bordo illuminato. L'85% di
`materiale` esiste per tenere allineati WebKit e Blink (608f2ed) su una fascia
larga quanto lo schermo; su una pillola di 60 px lo scarto non si legge.
Dietro `@supports`, un `feDisplacementMap` distorce davvero il fondale: solo
Blink accetta un filtro SVG in `backdrop-filter`, e WebKit ignorando l'url
scarterebbe anche il blur. Miglioria progressiva, non l'effetto principale.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import * as React from "react";
|
|
import { Drawer as DrawerPrimitive } from "vaul";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const Drawer = ({
|
|
shouldScaleBackground = true,
|
|
...props
|
|
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
|
|
<DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
|
|
);
|
|
Drawer.displayName = "Drawer";
|
|
|
|
const DrawerTrigger = DrawerPrimitive.Trigger;
|
|
|
|
const DrawerPortal = DrawerPrimitive.Portal;
|
|
|
|
const DrawerClose = DrawerPrimitive.Close;
|
|
|
|
const DrawerOverlay = React.forwardRef<
|
|
React.ElementRef<typeof DrawerPrimitive.Overlay>,
|
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
|
|
>(({ className, ...props }, ref) => (
|
|
<DrawerPrimitive.Overlay
|
|
ref={ref}
|
|
className={cn("fixed inset-0 z-50 bg-black/80", className)}
|
|
{...props}
|
|
/>
|
|
));
|
|
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
|
|
|
|
const DrawerContent = React.forwardRef<
|
|
React.ElementRef<typeof DrawerPrimitive.Content>,
|
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
|
|
>(({ className, children, ...props }, ref) => (
|
|
<DrawerPortal>
|
|
<DrawerOverlay />
|
|
<DrawerPrimitive.Content
|
|
ref={ref}
|
|
className={cn(
|
|
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background shadow-chrome",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
|
{children}
|
|
</DrawerPrimitive.Content>
|
|
</DrawerPortal>
|
|
));
|
|
DrawerContent.displayName = "DrawerContent";
|
|
|
|
const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
<div className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)} {...props} />
|
|
);
|
|
DrawerHeader.displayName = "DrawerHeader";
|
|
|
|
const DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
<div className={cn("mt-auto flex flex-col gap-2 p-4", className)} {...props} />
|
|
);
|
|
DrawerFooter.displayName = "DrawerFooter";
|
|
|
|
const DrawerTitle = React.forwardRef<
|
|
React.ElementRef<typeof DrawerPrimitive.Title>,
|
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
|
|
>(({ className, ...props }, ref) => (
|
|
<DrawerPrimitive.Title
|
|
ref={ref}
|
|
className={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
|
{...props}
|
|
/>
|
|
));
|
|
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
|
|
|
|
const DrawerDescription = React.forwardRef<
|
|
React.ElementRef<typeof DrawerPrimitive.Description>,
|
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
|
|
>(({ className, ...props }, ref) => (
|
|
<DrawerPrimitive.Description
|
|
ref={ref}
|
|
className={cn("text-sm text-muted-foreground", className)}
|
|
{...props}
|
|
/>
|
|
));
|
|
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
|
|
|
|
export {
|
|
Drawer,
|
|
DrawerPortal,
|
|
DrawerOverlay,
|
|
DrawerTrigger,
|
|
DrawerClose,
|
|
DrawerContent,
|
|
DrawerHeader,
|
|
DrawerFooter,
|
|
DrawerTitle,
|
|
DrawerDescription,
|
|
};
|