Compare commits

..

4 Commits

Author SHA1 Message Date
59677e3d7f Restructure header to make it more responsive 2023-05-26 21:31:38 +02:00
e9a63461fb Styling and responsive layout 2023-05-26 20:44:44 +02:00
afff716c09 Add languages 2023-05-26 05:49:37 +02:00
296b9862c9 Add Education 2023-05-26 05:43:18 +02:00
14 changed files with 146 additions and 25 deletions

View File

@ -1,13 +1,16 @@
import { PersonalData } from "./PersonalDataTypes";
export const personalData: PersonalData = {
updatedDate: '2023-05-26',
name: "David Hrdina Němeček",
brief: "Software developer, people manager.",
contacts: [
{icon: 'browser-firefox', text: 'www.dejvino.cz'},
{icon: 'envelope-at', text: 'explosive@dejvino.cz'},
{icon: 'git', text: 'https://git.dejvino.cz'}
{icon: 'git', text: 'https://git.dejvino.cz'},
{icon: 'telephone', text: '+420 111 222 333'},
{icon: 'geo-alt', text: 'Brno, Czechia'}
],
jobs: {
current: {
@ -25,9 +28,20 @@ export const personalData: PersonalData = {
}
]
},
education: {
previous: [
{
position: 'Information Technology (unfinished)',
company: 'University of Benimoto',
timerange: '2010 - 2017',
description: '',
}
]
},
skills: {
primary: ['Java', 'TypeScript', 'JavaScript'],
secondary: ['Kotlin', 'Go'],
languages: ['Czech (native)', 'English (proficient)', 'German (elementary)'],
others: ['Driver\'s license (B)']
},
interests: ['Guitars and Heavy Metal', 'Mazda MX-5', 'DIY electronics'],

View File

@ -15,17 +15,22 @@ export type Jobs = {
previous?: Job[]
}
export type Education = Jobs;
export type Skills = {
primary: string[],
secondary?: string[],
languages?: string[],
others?: string[]
}
export type PersonalData = {
updatedDate: string,
name: string,
brief: string,
contacts: Contact[],
jobs: Jobs,
education?: Education,
skills: Skills,
interests: string[]
}

View File

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

View File

@ -2,6 +2,7 @@ import React, { ReactNode } from 'react'
import { usePersonContext } from './PersonContext'
import Container from 'react-bootstrap/esm/Container'
import { useAutoFocus } from '../FocusedElement'
import { Col, Row } from 'react-bootstrap'
export function Contact(props: {icon?: string, text: string}) {
let textElement: ReactNode = <span className='contact-text'>{props.text}</span>
@ -21,10 +22,9 @@ export function Contact(props: {icon?: string, text: string}) {
textElement = <a href={url} className='contact-link' target='_blank'>{props.text}</a>
}
return (
<span className='contact'>
<i className={'bi-' + props.icon}> </i>
{textElement}
</span>
<Col className='contact' xs={'auto'}>
<i className={'bi-' + props.icon}></i>&nbsp;{textElement}
</Col>
)
}
@ -32,11 +32,15 @@ export function Contacts() {
const person = usePersonContext()
const focus = useAutoFocus<HTMLDivElement>('contacts')
return (
<Container ref={focus} className='contacts'>
<h2>Contacts</h2>
<Container ref={focus} className='contacts' fluid>
<Row>
<h2>Contacts</h2>
</Row>
<Row>
{person.contacts.map((contact, index) => (
<Contact key={index} {...contact} />
))}
</Row>
</Container>
)
}

View File

@ -0,0 +1,16 @@
import React from 'react';
import { usePersonContext } from './PersonContext';
import JobHistory from './JobHistory';
export default function WorkExperience() {
const person = usePersonContext()
return person.education ? (
<JobHistory
jobs={person.education}
heading='Education'
currentHeading='Currently studying'
/>
) : <></>
}

View File

@ -0,0 +1,13 @@
import React from 'react';
import { Container } from 'react-bootstrap';
import { usePersonContext } from './PersonContext';
export default function Footer() {
const personalData = usePersonContext()
return (
<Container fluid className="footer text-center">
<p><small>Created by {personalData.name}, last updated on {personalData.updatedDate}</small></p>
<p><small className='tiny'>CV engineered by <a href={'https://www.dejvino.cz/'} target={'_blank'}>Dejvino</a></small></p>
</Container>
)
}

View File

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

View File

@ -4,25 +4,35 @@ 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 { partition } from '../utils';
import { Jobs } from '@/PersonalDataTypes';
const entriesPerRow = 2
export type Props = {
jobs: Jobs,
heading: string,
entriesPerRow?: number,
currentHeading?: string,
}
export default function JobsHistory() {
const person = usePersonContext()
const defaultProps = {
entriesPerRow: 2,
currentHeading: 'Currently',
}
export default function JobHistory(props: Props) {
const jobs = props.jobs
const config = {...defaultProps, ...props}
return (
<Container>
<h2>Experience</h2>
{person.jobs.current && (
<h2>{config.heading}</h2>
{jobs.current && (
<Row>
<Col>
<JobCard heading={'Current position'} {...person.jobs.current} />
<JobCard heading={config.currentHeading} {...jobs.current} />
</Col>
</Row>
)}
{partition(person.jobs.previous, entriesPerRow).map((jobs, index) => (
{partition(jobs.previous, config.entriesPerRow).map((jobs, index) => (
<Row key={index}>
{(jobs.map((job, subindex) => (
<Col key={index + '_' + subindex}>

View File

@ -0,0 +1,8 @@
import React from 'react';
import Image from 'react-bootstrap/Image'
export default function Photo() {
return (
<Image alt='Photograph of the person' rounded fluid src='photo.png'></Image>
)
}

View File

@ -12,6 +12,9 @@ export default function Skills() {
{person.skills.secondary && (
<TagCloud title='Secondary' icon='bookmark-plus' tags={person.skills.secondary} />
)}
{person.skills.languages && (
<TagCloud title='Languages' icon='bookmarks' tags={person.skills.languages} />
)}
{person.skills.others && (
<TagCloud title='Others' icon='bookmark' tags={person.skills.others} />
)}

View File

@ -10,7 +10,7 @@ export type Props = {
}
function Tag(props: {text: string}) {
const tagKey = 'tag_' + props.text;
const tagKey = 'tag ' + props.text;
const elementRef = useAutoFocus(tagKey)
return (
<span ref={elementRef} className='badge text-bg-light'>{props.text}</span>

View File

@ -0,0 +1,16 @@
import React from 'react';
import { usePersonContext } from './PersonContext';
import JobHistory from './JobHistory';
export default function WorkExperience() {
const person = usePersonContext()
return (
<JobHistory
jobs={person.jobs}
heading='Work Experience'
currentHeading='Current position'
/>
)
}

View File

@ -2,6 +2,25 @@
@import 'bootstrap/dist/css/bootstrap.min.css';
@import 'bootstrap-icons/font/bootstrap-icons.min.css';
body {
background-color: lightgrey;
}
.main-container {
background-color: white;
padding-top: 1rem;
padding-bottom: 0.2rem;
}
.footer {
margin-top: 2rem;
}
.tiny {
font-size: 75%;
}
h2, h3, h4 {
margin-top: 1em;
}
.job-card {
margin-top: 1em;
}

View File

@ -1,19 +1,32 @@
'use client'
import React from 'react';
import Container from 'react-bootstrap/Container';
import JobsHistory from './components/JobsHistory';
import AboutBrief from './components/AboutBrief';
import Skills from './components/Skills';
import { Contacts } from './components/Contacts';
import WorkExperience from './components/WorkExperience';
import Education from './components/Education';
import { Col, Row } from 'react-bootstrap';
import Footer from './components/Footer';
import Photo from './components/Photo';
export default function Home() {
return (
<Container fluid='xxl'>
<AboutBrief />
<Contacts />
<JobsHistory />
<Skills />
<Container className='main-container' fluid='xxl'>
<Row>
<Col xs={'auto'} sm={4} lg={2}><Photo /></Col>
<Col>
<Row>
<Col xs={'auto'} lg={6}><AboutBrief /></Col>
<Col xs={'auto'} lg={6}><Contacts /></Col>
</Row>
</Col>
</Row>
<Row><WorkExperience /></Row>
<Row><Education /></Row>
<Row><Skills /></Row>
<Row><Footer /></Row>
</Container>
)
}