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))" },
}