fix: Sticky submenu + emoji flags instead of images

1. Made Settings Submenu Sticky 
   Problem: Settings submenu wasn't sticky like Dashboard
   Solution: Added sticky positioning to SubmenuBar

   Added classes:
   - sticky top-0 z-20
   - bg-background/95 backdrop-blur
   - supports-[backdrop-filter]:bg-background/60

   Result:  Settings submenu now stays at top when scrolling

2. Switched to Emoji Flags 
   Problem: Base64 images not showing in select options
   Better Solution: Use native emoji flags

   Benefits:
   -  No image loading required
   -  Native OS rendering
   -  Smaller bundle size
   -  Better performance
   -  Always works (no broken images)

   Implementation:
   function countryCodeToEmoji(countryCode: string): string {
     const codePoints = countryCode
       .toUpperCase()
       .split('')
       .map(char => 127397 + char.charCodeAt(0));
     return String.fromCodePoint(...codePoints);
   }

   // AE → 🇦🇪
   // US → 🇺🇸
   // ID → 🇮🇩

3. Updated Currency Select 
   Before: [Image] United Arab Emirates dirham (AED)
   After:  🇦🇪 United Arab Emirates dirham (AED)

   - Emoji flag in label
   - No separate icon prop needed
   - Works immediately

4. Updated Store Summary 
   Before: [Image] Your store is located in Indonesia
   After:  🇮🇩 Your store is located in Indonesia

   - Dynamic emoji flag based on currency
   - Cleaner implementation
   - No image loading

5. Simplified SearchableSelect 
   - Removed icon prop (not needed with emoji)
   - Removed image rendering code
   - Simpler component API

Files Modified:
- SubmenuBar.tsx: Added sticky positioning
- Store.tsx: Emoji flags + helper function
- searchable-select.tsx: Removed icon support

Why Emoji > Images:
 Universal support (all modern browsers/OS)
 No loading time
 No broken images
 Smaller code
 Native rendering
 Accessibility friendly
This commit is contained in:
dwindown
2025-11-06 12:08:04 +07:00
parent 2a679ffd15
commit 39a215c188
3 changed files with 20 additions and 30 deletions

View File

@@ -22,8 +22,6 @@ export interface Option {
label: React.ReactNode;
/** Optional text used for filtering. Falls back to string label or value. */
searchText?: string;
/** Optional icon (base64 image or URL) to display before the label */
icon?: string;
}
interface Props {
@@ -67,12 +65,7 @@ export function SearchableSelect({
aria-disabled={disabled}
tabIndex={disabled ? -1 : 0}
>
<div className="flex items-center gap-2 flex-1 min-w-0">
{selected?.icon && (
<img src={selected.icon} alt="" className="w-5 h-4 object-cover rounded-sm flex-shrink-0" />
)}
<span className="truncate">{selected ? selected.label : placeholder}</span>
</div>
{selected ? selected.label : placeholder}
<ChevronsUpDown className="opacity-50 h-4 w-4 shrink-0" />
</Button>
</PopoverTrigger>
@@ -111,10 +104,7 @@ export function SearchableSelect({
)}
/>
)}
{opt.icon && (
<img src={opt.icon} alt="" className="w-5 h-4 object-cover rounded-sm mr-2 flex-shrink-0" />
)}
<span className="truncate">{opt.label}</span>
{opt.label}
</CommandItem>
))}
</CommandList>