Make lazy-auth-server usable on mobile (#714)
The consent page shipped without a viewport meta tag, so mobile browsers laid it out at a desktop width. Its Approve/Deny buttons were 37px tall and nested a <button> inside an <a>, which is invalid HTML — interactive content is not permitted inside a link. - Add a viewport meta tag to the consent page - Replace the <a><button> nesting with anchors styled as buttons (role="button" plus a Space-key handler to keep button keyboard semantics) - Lay the actions out as a wrapping flex row with equal 56px tap targets - Add touch-action: manipulation so a tap resolves to a click immediately rather than waiting on the double-tap-to-zoom gesture - Suppress long-press text selection and the iOS callout menu on the buttons, scoped so the card's client/redirect details stay copyable - Give buttons an :active style since removing the native tap highlight otherwise leaves no press feedback - Apply the same 56px minimum and touch handling to the in-app view's buttons (the fullscreen toggle was ~33x33)
This commit is contained in:
parent
cf87f2a2c2
commit
9778cf97a2
2 changed files with 38 additions and 6 deletions
|
|
@ -414,20 +414,36 @@ async function handleAuthorize(req: Request, res: Response) {
|
|||
if (state) denyUrl.searchParams.set("state", state);
|
||||
res.type("text/html").send(/*html*/ `<!DOCTYPE html>
|
||||
<html><head><meta charset="utf-8"><title>Authorize</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>body{font-family:system-ui,sans-serif;max-width:420px;margin:40px auto;padding:0 16px;color-scheme:light dark}
|
||||
.box{border:1px solid #ccc;border-radius:8px;padding:20px}dl{display:grid;grid-template-columns:auto 1fr;gap:6px 12px;font-size:14px;margin:16px 0}
|
||||
.box{border:1px solid #ccc;border-radius:8px;padding:20px}
|
||||
dl{display:grid;grid-template-columns:auto 1fr;gap:6px 12px;font-size:14px;margin:16px 0}
|
||||
dt{color:#888}dd{margin:0;word-break:break-all}
|
||||
button{padding:10px 20px;margin:4px;font-size:15px;font-weight:bold;border:none;border-radius:6px;cursor:pointer}
|
||||
.approve{background:#1a7a3e;color:#fff}.deny{background:#b91c1c;color:#fff}</style></head>
|
||||
.actions{display:flex;flex-wrap:wrap;gap:12px;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
|
||||
.btn{box-sizing:border-box;flex:1;min-height:56px;min-width:56px;display:flex;align-items:center;justify-content:center;
|
||||
padding:12px 20px;font-size:16px;font-weight:bold;border:none;border-radius:8px;cursor:pointer;
|
||||
text-decoration:none;color:#fff;touch-action:manipulation;-webkit-tap-highlight-color:transparent}
|
||||
.btn:active{filter:brightness(0.8)}
|
||||
.approve{background:#1a7a3e}.deny{background:#b91c1c}</style></head>
|
||||
<body><div class="box">
|
||||
<h2>🔑 Mock Authorization</h2>
|
||||
<p>An application is requesting access:</p>
|
||||
<dl><dt>Client</dt><dd>${escapeHtml(client_id ?? "(none)")}</dd>
|
||||
<dt>Scope</dt><dd>${escapeHtml(scope ?? "(default)")}</dd>
|
||||
<dt>Redirect</dt><dd>${escapeHtml(redirect_uri)}</dd></dl>
|
||||
<a href="${escapeHtml(approveUrl.href)}"><button class="approve">Approve</button></a>
|
||||
<a href="${escapeHtml(denyUrl.href)}"><button class="deny">Deny</button></a>
|
||||
</div></body></html>`);
|
||||
<div class="actions">
|
||||
<a class="btn approve" role="button" href="${escapeHtml(approveUrl.href)}">Approve</a>
|
||||
<a class="btn deny" role="button" href="${escapeHtml(denyUrl.href)}">Deny</a>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Anchors only activate on Enter; role="button" promises Space too.
|
||||
for (const a of document.querySelectorAll(".btn"))
|
||||
a.addEventListener("keydown", (e) => {
|
||||
if (e.key === " ") { e.preventDefault(); a.click(); }
|
||||
});
|
||||
</script>
|
||||
</body></html>`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,17 @@
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-sm);
|
||||
/* Keep a long press on or near the buttons from starting text selection
|
||||
or raising the iOS callout menu instead of a click. */
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
|
||||
button {
|
||||
/* Match the consent page's 56px tap targets (server.ts .btn). */
|
||||
min-height: 56px;
|
||||
min-width: 56px;
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
border: none;
|
||||
border-radius: var(--border-radius-md);
|
||||
|
|
@ -27,12 +35,20 @@ button {
|
|||
font-weight: var(--font-weight-bold);
|
||||
background-color: var(--color-accent);
|
||||
cursor: pointer;
|
||||
/* Suppress the double-tap-to-zoom gesture so a tap resolves to a click
|
||||
immediately instead of waiting to see if a second tap follows. */
|
||||
touch-action: manipulation;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:active:not(:disabled) {
|
||||
filter: brightness(0.85);
|
||||
}
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background-color: color-mix(
|
||||
in srgb,
|
||||
|
|
|
|||
Loading…
Reference in a new issue