Skip to content

Commit

Permalink
Feat: Add project images and badge generator
Browse files Browse the repository at this point in the history
  • Loading branch information
rudyorre committed Dec 31, 2023
1 parent a496ff6 commit ea99126
Show file tree
Hide file tree
Showing 25 changed files with 245 additions and 59 deletions.
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"node": "^21.2.0",
"react": "^18",
"react-dom": "^18",
"react-intersection-observer": "^9.5.3",
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7"
},
Expand Down
Binary file added public/images/brewin-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/bstmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/cookies.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/multivariatelinearregression.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/ngram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/obstagoon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/portfolio.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/pos-tagger.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/scramble.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/smartpointer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/tensorfaux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/vit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Cards } from '@/components/cards';

import { Projects } from '@/components/projects';
import { Experience } from '@/components/experience';
import Hero from '@/components/hero';
import { Timeline } from '@/components/timeline';
Expand All @@ -12,9 +13,12 @@ export default function Home() {
rudyorre/<h1 className="text-6xl font-bold tracking-tight">Experience</h1>
<br />
<Experience />
<br />
<br />
<br />
rudyorre/<h1 className="text-6xl font-bold tracking-tight">Projects</h1>
<br />
<Cards />
<Projects />
</div>
)
}
15 changes: 14 additions & 1 deletion src/components/animation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
'use client';

import { useEffect, useState } from 'react';

