Browse Source

Jobs history sourced from personal data

master
Dejvino 11 months ago
parent
commit
2308c0394b
12 changed files with 120 additions and 47 deletions
  1. +0
    -11
      src/Person.ts
  2. +29
    -0
      src/PersonalData.ts
  3. +25
    -0
      src/PersonalDataTypes.ts
  4. +4
    -1
      src/app/FocusedElement.tsx
  5. +2
    -2
      src/app/components/AboutBrief.tsx
  6. +1
    -1
      src/app/components/JobCard.tsx
  7. +28
    -22
      src/app/components/JobsHistory.tsx
  8. +8
    -5
      src/app/components/PersonContext.tsx
  9. +9
    -3
      src/app/components/Skills.tsx
  10. +2
    -1
      src/app/components/TagCloud.tsx
  11. +2
    -1
      src/app/layout.tsx
  12. +10
    -0
      src/app/utils.ts

+ 0
- 11
src/Person.ts 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
- 0
src/PersonalData.ts 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
- 0
src/PersonalDataTypes.ts 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[]
}

+ 4
- 1
src/app/FocusedElement.tsx View File

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


+ 2
- 2
src/app/components/AboutBrief.tsx View File

@@ -1,10 +1,10 @@
import React, { useContext } from 'react';
import Container from 'react-bootstrap/Container';
import Image from 'react-bootstrap/Image'
import { PersonContext } from './PersonContext';
import { usePersonContext } from './PersonContext';

export default function AboutBrief() {
const person = useContext(PersonContext)
const person = usePersonContext()
return (
<Container className='about-brief'>
<Image alt='Photograph of the person' rounded={true} src='photo.png'></Image>


+ 1
- 1
src/app/components/JobCard.tsx View File

@@ -11,7 +11,7 @@ export type 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 (
<Card ref={focusRef} className='job-card'>
{props.heading && (


+ 28
- 22
src/app/components/JobsHistory.tsx View File

@@ -4,35 +4,41 @@ import Container from 'react-bootstrap/Container';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
import JobCard from './JobCard';
import { usePersonContext } from './PersonContext';
import { Job } from '../../PersonalDataTypes';
import { partition } from '../utils';

const entriesPerRow = 2

export default function JobsHistory() {
const person = usePersonContext()

function JobEntry(job: Job, heading?: string) {
return <JobCard
heading={heading}
{...job}
/>
}

return (
<Container>
<h2>Experience</h2>
{person.jobs.current && (
<Row>
<Col >
<JobCard
heading='Current position'
position='Senior Software Development Manager - UI Toolkit'
timerange='2022 - present'
company='Oracle | NetSuite'
description='Team leadership Lorem Ipsum'
/></Col>
<Col>
{JobEntry(person.jobs.current, 'Current position')}
</Col>
</Row>
<Row lg={2}>
<Col><JobCard
position='Software Development Manager - UI Toolkit'
timerange='2020 - 2022'
company='Oracle | NetSuite'
description='Team leadership Lorem Ipsum'
/></Col>
<Col><JobCard
position='Software Development Manager - ERP Tax'
timerange='2015 - 2020'
company='Oracle | NetSuite'
description='Team leadership Lorem Ipsum'
/></Col>
)}
{partition(person.jobs.previous, entriesPerRow).map((jobs, index) => (
<Row key={index}>
{(jobs.map((job, subindex) => (
<Col key={index + '_' + subindex}>
{JobEntry(job)}
</Col>
)))}
</Row>
</Container>
))}
</Container>
)
}

+ 8
- 5
src/app/components/PersonContext.tsx View File

@@ -1,14 +1,17 @@
'use client'
import React from 'react';
import React, { useContext } 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 }) {
return (
<PersonContext.Provider value={Person}>
<PersonContext.Provider value={personalData}>
{children}
</PersonContext.Provider>
)
}
}

export const usePersonContext = (): PersonalData => useContext(PersonContext)

+ 9
- 3
src/app/components/Skills.tsx View File

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

+ 2
- 1
src/app/components/TagCloud.tsx View File

@@ -18,9 +18,10 @@ function Tag(props: {text: string}) {
}

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


+ 2
- 1
src/app/layout.tsx View File

@@ -3,11 +3,12 @@ import { Inter } from 'next/font/google'

import './globals.css'
import { PersonProvider } from './components/PersonContext'
import { personalData } from '../PersonalData'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
title: 'David Hrdina Němeček | CV.',
title: personalData.name + ' | CV.',
description: 'Curriculum Vitae',
}



+ 10
- 0
src/app/utils.ts 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
}, []) : []
}

Loading…
Cancel
Save