IconPicker.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { useState } from 'react';
  2. import {
  3. Globe,
  4. Link,
  5. ExternalLink,
  6. Book,
  7. FileText,
  8. Home,
  9. Star,
  10. Heart,
  11. Bookmark,
  12. ShoppingCart,
  13. Music,
  14. Video,
  15. Image,
  16. Camera,
  17. Map,
  18. Compass,
  19. Coffee,
  20. Gift,
  21. Wrench,
  22. Zap,
  23. Cloud,
  24. Database,
  25. Folder,
  26. Mail,
  27. Phone,
  28. User,
  29. Users,
  30. Server,
  31. Terminal,
  32. Code,
  33. type LucideIcon,
  34. } from 'lucide-react';
  35. // Available icons for external links
  36. export const AVAILABLE_ICONS: { name: string; icon: LucideIcon }[] = [
  37. { name: 'globe', icon: Globe },
  38. { name: 'link', icon: Link },
  39. { name: 'external-link', icon: ExternalLink },
  40. { name: 'book', icon: Book },
  41. { name: 'file-text', icon: FileText },
  42. { name: 'home', icon: Home },
  43. { name: 'star', icon: Star },
  44. { name: 'heart', icon: Heart },
  45. { name: 'bookmark', icon: Bookmark },
  46. { name: 'shopping-cart', icon: ShoppingCart },
  47. { name: 'music', icon: Music },
  48. { name: 'video', icon: Video },
  49. { name: 'image', icon: Image },
  50. { name: 'camera', icon: Camera },
  51. { name: 'map', icon: Map },
  52. { name: 'compass', icon: Compass },
  53. { name: 'coffee', icon: Coffee },
  54. { name: 'gift', icon: Gift },
  55. { name: 'wrench', icon: Wrench },
  56. { name: 'zap', icon: Zap },
  57. { name: 'cloud', icon: Cloud },
  58. { name: 'database', icon: Database },
  59. { name: 'folder', icon: Folder },
  60. { name: 'mail', icon: Mail },
  61. { name: 'phone', icon: Phone },
  62. { name: 'user', icon: User },
  63. { name: 'users', icon: Users },
  64. { name: 'server', icon: Server },
  65. { name: 'terminal', icon: Terminal },
  66. { name: 'code', icon: Code },
  67. ];
  68. // Helper to get icon component by name
  69. export function getIconByName(name: string): LucideIcon {
  70. const found = AVAILABLE_ICONS.find((i) => i.name === name);
  71. return found?.icon || Link;
  72. }
  73. interface IconPickerProps {
  74. value: string;
  75. onChange: (value: string) => void;
  76. }
  77. export function IconPicker({ value, onChange }: IconPickerProps) {
  78. const [isOpen, setIsOpen] = useState(false);
  79. const SelectedIcon = getIconByName(value);
  80. return (
  81. <div className="relative">
  82. <button
  83. type="button"
  84. onClick={() => setIsOpen(!isOpen)}
  85. className="flex items-center gap-2 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white hover:border-bambu-gray focus:border-bambu-green focus:outline-none w-full"
  86. >
  87. <SelectedIcon className="w-5 h-5" />
  88. <span className="text-sm text-bambu-gray flex-1 text-left">{value}</span>
  89. </button>
  90. {isOpen && (
  91. <>
  92. {/* Backdrop */}
  93. <div
  94. className="fixed inset-0 z-40"
  95. onClick={() => setIsOpen(false)}
  96. />
  97. {/* Dropdown */}
  98. <div className="absolute z-50 mt-1 w-full max-h-64 overflow-y-auto bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-lg">
  99. <div className="grid grid-cols-5 gap-1 p-2">
  100. {AVAILABLE_ICONS.map(({ name, icon: Icon }) => (
  101. <button
  102. key={name}
  103. type="button"
  104. onClick={() => {
  105. onChange(name);
  106. setIsOpen(false);
  107. }}
  108. className={`p-2 rounded-lg transition-colors flex items-center justify-center ${
  109. value === name
  110. ? 'bg-bambu-green text-white'
  111. : 'hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white'
  112. }`}
  113. title={name}
  114. >
  115. <Icon className="w-5 h-5" />
  116. </button>
  117. ))}
  118. </div>
  119. </div>
  120. </>
  121. )}
  122. </div>
  123. );
  124. }