Compare commits
	
		
			4 Commits
		
	
	
		
			f4f4016640
			...
			59677e3d7f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 59677e3d7f | |||
| e9a63461fb | |||
| afff716c09 | |||
| 296b9862c9 | 
| @ -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'], | ||||
|  | ||||
| @ -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[] | ||||
| } | ||||
|  | ||||
| @ -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> | ||||
|  | ||||
| @ -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> {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> | ||||
|     ) | ||||
| } | ||||
							
								
								
									
										16
									
								
								src/app/components/Education.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/app/components/Education.tsx
									
									
									
									
									
										Normal 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' | ||||
|         /> | ||||
|     ) : <></> | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/app/components/Footer.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/app/components/Footer.tsx
									
									
									
									
									
										Normal 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> | ||||
|     ) | ||||
| } | ||||
| @ -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 && ( | ||||
|  | ||||
| @ -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}> | ||||
							
								
								
									
										8
									
								
								src/app/components/Photo.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/app/components/Photo.tsx
									
									
									
									
									
										Normal 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> | ||||
|     ) | ||||
| } | ||||
| @ -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} /> | ||||
|           )} | ||||
|  | ||||
| @ -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> | ||||
|  | ||||
							
								
								
									
										16
									
								
								src/app/components/WorkExperience.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/app/components/WorkExperience.tsx
									
									
									
									
									
										Normal 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' | ||||
|         /> | ||||
|     ) | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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> | ||||
|   ) | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user