diff --git a/.eslintrc.json b/.eslintrc.json index 3722418..56543d6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,8 @@ { - "extends": ["next/core-web-vitals", "next/typescript"] -} + "extends": ["next/core-web-vitals", "next/typescript"], + "rules": { + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-explicit-any": "warn", + "react-hooks/exhaustive-deps": "warn" + } +} \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index 7dd0d20..82f00bb 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,36 +1,33 @@ -import type { Metadata } from "next"; -import localFont from "next/font/local"; -import "./globals.css"; -import React from "react"; - -const geistSans = localFont({ - src: "./fonts/GeistVF.woff", - variable: "--font-geist-sans", - weight: "100 900", -}); -const geistMono = localFont({ - src: "./fonts/GeistMonoVF.woff", - variable: "--font-geist-mono", - weight: "100 900", -}); +import type { Metadata } from 'next' +import './globals.css' export const metadata: Metadata = { - title: "Quintavalle Pietro", - description: "My personal website", -}; + title: 'Pietro Quintavalle - Economics Student & Developer', + description: 'Economics student at USI with extensive data analytics and web development expertise. Google-certified in Data Analytics and IT Support.', + keywords: ['Pietro Quintavalle', 'Economics', 'Data Analytics', 'Web Development', 'Switzerland', 'USI'], + authors: [{ name: 'Pietro Quintavalle' }], + openGraph: { + title: 'Pietro Quintavalle - Economics Student & Developer', + description: 'Economics student at USI with extensive data analytics and web development expertise.', + url: 'https://your-domain.com', + siteName: 'Pietro Quintavalle Portfolio', + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title: 'Pietro Quintavalle - Economics Student & Developer', + description: 'Economics student at USI with extensive data analytics and web development expertise.', + }, +} export default function RootLayout({ children, -}: Readonly<{ - children: React.ReactNode; -}>) { +}: { + children: React.ReactNode +}) { return ( - - {children} - + {children} - ); -} + ) +} \ No newline at end of file diff --git a/components/Portfolio.tsx b/components/Portfolio.tsx new file mode 100644 index 0000000..7d55c1e --- /dev/null +++ b/components/Portfolio.tsx @@ -0,0 +1,721 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import { Github, Linkedin, Mail, ExternalLink, ChevronDown, Code, Database, BarChart3, Globe, Award, GraduationCap, Image, ExternalLink as LinkIcon } from 'lucide-react'; + +// Types +interface NordColors { + bg: string; + bgLight: string; + bgLighter: string; + bgLightest: string; + text: string; + textMuted: string; + accent: string; + blue: string; + darkBlue: string; + cyan: string; + green: string; + yellow: string; + orange: string; + red: string; + purple: string; +} + +interface Project { + title: string; + period: string; + description: string; + tech: string[]; + icon: React.ReactNode; + status: string; + images: string[]; + features: string[]; + github?: string; + demo?: string; +} + +interface Education { + institution: string; + degree: string; + period: string; + status: string; +} + +interface ProjectGalleryProps { + project: Project; + onClose: () => void; +} + +const Portfolio: React.FC = () => { + const [activeSection, setActiveSection] = useState('home'); + const [scrolled, setScrolled] = useState(false); + const [showProjectGallery, setShowProjectGallery] = useState(false); + + // Nord Color Palette + const nordColors: NordColors = { + bg: '#2E3440', + bgLight: '#3B4252', + bgLighter: '#434C5E', + bgLightest: '#4C566A', + text: '#D8DEE9', + textMuted: 'rgba(216, 222, 233, 0.6)', + accent: '#88C0D0', + blue: '#81A1C1', + darkBlue: '#5E81AC', + cyan: '#8FBCBB', + green: '#A3BE8C', + yellow: '#EBCB8B', + orange: '#D08770', + red: '#BF616A', + purple: '#B48EAD' + }; + + useEffect(() => { + const handleScroll = (): void => { + setScrolled(window.scrollY > 50); + }; + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, []); + + const skills: Record = { + 'Data & Analytics': ['Python', 'R', 'SQL', 'Statistical Analysis', 'Data Visualization', 'Business Intelligence'], + 'Web Development': ['JavaScript', 'TypeScript', 'React', 'Next.js', 'HTML5', 'CSS3', 'Tailwind CSS'], + 'Backend & Tools': ['Flask', 'Express', 'MongoDB', 'SQLite', 'Git', 'Linux'], + 'Other': ['Java', 'LaTeX', 'Project Planning', 'Financial Analysis'] + }; + + const projects: Project[] = [ + { + title: 'Valgo - Algorithm Visualizer', + period: 'Jun 2024 - Present', + description: 'Interactive web application designed to help users understand and visualize various sorting algorithms. Built with Next.js and React to make learning algorithms more engaging and intuitive.', + tech: ['Next.js', 'React', 'JavaScript', 'Algorithm Visualization'], + icon: , + status: 'Live', + images: [ + 'https://via.placeholder.com/600x400/81A1C1/2E3440?text=Algorithm+Visualizer', + 'https://via.placeholder.com/600x400/88C0D0/2E3440?text=Sorting+Demo', + 'https://via.placeholder.com/600x400/5E81AC/2E3440?text=Interactive+UI' + ], + features: ['Real-time algorithm visualization', 'Multiple sorting algorithms', 'Step-by-step breakdown', 'Performance comparison'], + github: 'https://github.com/Quinta0/valgo', + demo: 'https://valgo-demo.vercel.app' + }, + { + title: 'Boston Housing Price Prediction', + period: 'May 2024 - Present', + description: 'Machine learning model to predict housing prices in the Boston area based on various features such as crime rate, average number of rooms per dwelling, and accessibility to radial highways.', + tech: ['Python', 'Machine Learning', 'Data Analysis', 'Statistical Modeling'], + icon: , + status: 'In Progress', + images: [ + 'https://via.placeholder.com/600x400/A3BE8C/2E3440?text=Data+Visualization', + 'https://via.placeholder.com/600x400/EBCB8B/2E3440?text=ML+Model', + 'https://via.placeholder.com/600x400/D08770/2E3440?text=Results+Analysis' + ], + features: ['Predictive modeling', 'Feature engineering', 'Data visualization', 'Statistical analysis'], + github: 'https://github.com/Quinta0/boston-housing' + }, + { + title: 'Forest Fire Simulation', + period: 'Mar 2024 - Present', + description: 'Probability & Statistics course project modeling the spread of forest fires over a grid. Accounts for vegetation types, terrain elevation, wind patterns, humidity levels, and spontaneous ignition.', + tech: ['Python', 'Statistical Modeling', 'Simulation', 'Data Science'], + icon: , + status: 'Academic Project', + images: [ + 'https://via.placeholder.com/600x400/BF616A/2E3440?text=Fire+Simulation', + 'https://via.placeholder.com/600x400/B48EAD/2E3440?text=Statistical+Model', + 'https://via.placeholder.com/600x400/8FBCBB/2E3440?text=Data+Analysis' + ], + features: ['Monte Carlo simulation', 'Environmental factors modeling', 'Statistical analysis', 'Visualization tools'], + github: 'https://github.com/Quinta0/forest-fire-sim' + } + ]; + + const education: Education[] = [ + { + institution: 'USI Università della Svizzera italiana', + degree: "Bachelor's degree Economics", + period: 'Sep 2024 - Jun 2027', + status: 'Current' + }, + { + institution: 'USI Università della Svizzera italiana', + degree: 'Bachelor of Science - BS Informatics', + period: 'Jan 2022 - Jan 2024', + status: 'Completed' + }, + { + institution: 'Scuola cantonale di commercio', + degree: 'Maturità Cantonale e AFC Economics', + period: 'Sep 2017 - Jun 2021', + status: 'GPA: 4.5/5' + } + ]; + + const certificates: string[] = [ + 'Google Data Analytics Professional Certificate', + 'Google IT Support Professional Certificate', + 'IT Security: Defense against the digital dark arts', + 'Python for Data Science, AI & Development' + ]; + + const scrollToSection = (sectionId: string): void => { + document.getElementById(sectionId)?.scrollIntoView({ behavior: 'smooth' }); + setActiveSection(sectionId); + }; + + const ProjectGallery: React.FC = ({ project, onClose }) => ( +
+
e.stopPropagation()} + > +
+
+
+

