Add markdown support into descriptions for adding links

This commit is contained in:
Dejvino 2023-05-28 21:26:21 +02:00
parent 0d1e962999
commit be6d74d24a
12 changed files with 954 additions and 23 deletions

894
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-bootstrap": "^2.7.4", "react-bootstrap": "^2.7.4",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-markdown": "^8.0.7",
"typescript": "5.0.4" "typescript": "5.0.4"
} }
} }

View File

@ -12,6 +12,7 @@ export const personalData: PersonalData = {
{icon: 'telephone', text: '+420 111 222 333'}, {icon: 'telephone', text: '+420 111 222 333'},
{icon: 'geo-alt', text: 'Brno, Czechia'} {icon: 'geo-alt', text: 'Brno, Czechia'}
], ],
jobs: { jobs: {
current: { current: {
position: 'Senior Software Development Manager (UI Platform)', position: 'Senior Software Development Manager (UI Platform)',
@ -57,6 +58,16 @@ export const personalData: PersonalData = {
} }
] ]
}, },
projects: {
current: {
position: `Personal projects`,
description: `Various hardware and software projects. Usually open sourced and published on [projects.dejvino.com](https://projects.dejvino.com) .
These include video games, utilities, 3D models, devices with embedded microcontrollers etc.`,
tags: ['Java', 'Python', 'C/C++', 'Embedded devices', 'OpenSCAD', 'TypeScript', 'Linux', 'Git', 'Self-hosting']
}
},
education: { education: {
previous: [ previous: [
{ {
@ -73,11 +84,12 @@ export const personalData: PersonalData = {
} }
] ]
}, },
skills: { skills: {
primary: ['Java', 'TypeScript', 'JavaScript'], primary: ['Java', 'TypeScript', 'JavaScript', 'Engineering leadership', 'Linux'],
secondary: ['Kotlin', 'Go'], secondary: ['SQL', 'Kotlin', 'Go', 'C/C++', 'NodeJs', 'Git', 'Preact', 'Embedded devices'],
languages: ['Czech (native)', 'English (proficient)', 'German (elementary)'], languages: ['Czech (native)', 'English (proficient)', 'German (elementary)'],
others: ['Driver\'s license (B)'] others: ['Driver\'s license (B)']
}, },
interests: ['Guitars and Heavy Metal', 'Mazda MX-5', 'DIY electronics'], interests: ['Guitars', 'Heavy Metal', 'Mazda MX-5', 'DIY electronics', 'Linux', 'Open source'],
}; };

View File