export const Animation = () => {
// const [hsl, setHsl] = useState<string[]>([]);
// useEffect(() => {
// const HSL = window.getComputedStyle(document.documentElement)
// .getPropertyValue('--destructive')
// .split(/\s+/);
// setHsl(HSL);
// }, []);

return <div>
<svg
className="BgAnimation__svg"
Expand Down Expand Up @@ -40,7 +52,8 @@ export const Animation = () => {
<path
d="M294.685 193.474L268.932 219.258"
transform="translate(-294.685 -193.474) rotate(45 294.685 193.474)"
stroke="url(#paint3_linear)"
// stroke={`hsl(${hsl[0]}, ${hsl[1]}, ${hsl[2]})`}
stroke="url(#paint3_linear)"
>
<animateMotion dur="10s" repeatCount="indefinite" rotate="auto">
<mpath xlinkHref="#path_2" />
Expand Down
50 changes: 26 additions & 24 deletions src/components/cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

import { Button } from '@/components/ui/button';
import React, { useState, useEffect, useRef } from 'react';
import { useInView } from 'react-intersection-observer';
import { cn } from '@/lib/utils';
import styles from '@/components/styles/cards.module.css';
import { Project as ProjectType } from '@/constants/projects';

interface CardProps {
icon: string;
title: string;
subtitle: string;
parentMouseX: number;
parentMouseY: number;
project: ProjectType;
parentMouseX: number;
parentMouseY: number;
}

export function Cards() {
export function Cards({projects}: {projects: ProjectType[]}) {
const [mouseX, setMouseX] = useState<number>(0);
const [mouseY, setMouseY] = useState<number>(0);
const cardsRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -45,24 +45,25 @@ return (
)}
>
<div ref={cardsRef} id="cards" className="flex flex-wrap gap-[8px] justify-center mx-auto">
<Card icon="fa-duotone fa-apartment" title="Apartments" subtitle="Places to be apart. Wait, what?" parentMouseX={mouseX} parentMouseY={mouseY} />
<Card icon="fa-duotone fa-unicorn" title="Unicorns" subtitle="A single corn. Er, I mean horn." parentMouseX={mouseX} parentMouseY={mouseY} />
<Card icon="fa-duotone fa-apartment" title="Apartments" subtitle="Places to be apart. Wait, what?" parentMouseX={mouseX} parentMouseY={mouseY} />
<Card icon="fa-duotone fa-unicorn" title="Unicorns" subtitle="A single corn. Er, I mean horn." parentMouseX={mouseX} parentMouseY={mouseY} />
<Card icon="fa-duotone fa-apartment" title="Apartments" subtitle="Places to be apart. Wait, what?" parentMouseX={mouseX} parentMouseY={mouseY} />
<Card icon="fa-duotone fa-unicorn" title="Unicorns" subtitle="A single corn. Er, I mean horn." parentMouseX={mouseX} parentMouseY={mouseY} />
<Card icon="fa-duotone fa-apartment" title="Apartments" subtitle="Places to be apart. Wait, what?" parentMouseX={mouseX} parentMouseY={mouseY} />
<Card icon="fa-duotone fa-unicorn" title="Unicorns" subtitle="A single corn. Er, I mean horn." parentMouseX={mouseX} parentMouseY={mouseY} />
{projects.map((project: ProjectType, i: number) => (
<Card
key={i}
project={project}
parentMouseX={mouseX}
parentMouseY={mouseY}
/>
))}
</div>
</div>
);
}

function Card({ icon, title, subtitle, parentMouseX, parentMouseY }: CardProps) {
function Card({ project, parentMouseX, parentMouseY }: CardProps) {
const [mouseX, setMouseX] = useState<number>(0);
const [mouseY, setMouseY] = useState<number>(0);
const [isHovered, setIsHovered] = useState(false);
const cardsRef = useRef<HTMLDivElement>(null);
const { ref, inView } = useInView({ threshold: 0.9 });

useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
Expand All @@ -86,7 +87,7 @@ useEffect(() => {
return () => {
cardsRef.current?.removeEventListener('mousemove', handleMouseMove);
};
}, [cardsRef, parentMouseX, parentMouseY]);
}, [cardsRef, parentMouseX, parentMouseY, inView]);

const gradientOpacity = isHovered ? 0.1 : 0;

Expand All @@ -95,8 +96,9 @@ const hsl = window.getComputedStyle(document.documentElement).getPropertyValue('

return (
<div
className="bg-[rgba(255,255,255,0.1)] rounded-lg group"
style={{ background: `radial-gradient(800px circle at ${mouseX}px ${mouseY}px, hsla(${hsl[0]}, ${hsl[1]}, ${hsl[2]}, ${gradientOpacity * 5}), transparent 40%)` }}
ref={ref}
className={`bg-[rgba(255,255,255,0.1)] group rounded-lg`}
style={{ background: `radial-gradient(800px circle at ${mouseX}px ${mouseY}px, hsla(${hsl[0]}, ${hsl[1]}, ${hsl[2]}, ${gradientOpacity * 5}), transparent 40%)` }}
>
<div
className="bg-muted rounded-lg h-[calc(100%-2px)] w-[calc(100%-2px)] m-[1px]"
Expand All @@ -109,22 +111,22 @@ return (
<div className="overflow-hidden">
<img
className="w-full transform transition-transform duration-300 ease-in-out group-hover:scale-105"
src="http://rudyorre.com/images/brewin-logo.png"
src={project.image}
style={{
aspectRatio: "450/200",
objectFit: "cover",
}}
/>
</div>
<div className="p-4">
<h3 className="text-lg font-bold">Performance RNN</h3>
<p className="text-sm">Enjoy a real-time piano performance by a neural network.</p>
<h3 className="text-lg font-bold">{project.title}</h3>
<p className="text-sm">{project.description}</p>
<div className="flex space-x-2 mt-4">
<Button className="block" variant="default">
Explore demo
Explore demo
</Button>
<Button className="block" variant="outline">
View code
<Button className="block" variant="default">
View code
</Button>
</div>
</div>
Expand Down
7 changes: 4 additions & 3 deletions src/components/experience.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ import { Button } from '@/components/ui/button';

export const Experience = () => {
const [isOpen, setIsOpen] = useState<boolean>(false);
return <>

return <div>
<Timeline jobs={jobs.filter((job: Job) => job.featured)} />
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="item-1">
<AccordionContent>
<AccordionContent className="bg-muted pt-4 rounded-lg">
<Timeline jobs={jobs.filter((job: Job) => !job.featured)} />
</AccordionContent>
<AccordionTrigger className="mx-20">
<Button onClick={() => setIsOpen(!isOpen)}>{(isOpen) ? 'Close' : 'See More'}</Button>
</AccordionTrigger>
</AccordionItem>
</Accordion>
</>;
</div>;
};
8 changes: 4 additions & 4 deletions src/components/hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { Animation } from '@/components/animation';
import { Button } from '@/components/ui/button';

const Hero = () => (
<div className="grid grid-cols-2">
<div className="grid sm:grid-cols-2">
<div className="col-auto m-auto">
<h2 className="text-accent-foreground">
Hi, my name is
</h2>
<h1 className="text-6xl font-bold tracking-tight">
<h1 className="text-6xl font-bold tracking-tight my-1">
Rudy Orre.
</h1>
<div>
I build full-stack solutions.
I craft solutions through code.
</div>
{/* <a
style={{ color: "white" }}
Expand All @@ -22,7 +22,7 @@ const Hero = () => (
</Button>
</a> */}
</div>
<div className="col-auto max-w-[520px]">
<div className="sm:block hidden col-auto max-w-[520px]">
<Animation />
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions src/components/projects.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Cards } from '@/components/cards';
import { projects, Project as ProjectType } from '@/constants/projects';

export const Projects = () => {
return <div>
<Cards projects={projects.filter((p: ProjectType) => p.featured)} />
</div>;
};
5 changes: 3 additions & 2 deletions src/components/timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
AccordionTrigger,
} from '@/components/ui/minimal-accordion';
import { Job } from '@/constants/jobs';
import { generate } from '@/lib/badge-generator';

interface TimelineProps {
jobs: Job[],
Expand All @@ -24,7 +25,7 @@ export const Timeline = ({jobs}: TimelineProps) => {
<path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>
</svg>
</span>
<h3 className="flex items-center mb-1 text-lg font-semibold text-gray-900 dark:text-white">{job.role} <span className="bg-blue-100 text-blue-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300 ms-3">{job.company}</span></h3>
<h3 className="flex items-center mb-1 text-lg font-semibold text-gray-900 dark:text-white">{job.role} <span className="hidden sm:block bg-blue-100 text-blue-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300 ms-3">{job.company}</span></h3>
<time className="block mb-2 text-sm font-normal leading-none text-muted-foreground">{job.dates}</time>
</AccordionTrigger>
<AccordionContent className="mb-4 text-base font-normal text-muted-foreground">
Expand All @@ -38,7 +39,7 @@ export const Timeline = ({jobs}: TimelineProps) => {
</Accordion>
<div className="mt-1 flex gap-1">
{job.tags.map((tag: string, i: number) => (
<img key={job.role + job.company + 'tags' + i} src={tag} />
<img key={job.role + job.company + 'tags' + i} src={generate(tag)} />
))}
</div>
</li>
Expand Down
31 changes: 31 additions & 0 deletions src/constants/badges.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* A Map containing badge information, where keys are badge names and values are badge image URLs.
*
* Badges are commonly used to visually represent technologies, tools, or platforms used in a project.
*
* @remarks
* - Badge styling is mostly derived from https://github.com/Ileriayo/markdown-badges.
* - Consider using a dedicated badge library for more advanced features and customization options.
*/
export const badges: Map<string, string> = new Map(
Object.entries({
'python': 'https://img.shields.io/badge/Python-3670A0?style=flat&logo=python&logoColor=ffdd54',
'gitlab ci/cd': 'https://img.shields.io/badge/Gitlab%20CI/CD-%23181717.svg?style=flat&logo=gitlab&logoColor=white',
'next': 'https://img.shields.io/badge/Next-black?style=flat&logo=next.js&logoColor=white',
'postgres': 'https://img.shields.io/badge/Postgres-%23316192.svg?style=flat&logo=postgresql&logoColor=white',
'docker': 'https://img.shields.io/badge/Docker-%230db7ed.svg?style=flat&logo=docker&logoColor=white',
'pytorch': 'https://img.shields.io/badge/PyTorch-%23EE4C2C.svg?style=flat&logo=PyTorch&logoColor=white',
'pandas': 'https://img.shields.io/badge/Pandas-%23150458.svg?style=flat&logo=pandas&logoColor=white',
'jupyter': 'https://img.shields.io/badge/Jupyter-%23FA0F00.svg?style=flat&logo=jupyter&logoColor=white',
'javascript': 'https://img.shields.io/badge/JavaScript-%23323330.svg?style=flat&logo=javascript&logoColor=%23F7DF1E',
'cpp': 'https://img.shields.io/badge/C++-%2300599C.svg?style=flat&logo=c%2B%2B&logoColor=white',
'java': 'https://img.shields.io/badge/Java-%23ED8B00.svg?style=flat&logo=openjdk&logoColor=white',
'vs': 'https://img.shields.io/badge/Visual%20Studio-5C2D91.svg?style=flat&logo=visual-studio&logoColor=white',
'django': 'https://img.shields.io/badge/Django-%23092E20.svg?style=flat&logo=django&logoColor=white',
'sklearn': 'https://img.shields.io/badge/Scikit--Learn-%23F7931E.svg?style=flat&logo=scikit-learn&logoColor=white',
'tensorflow': 'https://img.shields.io/badge/TensorFlow-%23FF6F00.svg?style=flat&logo=TensorFlow&logoColor=white',
'shell': 'https://img.shields.io/badge/Shell-%23121011.svg?style=flat&logo=gnu-bash&logoColor=white',
'scipy': 'https://img.shields.io/badge/SciPy-%230C55A5.svg?style=flat&logo=scipy&logoColor=%white',
'selenium': 'https://img.shields.io/badge/Selenium-43B02A.svg?&style=flat&logo=selenium&logoColor=white',
})
);
Loading

0 comments on commit ea99126

Please sign in to comment.