All files / src/components PageIntro.tsx

100% Statements 3/3
100% Branches 27/27
100% Functions 2/2
100% Lines 3/3

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130                                                                                                        1939x   1939x                                                                                     8x                                                                
"use client";
 
import Link from "next/link";
import {
  Info,
  ArrowLeft,
  ArrowRight,
  ExternalLink,
  type LucideIcon,
} from "lucide-react";
import { useState } from "react";
 
export interface StepLink {
  href: string;
  label: string;
}
 
export interface DocLink {
  href: string;
  label: string;
  external?: boolean;
}
 
export interface PageIntroProps {
  /** Page title */
  title: string;
  /** Lucide icon component — unused in Stitch layout, kept for API compat */
  icon?: LucideIcon;
  /** Subtitle shown below the page-header */
  description: string;
  /** Info callout text shown in an expandable box */
  infoText?: string;
  /** Link to relevant documentation */
  docLink?: DocLink;
  /** Previous step in the user workflow */
  prevStep?: StepLink;
  /** Next step in the user workflow */
  nextStep?: StepLink;
}
 
/**
 * Shared page header — Stitch "Clinical Clarity" style.
 * Renders page-header utility class (text-4xl font-extrabold tracking-tight).
 */
export default function PageIntro({
  title,
  description,
  infoText,
  docLink,
  prevStep,
  nextStep,
}: PageIntroProps) {
  const [infoOpen, setInfoOpen] = useState(false);
 
  return (
    <div className="mb-8">
      {/* Title */}
      <h1 className="page-header">{title}</h1>
 
      {/* Subtitle */}
      <p className="text-[var(--text-secondary)] text-lg mt-1 max-w-3xl">
        {description}
      </p>
 
      {/* Workflow navigation */}
      {(prevStep || nextStep) && (
        <div className="flex items-center gap-4 text-sm mt-3 text-[var(--text-secondary)]">
          {prevStep && (
            <Link
              href={prevStep.href}
              className="flex items-center gap-1 font-bold text-[var(--accent)] hover:underline"
            >
              <ArrowLeft size={13} />
              {prevStep.label}
            </Link>
          )}
          {prevStep && nextStep && (
            <span className="text-[var(--border-ui)]" aria-hidden="true">
              ·
            </span>
          )}
          {nextStep && (
            <Link
              href={nextStep.href}
              className="flex items-center gap-1 font-bold text-[var(--accent)] hover:underline"
            >
              {nextStep.label}
              <ArrowRight size={13} />
            </Link>
          )}
        </div>
      )}
 
      {/* Info callout */}
      {(infoText || docLink) && (
        <div className="mt-4">
          <button
            onClick={() => setInfoOpen(!infoOpen)}
            className="flex items-center gap-1.5 text-xs font-bold text-[var(--accent)] hover:opacity-75 transition-opacity"
          >
            <Info size={13} />
            {infoOpen ? "Hide details" : "How does this work?"}
          </button>
 
          {infoOpen && (
            <div className="mt-2 p-4 rounded-xl bg-[var(--accent)]/5 border border-[var(--accent)]/15 text-sm text-[var(--text-primary)] max-w-3xl">
              {infoText && <p className="mb-2">{infoText}</p>}
              {docLink && (
                <Link
                  href={docLink.href}
                  target={docLink.external ? "_blank" : undefined}
                  rel={docLink.external ? "noopener noreferrer" : undefined}
                  className="inline-flex items-center gap-1 text-xs font-bold text-[var(--accent)] hover:underline"
                >
                  {docLink.external ? (
                    <ExternalLink size={11} />
                  ) : (
                    <Info size={11} />
                  )}
                  {docLink.label}
                </Link>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
}