Descriptions of unreliable narrator added
This commit is contained in:
parent
61b4cad61d
commit
0830dcf6e4
6 changed files with 79 additions and 5 deletions
2
404.php
2
404.php
|
|
@ -95,7 +95,7 @@ http_response_code(404);
|
|||
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
<link rel="icon" type="image/png" href="assets/img/moto_travel.png">
|
||||
<link rel="stylesheet" href="style.css?v=20260531u">
|
||||
<link rel="stylesheet" href="style.css?v=20260621a">
|
||||
<style>
|
||||
.not-found-card{
|
||||
max-width:680px;
|
||||
|
|
|
|||
57
_header.php
57
_header.php
|
|
@ -2,4 +2,59 @@
|
|||
// Shared header for public pages (index.php, contact.php, etc.)
|
||||
$brandUrl = $brandUrl ?? '/';
|
||||
if ($brandUrl === '') $brandUrl = '/';
|
||||
?><header class="site-header admin-header"><div class="brand-wrap"><a class="header-logo" href="<?=h($brandUrl)?>" aria-label="MVLog home"><img src="/assets/img/moto_travel.png" alt=""></a><a class="brand" href="<?=h($brandUrl)?>"><h1><?=h($siteHeaderTitle)?></h1><p>journal of an<br>unreliable narrator.</p></a></div><div class="header-actions"><button id="push-toggle" class="push-toggle" type="button" hidden aria-label="Notifications" title="Notifications"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 22a2.7 2.7 0 0 0 2.6-2h-5.2A2.7 2.7 0 0 0 12 22Zm7-6V11a7 7 0 0 0-5-6.7V3a2 2 0 0 0-4 0v1.3A7 7 0 0 0 5 11v5l-2 2v1h18v-1l-2-2Z"/></svg></button><a class="rss-link" href="/feed.php" aria-label="RSS feed" title="RSS feed"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.2 17.8a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM2.2 8.7v3.1a10 10 0 0 1 10 10h3.1A13.1 13.1 0 0 0 2.2 8.7Zm0-5.5v3.1a15.5 15.5 0 0 1 15.5 15.5h3.1A18.6 18.6 0 0 0 2.2 3.2Z"/></svg></a><a class="contact-link" href="/contact.php" aria-label="Contact" title="Contact"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z"/></svg></a></div></header>
|
||||
?><header class="site-header admin-header"><div class="brand-wrap"><a class="header-logo" href="<?=h($brandUrl)?>" aria-label="MVLog home"><img src="/assets/img/moto_travel.png" alt=""></a><a class="brand" href="<?=h($brandUrl)?>"><h1><?=h($siteHeaderTitle)?></h1><p class="narrator-trigger" tabindex="0" role="button" aria-haspopup="dialog" aria-label="Show unreliable narrator description">journal of an<br>unreliable narrator.</p></a><div class="narrator-balloon" role="dialog" aria-live="polite" hidden></div></div><div class="header-actions"><button id="push-toggle" class="push-toggle" type="button" hidden aria-label="Notifications" title="Notifications"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 22a2.7 2.7 0 0 0 2.6-2h-5.2A2.7 2.7 0 0 0 12 22Zm7-6V11a7 7 0 0 0-5-6.7V3a2 2 0 0 0-4 0v1.3A7 7 0 0 0 5 11v5l-2 2v1h18v-1l-2-2Z"/></svg></button><a class="rss-link" href="/feed.php" aria-label="RSS feed" title="RSS feed"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.2 17.8a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM2.2 8.7v3.1a10 10 0 0 1 10 10h3.1A13.1 13.1 0 0 0 2.2 8.7Zm0-5.5v3.1a15.5 15.5 0 0 1 15.5 15.5h3.1A18.6 18.6 0 0 0 2.2 3.2Z"/></svg></a><a class="contact-link" href="/contact.php" aria-label="Contact" title="Contact"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z"/></svg></a></div></header>
|
||||
<script>
|
||||
(function(){
|
||||
const trigger = document.querySelector('.narrator-trigger');
|
||||
const balloon = document.querySelector('.narrator-balloon');
|
||||
if (!trigger || !balloon) return;
|
||||
let descriptions = null;
|
||||
let hideTimer = null;
|
||||
const fallback = [
|
||||
"Motorcycle traveler with a camera, a sense of humor, and a complicated relationship with GPS instructions."
|
||||
];
|
||||
async function loadDescriptions(){
|
||||
if (descriptions) return descriptions;
|
||||
try {
|
||||
const res = await fetch('/unreliable_narrator_descriptions.json', {cache: 'force-cache'});
|
||||
const data = await res.json();
|
||||
descriptions = Array.isArray(data) && data.length ? data.filter(v => typeof v === 'string' && v.trim()) : fallback;
|
||||
} catch(e) {
|
||||
descriptions = fallback;
|
||||
}
|
||||
return descriptions;
|
||||
}
|
||||
function pick(list){ return list[Math.floor(Math.random() * list.length)] || fallback[0]; }
|
||||
async function showBalloon(ev){
|
||||
if (ev) { ev.preventDefault(); ev.stopPropagation(); }
|
||||
clearTimeout(hideTimer);
|
||||
const list = await loadDescriptions();
|
||||
balloon.textContent = pick(list);
|
||||
balloon.hidden = false;
|
||||
balloon.classList.add('is-open');
|
||||
}
|
||||
function hideBalloonSoon(){
|
||||
clearTimeout(hideTimer);
|
||||
hideTimer = setTimeout(() => {
|
||||
balloon.classList.remove('is-open');
|
||||
balloon.hidden = true;
|
||||
}, 180);
|
||||
}
|
||||
trigger.addEventListener('mouseenter', showBalloon);
|
||||
trigger.addEventListener('focus', showBalloon);
|
||||
trigger.addEventListener('mouseleave', hideBalloonSoon);
|
||||
trigger.addEventListener('blur', hideBalloonSoon);
|
||||
trigger.addEventListener('click', function(ev){
|
||||
if (!balloon.hidden && balloon.classList.contains('is-open')) {
|
||||
ev.preventDefault(); ev.stopPropagation(); hideBalloonSoon(); return;
|
||||
}
|
||||
showBalloon(ev);
|
||||
});
|
||||
balloon.addEventListener('mouseenter', () => clearTimeout(hideTimer));
|
||||
balloon.addEventListener('mouseleave', hideBalloonSoon);
|
||||
document.addEventListener('click', function(ev){
|
||||
if (!balloon.hidden && !balloon.contains(ev.target) && !trigger.contains(ev.target)) hideBalloonSoon();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1539,7 +1539,7 @@ $editDir = null; $editStatus = ''; $editRunning = false; $editData = ['title'=>'
|
|||
if ($editName !== '' || $editId !== '') { try { $editDir = resolve_input_dir_from_request($config['uploads_dir'], $editId, $editName, $articleIndex); $editStatus = input_dir_status($editDir); $editRunning = input_dir_running($editDir); if (!$editRunning) { $editData = read_data($editDir); $editFiles = media_sort_files($editDir, list_files($editDir)); } } catch (Throwable $e) { $err = $e->getMessage(); } }
|
||||
$runningJobs = active_worker_jobs($config);
|
||||
?>
|
||||
<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>MVLog Admin</title><link rel="icon" type="image/png" href="assets/img/moto_travel.png"><link rel="stylesheet" href="style.css?v=20260531u"><style>.admin-search-form{display:flex;flex-wrap:nowrap;align-items:center;gap:.55rem;margin:0 0 .6rem;overflow-x:auto;padding-bottom:2px}.admin-search-wrap{position:relative;min-width:180px;flex:1 1 auto}.admin-search-wrap input{margin:0;padding-right:2.15rem}.admin-search-clear{position:absolute;right:.45rem;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;background:#C46A3A;color:#111315;text-decoration:none;font-size:1rem;line-height:1;font-weight:700;box-shadow:0 1px 4px #0007;transition:opacity .15s ease,transform .15s ease}.admin-search-clear:hover{background:#d97b48;color:#111315;transform:translateY(-50%) scale(1.05)}.admin-search-clear.is-empty{opacity:.38;pointer-events:none}.admin-search-submit{display:inline-grid;place-items:center;width:2.35rem;height:2.35rem;padding:0;border-radius:.5rem;background:#C46A3A;color:#111315;flex:0 0 auto}.admin-search-submit .icon{font-size:1.02rem;line-height:1;transform:translateY(.01em)}.admin-search-filters{display:flex;flex-wrap:nowrap;gap:.7rem;align-items:center;flex:0 0 auto;white-space:nowrap}.admin-filter-item{display:inline-flex;align-items:center;gap:.35rem;margin:0;white-space:nowrap;font-size:.92rem}.admin-filter-item input[type=checkbox]{width:.9rem;height:.9rem;margin:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.description-teaser{margin:.2rem 0 .45rem;color:#eadfca}.description-quote{margin:.2rem 0 .45rem;font-style:italic;font-size:.82rem;color:#d4d7dd}.meta a{color:inherit;text-decoration:none}.meta a:hover{text-decoration:underline}.meta-filter{display:inline-flex;align-items:center;gap:.25rem;padding:.12rem .5rem;border-radius:999px;background:rgba(255,255,255,.06);cursor:pointer;user-select:none;transition:background-color .15s ease,transform .15s ease}.meta-filter:hover,.meta-filter:focus-visible{background:rgba(255,255,255,.12);transform:translateY(-1px);outline:none}.meta-filter:focus-visible{box-shadow:0 0 0 2px rgba(202,162,109,.35)}</style></head><body>
|
||||
<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>MVLog Admin</title><link rel="icon" type="image/png" href="assets/img/moto_travel.png"><link rel="stylesheet" href="style.css?v=20260621a"><style>.admin-search-form{display:flex;flex-wrap:nowrap;align-items:center;gap:.55rem;margin:0 0 .6rem;overflow-x:auto;padding-bottom:2px}.admin-search-wrap{position:relative;min-width:180px;flex:1 1 auto}.admin-search-wrap input{margin:0;padding-right:2.15rem}.admin-search-clear{position:absolute;right:.45rem;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;background:#C46A3A;color:#111315;text-decoration:none;font-size:1rem;line-height:1;font-weight:700;box-shadow:0 1px 4px #0007;transition:opacity .15s ease,transform .15s ease}.admin-search-clear:hover{background:#d97b48;color:#111315;transform:translateY(-50%) scale(1.05)}.admin-search-clear.is-empty{opacity:.38;pointer-events:none}.admin-search-submit{display:inline-grid;place-items:center;width:2.35rem;height:2.35rem;padding:0;border-radius:.5rem;background:#C46A3A;color:#111315;flex:0 0 auto}.admin-search-submit .icon{font-size:1.02rem;line-height:1;transform:translateY(.01em)}.admin-search-filters{display:flex;flex-wrap:nowrap;gap:.7rem;align-items:center;flex:0 0 auto;white-space:nowrap}.admin-filter-item{display:inline-flex;align-items:center;gap:.35rem;margin:0;white-space:nowrap;font-size:.92rem}.admin-filter-item input[type=checkbox]{width:.9rem;height:.9rem;margin:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.description-teaser{margin:.2rem 0 .45rem;color:#eadfca}.description-quote{margin:.2rem 0 .45rem;font-style:italic;font-size:.82rem;color:#d4d7dd}.meta a{color:inherit;text-decoration:none}.meta a:hover{text-decoration:underline}.meta-filter{display:inline-flex;align-items:center;gap:.25rem;padding:.12rem .5rem;border-radius:999px;background:rgba(255,255,255,.06);cursor:pointer;user-select:none;transition:background-color .15s ease,transform .15s ease}.meta-filter:hover,.meta-filter:focus-visible{background:rgba(255,255,255,.12);transform:translateY(-1px);outline:none}.meta-filter:focus-visible{box-shadow:0 0 0 2px rgba(202,162,109,.35)}</style></head><body>
|
||||
<header class="site-header admin-header"><div class="brand-wrap"><a class="header-logo" href="/" aria-label="MVLog home" target="_blank"><img src="assets/img/moto_travel.png" alt=""></a><a class="brand" href="index.php"><h1 style="font-size:1.15rem">MVLog <span class="admin-word">Admin</span></h1><p>journal of an<br>unreliable narrator.</p></a></div></header>
|
||||
<main>
|
||||
<?php if($err): ?><div class="err"><?=h($err)?></div><?php endif; ?>
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ function render_blank_page(){
|
|||
<?php include __DIR__ . '/_pwa_head.php'; ?>
|
||||
|
||||
<link rel="icon" type="image/png" href="/assets/img/moto_travel.png">
|
||||
<link rel="stylesheet" href="/style.css?v=20260531u">
|
||||
<link rel="stylesheet" href="/style.css?v=20260621a">
|
||||
<style>html,body{height:100%;overflow:hidden}body{height:100dvh}main{flex:1;min-height:0}</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -547,7 +547,7 @@ $siteHeaderTitle = $headerTitles[array_rand($headerTitles)];
|
|||
|
||||
<link rel="alternate" type="application/rss+xml" title="MVLog RSS" href="/feed.php">
|
||||
<link rel="icon" type="image/png" href="/assets/img/moto_travel.png">
|
||||
<link rel="stylesheet" href="/style.css?v=20260531u">
|
||||
<link rel="stylesheet" href="/style.css?v=20260621a">
|
||||
<style>
|
||||
.filter-form{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.55rem;align-items:center;margin:0 0 .4rem}
|
||||
.filter-input-wrap{position:relative;min-width:0}
|
||||
|
|
|
|||
|
|
@ -216,3 +216,7 @@ body.map-lightbox-open { overflow: hidden; }
|
|||
.site-header .header-actions .rss-link,
|
||||
.site-header .header-actions .contact-link{position:static!important}
|
||||
.site-header .header-actions svg{width:.75rem!important;height:.75rem!important;max-width:.75rem!important;max-height:.75rem!important;display:block}
|
||||
|
||||
/* Unreliable narrator header balloon */
|
||||
.narrator-trigger{cursor:help;outline:none}.narrator-trigger:focus-visible{color:#F3F4F6;text-shadow:0 0 .35rem rgba(59,167,160,.55)}.narrator-balloon{position:absolute;left:50%;top:calc(100% + .85rem);transform:translateX(-50%) translateY(-.25rem);width:min(28rem,calc(100vw - 2rem));box-sizing:border-box;padding:.85rem 1rem;border:1px solid rgba(59,167,160,.55);border-radius:.85rem;background:rgba(17,19,21,.96);box-shadow:0 1rem 2.4rem rgba(0,0,0,.55);color:#F3F4F6;font-family:IBMPlexCaption,system-ui,sans-serif;font-size:.92rem;line-height:1.45;letter-spacing:normal;text-transform:none;text-align:left;z-index:1200;opacity:0;pointer-events:none;transition:opacity .16s ease,transform .16s ease}.narrator-balloon::before{content:"";position:absolute;left:50%;top:-.48rem;width:.85rem;height:.85rem;transform:translateX(-50%) rotate(45deg);background:rgba(17,19,21,.96);border-left:1px solid rgba(59,167,160,.55);border-top:1px solid rgba(59,167,160,.55)}.narrator-balloon.is-open{opacity:1;pointer-events:auto;transform:translateX(-50%) translateY(0)}
|
||||
@media (max-width:640px){.narrator-balloon{top:calc(100% + .65rem);font-size:.86rem;width:min(23rem,calc(100vw - 1.2rem));}}
|
||||
|
|
|
|||
15
unreliable_narrator_descriptions.json
Normal file
15
unreliable_narrator_descriptions.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[
|
||||
"Croatian by origin, Danish by address, and perpetually somewhere between a plan and a detour. Most journeys start with a destination in mind and end with a story that wasn't part of the itinerary.",
|
||||
"Motorcycle traveler with a talent for finding interesting roads and questionable shortcuts. My memory tends to improve stories over time, which is why this is an unreliable journal rather than an official historical record.",
|
||||
"Moved to Denmark, learned that weather is mostly a state of mind, and started exploring Europe on two wheels. Somewhere along the way discovered that facts are important, but a good story is often more memorable.",
|
||||
"Software engineer by profession, motorcycle traveler by preference, and accidental storyteller whenever things fail to go according to plan.",
|
||||
"The unreliable narrator is someone who genuinely intends to tell the truth but occasionally remembers events the way they should have happened rather than the way they actually did.",
|
||||
"Motorcycle traveler, hockey lover, software engineer, and enthusiastic amateur at most other things. I believe every bad decision deserves at least one good story.",
|
||||
"The unreliable narrator is someone who starts with the facts, improves them slightly for dramatic effect, and eventually becomes convinced that's how it happened all along.",
|
||||
"A believer in motorcycles, loud music, spontaneous decisions, and the theory that getting lost is just sightseeing without a schedule.",
|
||||
"Hockey fan, motorcycle traveler, and collector of roads that looked like excellent ideas on the map.",
|
||||
"Born in Germany, raised in Croatia, living in Denmark, and still not entirely sure where I'm going. Fortunately, that's rarely stopped me.",
|
||||
"Equal parts curiosity, stubbornness, and fuel. The exact proportions vary by country.",
|
||||
"Motorcycle traveler with a camera, a sense of humor, and a complicated relationship with GPS instructions.",
|
||||
"Liking long roads, loud guitars, hockey, pizza, and adventures that sound slightly irresponsible when explained afterward."
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue