diff --git a/cv.json b/cv.json deleted file mode 100644 index 79cf10f..0000000 --- a/cv.json +++ /dev/null @@ -1,127 +0,0 @@ -{ - "name": "David Hrdina Němeček", - "photo": "photo.png", - "headline": "Principal Software Engineer at Oracle NetSuite", - "summary": "Working on the UI platform architecture for 40k+ companies. Focused on AI-assisted engineering, observability, and performance.", - "email": "explosive@dejvino.cz", - "location": "Brno, Czechia", - "phone": "+420 775 26 26 32", - "contact_links": { - "Website": "https://www.dejvino.cz", - "Email": "mailto:explosive@dejvino.cz", - "Resume": "https://dejvino.cz/cv" - }, - "about": [ - "Principal Software Engineer at Oracle NetSuite, working on the UI platform for 40k+ companies." - ], - "highlights": [ - { - "title": "Telemetry stack architecture", - "description": [ - "Shaped telemetry direction across user behavior and performance.", - "Designed and rolled out a custom OpenTelemetry-based tracing library to gain rich and reliable insights across multiple front-ends and back-end." - ], - "date": "2024 – 2026" - }, - { - "title": "UI performance optimizations", - "description": "Tiered JS bundle dependency loading for shorter page load times.", - "date": "2025 – 2026" - } - ], - "outside_work": [ - "Mandolin", - "Synthwave", - "Electronics", - "3D Printing", - "Mountain Biking" - ], - "experience": [ - { - "title": "Principal Software Engineer (UI Platform Architecture)", - "company": "Oracle|NetSuite", - "date": "2023 – present", - "description": "UI Architect working on feature discovery, solution prototyping and technical designs. Mainly focused on UI telemetry, performance, CI/CD tooling and pipelines." - }, - { - "title": "Senior Software Development Manager (UI Platform)", - "company": "Oracle|NetSuite", - "date": "2022 – 2023", - "description": "Engineering lead for multiple UI Platform teams who designed, developed and released a UI framework and tooling used by the rest of the organization. Leader of a UI testing architecture group responsible for defining a testing strategy across the UI Platform." - }, - { - "title": "Software Development Manager (UI Platform)", - "company": "Oracle|NetSuite", - "date": "2020 – 2022", - "description": "Engineering lead for a UI Platform team who developed components for a UI toolkit used by the rest of the organization. Technical product owner while bootstrapping a team." - }, - { - "title": "Software Development Manager (ERP, Tax)", - "company": "Oracle|NetSuite", - "date": "2017 – 2020", - "description": "Lead developer for ERP: Tax. Design and implementation of a pluggable Tax calculation engine. Coordination of multiple squads supporting both the legacy and the next-gen systems concurrently." - }, - { - "title": "Senior Software Engineer (ERP, Tax)", - "company": "Oracle|NetSuite", - "date": "2013 – 2017", - "description": "Development of Tax calculation and reporting modules in a cloud ERP system. Large-scale refactoring of legacy code. Introduction of a pluggable architecture." - }, - { - "title": "Software Engineer", - "company": "Q2 Interactive", - "date": "2009 – 2013", - "description": "Development and project leadership of multiple web applications and services: CRM system (PHP backend server, JavaScript frontend, Android client app), Accounting web app (PHP, JavaScript), e-commerce sites (Magento) and Linux server maintenance." - } - ], - "skills": { - "Main": [ - "TypeScript", - "Java", - "Linux", - "NodeJs" - ], - "Support": [ - "Kotlin", - "Go", - "JavaScript", - "Oracle", - "SQL", - "Git", - "React", - "Preact", - "Python" - ], - "Languages": [ - "Czech (native)", - "English (proficient)", - "German (elementary)" - ], - "Other": [ - "C/C++", - "Supercomputers", - "OpenMPI", - "Visualization", - "Data science", - "Embedded", - "OpenSCAD" - ] - }, - "education": [ - { - "degree": "Master's degree", - "field": "Parallel and Distributed Systems", - "institution": "Faculty of Informatics, Masaryk University Brno", - "date": "2011 – 2013", - "thesis": "Efficient computation and visualization of correlations in medical signals. The first part consisted of high-performance computation of correlations on large volumes of analog data using supercomputers. The second part covered the visualization of the computed results which allowed interactive exploration and processing of the data by a researcher." - }, - { - "degree": "Bachelor's degree", - "field": "Parallel and Distributed Systems", - "institution": "Faculty of Informatics, Masaryk University Brno", - "date": "2008 – 2011", - "thesis": "Parallel implementation of force-field decompression algorithm. The solution executed on a supercomputer cluster to perform real-time simulation of molecular forces. This in turn provided haptic feedback to a 3D pointing device." - } - ], - "philosophy": "I design platform layers that stay out of the way while enabling everything else. Quiet infrastructure. Measurable value." -} \ No newline at end of file diff --git a/index.php b/index.php index 4b1ab1f..e11325b 100644 --- a/index.php +++ b/index.php @@ -20,6 +20,32 @@ $nav_links = [ ]; $highlights = $cvData['highlights'] ?? []; +/** + * Sourced Interests Showcase (from filesystem) + */ +$interests_showcase = []; +$interests_base = __DIR__ . '/interests'; +if (is_dir($interests_base)) { + $folders = glob($interests_base . '/*', GLOB_ONLYDIR); + if ($folders) { + foreach ($folders as $folder) { + $config_path = $folder . '/interest.json'; + $config = []; + if (file_exists($config_path)) { + $config = json_decode(file_get_contents($config_path), true); + } + $img_file = $config['image'] ?? 'image.png'; + $has_image = file_exists($folder . '/' . $img_file); + + $interests_showcase[] = [ + 'name' => $config['name'] ?? basename($folder), + 'image' => $has_image ? 'interests/' . basename($folder) . '/' . $img_file : null, + 'caption' => $config['caption'] ?? '' + ]; + } + } +} + $site_url = "https://www.dejvino.cz/"; $site_title = $name; $site_desc = "$name - $headline"; @@ -202,6 +228,41 @@ $cv_skills = $cvData['cv']['skills'] ?? []; + + +
+ +
+ $item): ?> +
+ + <?= htmlspecialchars($item['name']) ?> + +

