Jobs history sourced from personal data

This commit is contained in:
Dejvino 2023-05-25 15:29:51 +02:00
parent 9edf9777a0
commit 2308c0394b
12 changed files with 120 additions and 47 deletions

View File

@ -1,11 +0,0 @@
export const Person = {
name: "David Hrdina Němeček",
brief: "Software developer, people manager.",
skills: {
primary: ['Java', 'TypeScript', 'JavaScript'],
secondary: ['Kotlin', 'Go'],
others: ['Driver\'s license (B)']
},
interests: ['Guitars and Heavy Metal', 'Mazda MX-5', 'DIY electronics'],
};

29
src/PersonalData.ts Normal file
View File

@ -0,0 +1,29 @@
import { PersonalData } from "./PersonalDataTypes";
export const personalData: PersonalData = {
name: "David Hrdina Němeček",
brief: "Software developer, people manager.",
jobs: {
current: {
position: 'Janitor',
company: 'Cleaners Limited',
timerange: '2022 - present',
description: 'Cleanup duty 24/7.',
},
previous: [
{
position: 'CEO',
company: 'CryptoDancers',
timerange: '2019 - 2022',
description: 'Revolutionizing the crypto world.',
}
]
},
skills: {
primary: ['Java', 'TypeScript', 'JavaScript'],
secondary: ['Kotlin', 'Go'],
others: ['Driver\'s license (B)']
},
interests: ['Guitars and Heavy Metal', 'Mazda MX-5', 'DIY electronics'],
};

25
src/PersonalDataTypes.ts Normal file
View File

@ -0,0 +1,25 @@
export type Job = {
position: string,
company: string,
timerange: string,
description: string
}
export type Jobs = {
current?: Job,
previous?: Job[]
}
export type Skills = {
primary: string[],
secondary?: string[],
others?: string[]
}
export type PersonalData = {
name: string,
brief: string,
jobs: Jobs,
skills: Skills,
interests: string[]
}

View File

