Re-layouting

This commit is contained in:
Dejvino 2026-05-20 21:12:34 +02:00
parent c204fc0ab8
commit 86b5743f7a
3 changed files with 170 additions and 77 deletions

18
cv.json
View File

@ -1,6 +1,5 @@
{ {
"name": "David Hrdina Němeček", "name": "David Hrdina Němeček",
"subtitle": "Software developer",
"photo": "photo.png", "photo": "photo.png",
"email": "explosive@dejvino.cz", "email": "explosive@dejvino.cz",
"location": "Brno, Czechia", "location": "Brno, Czechia",
@ -113,5 +112,20 @@
"Embedded", "Embedded",
"OpenSCAD" "OpenSCAD"
] ]
} },
"highlights": [
{
"title": "Telemetry stack architecture",
"subtitle": "Shaped telemetry direction across user behavior, performance, and infrastructure for NetSuite Prime and Classic.",
"description": "Advanced OpenTelemetry delivery, Oracle APM integration paths, and OpenSearch trace visibility across multiple teams. Designed action-root hybrid sampling and trace context propagation for Classic iframe flows."
},
{
"title": "UI performance optimizations",
"subtitle": "Designed tiered toolkit and external dependency loading for NetSuite Next startup.",
"description": "Main startup toolkit.bundle.js reduced by ~619 KB. Identified concrete improvement tracks including duplicate /myRoles calls, per-feature SSE registration, and obsolete polling."
}
],
"headline": "UI Platform Architect · Telemetry, Performance, and AI-Enabled Engineering",
"summary": "NetSuite UI platform engineer specializing in telemetry, observability, performance, technical design, and AI-assisted engineering enablement. Experienced in OpenTelemetry, Oracle APM, OpenSearch trace visibility, frontend/backend trace correlation, NetSuite Next performance analysis, JavaScript loading guardrails, UI-CBS contract testing, and AI interaction telemetry. Strong at turning ambiguous platform problems into validated prototypes, architecture direction, implementation plans, and handovers that help cross-functional teams execute.",
"role_summary": "UI platform architect on NetSuite Next/Prime focused on telemetry and observability architecture, performance engineering, cross-team technical design, and AI-assisted engineering enablement."
} }

141
index.php
View File

