fix(collections): make per-card remove buttons usable on touch
All checks were successful
deploy / test-backend (pull_request) Successful in 28m14s
deploy / test-frontend (pull_request) Successful in 10m17s
deploy / build-and-push (pull_request) Has been skipped
deploy / deploy (pull_request) Has been skipped

The remove buttons on a collection's cards were revealed only on
hover / focus-within (opacity 0 → 1), so on touch they were invisible and
undiscoverable. Show them persistently at the 640px breakpoint and enlarge
the hit area from 24px to 32px (kept below the full 44px floor because the
button floats over a 4-up cover thumbnail).

Test pins the CSS contract (jsdom can't evaluate @media): the mobile block
makes `.remove` opaque.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-25 20:08:16 +02:00
parent dee53fa212
commit 9a16082015
5 changed files with 65 additions and 3 deletions

2
backend/Cargo.lock generated
View File

@@ -1517,7 +1517,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mangalord"
version = "0.88.0"
version = "0.88.1"
dependencies = [
"anyhow",
"argon2",

View File

@@ -1,6 +1,6 @@
[package]
name = "mangalord"
version = "0.88.0"
version = "0.88.1"
edition = "2021"
default-run = "mangalord"

View File

@@ -1,6 +1,6 @@
{
"name": "mangalord-frontend",
"version": "0.88.0",
"version": "0.88.1",
"private": true,
"type": "module",
"scripts": {

View File

@@ -406,6 +406,19 @@
opacity: 1;
}
/* Touch has no hover, so the reveal-on-hover treatment leaves the
remove buttons invisible and undiscoverable. Show them persistently
and enlarge the hit area on phones. (Capped well below 44px because
the button floats over a 4-up cover thumbnail — a full touch-floor
square would swallow the cover.) */
@media (max-width: 640px) {
.remove {
opacity: 1;
width: 32px;
height: 32px;
}
}
.icon-btn {
display: inline-flex;
align-items: center;

View File

@@ -0,0 +1,49 @@
import { describe, it, expect } from 'vitest';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
// The per-card "remove" buttons on a collection are revealed on hover /
// focus-within (opacity 0 → 1), which leaves them invisible and
// undiscoverable on touch. They must be shown persistently at the mobile
// breakpoint. jsdom can't evaluate @media or layout, so this pins the CSS
// contract: the 640px block makes `.remove` opaque. (Same approach as the
// shared touch-target contract test.)
const SRC = readFileSync(
resolve(process.cwd(), 'src/routes/collections/[id]/+page.svelte'),
'utf8'
);
// Brace-balanced extraction of every `@media (max-width: 640px) { ... }` body.
function mobileBlocks(css: string): string {
const marker = '@media (max-width: 640px)';
let out = '';
let from = 0;
for (;;) {
const start = css.indexOf(marker, from);
if (start === -1) break;
const open = css.indexOf('{', start);
if (open === -1) break;
let depth = 0;
let i = open;
for (; i < css.length; i++) {
if (css[i] === '{') depth++;
else if (css[i] === '}') {
depth--;
if (depth === 0) break;
}
}
out += css.slice(open + 1, i) + '\n';
from = i + 1;
}
return out;
}
const squish = (s: string) => s.replace(/\s+/g, ' ');
describe('collection remove buttons on touch', () => {
it('reveals the remove buttons persistently at the mobile breakpoint', () => {
const mobile = squish(mobileBlocks(SRC));
expect(mobile).toMatch(/\.remove[^}]*opacity:\s*1/);
});
});