import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters" import type { Meta, StoryObj } from "@storybook/react" import type { ReactNode } from "react" import { StoryCell, StoryGrid, StorySection, } from "../board.storyHelpers.tsx" import { RouterLinkProvider } from "../RouterLink/RouterLinkProvider.tsx" import type { RouterLinkProps } from "../RouterLink/routerLink.ts" import { MarkdownLine } from "./MarkdownLine.tsx" /** * A stand-in for react-router's ``, the same one * `TextLink.stories.tsx` uses. The marker attribute is how the * boards show which destinations the injected router was handed and * which went straight to the platform. */ const SoftRouterLink = ({ href, ...linkProps }: RouterLinkProps): ReactNode => ( ) /** * Task names, invented. Every string in this file is fixture data — * this package is published, and a screenshot of a story is not * greppable by anybody checking for household detail later. */ const CARD_TITLES = [ String.raw`Ingest 53 movies from \`Downloads/MOVIES\` into \`G:\Movies\``.replaceAll( String.raw`\``, "`", ), "**Urgent:** the rack fans are running at 100%", "Re-tag the *Halloween* playlist before October", "~~Buy a second spool~~ — arrived Tuesday", "Run ingest_the_files.sh nightly, not hourly", ] const meta = { title: "Components/Content/MarkdownLine", component: MarkdownLine, parameters: { layout: "padded" }, args: { value: CARD_TITLES[0] ?? "", }, } satisfies Meta export default meta type Story = StoryObj export const Playground: Story = { parameters: playgroundParameters, } /** * The four marks, each in the shape a title actually uses it for. * Code is the one that earns its place most often — an agent-written * task name is a third file paths by volume. */ export const AllMarks: Story = { render: () => ( ), } /** * WHY THE MARKS ARE WORTH HAVING AT ALL. * * Five names in one flat weight against the same five with their * marks drawn. The argument is not decoration: in the flat column * the eye has to read every title to the end to tell two of them * apart, and in the marked one the part that *differs* is the part * that is drawn differently. */ export const WhyItHelps: Story = { render: () => (
    {CARD_TITLES.map((title) => (
  • {title}
  • ))}
    {CARD_TITLES.map((title) => (
  • ))}
), } /** * A file name is the case this component is most often asked to get * *wrong*. `ingest_the_files.sh` has two underscores and is not * italic, because CommonMark's flanking rules say an underscore * inside a word opens nothing — and a Windows path keeps its * backslashes. */ export const FileNames: Story = { render: () => (
), } /** * THE `href` CASE, and the one that is easy to get wrong. * * A card title is usually a link to the card. When the title also * *contains* a link, `href` makes the component emit siblings — * plain runs anchored to the card, the markdown link anchored to its * own destination. Nesting them would be invalid HTML, and the * browser would silently drop the second half of the card's link. */ export const AsALink: Story = { render: () => ( ), } /** * With a router injected, an in-app destination goes through it and * an off-origin one does not — `data-router="soft"` marks the ones * the router was handed. Off-origin links open in a new tab, because * a title that names a pull request is a reference and following it * should not lose the board the reader was on. */ export const Routed: Story = { decorators: [ (Story) => ( ), ], render: () => ( ), } /** * A URL whose scheme is not on `safeUrls.ts`'s allowlist keeps * **every character of its source** and becomes no link at all. A * reader who can see the trap is better served than one shown a * confident blue word that silently refuses to work. */ /** * A whole card title as one link, with a code span inside it — the * shape Docket's backlog rows and board cards are. * * It exists so a test can assert the link's **accessible name**, * which is where a mark's surrounding spaces go missing without * anything on screen changing. */ export const TitleAsALink: Story = { render: () => ( ), } /** * INSIDE A WHOLE-CARD LINK. * * The card is the link — middle-click opens it, like anything else * on the web — so the line inside it emits no anchor of its own. The * marks still draw; a markdown link's text still reads; nothing * inside navigates separately. * * The bare URL is the case that makes this a prop rather than a * convention. It autolinks, so a captured note ending in a URL would * nest an anchor without anybody having typed `[]()`. */ export const InsideACardLink: Story = { render: () => (
Filed from the capture inbox ), } export const RefusedUrl: Story = { args: { value: "[click me](javascript:alert(1))" }, }