app/components/admin/media-picker.tsx
106 lines and 5 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| MediaPicker | 18 to 114 | 12 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:27> | 27 to 30 | 3 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:29> | 29 to 29 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:83> | 83 to 97 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:88> | 88 to 88 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
Imports
It imports no other module of this repo. Imported by app/components/admin/settings-drawer.tsx.
Source
import { useEffect } from "react";
import { useFetcher } from "react-router";
import { Empty } from "capsomer/react/empty";
type PickedMedia = {
key: string;
url: string;
alt: string;
};
type PickerRow = {
key: string;
url: string;
thumb: string;
alt: string;
};
export function MediaPicker({
onPick,
onCancel,
}: {
onPick: (picked: PickedMedia) => void;
onCancel?: () => void;
}) {
const media = useFetcher<{ objects: PickerRow[]; truncated: boolean }>();
useEffect(() => {
// The router reports a failed load to the error boundary; the promise has nothing left to say.
if (media.state === "idle" && !media.data) media.load("/admin/media?picker=1").catch(() => undefined);
}, [media]);
const objects = media.data?.objects ?? [];
// Before the first answer, the idle render included: without data, "no images" would be a guess.
const loading = !media.data;
/* Mounted empty on the first render and filled after, so the loading and the result are both announced. */
const status = (
<p className="cap-sr-only" role="status">
{media.state === "loading" && loading
? "Loading media"
: loading
? ""
: objects.length === 0
? "No images yet"
: `${objects.length} image${objects.length === 1 ? "" : "s"}`}
</p>
);
if (loading) {
return (
<>
{status}
<p className="cap-muted">Loading media...</p>
</>
);
}
if (objects.length === 0) {
return (
<>
{status}
<Empty
kind="nothing-yet"
action={
onCancel ? (
<button type="button" className="cap-btn" onClick={onCancel}>
Close
</button>
) : undefined
}
>
No images in the bucket yet. Upload one from the body editor by dropping or pasting it, and
it will appear here.
</Empty>
</>
);
}
return (
<>
{status}
<div className="cap-media" data-size="s">
<ul className="cap-media-grid" role="list" aria-label="Images in the library">
{objects.map((object) => (
<li key={object.key} className="cap-media-tile">
<button
type="button"
className="cap-media-open"
onClick={() => onPick({ key: object.key, url: object.url, alt: object.alt })}
>
{/* The thumbnail, never the original, so the grid cannot pull full-resolution bytes. */}
<span className="cap-media-thumb">
<img src={object.thumb} alt="" loading="lazy" width={160} height={160} />
</span>
<span className="cap-media-name">{object.key.replace(/^posts\//, "")}</span>
</button>
</li>
))}
</ul>
</div>
{media.data?.truncated ? (
<p className="cap-muted">
Showing the first page. Open the media library to page through the rest.
</p>
) : null}
{onCancel ? (
<div>
<button type="button" className="cap-btn" data-variant="quiet" onClick={onCancel}>
Cancel
</button>
</div>
) : null}
</>
);
}