112 lines
5.8 KiB
PHP
112 lines
5.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/app.php';
|
|
|
|
ensure_recliner_schema();
|
|
$meta = project_meta();
|
|
$presetId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
|
|
$preset = $presetId ? get_preset((int) $presetId) : null;
|
|
http_response_code($preset ? 200 : 404);
|
|
$assetVersion = (string) max(@filemtime(__DIR__ . '/assets/css/custom.css') ?: time(), @filemtime(__DIR__ . '/assets/js/main.js') ?: time());
|
|
$pageTitle = ($preset ? $preset['name'] . ' · ' : '') . $meta['name'];
|
|
$pageDescription = $preset
|
|
? 'Preset detail for ' . $preset['name'] . ' with a saved recline angle of ' . $preset['angle_deg'] . ' degrees.'
|
|
: $meta['description'];
|
|
?>
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= e($pageTitle) ?></title>
|
|
<meta name="description" content="<?= e($pageDescription) ?>">
|
|
<meta name="theme-color" content="#0b0d10">
|
|
<?php if (!empty($meta['image'])): ?>
|
|
<meta property="og:image" content="<?= e($meta['image']) ?>">
|
|
<meta property="twitter:image" content="<?= e($meta['image']) ?>">
|
|
<?php endif; ?>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
|
<link rel="stylesheet" href="/assets/css/custom.css?v=<?= e($assetVersion) ?>">
|
|
</head>
|
|
<body>
|
|
<header class="border-bottom border-secondary-subtle shell-header">
|
|
<nav class="navbar navbar-expand-lg navbar-dark">
|
|
<div class="container-xxl py-2">
|
|
<a class="navbar-brand fw-semibold" href="/index.php">Recliner Haptics</a>
|
|
<div class="ms-auto d-flex gap-2">
|
|
<a class="btn btn-sm btn-outline-light" href="/index.php#presets">Back to presets</a>
|
|
<?php if ($preset): ?>
|
|
<a class="btn btn-sm btn-light" href="/index.php?preset=<?= e((string) $preset['id']) ?>#simulator">Open in simulator</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main class="py-4 py-lg-5">
|
|
<div class="container-xl">
|
|
<?php if (!$preset): ?>
|
|
<section class="panel p-4 p-lg-5 text-center mx-auto" style="max-width: 720px;">
|
|
<div class="small-label">Preset detail</div>
|
|
<h1 class="h3 mb-3">Preset not found</h1>
|
|
<p class="text-secondary mb-4">The requested preset does not exist yet or may have been removed.</p>
|
|
<a class="btn btn-light" href="/index.php#presets">Return to the simulator</a>
|
|
</section>
|
|
<?php else: ?>
|
|
<section class="hero-panel panel p-4 p-lg-5 mb-4">
|
|
<div class="row g-4 align-items-center">
|
|
<div class="col-lg-8">
|
|
<div class="eyebrow mb-3">Preset detail · #<?= e((string) $preset['id']) ?></div>
|
|
<h1 class="display-title mb-3"><?= e($preset['name']) ?></h1>
|
|
<p class="lead text-secondary mb-4">A saved recliner profile for repeatable haptic demos. Use this screen to review the settings, then reopen it in the simulator to test with a connected controller.</p>
|
|
<div class="d-flex flex-wrap gap-2 meta-pills">
|
|
<span class="chip"><?= e((string) $preset['angle_deg']) ?>° angle</span>
|
|
<span class="chip"><?= e((string) $preset['intensity_pct']) ?>% intensity</span>
|
|
<span class="chip"><?= e(ucfirst((string) $preset['pattern_mode'])) ?> rumble</span>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<div class="panel inset-panel p-3 h-100">
|
|
<div class="small-label mb-3">Profile tone</div>
|
|
<div class="h4 mb-2"><?= e(preset_tone((int) $preset['angle_deg'])) ?></div>
|
|
<p class="text-secondary small mb-0">Saved on <?= e(date('F j, Y H:i', strtotime((string) $preset['created_at']))) ?> UTC.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-lg-7">
|
|
<section class="panel p-4 h-100">
|
|
<div class="small-label mb-3">Settings overview</div>
|
|
<div class="spec-list preset-detail-specs">
|
|
<div><span>Recline angle</span><strong><?= e((string) $preset['angle_deg']) ?>°</strong></div>
|
|
<div><span>Vibration intensity</span><strong><?= e((string) $preset['intensity_pct']) ?>%</strong></div>
|
|
<div><span>Pattern</span><strong><?= e(ucfirst((string) $preset['pattern_mode'])) ?></strong></div>
|
|
<div><span>Saved at</span><strong><?= e((string) $preset['created_at']) ?></strong></div>
|
|
</div>
|
|
<hr class="border-secondary-subtle my-4">
|
|
<div class="small-label mb-2">Operator notes</div>
|
|
<p class="text-secondary mb-0"><?= e($preset['notes'] ?: 'No notes added for this preset.') ?></p>
|
|
</section>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<section class="panel p-4 h-100 d-flex flex-column justify-content-between">
|
|
<div>
|
|
<div class="small-label mb-3">Next action</div>
|
|
<h2 class="h4 mb-2">Load this profile into the simulator</h2>
|
|
<p class="text-secondary mb-4">Jump back into the main workspace with these saved values prefilled. Then press <strong>Test vibration</strong> to drive the controller.</p>
|
|
</div>
|
|
<div class="d-grid gap-2">
|
|
<a class="btn btn-light" href="/index.php?preset=<?= e((string) $preset['id']) ?>#simulator">Open in simulator</a>
|
|
<a class="btn btn-outline-light" href="/index.php#presets">Browse recent presets</a>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>
|