@ -5,8 +5,8 @@ export type Contact = {
export type Job = { export type Job = {
position: string, position: string,
company: string, company?: string,
timerange: string, timerange?: string,
description: string, description: string,
tags?: string[], tags?: string[],
} }
@ -18,6 +18,8 @@ export type Jobs = {
export type Education = Jobs; export type Education = Jobs;
export type Projects = Jobs;
export type Skills = { export type Skills = {
primary: string[], primary: string[],
secondary?: string[], secondary?: string[],
@ -31,6 +33,7 @@ export type PersonalData = {
brief: string, brief: string,
contacts: Contact[], contacts: Contact[],
jobs: Jobs, jobs: Jobs,
projects?: Projects,
education?: Education, education?: Education,
skills: Skills, skills: Skills,
interests: string[] interests: string[]

View File

@ -1,15 +1,14 @@
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 { usePersonContext } from '../hooks/PersonContext'; import { usePersonContext } from '../hooks/PersonContext';
import { Col, Row } from 'react-bootstrap'; import md from './Markdown';
export default function AboutBrief() { export default function AboutBrief() {
const person = usePersonContext() const person = usePersonContext()
return ( return (
<Container className='about-brief' fluid> <Container className='about-brief' fluid>
<h1>{person.name}</h1> <h1>{person.name}</h1>
<p className='brief'>{person.brief}</p> <p className='brief'>{md(person.brief)}</p>
</Container> </Container>
) )
} }

View File

@ -3,7 +3,7 @@ import React from 'react';
import { usePersonContext } from '../hooks/PersonContext'; import { usePersonContext } from '../hooks/PersonContext';
import JobHistory from './job/JobsHistory'; import JobHistory from './job/JobsHistory';
export default function WorkExperience() { export default function Education() {
const person = usePersonContext() const person = usePersonContext()
return person.education ? ( return person.education ? (

View File

@ -0,0 +1,5 @@
import ReactMarkdown from "react-markdown";
export default function md(text: string) {
return <ReactMarkdown>{text}</ReactMarkdown>
}

View File

@ -0,0 +1,16 @@
import React from 'react';
import { usePersonContext } from '../hooks/PersonContext';
import JobHistory from './job/JobsHistory';
export default function Projects() {
const person = usePersonContext()
return person.projects ? (
<JobHistory
jobs={person.projects}
heading='Projects'
currentHeading='Currently active'
/>
) : <></>
}

View File

@ -3,14 +3,11 @@ import Card from 'react-bootstrap/Card';
import { useAutoFocus } from '../../hooks/FocusedElement'; import { useAutoFocus } from '../../hooks/FocusedElement';
import { Placeholder } from 'react-bootstrap'; import { Placeholder } from 'react-bootstrap';
import JobTags from './JobTags'; import JobTags from './JobTags';
import { Job } from '@/PersonalDataTypes';
import md from '../Markdown';
export type Props = { export type Props = Job & {
heading?: string, heading?: string
position: string,
timerange: string,
company: string,
description: string,
tags?: string[]
}; };
export function JobCardPlaceholder() { export function JobCardPlaceholder() {
@ -37,9 +34,11 @@ export default function JobCard(props: Props) {
<Card.Body> <Card.Body>
<Card.Title>{props.position}</Card.Title> <Card.Title>{props.position}</Card.Title>
<Card.Subtitle> <Card.Subtitle>
<span className='company-name'>{props.company}</span>, <span className='timerange'>{props.timerange}</span> {props.company && <span className='company-name'>{props.company}</span>}
{props.company && props.timerange && <span>, </span>}
{props.timerange && <span className='timerange'>{props.timerange}</span>}
</Card.Subtitle> </Card.Subtitle>
<Card.Text className='multiline'>{props.description}</Card.Text> <Card.Text className='multiline'>{md(props.description)}</Card.Text>
{props.tags && <JobTags tags={props.tags} />} {props.tags && <JobTags tags={props.tags} />}
</Card.Body> </Card.Body>
</Card> </Card>

View File

@ -4,6 +4,7 @@ import { Job } from '@/PersonalDataTypes';
import { Accordion, Row } from 'react-bootstrap'; import { Accordion, Row } from 'react-bootstrap';
import { JobListProps } from './types'; import { JobListProps } from './types';
import JobTags from './JobTags'; import JobTags from './JobTags';
import md from '../Markdown';
export type Props = { export type Props = {
@ -23,7 +24,7 @@ export default function JobsAccordion(props: JobListProps) {
return ( return (
<div> <div>
<div><strong>{job.position}</strong></div> <div><strong>{job.position}</strong></div>
<div>{job.company}, {job.timerange}</div> <div>{[job.company, job.timerange].filter(x => x).join(', ')}</div>
{heading && (<div>({heading})</div>)} {heading && (<div>({heading})</div>)}
</div> </div>
) )
@ -34,7 +35,7 @@ export default function JobsAccordion(props: JobListProps) {
<Accordion.Item eventKey="current"> <Accordion.Item eventKey="current">
<Accordion.Header><JobTitle heading={config.currentHeading} job={jobs.current} /> </Accordion.Header> <Accordion.Header><JobTitle heading={config.currentHeading} job={jobs.current} /> </Accordion.Header>
<Accordion.Body> <Accordion.Body>
{jobs.current.description} {md(jobs.current.description)}
{jobs.current.tags && <JobTags tags={jobs.current.tags} />} {jobs.current.tags && <JobTags tags={jobs.current.tags} />}
</Accordion.Body> </Accordion.Body>
</Accordion.Item> </Accordion.Item>
@ -43,7 +44,7 @@ export default function JobsAccordion(props: JobListProps) {
<Accordion.Item eventKey={`previous-${index}`} key={index}> <Accordion.Item eventKey={`previous-${index}`} key={index}>
<Accordion.Header><JobTitle job={job} /></Accordion.Header> <Accordion.Header><JobTitle job={job} /></Accordion.Header>
<Accordion.Body className='multiline'> <Accordion.Body className='multiline'>
{job.description} {md(job.description)}
{job.tags && <JobTags tags={job.tags} />} {job.tags && <JobTags tags={job.tags} />}
</Accordion.Body> </Accordion.Body>
</Accordion.Item> </Accordion.Item>

View File

@ -65,7 +65,7 @@ body {
margin: 0.75em; margin: 0.75em;
} }
.accordion-button.collapsed { .accordion-button.collapsed {
background-color: lavender; background-color: #eff2ff;
} }
.accordion { .accordion {
margin: 1rem; margin: 1rem;

View File

@ -9,7 +9,7 @@ import Education from './components/Education';
import { Col, Row } from 'react-bootstrap'; import { Col, Row } from 'react-bootstrap';
import Footer from './components/Footer'; import Footer from './components/Footer';
import Photo from './components/Photo'; import Photo from './components/Photo';
import useSize from './hooks/Size'; import Projects from './components/Projects';
export default function Home() { export default function Home() {
return ( return (
@ -27,6 +27,7 @@ export default function Home() {
<Row> <Row>
<Col xs={12} xl={7}> <Col xs={12} xl={7}>
<Row><WorkExperience /></Row> <Row><WorkExperience /></Row>
<Row><Projects /></Row>
<Row><Education /></Row> <Row><Education /></Row>
</Col> </Col>
<Col> <Col>