UAT-3: browser gate (hard stop) + iPad Safari fix

Spec CAPTURE.md §Browsers: Phone iOS Safari / Android Chrome, PC
Chrome / Edge / Firefox, others hard stop.

- browserGate.js: UA detection + allowlist (pure, DOM-free)
- +layout.svelte: renders hard-stop panel when unsupported
- iPadOS 13+ reports as Macintosh — added Safari rule (Version/ +
  Safari/ without Chrome/) so iPad Safari is not blocked
- 27 unit tests incl. iPad Safari regression
- 107/107 full suite green
This commit is contained in:
Ty
2026-09-14 07:44:49 -07:00
parent a83c9239ff
commit 0d06e6f7b7
4 changed files with 470 additions and 5 deletions
+63 -5
View File
@@ -1,13 +1,71 @@
<script>
import '../app.css';
import { checkBrowserGate } from '$lib/core/browserGate.js';
// UAT-3: hard-stop browser gate (CAPTURE.md §Browsers).
// Client-side only: the gate must be invisible to crawlers/bots
// and to any non-JS context, and the app must not render in an
// unsupported browser.
const gate = typeof navigator !== 'undefined' ? checkBrowserGate(navigator.userAgent) : null;
let unsupported = $state(gate ? !gate.supported : false);
let browserName = $state(gate ? gate.browser.name : 'this browser');
</script>
<svelte:head>
<title>SlabUploader — Milestone 1</title>
</svelte:head>
<main>
<h1>SlabUploader</h1>
<p>Milestone 1 — Capture (browser-only)</p>
<slot />
</main>
{#if unsupported}
<!-- Hard stop: the app does NOT render in an unsupported browser. -->
<div class="gate">
<h1>Unsupported browser</h1>
<p>SlabUploader does not work in <strong>{browserName}</strong>.</p>
<p class="sub">Use one of the supported clients:</p>
<ul>
<li>Phone — iOS Safari, Android Chrome</li>
<li>PC — Chrome, Edge, Firefox</li>
</ul>
</div>
{:else}
<main>
<h1>SlabUploader</h1>
<p>Milestone 1 — Capture (browser-only)</p>
<slot />
</main>
{/if}
<style>
.gate {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
max-width: 32rem;
margin: 1rem auto;
padding: 2rem;
border: 2px solid #b00020;
border-radius: 0.5rem;
text-align: center;
}
.gate h1 {
color: #b00020;
margin: 0 0 1rem;
}
.gate .sub {
margin: 1rem 0 0.5rem;
}
.gate ul {
text-align: left;
margin: 0;
padding: 0;
list-style: none;
}
.gate li {
margin: 0.25rem 0;
}
</style>