@ -6,12 +6,23 @@
$cvData = json_decode(file_get_contents(__DIR__ . '/cv.json'), true); $cvData = json_decode(file_get_contents(__DIR__ . '/cv.json'), true);
$name = $cvData['name'] ?? ''; $name = $cvData['name'] ?? '';
$site_title = $cvData['subtitle'] ?? ''; $headline = $cvData['headline'] ?? '';
$site_url = "https://www.dejvino.cz/"; $summary = $cvData['summary'] ?? '';
$site_desc = "$name - " . ($cvData['subtitle'] ?? ''); $role_summary = $cvData['role_summary'] ?? '';
$subtitle = $cvData['subtitle'] ?? ''; $location = $cvData['location'] ?? '';
$photo_file = $cvData['photo'] ?? ''; $photo_file = $cvData['photo'] ?? '';
$nav_links = [
'Blog' => 'https://wp.dejvino.com/',
'Projects' => 'https://projects.dejvino.com/',
'Code' => 'https://git.dejvino.cz/',
];
$highlights = $cvData['highlights'] ?? [];
$site_url = "https://www.dejvino.cz/";
$site_title = $name;
$site_desc = "$name - $headline";
$mailto_link = $cvData['contact_links']['Email'] ?? ''; $mailto_link = $cvData['contact_links']['Email'] ?? '';
if (preg_match('/mailto:([^@]+)/', $mailto_link, $m)) { if (preg_match('/mailto:([^@]+)/', $mailto_link, $m)) {
$email_user = $m[1]; $email_user = $m[1];
@ -19,16 +30,6 @@ if (preg_match('/mailto:([^@]+)/', $mailto_link, $m)) {
$email_user = $cvData['email'] ?? ''; $email_user = $cvData['email'] ?? '';
} }
$about_text = $cvData['about'] ?? [];
$nav_links = [
"~/blog" => "https://wp.dejvino.com/",
"~/projects" => "https://projects.dejvino.com/",
"~/code" => "https://git.dejvino.cz/",
];
$hardware_info = $cvData['hardware_info'] ?? '';
$extra_contact_links = $cvData['contact_links'] ?? []; $extra_contact_links = $cvData['contact_links'] ?? [];
/** /**
@ -36,7 +37,7 @@ $extra_contact_links = $cvData['contact_links'] ?? [];
*/ */
// Map experience to expected structure // Map experience to expected structure
$cv_experience = array_map(function ($e) { $cv_experience = array_map(function ($e) {
return [ return [
'title' => $e['title'] ?? '', 'title' => $e['title'] ?? '',
'org' => $e['organization'] ?? '', 'org' => $e['organization'] ?? '',
'date' => $e['date'] ?? '', 'date' => $e['date'] ?? '',
@ -47,7 +48,6 @@ $cv_experience = array_map(function ($e) {
// Helper to calculate years between start and end dates // Helper to calculate years between start and end dates
function calculateYears($dateStr) { function calculateYears($dateStr) {
// Extract start and end years, support 'present' or 'current' // Extract start and end years, support 'present' or 'current'
$matches = [];
$dateStr = str_replace(['', '—', '', '-'], '-', $dateStr); $dateStr = str_replace(['', '—', '', '-'], '-', $dateStr);
$parts = array_map('trim', explode('-', $dateStr, 2)); $parts = array_map('trim', explode('-', $dateStr, 2));
if (count($parts) < 2) { if (count($parts) < 2) {
@ -78,7 +78,7 @@ $cv_skills = $cvData['skills'] ?? [];
/** /**
* Page design: * Page design:
* - clean and simple, human-maintaninable * - clean and simple, human-maintainable
* - no dependencies * - no dependencies
* - single-file website * - single-file website
*/ */
@ -98,7 +98,7 @@ $cv_skills = $cvData['skills'] ?? [];
<meta property="og:type" content="website"> <meta property="og:type" content="website">
<meta property="og:url" content="<?= $site_url ?>"> <meta property="og:url" content="<?= $site_url ?>">
<meta property="og:title" content="<?= $name ?>"> <meta property="og:title" content="<?= $name ?>">
<meta property="og:description" content="<?= $subtitle ?>"> <meta property="og:description" content="<?= $headline ?>">
<style> <style>
<?php <?php
@ -111,54 +111,71 @@ $cv_skills = $cvData['skills'] ?? [];
<body class="preload"> <body class="preload">
<main class="bento-grid"> <main class="bento-grid">
<section class="card profile">
<?php <section class="card hero">
if (file_exists($photo_file)) { <div class="hero-row hero-identity">
$avatarBase64 = base64_encode(file_get_contents($photo_file)); <?php
echo '<img src="data:image/png;base64,' . $avatarBase64 . '" alt="' . $name . '" class="avatar" width="120" height="160" />'; if (file_exists($photo_file)) {
} else { $avatarBase64 = base64_encode(file_get_contents($photo_file));
echo '<div class="avatar-placeholder"></div>'; echo '<img src="data:image/png;base64,' . $avatarBase64 . '" alt="' . $name . '" class="avatar" width="80" height="106" />';
} } else {
?> echo '<div class="avatar-placeholder"></div>';
<header class="header-text"> }
<h1><?= $name ?></h1> ?>
<p class="subtitle"><?= $subtitle ?></p> <div class="hero-name">
</header> <h1><?= $name ?></h1>
<?php if ($headline): ?>
<p class="headline"><?= $headline ?></p>
<?php endif; ?>
<?php if ($location): ?>
<p class="location"><?= $location ?></p>
<?php endif; ?>
</div>
</div>
<?php if ($role_summary): ?>
<div class="hero-row hero-description">
<p><?= $role_summary ?></p>
</div>
<?php endif; ?>
<div class="hero-row hero-contacts">
<?php foreach ($extra_contact_links as $label => $url): ?>
<a href="<?= $url ?>" target="_blank"><?= $label ?></a>
<?php endforeach; ?>
</div>
<div class="hero-row hero-nav">
<?php foreach ($nav_links as $label => $url): ?>
<a href="<?= trim($url) ?>" target="_blank"><?= $label ?></a>
<?php endforeach; ?>
</div>
</section> </section>
<section class="card about">
<h2>Bio</h2> <?php if ($summary): ?>
<?php foreach ($about_text as $para): ?> <section class="card summary">
<p><?= $para ?></p> <h2>Summary</h2>
<p><?= $summary ?></p>
</section>
<?php endif; ?>
<?php if ($highlights): ?>
<section class="card selected-work">
<h2>Selected Work</h2>
<?php foreach ($highlights as $h): ?>
<article class="highlight-item">
<h3><?= $h['title'] ?? '' ?></h3>
<?php if ($h['subtitle'] ?? ''): ?>
<p class="highlight-subtitle"><?= $h['subtitle'] ?></p>
<?php endif; ?>
<?php if ($h['description'] ?? ''): ?>
<p class="highlight-description"><?= $h['description'] ?></p>
<?php endif; ?>
</article>
<?php endforeach; ?> <?php endforeach; ?>
</section> </section>
<?php endif; ?>
<section class="card interests">
<h2>Likes</h2>
<p><?= $hardware_info ?></p>
</section>
<section class="card contact">
<h2>Remote_Access</h2>
<address class="mono-addr">
Email: <span id="contact-mail">uncovering...</span>
</address>
<address class="mono-addr">
Socials:
<?php foreach ($extra_contact_links as $label => $url): ?>
<br><a href="<?= $url ?>" target="_blank"><?= $label ?></a>
<?php endforeach; ?>
</address>
</section>
<section class="card links">
<h2>Navigation</h2>
<ul class="link-grid">
<?php foreach ($nav_links as $label => $url): ?>
<li><a href="<?= trim($url) ?>" target="_blank"><span><?= $label ?></span></a></li>
<?php endforeach; ?>
</ul>
</section>
<section class="card cv-container"> <section class="card cv-container">
<label class="cv-header" for="cv-toggle"> <label class="cv-header" for="cv-toggle">

View File

@ -74,7 +74,7 @@ body {
.bento-grid { .bento-grid {
display: grid; display: grid;
max-width: 800px; max-width: 1000px;
gap: 24px; gap: 24px;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
} }
@ -122,15 +122,13 @@ body {
filter: none !important; filter: none !important;
margin-right: 16px !important; margin-right: 16px !important;
} }
.profile { grid-column: span 3; } .hero { grid-column: span 3; }
.about { grid-column: span 2; }
.interests { grid-column: span 1; }
.contact { grid-column: span 1; }
.links { grid-column: span 2; }
.hiring-toggle { grid-column: span 3; } .hiring-toggle { grid-column: span 3; }
.summary { grid-column: span 3; }
.selected-work { grid-column: span 3; }
.cv-container { grid-column: span 3; } .cv-container { grid-column: span 3; }
.experience { grid-column: span 2; } .experience { grid-column: span 3; }
.skills { grid-column: span 1; } .skills { grid-column: span 3; }
.education { grid-column: span 3; } .education { grid-column: span 3; }
/* Shuffle Logic */ /* Shuffle Logic */
@ -144,11 +142,9 @@ body {
filter: none !important; filter: none !important;
margin-right: 16px !important; margin-right: 16px !important;
} }
.profile { transform: rotate(0.1deg); } .hero { transform: rotate(0.1deg); }
.about { transform: translate(-4px, 2px) rotate(-0.5deg); } .summary { transform: translate(-2px, 2px) rotate(-0.3deg); }
.interests { transform: translate(6px, -2px) rotate(0.4deg); } .selected-work { transform: translate(2px, -2px) rotate(-0.2deg); }
.links { transform: translate(-2px, -4px) rotate(-0.3deg); }
.contact { transform: translate(4px, 6px) rotate(0.5deg); }
.hiring-toggle { transform: translate(-2px, 3px) rotate(0.2deg); } .hiring-toggle { transform: translate(-2px, 3px) rotate(0.2deg); }
.experience { transform: translate(3px, -2px) rotate(-0.2deg); } .experience { transform: translate(3px, -2px) rotate(-0.2deg); }
.skills { transform: translate(-3px, 4px) rotate(0.6deg); } .skills { transform: translate(-3px, 4px) rotate(0.6deg); }
@ -174,6 +170,70 @@ body {
.profile { display: flex; align-items: center; gap: 32px; } .profile { display: flex; align-items: center; gap: 32px; }
.hero {
display: flex;
flex-direction: column;
gap: 16px;
}
.hero-identity {
display: flex;
align-items: center;
gap: 20px;
}
.hero-name {
flex: 1;
}
.hero-name h1 {
margin: 0 0 4px 0;
}
.hero-name .headline {
margin: 0 0 4px 0;
font-size: 1rem;
color: var(--accent-color);
}
.hero-name .location {
margin: 0;
font-size: 0.85rem;
opacity: 0.7;
}
.hero-description {
margin: 0;
}
.hero-description p {
margin: 0;
line-height: 1.5;
}
.hero-contacts {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.hero-contacts a {
color: var(--link-color);
text-decoration: none;
font-size: 0.9rem;
}
.hero-contacts a:hover {
text-decoration: underline;
}
.hero-nav {
display: flex;
flex-wrap: wrap;
gap: 12px;
padding-top: 8px;
border-top: 1px solid rgba(0, 243, 255, 0.15);
}
.hero-nav a {
color: var(--text-color);
text-decoration: none;
font-size: 0.85rem;
opacity: 0.8;
}
.hero-nav a:hover {
opacity: 1;
text-decoration: underline;
}
.hiring-toggle { .hiring-toggle {
padding: 12px 24px; padding: 12px 24px;
cursor: pointer; cursor: pointer;
@ -477,6 +537,8 @@ a { color: var(--link-color); text-decoration: none; }
margin-right: 16px !important; margin-right: 16px !important;
} }
.profile { flex-direction: column; text-align: center; } .profile { flex-direction: column; text-align: center; }
.hero { flex-direction: column; text-align: center; }
.hero-identity { flex-direction: column; text-align: center; }
} }
/* Print mode */ /* Print mode */