@ -52,7 +52,10 @@ export function useAutoFocus<ElementType extends HTMLElement>(elementKey: string
let cleanup = () => {} let cleanup = () => {}
if (elementRef.current) { if (elementRef.current) {
const elem = elementRef.current const elem = elementRef.current
elem.onclick = focusElement elem.onclick = (evt) => {
evt.stopPropagation()
focusElement()
}
const classNameBackup = elem.className const classNameBackup = elem.className
elem.className += ' ' + focusedClass elem.className += ' ' + focusedClass
cleanup = () => { cleanup = () => {

View File

@ -1,10 +1,10 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import Container from 'react-bootstrap/Container'; import Container from 'react-bootstrap/Container';
import Image from 'react-bootstrap/Image' import Image from 'react-bootstrap/Image'
import { PersonContext } from './PersonContext'; import { usePersonContext } from './PersonContext';
export default function AboutBrief() { export default function AboutBrief() {
const person = useContext(PersonContext) const person = usePersonContext()
return ( return (
<Container className='about-brief'> <Container className='about-brief'>
<Image alt='Photograph of the person' rounded={true} src='photo.png'></Image> <Image alt='Photograph of the person' rounded={true} src='photo.png'></Image>

View File

@ -11,7 +11,7 @@ export type Props = {
}; };
export default function JobCard(props: Props) { export default function JobCard(props: Props) {
const focusRef = useAutoFocus<HTMLDivElement>([props.position, props.company].join(', ')) const focusRef = useAutoFocus<HTMLDivElement>('position ' + [props.position, props.company].join(', '))
return ( return (
<Card ref={focusRef} className='job-card'> <Card ref={focusRef} className='job-card'>
{props.heading && ( {props.heading && (

View File

@ -4,35 +4,41 @@ import Container from 'react-bootstrap/Container';
import Col from 'react-bootstrap/Col'; import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row'; import Row from 'react-bootstrap/Row';
import JobCard from './JobCard'; import JobCard from './JobCard';
import { usePersonContext } from './PersonContext';
import { Job } from '../../PersonalDataTypes';
import { partition } from '../utils';
const entriesPerRow = 2
export default function JobsHistory() { export default function JobsHistory() {
const person = usePersonContext()
function JobEntry(job: Job, heading?: string) {
return <JobCard
heading={heading}
{...job}
/>
}
return ( return (
<Container> <Container>
<h2>Experience</h2> <h2>Experience</h2>
{person.jobs.current && (
<Row> <Row>
<Col > <Col>
<JobCard {JobEntry(person.jobs.current, 'Current position')}
heading='Current position' </Col>
position='Senior Software Development Manager - UI Toolkit'
timerange='2022 - present'
company='Oracle | NetSuite'
description='Team leadership Lorem Ipsum'
/></Col>
</Row> </Row>
<Row lg={2}> )}
<Col><JobCard {partition(person.jobs.previous, entriesPerRow).map((jobs, index) => (
position='Software Development Manager - UI Toolkit' <Row key={index}>
timerange='2020 - 2022' {(jobs.map((job, subindex) => (
company='Oracle | NetSuite' <Col key={index + '_' + subindex}>
description='Team leadership Lorem Ipsum' {JobEntry(job)}
/></Col> </Col>
<Col><JobCard )))}
position='Software Development Manager - ERP Tax'
timerange='2015 - 2020'
company='Oracle | NetSuite'
description='Team leadership Lorem Ipsum'
/></Col>
</Row> </Row>
))}
</Container> </Container>
) )
} }

View File

@ -1,14 +1,17 @@
'use client' 'use client'
import React from 'react'; import React, { useContext } from 'react';
import { createContext } from 'react'; import { createContext } from 'react';
import { Person } from '../../Person'; import { personalData } from '../../PersonalData';
import { PersonalData } from '../../PersonalDataTypes';
export const PersonContext = createContext(Person); export const PersonContext = createContext(personalData);
export function PersonProvider({ children }) { export function PersonProvider({ children }) {
return ( return (
<PersonContext.Provider value={Person}> <PersonContext.Provider value={personalData}>
{children} {children}
</PersonContext.Provider> </PersonContext.Provider>
) )
} }
export const usePersonContext = (): PersonalData => useContext(PersonContext)

View File

@ -9,9 +9,15 @@ export default function Skills() {
<Container className='skills'> <Container className='skills'>
<h2>Skills</h2> <h2>Skills</h2>
<TagCloud title='Primary' icon='bookmark-star' style='primary' tags={person.skills.primary} /> <TagCloud title='Primary' icon='bookmark-star' style='primary' tags={person.skills.primary} />
{person.skills.secondary && (
<TagCloud title='Secondary' icon='bookmark-plus' tags={person.skills.secondary} /> <TagCloud title='Secondary' icon='bookmark-plus' tags={person.skills.secondary} />
)}
{person.skills.others && (
<TagCloud title='Others' icon='bookmark' tags={person.skills.others} /> <TagCloud title='Others' icon='bookmark' tags={person.skills.others} />
)}
{person.interests && (
<TagCloud title='Interests' icon='bookmark-heart' style='light' tags={person.interests} /> <TagCloud title='Interests' icon='bookmark-heart' style='light' tags={person.interests} />
)}
</Container> </Container>
) )
} }

View File

@ -18,9 +18,10 @@ function Tag(props: {text: string}) {
} }
export default function TagCloud(props: Props) { export default function TagCloud(props: Props) {
const focusRef = useAutoFocus<HTMLDivElement>('tags ' + props.title)
const containerClasses = ['tag-cloud', 'cloud-' + (props.style || 'standard')] const containerClasses = ['tag-cloud', 'cloud-' + (props.style || 'standard')]
return ( return (
<Container className={containerClasses.join(' ')}> <Container ref={focusRef} className={containerClasses.join(' ')}>
<h4>{props.icon && (<i className={'bi-' + props.icon}> </i>)}{props.title}</h4> <h4>{props.icon && (<i className={'bi-' + props.icon}> </i>)}{props.title}</h4>
<Container className='tag-badges'> <Container className='tag-badges'>
{props.tags.map((tag: string) => (<Tag key={tag} text={tag} />) )} {props.tags.map((tag: string) => (<Tag key={tag} text={tag} />) )}

View File

@ -3,11 +3,12 @@ import { Inter } from 'next/font/google'
import './globals.css' import './globals.css'
import { PersonProvider } from './components/PersonContext' import { PersonProvider } from './components/PersonContext'
import { personalData } from '../PersonalData'
const inter = Inter({ subsets: ['latin'] }) const inter = Inter({ subsets: ['latin'] })
export const metadata = { export const metadata = {
title: 'David Hrdina Němeček | CV.', title: personalData.name + ' | CV.',
description: 'Curriculum Vitae', description: 'Curriculum Vitae',
} }

10
src/app/utils.ts Normal file
View File

@ -0,0 +1,10 @@
export function partition<T>(array: T[]|undefined, entriesPerRow: number): T[][] {
return array ? array.reduce((accumulator: T[][], current: T, index) => {
if (index % entriesPerRow == 0) {
accumulator[accumulator.length] = [current]
} else {
accumulator[accumulator.length - 1]
}
return accumulator
}, []) : []
}