Skip to content

Commit 84ceaa4

Browse files
committed
sorting
1 parent fb5dc39 commit 84ceaa4

File tree

4 files changed

+394
-77
lines changed

4 files changed

+394
-77
lines changed

components/GithubProjectsPage.tsx

Lines changed: 126 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ import {
2424
TooltipProvider,
2525
TooltipTrigger,
2626
} from "@/components/ui/tooltip";
27+
import {
28+
Select,
29+
SelectContent,
30+
SelectItem,
31+
SelectTrigger,
32+
SelectValue,
33+
} from "@/components/ui/select"
34+
35+
36+
37+
2738

2839
const DiscordIcon = ({ className = "" }) => (
2940
<svg
@@ -81,7 +92,7 @@ const languageColors: { [key: string]: string } = {
8192

8293
const LanguageBar = ({ languages }: { languages: Language }) => {
8394
const totalBytes = Object.values(languages).reduce((sum, value) => sum + value, 0);
84-
95+
8596
const percentages = Object.entries(languages).map(([name, bytes]) => ({
8697
name,
8798
percentage: (bytes / totalBytes) * 100
@@ -90,7 +101,7 @@ const LanguageBar = ({ languages }: { languages: Language }) => {
90101
return (
91102
<div className="space-y-4">
92103
<h2 className="text-lg font-semibold text-white">Languages</h2>
93-
104+
94105
<TooltipProvider>
95106
<div className="h-2 w-full flex rounded-full overflow-hidden">
96107
{percentages.map(({ name, percentage }) => (
@@ -104,12 +115,12 @@ const LanguageBar = ({ languages }: { languages: Language }) => {
104115
className="transition-opacity hover:opacity-80"
105116
/>
106117
</TooltipTrigger>
107-
<TooltipContent
118+
<TooltipContent
108119
className="bg-slate-800 border-slate-700 text-white"
109120
side="top"
110121
>
111122
<div className="flex items-center gap-2">
112-
<div
123+
<div
113124
className="w-3 h-3 rounded-full"
114125
style={{ backgroundColor: languageColors[name] || '#ededed' }}
115126
/>
@@ -120,10 +131,10 @@ const LanguageBar = ({ languages }: { languages: Language }) => {
120131
))}
121132
</div>
122133
</TooltipProvider>
123-
134+
124135
<div className="flex flex-wrap gap-4">
125136
{percentages
126-
.filter(({ percentage }) => percentage >= 2)
137+
.filter(({ percentage }) => percentage >= 2)
127138
.map(({ name, percentage }) => (
128139
<div key={name} className="flex items-center gap-2">
129140
<span
@@ -172,6 +183,9 @@ export default function GithubProjectsPage() {
172183
description: '',
173184
reason: ''
174185
});
186+
const [sortBy, setSortBy] = useState<SortOption>('none');
187+
188+
175189
const projectsPerPage = 9;
176190

177191
useEffect(() => {
@@ -189,14 +203,36 @@ export default function GithubProjectsPage() {
189203
};
190204
fetchProjects();
191205
}, []);
206+
type SortOption = 'none' | 'stars' | 'forks';
207+
208+
const sortProjects = (projects: Project[], sortBy: SortOption) => {
209+
if (sortBy === 'none') return projects;
210+
211+
return [...projects].sort((a, b) => {
192212

193-
const filteredProjects = projects.filter((project) =>
194-
project.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
195-
project.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
196-
project.tags.some((tag) => tag.toLowerCase().includes(searchTerm.toLowerCase())) ||
197-
Object.keys(project.languages).some((lang) =>
198-
lang.toLowerCase().includes(searchTerm.toLowerCase())
199-
)
213+
const aValue = parseFloat(a[sortBy].toLowerCase().replace(/[,k]/g, '')) *
214+
(a[sortBy].toLowerCase().includes('k') ? 1000 : 1);
215+
const bValue = parseFloat(b[sortBy].toLowerCase().replace(/[,k]/g, '')) *
216+
(b[sortBy].toLowerCase().includes('k') ? 1000 : 1);
217+
218+
219+
if (isNaN(aValue)) return 1;
220+
if (isNaN(bValue)) return -1;
221+
if (isNaN(aValue) && isNaN(bValue)) return 0;
222+
223+
return bValue - aValue;
224+
});
225+
};
226+
const filteredProjects = sortProjects(
227+
projects.filter((project) =>
228+
project.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
229+
project.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
230+
project.tags.some((tag) => tag.toLowerCase().includes(searchTerm.toLowerCase())) ||
231+
Object.keys(project.languages).some((lang) =>
232+
lang.toLowerCase().includes(searchTerm.toLowerCase())
233+
)
234+
),
235+
sortBy
200236
);
201237

202238
const indexOfLastProject = currentPage * projectsPerPage;
@@ -293,73 +329,85 @@ export default function GithubProjectsPage() {
293329
onChange={(e) => setSearchTerm(e.target.value)}
294330
/>
295331
</div>
332+
<div className="flex justify-end max-w-6xl mx-auto mb-8">
333+
<Select value={sortBy} onValueChange={(value: SortOption) => setSortBy(value)}>
334+
<SelectTrigger className="w-[180px] bg-slate-800/50 border-slate-700 text-white">
335+
<SelectValue placeholder="Sort by..." />
336+
</SelectTrigger>
337+
<SelectContent className="bg-slate-800 border-slate-700">
338+
<SelectItem value="none" className="text-white hover:bg-slate-700">No sorting</SelectItem>
339+
<SelectItem value="stars" className="text-white hover:bg-slate-700">Most Stars</SelectItem>
340+
<SelectItem value="forks" className="text-white hover:bg-slate-700">Most Forks</SelectItem>
341+
</SelectContent>
342+
</Select>
343+
</div>
296344
</div>
297345

298346
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-8">
299-
{currentProjects.map((project) => {
300-
const isSaved = savedProjects.includes(project.name);
301-
return (
302-
<div
303-
key={project.name}
304-
className="group relative cursor-pointer"
305-
onClick={() => handleCardClick(project.url)}
306-
>
307-
<div className={`absolute inset-0 ${project.color} rounded-xl blur-md opacity-20 group-hover:opacity-30 transition-all duration-500`}></div>
308-
<Card className="relative h-full bg-slate-800/50 border-slate-700 hover:border-slate-600 transition-all duration-500 backdrop-blur-sm transform-gpu hover:-translate-y-2 hover:scale-105">
309-
<CardContent className="p-6">
310-
<div className="flex justify-between items-start mb-4">
311-
<h2 className="text-2xl font-bold text-white group-hover:text-transparent group-hover:bg-gradient-to-r group-hover:from-blue-400 group-hover:via-purple-400 group-hover:to-pink-400 group-hover:bg-clip-text transition-all duration-300">
312-
{project.name}
313-
</h2>
314-
<Button
315-
variant="ghost"
316-
size="sm"
317-
className={`text-gray-400 ${isSaved ? 'text-green-500' : 'hover:text-white'}`}
318-
onClick={(e) => {
319-
e.stopPropagation();
320-
if (isSaved) {
321-
removeProject(project.name);
322-
} else {
323-
addProject(project.name);
324-
}
325-
}}
326-
>
327-
{isSaved ? 'Unsave' : 'Save'}
328-
</Button>
329-
</div>
330-
<p className="text-gray-300 mb-6">{project.description}</p>
331-
<div className="flex flex-wrap gap-2 mb-6">
332-
{project.tags.map((tag, tagIndex) => (
347+
{currentProjects.map((project) => {
348+
const isSaved = savedProjects.includes(project.name);
349+
return (
333350
<div
334-
key={tagIndex}
335-
onClick={(e) => {
336-
e.stopPropagation();
337-
setSearchTerm(tag);
338-
}}
339-
className="bg-slate-700/50 text-gray-300 text-sm px-3 py-1 rounded-full flex items-center transform transition-all duration-300 hover:scale-105 hover:bg-slate-600/50"
351+
key={project.name}
352+
className="group relative cursor-pointer"
353+
onClick={() => handleCardClick(project.url)}
340354
>
341-
<Tag className="h-3 w-3 mr-1.5" />
342-
{tag}
355+
<div className={`absolute inset-0 ${project.color} rounded-xl blur-md opacity-20 group-hover:opacity-30 transition-all duration-500`}></div>
356+
<Card className="relative h-full bg-slate-800/50 border-slate-700 hover:border-slate-600 transition-all duration-500 backdrop-blur-sm transform-gpu hover:-translate-y-2 hover:scale-105">
357+
<CardContent className="p-6">
358+
<div className="flex justify-between items-start mb-4">
359+
<h2 className="text-2xl font-bold text-white group-hover:text-transparent group-hover:bg-gradient-to-r group-hover:from-blue-400 group-hover:via-purple-400 group-hover:to-pink-400 group-hover:bg-clip-text transition-all duration-300">
360+
{project.name}
361+
</h2>
362+
<Button
363+
variant="ghost"
364+
size="sm"
365+
className={`text-gray-400 ${isSaved ? 'text-green-500' : 'hover:text-white'}`}
366+
onClick={(e) => {
367+
e.stopPropagation();
368+
if (isSaved) {
369+
removeProject(project.name);
370+
} else {
371+
addProject(project.name);
372+
}
373+
}}
374+
>
375+
{isSaved ? 'Unsave' : 'Save'}
376+
</Button>
377+
</div>
378+
<p className="text-gray-300 mb-6">{project.description}</p>
379+
<div className="flex flex-wrap gap-2 mb-6">
380+
{project.tags.map((tag, tagIndex) => (
381+
<div
382+
key={tagIndex}
383+
onClick={(e) => {
384+
e.stopPropagation();
385+
setSearchTerm(tag);
386+
}}
387+
className="bg-slate-700/50 text-gray-300 text-sm px-3 py-1 rounded-full flex items-center transform transition-all duration-300 hover:scale-105 hover:bg-slate-600/50"
388+
>
389+
<Tag className="h-3 w-3 mr-1.5" />
390+
{tag}
391+
</div>
392+
))}
393+
</div>
394+
<LanguageBar languages={project.languages} />
395+
<div className="flex justify-start gap-6 text-sm text-gray-400 mt-6">
396+
<span className="flex items-center">
397+
<Star className="h-4 w-4 mr-1.5 text-yellow-500" />
398+
{project.stars}
399+
</span>
400+
<span className="flex items-center">
401+
<GitFork className="h-4 w-4 mr-1.5" />
402+
{project.forks}
403+
</span>
404+
</div>
405+
</CardContent>
406+
</Card>
343407
</div>
344-
))}
345-
</div>
346-
<LanguageBar languages={project.languages} />
347-
<div className="flex justify-start gap-6 text-sm text-gray-400 mt-6">
348-
<span className="flex items-center">
349-
<Star className="h-4 w-4 mr-1.5 text-yellow-500" />
350-
{project.stars}
351-
</span>
352-
<span className="flex items-center">
353-
<GitFork className="h-4 w-4 mr-1.5" />
354-
{project.forks}
355-
</span>
356-
</div>
357-
</CardContent>
358-
</Card>
359-
</div>
360-
);
361-
})}
362-
</div>
408+
);
409+
})}
410+
</div>
363411

364412
<div className="flex justify-center gap-4 mb-16">
365413
<Button
@@ -427,8 +475,8 @@ export default function GithubProjectsPage() {
427475

428476
{submissionStatus.status && (
429477
<Alert className={`${submissionStatus.status === 'success' ? 'bg-green-500/20 border-green-500' :
430-
submissionStatus.status === 'error' ? 'bg-red-500/20 border-red-500' :
431-
'bg-blue-500/20 border-blue-500'
478+
submissionStatus.status === 'error' ? 'bg-red-500/20 border-red-500' :
479+
'bg-blue-500/20 border-blue-500'
432480
} text-white border`}>
433481
<AlertCircle className="h-4 w-4" />
434482
<AlertTitle>
@@ -556,4 +604,5 @@ export default function GithubProjectsPage() {
556604
</AlertDialogContent>
557605
</AlertDialog>
558606
</div>
559-
)};
607+
)
608+
};

0 commit comments

Comments
 (0)