diff --git a/app/cv/page.tsx b/app/cv/page.tsx new file mode 100644 index 0000000..6c0529a --- /dev/null +++ b/app/cv/page.tsx @@ -0,0 +1,270 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import React from 'react'; + +interface Job { + title: string; + organization: string; + startDate: string; + endDate?: string; + location: string; + description: string; +} + +interface Education { + degree: string; + institution: string; + startDate: string; + endDate?: string; + location: string; + description: string; +} + +interface Publication { + title: string; + date: string; + authors: string[]; + url: string; +} + +const CvPage = async () => { + const workPath = path.join(process.cwd(), 'app/data/cv/work-experience.json'); + const educationPath = path.join( + process.cwd(), + 'app/data/cv/educational-experience.json', + ); + const publicationsPath = path.join( + process.cwd(), + 'app/data/cv/publications.json', + ); + + const workExperience: Job[] = JSON.parse(await fs.readFile(workPath, 'utf8')); + const educationalExperience: Education[] = JSON.parse( + await fs.readFile(educationPath, 'utf8'), + ); + const publications: Publication[] = JSON.parse( + await fs.readFile(publicationsPath, 'utf8'), + ); + + const parseDate = (dateStr: string): Date => { + if (dateStr.toLowerCase() === 'present') { + return new Date(); // Current date for ongoing entries + } + return new Date(dateStr); + }; + + const calculateSpanInYears = (startDate: Date, endDate: Date): number => { + const startYear = startDate.getFullYear(); + const endYear = Math.min(endDate.getFullYear(), new Date().getFullYear()); + return endYear - startYear + 1; + }; + + const combinedItems = [ + ...workExperience.map((job) => ({ + type: 'work', + startDate: parseDate(job.startDate), + endDate: parseDate(job.endDate || 'Present'), + data: job, + })), + ...educationalExperience.map((edu) => ({ + type: 'education', + startDate: parseDate(edu.startDate), + endDate: parseDate(edu.endDate || 'Present'), + data: edu, + })), + ...publications.map((pub) => ({ + type: 'publication', + startDate: parseDate(pub.date), + endDate: parseDate(pub.date), + data: pub, + })), + ]; + + const earliestYear = Math.min( + ...combinedItems.map((item) => item.startDate.getFullYear()), + ); + const latestYear = Math.max( + ...combinedItems.map((item) => item.endDate.getFullYear()), + ); + + const allYears = []; + for (let year = latestYear; year >= earliestYear; year--) { + allYears.push(year); + } + + const getItemsForYear = (year: number) => { + return combinedItems.filter( + (item) => + item.startDate.getFullYear() <= year && + item.endDate.getFullYear() >= year, + ); + }; + + // Track already rendered work and education items to avoid repeating + const renderedWorkItems = new Set(); + const renderedEducationItems = new Set(); + + return ( +
+
+

Curriculum Vitae

+ +
+
+

Year

+

Work

+

Education

+

Publications

+
+ + {allYears.map((year) => { + const itemsForYear = getItemsForYear(year); + + return ( +
+
+
+
{year}
+
+ {/* Work Experience Column (spanning multiple years) */} +
+ {itemsForYear + .filter((item) => item.type === 'work') + .map((item) => { + const spanInYears = calculateSpanInYears( + item.startDate, + item.endDate, + ); + + if ( + item.startDate.getFullYear() === year && + !renderedWorkItems.has(item) + ) { + renderedWorkItems.add(item); + return ( +
+

+ {(item.data as Job).title} at{' '} + {(item.data as Job).organization} +

+

+ {item.startDate.getFullYear()} -{' '} + {item.endDate.getFullYear() === + new Date().getFullYear() + ? 'Present' + : item.endDate.getFullYear()}{' '} + | {(item.data as Job).location} +

+

+ {(item.data as Job).description} +

+
+ ); + } else { + return null; // Prevent rendering in non-start years + } + })} +
+ + {/* Educational Experience Column (spanning multiple years) */} +
+ {itemsForYear + .filter((item) => item.type === 'education') + .map((item) => { + const spanInYears = calculateSpanInYears( + item.startDate, + item.endDate, + ); + + if ( + item.startDate.getFullYear() === year && + !renderedEducationItems.has(item) + ) { + renderedEducationItems.add(item); + return ( +
+

+ {(item.data as Education).degree} at{' '} + {(item.data as Education).institution} +

+

+ {item.startDate.getFullYear()} -{' '} + {item.endDate.getFullYear() === + new Date().getFullYear() + ? 'Present' + : item.endDate.getFullYear()}{' '} + | {(item.data as Education).location} +

+

+ {(item.data as Education).description} +

+
+ ); + } else { + return null; // Prevent rendering in non-start years + } + })} +
+ + {/* Publications Column (single row) */} +
+ {itemsForYear + .filter((item) => item.type === 'publication') + .map((item) => ( +
+

+ {(item.data as Publication).title} +

+

+ {(item.data as Publication).date} |{' '} + {(item.data as Publication).authors.join(', ')} +

+ + View Publication + +
+ ))} +
+
+ ); + })} +
+
+
+ ); +}; + +export default CvPage; diff --git a/app/data/content.ts b/app/data/content.ts index 40dd89b..761a8ea 100644 --- a/app/data/content.ts +++ b/app/data/content.ts @@ -22,6 +22,7 @@ import webDevelopment from '../images/services/web-development.png'; export const navLinks = [ { name: 'Featured Projects', href: '/#project' }, { name: 'Services', href: '/#service' }, + { name: 'CV', href: 'cv' }, ] as const; export const heroSectionData = { diff --git a/app/data/cv/educational-experience.json b/app/data/cv/educational-experience.json new file mode 100644 index 0000000..d6961d2 --- /dev/null +++ b/app/data/cv/educational-experience.json @@ -0,0 +1,26 @@ +[ + { + "degree": "Ph.D. in Prehistory and Historical Archaeology", + "institution": "University of Vienna", + "startDate": "March 2019", + "endDate": "Present", + "description": "Doctoral studies focusing on prehistoric and historical archaeological research.", + "location": "Vienna, Austria" + }, + { + "degree": "M.Sc. in Landscape Archaeology", + "institution": "Hochschule für Technik und Wirtschaft / Freie Universität", + "startDate": "April 2016", + "endDate": "June 2018", + "description": "Master thesis on ancient archaeological sites using modern field archaeology methods.", + "location": "Berlin, Germany" + }, + { + "degree": "B.A. in Conservation & Restoration / Field Archaeology", + "institution": "Hochschule für Technik und Wirtschaft", + "startDate": "October 2012", + "endDate": "March 2016", + "description": "Focus on field archaeology and excavation techniques.", + "location": "Berlin, Germany" + } +] diff --git a/app/data/cv/publications.json b/app/data/cv/publications.json new file mode 100644 index 0000000..1d2dc3a --- /dev/null +++ b/app/data/cv/publications.json @@ -0,0 +1,270 @@ +[ + { + "title": "Different Folks, Different Strokes", + "authors": [ + "Merrill, Samuel", + "Verhoeven, Geert", + "Wild, Benjamin", + "Schlegel, Jona" + ], + "date": "May 2023", + "url": "https://doi.org/10.48619/indigo.v0i0.701", + "type": "Journal article", + "journal": "INDIGO Journal" + }, + { + "title": "Towards a Graffiti Thesaurus", + "authors": [ + "Schlegel, Jona", + "Carloni, Massimiliano", + "Wogrin, Stefan", + "Verhoeven, Geert" + ], + "date": "May 2022", + "url": "https://doi.org/10.5281/zenodo.6578470", + "type": "Journal article", + "journal": "Zenodo" + }, + { + "title": "Finding Listeners for Walls That Speak", + "authors": [ + "Verhoeven, Geert", + "Schlegel, Jona", + "Wild, Benjamin", + "Wogrin, Stefan", + "Carloni, Massimiliano" + ], + "date": "May 2023", + "url": "https://doi.org/10.48619/indigo.v0i0.699", + "type": "Journal article", + "journal": "INDIGO Journal" + }, + { + "title": "Facing a Chameleon – How Project INDIGO Discovers and Records New Graffiti", + "authors": [ + "Verhoeven, Geert", + "Schlegel, Jona", + "Wild, Benjamin", + "Wogrin, Stefan", + "Carloni, Massimiliano" + ], + "date": "May 2023", + "url": "https://doi.org/10.48619/indigo.v0i0.703", + "type": "Journal article", + "journal": "INDIGO Journal" + }, + { + "title": "Project INDIGO – Document, Disseminate & Analyse a Graffiti-Scape", + "authors": [ + "Verhoeven, Geert", + "Schlegel, Jona", + "Wild, Benjamin", + "Wieser, Martin", + "Pfeifer, Norbert", + "Wogrin, Stefan" + ], + "date": "February 2022", + "url": "https://doi.org/10.5194/isprs-archives-XLVI-2-W1-2022-513-2022", + "type": "Conference paper", + "conference": "The International Archives of the Photogrammetry, Remote Sensing and Spatial Information Sciences" + }, + { + "title": "Prospecting the UNESCO World Heritage Site of Müstair (Switzerland)", + "authors": [ + "Schlegel, Jona", + "Verhoeven, Geert", + "Cassitti, Patrick ", + "Hinterleitner, Alois", + "Löcker, Klaus", + "Schiel, Hannes", + "Walser, Christoph", + "Reitmaier, Thomas", + "Neubauer, Wolfgang" + ], + "date": "June 2021", + "url": "https://doi.org/10.3390/rs13132515", + "type": "Journal article", + "journal": "Remote Sensing" + }, + { + "title": "Pliska – Integrated Geophysical Prospection of the First Early Medieval Bulgarian Capital", + "authors": [ + "Filzwieser, Roland", + "Schlegel, Jona", + "Aladzhov, Andrey", + "Hinterleitner, Alois", + "Doneus, Nives", + "Schiel, Hannes", + "Dimitrov, Janko", + "Gamon, Martin", + "Daim, Falko", + "Neubauer, Wolfgang" + ], + "date": "December 2019", + "url": "https://www.semanticscholar.org/paper/Pliska-%E2%80%93-integrated-geophysical-prospection-of-the-Filzwieser-Aladzhov/ddfbb46fdab2c85a2814045b64816c1a1919e669", + "type": "Journal article", + "journal": "Semantics Scholar" + }, + { + "title": "AUTOGRAF—AUTomated Orthorectification of GRAFfiti Photos", + "authors": [ + "Wild, Benjamin", + "Verhoeven, Geert", + "Wieser, Martin", + "Ressl, Camillo", + "Schlegel, Jona", + "Wogrin, Stefan", + "Otepka-Schremmer, Johannes", + "Pfeifer, Norbert" + ], + "date": "December 2022", + "url": "https://doi.org/10.3390/heritage5040156", + "type": "Journal article", + "journal": "Heritage" + }, + { + "title": "‘Imagine Being a Racist’: goINDIGO 2022’s «Ethics & Legality in Graffiti (Research)» Discussion Round", + "authors": [ + "Wild, Benjamin", + "Verhoeven, Geert", + "Pfeifer, Norbert", + "Bonadio, Enrico", + "DEADBEAT HERO", + "JANER ONE", + "Carloni, Massimiliano", + "Ricci, Chiara", + "Schlegel, Jona" + ], + "date": "May 2023", + "url": "https://doi.org/10.48619/indigo.v0i0.702", + "type": "Journal article", + "journal": "INDIGO Journal" + }, + { + "title": "Making a Mark – Towards a Graffiti Thesaurus", + "authors": [ + "Schlegel, Jona", + "Massimiliano Carloni", + "Wogrin, Stefan", + "Graf, Ann M.", + "Verhoeven, Geert" + ], + "date": "May 2023", + "url": "https://doi.org/10.48619/indigo.v0i0.710", + "type": "Journal article", + "journal": "INDIGO Journal" + }, + { + "title": "Towards an automated analysis of geophysical archaeological prospection data", + "authors": ["Schlegel, Jona"], + "date": "November 2020", + "url": "", + "type": "Conference paper", + "conference": "CHNT25 Conference" + }, + { + "title": "CrowdSlide – a mobile web application for building a database of gravitational mass movements using volunteer field reports", + "authors": ["Schlegel, Jona", " Grass, Annemarie", "Fuchs, Florian"], + "date": "May 2020", + "url": "https://doi.org/10.5194/egusphere-egu2020-16503", + "type": "Conference paper", + "conference": "EGU General Assembly Conference Abstracts" + }, + { + "title": "Entdeckung und Erkundung des antiken Stadtgrundrisses von Seleukeia Sidera, Türkei – Ein erster Überblick", + "authors": ["Schlegel, Jona", "Schenk, Thomas"], + "date": "April 2018", + "url": "", + "type": "Conference abstract", + "conference": "Verband für Grabungstechnik und Feldarchäologie e.V." + }, + { + "title": "Recreating an ancient marketplace with geophysical and topographical data", + "authors": ["Gillikin, Kelly", "Schlegel, Jona"], + "date": "March 2018", + "url": "", + "type": "Conference abstract", + "conference": "CAA 2018" + }, + { + "title": "Grabungstechnik Praktische Archäologie", + "authors": ["Schlegel, Jona"], + "date": "June 2014", + "url": "", + "type": "Other", + "publisher": "Online Lehre Plus HTW Berlin" + }, + { + "title": "Dem Donaukanal-Chamäleon auf der Spur", + "authors": ["Wild, Benjamin", "Schlegel, Jona"], + "date": "March 2023", + "url": "https://www.derstandard.de/story/2000144976673/dem-donaukanal-chamaeleon-auf-der-spur", + "type": "Article", + "publisher": "Der Standard" + }, + { + "title": "disseminate | analyse | understand graffiti-scapes. Proceedings of the goINDIGO2023 international graffiti symposium", + "authors": [ + "Verhoeven, Geert", + "Schlegel, Jona", + "Wild, Benjamin", + "Wogrin, Stefan" + ], + "date": "September 2024", + "url": "https://doi.org/10.5281/zenodo.13786065", + "type": "Proceedings", + "publisher": "Zenodo" + }, + { + "title": "Dissipating and Unravelling Bits of Graffiti Bytes", + "authors": [ + "Verhoeven, Geert", + "Schlegel, Jona", + "Wild, Benjamin", + "Wogrin, Stefan" + ], + "date": "September 2024", + "url": "https://doi.org/10.5281/zenodo.13786065", + "type": "Proceedings", + "conference": "goINDIGO 2023" + }, + { + "title": "Decoding the Walls – Urban Graffiti Layers Through Digital Processing", + "authors": [ + "Schlegel, Jona", + "Verhoeven, Geert", + "Wild, Benjamin", + "Wogrin, Stefan" + ], + "date": "September 2024", + "url": "https://journals.ap2.pt/index.php/indigo/article/view/975", + "type": "Journal article", + "journal": "INDIGO Journal" + }, + { + "title": "Graffiti on the Urban Fringe – A Geospatial Analysis", + "authors": [ + "Schlegel, Jona", + "Verhoeven, Geert", + "Wild, Benjamin", + "Wogrin, Stefan" + ], + "date": "September 2024", + "url": "https://journals.ap2.pt/index.php/indigo/article/view/971", + "type": "Journal article", + "journal": "INDIGO Journal" + }, + { + "title": "Graffiti as Cultural Markers – From Ancient Sites to Modern Walls", + "authors": [ + "Schlegel, Jona", + "Verhoeven, Geert", + "Wild, Benjamin", + "Wogrin, Stefan" + ], + "date": "September 2024", + "url": "https://journals.ap2.pt/index.php/indigo/article/view/981", + "type": "Journal article", + "journal": "INDIGO Journal" + } +] diff --git a/app/data/cv/work-experience.json b/app/data/cv/work-experience.json new file mode 100644 index 0000000..dc3241a --- /dev/null +++ b/app/data/cv/work-experience.json @@ -0,0 +1,34 @@ +[ + { + "title": "Freelancer", + "organization": "archaeoINK", + "startDate": "January 2024", + "endDate": "Present", + "description": "Providing services in scientific communication, including web development (consulting and execution), illustration, knowledge management, database structures (CIDOC CRM), and controlled vocabulary for archaeological data sharing.", + "location": "Vienna, Austria" + }, + { + "title": "Researcher", + "organization": "Ludwig Boltzmann Institute for Archaeological Prospection and Virtual Archaeology", + "startDate": "May 2018", + "endDate": "September 2023", + "description": "Specialised in ground-penetrating radar (GPR) surveys, magnetic motorised surveying, data interpretation using GIS, and project management across multiple international sites.", + "location": "Vienna, Austria" + }, + { + "title": "Student Assistant", + "organization": "Hochschule für Technik und Wirtschaft", + "startDate": "November 2017", + "endDate": "December 2017", + "description": "Involved in post-processing and interpretation of geophysical data from the Seleukia Sidera project, Turkey.", + "location": "Berlin, Germany" + }, + { + "title": "Intern", + "organization": "Ludwig Boltzmann Institute for Archaeological Prospection and Virtual Archaeology", + "startDate": "April 2017", + "endDate": "June 2017", + "description": "Worked on magnetic and ground-penetrating radar data processing and the reconstruction of archaeological sites in Herforst, Germany.", + "location": "Vienna, Austria" + } +]