Update
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { GridSkeleton } from '@/components/ui/grid-skeleton';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { MediaItem } from '@/components/ui/media-item';
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -28,17 +29,17 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
|
||||
// Track the current active tab
|
||||
const [activeTab, setActiveTab] = useState('memes');
|
||||
|
||||
|
||||
// Track search queries
|
||||
const [searchQueries, setSearchQueries] = useState({
|
||||
memes: '',
|
||||
backgrounds: ''
|
||||
backgrounds: '',
|
||||
});
|
||||
|
||||
|
||||
// Track if data has been loaded for each tab (to prevent infinite loading on empty results)
|
||||
const [dataLoaded, setDataLoaded] = useState({
|
||||
memes: false,
|
||||
backgrounds: false
|
||||
backgrounds: false,
|
||||
});
|
||||
|
||||
// Fetch data when sidebar opens for the current active tab
|
||||
@@ -48,22 +49,22 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
const query = searchQueries.memes;
|
||||
if (query) {
|
||||
searchMemes(query).finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, memes: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, memes: true }));
|
||||
});
|
||||
} else {
|
||||
fetchMemes().finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, memes: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, memes: true }));
|
||||
});
|
||||
}
|
||||
} else if (activeTab === 'backgrounds' && !dataLoaded.backgrounds && !isFetchingBackgrounds) {
|
||||
const query = searchQueries.backgrounds;
|
||||
if (query) {
|
||||
searchBackgrounds(query).finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, backgrounds: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, backgrounds: true }));
|
||||
});
|
||||
} else {
|
||||
fetchBackgrounds().finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, backgrounds: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, backgrounds: true }));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -76,22 +77,22 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
const query = searchQueries.memes;
|
||||
if (query) {
|
||||
searchMemes(query).finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, memes: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, memes: true }));
|
||||
});
|
||||
} else {
|
||||
fetchMemes().finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, memes: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, memes: true }));
|
||||
});
|
||||
}
|
||||
} else if (value === 'backgrounds' && !dataLoaded.backgrounds && !isFetchingBackgrounds) {
|
||||
const query = searchQueries.backgrounds;
|
||||
if (query) {
|
||||
searchBackgrounds(query).finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, backgrounds: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, backgrounds: true }));
|
||||
});
|
||||
} else {
|
||||
fetchBackgrounds().finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, backgrounds: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, backgrounds: true }));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -99,9 +100,9 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
|
||||
// Handle search input changes
|
||||
const handleSearchChange = (value) => {
|
||||
setSearchQueries(prev => ({
|
||||
setSearchQueries((prev) => ({
|
||||
...prev,
|
||||
[activeTab]: value
|
||||
[activeTab]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -110,30 +111,30 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
const query = searchQueries[activeTab];
|
||||
if (activeTab === 'memes') {
|
||||
searchMemes(query).finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, memes: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, memes: true }));
|
||||
});
|
||||
} else if (activeTab === 'backgrounds') {
|
||||
searchBackgrounds(query).finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, backgrounds: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, backgrounds: true }));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle clearing search
|
||||
const handleClearSearch = () => {
|
||||
setSearchQueries(prev => ({
|
||||
setSearchQueries((prev) => ({
|
||||
...prev,
|
||||
[activeTab]: ''
|
||||
[activeTab]: '',
|
||||
}));
|
||||
|
||||
|
||||
// Reset data loaded state and fetch fresh data without search
|
||||
if (activeTab === 'memes') {
|
||||
fetchMemes().finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, memes: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, memes: true }));
|
||||
});
|
||||
} else if (activeTab === 'backgrounds') {
|
||||
fetchBackgrounds().finally(() => {
|
||||
setDataLoaded(prev => ({ ...prev, backgrounds: true }));
|
||||
setDataLoaded((prev) => ({ ...prev, backgrounds: true }));
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -178,7 +179,7 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
<img src={selectedMeme.gif_url} alt="Selected Meme" className="h-full w-full object-cover" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex aspect-[9/16] h-[200px] items-center justify-center rounded-lg border-2 border-dashed border-gray-300 p-2 text-center text-xs text-gray-500">
|
||||
<div className="text-muted-foreground flex aspect-[9/16] h-[200px] items-center justify-center rounded-lg border-2 border-dashed border-gray-300 p-2 text-center text-xs">
|
||||
No meme
|
||||
</div>
|
||||
)}
|
||||
@@ -197,7 +198,7 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
<img src={selectedBackground.media_url} alt="Selected Background" className="h-full w-full object-cover" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex aspect-[9/16] h-[200px] items-center justify-center rounded-lg border-2 border-dashed border-gray-300 p-2 text-center text-xs text-gray-500">
|
||||
<div className="text-muted-foreground flex aspect-[9/16] h-[200px] items-center justify-center rounded-lg border-2 border-dashed border-gray-300 p-2 text-center text-xs">
|
||||
No background
|
||||
</div>
|
||||
)}
|
||||
@@ -216,56 +217,61 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
{/* Search Bar */}
|
||||
<div className="relative flex items-center gap-2 px-2 pt-3">
|
||||
<div className="relative flex-1">
|
||||
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
|
||||
<Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
|
||||
<Input
|
||||
placeholder={`Search ${activeTab === 'memes' ? 'memes' : 'backgrounds'}...`}
|
||||
value={searchQueries[activeTab]}
|
||||
onChange={(e) => handleSearchChange(e.target.value)}
|
||||
onKeyDown={handleSearchKeyDown}
|
||||
className="pl-10 pr-10"
|
||||
className="pr-10 pl-10"
|
||||
/>
|
||||
{searchQueries[activeTab] && (
|
||||
<button
|
||||
onClick={handleClearSearch}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||
className="text-muted-foreground hover:text-foreground absolute top-1/2 right-3 -translate-y-1/2"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleSearch}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="px-3"
|
||||
>
|
||||
<Button onClick={handleSearch} variant="outline" size="sm" className="px-3">
|
||||
<Search className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<TabsContent value="backgrounds" className="">
|
||||
{isFetchingBackgrounds && <GridSkeleton itemCount={6} />}
|
||||
{!isFetchingBackgrounds && backgrounds.length === 0 && <div className="w-full text-center p-8 text-gray-500">No backgrounds found.</div>}
|
||||
{!isFetchingBackgrounds && backgrounds.length === 0 && (
|
||||
<div className="text-muted-foreground w-full p-8 text-center">
|
||||
<p className="mb-4 text-sm">No backgrounds found.</p>
|
||||
<div className="flex flex-col gap-3">
|
||||
{searchQueries.backgrounds && (
|
||||
<Button variant="secondary" onClick={handleClearSearch} className="rounded-full text-sm">
|
||||
Clear Search
|
||||
</Button>
|
||||
)}
|
||||
{import.meta.env.VITE_DISCORD_LINK && (
|
||||
<Button variant="" asChild className="rounded-full text-sm">
|
||||
<a href={import.meta.env.VITE_DISCORD_LINK} target="_blank" rel="noopener noreferrer">
|
||||
Request in Discord
|
||||
</a>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!isFetchingBackgrounds && backgrounds.length > 0 && (
|
||||
<>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="grid grid-cols-2 gap-2 p-2">
|
||||
{backgrounds.map((item, index) => (
|
||||
<Button
|
||||
<MediaItem
|
||||
key={item.ids}
|
||||
variant="ghost"
|
||||
className={`aspect-[9/16] h-auto w-full overflow-hidden rounded-lg bg-gray-100 p-0 transition-all hover:bg-gray-100 hover:ring-2 hover:ring-blue-500 ${
|
||||
selectedBackground?.ids === item.ids ? 'ring-2 ring-blue-500' : ''
|
||||
}`}
|
||||
src={item.media_url}
|
||||
alt="Background"
|
||||
onClick={() => handleBackgroundSelect(item)}
|
||||
>
|
||||
<img
|
||||
src={item.media_url}
|
||||
alt="Background"
|
||||
width={150}
|
||||
height={150}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
</Button>
|
||||
isSelected={selectedBackground?.ids === item.ids}
|
||||
className="transition-all hover:ring-2 hover:ring-blue-500"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
@@ -274,21 +280,37 @@ export default function EditSidebar({ isOpen, onClose }) {
|
||||
|
||||
<TabsContent value="memes" className="">
|
||||
{isFetchingMemes && <GridSkeleton itemCount={6} />}
|
||||
{!isFetchingMemes && memes.length === 0 && <div className="w-full text-center p-8 text-gray-500">No memes found.</div>}
|
||||
{!isFetchingMemes && memes.length === 0 && (
|
||||
<div className="text-muted-foreground w-full p-8 text-center">
|
||||
<p className="mb-4 text-sm">No memes found.</p>
|
||||
<div className="flex flex-col gap-2">
|
||||
{searchQueries.memes && (
|
||||
<Button variant="outline" onClick={handleClearSearch} className="text-sm">
|
||||
Clear Search
|
||||
</Button>
|
||||
)}
|
||||
{import.meta.env.VITE_DISCORD_LINK && (
|
||||
<Button variant="secondary" asChild className="text-sm">
|
||||
<a href={import.meta.env.VITE_DISCORD_LINK} target="_blank" rel="noopener noreferrer">
|
||||
Request in Discord
|
||||
</a>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!isFetchingMemes && memes.length > 0 && (
|
||||
<>
|
||||
<div className="grid grid-cols-2 gap-2 p-2">
|
||||
{memes.map((item, index) => (
|
||||
<Button
|
||||
<MediaItem
|
||||
key={item.ids}
|
||||
variant="ghost"
|
||||
className={`aspect-[9/16] h-auto w-full overflow-hidden rounded-lg bg-gray-100 p-0 transition-all hover:bg-gray-100 hover:ring-2 hover:ring-blue-500 ${
|
||||
selectedMeme?.ids === item.ids ? 'ring-2 ring-blue-500' : ''
|
||||
}`}
|
||||
src={item.gif_url}
|
||||
alt="Meme"
|
||||
onClick={() => handleMemeSelect(item)}
|
||||
>
|
||||
<img src={item.gif_url} alt="Meme" width={150} height={150} className="h-full w-full object-cover" />
|
||||
</Button>
|
||||
isSelected={selectedMeme?.ids === item.ids}
|
||||
className="transition-all hover:ring-2 hover:ring-blue-500"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user