diff --git a/.github/workflows/check-linting-and-format.yml b/.github/workflows/check-linting-and-format.yml index 7f25705..a4c5608 100644 --- a/.github/workflows/check-linting-and-format.yml +++ b/.github/workflows/check-linting-and-format.yml @@ -16,19 +16,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18] + node-version: [20] steps: - name: Check out Git repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3e82242 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +.xata +.vercel +.next +.github +node_modules +.all-contributorsrc +.xatarc \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..44aeb40 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib" +} diff --git a/README.md b/README.md index a0506a0..2cc3d66 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ You will need to sign up with Xata and set up a database for the build. After re #### Installation ``` -npm install -g @xata.io/cli@latest +npm install -g "@xata.io/cli@latest" ``` #### Authentication ``` diff --git a/bin/act b/bin/act deleted file mode 100755 index 3968e32..0000000 Binary files a/bin/act and /dev/null differ diff --git a/components/Button.tsx b/components/Button.tsx deleted file mode 100644 index 8e9b4bb..0000000 --- a/components/Button.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ButtonHTMLAttributes, PropsWithChildren } from 'react'; - -type ButtonProps = { - className?: string; -} & ButtonHTMLAttributes; - -function Button({ - children, - className, - ...props -}: PropsWithChildren) { - return ( -
-
- -
- ); -} - -export default Button; diff --git a/components/Card.tsx b/components/Card.tsx deleted file mode 100644 index a7c2084..0000000 --- a/components/Card.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { emojify } from '@twuni/emojify'; -import { - GoStar, - GoRepoForked, - GoAlertFill, - GoIssueOpened -} from 'react-icons/go'; -import { RepoItem } from 'types'; -import { useSetAtom } from 'jotai'; -import { repoAtom } from 'utils/state/repoAtom'; - -interface Props { - repo: RepoItem; -} - -function Card({ repo }: Props) { - const setRepo = useSetAtom(repoAtom); - return ( -
-
-
-
- - {repo.owner.login} - -

- - {repo.name} - -

- -
- -
- {emojify(repo.description)} -
- -
- {repo.topics.map((topic: string) => ( - - {topic} - - ))} -
-
- - {/* stars and forks cards */} -
- - -
-
- {repo.stargazers_count} -
-
Stars
-
-
- Checkout all the stars here! -
-
- - -
-
- {repo.forks} -
-
Forks
-
-
- Checkout all the forks here! -
-
- - -
-
- {repo.open_issues_count} -
-
Issues
-
-
- Checkout all open issues here! -
-
-
-
-
- ); -} - -export default Card; diff --git a/components/Footer.tsx b/components/Footer.tsx deleted file mode 100644 index 7ebc82f..0000000 --- a/components/Footer.tsx +++ /dev/null @@ -1,35 +0,0 @@ -const creators: Record = { - Usman: 'https://twitter.com/MaxProgramming1/', - Sunrit: 'https://twitter.com/JanaSunrise/', - 'You all': '/contributors' -}; - -const Footer = () => { - return ( - - ); -}; - -export default Footer; diff --git a/components/Header.tsx b/components/Header.tsx deleted file mode 100644 index 5e043f4..0000000 --- a/components/Header.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import Link from 'next/link'; -import { useRouter } from 'next/router'; - -import { IoLogoGithub } from 'react-icons/io'; -import { BsPeopleFill } from 'react-icons/bs'; - -import Search, { SearchProps } from './Search'; -import { signIn, signOut, useSession } from 'next-auth/react'; - -function SearchBar(props: SearchProps) { - const router = useRouter(); - - return router.pathname === '/repos/[language]' && ; -} - -function Header() { - const session = useSession(); - - return ( -
-
-
- - Hacktoberfest - - - - -
- - - - - - - - -
-
- - -
-
- ); -} - -export default Header; diff --git a/components/Hero.tsx b/components/Hero.tsx deleted file mode 100644 index 001edfd..0000000 --- a/components/Hero.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { FormEventHandler, MouseEventHandler, useRef, useState } from 'react'; -import Link from 'next/link'; - -import languages from 'assets/languages.json'; -import LanguageButton from './LanguageButton'; -import { useRouter } from 'next/router'; -import sortByName from 'utils/sortByName'; -import Button from './Button'; - -const { main: mainLanguages, others: otherLanguages } = languages; - -function Hero() { - const [errorMessage, setErrorMessage] = useState(null); - const [isSearchEmpty, setIsSearchEmpty] = useState(true); - const formRef = useRef(null); - const router = useRouter(); - const handleClear: MouseEventHandler = () => { - if (formRef.current && !isSearchEmpty) { - formRef.current.reset(); - setIsSearchEmpty(true); - setErrorMessage(null); - } - }; - const handleSubmit: FormEventHandler = e => { - e.preventDefault(); - const formData = new FormData(e.target as HTMLFormElement); - const search = (formData.get('search') as string).trim(); - // Check if the input is empty or contains only spaces - if (search === '') { - setErrorMessage('Empty search terms invalid!'); - return; - } - // Clear any previous error message & proceed to search - setErrorMessage(null); - router.push(`/repos/${search}`); - }; - return ( -
-
-
-
-

- Search your language -

-
-
-
- { - setIsSearchEmpty(e.target.value.trim() === ''); - }} - /> - - {!isSearchEmpty && ( - - )} -
- -
-
-

- Or select the programming language you would like to find - repositories for. -

- - {mainLanguages.map(language => ( - - ))} - -
- - -
    - {otherLanguages.sort(sortByName).map(language => ( -
  • - - {language} - -
  • - ))} -
-
- {/* - - */} -
-
-
- ); -} - -const SearchIcon = () => ( - - - -); -const ClearIcon = () => { - return ( - - - - ); -}; - -export default Hero; diff --git a/components/LanguageButton.tsx b/components/LanguageButton.tsx deleted file mode 100644 index 39dcf10..0000000 --- a/components/LanguageButton.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import Link from 'next/link'; -import Button from './Button'; -import Icons from './Icons'; - -function LanguageButton({ language }: { language: string }) { - let lan: string = language.toLowerCase(); - lan === 'c++' ? (lan = 'cpp') : ''; - let icon = Icons[lan]; - - return ( - - - - ); -} - -export default LanguageButton; diff --git a/components/Pagination.tsx b/components/Pagination.tsx deleted file mode 100644 index 82fec3d..0000000 --- a/components/Pagination.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Link from 'next/link'; -import { useRouter } from 'next/router'; -import { BsArrowLeft, BsArrowRight } from 'react-icons/bs'; -import Button from './Button'; - -interface Props { - page: number; - totalCount: number; -} - -const MAX_PER_PAGE = 21; - -function Pagination({ page, totalCount }: Props) { - const router = useRouter(); - return ( -
- {page > 1 && ( - - - - )} - {totalCount >= MAX_PER_PAGE && - page < Math.ceil(totalCount / MAX_PER_PAGE) && ( - - - - )} -
- ); -} - -export default Pagination; diff --git a/components/Search.tsx b/components/Search.tsx deleted file mode 100644 index db07c6b..0000000 --- a/components/Search.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useRouter } from 'next/router'; -import { SubmitHandler, useForm } from 'react-hook-form'; -import { GoX } from 'react-icons/go'; - -interface FormValues { - searchQuery: string; -} -export interface SearchProps { - className?: string; -} - -export default function Search({ className }: SearchProps) { - const router = useRouter(); - - const { register, handleSubmit, reset } = useForm({ - defaultValues: { - searchQuery: router.query.q as string - } - }); - - const onSubmit: SubmitHandler = ({ searchQuery }) => { - let trimmedQuery = searchQuery.trim(); - //Performs search only with non-empty strings - if (trimmedQuery !== '') { - router.push({ query: { ...router.query, q: trimmedQuery } }); - } - }; - - return ( -
-
-
- - -
-
-
- ); -} diff --git a/components/Sort.tsx b/components/Sort.tsx deleted file mode 100644 index ff70b63..0000000 --- a/components/Sort.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { useRouter } from 'next/router'; -import Link from 'next/link'; -import languages from 'assets/languages.json'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCode } from '@fortawesome/free-solid-svg-icons'; -import { faArrowUpAZ } from '@fortawesome/free-solid-svg-icons'; -import sortByName from 'utils/sortByName'; -import Button from './Button'; - -const { mainLanguages } = languages; - -enum SortTypes { - BestMatch = 'Best match', - MostStars = 'Most stars', - FewestStars = 'Fewest stars', - MostForks = 'Most forks', - FewestForks = 'Fewest forks', - MostHelpWantedIssues = 'Most help wanted issues', - RecentlyUpdated = 'Recently updated', - LeastRecentlyUpdated = 'Least recently updated' -} - -export default function Sort() { - const router = useRouter(); - - const navigationItems = [ - { - name: 'Best match', - href: { query: { ...router.query } } - }, - { - name: 'Most stars', - href: { query: { ...router.query, s: 'stars', o: 'desc' } } - }, - { - name: 'Fewest stars', - href: { query: { ...router.query, s: 'stars', o: 'asc' } } - }, - { - name: 'Most forks', - href: { query: { ...router.query, s: 'forks', o: 'desc' } } - }, - { - name: 'Fewest forks', - href: { query: { ...router.query, s: 'forks', o: 'asc' } } - }, - { - name: 'Most help wanted issues', - href: { query: { ...router.query, s: 'help-wanted-issues', o: 'desc' } } - }, - { - name: 'Recently updated', - href: { query: { ...router.query, s: 'updated', o: 'desc' } } - }, - { - name: 'Least recently updated', - href: { query: { ...router.query, s: 'updated', o: 'asc' } } - } - ]; - - const selectedSort = (): SortTypes => { - if (router.query.o === 'asc') { - if (router.query.s === 'stars') return SortTypes.FewestStars; - if (router.query.s === 'forks') return SortTypes.FewestForks; - if (router.query.s === 'updated') return SortTypes.LeastRecentlyUpdated; - return SortTypes.BestMatch; - } else if (router.query.o === 'desc') { - if (router.query.s === 'stars') return SortTypes.MostStars; - if (router.query.s === 'forks') return SortTypes.MostForks; - if (router.query.s === 'updated') return SortTypes.RecentlyUpdated; - if (router.query.s === 'help-wanted-issues') - return SortTypes.MostHelpWantedIssues; - return SortTypes.BestMatch; - } else { - return SortTypes.BestMatch; - } - }; - - const handleClick = () => { - const elem = document.activeElement as HTMLElement; - if (elem) { - elem?.blur(); - } - }; - return ( -
-
- -
-
    - {mainLanguages.sort(sortByName).map(language => ( -
  • - - {language} - -
  • - ))} -
-
-
-
- -
-
    - {navigationItems.map((item, index) => { - const query = item.href.query; - if (item.name === SortTypes.BestMatch) { - delete query.o; - delete query.s; - } - return ( -
  • - {item.name} -
  • - ); - })} -
-
-
-
- ); -} diff --git a/components/StarsFilter.tsx b/components/StarsFilter.tsx deleted file mode 100644 index cad1f10..0000000 --- a/components/StarsFilter.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { useEffect } from 'react'; -import { useRouter } from 'next/router'; -import { SubmitHandler, Controller, useForm } from 'react-hook-form'; - -interface FormValues { - startStars: number | ''; - endStars: number | ''; -} - -export default function StarsFilter() { - const router = useRouter(); - const { handleSubmit, control, reset } = useForm({ - defaultValues: { - startStars: !router.query.startStars - ? '' - : +(router.query.startStars as string), - endStars: !router.query.endStars ? '' : +(router.query.endStars as string) - } - }); - - const onSubmit: SubmitHandler = ({ startStars, endStars }) => { - let query; - if ( - typeof endStars === 'number' && - typeof startStars === 'number' && - endStars < startStars - ) { - reset({ startStars, endStars: '' }); - query = { startStars }; - const { endStars, ...rest } = router.query; - router.push({ query: { ...rest, ...query } }); - } else { - query = { - startStars, - endStars - }; - router.push({ query: { ...router.query, ...query } }); - } - }; - - useEffect(() => { - reset(); - }, [router.query?.language, reset]); - - return ( -
-
- ( - { - field.onChange(parseInt(e.target.value, 10)); - }} - placeholder="Star's Starting Range" - min="0" - /> - )} - control={control} - /> - ( - { - field.onChange(parseInt(e.target.value, 10)); - }} - placeholder="Star's Finish Range" - min="0" - /> - )} - control={control} - /> - - {/* Flex container to center the button */} -
- -
-
-
- ); -} diff --git a/next-env.d.ts b/next-env.d.ts index a4a7b3f..40c3d68 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/next-seo.config.ts b/next-seo.config.ts deleted file mode 100644 index 40b15c8..0000000 --- a/next-seo.config.ts +++ /dev/null @@ -1,78 +0,0 @@ -const today = new Date(); -const currentMonth = today.getMonth(); -const currentYear = today.getFullYear(); - -const config = { - title: 'Hacktoberfest Projects', - description: `Quickly and easily find projects to contribute to ${currentMonth > 9 ? `upcoming Hacktoberfest ${currentYear + 1}` : `this Hacktoberfest ${currentYear}`}!`, - additionalMetaTags: [ - { - property: 'keywords', - content: 'hacktoberfest, open-source, contribution, oss' - }, - { - name: 'theme-color', - content: '#1A202C' - }, - { - name: 'color-scheme', - content: 'dark' - }, - { - name: 'msapplication-TileColor', - content: '#ffd74d' - } - ], - openGraph: { - type: 'website', - locale: 'en_US', - url: 'https://hacktoberfest-projects.vercel.app', - title: 'Hacktoberfest projects', - description: `Quickly and easily find projects to contribute to ${currentMonth > 9 ? `upcoming Hacktoberfest ${currentYear + 1}` : `this Hacktoberfest ${currentYear}`}!`, - site_name: 'Hacktoberfest projects', - images: [ - { - url: '/hacktoberfest.svg', - width: 800, - height: 600, - alt: 'Og Image Alt', - type: 'image/jpeg' - } - ] - }, - - twitter: { - creator: '@MaxProgramming1', - cardType: 'summary_large_image', - title: 'Hacktoberfest projects', - url: 'https://hacktoberfest-projects.vercel.app' - }, - additionalLinkTags: [ - { - rel: 'icon', - href: '/favicon.ico' - }, - { - rel: 'icon', - href: '/favicon-32x32.ico', - sizes: '32x32' - }, - { - rel: 'icon', - href: '/favicon-16x16.ico', - sizes: '16x16' - }, - { - rel: 'apple-touch-icon', - href: '/apple-touch-icon.ico', - sizes: '76x76' - }, - { - rel: 'mask-icon', - href: '/safari-pinned-tab.svg', - color: '#5bbad5' - } - ] -}; - -export default config; diff --git a/next.config.mjs b/next.config.mjs index 1cad4e1..a2bac7a 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,6 @@ -await import('./env.mjs'); +import './src/env.mjs'; -/** @type {import('next').NextConfig} */ +/**@type {import('next').NextConfig}*/ const config = { reactStrictMode: true, async redirects() { diff --git a/package.json b/package.json index d47cfd1..e2c6614 100644 --- a/package.json +++ b/package.json @@ -10,21 +10,19 @@ "format": "prettier --write \"./**/*.{ts,tsx,json}\"" }, "dependencies": { - "@fontsource/poppins": "^5.0.16", - "@fortawesome/fontawesome-svg-core": "^6.6.0", - "@fortawesome/free-regular-svg-icons": "^6.6.0", - "@fortawesome/free-solid-svg-icons": "^6.6.0", - "@fortawesome/react-fontawesome": "^0.2.2", - "@next-auth/xata-adapter": "^0.2.2", + "@auth/xata-adapter": "^1.4.2", "@t3-oss/env-nextjs": "^0.11.1", "@twuni/emojify": "^1.0.2", "@xata.io/client": "^0.30.0", "axios": "^1.7.7", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "daisyui": "^4.12.10", "framer-motion": "^11.5.4", "jotai": "^2.9.3", - "next": "^14.2.8", - "next-auth": "^4.24.7", + "lucide-react": "^0.439.0", + "next": "^14.2.9", + "next-auth": "5.0.0-beta.20", "next-cloudinary": "^6.12.0", "next-seo": "^6.6.0", "nextjs-progressbar": "^0.0.16", @@ -33,6 +31,8 @@ "react-hook-form": "^7.53.0", "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7", "zod": "^3.23.8" }, "devDependencies": { @@ -40,12 +40,12 @@ "@types/react": "18.3.5", "@types/twuni__emojify": "^1.0.2", "autoprefixer": "^10.4.20", - "eslint": "9.10.0", - "eslint-config-next": "14.2.8", + "eslint": "8.57.0", + "eslint-config-next": "14.2.9", "postcss": "^8.4.45", "prettier": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.6", "tailwindcss": "^3.4.10", - "typescript": "5.5.4" + "typescript": "5.6.2" } } diff --git a/pages/404.tsx b/pages/404.tsx deleted file mode 100644 index 0b08753..0000000 --- a/pages/404.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import Button from 'components/Button'; -import Header from 'components/Header'; -import Link from 'next/link'; - -export default function Custom404() { - return ( - <> -
- -
-
-

404

-
-

We are sorry,Page not found!

-

- The Page you are looking for might have been removed or it is - Temporarily unavailable -

- - - -
-
-
- - ); -} diff --git a/pages/_app.tsx b/pages/_app.tsx deleted file mode 100644 index 88ed79c..0000000 --- a/pages/_app.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import Head from 'next/head'; -import NextNProgress from 'nextjs-progressbar'; -import { DefaultSeo } from 'next-seo'; -import { motion } from 'framer-motion'; -import { SessionProvider, type SessionProviderProps } from 'next-auth/react'; - -import SEO from 'next-seo.config'; - -import '@fontsource/poppins'; -import '../styles/globals.css'; - -import type { AppProps } from 'next/app'; -import Footer from 'components/Footer'; -import ReportModal from 'components/ReportModal'; -import { Toaster } from 'react-hot-toast'; - -function MyApp({ - Component, - pageProps, - router -}: AppProps) { - return ( - - - - - - - - -