+
+ +
+
+
@@ -226,28 +287,6 @@ $cv_skills = $cvData['cv']['skills'] ?? [];
- - -
-

Outside Work

-
- - - -
-
- -
-

Interests

-
- - - -
-
- - -
@@ -329,6 +368,34 @@ $cv_skills = $cvData['cv']['skills'] ?? []; const el = document.getElementById("contact-mail"); if (el) el.innerHTML = `${addr}`; })('', 'dejvino', 'cz'); + + // Interests Showcase Logic + (() => { + const slides = document.querySelectorAll('.interest-slide'); + const labels = document.querySelectorAll('.interests-nav li'); + if (!slides.length) return; + + let currentIndex = 0; + let interval = setInterval(next, 5000); + + function show(index) { + slides.forEach(s => s.classList.remove('active')); + labels.forEach(l => l.classList.remove('active')); + slides[index].classList.add('active'); + labels[index].classList.add('active'); + currentIndex = index; + } + + function next() { show((currentIndex + 1) % slides.length); } + + labels.forEach((label, i) => { + label.addEventListener('click', () => { + show(i); + clearInterval(interval); + interval = setInterval(next, 8000); // Slower auto-switch after manual interaction + }); + }); + })(); diff --git a/interests/1/interest.json b/interests/1/interest.json new file mode 100644 index 0000000..2729107 --- /dev/null +++ b/interests/1/interest.json @@ -0,0 +1,5 @@ +{ + "name": "Mandolin", + "image": "image.png", + "caption": "Octave mandolin is my instrument of choice. Wide range of tones, pleasant sound. Great way to relax your mind, explore melodies and harmonies." +} \ No newline at end of file diff --git a/interests/3/interest.json b/interests/3/interest.json new file mode 100644 index 0000000..ed6dd2f --- /dev/null +++ b/interests/3/interest.json @@ -0,0 +1,5 @@ +{ + "name": "Electronics tinkering", + "image": "image.png", + "caption": "Building a useful device from scratch. Retrofitting modern brains into a broken vintage shell. Electronics is the magic that makes things alive." +} \ No newline at end of file diff --git a/interests/4/image.png b/interests/4/image.png new file mode 100644 index 0000000..2535077 Binary files /dev/null and b/interests/4/image.png differ diff --git a/interests/4/interest.json b/interests/4/interest.json new file mode 100644 index 0000000..6811291 --- /dev/null +++ b/interests/4/interest.json @@ -0,0 +1,5 @@ +{ + "name": "Synthwave", + "image": "image.png", + "caption": "Neon-filled nostalgia. Fun to create, relaxing to listen to it." +} \ No newline at end of file diff --git a/interests/5/interest.json b/interests/5/interest.json new file mode 100644 index 0000000..4e04ae2 --- /dev/null +++ b/interests/5/interest.json @@ -0,0 +1,5 @@ +{ + "name": "3D Printing", + "image": "image.png", + "caption": "" +} \ No newline at end of file diff --git a/interests/6/interest.json b/interests/6/interest.json new file mode 100644 index 0000000..77cce11 --- /dev/null +++ b/interests/6/interest.json @@ -0,0 +1,5 @@ +{ + "name": "Mountain Biking", + "image": "image.png", + "caption": "" +} \ No newline at end of file diff --git a/interests/7/interest.json b/interests/7/interest.json new file mode 100644 index 0000000..456e996 --- /dev/null +++ b/interests/7/interest.json @@ -0,0 +1,5 @@ +{ + "name": "RC Cars", + "image": "image.png", + "caption": "Rock crawlers, construction trucks, military vehicles. There is a fun challenge awaiting an RC car on every corner." +} \ No newline at end of file diff --git a/style.css b/style.css index bee0ccd..9f97bd7 100644 --- a/style.css +++ b/style.css @@ -129,6 +129,7 @@ body { margin-right: 16px !important; } .hero { grid-column: span 3; } + .interests-showcase { grid-column: span 3; } .hiring-toggle { grid-column: span 3; } .selected-work { grid-column: span 2; } body:not(.cv-mode) .personal { grid-column: span 3; } @@ -1030,3 +1031,97 @@ a { color: var(--link-color); text-decoration: none; } padding: 0; opacity: 0.6; } + +/* Interests Showcase Styles */ +.interests-showcase { + display: flex; + flex-direction: column; + padding: 24px !important; + min-height: 400px; + overflow: hidden; +} + +.interests-nav { + margin-bottom: 24px; +} + +.interests-nav h2 { margin-top: 0; font-size: 0.75rem; margin-bottom: 16px; } +.interests-nav ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.interests-nav li { + padding: 8px 16px; + border-radius: 20px; + background: rgba(0, 243, 255, 0.05); + border: 1px solid rgba(0, 243, 255, 0.15); + cursor: pointer; + transition: all 0.2s ease; + font-size: 0.9rem; + color: var(--text-color); +} + +.interests-nav li:hover { background: rgba(0, 243, 255, 0.15); border-color: rgba(0, 243, 255, 0.4); } + +.interests-nav li.active { + background: var(--accent-color); + color: #000; + border-color: var(--accent-color); + font-weight: bold; + box-shadow: 0 0 15px var(--accent-color); +} + +.interests-display { + flex: 1; + position: relative; + min-height: 250px; + border-radius: 12px; + overflow: hidden; + display: flex; + background: #000; +} + +.interest-slide { + display: none; + width: 100%; + height: 100%; + flex-direction: column; + align-items: center; + justify-content: center; + position: absolute; + inset: 0; + padding: 30px; + color: #fff; /* Changed to white for dark backgrounds */ +} +.interest-slide.active { display: flex; animation: interestFadeIn 0.4s ease-out; } + +.interest-slide img { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + z-index: 1; +} + +.interest-slide .caption { + position: relative; + z-index: 2; + font-size: 1.0rem; + line-height: 2.0; + color: inherit; + font-weight: bold; + text-shadow: 0 1px 2px rgba(255,255,255,0.5); +} + +.interest-slide img + .caption { + color: #fff; + text-shadow: 0 0 10px #000, 0 0 20px #000; +} + +@keyframes interestFadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }