feat: apply theme colors to all pages and modals - implement light/dark theme CSS variables across UI components
This commit is contained in:
@@ -655,35 +655,35 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
<div className="flex items-center gap-3 pointer-events-auto">
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="w-11 h-11 flex items-center justify-center bg-white rounded-full shadow-xl hover:bg-gray-50 transition-all border border-gray-100 shrink-0"
|
||||
className="w-11 h-11 flex items-center justify-center bg-[var(--surface)] rounded-full shadow-xl hover:bg-[var(--background)] transition-all border border-[var(--border)] shrink-0"
|
||||
title="Quay lại"
|
||||
>
|
||||
<ChevronLeft className="w-6 h-6 text-gray-800" />
|
||||
<ChevronLeft className="w-6 h-6 text-[var(--text-primary)]" />
|
||||
</button>
|
||||
|
||||
{/* Nút lọc Tag và Dropdown */}
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setIsFilterDropdownOpen(prev => !prev)}
|
||||
className="w-11 h-11 bg-white rounded-full shadow-xl hover:bg-gray-50 transition-all border border-gray-100 flex items-center justify-center shrink-0"
|
||||
className="w-11 h-11 bg-[var(--surface)] rounded-full shadow-xl hover:bg-[var(--background)] transition-all border border-[var(--border)] flex items-center justify-center shrink-0"
|
||||
title="Lọc theo loại"
|
||||
>
|
||||
<Filter className="w-6 h-6 text-gray-800" />
|
||||
<Filter className="w-6 h-6 text-[var(--text-primary)]" />
|
||||
</button>
|
||||
|
||||
{/* Filter Dropdown Content */}
|
||||
{isFilterDropdownOpen && (
|
||||
<div className="absolute top-full left-0 mt-3 bg-white/90 backdrop-blur-md p-3 rounded-2xl shadow-xl border border-white/20 flex flex-col gap-3 max-w-[220px] z-[1003] animate-in slide-in-from-left-2 duration-200 max-h-[400px] overflow-y-auto">
|
||||
<div className="absolute top-full left-0 mt-3 bg-[var(--surface)]/90 backdrop-blur-md p-3 rounded-2xl shadow-xl border border-[var(--surface)]/20 flex flex-col gap-3 max-w-[220px] z-[1003] animate-in slide-in-from-left-2 duration-200 max-h-[400px] overflow-y-auto">
|
||||
{/* Tour Filter Section */}
|
||||
<div>
|
||||
<div className="flex items-center gap-2 px-2 py-1 border-b border-gray-100 mb-1.5">
|
||||
<div className="flex items-center gap-2 px-2 py-1 border-b border-[var(--border)] mb-1.5">
|
||||
<Filter className="w-3.5 h-3.5 text-blue-600" />
|
||||
<span className="text-[10px] font-black uppercase text-gray-500 tracking-wider">🧳 Chuyến đi</span>
|
||||
<span className="text-[10px] font-black uppercase text-[var(--text-muted)] tracking-wider">🧳 Chuyến đi</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<button
|
||||
onClick={() => { setSelectedFilterTag(null); setIsFilterDropdownOpen(false); }}
|
||||
className={`px-2.5 py-1 rounded-lg text-[10px] font-bold transition-all ${!selectedFilterTag ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-500 hover:bg-gray-200'}`}
|
||||
className={`px-2.5 py-1 rounded-lg text-[10px] font-bold transition-all ${!selectedFilterTag ? 'bg-blue-600 text-white' : 'bg-[var(--background)] text-[var(--text-muted)] hover:bg-[var(--border)]'}`}
|
||||
>
|
||||
Tất cả
|
||||
</button>
|
||||
@@ -691,7 +691,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
<button
|
||||
key={tag}
|
||||
onClick={() => { setSelectedFilterTag(tag === selectedFilterTag ? null : tag); setIsFilterDropdownOpen(false); }}
|
||||
className={`px-2.5 py-1 rounded-lg text-[10px] font-bold transition-all ${selectedFilterTag === tag ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-500 hover:bg-gray-200'}`}
|
||||
className={`px-2.5 py-1 rounded-lg text-[10px] font-bold transition-all ${selectedFilterTag === tag ? 'bg-blue-600 text-white' : 'bg-[var(--background)] text-[var(--text-muted)] hover:bg-[var(--border)]'}`}
|
||||
>
|
||||
{tag}
|
||||
</button>
|
||||
@@ -701,15 +701,15 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
|
||||
{/* Photo Filter Section */}
|
||||
{availablePhotoTags.length > 0 && (
|
||||
<div className="border-t border-gray-200 pt-3">
|
||||
<div className="flex items-center gap-2 px-2 py-1 border-b border-gray-100 mb-1.5">
|
||||
<div className="border-t border-[var(--border)] pt-3">
|
||||
<div className="flex items-center gap-2 px-2 py-1 border-b border-[var(--border)] mb-1.5">
|
||||
<ImageIcon className="w-3.5 h-3.5 text-emerald-600" />
|
||||
<span className="text-[10px] font-black uppercase text-gray-500 tracking-wider">📸 Ảnh công khai</span>
|
||||
<span className="text-[10px] font-black uppercase text-[var(--text-muted)] tracking-wider">📸 Ảnh công khai</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
<button
|
||||
onClick={() => { setSelectedPhotoFilterTags([]); setIsFilterDropdownOpen(false); }}
|
||||
className={`px-2 py-1 rounded-lg text-[9px] font-bold transition-all ${selectedPhotoFilterTags.length === 0 ? 'bg-emerald-600 text-white' : 'bg-gray-100 text-gray-500 hover:bg-gray-200'}`}
|
||||
className={`px-2 py-1 rounded-lg text-[9px] font-bold transition-all ${selectedPhotoFilterTags.length === 0 ? 'bg-emerald-600 text-white' : 'bg-[var(--background)] text-[var(--text-muted)] hover:bg-[var(--border)]'}`}
|
||||
>
|
||||
Tất cả
|
||||
</button>
|
||||
@@ -725,7 +725,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
: [...prev, tagId]
|
||||
);
|
||||
}}
|
||||
className={`px-2 py-1 rounded-lg text-[9px] font-bold transition-all ${selectedPhotoFilterTags.includes(tagId) ? 'bg-emerald-600 text-white' : 'bg-gray-100 text-gray-500 hover:bg-gray-200'}`}
|
||||
className={`px-2 py-1 rounded-lg text-[9px] font-bold transition-all ${selectedPhotoFilterTags.includes(tagId) ? 'bg-emerald-600 text-white' : 'bg-[var(--background)] text-[var(--text-muted)] hover:bg-[var(--border)]'}`}
|
||||
title={tagLabel}
|
||||
>
|
||||
{tagLabel.length > 13 ? tagLabel.substring(0, 13) + '...' : tagLabel}
|
||||
@@ -740,37 +740,37 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
</div>
|
||||
|
||||
{/* Search Box - Thay thế div "Khám phá khu vực" */}
|
||||
<div className="relative flex items-center bg-white/90 backdrop-blur-md rounded-2xl shadow-xl border border-white/20 flex-1 max-w-xs sm:max-w-md pointer-events-auto hidden sm:flex px-4 py-3">
|
||||
<div className="relative flex items-center bg-[var(--surface)]/90 backdrop-blur-md rounded-2xl shadow-xl border border-[var(--surface)]/20 flex-1 max-w-xs sm:max-w-md pointer-events-auto hidden sm:flex px-4 py-3">
|
||||
<Navigation className="w-4 h-4 text-blue-600 mr-2 flex-shrink-0" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Tìm kiếm địa điểm, tour..."
|
||||
className="flex-1 bg-transparent outline-none text-gray-800 text-sm font-medium"
|
||||
className="flex-1 bg-transparent outline-none text-[var(--text-primary)] text-sm font-medium"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
{isSearchingSuggestions && <Loader2 className="w-4 h-4 animate-spin text-blue-500 mr-2" />}
|
||||
{searchQuery && (
|
||||
<button onClick={() => { setSearchQuery(''); setSuggestions([]); }} className="p-1 text-gray-400 hover:text-gray-600 rounded-full">
|
||||
<button onClick={() => { setSearchQuery(''); setSuggestions([]); }} className="p-1 text-[var(--text-muted)] hover:text-[var(--text-secondary)] rounded-full">
|
||||
<X className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Dropdown danh sách gợi ý */}
|
||||
{suggestions.length > 0 && (
|
||||
<div className="absolute top-full left-0 right-0 mt-3 bg-white/95 backdrop-blur-md rounded-2xl shadow-2xl border border-white/20 overflow-hidden z-[1003] animate-in slide-in-from-top-2 duration-200">
|
||||
<div className="absolute top-full left-0 right-0 mt-3 bg-[var(--surface)]/95 backdrop-blur-md rounded-2xl shadow-2xl border border-[var(--surface)]/20 overflow-hidden z-[1003] animate-in slide-in-from-top-2 duration-200">
|
||||
{suggestions.map((s, idx) => (
|
||||
<button
|
||||
key={`${s.type}-${s.id}-${idx}`}
|
||||
onClick={() => handleSelectSuggestion(s)}
|
||||
className="w-full text-left px-4 py-3 hover:bg-blue-50 flex items-center gap-3 transition-colors border-b border-gray-50 last:border-0"
|
||||
className="w-full text-left px-4 py-3 hover:bg-[var(--background)] flex items-center gap-3 transition-colors border-b border-[var(--border)] last:border-0"
|
||||
>
|
||||
<div className={`p-2 rounded-xl flex-shrink-0 ${s.type === 'tour' ? 'bg-blue-50 text-blue-600' : 'bg-green-50 text-green-600'}`}>
|
||||
{s.type === 'tour' ? <ImageIcon className="w-4 h-4" /> : <MapPin className="w-4 h-4" />}
|
||||
</div>
|
||||
<div className="flex flex-col min-w-0">
|
||||
<span className="text-sm font-bold text-gray-800 truncate">{s.name}</span>
|
||||
<span className="text-[10px] font-black uppercase text-gray-400 tracking-wider">
|
||||
<span className="text-sm font-bold text-[var(--text-primary)] truncate">{s.name}</span>
|
||||
<span className="text-[10px] font-black uppercase text-[var(--text-muted)] tracking-wider">
|
||||
{s.type === 'tour' ? 'Chuyến đi của bạn' : 'Địa điểm trên bản đồ'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -790,7 +790,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
console.log("Đang mở Ảnh của tôi...");
|
||||
onOpenMyPhotos();
|
||||
}}
|
||||
className="w-11 h-11 md:w-auto bg-white p-0 md:px-4 md:py-3 rounded-2xl shadow-xl hover:bg-blue-50 text-blue-600 transition-all flex items-center justify-center md:justify-start gap-2 font-bold border border-blue-100 shrink-0"
|
||||
className="w-11 h-11 md:w-auto bg-[var(--surface)] p-0 md:px-4 md:py-3 rounded-2xl shadow-xl hover:bg-blue-100 text-blue-600 transition-all flex items-center justify-center md:justify-start gap-2 font-bold border border-blue-100 shrink-0"
|
||||
title="Ảnh của tôi"
|
||||
>
|
||||
<ImageIcon className="w-5 h-5" />
|
||||
@@ -822,31 +822,31 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
|
||||
{/* Lựa chọn Ngôn ngữ */}
|
||||
<div className="relative group shrink-0">
|
||||
<button className="w-11 h-11 bg-white dark:bg-slate-800 p-0 rounded-2xl shadow-xl hover:bg-slate-50 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 transition-all flex items-center justify-center border border-gray-100 dark:border-slate-700">
|
||||
<button className="w-11 h-11 bg-[var(--surface)] dark:bg-slate-800 p-0 rounded-2xl shadow-xl hover:bg-[var(--background)] dark:hover:bg-slate-700 text-[var(--text-secondary)] dark:text-slate-200 transition-all flex items-center justify-center border border-[var(--border)] dark:border-slate-700">
|
||||
<Globe className="w-5 h-5" />
|
||||
</button>
|
||||
<div className="absolute right-0 top-12 mt-1 hidden group-hover:block bg-white dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl shadow-2xl p-2 z-[9999] w-32 animate-in fade-in duration-200">
|
||||
<button onClick={() => changeLanguage('vi')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold ${lang === 'vi' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700'}`}>Tiếng Việt</button>
|
||||
<button onClick={() => changeLanguage('en')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold ${lang === 'en' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700'}`}>English</button>
|
||||
<button onClick={() => changeLanguage('zh')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold ${lang === 'zh' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700'}`}>中文</button>
|
||||
<div className="absolute right-0 top-12 mt-1 hidden group-hover:block bg-[var(--surface)] dark:bg-slate-800 border border-[var(--border)] dark:border-slate-700 rounded-2xl shadow-2xl p-2 z-[9999] w-32 animate-in fade-in duration-200">
|
||||
<button onClick={() => changeLanguage('vi')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold ${lang === 'vi' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-[var(--text-secondary)] dark:text-slate-200 hover:bg-[var(--background)] dark:hover:bg-slate-700'}`}>Tiếng Việt</button>
|
||||
<button onClick={() => changeLanguage('en')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold ${lang === 'en' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-[var(--text-secondary)] dark:text-slate-200 hover:bg-[var(--background)] dark:hover:bg-slate-700'}`}>English</button>
|
||||
<button onClick={() => changeLanguage('zh')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold ${lang === 'zh' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-[var(--text-secondary)] dark:text-slate-200 hover:bg-[var(--background)] dark:hover:bg-slate-700'}`}>中文</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lựa chọn Giao diện */}
|
||||
<div className="relative group shrink-0">
|
||||
<button className="w-11 h-11 bg-white dark:bg-slate-800 p-0 rounded-2xl shadow-xl hover:bg-slate-50 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 transition-all flex items-center justify-center border border-gray-100 dark:border-slate-700">
|
||||
<button className="w-11 h-11 bg-[var(--surface)] dark:bg-slate-800 p-0 rounded-2xl shadow-xl hover:bg-[var(--background)] dark:hover:bg-slate-700 text-[var(--text-secondary)] dark:text-slate-200 transition-all flex items-center justify-center border border-[var(--border)] dark:border-slate-700">
|
||||
{theme === 'light' && <Sun className="w-5 h-5 text-amber-500" />}
|
||||
{theme === 'dark' && <Moon className="w-5 h-5 text-indigo-400" />}
|
||||
{theme === 'system' && <Laptop className="w-5 h-5 animate-pulse" />}
|
||||
</button>
|
||||
<div className="absolute right-0 top-12 mt-1 hidden group-hover:block bg-white dark:bg-slate-800 border border-gray-100 dark:border-slate-700 rounded-2xl shadow-2xl p-2 z-[9999] w-32 animate-in fade-in duration-200">
|
||||
<button onClick={() => changeTheme('light')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold flex items-center gap-2 ${theme === 'light' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700'}`}>
|
||||
<div className="absolute right-0 top-12 mt-1 hidden group-hover:block bg-[var(--surface)] dark:bg-slate-800 border border-[var(--border)] dark:border-slate-700 rounded-2xl shadow-2xl p-2 z-[9999] w-32 animate-in fade-in duration-200">
|
||||
<button onClick={() => changeTheme('light')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold flex items-center gap-2 ${theme === 'light' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-[var(--text-secondary)] dark:text-slate-200 hover:bg-[var(--background)] dark:hover:bg-slate-700'}`}>
|
||||
<Sun className="w-3.5 h-3.5 text-amber-500" /> {t('themeLight')}
|
||||
</button>
|
||||
<button onClick={() => changeTheme('dark')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold flex items-center gap-2 ${theme === 'dark' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700'}`}>
|
||||
<button onClick={() => changeTheme('dark')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold flex items-center gap-2 ${theme === 'dark' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-[var(--text-secondary)] dark:text-slate-200 hover:bg-[var(--background)] dark:hover:bg-slate-700'}`}>
|
||||
<Moon className="w-3.5 h-3.5 text-indigo-400" /> {t('themeDark')}
|
||||
</button>
|
||||
<button onClick={() => changeTheme('system')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold flex items-center gap-2 ${theme === 'system' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700'}`}>
|
||||
<button onClick={() => changeTheme('system')} className={`w-full text-left px-3 py-2 rounded-xl text-xs font-bold flex items-center gap-2 ${theme === 'system' ? 'bg-blue-50 text-blue-600 dark:bg-blue-950 dark:text-blue-400' : 'text-[var(--text-secondary)] dark:text-slate-200 hover:bg-[var(--background)] dark:hover:bg-slate-700'}`}>
|
||||
<Laptop className="w-3.5 h-3.5" /> {t('themeSystem')}
|
||||
</button>
|
||||
</div>
|
||||
@@ -880,7 +880,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
{onLogout && (
|
||||
<button
|
||||
onClick={onLogout}
|
||||
className="w-11 h-11 md:w-auto bg-white p-0 md:px-4 md:py-3 rounded-2xl shadow-xl hover:bg-red-50 hover:text-red-600 transition-all flex items-center justify-center md:justify-start gap-2 font-bold text-gray-700 border border-gray-100 shrink-0"
|
||||
className="w-11 h-11 md:w-auto bg-[var(--surface)] p-0 md:px-4 md:py-3 rounded-2xl shadow-xl hover:bg-red-50 hover:text-red-600 transition-all flex items-center justify-center md:justify-start gap-2 font-bold text-[var(--text-secondary)] border border-[var(--border)] shrink-0"
|
||||
title="Đăng xuất"
|
||||
>
|
||||
<LogOut className="w-5 h-5" />
|
||||
@@ -996,7 +996,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
className: 'custom-bubble',
|
||||
html: `
|
||||
<div class="relative group w-14 h-14">
|
||||
<div class="w-14 h-14 rounded-full border-4 ${status.borderClass} shadow-lg overflow-hidden transition-transform group-hover:scale-110 flex items-center justify-center bg-gray-100">
|
||||
<div class="w-14 h-14 rounded-full border-4 ${status.borderClass} shadow-lg overflow-hidden transition-transform group-hover:scale-110 flex items-center justify-center bg-[var(--background)]">
|
||||
<img src="${tourImage}" class="w-full h-full object-cover" onerror="this.src='https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?w=100'"/>
|
||||
</div>
|
||||
<div class="absolute -bottom-1 -right-1 bg-blue-600 rounded-full w-5 h-5 border-2 border-white flex items-center justify-center text-[10px] font-black text-white">
|
||||
@@ -1019,16 +1019,16 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
</div>
|
||||
)}
|
||||
{tour.description && (
|
||||
<div className="text-[10px] text-gray-500 line-clamp-2 leading-tight italic mb-1.5">
|
||||
<div className="text-[10px] text-[var(--text-muted)] line-clamp-2 leading-tight italic mb-1.5">
|
||||
{tour.description}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-1.5 pt-1 border-t border-gray-100">
|
||||
<div className="flex items-center gap-1.5 pt-1 border-t border-[var(--border)]">
|
||||
<span className={`w-2 h-2 rounded-full ${
|
||||
status.color === 'green' ? 'bg-emerald-500' :
|
||||
status.color === 'red' ? 'bg-rose-500' : 'bg-gray-400'
|
||||
status.color === 'red' ? 'bg-rose-500' : 'bg-[var(--text-muted)]'
|
||||
}`} />
|
||||
<span className="text-[9px] font-bold text-gray-600">{status.label}</span>
|
||||
<span className="text-[9px] font-bold text-[var(--text-secondary)]">{status.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -1146,13 +1146,13 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
{item.type === 'RESTAURANT' ? t('businessRestaurant') : item.type === 'HOTEL' ? t('businessHotel') : t('businessHomestay')}
|
||||
</div>
|
||||
{item.address && (
|
||||
<div className="text-[10px] text-gray-500 mb-1 font-semibold">{item.address}</div>
|
||||
<div className="text-[10px] text-[var(--text-muted)] mb-1 font-semibold">{item.address}</div>
|
||||
)}
|
||||
{item.phone && (
|
||||
<div className="text-[9px] text-gray-400">SĐT: {item.phone}</div>
|
||||
<div className="text-[9px] text-[var(--text-muted)]">SĐT: {item.phone}</div>
|
||||
)}
|
||||
{item.email && (
|
||||
<div className="text-[9px] text-gray-400">Email: {item.email}</div>
|
||||
<div className="text-[9px] text-[var(--text-muted)]">Email: {item.email}</div>
|
||||
)}
|
||||
<div className="text-[10px] text-slate-600 font-medium italic mt-1 pt-1 border-t border-emerald-100 whitespace-pre-line">
|
||||
{item.description}
|
||||
@@ -1167,7 +1167,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
{/* Context Menu Chia sẻ */}
|
||||
{shareMenu && (
|
||||
<div
|
||||
className="absolute z-[2000] bg-white rounded-2xl shadow-2xl border border-gray-100 py-2 w-48 animate-in zoom-in-95 duration-200"
|
||||
className="absolute z-[2000] bg-[var(--surface)] rounded-2xl shadow-2xl border border-[var(--border)] py-2 w-48 animate-in zoom-in-95 duration-200"
|
||||
style={{ top: shareMenu.y, left: shareMenu.x }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
@@ -1175,19 +1175,19 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
shareMenu.canShare ? (
|
||||
<button
|
||||
onClick={() => handleShare(shareMenu.id, shareMenu.title)}
|
||||
className="w-full text-left px-4 py-2 hover:bg-blue-50 text-sm font-bold text-gray-700 flex items-center gap-2 transition-colors"
|
||||
className="w-full text-left px-4 py-2 hover:bg-blue-50 text-sm font-bold text-blue-700 flex items-center gap-2 transition-colors"
|
||||
>
|
||||
<Share2 className="w-4 h-4 text-blue-600" /> Sao chép liên kết
|
||||
</button>
|
||||
) : (
|
||||
<div className="px-4 py-2 text-xs text-gray-400 italic font-bold">Bạn đã gia nhập tour này</div>
|
||||
<div className="px-4 py-2 text-xs text-[var(--text-muted)] italic font-bold">Bạn đã gia nhập tour này</div>
|
||||
)
|
||||
) : shareMenu.hasPendingRequest ? (
|
||||
<button
|
||||
disabled
|
||||
className="w-full text-left px-4 py-2 text-sm font-bold text-gray-400 flex items-center gap-2 cursor-not-allowed bg-gray-50/50"
|
||||
className="w-full text-left px-4 py-2 text-sm font-bold text-[var(--text-muted)] flex items-center gap-2 cursor-not-allowed bg-[var(--background)]/50"
|
||||
>
|
||||
<Clock className="w-4 h-4 text-gray-400" /> Đang chờ duyệt...
|
||||
<Clock className="w-4 h-4 text-[var(--text-muted)]" /> Đang chờ duyệt...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
@@ -1268,33 +1268,33 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
<div className="absolute bottom-6 left-6 z-[1002] pointer-events-auto flex flex-col items-start gap-2">
|
||||
<button
|
||||
onClick={() => setIsLeaderboardOpen(prev => !prev)}
|
||||
className="bg-white dark:bg-slate-900 border border-gray-150 dark:border-slate-800 text-slate-800 dark:text-slate-100 shadow-2xl rounded-2xl py-2.5 px-4 text-xs font-bold flex items-center gap-2 hover:bg-gray-50 dark:hover:bg-slate-850 transition-all cursor-pointer active:scale-95"
|
||||
className="bg-[var(--surface)] dark:bg-slate-900 border border-[var(--border)] dark:border-slate-800 text-[var(--text-primary)] dark:text-slate-100 shadow-2xl rounded-2xl py-2.5 px-4 text-xs font-bold flex items-center gap-2 hover:bg-[var(--background)] dark:hover:bg-slate-850 transition-all cursor-pointer active:scale-95"
|
||||
>
|
||||
<Users className="w-4 h-4 text-amber-500" />
|
||||
<span>{t('trustedMembers')} ({trustedUsers.length})</span>
|
||||
</button>
|
||||
|
||||
{isLeaderboardOpen && (
|
||||
<div className="bg-white/95 dark:bg-slate-900/95 backdrop-blur-md border border-gray-100 dark:border-slate-800 rounded-3xl shadow-2xl p-4 w-72 max-h-[350px] overflow-y-auto no-scrollbar animate-in slide-in-from-bottom-2 duration-300">
|
||||
<div className="bg-[var(--surface)]/95 dark:bg-slate-900/95 backdrop-blur-md border border-[var(--border)] dark:border-slate-800 rounded-3xl shadow-2xl p-4 w-72 max-h-[350px] overflow-y-auto no-scrollbar animate-in slide-in-from-bottom-2 duration-300">
|
||||
<h4 className="text-xs font-black uppercase text-amber-600 dark:text-amber-500 tracking-widest mb-3 flex items-center gap-2">
|
||||
🏆 {t('trustedMembers')}
|
||||
</h4>
|
||||
{trustedUsers.length === 0 ? (
|
||||
<p className="text-xs text-gray-400 italic">Chưa có thành viên nào được đánh giá.</p>
|
||||
<p className="text-xs text-[var(--text-muted)] italic">Chưa có thành viên nào được đánh giá.</p>
|
||||
) : (
|
||||
<div className="space-y-2.5">
|
||||
{trustedUsers.map((u, idx) => (
|
||||
<div key={u.id} className="flex items-center justify-between gap-3 p-2 bg-gray-50/50 dark:bg-slate-850/50 rounded-xl border border-gray-100/50 dark:border-slate-800/50">
|
||||
<div key={u.id} className="flex items-center justify-between gap-3 p-2 bg-[var(--background)]/50 dark:bg-slate-850/50 rounded-xl border border-[var(--border)]/50 dark:border-slate-800/50">
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<div className="w-5 h-5 font-bold text-[10px] text-gray-500 flex items-center justify-center bg-gray-100 dark:bg-slate-800 rounded-lg">
|
||||
<div className="w-5 h-5 font-bold text-[10px] text-[var(--text-muted)] flex items-center justify-center bg-[var(--background)] dark:bg-slate-800 rounded-lg">
|
||||
{idx + 1}
|
||||
</div>
|
||||
<span className="text-xs font-bold text-gray-800 dark:text-slate-200 truncate">{u.name}</span>
|
||||
<span className="text-xs font-bold text-[var(--text-primary)] dark:text-slate-200 truncate">{u.name}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 text-[11px] font-bold text-amber-500 shrink-0">
|
||||
<span>★</span>
|
||||
<span>{u.averageScore}</span>
|
||||
<span className="text-[9px] text-gray-400 font-medium">({u.ratingCount})</span>
|
||||
<span className="text-[9px] text-[var(--text-muted)] font-medium">({u.ratingCount})</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -1312,7 +1312,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
setIsRecommendedOpen(prev => !prev);
|
||||
setIsBlacklistOpen(false);
|
||||
}}
|
||||
className="bg-white dark:bg-slate-900 border border-gray-150 dark:border-slate-800 text-slate-800 dark:text-slate-100 shadow-2xl rounded-2xl py-2.5 px-4 text-xs font-bold flex items-center gap-2 hover:bg-gray-50 dark:hover:bg-slate-850 transition-all cursor-pointer active:scale-95 border-emerald-500/20"
|
||||
className="bg-[var(--surface)] dark:bg-slate-900 border border-[var(--border)] dark:border-slate-800 text-[var(--text-primary)] dark:text-slate-100 shadow-2xl rounded-2xl py-2.5 px-4 text-xs font-bold flex items-center gap-2 hover:bg-[var(--background)] dark:hover:bg-slate-850 transition-all cursor-pointer active:scale-95 border-emerald-500/20"
|
||||
>
|
||||
<Star className="w-4 h-4 text-emerald-500 fill-emerald-500 animate-pulse" />
|
||||
<span>{t('recommendedTitle') || 'Đề xuất dịch vụ'} ({recommendedLocations.length})</span>
|
||||
@@ -1324,7 +1324,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
setIsBlacklistOpen(prev => !prev);
|
||||
setIsRecommendedOpen(false);
|
||||
}}
|
||||
className="bg-white dark:bg-slate-900 border border-gray-150 dark:border-slate-800 text-slate-800 dark:text-slate-100 shadow-2xl rounded-2xl py-2.5 px-4 text-xs font-bold flex items-center gap-2 hover:bg-gray-50 dark:hover:bg-slate-850 transition-all cursor-pointer active:scale-95 border-red-500/20"
|
||||
className="bg-[var(--surface)] dark:bg-slate-900 border border-[var(--border)] dark:border-slate-800 text-[var(--text-primary)] dark:text-slate-100 shadow-2xl rounded-2xl py-2.5 px-4 text-xs font-bold flex items-center gap-2 hover:bg-[var(--background)] dark:hover:bg-slate-850 transition-all cursor-pointer active:scale-95 border-red-500/20"
|
||||
>
|
||||
<ShieldAlert className="w-4 h-4 text-red-500 animate-pulse" />
|
||||
<span>{t('blacklistTitle') || 'Danh sách đen'} ({blacklist.length})</span>
|
||||
@@ -1332,8 +1332,8 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
|
||||
{/* Recommendations Panel */}
|
||||
{isRecommendedOpen && (
|
||||
<div className="bg-white/95 dark:bg-slate-900/95 backdrop-blur-md border border-gray-100 dark:border-slate-800 rounded-3xl shadow-2xl p-4 w-72 max-h-[350px] overflow-y-auto no-scrollbar animate-in slide-in-from-bottom-2 duration-300">
|
||||
<h4 className="text-xs font-black uppercase text-emerald-600 dark:text-emerald-500 tracking-widest mb-3 flex items-center gap-2 border-b border-gray-100 dark:border-slate-800 pb-2">
|
||||
<div className="bg-[var(--surface)]/95 dark:bg-slate-900/95 backdrop-blur-md border border-[var(--border)] dark:border-slate-800 rounded-3xl shadow-2xl p-4 w-72 max-h-[350px] overflow-y-auto no-scrollbar animate-in slide-in-from-bottom-2 duration-300">
|
||||
<h4 className="text-xs font-black uppercase text-emerald-600 dark:text-emerald-500 tracking-widest mb-3 flex items-center gap-2 border-b border-[var(--border)] dark:border-slate-800 pb-2">
|
||||
🌟 {t('recommendedTitle') || 'Đề xuất chất lượng'}
|
||||
</h4>
|
||||
|
||||
@@ -1363,7 +1363,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
</div>
|
||||
|
||||
{processedRecommendations.length === 0 ? (
|
||||
<p className="text-xs text-gray-400 italic text-center py-4">Chưa có địa điểm đề xuất nào.</p>
|
||||
<p className="text-xs text-[var(--text-muted)] italic text-center py-4">Chưa có địa điểm đề xuất nào.</p>
|
||||
) : (
|
||||
<div className="space-y-2.5">
|
||||
{processedRecommendations.map((item) => {
|
||||
@@ -1411,7 +1411,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="text-[10px] text-slate-600 dark:text-slate-400 font-medium italic mt-1.5 pt-1.5 border-t border-gray-100 dark:border-slate-800 whitespace-pre-line">
|
||||
<div className="text-[10px] text-[var(--text-secondary)] dark:text-slate-400 font-medium italic mt-1.5 pt-1.5 border-t border-[var(--border)] dark:border-slate-800 whitespace-pre-line">
|
||||
{item.description}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1424,8 +1424,8 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
|
||||
{/* Blacklist Panel */}
|
||||
{isBlacklistOpen && (
|
||||
<div className="bg-white/95 dark:bg-slate-900/95 backdrop-blur-md border border-gray-100 dark:border-slate-800 rounded-3xl shadow-2xl p-4 w-72 max-h-[350px] overflow-y-auto no-scrollbar animate-in slide-in-from-bottom-2 duration-300">
|
||||
<h4 className="text-xs font-black uppercase text-red-600 dark:text-red-500 tracking-widest mb-3 flex items-center gap-2 border-b border-gray-100 dark:border-slate-800 pb-2">
|
||||
<div className="bg-[var(--surface)]/95 dark:bg-slate-900/95 backdrop-blur-md border border-[var(--border)] dark:border-slate-800 rounded-3xl shadow-2xl p-4 w-72 max-h-[350px] overflow-y-auto no-scrollbar animate-in slide-in-from-bottom-2 duration-300">
|
||||
<h4 className="text-xs font-black uppercase text-red-600 dark:text-red-500 tracking-widest mb-3 flex items-center gap-2 border-b border-[var(--border)] dark:border-slate-800 pb-2">
|
||||
⚠️ {t('blacklistTitle')}
|
||||
</h4>
|
||||
|
||||
@@ -1448,7 +1448,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
</div>
|
||||
|
||||
{processedBlacklist.length === 0 ? (
|
||||
<p className="text-xs text-gray-400 italic text-center py-4">{t('emptyBlacklist')}</p>
|
||||
<p className="text-xs text-[var(--text-muted)] italic text-center py-4">{t('emptyBlacklist')}</p>
|
||||
) : (
|
||||
<div className="space-y-2.5">
|
||||
{processedBlacklist.map((item) => {
|
||||
@@ -1488,7 +1488,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onOpenMyPhotos,
|
||||
📍 Định vị trên bản đồ
|
||||
</button>
|
||||
)}
|
||||
<div className="text-[10px] text-red-600 dark:text-red-400 font-medium italic mt-1.5 pt-1.5 border-t border-gray-100 dark:border-slate-850">
|
||||
<div className="text-[10px] text-red-600 dark:text-red-400 font-medium italic mt-1.5 pt-1.5 border-t border-[var(--border)] dark:border-slate-850">
|
||||
Lý do: {item.reason}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user