{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "media-asset-gallery",
  "title": "Media Asset Gallery",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/media-asset-gallery/MediaAssetGallery.tsx",
      "content": "'use client'\n\nimport { useMemo, useState } from 'react'\nimport {\n  ArrowDownToLine,\n  Check,\n  CheckCircle2,\n  Code2,\n  Copy,\n  ExternalLink,\n  Eye,\n  FileCode,\n  HardDrive,\n  Image as ImageIcon,\n  Layers,\n  Palette,\n  Search,\n  Shapes,\n  Share2,\n  Tag,\n  Upload,\n  Video,\n  X,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Separator } from '@/components/ui/separator'\nimport {\n  Sheet,\n  SheetClose,\n  SheetContent,\n  SheetDescription,\n  SheetFooter,\n  SheetHeader,\n  SheetTitle,\n} from '@/components/ui/sheet'\nimport { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'\n\nexport interface AssetItem {\n  id: string\n  title: string\n  filename: string\n  category: 'all' | 'images' | 'vectors' | 'videos' | 'logos'\n  type: 'image' | 'vector' | 'video' | 'logo'\n  format: string\n  aspectRatio: '16:9' | '1:1' | '9:16' | 'vector'\n  aspectRatioLabel: string\n  resolutionBadge: string\n  dimensions: string\n  fileSize: string\n  uploadedBy: {\n    name: string\n    role: string\n    avatarInitials: string\n  }\n  uploadDate: string\n  license: string\n  colorSpace: string\n  palette: string[]\n  tags: string[]\n  previewUrl: string\n  downloadOptions: {\n    id: string\n    label: string\n    resolution: string\n    size: string\n    badge?: string\n  }[]\n}\n\nexport interface MediaAssetGalleryProps {\n  className?: string\n}\n\nconst ASSETS: AssetItem[] = [\n  {\n    id: 'dam-01',\n    title: 'Hyperion Cloud UI Design System',\n    filename: 'hyperion-cloud-design-system-4k.png',\n    category: 'images',\n    type: 'image',\n    format: 'PNG',\n    aspectRatio: '16:9',\n    aspectRatioLabel: '16:9 Landscape',\n    resolutionBadge: '4K',\n    dimensions: '3840 × 2160',\n    fileSize: '2.4 MB',\n    uploadedBy: {\n      name: 'Elena Vance',\n      role: 'Brand Architecture Lead',\n      avatarInitials: 'EV',\n    },\n    uploadDate: 'Aug 18, 2026',\n    license: 'Enterprise Commercial',\n    colorSpace: 'Display P3 · 300 DPI',\n    palette: ['#0F172A', '#2563EB', '#38BDF8', '#10B981', '#F8FAFC'],\n    tags: ['#marketing', '#product-ui'],\n    previewUrl: 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=1200&auto=format&fit=crop&q=80',\n    downloadOptions: [\n      { id: 'opt-1', label: 'Original Master (4K)', resolution: '3840 × 2160', size: '2.4 MB', badge: 'Lossless' },\n      { id: 'opt-2', label: 'Web Optimized (1080p)', resolution: '1920 × 1080', size: '640 KB', badge: 'Recommended' },\n      { id: 'opt-3', label: 'Mobile Thumbnail', resolution: '640 × 360', size: '92 KB' },\n    ],\n  },\n  {\n    id: 'dam-02',\n    title: 'NeoCorp Brand Identity & Vector Glyphs',\n    filename: 'neocorp-brand-vector-glyphs.svg',\n    category: 'vectors',\n    type: 'vector',\n    format: 'SVG',\n    aspectRatio: 'vector',\n    aspectRatioLabel: 'Raw Vector',\n    resolutionBadge: 'Vector',\n    dimensions: 'Vector Bezier',\n    fileSize: '420 KB',\n    uploadedBy: {\n      name: 'Marcus Chen',\n      role: 'Principal Iconographer',\n      avatarInitials: 'MC',\n    },\n    uploadDate: 'Aug 15, 2026',\n    license: 'Internal Brand Core',\n    colorSpace: 'sRGB · Vector Paths',\n    palette: ['#4F46E5', '#7C3AED', '#EC4899', '#312E81', '#FFFFFF'],\n    tags: ['#brand-guidelines', '#marketing'],\n    previewUrl: 'https://images.unsplash.com/photo-1634017839464-5c339ebe3cb4?w=1200&auto=format&fit=crop&q=80',\n    downloadOptions: [\n      { id: 'opt-1', label: 'Master SVG Vector', resolution: 'Scalable Bezier', size: '420 KB', badge: 'Source' },\n      { id: 'opt-2', label: 'PNG Hi-Res Raster', resolution: '4096 × 4096', size: '1.1 MB' },\n      { id: 'opt-3', label: 'PDF Vector Spec', resolution: 'Vector PDF', size: '850 KB' },\n    ],\n  },\n  {\n    id: 'dam-03',\n    title: 'Solaris OS 2.0 Product Launch Teaser',\n    filename: 'solaris-os-launch-teaser-h265.mp4',\n    category: 'videos',\n    type: 'video',\n    format: 'MP4',\n    aspectRatio: '16:9',\n    aspectRatioLabel: '16:9 Landscape',\n    resolutionBadge: '4K',\n    dimensions: '3840 × 2160',\n    fileSize: '18.6 MB',\n    uploadedBy: {\n      name: 'Sarah Jenkins',\n      role: 'Motion Art Director',\n      avatarInitials: 'SJ',\n    },\n    uploadDate: 'Aug 12, 2026',\n    license: 'Global Broadcast Sync',\n    colorSpace: 'Rec. 709 · 60 FPS ProRes',\n    palette: ['#18181B', '#EA580C', '#F59E0B', '#06B6D4', '#FAFAFA'],\n    tags: ['#marketing', '#product-ui'],\n    previewUrl: 'https://images.unsplash.com/photo-1550745165-9bc0b252726f?w=1200&auto=format&fit=crop&q=80',\n    downloadOptions: [\n      {\n        id: 'opt-1',\n        label: 'Master 4K Video (ProRes)',\n        resolution: '3840 × 2160 · 60fps',\n        size: '18.6 MB',\n        badge: 'Cinema',\n      },\n      { id: 'opt-2', label: 'Web Stream MP4 (1080p)', resolution: '1920 × 1080 · 30fps', size: '4.8 MB', badge: 'Web' },\n      { id: 'opt-3', label: 'Poster Frame Keyframe', resolution: '3840 × 2160 PNG', size: '1.9 MB' },\n    ],\n  },\n  {\n    id: 'dam-04',\n    title: 'Executive Leadership — Studio Headshot 01',\n    filename: 'alex-morgan-executive-portrait.jpg',\n    category: 'images',\n    type: 'image',\n    format: 'JPG',\n    aspectRatio: '1:1',\n    aspectRatioLabel: '1:1 Square',\n    resolutionBadge: '2K',\n    dimensions: '2048 × 2048',\n    fileSize: '1.8 MB',\n    uploadedBy: {\n      name: 'David Kim',\n      role: 'Staff Photographer',\n      avatarInitials: 'DK',\n    },\n    uploadDate: 'Aug 10, 2026',\n    license: 'Press Kit Editorial',\n    colorSpace: 'Adobe RGB (1998) · 300 DPI',\n    palette: ['#0F172A', '#334155', '#94A3B8', '#0EA5E9', '#F8FAFC'],\n    tags: ['#headshots', '#brand-guidelines'],\n    previewUrl: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=1200&auto=format&fit=crop&q=80',\n    downloadOptions: [\n      { id: 'opt-1', label: 'Full Resolution (2K RAW)', resolution: '2048 × 2048', size: '1.8 MB', badge: 'Print' },\n      { id: 'opt-2', label: 'Square Avatar Web', resolution: '800 × 800', size: '210 KB', badge: 'Web' },\n      { id: 'opt-3', label: 'Compressed WebP', resolution: '400 × 400', size: '45 KB' },\n    ],\n  },\n  {\n    id: 'dam-05',\n    title: 'Mobile App Onboarding Carousel — Portrait',\n    filename: 'mobile-onboarding-mockup-9-16.png',\n    category: 'images',\n    type: 'image',\n    format: 'PNG',\n    aspectRatio: '9:16',\n    aspectRatioLabel: '9:16 Portrait',\n    resolutionBadge: '1080p',\n    dimensions: '1080 × 1920',\n    fileSize: '1.2 MB',\n    uploadedBy: {\n      name: 'Aria Rodriguez',\n      role: 'Mobile UX Architect',\n      avatarInitials: 'AR',\n    },\n    uploadDate: 'Aug 08, 2026',\n    license: 'App Store / Marketing',\n    colorSpace: 'Display P3 · 460 PPI',\n    palette: ['#09090B', '#7C3AED', '#C026D3', '#38BDF8', '#FFFFFF'],\n    tags: ['#product-ui', '#marketing'],\n    previewUrl: 'https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?w=1200&auto=format&fit=crop&q=80',\n    downloadOptions: [\n      { id: 'opt-1', label: 'High Density 9:16 PNG', resolution: '1080 × 1920', size: '1.2 MB', badge: 'Retina' },\n      { id: 'opt-2', label: 'Standard Mobile Display', resolution: '720 × 1280', size: '420 KB' },\n      { id: 'opt-3', label: 'Story Template JPEG', resolution: '1080 × 1920', size: '280 KB' },\n    ],\n  },\n  {\n    id: 'dam-06',\n    title: 'UIPKGE Monogram & Wordmark Master Kit',\n    filename: 'uipkge-monogram-symbol-master.svg',\n    category: 'logos',\n    type: 'logo',\n    format: 'SVG',\n    aspectRatio: '1:1',\n    aspectRatioLabel: '1:1 Square',\n    resolutionBadge: 'Vector',\n    dimensions: '1024 × 1024',\n    fileSize: '180 KB',\n    uploadedBy: {\n      name: 'Elena Vance',\n      role: 'Brand Architecture Lead',\n      avatarInitials: 'EV',\n    },\n    uploadDate: 'Aug 04, 2026',\n    license: 'Master Trademark',\n    colorSpace: 'Pantone Solid Coated · Vector',\n    palette: ['#000000', '#059669', '#047857', '#34D399', '#FFFFFF'],\n    tags: ['#brand-guidelines'],\n    previewUrl: 'https://images.unsplash.com/photo-1620641788421-7a1c342ea42e?w=1200&auto=format&fit=crop&q=80',\n    downloadOptions: [\n      { id: 'opt-1', label: 'SVG Master Vector', resolution: 'Scalable Vector', size: '180 KB', badge: 'Primary' },\n      { id: 'opt-2', label: 'Transparent PNG Kit', resolution: '2048 × 2048', size: '340 KB' },\n      { id: 'opt-3', label: 'Favicon & App Icon Bundle', resolution: 'Multi-Res .ICO', size: '95 KB' },\n    ],\n  },\n]\n\nconst aspectFilterOptions = [\n  { value: 'all', label: 'All Ratios' },\n  { value: '16:9', label: '16:9 Landscape' },\n  { value: '1:1', label: '1:1 Square' },\n  { value: '9:16', label: '9:16 Portrait' },\n  { value: 'vector', label: 'Raw Vector' },\n]\n\nconst availableTags = ['#marketing', '#product-ui', '#brand-guidelines', '#headshots']\n\nexport function MediaAssetGallery({ className }: MediaAssetGalleryProps) {\n  const [searchQuery, setSearchQuery] = useState('')\n  const [selectedCategory, setSelectedCategory] = useState('all')\n  const [selectedAspectRatio, setSelectedAspectRatio] = useState('all')\n  const [selectedTag, setSelectedTag] = useState<string | null>(null)\n\n  const [selectedAsset, setSelectedAsset] = useState<AssetItem | null>(null)\n  const [isDrawerOpen, setIsDrawerOpen] = useState(false)\n  const [selectedResolutionOption, setSelectedResolutionOption] = useState<string>('opt-1')\n\n  const [notificationToast, setNotificationToast] = useState<string | null>(null)\n  const [copiedEmbed, setCopiedEmbed] = useState(false)\n\n  const showNotification = (msg: string) => {\n    setNotificationToast(msg)\n    setTimeout(() => {\n      setNotificationToast(null)\n    }, 2800)\n  }\n\n  const copyHex = (color: string) => {\n    navigator.clipboard?.writeText(color)\n    showNotification(`Copied color hex ${color} to clipboard`)\n  }\n\n  const copyEmbedSnippet = (asset: AssetItem) => {\n    const code = `<img src=\"${asset.previewUrl}\" alt=\"${asset.title}\" loading=\"lazy\" />`\n    navigator.clipboard?.writeText(code)\n    setCopiedEmbed(true)\n    showNotification('Copied HTML embed snippet to clipboard')\n    setTimeout(() => {\n      setCopiedEmbed(false)\n    }, 2200)\n  }\n\n  const copyAssetLink = (asset: AssetItem, event?: React.MouseEvent) => {\n    if (event) event.stopPropagation()\n    navigator.clipboard?.writeText(`https://cdn.uipkge.dev/assets/${asset.filename}`)\n    showNotification(`Link copied for \"${asset.title}\"`)\n  }\n\n  const triggerInstantDownload = (asset: AssetItem, event?: React.MouseEvent) => {\n    if (event) event.stopPropagation()\n    showNotification(`Downloading ${asset.filename} (${asset.fileSize})...`)\n  }\n\n  const openInspector = (asset: AssetItem) => {\n    setSelectedAsset(asset)\n    setSelectedResolutionOption(asset.downloadOptions[0]?.id || 'opt-1')\n    setIsDrawerOpen(true)\n  }\n\n  const toggleTag = (tag: string) => {\n    setSelectedTag((prev) => (prev === tag ? null : tag))\n  }\n\n  const filteredAssets = useMemo(() => {\n    return ASSETS.filter((item) => {\n      if (selectedCategory !== 'all' && item.category !== selectedCategory) {\n        return false\n      }\n      if (selectedAspectRatio !== 'all' && item.aspectRatio !== selectedAspectRatio) {\n        return false\n      }\n      if (selectedTag && !item.tags.includes(selectedTag)) {\n        return false\n      }\n      if (searchQuery.trim() !== '') {\n        const q = searchQuery.toLowerCase().trim()\n        const titleMatch = item.title.toLowerCase().includes(q)\n        const fileMatch = item.filename.toLowerCase().includes(q)\n        const tagMatch = item.tags.some((t) => t.toLowerCase().includes(q))\n        const formatMatch = item.format.toLowerCase().includes(q)\n        if (!titleMatch && !fileMatch && !tagMatch && !formatMatch) {\n          return false\n        }\n      }\n      return true\n    })\n  }, [selectedCategory, selectedAspectRatio, selectedTag, searchQuery])\n\n  return (\n    <div data-slot=\"media-asset-gallery\" className={cn('w-full space-y-6', className)}>\n      {/* Top Floating Toast Notification */}\n      {notificationToast && (\n        <div\n          role=\"status\"\n          aria-live=\"polite\"\n          className=\"bg-foreground text-background animate-in fade-in slide-in-from-top-2 fixed top-6 right-6 z-50 flex items-center gap-2.5 rounded-lg px-4 py-2.5 text-xs font-medium shadow-lg transition-colors\"\n        >\n          <CheckCircle2 className=\"text-primary size-4 shrink-0\" />\n          <span>{notificationToast}</span>\n        </div>\n      )}\n\n      {/* Header Section */}\n      <div className=\"bg-card text-card-foreground border-border/80 flex flex-col gap-5 rounded-2xl border p-5 shadow-xs sm:flex-row sm:items-center sm:justify-between lg:p-6\">\n        <div className=\"space-y-1\">\n          <div className=\"flex flex-wrap items-center gap-2.5\">\n            <div className=\"bg-primary/10 text-primary grid size-9 place-items-center rounded-xl\">\n              <Layers className=\"size-5\" />\n            </div>\n            <h1 className=\"text-xl font-bold tracking-tight sm:text-2xl\">Digital Asset Management (DAM)</h1>\n            <Badge variant=\"secondary\" className=\"font-mono text-xs\">\n              v2.4\n            </Badge>\n          </div>\n          <p className=\"text-muted-foreground flex flex-wrap items-center gap-2 text-xs\">\n            <HardDrive className=\"size-3.5\" />\n            <span className=\"font-medium\">Total Assets:</span>\n            <span className=\"text-foreground font-semibold tabular-nums\">1,420 media files · 24.8 GB</span>\n            <span className=\"text-border hidden sm:inline\">|</span>\n            <span className=\"text-muted-foreground hidden sm:inline\">Cloud Sync Active</span>\n            <span className=\"bg-success inline-block size-1.5 rounded-full\" />\n          </p>\n        </div>\n\n        <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center\">\n          {/* Search Input */}\n          <div className=\"relative w-full sm:w-64 lg:w-72\">\n            <Search\n              aria-hidden=\"true\"\n              className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\"\n            />\n            <Input\n              value={searchQuery}\n              onChange={(e) => setSearchQuery(e.target.value)}\n              type=\"search\"\n              placeholder=\"Search assets or tags…\"\n              className=\"h-9 pr-8 pl-9 text-xs\"\n            />\n            {searchQuery && (\n              <button\n                type=\"button\"\n                className=\"text-muted-foreground hover:text-foreground absolute top-1/2 right-2.5 min-h-6 -translate-y-1/2 text-xs\"\n                aria-label=\"Clear search\"\n                onClick={() => setSearchQuery('')}\n              >\n                <X className=\"size-3.5\" />\n              </button>\n            )}\n          </div>\n\n          {/* Upload Media Button */}\n          <Button\n            size=\"sm\"\n            className=\"shrink-0 font-medium\"\n            onClick={() => showNotification('Upload dialog ready: Drop media files to ingest.')}\n          >\n            <Upload className=\"size-4\" />\n            Upload Media\n          </Button>\n        </div>\n      </div>\n\n      {/* Filter Toolbar */}\n      <div className=\"bg-card text-card-foreground border-border/80 space-y-4 rounded-2xl border p-4 shadow-xs sm:p-5\">\n        {/* Category Tabs and Aspect Ratio Filters */}\n        <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n          {/* Type Filter Tabs */}\n          <Tabs value={selectedCategory} onValueChange={setSelectedCategory} className=\"w-full lg:w-auto\">\n            <TabsList className=\"grid w-full grid-cols-2 gap-1 sm:grid-cols-5 lg:w-auto\">\n              <TabsTrigger value=\"all\" className=\"text-xs\">\n                All Assets\n              </TabsTrigger>\n              <TabsTrigger value=\"images\" className=\"text-xs\">\n                <ImageIcon className=\"mr-1.5 hidden size-3.5 sm:inline\" />\n                Images\n              </TabsTrigger>\n              <TabsTrigger value=\"vectors\" className=\"text-xs\">\n                <FileCode className=\"mr-1.5 hidden size-3.5 sm:inline\" />\n                Vectors & Icons\n              </TabsTrigger>\n              <TabsTrigger value=\"videos\" className=\"text-xs\">\n                <Video className=\"mr-1.5 hidden size-3.5 sm:inline\" />\n                Videos\n              </TabsTrigger>\n              <TabsTrigger value=\"logos\" className=\"text-xs\">\n                <Shapes className=\"mr-1.5 hidden size-3.5 sm:inline\" />\n                Brand Logos\n              </TabsTrigger>\n            </TabsList>\n          </Tabs>\n\n          {/* Aspect Ratio Filter Pills */}\n          <div className=\"flex flex-wrap items-center gap-1.5 overflow-x-auto pb-1 sm:pb-0\">\n            <span className=\"text-muted-foreground mr-1 text-xs font-medium\">Ratio:</span>\n            {aspectFilterOptions.map((opt) => (\n              <button\n                key={opt.value}\n                type=\"button\"\n                className={cn(\n                  'focus-visible:ring-ring min-h-6 rounded-lg px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                  selectedAspectRatio === opt.value\n                    ? 'bg-primary text-primary-foreground shadow-xs'\n                    : 'bg-muted/70 text-muted-foreground hover:bg-muted hover:text-foreground',\n                )}\n                onClick={() => setSelectedAspectRatio(opt.value)}\n              >\n                {opt.label}\n              </button>\n            ))}\n          </div>\n        </div>\n\n        <Separator className=\"bg-border/60\" />\n\n        {/* Tag Chips and Result Meta */}\n        <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n          <div className=\"flex flex-wrap items-center gap-2\">\n            <span className=\"text-muted-foreground flex items-center gap-1 text-xs font-medium\">\n              <Tag className=\"size-3.5\" />\n              Tags:\n            </span>\n            {availableTags.map((tag) => (\n              <button\n                key={tag}\n                type=\"button\"\n                className={cn(\n                  'focus-visible:ring-ring min-h-6 rounded-md border px-2.5 py-0.5 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                  selectedTag === tag\n                    ? 'border-primary bg-primary/10 text-primary font-semibold'\n                    : 'border-border bg-background text-muted-foreground hover:border-foreground/30 hover:text-foreground',\n                )}\n                onClick={() => toggleTag(tag)}\n              >\n                {tag}\n              </button>\n            ))}\n            {(selectedTag || selectedAspectRatio !== 'all' || searchQuery || selectedCategory !== 'all') && (\n              <button\n                type=\"button\"\n                className=\"text-muted-foreground hover:text-foreground ml-1 min-h-6 text-xs underline underline-offset-2\"\n                onClick={() => {\n                  setSelectedTag(null)\n                  setSelectedAspectRatio('all')\n                  setSearchQuery('')\n                  setSelectedCategory('all')\n                }}\n              >\n                Reset Filters\n              </button>\n            )}\n          </div>\n\n          <div className=\"text-muted-foreground text-xs tabular-nums\">\n            Showing <span className=\"text-foreground font-semibold\">{filteredAssets.length}</span> of {ASSETS.length}{' '}\n            assets\n          </div>\n        </div>\n      </div>\n\n      {/* Asset Grid (3-column, responsive) */}\n      {filteredAssets.length > 0 ? (\n        <div className=\"grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3\">\n          {filteredAssets.map((asset) => (\n            <Card\n              key={asset.id}\n              className=\"border-border/80 bg-card hover:border-border group relative flex flex-col overflow-hidden rounded-xl border p-0 shadow-xs transition-colors duration-200 hover:shadow-md\"\n              onClick={() => openInspector(asset)}\n            >\n              {/* Preview Container with Aspect Ratio Tags and Overlay Actions */}\n              <div className=\"bg-muted/40 relative aspect-video w-full cursor-pointer overflow-hidden\">\n                <img\n                  src={asset.previewUrl}\n                  alt={asset.title}\n                  loading=\"lazy\"\n                  className=\"size-full object-cover transition-transform duration-300 group-hover:scale-105\"\n                />\n\n                {/* Gradient Overlay on Hover */}\n                <div className=\"absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-black/30 opacity-0 transition-opacity duration-200 group-hover:opacity-100\" />\n\n                {/* Top Aspect Ratio & Resolution Badges */}\n                <div className=\"absolute top-2.5 left-2.5 flex flex-wrap items-center gap-1.5\">\n                  <Badge\n                    variant=\"secondary\"\n                    className=\"bg-background/90 text-foreground font-mono text-xs shadow-xs backdrop-blur-xs\"\n                  >\n                    {asset.aspectRatio}\n                  </Badge>\n                  <Badge\n                    variant=\"outline\"\n                    className=\"bg-background/90 text-foreground font-mono text-xs shadow-xs backdrop-blur-xs\"\n                  >\n                    {asset.resolutionBadge}\n                  </Badge>\n                </div>\n\n                {/* Top Right Format Pill */}\n                <div className=\"absolute top-2.5 right-2.5\">\n                  <Badge className=\"bg-primary/95 text-primary-foreground font-mono text-xs shadow-xs\">\n                    {asset.format}\n                  </Badge>\n                </div>\n\n                {/* Bottom Hover Overlay Actions */}\n                <div className=\"absolute right-2.5 bottom-2.5 left-2.5 flex items-center justify-between opacity-0 transition-opacity duration-200 group-hover:opacity-100\">\n                  <div className=\"flex items-center gap-1 text-xs font-medium text-white drop-shadow-xs\">\n                    <Eye className=\"size-3.5\" />\n                    <span>Inspect</span>\n                  </div>\n                  <div className=\"flex items-center gap-1.5\">\n                    <Button\n                      variant=\"secondary\"\n                      size=\"icon-xs\"\n                      className=\"size-7 bg-white/90 text-zinc-900 shadow-xs hover:bg-white\"\n                      title=\"Copy asset link\"\n                      aria-label=\"Copy asset link\"\n                      onClick={(e) => copyAssetLink(asset, e)}\n                    >\n                      <Copy className=\"size-3.5\" />\n                    </Button>\n                    <Button\n                      variant=\"default\"\n                      size=\"icon-xs\"\n                      className=\"size-7 shadow-xs\"\n                      title=\"Instant download\"\n                      aria-label=\"Instant download\"\n                      onClick={(e) => triggerInstantDownload(asset, e)}\n                    >\n                      <ArrowDownToLine className=\"size-3.5\" />\n                    </Button>\n                  </div>\n                </div>\n              </div>\n\n              {/* Asset Card Content */}\n              <CardContent className=\"flex flex-1 flex-col justify-between gap-3 p-4\">\n                <div className=\"space-y-1.5\">\n                  <div className=\"flex items-start justify-between gap-2\">\n                    <h2 className=\"group-hover:text-primary line-clamp-1 text-sm font-semibold tracking-tight transition-colors\">\n                      {asset.title}\n                    </h2>\n                  </div>\n                  <p className=\"text-muted-foreground truncate font-mono text-xs\">{asset.filename}</p>\n                </div>\n\n                {/* Tags */}\n                <div className=\"flex flex-wrap items-center gap-1.5\">\n                  {asset.tags.map((t) => (\n                    <span\n                      key={t}\n                      className=\"bg-muted/70 text-muted-foreground rounded-md px-2 py-0.5 text-xs font-medium\"\n                    >\n                      {t}\n                    </span>\n                  ))}\n                </div>\n\n                {/* Metadata Footer Row */}\n                <div className=\"border-border/60 flex items-center justify-between border-t pt-3 text-xs\">\n                  <span className=\"text-muted-foreground font-mono tabular-nums\">{asset.dimensions}</span>\n                  <span className=\"text-foreground font-semibold tabular-nums\">\n                    {asset.fileSize} · {asset.format}\n                  </span>\n                </div>\n              </CardContent>\n            </Card>\n          ))}\n        </div>\n      ) : (\n        /* Empty State */\n        <div className=\"bg-card text-card-foreground border-border/80 flex flex-col items-center justify-center rounded-2xl border p-12 text-center shadow-xs\">\n          <div className=\"bg-muted/70 text-muted-foreground mb-3 grid size-12 place-items-center rounded-xl\">\n            <Search className=\"size-6\" />\n          </div>\n          <h2 className=\"text-base font-semibold\">No assets found</h2>\n          <p className=\"text-muted-foreground mt-1 max-w-sm text-xs\">\n            No media assets match your active category, aspect ratio, or search query. Try clearing filters to view all\n            assets.\n          </p>\n          <Button\n            variant=\"outline\"\n            size=\"sm\"\n            className=\"mt-4\"\n            onClick={() => {\n              setSearchQuery('')\n              setSelectedCategory('all')\n              setSelectedAspectRatio('all')\n              setSelectedTag(null)\n            }}\n          >\n            Clear All Filters\n          </Button>\n        </div>\n      )}\n\n      {/* Asset Detail Inspector Drawer (Sheet) */}\n      <Sheet open={isDrawerOpen} onOpenChange={setIsDrawerOpen}>\n        <SheetContent\n          side=\"right\"\n          className=\"border-border bg-card text-card-foreground w-full space-y-6 overflow-y-auto p-6 sm:max-w-md lg:max-w-lg\"\n        >\n          {selectedAsset && (\n            <div className=\"space-y-6\">\n              {/* Drawer Header */}\n              <SheetHeader className=\"space-y-1 text-left\">\n                <div className=\"flex items-center gap-2\">\n                  <Badge className=\"bg-primary/95 text-primary-foreground font-mono text-xs\">\n                    {selectedAsset.format}\n                  </Badge>\n                  <Badge variant=\"outline\" className=\"font-mono text-xs\">\n                    {selectedAsset.aspectRatioLabel}\n                  </Badge>\n                  <Badge variant=\"secondary\" className=\"font-mono text-xs\">\n                    {selectedAsset.resolutionBadge}\n                  </Badge>\n                </div>\n                <SheetTitle className=\"text-lg font-bold tracking-tight\">{selectedAsset.title}</SheetTitle>\n                <SheetDescription className=\"text-muted-foreground truncate font-mono text-xs\">\n                  {selectedAsset.filename}\n                </SheetDescription>\n              </SheetHeader>\n\n              {/* Full Media Preview with Actions */}\n              <div className=\"border-border/80 bg-muted/40 relative overflow-hidden rounded-xl border\">\n                <img\n                  src={selectedAsset.previewUrl}\n                  alt={selectedAsset.title}\n                  className=\"aspect-video w-full object-cover\"\n                />\n                <div className=\"bg-card/90 border-border/80 absolute right-2 bottom-2 flex items-center gap-1 rounded-lg border p-1 backdrop-blur-xs\">\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon-xs\"\n                    className=\"size-6 text-xs\"\n                    title=\"Copy Direct URL\"\n                    onClick={() => copyAssetLink(selectedAsset)}\n                  >\n                    <Copy className=\"size-3\" />\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon-xs\"\n                    className=\"size-6 text-xs\"\n                    title=\"Open preview in new tab\"\n                    asChild\n                  >\n                    <a href={selectedAsset.previewUrl} target=\"_blank\" rel=\"noreferrer\">\n                      <ExternalLink className=\"size-3\" />\n                    </a>\n                  </Button>\n                </div>\n              </div>\n\n              {/* Color Palette Swatches */}\n              <div className=\"space-y-2.5\">\n                <div className=\"flex items-center justify-between text-xs\">\n                  <span className=\"text-foreground flex items-center gap-1.5 font-semibold\">\n                    <Palette className=\"text-primary size-3.5\" />\n                    Color Palette Swatches\n                  </span>\n                  <span className=\"text-muted-foreground text-xs\">Click swatch to copy HEX</span>\n                </div>\n                <div className=\"grid grid-cols-5 gap-2\">\n                  {selectedAsset.palette.map((color) => (\n                    <button\n                      key={color}\n                      type=\"button\"\n                      className=\"group/color border-border/60 hover:border-primary focus-visible:ring-ring flex flex-col items-center gap-1.5 rounded-lg border p-2 text-center transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n                      onClick={() => copyHex(color)}\n                    >\n                      <span\n                        className=\"size-7 rounded-md border border-black/10 shadow-inner transition-transform group-hover/color:scale-110\"\n                        style={{ backgroundColor: color }}\n                      />\n                      <span className=\"text-muted-foreground group-hover/color:text-foreground font-mono text-xs uppercase\">\n                        {color}\n                      </span>\n                    </button>\n                  ))}\n                </div>\n              </div>\n\n              <Separator className=\"bg-border/60\" />\n\n              {/* Metadata Breakdown Grid */}\n              <div className=\"space-y-3\">\n                <h3 className=\"text-foreground text-xs font-semibold tracking-wider uppercase\">Asset Metadata</h3>\n                <div className=\"bg-muted/40 border-border/60 grid grid-cols-2 gap-3 rounded-xl border p-3.5 text-xs\">\n                  <div>\n                    <span className=\"text-muted-foreground block text-xs\">Dimensions</span>\n                    <span className=\"text-foreground font-mono font-medium tabular-nums\">\n                      {selectedAsset.dimensions}\n                    </span>\n                  </div>\n                  <div>\n                    <span className=\"text-muted-foreground block text-xs\">File Size</span>\n                    <span className=\"text-foreground font-semibold tabular-nums\">{selectedAsset.fileSize}</span>\n                  </div>\n                  <div>\n                    <span className=\"text-muted-foreground block text-xs\">Color Space</span>\n                    <span className=\"text-foreground font-medium\">{selectedAsset.colorSpace}</span>\n                  </div>\n                  <div>\n                    <span className=\"text-muted-foreground block text-xs\">License</span>\n                    <span className=\"text-foreground font-medium\">{selectedAsset.license}</span>\n                  </div>\n                  <div>\n                    <span className=\"text-muted-foreground block text-xs\">Uploaded By</span>\n                    <div className=\"mt-0.5 flex items-center gap-1.5\">\n                      <span className=\"bg-primary/10 text-primary grid size-4.5 place-items-center rounded-full text-xs font-semibold\">\n                        {selectedAsset.uploadedBy.avatarInitials}\n                      </span>\n                      <span className=\"text-foreground font-medium\">{selectedAsset.uploadedBy.name}</span>\n                    </div>\n                  </div>\n                  <div>\n                    <span className=\"text-muted-foreground block text-xs\">Upload Date</span>\n                    <span className=\"text-foreground font-medium tabular-nums\">{selectedAsset.uploadDate}</span>\n                  </div>\n                </div>\n              </div>\n\n              {/* Resolution Download Choices */}\n              <div className=\"space-y-3\">\n                <div className=\"flex items-center justify-between\">\n                  <h3 className=\"text-foreground text-xs font-semibold tracking-wider uppercase\">\n                    Download Resolution\n                  </h3>\n                  <span className=\"text-muted-foreground font-mono text-xs\">Format: {selectedAsset.format}</span>\n                </div>\n\n                <div className=\"space-y-2\">\n                  {selectedAsset.downloadOptions.map((opt) => (\n                    <button\n                      key={opt.id}\n                      type=\"button\"\n                      className={cn(\n                        'focus-visible:ring-ring flex w-full items-center justify-between rounded-xl border p-3 text-left transition-[background-color,box-shadow] focus-visible:ring-2 focus-visible:outline-none',\n                        selectedResolutionOption === opt.id\n                          ? 'border-primary bg-primary/5 text-foreground shadow-xs'\n                          : 'border-border/70 bg-card hover:bg-muted/40 text-muted-foreground',\n                      )}\n                      onClick={() => setSelectedResolutionOption(opt.id)}\n                    >\n                      <div className=\"space-y-0.5\">\n                        <div className=\"flex items-center gap-2\">\n                          <span className=\"text-foreground text-xs font-semibold\">{opt.label}</span>\n                          {opt.badge && (\n                            <Badge variant=\"secondary\" className=\"px-1.5 py-0 text-xs font-normal\">\n                              {opt.badge}\n                            </Badge>\n                          )}\n                        </div>\n                        <span className=\"text-muted-foreground font-mono text-xs tabular-nums\">{opt.resolution}</span>\n                      </div>\n                      <div className=\"flex items-center gap-3\">\n                        <span className=\"text-foreground text-xs font-semibold tabular-nums\">{opt.size}</span>\n                        <span\n                          className={cn(\n                            'flex size-4 items-center justify-center rounded-full border',\n                            selectedResolutionOption === opt.id\n                              ? 'border-primary bg-primary text-primary-foreground'\n                              : 'border-border',\n                          )}\n                        >\n                          {selectedResolutionOption === opt.id && <Check className=\"size-2.5\" />}\n                        </span>\n                      </div>\n                    </button>\n                  ))}\n                </div>\n              </div>\n\n              {/* Embed Code Copy */}\n              <div className=\"space-y-2\">\n                <div className=\"flex items-center justify-between text-xs\">\n                  <span className=\"text-foreground flex items-center gap-1.5 font-semibold\">\n                    <Code2 className=\"text-primary size-3.5\" />\n                    HTML CDN Embed Snippet\n                  </span>\n                  <button\n                    type=\"button\"\n                    className=\"text-primary flex min-h-6 items-center gap-1 text-xs font-medium hover:underline\"\n                    onClick={() => copyEmbedSnippet(selectedAsset)}\n                  >\n                    <Copy className=\"size-3\" />\n                    <span>{copiedEmbed ? 'Copied!' : 'Copy Code'}</span>\n                  </button>\n                </div>\n                <div className=\"bg-muted/60 border-border/80 text-muted-foreground overflow-x-auto rounded-xl border p-2.5 font-mono text-xs\">\n                  &lt;img src=\"{selectedAsset.previewUrl}\" alt=\"{selectedAsset.title}\" loading=\"lazy\" /&gt;\n                </div>\n              </div>\n\n              {/* Sheet Footer Actions */}\n              <SheetFooter className=\"border-border/80 flex flex-col-reverse gap-2 border-t pt-4 sm:flex-row sm:justify-end\">\n                <SheetClose asChild>\n                  <Button variant=\"outline\" size=\"sm\" className=\"text-xs font-medium\">\n                    Close\n                  </Button>\n                </SheetClose>\n                <Button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  className=\"text-xs font-medium\"\n                  onClick={() => copyAssetLink(selectedAsset)}\n                >\n                  <Share2 className=\"size-3.5\" />\n                  Share Link\n                </Button>\n                <Button\n                  aria-label=\"Download attachment\"\n                  size=\"sm\"\n                  className=\"text-xs font-medium\"\n                  onClick={() => triggerInstantDownload(selectedAsset)}\n                >\n                  <ArrowDownToLine className=\"size-3.5\" />\n                  Download Asset\n                </Button>\n              </SheetFooter>\n            </div>\n          )}\n        </SheetContent>\n      </Sheet>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/MediaAssetGallery.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/input.json",
    "https://uipkge.dev/r/react/separator.json",
    "https://uipkge.dev/r/react/sheet.json",
    "https://uipkge.dev/r/react/tabs.json"
  ],
  "description": "Figma/Unsplash style Digital Asset Manager (DAM) with resolution tags, aspect ratio filters, tag chips, color palette inspector, multi-resolution download picker, and slide-over inspector drawer.",
  "categories": [
    "media",
    "app",
    "dashboard"
  ]
}