-
Notifications
You must be signed in to change notification settings - Fork 5
feat: Sort project cards #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
2ba38e3
383b6a7
c2fb2c2
9413396
af77643
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import React, { useState } from "react"; | ||
| import "../styles/components/SortDropdown.css"; | ||
| import downArrow from "../assets/down.png"; | ||
| import upArrow from "../assets/up-arrow.png"; | ||
| import { SortDropdownProps } from "../utils/types"; | ||
| const SortDropdown: React.FC<SortDropdownProps> = ({ | ||
| setSortField, | ||
| setSortType, | ||
| sortField, | ||
| sortType, | ||
| }) => { | ||
| const [showMenu, setShowMenu] = useState(false); | ||
|
|
||
| const toggleSort = () => { | ||
| setSortType(sortType === "desc" ? "asc" : "desc"); | ||
| } | ||
| const toggleDropdown = () => { | ||
| setShowMenu(!showMenu); | ||
| }; | ||
| const handleSortField = (field: string) => { | ||
| setSortField(field); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className={`dropdown ${showMenu ? "show" : ""}`}> | ||
| <div className="sort-button"> | ||
| <button disabled={window.innerWidth >= 760} onClick={toggleDropdown}> | ||
| Sort by:{" "}{sortField.charAt(0).toUpperCase()+sortField.slice(1)} | ||
| </button> | ||
| <div className="sort-Arrow-container" onClick={(e) => { | ||
| e.stopPropagation(); | ||
| toggleSort(); | ||
| }}> | ||
| <img src={sortType === "desc" ? downArrow : upArrow} className="sort-Arrow" alt="▼" /> | ||
|
|
||
| </div> | ||
|
|
||
| </div> | ||
| <div className={`dropdown-content ${showMenu ? "show" : ""}`}> | ||
| <div className={`dropdown-item ${"name" === sortField ? "selected" : ""}`} onClick={() => handleSortField("name")}> | ||
| {" "} | ||
|
|
||
| Name | ||
| </div> | ||
| <div className={`dropdown-item ${"forks" === sortField ? "selected" : ""}`} onClick={() => handleSortField("forks")}> | ||
| <span | ||
|
|
||
| ></span> | ||
| Forks | ||
| </div> | ||
| <div className={`dropdown-item ${"stars" === sortField ? "selected" : ""}`} onClick={() => handleSortField("stars")}> | ||
|
|
||
| Stars | ||
| </div> | ||
|
|
||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default SortDropdown; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we add another field? current behaviour is to fetch repo data by last updated, which means we get to see currently active repos on the top in # notice sort:updated
response = requests.get(url, params={'sort':'updated', 'per_page': 100, 'type': 'public'}) if that could be the default that would be great, feel free to add other fields if you like also while your dropdown is nice and simple, could you look into a more modular filter system like as below? let me know if you feel like any other fields are necessary. If you think these are enough then a dropdown is sufficient |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,51 @@ | ||
| import { useState } from "react"; | ||
| import { useEffect, useState } from "react"; | ||
| import CardGrid from "../sections/CardGrid"; | ||
| import "../styles/pages/Projects.css"; | ||
| import { REPO_DATA_TYPE } from "../utils/types"; | ||
| import RepoData from '../data/repo_data.json'; | ||
|
|
||
| import SortDropdown from "../components/SortDropdown"; | ||
| const Projects = () => { | ||
| const repoList: REPO_DATA_TYPE[] = RepoData as REPO_DATA_TYPE[] | ||
|
|
||
| const [sortField, setSortField] = useState("name"); | ||
|
||
| const [sortType,setSortType]=useState("asc") | ||
|
||
| const languages = [...new Set(repoList.map(repo => repo.language))]; | ||
| const [selectedLanguage, setSelectedLanguage] = useState<string[]>([]); | ||
| const [FilteredRepos, setFilteredRepos] = useState<REPO_DATA_TYPE[]>(repoList); | ||
|
|
||
|
|
||
| //sorting based on STARS ,FORKS , NAME | ||
| // and Also filtered by Language | ||
| useEffect ( () => { | ||
| let result = repoList.filter((repo) => | ||
| selectedLanguage.length === 0 || selectedLanguage.includes(repo.language) | ||
| ); | ||
|
|
||
| if (sortField === "name") { | ||
|
|
||
| result.sort((a, b) => { | ||
| const cmp = a.name.toLowerCase().localeCompare(b.name.toLowerCase()); | ||
| return sortType === "asc" ? cmp : -cmp; | ||
| }); | ||
|
|
||
| } | ||
| else if (sortField === "stars") { | ||
| result.sort((a, b) => { | ||
| const cmp = a.stars-b.stars; | ||
| return sortType === "asc" ? cmp : -cmp; | ||
| }); | ||
| } | ||
| else if (sortField === "forks") { | ||
| result.sort((a, b) => { | ||
| const cmp = a.forks-b.forks; | ||
| return sortType === "asc" ? cmp : -cmp; | ||
| }); | ||
|
|
||
| } | ||
| setFilteredRepos(result) | ||
|
|
||
| },[selectedLanguage,sortField,sortType]) | ||
|
|
||
|
|
||
|
|
||
|
|
||
| const toggleLanguage = (lang: string) => { | ||
|
|
@@ -22,11 +59,7 @@ const Projects = () => { | |
| }); | ||
| }; | ||
|
|
||
| const filteredRepos = repoList.filter(repo => { | ||
| if (selectedLanguage.length === 0) | ||
| return true; | ||
| return selectedLanguage.includes(repo.language); | ||
| }) | ||
|
|
||
|
|
||
| return ( | ||
| <div className="page-container"> | ||
|
|
@@ -36,7 +69,7 @@ const Projects = () => { | |
| Explore our repositories for projects that may help you, feel free to contribute to which ever ones suit you! | ||
| </p> | ||
| </section> | ||
|
|
||
| <div className="filter-container"> | ||
| <div className="language-filter"> | ||
| {languages.map(lang => ( | ||
| <button | ||
|
|
@@ -47,8 +80,19 @@ const Projects = () => { | |
| {lang} | ||
| </button> | ||
| ))} | ||
|
|
||
| </div> | ||
|
|
||
| <SortDropdown | ||
| setSortField={setSortField} | ||
| setSortType={setSortType} | ||
| sortField={sortField} | ||
| sortType={sortType} | ||
| /> | ||
|
|
||
|
|
||
| </div> | ||
| <CardGrid repos={filteredRepos} displayMode="all" /> | ||
| <CardGrid repos={FilteredRepos} displayMode="all" /> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| .dropdown { | ||
| position: relative; | ||
| display: inline-block; | ||
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", | ||
| "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; | ||
|
|
||
| padding: 10px; | ||
| } | ||
|
|
||
| .selected { | ||
| background-color: #393737; | ||
| border-radius: 0 0 5px 5px; | ||
| } | ||
| .sort-button { | ||
| background-color: #2f2f2f; | ||
| color: #fcfcfc; | ||
| border: none; | ||
| padding: 8px 15px; | ||
| font-size: 14px; | ||
| border-radius: 5px; | ||
|
|
||
| cursor: pointer; | ||
| width: 200px; | ||
| transition: background 300ms, color 300ms, scale 300ms; | ||
|
|
||
| display: flex; | ||
| justify-content: space-between; | ||
|
|
||
| } | ||
| .sort-button button{ | ||
| color: #fcfcfc; | ||
| background-color: #2f2f2f; | ||
| width: 100%; | ||
| text-align: left; | ||
| border: none; | ||
| } | ||
| .sort-Arrow-container{ | ||
| display: flex; | ||
| } | ||
|
|
||
| .sort-Arrow { | ||
| width: 15px; | ||
|
|
||
| filter: brightness(0) invert(1); | ||
| color: white; | ||
| } | ||
|
|
||
| .dropdown-content { | ||
| opacity: 0; | ||
| transition: opacity 0.3s ease, transform 0.3s ease; | ||
| position: absolute; | ||
| border-radius: 0 0 5px 5px; | ||
| background-color: #2f2f2f; | ||
| color: #fcfcfc; | ||
| width: 230px; | ||
|
|
||
| z-index: 1; | ||
| } | ||
|
|
||
| .dropdown-content div { | ||
| padding: 10px 20px; | ||
| cursor: pointer; | ||
| display: flex; | ||
|
|
||
| align-items: center; | ||
| } | ||
|
|
||
| .dropdown-item { | ||
| text-align: center; | ||
| font-size: small; | ||
| transition: background 300ms, color 300ms, scale 300ms; | ||
| } | ||
| .dropdown-item:hover { | ||
| background-color: #393737; | ||
| border-radius: 0 0 5px 5px; | ||
| } | ||
|
|
||
|
|
||
| /* | ||
| for large screens toggle on hover */ | ||
| .dropdown:hover .dropdown-content { | ||
| opacity: 1; | ||
| transform: translateY(0); | ||
| } | ||
|
|
||
| .dropdown:hover .sort-button{ | ||
| border-radius: 5px 5px 0 0; | ||
| } | ||
|
|
||
| /* | ||
| for small screens toggling on click */ | ||
| .dropdown-content.show { | ||
| opacity: 1; | ||
| transform: translateY(0); | ||
|
|
||
| } | ||
| .dropdown.show .sort-button{ | ||
| border-radius: 5px 5px 0 0 ; | ||
|
|
||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| @media (max-width: 768px) { | ||
| .dropdown:hover .dropdown-content { | ||
| display: none; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,12 +3,14 @@ | |
| display: grid; | ||
| gap: 1rem; | ||
| padding: 1rem; | ||
|
|
||
| justify-content: center; | ||
| } | ||
|
|
||
| /* Default layout for all cards */ | ||
| .gh-card-grid.all { | ||
| grid-template-columns: repeat(3, 1fr); | ||
|
|
||
| grid-template-columns: repeat(2, 1fr); | ||
|
||
| } | ||
|
|
||
| /* Prominent layout for fewer cards */ | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be better/easier to just use a library like react-icons or fontawesome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or even just use something stupid like
^andvlol, or check if the font supports emojisThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Emojis look like garbage on Windows. And icons can be used for other things later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in that case react-icons is already a dependency, so should be an easy change @Waqibsk