diff --git a/src/components/Section.tsx b/src/components/Section.tsx index 0573d63..38c4ea9 100644 --- a/src/components/Section.tsx +++ b/src/components/Section.tsx @@ -3,12 +3,12 @@ import { mergeSxProps } from '../utils' export type SectionProps = { - title: string + title?: string } & StackProps export const Section = ({title, children, sx, ...rest}: SectionProps) => ( - {title} + {title && {title}} {children} ) diff --git a/src/configs/projects.json b/src/configs/projects.json new file mode 100644 index 0000000..7bf3a4f --- /dev/null +++ b/src/configs/projects.json @@ -0,0 +1,87 @@ +{ + "Pie-Hub": { + "relevancy": [ + "fe", + "be" + ], + "date": { + "start": 2021 + }, + "tech": [ + "Raspberry Pi 4", + "General Purpose I/O", + "I2C", + "Python", + "Bash", + "UNIX services", + "Node.js", + "TypeScript" + ], + "summary": "React app with back end running on a Raspberry Pi. Shows useful information in one place including: room temperature and humidity, task list from Notion, and time.", + "description": [ + "React app hosted on a single-board computer (RPi) along with a RESTful API written with Express.js", + "Wrote a proxy service for Notion (the app then displays a task list)", + "Connected an indoor temperature and humidity sensor", + "Wired up a relay board to control appliances through software" + ] + }, + "Rychly Portfolio": { + "tech": [ + "React" + ], + "date": { + "start": 2023, + "ongoing": true + }, + "summary": "Responsive React app that shows off who I am as a professional and a bit more.", + "description": [ + "The 'Fast' Portfolio ([What does Rychly mean?](https://translate.google.com/details?sl=cs&tl=en&text=rychl%C3%BD&op=translate))", + "Responsive design, uses Material UI and React Router", + "Content can be easily updated through YAML configuration files", + "Main page filters content based on the selected type of developer" + ] + }, + "Game Development in Haskell": { + "relevancy": [ + "fe", + "be" + ], + "date": { + "finish": "May 2021" + }, + "tech": [ + "Haskell", + "apecs (Entity Component System)" + ], + "summary": "Bachelor's thesis exploring the limits of functional programming when used in realtime applications, specifically games.", + "description": [ + "Bachelor's thesis exploring the limits of functional programming when used in realtime applications, specifically games." + ] + }, + "pure-asteroids": { + "date": { + "finish": "Apr 2021" + }, + "tech": [ + "Haskell", + "SDL2" + ], + "summary": "An atempt at a purely functional game engine focusing on type safety and clarity.", + "description": [ + "An atempt at a purely functional game engine focusing on type safety and clarity." + ] + }, + "hAsteroids": { + "date": { + "finish": "Apr 2021" + }, + "tech": [ + "Haskell", + "SDL2" + ], + "summary": "Game in Haskell built using the apecs library.", + "description": [ + "Game in Haskell built using the apecs library." + ] + } +} diff --git a/src/configs/projects.yaml b/src/configs/projects.yaml new file mode 100644 index 0000000..0dd24f2 --- /dev/null +++ b/src/configs/projects.yaml @@ -0,0 +1,64 @@ +Pie-Hub: + relevancy: [fe, be] + date: + start: 2021 + tech: + - Raspberry Pi 4 + - General Purpose I/O + - I2C + - Python + - Bash + - UNIX services + - Node.js + - TypeScript + summary: "React app with back end running on a Raspberry Pi. Shows useful information in one place including: room temperature and humidity, task list from Notion, and time." + description: + - React app hosted on a single-board computer (RPi) along with a RESTful API written with Express.js + - Wrote a proxy service for Notion (the app then displays a task list) + - Connected an indoor temperature and humidity sensor + - Wired up a relay board to control appliances through software + + +Rychly Portfolio: + tech: + - React + date: + start: 2023 + ongoing: true + summary: Responsive React app that shows off who I am as a professional and a bit more. + description: + - The 'Fast' Portfolio ([What does Rychly mean?](https://translate.google.com/details?sl=cs&tl=en&text=rychl%C3%BD&op=translate)) + - Responsive design, uses Material UI and React Router + - Content can be easily updated through YAML configuration files + - Main page filters content based on the selected type of developer + +Game Development in Haskell: + relevancy: [fe, be] + date: + finish: May 2021 + tech: + - Haskell + - apecs (Entity Component System) + summary: Bachelor's thesis exploring the limits of functional programming when used in realtime applications, specifically games. + description: + - Bachelor's thesis exploring the limits of functional programming when used in realtime applications, specifically games. + +pure-asteroids: + date: + finish: Apr 2021 + tech: + - Haskell + - SDL2 + summary: An atempt at a purely functional game engine focusing on type safety and clarity. + description: + - An atempt at a purely functional game engine focusing on type safety and clarity. + +hAsteroids: + date: + finish: Apr 2021 + tech: + - Haskell + - SDL2 + summary: Game in Haskell built using the apecs library. + description: + - Game in Haskell built using the apecs library. diff --git a/src/pages/LandingPage/LandingPage.tsx b/src/pages/LandingPage/LandingPage.tsx index 113735e..7119973 100644 --- a/src/pages/LandingPage/LandingPage.tsx +++ b/src/pages/LandingPage/LandingPage.tsx @@ -5,6 +5,7 @@ import { FilterSelector } from './FilterSelector' import { ExperienceList } from './ExperienceList' import { EducationList } from './EducationList' import { Todo } from '../../components/Todo' +import { ProjectList } from './ProjectList' export const LandingPage = () => ( @@ -45,7 +46,7 @@ export const LandingPage = () => ( - + ) diff --git a/src/pages/LandingPage/index.tsx b/src/pages/LandingPage/index.tsx index ee110fd..581cbe6 100644 --- a/src/pages/LandingPage/index.tsx +++ b/src/pages/LandingPage/index.tsx @@ -1,3 +1 @@ -import { LandingPage } from './LandingPage' - -export { LandingPage } +export { LandingPage } from './LandingPage' diff --git a/src/pages/Things/Project.tsx b/src/pages/Things/Project.tsx new file mode 100644 index 0000000..39e7794 --- /dev/null +++ b/src/pages/Things/Project.tsx @@ -0,0 +1,39 @@ +import { Card, CardProps, Typography } from '@mui/material' +import { ListFromMd } from '../../components/ListFromMd' +import _ from 'lodash' +import { SpanFromMd } from '../../components/SpanFromMd' + + +// TODO flag for projects that are displayed on the landing page vs only on the things page +type ProjectDetails = { + name: string + summary: string + description: string[] + tech: string[] + date: { + start?: string | number + finish?: string | number + ongoing?: boolean + } +} + +type ProjectProps = { + details: ProjectDetails + summary?: boolean +} & CardProps + +export const Project = ({ details, summary, ...props }: ProjectProps) => ( + + {details.name} + + {[ + details.date.start, + details.date.ongoing ? 'Ongoing' : details.date.finish, + ].filter(_.identity).join('–')} + + {summary + ? + : + } + +) \ No newline at end of file diff --git a/src/pages/Things/Things.tsx b/src/pages/Things/Things.tsx index e695a2b..100c821 100644 --- a/src/pages/Things/Things.tsx +++ b/src/pages/Things/Things.tsx @@ -1,12 +1,37 @@ import { Box, Typography } from '@mui/material' -import { Todo } from '../../components/Todo' +import rawProjects from '../../configs/projects.json' +import { unKeyBy } from '../../utils' +import { useMemo } from 'react' +import { Project } from './Project' +import { Section } from '../../components/Section' -export const Things = () => ( - - I like people. They are what matters. - But as an engineer I like things even more. Designing them. Making them. - Here are some of my favorite things I have made, including software and hardware. - - -) +export const getProjects = () => unKeyBy(rawProjects, 'name') + +export const Things = () => { + const projects = useMemo(getProjects, []) + + return ( + + I like people. They are what matters. + + But as an engineer I like
+ + Things + +
even more +
+ + I enjoy designing them, making them, and improving them. + + Here are some of my favorites that I have made, including software and hardware. +
+ {projects.map((project, i) => )} +
+
+ )} diff --git a/src/pages/Things/index.tsx b/src/pages/Things/index.tsx new file mode 100644 index 0000000..e626a85 --- /dev/null +++ b/src/pages/Things/index.tsx @@ -0,0 +1 @@ +export { Things } from './Things' diff --git a/src/utils.ts b/src/utils.ts index 08b2346..475b622 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,9 +5,14 @@ import { Converter } from 'showdown' type ObjectOfObjects = { [k: string]: object } -/** Sort of the reverse to `keyBy` from lodash */ -export const unKeyBy = (obj: T, keyProp: string) => - _.map(obj, (val, key) => ({...val, [keyProp]: key })) +/** Sort of the reverse of `keyBy` from lodash */ +export const unKeyBy = ( + obj: T, + keyProp: KeyProp, +) => _.map(obj, (val, key) => ( + {...val, [keyProp]: key } + ) as T[keyof T] & { [K in KeyProp]: keyof T } + ) /** Mainly useful when we know `o` has a single key */ export const getFirstKey = >(o: Obj) => Object.keys(o)[0]