diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml new file mode 100644 index 000000000..4bd5581f0 --- /dev/null +++ b/.github/workflows/spellcheck.yml @@ -0,0 +1,24 @@ +name: Spellcheck + +on: + push: + branches: + - main # Adjust this branch name if needed + pull_request: + types: + - opened + - synchronize + +jobs: + spellcheck: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install codespell + run: pip install codespell + + - name: Run spellcheck + run: codespell --quiet-level=2 --check-filenames -- ./**/*.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 93a78297f..2a95594ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -178,6 +178,54 @@ When adding _YouTube_ channel link, please specify _the language_ of the channel --- +### Commit Message Guidelines using Commitlint + +We follow a standardized commit message format using Commitlint to ensure consistency and clarity in our commit history. Each commit message should adhere to the following guidelines: + +1. **Type**: The commit type must be one of the following: + + - `feat`: A new feature or enhancement. + - `fix`: A bug fix. + - `docs`: Documentation changes. + - `style`: Code style changes (e.g., formatting, semicolons). + - `refactor`: Code refactorings with no feature changes or bug fixes. + - `test`: Adding or improving tests. + - `chore`: General maintenance tasks, build changes, etc. + +2. **Scope** (Optional): The scope provides context for the commit, indicating the specific part of the project being affected. Use a short description in lowercase (e.g., `auth`, `navbar`, `README`). + +3. **Description**: A brief and meaningful description of the changes made. Start with a capital letter and use the imperative mood (e.g., "Add new feature" instead of "Added new feature"). + +4. **Issue reference** (Optional): Include the issue number associated with the commit (e.g., `#123`). + +### Examples: + +#### Valid Commit Messages: + +- `feat: Add user authentication feature` +- `fix(auth): Resolve login page redirect issue` +- `docs: Update installation instructions` +- `style: Format code according to project guidelines` +- `refactor(navbar): Improve responsiveness` +- `test: Add unit tests for API endpoints` +- `chore: Update dependencies to latest versions` +- `fix: Handle edge case in data processing (#456)` + +#### Invalid Commit Messages: + +- `Added new stuff` +- `Fixed a bug` +- `Updated code` +- `auth feature update` +- `chore: fixed some stuff` + +### Commit Example with Commitlint: + +```bash +git commit -m "feat(auth): Implement user signup process (#789)" +``` +
+ ## Remarks ✅ - If something is missing here, or you feel something is not well described, either create a PR, [raise an issue](https://github.com/rupali-codes/LinksHub/issues), or [do a code review of the person’s PR](https://www.freecodecamp.org/news/code-review-tips/) (ensure that your review conforms to the [Code of Conduct](https://github.com/CBID2/LinksHub-my-version-/blob/main/CODE_OF_CONDUCT.md)) diff --git a/components/BackToTop/BackToTopButton.tsx b/components/BackToTop/BackToTopButton.tsx index 7be3e28c5..1ed022fbe 100644 --- a/components/BackToTop/BackToTopButton.tsx +++ b/components/BackToTop/BackToTopButton.tsx @@ -52,6 +52,8 @@ export const BackToTopButton = () => { diff --git a/components/NewIssue/NewIssue.tsx b/components/NewIssue/NewIssue.tsx index 774b56c39..408a124fc 100644 --- a/components/NewIssue/NewIssue.tsx +++ b/components/NewIssue/NewIssue.tsx @@ -5,13 +5,14 @@ const NewIssue: FC = () => { return (
Be the first to add by creating a GitHub issue - - here - + + here +
) } diff --git a/components/Searchbar/Searchbar.tsx b/components/Searchbar/Searchbar.tsx index 033f279b8..7b53d4849 100644 --- a/components/Searchbar/Searchbar.tsx +++ b/components/Searchbar/Searchbar.tsx @@ -67,8 +67,10 @@ export const Searchbar: React.FC = ({ setSearch }) => { return (
-
- +
+ = ({ setSearch }) => { diff --git a/components/Share/Share.tsx b/components/Share/Share.tsx index 5814b6f54..320977ce1 100644 --- a/components/Share/Share.tsx +++ b/components/Share/Share.tsx @@ -8,6 +8,7 @@ type ShareProps = { }; export const Share: React.FC = ({ url, title }) => { + const showShareOptions = false async function handleShare() { if (navigator.share) { try { @@ -55,8 +56,25 @@ export const Share: React.FC = ({ url, title }) => { paddingRight: "6px", paddingTop: "2px", paddingBottom: "2px", - }} - /> + }} + /> + + {showShareOptions && ( +

+ Share +

+ )}
); }; diff --git a/components/SideNavbar/SideNavbarBody.tsx b/components/SideNavbar/SideNavbarBody.tsx index 2dfc37854..7a2360035 100644 --- a/components/SideNavbar/SideNavbarBody.tsx +++ b/components/SideNavbar/SideNavbarBody.tsx @@ -10,8 +10,13 @@ export const SideNavbarBody: FC = () => { const { setSearch, searchResults, debouncedSearch } = useSidebarSearch() return ( -
-
+
+
diff --git a/components/SideNavbar/SideNavbarCategory.tsx b/components/SideNavbar/SideNavbarCategory.tsx index ebd56f621..84931ccb9 100644 --- a/components/SideNavbar/SideNavbarCategory.tsx +++ b/components/SideNavbar/SideNavbarCategory.tsx @@ -27,6 +27,7 @@ export const SideNavbarCategory: FC<{ diff --git a/components/ThemeToggler/themeToggler.tsx b/components/ThemeToggler/themeToggler.tsx index ed98ddd40..850abee07 100644 --- a/components/ThemeToggler/themeToggler.tsx +++ b/components/ThemeToggler/themeToggler.tsx @@ -27,11 +27,18 @@ export function ThemeToggler() { ) diff --git a/components/TopBar/TopBar.tsx b/components/TopBar/TopBar.tsx index f72f1a0db..c046bf426 100644 --- a/components/TopBar/TopBar.tsx +++ b/components/TopBar/TopBar.tsx @@ -1,19 +1,38 @@ -import { FC, useState } from 'react' +import { FC, useEffect, useState } from 'react' import { useRouter } from 'next/router' import { FaSlackHash, FaInfoCircle } from 'react-icons/fa' import PopupDesc from 'components/popup/popupCategoryDesc' import { ICategoryData } from 'types' import categoryDescriptions from './CategoryDescriptions' +import { useResults } from 'hooks/ResultsContext' import { Tooltip } from 'react-tooltip' -export const TopBar: FC<{ className?: string | undefined }> = (props) => { - const { className } = props +interface TopBarProps { + className?: string + results: number +} + +export const TopBar: FC = ({ className }) => { + const { results } = useResults() + const [isSearchFound, setIsSearchFound] = useState(false) const [currentCategory, setCurrentCategory] = useState( null ) const router = useRouter() const category = router.asPath.replace('/', '') const categoryName = category.split('-').join(' ') + const regEx = /[ `!@#$%^&*()_+\=\[\]{};':"\\|,.<>\/?~]/g + const cleanedCategory = category + .replaceAll(regEx, ' ') + .replaceAll('search query ', '') + + useEffect(() => { + if (results > 0) { + setIsSearchFound(true) + } else if (results === 0) { + setIsSearchFound(false) + } + }, [results]) if (router.pathname.length === 1) { return null @@ -33,28 +52,78 @@ export const TopBar: FC<{ className?: string | undefined }> = (props) => { } return ( -
- - - {category.split('-').join(' ')} - - + + +
+ ) : ( +
- + + {category.split('-').join(' ')} + + + - - - -
+ +
+ )} + ) } diff --git a/components/popup/popupInfo.tsx b/components/popup/popupInfo.tsx index 3f24b51f9..0d204edc5 100644 --- a/components/popup/popupInfo.tsx +++ b/components/popup/popupInfo.tsx @@ -55,7 +55,7 @@ export const PopupInfo: React.FC<{

{currentCard?.description}

-
+ + + {/* Close Text */} +
+

+ Close +

+
, overlayRoot )} diff --git a/database/cloud_computing_platforms/azure.json b/database/cloud_computing_platforms/azure.json index 7b1391fae..f68c63436 100644 --- a/database/cloud_computing_platforms/azure.json +++ b/database/cloud_computing_platforms/azure.json @@ -5,5 +5,12 @@ "url": "https://learn.microsoft.com/en-us/azure/?product=popular", "category": "cloud computing", "subcategory": "azure" + }, + { + "name": "Microsoft Learn & Certified", + "description": "Microsoft has certification paths for many technical job roles. Each of these certifications consists of passing a series of exams to earn them. ", + "url": "https://learn.microsoft.com/en-us/certifications/", + "category": "cloud computing", + "subcategory": "azure" } ] \ No newline at end of file diff --git a/database/competitive_programming/platforms.json b/database/competitive_programming/platforms.json new file mode 100644 index 000000000..7a05d241c --- /dev/null +++ b/database/competitive_programming/platforms.json @@ -0,0 +1,16 @@ +[ + { + "name": "LeetCode", + "description": "This site offers competitive coding challenges and interview preparation resources for software engineers and developers.", + "url": "https://leetcode.com/", + "category": "competitive_programming", + "subcategory": "platforms" + }, + { + "name": "HackerRank", + "description": "This resource provides developers with competitive programming challenges to improve their skills in multiple languages. It also allows tech recruiters to assess developers on their problem-solving skills.", + "url": "https://www.hackerrank.com/", + "category": "competitive_programming", + "subcategory": "platforms" + } +] diff --git a/database/data.ts b/database/data.ts index 824373c77..b3e9495a7 100644 --- a/database/data.ts +++ b/database/data.ts @@ -260,4 +260,10 @@ export const sidebarData: ISidebar[] = [ { name: 'communities', url: '/communities', resources: DB.communities }, ], }, + { + category: 'competitive_programming', + subcategory: [ + { name: 'platforms', url: '/platforms', resources: DB.platforms }, + ], + }, ] diff --git a/database/frontend/online-code-editors.json b/database/frontend/online-code-editors.json index 02a89ddf7..0d148eb1c 100644 --- a/database/frontend/online-code-editors.json +++ b/database/frontend/online-code-editors.json @@ -83,20 +83,6 @@ "category": "frontend", "subcategory": "online-code-editors" }, - { - "name": "HackerRank", - "description": "An online IDE to practice your competitive programming skills. It allows you to code in multiple languages.", - "url": "https://www.hackerrank.com/", - "category": "frontend", - "subcategory": "online-code-editors" - }, - { - "name": "LeetCode", - "description": "LeetCode is the best platform to help you enhance your programming skills, and expand your knowledge.", - "url": "https://leetcode.com/", - "category": "frontend", - "subcategory": "online-code-editors" - }, { "name": "Programiz", "description": "Learn to program with our beginner-friendly tutorials and examples. Read tutorials, try examples, write code, and learn to program.", diff --git a/database/index.ts b/database/index.ts index 0d8641a82..b44becb29 100644 --- a/database/index.ts +++ b/database/index.ts @@ -89,3 +89,5 @@ export { default as devtools } from './other/devtools.json' export { default as podcasts } from './other/podcasts.json' export { default as otherResources } from './other/other-resources.json' export { default as communities } from './other/communities.json' +// competitive programming +export {default as platforms } from './competitive_programming/platforms.json' \ No newline at end of file diff --git a/database/other/podcasts.json b/database/other/podcasts.json index 4337b487e..4a02804ad 100644 --- a/database/other/podcasts.json +++ b/database/other/podcasts.json @@ -12,5 +12,13 @@ "url": "https://www.codenewbie.org/podcast", "category": "other", "subcategory": "podcasts" + }, + { + "name": "Stackoverflow Podcast", + "description": " In Stack Overflow Podcast, hosts Ben Popper, Cassidy Williams, and Ceora Ford explore what it means to work in software and how code is reshaping our world.", + "url": "https://stackoverflow.blog/podcast/", + "category": "other", + "subcategory": "podcasts" } + ] \ No newline at end of file diff --git a/database/resources/e-book.json b/database/resources/e-book.json index 2cf169f2f..57f113aac 100644 --- a/database/resources/e-book.json +++ b/database/resources/e-book.json @@ -46,5 +46,13 @@ "category": "resource", "subcategory": "e-book", "language": "english" + }, + { + "name": "Book Yard", + "description": "'The Library to the World', in which books, education materials, information, reference materials, documents, and content will be provided freely", + "url": "www.bookyards.com", + "category": "resource", + "subcategory": "e-book", + "language": "english" } ] \ No newline at end of file diff --git a/database/resources/official-docs.json b/database/resources/official-docs.json index d1dc8160c..44fe149b0 100644 --- a/database/resources/official-docs.json +++ b/database/resources/official-docs.json @@ -79,10 +79,24 @@ { "name": "Express", "description": "Express is a fast, unopinionated, and minimalist web framework for Node.js", - "url": "https://svelte.dev/docs/introduction", + "url": "https://expressjs.com", + "category": "resources", + "subcategory": "officialdocs" + } , + { + "name": "Laravel", + "description": "Laravel is a web application framework with the expressive, elegant syntax", + "url": "https://laravel.com/", + "category": "resources", + "subcategory": "officialdocs" + }, + { + "name": "Ember.js", + "description": "Ember.js is a productive, battle-tested JavaScript framework used for building modern web applications", + "url": "https://guides.emberjs.com/release/", "category": "resources", "subcategory": "officialdocs" - } + } ] diff --git a/database/youtube/data-structures.json b/database/youtube/data-structures.json index 44a8c2ae6..b545b26bc 100644 --- a/database/youtube/data-structures.json +++ b/database/youtube/data-structures.json @@ -9,7 +9,7 @@ }, { "name": "CodeHelp - by Babbar", - "description": "This channel provides free placement specific DSA course in C++.", + "description": "This channel provides free placement-specific DSA courses in C++.", "url": "https://www.youtube.com/playlist?list=PLDzeHZWIZsTryvtXdMr6rPh4IDexB5NIA", "category": "youtube", "subcategory": "data-structures", @@ -17,7 +17,7 @@ }, { "name": "Apna College", - "description": "This channel provides free courses for DSA, Java, C++, C etc.", + "description": "This channel provides free courses for DSA, Java, C++, C, etc.", "url": "https://www.youtube.com/watch?v=z9bZufPHFLU&list=PLfqMhTWNBTe0b2nM6JHVCnAkhQRGiZMSJ", "category": "youtube", "subcategory": "data-structures", @@ -25,7 +25,8 @@ }, { "name": "Kunal Kushwaha", - "description": "This channel provides free Java specific DSA course with interview-preparation.", + "description": "This channel provides free Java-specific DSA course with interview preparation.", + "description": "This channel provides a free Java-specific DSA course with interview preparation.", "url": "https://youtube.com/playlist?list=PL9gnSGHSqcnr_DxHsP7AW9ftq0AtAyYqJ", "category": "youtube", "subcategory": "data-structures", @@ -33,7 +34,7 @@ }, { "name": "CodeWithHarry", - "description": "An all-in-one destination for DSA, Python, C++, JavaScript, Nodejs, Java, PHP & many more.", + "description": "An all-in-one destination for DSA, Python, C++, JavaScript, Nodejs, Java, PHP, & many more.", "url": "https://www.youtube.com/@CodeWithHarry/playlists", "category": "youtube", "subcategory": "data-structures", @@ -57,7 +58,7 @@ }, { "name": "Pepcoding", - "description": "One of the best channels for DSA and Java. It is also helpful for both students and working professionals.", + "description": "One of the best channels for learning DSA and Java. It is also helpful for both students and working professionals.", "url": "https://www.youtube.com/@Pepcoding/featured", "category": "youtube", "subcategory": "data-structures", @@ -97,7 +98,7 @@ }, { "name": "Hello World DSA", - "description": "This channel provides C++ specific DSA content. This course also provides explanations of Algorithms.", + "description": "This channel provides C++-specific DSA content. This course also provides explanations of Algorithms.", "url": "https://www.youtube.com/@HelloWorldbyprince/playlists", "category": "youtube", "subcategory": "data-structures", @@ -113,7 +114,7 @@ }, { "name": "Data Structure & Algorithms Full Course In Hindi", - "description": "DSA playlist for understanding concepts of core coding using the c++ language", + "description": "DSA playlist for understanding concepts of core coding using the C++ language", "url": "https://www.youtube.com/playlist?list=PLzjZaW71kMwQ1DIWTn0d_KDHU4_E52-rq", "category": "youtube", "subcategory": "data-structures", @@ -121,18 +122,28 @@ }, { "name": "CODING NINJAS", - "description": "This channel provides DSA course in Python from beginner to advance level.", + + "description": "This channel provides a DSA course about Python from beginner to advanced.", + "url": "https://youtube.com/playlist?list=PLrk5tgtnMN6TYBW0-U4YhIRyYEVpqVEnJ", "category": "youtube", "subcategory": "data-structures", "language": "english" }, { - "name": "CampusX", - "description": "Since Python is a widely used language in the tech industry, a playlist that focuses on various aspects of this programming language would be a valuable addition to this website.", - "url": "https://www.youtube.com/watch?v=f9Aje_cN_CY&list=RDCMUCCWi3hpnq_Pe03nGxuS7isg&start_radio=1&rv=f9Aje_cN_CY&t=41378", + "name": "Data Structures - Full Course Using C and C++", + "description": "Learn about DSAs and how they are implemented in C or C++ in this comprehensive course by FreeCodeCamp. ", + "url": "https://www.youtube.com/watch?v=B31LgI4Y4DQ", "category": "youtube", "subcategory": "data-structures", "language": "english" + }, + { + "name":"Code step by step", + "description": "A comprehensive playlist in Hindi that teaches developers data structures in Javascript from scratch.", + "url": "https://www.youtube.com/watch?v=wZHtZ_VJGKI&list=PL8p2I9GklV47TMMnPzqnkCtSOS3ebr4O7&ab_channel=CodeStepByStep", + "category":"youtube", + "subcategory":"data-structures", + "language":"hindi" } ] diff --git a/database/youtube/web-development.json b/database/youtube/web-development.json index 2da7a23c6..f28c9b4cd 100644 --- a/database/youtube/web-development.json +++ b/database/youtube/web-development.json @@ -302,5 +302,13 @@ "category": "youtube", "subcategory": "web-development", "language": "english" + }, + { + "name": "The Coder Coder", + "description": "This site provides practical tips for beginner web developers.", + "url": "https://www.youtube.com/c/TheCoderCoder", + "category": "youtube", + "subcategory": "web-development", + "language": "english" } ] diff --git a/hooks/ResultsContext.tsx b/hooks/ResultsContext.tsx new file mode 100644 index 000000000..cb9941e65 --- /dev/null +++ b/hooks/ResultsContext.tsx @@ -0,0 +1,28 @@ +import React, { createContext, useContext, useState, ReactNode } from 'react' + +interface ResultsContextValue { + results: number + setResults: React.Dispatch> +} + +const ResultsContext = createContext(null) + +export const ResultsProvider: React.FC<{ children: ReactNode }> = ({ + children, +}) => { + const [results, setResults] = useState(-1) + + return ( + + {children} + + ) +} + +export const useResults = () => { + const context = useContext(ResultsContext) + if (!context) { + throw new Error('useResults must be used within a ResultsProvider') + } + return context +} diff --git a/pages/[subcategory]/index.tsx b/pages/[subcategory]/index.tsx index 726181dcd..55cc006f6 100644 --- a/pages/[subcategory]/index.tsx +++ b/pages/[subcategory]/index.tsx @@ -5,9 +5,11 @@ import Head from 'next/head' import useFilterDB from 'hooks/useFilterDB' import CardsList from 'components/Cards/CardsList' import ComingSoon from 'components/NewIssue/NewIssue' +import { useResults } from 'hooks/ResultsContext' const SubCategory = () => { const router = useRouter() + const { results } = useResults() const title = `LinksHub - ${router.asPath .charAt(1) .toUpperCase()}${router.asPath.slice(2)}` @@ -32,7 +34,10 @@ const SubCategory = () => { content="LinksHub is the ultimate hub of ready-to-use tech resources. Discover free tools and libraries to streamline your development process and build better projects." /> - + @@ -80,7 +85,10 @@ const SubCategory = () => { content="https://discord.com/invite/NvK67YnJX5" /> - +
{content}
diff --git a/pages/_app.tsx b/pages/_app.tsx index 5d6e9489c..c0a18b28a 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -4,15 +4,18 @@ import GeneralLayout from 'layouts/GeneralLayout' import { GlobalProvider } from 'context/GlobalContext' import { Preloader } from 'components/Loader/Preloader' import { ThemeProvider } from 'next-themes' +import { ResultsProvider } from 'hooks/ResultsContext' export default function App({ Component, pageProps }: AppProps) { return ( - - - - - + + + + + + + ) diff --git a/pages/contributors.tsx b/pages/contributors.tsx index d615b1924..cd472bd88 100644 --- a/pages/contributors.tsx +++ b/pages/contributors.tsx @@ -136,12 +136,14 @@ const ContributorsPage: FC<{ contributors: Contributor[] }> = ({ GitHub Contributions diff --git a/pages/index.tsx b/pages/index.tsx index 96d145e47..aeab8cc19 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -22,7 +22,10 @@ export default function Home() { /> - + diff --git a/pages/search.tsx b/pages/search.tsx index 9ea5f755c..1da0074bc 100644 --- a/pages/search.tsx +++ b/pages/search.tsx @@ -7,8 +7,10 @@ import { TopBar } from 'components/TopBar/TopBar' import ComingSoon from 'components/NewIssue/NewIssue' import useFilterSearch from 'hooks/useFilterSearch' +import { useResults } from 'hooks/ResultsContext' const Search = () => { + const { results, setResults } = useResults() const router = useRouter() const title = `LinksHub - ${router.asPath .charAt(1) @@ -17,12 +19,20 @@ const Search = () => { const { filterSearch } = useFilterSearch() useEffect(() => { - if (!query || query === '') router.replace('/') - }, [query, router]) + if (!query || query === '') router.replace('/'); + }, [query, router]); let content: JSX.Element[] | JSX.Element - - const data = filterSearch(query as string) + + const data = filterSearch(query as string); + + useEffect(() => { + if (data.length > 0 && data.length !== -1) { + setResults(data.length) + } else { + setResults(0) + } + }, [data]) if (data.length > 0) { content = @@ -41,7 +51,10 @@ const Search = () => { content="LinksHub is the ultimate hub of ready-to-use tech resources. Discover free tools and libraries to streamline your development process and build better projects." /> - + @@ -49,10 +62,7 @@ const Search = () => { {/* Open Graph */} - + { {/* Twitter */} - + { property="discord:invite" content="https://discord.com/invite/NvK67YnJX5" /> + - +
{content}
- ) -} + ); +}; -export default Search +export default Search; diff --git a/types/index.ts b/types/index.ts index b5bc0afc5..b7faaac66 100644 --- a/types/index.ts +++ b/types/index.ts @@ -44,6 +44,7 @@ export type Category = | 'youtube' | 'other' | 'devops' + | 'competitive_programming' export type SubCategories = { name: string @@ -158,4 +159,6 @@ export const subcategoryArray = [ 'github', 'other-resources', 'podcasts', + // competitive programming + 'platforms', ]