From 832be077f7ab1a56a52c8798f4340be0a36ac9db Mon Sep 17 00:00:00 2001 From: Matz Hilven Date: Mon, 10 Jun 2024 14:33:20 +0200 Subject: [PATCH] improvements --- src/app/layout.tsx | 19 ++++++-- src/app/page.tsx | 96 +----------------------------------- src/app/projects/page.tsx | 99 ++++++++++++++++++++++++++++++++++++++ src/components/NavLink.tsx | 18 +++++++ src/components/Navbar.tsx | 39 +++++++++++++++ tailwind.config.ts | 21 +++----- 6 files changed, 179 insertions(+), 113 deletions(-) create mode 100644 src/app/projects/page.tsx create mode 100644 src/components/NavLink.tsx create mode 100644 src/components/Navbar.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 6e31a38..fcb8309 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -4,25 +4,34 @@ import '@mantine/core/styles.css' import type { Metadata } from 'next' import React from 'react' import { ColorSchemeScript, MantineProvider } from '@mantine/core' - +import { Montserrat } from 'next/font/google' +import Navbar from '@/components/Navbar' export const metadata: Metadata = { - title: 'Matz Hilven', + title: 'Matz Hilven | Software Engineer', description: 'todo', } +const font = Montserrat({ + subsets: ['latin'], + display: 'swap', +}) + export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( - + -
- {children} +
+ +
+ {children} +
diff --git a/src/app/page.tsx b/src/app/page.tsx index ce71969..5449e07 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,99 +1,5 @@ -'use client' - -import React, { useState, useEffect, useMemo } from 'react' -import { ProjectCard } from '@/components/ProjectCard' -import projectsData from '../../public/projects.json' -import { projectsSchema, Project } from '@/typings/project' -import { useInView } from 'react-intersection-observer' - const Page = () => { - const parsedProjects = projectsSchema.safeParse(projectsData) - - if (!parsedProjects.success) { - console.error('Invalid project data', parsedProjects.error) - return
Error loading projects
- } - - const projects: Project[] = parsedProjects.data - - const [currentPage, setCurrentPage] = useState(1) - const [itemsPerPage] = useState(12) - const [filterTag, setFilterTag] = useState(null) - const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc') - - const { ref, inView } = useInView({ - threshold: 1.0, - }) - - const handleFilterChange = (event: React.ChangeEvent) => { - setFilterTag(event.target.value === 'All' ? null : event.target.value) - setCurrentPage(1) - } - - const handleSortChange = (event: React.ChangeEvent) => { - setSortOrder(event.target.value as 'asc' | 'desc') - setCurrentPage(1) - } - - const filteredAndSortedProjects = useMemo(() => { - let updatedProjects = filterTag - ? projects.filter(project => project.tags.includes(filterTag)) - : projects - - updatedProjects = [...updatedProjects].sort((a, b) => { - if (sortOrder === 'asc') { - return a.name.localeCompare(b.name) - } else { - return b.name.localeCompare(a.name) - } - }) - - return updatedProjects - }, [projects, filterTag, sortOrder]) - - const visibleProjects = useMemo(() => { - return filteredAndSortedProjects.slice(0, currentPage * itemsPerPage) - }, [filteredAndSortedProjects, currentPage, itemsPerPage]) - - useEffect(() => { - if ( - inView && - currentPage * itemsPerPage < filteredAndSortedProjects.length - ) { - setCurrentPage(prevPage => prevPage + 1) - } - }, [inView, currentPage, itemsPerPage, filteredAndSortedProjects.length]) - - return ( -
-
- - -
-
- {visibleProjects.map((project, index) => ( - - ))} -
-
-
- ) + return
hey
} export default Page diff --git a/src/app/projects/page.tsx b/src/app/projects/page.tsx new file mode 100644 index 0000000..d5aff24 --- /dev/null +++ b/src/app/projects/page.tsx @@ -0,0 +1,99 @@ +'use client' + +import React, { useState, useEffect, useMemo } from 'react' +import { ProjectCard } from '@/components/ProjectCard' +import projectsData from '../../../public/projects.json' +import { projectsSchema, Project } from '@/typings/project' +import { useInView } from 'react-intersection-observer' + +const Page = () => { + const parsedProjects = projectsSchema.safeParse(projectsData) + + if (!parsedProjects.success) { + console.error('Invalid project data', parsedProjects.error) + return
Error loading projects
+ } + + const projects: Project[] = parsedProjects.data + + const [currentPage, setCurrentPage] = useState(1) + const [itemsPerPage] = useState(12) + const [filterTag, setFilterTag] = useState(null) + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc') + + const { ref, inView } = useInView({ + threshold: 1.0, + }) + + const handleFilterChange = (event: React.ChangeEvent) => { + setFilterTag(event.target.value === 'All' ? null : event.target.value) + setCurrentPage(1) + } + + const handleSortChange = (event: React.ChangeEvent) => { + setSortOrder(event.target.value as 'asc' | 'desc') + setCurrentPage(1) + } + + const filteredAndSortedProjects = useMemo(() => { + let updatedProjects = filterTag + ? projects.filter(project => project.tags.includes(filterTag)) + : projects + + updatedProjects = [...updatedProjects].sort((a, b) => { + if (sortOrder === 'asc') { + return a.name.localeCompare(b.name) + } else { + return b.name.localeCompare(a.name) + } + }) + + return updatedProjects + }, [projects, filterTag, sortOrder]) + + const visibleProjects = useMemo(() => { + return filteredAndSortedProjects.slice(0, currentPage * itemsPerPage) + }, [filteredAndSortedProjects, currentPage, itemsPerPage]) + + useEffect(() => { + if ( + inView && + currentPage * itemsPerPage < filteredAndSortedProjects.length + ) { + setCurrentPage(prevPage => prevPage + 1) + } + }, [inView, currentPage, itemsPerPage, filteredAndSortedProjects.length]) + + return ( +
+
+ + +
+
+ {visibleProjects.map((project, index) => ( + + ))} +
+
+
+ ) +} + +export default Page diff --git a/src/components/NavLink.tsx b/src/components/NavLink.tsx new file mode 100644 index 0000000..de0c6aa --- /dev/null +++ b/src/components/NavLink.tsx @@ -0,0 +1,18 @@ +import Link from 'next/link' + +type NavLinkProps = { + href: string + isActive: boolean + label: string +} + +const NavLink = ({ href, isActive, label }: NavLinkProps) => { + return ( +
+ {label} + +
+ ) +} + +export default NavLink diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx new file mode 100644 index 0000000..b07144a --- /dev/null +++ b/src/components/Navbar.tsx @@ -0,0 +1,39 @@ +'use client' + +import React from 'react' +import { usePathname } from 'next/navigation' +import NavLink from './NavLink' +import Link from 'next/link' + +const routes = [ + { path: '/', label: 'About' }, + { path: '/projects', label: 'Projects' }, + { path: '/homelab', label: 'Homelab' }, + { path: '/contact', label: 'Contact' }, +] + +const Navbar = () => { + const pathname = usePathname() + + return ( + + ) +} + +export default Navbar diff --git a/tailwind.config.ts b/tailwind.config.ts index 70c2aeb..c039606 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -2,21 +2,9 @@ import type { Config } from 'tailwindcss' const config = { darkMode: ['class'], - content: [ - './pages/**/*.{ts,tsx}', - './components/**/*.{ts,tsx}', - './app/**/*.{ts,tsx}', - './src/**/*.{ts,tsx}', - ], + content: ['./src/**/*.{ts,tsx}'], prefix: '', theme: { - container: { - center: true, - padding: '2rem', - screens: { - '2xl': '1400px', - }, - }, extend: { dropShadow: { glow: [ @@ -25,6 +13,12 @@ const config = { ], }, keyframes: { + gradient: { + '0%, 100%': { backgroundPosition: '0% 50%' }, + '25%': { backgroundPosition: '100% 0%' }, + '50%': { backgroundPosition: '100% 100%' }, + '75%': { backgroundPosition: '0% 100%' }, + }, jump: { '0%, 100%': { transform: 'translateY(0)' }, '50%': { transform: 'translateY(-10px)' }, @@ -32,6 +26,7 @@ const config = { }, animation: { jump: 'jump 0.4s ease-in-out', + gradient: 'gradient 10s ease infinite', }, }, },