+ {project.title} +

+
+ + {project.period} + + + {project.status} + +
+
+ +
+ + {/* Project Images */} +
+ {project.images.map((image: string, idx: number) => ( +
+ {`${project.title} +
+ ))} +
+ + {/* Description */} +
+

+ About This Project +

+

+ {project.description} +

+
+ + {/* Features */} +
+

+ Key Features +

+
+ {project.features.map((feature: string, idx: number) => ( +
+
+ {feature} +
+ ))} +
+
+ + {/* Tech Stack */} +
+

+ Technology Stack +

+
+ {project.tech.map((tech: string) => ( + + {tech} + + ))} +
+
+ + {/* Links */} +
+ {project.github && ( + + + View Code + + )} + {project.demo && ( + + + Live Demo + + )} +
+
+
+
+ ); + + return ( +
+ {/* Navigation */} + + + {/* Hero Section */} +
+
+
+

+ Pietro + Quintavalle +

+
+ Economics Student • Data Analytics • Web Development +
+

+ Passionate about the intersection of economics and technology, exploring how data and code can solve real-world problems. +

+
+ + +
+ +
+ +
+
+ + {/* About Section */} +
+
+

+ About Me +

+ +
+
+

+ I'm an Economics student at USI with extensive experience in data analytics and web development. + My journey combines analytical thinking with technical skills to create meaningful solutions. +

+

+ Google-certified in Data Analytics and IT Support, I bring proven expertise in Python, R, SQL, + and modern web technologies like Next.js and React. +

+
+ + Italian (Native) + + + English (C2) + + + Switzerland 🇨🇭 + +
+
+ +
+ {Object.entries(skills).map(([category, skillList]: [string, string[]]) => ( +
+

+ {category} +

+
+ {skillList.map((skill: string) => ( + + {skill} + + ))} +
+
+ ))} +
+
+
+
+ + {/* Projects Section */} +
+
+

+ Featured Projects +

+ +
+ {projects.map((project: Project, index: number) => ( +
setShowProjectGallery(project)} + > +
+
+ {project.icon} +
+
+

+ {project.title} +

+

+ {project.period} +

+
+
+ +

+ {project.description} +

+ +
+ {project.tech.map((tech: string) => ( + + {tech} + + ))} +
+ +
+ + + View Gallery + + + {project.status} + +
+
+ ))} +
+
+
+ + {/* Education & Certificates Section */} +
+
+

+ Education & Certifications +

+ +
+ {/* Education */} +
+

+ + Education +

+ +
+ {education.map((edu: Education, index: number) => ( +
+

+ {edu.degree} +

+

+ {edu.institution} +

+
+ + {edu.period} + + + {edu.status} + +
+
+ ))} +
+
+ + {/* Certificates */} +
+

+ + Certifications +

+ +
+ {certificates.map((cert: string, index: number) => ( +
+
+ {cert} +
+ ))} +
+ +
+

+ Interests +

+
+ {['Computer Hardware', 'Web Development', 'Finance', 'Economics', 'Literature'].map((interest: string) => ( + + {interest} + + ))} +
+
+
+
+
+
+ + {/* Contact Section */} +
+
+

+ Let's Connect +

+

+ I'm always interested in discussing new opportunities, collaborations, or just having a chat about technology and economics. +

+ + +
+
+ + {/* Footer */} +
+
+

+ Built with ❄️ using Next.js & Nord theme • Pietro Quintavalle © 2025 +

+
+
+ + {/* Project Gallery Modal */} + {showProjectGallery && ( + setShowProjectGallery(false)} + /> + )} +
+ ); +}; + +export default Portfolio; \ No newline at end of file diff --git a/lib/constants.ts b/lib/constants.ts new file mode 100644 index 0000000..bd0b44f --- /dev/null +++ b/lib/constants.ts @@ -0,0 +1,31 @@ +export const NORD_COLORS: NordColors = { + bg: '#2E3440', + bgLight: '#3B4252', + bgLighter: '#434C5E', + bgLightest: '#4C566A', + text: '#D8DEE9', + textMuted: 'rgba(216, 222, 233, 0.6)', + accent: '#88C0D0', + blue: '#81A1C1', + darkBlue: '#5E81AC', + cyan: '#8FBCBB', + green: '#A3BE8C', + yellow: '#EBCB8B', + orange: '#D08770', + red: '#BF616A', + purple: '#B48EAD' +}; + +export const SKILLS: Record = { + 'Data & Analytics': ['Python', 'R', 'SQL', 'Statistical Analysis', 'Data Visualization', 'Business Intelligence'], + 'Web Development': ['JavaScript', 'TypeScript', 'React', 'Next.js', 'HTML5', 'CSS3', 'Tailwind CSS'], + 'Backend & Tools': ['Flask', 'Express', 'MongoDB', 'SQLite', 'Git', 'Linux'], + 'Other': ['Java', 'LaTeX', 'Project Planning', 'Financial Analysis'] +}; + +export const CERTIFICATES: string[] = [ + 'Google Data Analytics Professional Certificate', + 'Google IT Support Professional Certificate', + 'IT Security: Defense against the digital dark arts', + 'Python for Data Science, AI & Development' +]; \ No newline at end of file diff --git a/next.config.mjs b/next.config.mjs index 4678774..1452eba 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,11 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + experimental: { + appDir: true, + }, + images: { + domains: ['via.placeholder.com'], + }, +} -export default nextConfig; +module.exports = nextConfig \ No newline at end of file diff --git a/package.json b/package.json index afcfe13..052f4cb 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,28 @@ { - "name": "personalwebsite", + "name": "pietro-portfolio", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "type-check": "tsc --noEmit" }, "dependencies": { - "@radix-ui/react-slot": "^1.1.0", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.1", - "lucide-react": "^0.441.0", - "next": "14.2.13", - "react": "^18", - "react-dom": "^18", - "tailwind-merge": "^2.5.2", - "tailwindcss-animate": "^1.0.7" + "next": "14.2.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "lucide-react": "^0.263.1" }, "devDependencies": { - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "eslint": "^8", - "eslint-config-next": "14.2.13", - "postcss": "^8", - "tailwindcss": "^3.4.1", - "typescript": "^5" + "@types/node": "^20.14.9", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "eslint": "^8.57.0", + "eslint-config-next": "14.2.4", + "postcss": "^8.4.39", + "tailwindcss": "^3.4.4", + "typescript": "^5.5.3" } -} +} \ No newline at end of file diff --git a/tailwind.config.ts b/tailwind.config.ts index ebc9f38..17eb3fa 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -8,49 +8,29 @@ const config: Config = { "./app/**/*.{js,ts,jsx,tsx,mdx}", ], theme: { - extend: { - colors: { - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))' - }, - popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))' - }, - primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))' - }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))' - }, - muted: { - DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))' - }, - accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))' - }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))' - }, - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - chart: { - '1': 'hsl(var(--chart-1))', - '2': 'hsl(var(--chart-2))', - '3': 'hsl(var(--chart-3))', - '4': 'hsl(var(--chart-4))', - '5': 'hsl(var(--chart-5))' - } - }, + extend: { + colors: { + nord: { + 0: '#2E3440', + 1: '#3B4252', + 2: '#434C5E', + 3: '#4C566A', + 4: '#D8DEE9', + 5: '#E5E9F0', + 6: '#ECEFF4', + 7: '#8FBCBB', + 8: '#88C0D0', + 9: '#81A1C1', + 10: '#5E81AC', + 11: '#BF616A', + 12: '#D08770', + 13: '#EBCB8B', + 14: '#A3BE8C', + 15: '#B48EAD', + }, + }, + }, + }, borderRadius: { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', diff --git a/tsconfig.json b/tsconfig.json index e7ff90f..8b63fb1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], + "lib": ["dom", "dom.iterable", "es6"], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -17,10 +17,14 @@ "name": "next" } ], + "baseUrl": ".", "paths": { - "@/*": ["./*"] + "@/*": ["./src/*"], + "@/components/*": ["./src/components/*"], + "@/lib/*": ["./src/lib/*"], + "@/types/*": ["./src/types/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] -} +} \ No newline at end of file