chore(frontend): add ESLint + Prettier; fix real findings; format the tree

The frontend had no JS/TS linter — only svelte-check. Add flat-config ESLint (typescript-eslint
+ eslint-plugin-svelte) and Prettier (tabs/single-quote, matching the existing style).

Rules encode "catch bugs, not enforce taste":
  - svelte/require-each-key KEPT — it is the exact bug class as the feed mis-tap fix. Fixed every
    flagged block: keyed activeFilters, filteredUsers, stagedFiles (by previewUrl), captionTags,
    admin tabs/jobs/users, the export-viewer suggestions/filters/comments, and the static skeleton
    loops.
  - svelte/prefer-svelte-reactivity KEPT — inline-disabled only the verified-safe sites (a local
    freq Map in a $derived.by, throwaway URLSearchParams query builders), with a reason each.
  - svelte/no-navigation-without-resolve OFF — wants resolve() around every goto()/href; taste, not
    a bug, and pure churn.
  - svelte/no-unused-svelte-ignore OFF — those comments are consumed by svelte-check, which ESLint
    can't see, so it wrongly calls them unused; removing them would reintroduce a11y warnings.
  - no-explicit-any OFF for *.test.ts only (partial fixtures legitimately use any).

Real code fixes beyond keys: removed a dead jobLabel(), an unused ViewerComment import and unused
catch binding, an unused scroll-lock arg, and replaced an empty interface with a type alias.

Then `prettier --write` (54 files). Formatting only. Verified: eslint clean, svelte-check 0 errors,
vitest 46 passed, vite build succeeds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
fabi
2026-07-15 20:45:42 +02:00
parent 4d14df18d0
commit f8cba95e49
59 changed files with 4046 additions and 998 deletions

View File

@@ -46,9 +46,7 @@ export class SlideQueue {
// 2. Refill shuffle queue from `allKnown` minus recently shown.
if (this.shuffleQueue.length === 0) {
this.shuffleQueue = shuffle(
Array.from(this.allKnown.values()).filter(
(s) => !this.recentlyShown.includes(s.id)
)
Array.from(this.allKnown.values()).filter((s) => !this.recentlyShown.includes(s.id))
);
// If everything is recently shown (small event), fall back to the full pool.
if (this.shuffleQueue.length === 0) {

View File

@@ -20,14 +20,7 @@
>
{#if isVideo}
<!-- svelte-ignore a11y_media_has_caption -->
<video
{src}
autoplay
muted
playsinline
{onended}
class="h-full w-full object-contain"
></video>
<video {src} autoplay muted playsinline {onended} class="h-full w-full object-contain"></video>
{:else}
<img {src} alt="" class="h-full w-full object-contain" />
{/if}
@@ -35,7 +28,11 @@
<style>
@keyframes crossfade-in {
from { opacity: 0; }
to { opacity: 1; }
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>

View File

@@ -24,14 +24,7 @@
>
{#if isVideo}
<!-- svelte-ignore a11y_media_has_caption -->
<video
{src}
autoplay
muted
playsinline
{onended}
class="h-full w-full object-contain"
></video>
<video {src} autoplay muted playsinline {onended} class="h-full w-full object-contain"></video>
{:else}
<img
{src}
@@ -44,11 +37,19 @@
<style>
@keyframes kb-fade {
from { opacity: 0; }
to { opacity: 1; }
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes kb-zoom {
from { transform: scale(1.0); }
to { transform: scale(1.1); }
from {
transform: scale(1);
}
to {
transform: scale(1.1);
}
}
</style>

View File

@@ -13,7 +13,9 @@ let sentinel: SentinelLike | null = null;
let visibilityHandler: (() => void) | null = null;
export async function acquireWakeLock(): Promise<void> {
const wakeLock = (navigator as Navigator & { wakeLock?: { request: (t: string) => Promise<SentinelLike> } }).wakeLock;
const wakeLock = (
navigator as Navigator & { wakeLock?: { request: (t: string) => Promise<SentinelLike> } }
).wakeLock;
if (!wakeLock) return;
try {
sentinel = await wakeLock.request('screen');