artifact.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. 'use client';
  2. import { Button } from '@/components/ui/button';
  3. import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
  4. import { cn } from '@/lib/utils';
  5. import { type LucideIcon, XIcon } from 'lucide-react';
  6. import type { ComponentProps, HTMLAttributes } from 'react';
  7. export type ArtifactProps = HTMLAttributes<HTMLDivElement>;
  8. export const Artifact = ({ className, ...props }: ArtifactProps) => (
  9. <div
  10. className={cn(
  11. 'flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm',
  12. className,
  13. )}
  14. {...props}
  15. />
  16. );
  17. export type ArtifactHeaderProps = HTMLAttributes<HTMLDivElement>;
  18. export const ArtifactHeader = ({ className, ...props }: ArtifactHeaderProps) => (
  19. <div
  20. className={cn('flex items-center justify-between border-b bg-muted/50 px-4 py-3', className)}
  21. {...props}
  22. />
  23. );
  24. export type ArtifactCloseProps = ComponentProps<typeof Button>;
  25. export const ArtifactClose = ({
  26. className,
  27. children,
  28. size = 'sm',
  29. variant = 'ghost',
  30. ...props
  31. }: ArtifactCloseProps) => (
  32. <Button
  33. className={cn('size-8 p-0 text-muted-foreground hover:text-foreground', className)}
  34. size={size}
  35. type="button"
  36. variant={variant}
  37. {...props}
  38. >
  39. {children ?? <XIcon className="size-4" />}
  40. <span className="sr-only">Close</span>
  41. </Button>
  42. );
  43. export type ArtifactTitleProps = HTMLAttributes<HTMLParagraphElement>;
  44. export const ArtifactTitle = ({ className, ...props }: ArtifactTitleProps) => (
  45. <p className={cn('font-medium text-foreground text-sm', className)} {...props} />
  46. );
  47. export type ArtifactDescriptionProps = HTMLAttributes<HTMLParagraphElement>;
  48. export const ArtifactDescription = ({ className, ...props }: ArtifactDescriptionProps) => (
  49. <p className={cn('text-muted-foreground text-sm', className)} {...props} />
  50. );
  51. export type ArtifactActionsProps = HTMLAttributes<HTMLDivElement>;
  52. export const ArtifactActions = ({ className, ...props }: ArtifactActionsProps) => (
  53. <div className={cn('flex items-center gap-1', className)} {...props} />
  54. );
  55. export type ArtifactActionProps = ComponentProps<typeof Button> & {
  56. tooltip?: string;
  57. label?: string;
  58. icon?: LucideIcon;
  59. };
  60. export const ArtifactAction = ({
  61. tooltip,
  62. label,
  63. icon: Icon,
  64. children,
  65. className,
  66. size = 'sm',
  67. variant = 'ghost',
  68. ...props
  69. }: ArtifactActionProps) => {
  70. const button = (
  71. <Button
  72. className={cn('size-8 p-0 text-muted-foreground hover:text-foreground', className)}
  73. size={size}
  74. type="button"
  75. variant={variant}
  76. {...props}
  77. >
  78. {Icon ? <Icon className="size-4" /> : children}
  79. <span className="sr-only">{label || tooltip}</span>
  80. </Button>
  81. );
  82. if (tooltip) {
  83. return (
  84. <TooltipProvider>
  85. <Tooltip>
  86. <TooltipTrigger asChild>{button}</TooltipTrigger>
  87. <TooltipContent>
  88. <p>{tooltip}</p>
  89. </TooltipContent>
  90. </Tooltip>
  91. </TooltipProvider>
  92. );
  93. }
  94. return button;
  95. };
  96. export type ArtifactContentProps = HTMLAttributes<HTMLDivElement>;
  97. export const ArtifactContent = ({ className, ...props }: ArtifactContentProps) => (
  98. <div className={cn('flex-1 overflow-auto p-4', className)} {...props} />
  99. );