Takazudo Modular Styleguide

MDX/ArticleImage

Default
With Caption
Without Caption

Component Source

article-image.tsx

import type { FunctionComponent } from 'preact';
import { ResponsiveImage } from '@/components/responsive-image';
import { getImageMetadata } from '@/src/lib/metadata-db';
import { captionClass } from '../caption-class';
import { buildEnlargeData, EnlargeButton } from '../image-enlarge-affordance';

export interface ArticleImageProps {
  slug: string;
  caption?: string;
}

const figureClass = 'w-full pt-vgap-sm pb-vgap-lg';

// The image box also serves as the `.zd-enlargeable` element so the
// absolutely-positioned enlarge button anchors to the image (not the
// full-width figure). `.zd-enlargeable` (image-enlarge.css) supplies the
// `position: relative` positioning context (#405).
const imgClass = 'lg:mx-auto lg:max-w-[85%]';

export const ArticleImage: FunctionComponent<ArticleImageProps> = ({ slug, caption }) => {
  const alt = caption ? '' : slug.replace(/-/g, ' ');
  // Enlarge affordance (#405) — present only when the image has pipeline
  // variants. Missing-metadata / variantless images render without it.
  const enlargeData = buildEnlargeData(slug, getImageMetadata(slug));
  return (
    <figure className={figureClass} aria-label={alt || undefined}>
      {enlargeData ? (
        <div className={`zd-enlargeable ${imgClass}`} {...enlargeData}>
          <ResponsiveImage slug={slug} alt={alt} />
          <EnlargeButton />
        </div>
      ) : (
        <div className={imgClass}>
          <ResponsiveImage slug={slug} alt={alt} />
        </div>
      )}
      {caption && <figcaption className={captionClass}>{caption}</figcaption>}
    </figure>
  );
};

Story Source

article-image.stories.tsx

import { ArticleImage } from './article-image';
import type { ControlsMap } from '../../../sub-packages/styleguide-v2/src/data/control-types';

export const meta = {
  title: 'MDX/ArticleImage',
};

export const controls: ControlsMap = {
  slug: { type: 'text', default: 'oxi-cap-ep1-front-panel' },
  caption: { type: 'text', default: 'OXI ONE MKII front panel overview' },
};

/**
 * Default - with caption
 */
export const Default = {
  args: { slug: 'oxi-cap-ep1-front-panel', caption: 'OXI ONE MKII front panel overview' },
  render: ({ slug, caption }: { slug: string; caption: string }) => (
    <ArticleImage slug={slug} caption={caption || undefined} />
  ),
};

export const WithCaption = () => (
  <ArticleImage slug="oxi-cap-ep1-front-panel" caption="OXI ONE MKII front panel overview" />
);

export const WithoutCaption = () => <ArticleImage slug="oxi-cap-ep1-grid-notes" />;