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
50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
import React from 'react';
|
|
import { Link, useLocation } from 'react-router-dom';
|
|
import type { SubItem } from '@/nav/tree';
|
|
|
|
type Props = { items?: SubItem[] };
|
|
|
|
export default function SubmenuBar({ items = [] }: Props) {
|
|
// Always call hooks first
|
|
const { pathname } = useLocation();
|
|
|
|
// Single source of truth: props.items. No fallbacks, no demos, no path-based defaults
|
|
if (items.length === 0) return null;
|
|
|
|
return (
|
|
<div data-submenubar className="border-b border-border bg-background md:bg-background/95 md:backdrop-blur md:supports-[backdrop-filter]:bg-background/60 sticky top-0 z-20">
|
|
<div className="px-4 py-2">
|
|
<div className="flex gap-2 overflow-x-auto no-scrollbar">
|
|
{items.map((it) => {
|
|
const key = `${it.label}-${it.path || it.href}`;
|
|
// Fix: Always use exact match to prevent first submenu from being always active
|
|
const isActive = !!it.path && pathname === it.path;
|
|
const cls = [
|
|
'inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 border text-sm whitespace-nowrap',
|
|
'focus:outline-none focus:ring-0 focus:shadow-none',
|
|
isActive ? 'bg-accent text-accent-foreground' : 'hover:bg-accent hover:text-accent-foreground',
|
|
].join(' ');
|
|
|
|
if (it.mode === 'spa' && it.path) {
|
|
return (
|
|
<Link key={key} to={it.path} className={cls} data-discover>
|
|
{it.label}
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
if (it.mode === 'bridge' && it.href) {
|
|
return (
|
|
<a key={key} href={it.href} className={cls} data-discover>
|
|
{it.label}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
return null;
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |