import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
import type { Meta, StoryObj } from "@storybook/react"
import { Badge } from "../Badge/Badge.tsx"
import {
ContainerBoard,
StoryCell,
StoryGrid,
StorySection,
} from "../board.storyHelpers.tsx"
import { MediaTile } from "./MediaTile.tsx"
/**
* An inline SVG rather than a fixture file or a placeholder service:
* it decodes synchronously, needs no network, and makes the
* `loaded` state deterministic in CI — which matters because the
* *cached* path is one of the three states this component exists to
* get right.
*/
const toPosterSrc = (label: string) =>
`data:image/svg+xml;utf8,${encodeURIComponent(
``,
)}`
/** 404s, which is what makes the error state real rather than mocked. */
const MISSING_SRC = "/charcuterie-missing-poster.png"
const meta = {
title: "Components/Data/MediaTile",
component: MediaTile,
parameters: { layout: "padded" },
args: { aspectRatio: "poster" },
} satisfies Meta
export default meta
type Story = StoryObj
export const Playground: Story = {
parameters: playgroundParameters,
args: {
alt: "Blade Runner (1982) poster",
src: toPosterSrc("Blade Runner"),
subtitle: "1982 · 4K remaster",
title: "Blade Runner",
},
}
export const AllVariants: Story = {
args: { alt: "Poster", title: "Blade Runner" },
render: () => (
),
}
/**
* The three states are the component, and no hand-rolled version in
* the fleet models more than one of them.
*/
export const AllStates: Story = {
args: { alt: "Poster", title: "Blade Runner" },
render: () => (
4K
}
href="#blade-runner"
src={toPosterSrc("Blade Runner")}
subtitle="1982 · 4K remaster"
title="Blade Runner"
/>
),
}
/**
* The caption's type steps up past `--cq-sm`, so a tile in a dense
* 8-across grid and the same tile in a 3-across one are legible at
* both — the intermediate widths where the fleet's poster grids look
* wrong today.
*/
export const Responsive: Story = {
args: { alt: "Poster", title: "Blade Runner" },
render: () => (
),
}
export const Grid: Story = {
args: { alt: "Poster", title: "Blade Runner" },
render: () => (
// Two elements, not one: the container and the grid that queries
// it **must** be different, because a container query matches
// descendants only. Collapsed into one `
` this compiles,
// generates real CSS, and silently stays two columns — which on a
// desktop is four 700px posters.
),
}
/**
* The linked tile's contract: the accessible name is exactly the
* title — not the title plus the subtitle plus the alt text — and
* Tab reaches it. `getByRole("link", { name: "Blade Runner" })` is
* what an agent will actually write.
*/
export const Interactive: Story = {
args: {
alt: "Blade Runner (1982) poster",
href: "#blade-runner",
src: toPosterSrc("Blade Runner"),
subtitle: "1982 · 4K remaster",
title: "Blade Runner",
},
}
/**
* Same chrome as the link — pointer, hover fade, focus ring —
* as a button. Wrapping the tile in a bare `