diff --git a/package-lock.json b/package-lock.json index 92df2ab..e40c2ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "bcryptjs": "^2.4.3", "drizzle-kit": "^0.24.2", "drizzle-orm": "^0.33.0", + "framer-motion": "^11.11.10", "next": "14.2.5", "next-auth": "^5.0.0-beta.22", "nodemailer": "^6.9.15", @@ -3044,6 +3045,31 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/framer-motion": { + "version": "11.11.10", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.11.10.tgz", + "integrity": "sha512-061Bt1jL/vIm+diYIiA4dP/Yld7vD47ROextS7ESBW5hr4wQFhxB5D5T5zAc3c/5me3cOa+iO5LqhA38WDln/A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", diff --git a/package.json b/package.json index 62d64e3..e6aaf56 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "bcryptjs": "^2.4.3", "drizzle-kit": "^0.24.2", "drizzle-orm": "^0.33.0", + "framer-motion": "^11.11.10", "next": "14.2.5", "next-auth": "^5.0.0-beta.22", "nodemailer": "^6.9.15", diff --git a/src/app/contributors/page.tsx b/src/app/contributors/page.tsx new file mode 100644 index 0000000..8027d96 --- /dev/null +++ b/src/app/contributors/page.tsx @@ -0,0 +1,12 @@ +import ContributorPage from '@/components/ui/ContributorPage' +import React from 'react' + +const page = () => { + return ( + <> + + + ) +} + +export default page \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3e2b5f9..cd2f290 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -62,7 +62,7 @@ export default async function RootLayout({ }>) { const session = await auth(); const h = headers(); - const pathname = h.get("x-current-path"); + const pathname = h.get("x-current-path") || ""; if (session) { if (!session.user?.emailVerified) { diff --git a/src/components/ui/Contributor.css b/src/components/ui/Contributor.css new file mode 100644 index 0000000..a5370ab --- /dev/null +++ b/src/components/ui/Contributor.css @@ -0,0 +1,473 @@ +.profile-card-container { + border-radius: 0.5rem; + overflow: hidden; + border: 1px solid; + transition: all 0.3s ease-in-out; +} + +.profile-card-container:hover { + transform: translateY(-5px); + transition: all 0.3s ease-in-out; +} + +.profile-card-container-light { + background-color: white; + backdrop-filter: blur(0.5rem); + border-color: #d1d5db; +} + +.profile-card-container-dark { + background-color: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(1rem); + border-color: rgba(255, 255, 255, 0.1); +} + +.profile-card-content { + padding: 1.5rem; + text-align: center; +} + +.profile-card-avatar { + width: 6rem; + height: 6rem; + border-radius: 50%; + margin: 0 auto 1rem; + border-width: 4px; +} + +.profile-card-avatar-light { + border-color: #0a731f; +} + +.profile-card-avatar-dark { + border-color: #0a731f; +} + +.profile-card-title { + font-weight: bold; + font-size: 1.25rem; +} + +.profile-card-title-light { + color: #1f2937; +} + +.profile-card-title-dark { + color: white; +} + +.profile-card-type { + font-size: 0.875rem; + margin-bottom: 0.5rem; +} + +.profile-card-type-light { + color: #4b5563; +} + +.profile-card-type-dark { + color: #0b9b51; +} + +.profile-card-contributions { + margin-top: 1rem; + border-radius: 9999px; + padding: 0.5rem 1rem; + display: inline-block; +} + +.profile-card-contributions-light { + background-color: #d2fbff; +} + +.profile-card-contributions-dark { + background-color: rgba(255, 255, 255, 0.1); +} + +.profile-card-contributions-text-light { + font-weight: 600; + color: #004d25; +} + +.profile-card-contributions-text-dark { + font-weight: 600; + color: #179051; +} + +.profile-card-footer { + padding: 0.75rem 1.5rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.profile-card-footer-light { + background-color: #006019; +} + +.profile-card-footer-dark { + background-color: rgba(255, 255, 255, 0.05); +} + +.profile-card-profile-link { + display: flex; + align-items: center; + transition: color 0.2s; +} + +.profile-card-profile-link-light { + color: #fff; +} + +.profile-card-profile-link-dark { + color: white; +} + +.profile-card-profile-link:hover { + color: rgba(255, 255, 255, 0.8); +} + +.profile-card-github-icon { + color: rgba(255, 255, 255, 0.5); +} + + + + + + + + + + + +.stat-card-container { + border-radius: 0.5rem; + padding: 1.5rem; + display: flex; + align-items: center; + border-width: 1px; + transition: all 0.3s ease-in-out; +} + +.stat-card-container.dark-mode { + background-color: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(10px); + border-color: rgba(255, 255, 255, 0.1); +} + +.stat-card-container.light-mode { + background-color: #dbdbdb; + backdrop-filter: blur(4px); + border-color: #d1d5db; +} + +.stat-card-icon-container { + border-radius: 9999px; + padding: 0.75rem; + margin-right: 1rem; +} + +.stat-card-icon-container.dark-mode { + background-color: rgba(255, 255, 255, 0.1); +} + +.stat-card-icon-container.light-mode { + background-color: #e5e7eb; +} + +.stat-card-value { + font-size: 1.875rem; + font-weight: bold; +} + +.stat-card-value.dark-mode { + color: #ffffff; +} + +.stat-card-value.light-mode { + color: #1f2937; +} + +.stat-card-label { + font-size: 0.875rem; +} + +.stat-card-label.dark-mode { + color: rgba(255, 255, 255, 0.7); +} + +.stat-card-label.light-mode { + color: #4b5563; +} + + + + + +.page-container { + min-height: 100vh; + width: 100%; +} + +.page-container.dark-mode { + background: linear-gradient(to bottom right, #111827, #000); + color: #fff; +} + +.page-container.light-mode { + background: linear-gradient(to bottom right, #fff, #ebf8ff); + color: #000; +} + +/* Hero Section */ +.hero-section { + position: relative; + height: 45vh; + display: flex; + align-items: center; + justify-content: center; + text-align: center; +} + +.hero-section.dark-mode { + background: linear-gradient(to bottom right, #111827, #000, #1f2937); +} + +.hero-section.light-mode { + background: linear-gradient(to bottom right, #fff, #ebf8ff, #bfdbfe); +} + +.hero-overlay { + position: absolute; + inset: 0; + backdrop-filter: blur(4px); +} + +.hero-overlay.dark-mode { + background-color: rgba(0, 0, 0, 0.5); +} + +.hero-overlay.light-mode { + background-color: rgba(70, 100, 100, 0) +} + +.hero-content { + position: relative; + z-index: 10; + max-width: 64rem; + margin-left: auto; + margin-right: auto; + padding-left: 1rem; + padding-right: 1rem; +} + +.hero-heading { + font-size: 3rem; + font-weight: bold; +} + +.hero-heading.sm { + font-size: 4rem; +} + +.hero-heading.md { + font-size: 5rem; +} + +.hero-heading.dark-mode { + color: #fff; +} + +.hero-heading.light-mode { + color: #000; +} + +.hero-subheading { + font-size: 1.25rem; +} + +.hero-subheading.sm { + font-size: 1.5rem; +} + +.hero-subheading.dark-mode { + color: rgba(255, 255, 255, 0.8); +} + +.hero-subheading.light-mode { + color: rgba(0, 0, 0, 0.8); +} + +.stats-section { + padding: 4rem 1rem; +} + +.stats-section.dark-mode { + background-color: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(12px); +} + +.stats-section.light-mode { + background-color: rgba(255, 255, 255, 0.3); + backdrop-filter: blur(12px); +} + +.stats-container { + max-width: 112rem; + margin-left: auto; + margin-right: auto; +} + +.stats-heading { + font-size: 1.875rem; + font-weight: bold; + text-align: center; + margin-bottom: 3rem; +} + +.stats-heading.dark-mode { + color: #fff; +} + +.stats-heading.light-mode { + color: #000; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(1, 1fr); + gap: 2rem; +} + +@media (min-width: 768px) { + .stats-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 1024px) { + .stats-grid { + grid-template-columns: repeat(4, 1fr); + } +} + +.contributors-section { + padding: 4rem 1rem; +} + +.contributors-heading { + font-size: 1.875rem; + font-weight: bold; + text-align: center; + margin-bottom: 3rem; +} + +.contributors-heading.dark-mode { + color: #fff; +} + +.contributors-heading.light-mode { + color: #000; +} + +.contributors-grid { + display: grid; + grid-template-columns: repeat(1, 1fr); + gap: 2rem; +} + +@media (min-width: 640px) { + .contributors-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 1024px) { + .contributors-grid { + grid-template-columns: repeat(3, 1fr); + } +} + +.pagination-container { + margin-top: 2rem; + display: flex; + justify-content: center; +} + +.pagination-button { + margin-left: 0.25rem; + margin-right: 0.25rem; + padding: 0.5rem 1rem; + border-radius: 0.375rem; + transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out; +} + +.pagination-button.active { + background-color: #007bff; + color: #fff; +} + +.pagination-button.inactive { + background-color: #e0e0e0; + color: #333; +} + +.pagination-button.inactive:hover { + background-color: #d5d5d5; +} + +@media (prefers-color-scheme: dark) { + .pagination-button.inactive { + background-color: #444; + color: #f0f0f0; + } + + .pagination-button.inactive:hover { + background-color: #555; + } +} + +.theme-btn { + background: linear-gradient(135deg, #07be9b, #072015); + color: #fff; + border: none; + padding: 9px 7px; + font-size: 16px; + border-radius: 20px; + cursor: pointer; + font-weight: 600; + transition: background 0.4s ease-in-out, transform 0.8s ease, box-shadow 0.8s ease; + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); + letter-spacing: 0.5px; + position: absolute; + z-index: 9; + right: 0; + top: 0; +} + +.theme-btn:hover { + background: linear-gradient(135deg, #072015, #07be9b); + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.25); +} + +.theme-btn:active { + transform: translateY(1px) scale(0.98); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); +} + +.theme-btn:focus { + outline: none; + box-shadow: 0 0 10px rgba(0, 123, 255, 0.75); +} + +.theme-btn:disabled { + background: linear-gradient(135deg, #d3d3d3, #a9a9a9); + cursor: not-allowed; + opacity: 0.6; + box-shadow: none; +} + +.darkThemeBtn { + cursor: pointer; +} \ No newline at end of file diff --git a/src/components/ui/ContributorPage.tsx b/src/components/ui/ContributorPage.tsx new file mode 100644 index 0000000..5585e10 --- /dev/null +++ b/src/components/ui/ContributorPage.tsx @@ -0,0 +1,342 @@ +'use client'; + +import React, { useEffect, useState } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import '../ui/Contributor.css' + + +interface Contributor { + id: number; + login: string; + avatar_url: string; + html_url: string; + contributions: number; + type: string; + mode: string; +} + +interface RepoStats { + stars: number; + forks: number; + openIssues: number; +} + +const ContributorCard: React.FC = ({ + login, + avatar_url, + html_url, + contributions, + type, + mode, +}) => ( + +
+ {login} +

+ {login} +

+

+ {type} +

+
+ + {contributions} contributions + +
+
+
+ + + + + + View Profile + + + + +
+
+); + +interface StatCardProps { + label: string; + value: number; + icon: React.ReactNode; + mode: string; +} + +const StatCard: React.FC = ({ label, value, icon, mode }) => ( + +
+ {icon} +
+
+

+ {value} +

+

+ {label} +

+
+
+); + +export default function ContributorPage() { + const [contributors, setContributors] = useState([]); + const [repoStats, setRepoStats] = useState({ + stars: 0, + forks: 0, + openIssues: 0, + }); + const [loading, setLoading] = useState(true); + const [email, setEmail] = useState(''); + + const [currentPage, setCurrentPage] = useState(1); + const contributorsPerPage = 9; + + useEffect(() => { + const fetchData = async () => { + try { + let allContributors: Contributor[] = []; + let page = 1; + const perPage = 100; + + while (true) { + const contributorsResponse = await fetch( + `https://api.github.com/repos/ajaynegi45/Uttarakhand-Culture-NewUI/contributors?page=${page}&per_page=${perPage}`, + ); + + if (!contributorsResponse.ok) { + throw new Error('Failed to fetch contributors data'); + } + const contributorsData: Contributor[] = + await contributorsResponse.json(); + + if (contributorsData.length === 0) break; + + allContributors = [...allContributors, ...contributorsData]; + page++; + } + setContributors(allContributors); + + const repoResponse = await fetch( + 'https://api.github.com/repos/ajaynegi45/Uttarakhand-Culture-NewUI', + ); + const repoData = await repoResponse.json(); + setRepoStats({ + stars: repoData.stargazers_count, + forks: repoData.forks_count, + openIssues: repoData.open_issues_count, + }); + } catch (error) { + console.error('Error fetching data:', error); + } finally { + setLoading(false); + } + }; + + fetchData(); + }, []); + + const indexOfLastContributor = currentPage * contributorsPerPage; + const indexOfFirstContributor = indexOfLastContributor - contributorsPerPage; + const currentContributors = contributors.slice( + indexOfFirstContributor, + indexOfLastContributor, + ); + + const paginate = (pageNumber: number) => setCurrentPage(pageNumber); + + const totalPages = Math.ceil(contributors.length / contributorsPerPage); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + console.log('Submitted email:', email); + setEmail(''); + }; + + const scrollToNextSection = () => { + window.scrollBy({ + top: window.innerHeight, + behavior: 'smooth', + }); + }; + + const [mode, setMode] = useState('light'); + + // Function to toggle between light and dark mode + const toggleMode = () => { + setMode((prevMode) => (prevMode === "light" ? "dark" : "light")); + }; + + return ( +
+ + {/* Hero Section */} +
+
+
+
+ + + +
+
+
+
+
+ + Our Amazing Contributors + + + Shaping the future of Uttarakhand-Culture, one commit at a time + +
+
+ + {/* Statistics Section */} +
+
+

+ Project Statistics +

+
+ + } + /> + + + + } + /> + + } + /> + + + } + /> +
+
+
+ + {/* Contributors Section */} +
+
+

+ Meet Our Contributors +

+ {loading ? ( +

Loading...

+ ) : ( +
+ {currentContributors.map((contributor) => ( + + ))} +
+ )} + +
+ {Array.from({ length: totalPages }, (_, index) => ( + + ))} +
+
+
+
+ ); +} diff --git a/src/components/ui/Footer.tsx b/src/components/ui/Footer.tsx index 58ade76..e0498ad 100644 --- a/src/components/ui/Footer.tsx +++ b/src/components/ui/Footer.tsx @@ -14,7 +14,7 @@ export default function Footer() {
- +

Subscribe

@@ -41,7 +41,7 @@ export default function Footer() {

Contribution

Issues About us - Contribution + Contribution diff --git a/src/routes.ts b/src/routes.ts index 670c899..1c24099 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -3,7 +3,7 @@ * These routes do not require authentication * @type {string[]} */ -export const publicRoutes: string[] = ["/", "/explore", "/language", "/trekking", "/map", "/about"]; +export const publicRoutes: string[] = ["/", "/explore", "/language", "/trekking", "/map", "/about", "/contributors"]; /** * An array of routes that are used for authentication