Jobs history sourced from personal data
This commit is contained in:
parent
9edf9777a0
commit
2308c0394b
@ -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
29
src/PersonalData.ts
Normal 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
25
src/PersonalDataTypes.ts
Normal 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[]
|
||||||
|
}
|
@ -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 = () => {
|
||||||
|
@ -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>
|
||||||
|
@ -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 && (
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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} />
|
||||||
<TagCloud title='Secondary' icon='bookmark-plus' tags={person.skills.secondary} />
|
{person.skills.secondary && (
|
||||||
<TagCloud title='Others' icon='bookmark' tags={person.skills.others} />
|
<TagCloud title='Secondary' icon='bookmark-plus' tags={person.skills.secondary} />
|
||||||
<TagCloud title='Interests' icon='bookmark-heart' style='light' tags={person.interests} />
|
)}
|
||||||
|
{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} />
|
||||||
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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} />) )}
|
||||||
|
@ -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
10
src/app/utils.ts
Normal 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
|
||||||
|
}, []) : []
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user