Retour au catalogue

Code Block API

Reference API avec endpoint, badge de methode HTTP (GET/POST), liste de parametres et exemple de reponse JSON formate.

code-blockmedium Both Responsive a11y
minimalcorporatesaasuniversalcentered
Theme
"use client";

import { motion } from "framer-motion";
import { Copy, Check, ChevronRight } from "lucide-react";
import { useState } from "react";

interface ApiParam {
  name: string;
  type: string;
  required: boolean;
  description: string;
}

interface CodeBlockApiProps {
  title?: string;
  description?: string;
  method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
  endpoint?: string;
  params?: ApiParam[];
  responseLines?: { text: string; indent?: number; color?: string }[];
}

const EASE = [0.16, 1, 0.3, 1] as const;

const METHOD_COLORS: Record<string, string> = {
  GET: "#a5d6a7",
  POST: "#90caf9",
  PUT: "#ffe082",
  PATCH: "#ce93d8",
  DELETE: "#ef9a9a",
};

const TOKEN_COLORS: Record<string, string> = {
  key: "#90caf9",
  string: "#a5d6a7",
  number: "#ffe082",
  muted: "var(--color-foreground-muted)",
  accent: "var(--color-accent)",
};

export default function CodeBlockApi({
  title = "Reference API",
  description = "Documentation complete de nos endpoints.",
  method = "GET",
  endpoint = "/api/v1/users",
  params = [],
  responseLines = [],
}: CodeBlockApiProps) {
  const [copied, setCopied] = useState(false);

  function handleCopy() {
    navigator.clipboard.writeText(
      `curl -X ${method} https://api.acme.dev${endpoint}`
    );
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  }

  return (
    <section
      style={{
        padding: "var(--section-padding-y) 0",
        background: "var(--color-background)",
      }}
    >
      <div
        style={{
          maxWidth: "var(--container-max-width)",
          margin: "0 auto",
          padding: "0 var(--container-padding-x)",
        }}
      >
        <motion.div
          initial={{ opacity: 0, y: 16 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.5, ease: EASE }}
          style={{ textAlign: "center", marginBottom: "2.5rem" }}
        >
          <h2
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: "clamp(1.75rem, 3vw, 2.5rem)",
              fontWeight: 700,
              color: "var(--color-foreground)",
              marginBottom: "0.75rem",
              letterSpacing: "-0.02em",
            }}
          >
            {title}
          </h2>
          <p
            style={{
              fontSize: "1.0625rem",
              color: "var(--color-foreground-muted)",
              maxWidth: "520px",
              margin: "0 auto",
              lineHeight: 1.6,
            }}
          >
            {description}
          </p>
        </motion.div>

        <motion.div
          initial={{ opacity: 0, y: 24 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.6, delay: 0.1, ease: EASE }}
          style={{
            maxWidth: "780px",
            margin: "0 auto",
            borderRadius: "var(--radius-lg)",
            border: "1px solid var(--color-border)",
            background: "var(--color-background-alt)",
            overflow: "hidden",
          }}
        >
          {/* Endpoint bar */}
          <div
            style={{
              display: "flex",
              alignItems: "center",
              gap: "12px",
              padding: "0.875rem 1.25rem",
              borderBottom: "1px solid var(--color-border)",
              background: "var(--color-background-card)",
            }}
          >
            <span
              style={{
                display: "inline-block",
                padding: "3px 10px",
                borderRadius: "var(--radius-sm)",
                fontSize: "0.6875rem",
                fontWeight: 700,
                fontFamily: "var(--font-mono, monospace)",
                color: "#111",
                background: METHOD_COLORS[method] ?? "var(--color-accent)",
                letterSpacing: "0.04em",
              }}
            >
              {method}
            </span>
            <code
              style={{
                flex: 1,
                fontFamily: "var(--font-mono, monospace)",
                fontSize: "0.875rem",
                color: "var(--color-foreground)",
              }}
            >
              {endpoint}
            </code>
            <button
              onClick={handleCopy}
              style={{
                display: "inline-flex",
                alignItems: "center",
                gap: "4px",
                padding: "4px 10px",
                borderRadius: "var(--radius-sm)",
                border: "1px solid var(--color-border)",
                background: "transparent",
                color: "var(--color-foreground-muted)",
                fontSize: "0.75rem",
                cursor: "pointer",
              }}
            >
              {copied ? (
                <Check style={{ width: 14, height: 14, color: "var(--color-accent)" }} />
              ) : (
                <Copy style={{ width: 14, height: 14 }} />
              )}
            </button>
          </div>

          {/* Parameters */}
          {params.length > 0 && (
            <div
              style={{
                padding: "1rem 1.25rem",
                borderBottom: "1px solid var(--color-border)",
              }}
            >
              <div
                style={{
                  fontSize: "0.6875rem",
                  fontWeight: 600,
                  textTransform: "uppercase",
                  letterSpacing: "0.08em",
                  color: "var(--color-foreground-light)",
                  marginBottom: "0.75rem",
                }}
              >
                Parametres
              </div>
              <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
                {params.map((p) => (
                  <div
                    key={p.name}
                    style={{
                      display: "flex",
                      alignItems: "baseline",
                      gap: "10px",
                      fontSize: "0.8125rem",
                    }}
                  >
                    <ChevronRight
                      style={{
                        width: 12,
                        height: 12,
                        color: "var(--color-accent)",
                        flexShrink: 0,
                        marginTop: "3px",
                      }}
                    />
                    <code
                      style={{
                        fontFamily: "var(--font-mono, monospace)",
                        fontWeight: 600,
                        color: "var(--color-foreground)",
                      }}
                    >
                      {p.name}
                    </code>
                    <span
                      style={{
                        fontSize: "0.6875rem",
                        padding: "1px 6px",
                        borderRadius: "var(--radius-sm)",
                        background: "var(--color-accent-subtle)",
                        color: "var(--color-foreground-muted)",
                        fontFamily: "var(--font-mono, monospace)",
                      }}
                    >
                      {p.type}
                    </span>
                    {p.required && (
                      <span
                        style={{
                          fontSize: "0.625rem",
                          fontWeight: 600,
                          textTransform: "uppercase",
                          color: "#ef9a9a",
                          letterSpacing: "0.05em",
                        }}
                      >
                        requis
                      </span>
                    )}
                    <span
                      style={{
                        color: "var(--color-foreground-muted)",
                        fontSize: "0.8125rem",
                      }}
                    >
                      {p.description}
                    </span>
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* Response */}
          {responseLines.length > 0 && (
            <div style={{ padding: "1rem 1.25rem" }}>
              <div
                style={{
                  fontSize: "0.6875rem",
                  fontWeight: 600,
                  textTransform: "uppercase",
                  letterSpacing: "0.08em",
                  color: "var(--color-foreground-light)",
                  marginBottom: "0.75rem",
                }}
              >
                Exemple de reponse
              </div>
              <div
                style={{
                  fontFamily: "var(--font-mono, monospace)",
                  fontSize: "0.8125rem",
                  lineHeight: 1.85,
                }}
              >
                {responseLines.map((line, i) => (
                  <div
                    key={i}
                    style={{ paddingLeft: `${(line.indent ?? 0) * 1.25}rem` }}
                  >
                    <span
                      style={{
                        color: line.color
                          ? TOKEN_COLORS[line.color] ?? "var(--color-foreground-muted)"
                          : "var(--color-foreground-muted)",
                      }}
                    >
                      {line.text || "\u00A0"}
                    </span>
                  </div>
                ))}
              </div>
            </div>
          )}
        </motion.div>
      </div>
    </section>
  );
}

Avis

Code Block API — React Code-block Section — Incubator