Card.tsx 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import { createContext, useContext } from 'react';
  2. import type { ReactNode, MouseEvent, HTMLAttributes } from 'react';
  3. type CardDensity = 'normal' | 'dense';
  4. const CardDensityContext = createContext<CardDensity>('normal');
  5. export function CardDensityProvider({ density, children }: { density: CardDensity; children: ReactNode }) {
  6. return <CardDensityContext.Provider value={density}>{children}</CardDensityContext.Provider>;
  7. }
  8. interface CardProps extends HTMLAttributes<HTMLDivElement> {
  9. children: ReactNode;
  10. className?: string;
  11. onClick?: (e: MouseEvent) => void;
  12. onContextMenu?: (e: MouseEvent) => void;
  13. }
  14. interface CardSectionProps {
  15. children: ReactNode;
  16. className?: string;
  17. dense?: boolean;
  18. }
  19. export function Card({ children, className = '', onClick, onContextMenu, ...rest }: CardProps) {
  20. return (
  21. <div
  22. className={`bg-bambu-dark-secondary rounded-xl border border-bambu-dark-tertiary card-shadow ${className}`}
  23. onClick={onClick}
  24. onContextMenu={onContextMenu}
  25. {...rest}
  26. >
  27. {children}
  28. </div>
  29. );
  30. }
  31. export function CardHeader({ children, className = '', dense }: CardSectionProps) {
  32. const ctxDense = useContext(CardDensityContext) === 'dense';
  33. const isDense = dense ?? ctxDense;
  34. const padding = isDense ? 'px-4 py-2.5' : 'px-6 py-4';
  35. return (
  36. <div className={`${padding} border-b border-bambu-dark-tertiary ${className}`}>
  37. {children}
  38. </div>
  39. );
  40. }
  41. export function CardContent({ children, className = '', dense }: CardSectionProps) {
  42. const ctxDense = useContext(CardDensityContext) === 'dense';
  43. const isDense = dense ?? ctxDense;
  44. const padding = isDense ? 'p-4' : 'p-6';
  45. return <div className={`${padding} ${className}`}>{children}</div>;
  46. }