Takazudo Modular Styleguide

Guides/SeriesNav

Default
Last Article
Long Series
Middle Article
Two Article Series

Component Source

series-nav.tsx

import { Link } from '@/components/shared/link';
import { ArrowRight } from '@/components/svg';

interface SeriesNavProps {
  seriesName: string;
  articles: { slug: string; title: string }[];
  currentSlug: string;
  locale?: 'ja' | 'en';
}

/**
 * Series navigation component for guide article pages.
 * Shows links to all articles in the same series, with the
 * current article displayed as non-linked text.
 * Uses a TOC-like dashed border box layout.
 */
export function SeriesNav({ seriesName, articles, currentSlug, locale = 'ja' }: SeriesNavProps) {
  if (articles.length === 0) return null;

  const isEn = locale === 'en';
  const guidesPrefix = isEn ? '/en/guides' : '/guides';

  return (
    <nav
      aria-label={isEn ? 'Series navigation' : 'シリーズナビゲーション'}
      className={
        'mt-vgap-lg border-t border-dashed border-zd-white pt-vgap-sm lg:border lg:pt-vgap-md lg:px-hgap-md lg:pb-vgap-sm'
      }
    >
      <h2 className={'font-futura font-bold text-base md:text-lg pb-vgap-sm'}>{seriesName}</h2>
      <ol className="list-none p-0 m-0">
        {articles.map((article, index) => {
          const isCurrent = article.slug === currentSlug;
          return (
            <li key={article.slug} className={'py-vgap-xs font-futura text-sm md:text-base'}>
              {isCurrent ? (
                <span className="inline-flex items-center" aria-current="page">
                  <ArrowRight aria-hidden="true" className="w-[18px] mr-[5px] flex-shrink-0" />
                  {index + 1}. {article.title}
                  {isEn ? ' (this article)' : '(この記事)'}
                </span>
              ) : (
                <Link
                  to={`${guidesPrefix}/${article.slug}/`}
                  className="inline-flex items-center zd-invert-color-link"
                >
                  <ArrowRight aria-hidden="true" className="w-[18px] mr-[5px] flex-shrink-0" />
                  {index + 1}. {article.title}
                </Link>
              )}
            </li>
          );
        })}
      </ol>
    </nav>
  );
}

Story Source

series-nav.stories.tsx

import { SeriesNav } from './series-nav';
import type { ControlsMap } from '../../sub-packages/styleguide-v2/src/data/control-types';

export const meta = {
  title: 'Guides/SeriesNav',
};

export const controls: ControlsMap = {
  seriesName: { type: 'text', default: 'モジュラーシンセ入門シリーズ' },
};

const sampleArticles = [
  { slug: 'modular-synth-basics', title: 'モジュラーシンセ基礎知識' },
  { slug: 'first-modules', title: 'はじめてのモジュール選び' },
  { slug: 'patching-101', title: 'パッチングの基本' },
  { slug: 'power-and-cases', title: '電源とケースの選び方' },
  { slug: 'sound-design-tips', title: 'サウンドデザインのコツ' },
];

/**
 * Default - viewing the first article in a 5-article series
 */
export const Default = {
  args: { seriesName: 'モジュラーシンセ入門シリーズ' },
  render: ({ seriesName }: { seriesName: string }) => (
    <SeriesNav
      seriesName={seriesName}
      articles={sampleArticles}
      currentSlug="modular-synth-basics"
    />
  ),
};

/**
 * Viewing a middle article in the series
 */
export const MiddleArticle = () => (
  <SeriesNav
    seriesName="モジュラーシンセ入門シリーズ"
    articles={sampleArticles}
    currentSlug="patching-101"
  />
);

/**
 * Viewing the last article in the series
 */
export const LastArticle = () => (
  <SeriesNav
    seriesName="モジュラーシンセ入門シリーズ"
    articles={sampleArticles}
    currentSlug="sound-design-tips"
  />
);

/**
 * Short series with only 2 articles
 */
export const TwoArticleSeries = () => (
  <SeriesNav
    seriesName="VCO比較シリーズ"
    articles={[
      { slug: 'analog-vco', title: 'アナログVCOの特徴' },
      { slug: 'digital-vco', title: 'デジタルVCOの特徴' },
    ]}
    currentSlug="analog-vco"
  />
);

/**
 * Long series with many articles
 */
export const LongSeries = () => (
  <SeriesNav
    seriesName="Mutable Instruments 全モジュールレビュー"
    articles={[
      { slug: 'braids', title: 'Braids - マクロオシレーター' },
      { slug: 'clouds', title: 'Clouds - グラニュラープロセッサー' },
      { slug: 'rings', title: 'Rings - レゾネーター' },
      { slug: 'plaits', title: 'Plaits - マクロオシレーター2' },
      { slug: 'beads', title: 'Beads - グラニュラープロセッサー2' },
      { slug: 'stages', title: 'Stages - セグメントジェネレーター' },
      { slug: 'marbles', title: 'Marbles - ランダムサンプラー' },
      { slug: 'tides', title: 'Tides - ファンクションジェネレーター' },
    ]}
    currentSlug="rings"
  />
);