{
  "name": "testimonials/carousel",
  "type": "registry:component",
  "description": "Testimonial carousel with media focus",
  "files": [
    {
      "path": "example/Testimonials/SectionTestimonials_Carousel.astro",
      "type": "registry:component",
      "content": "---\nimport BackgroundEffect from '@@/components/ui/BackgroundEffect.astro';\nimport Card from '@@/components/ui/Card.astro';\nimport { Icon } from 'astro-icon/components';\nimport myImage from '@/assets/placeholder.png';\n---\n\n<section class=\"relative overflow-hidden\">\n  <BackgroundEffect\n    gradientType=\"var(--gradient-top-fade-linear)\"\n    patternType=\"none\"\n    noiseType=\"none\"\n  />\n\n  <div class=\"container\">\n    <div class=\"mb-10 text-center\">\n      <div\n        class=\"rounded-card mb-4 inline-flex items-center gap-2 px-4 py-2 text-sm\"\n        data-scheme=\"shift\"\n      >\n        <span class=\"bg-accent h-2 w-2 rounded-full\"></span>\n        Testimonials\n      </div>\n      <h2 class=\"h2 mb-4\">\n        What People Say About <span class=\"sp-emphasis\">Pablo</span>\n      </h2>\n      <p class=\"text-fg-sub mx-auto max-w-3xl text-lg md:text-xl\">\n        Discover how Pablo is transforming the way people build websites\n      </p>\n    </div>\n\n    <!-- Carousel -->\n    <div\n      class=\"relative -ml-[calc(50vw-50%)] mt-10 w-screen sm:mt-16\"\n      data-carousel-root\n    >\n      <!-- Viewport -->\n      <div class=\"overflow-hidden\">\n        <div\n          data-carousel-track\n          class=\"flex w-full items-stretch gap-4 pl-[10vw] transition-transform duration-500 sm:gap-6\"\n        >\n          {/** Slide 1 **/}\n          <div\n            data-slide=\"0\"\n            data-slide-original\n            class=\"flex w-[80vw] min-w-[80vw] shrink-0\"\n          >\n            <Card\n              className=\"shadow-8 h-full w-full flex-1 overflow-hidden lg:rounded-2xl\"\n            >\n              <div class=\"grid h-full grid-cols-1 lg:grid-cols-2\">\n                <!-- Left: Text Content -->\n                <div\n                  class=\"flex flex-col justify-center p-6 sm:p-8 md:p-10 lg:p-12 xl:p-16\"\n                >\n                  <blockquote\n                    class=\"text-fg mb-8 text-xl font-medium sm:text-2xl lg:text-3xl\"\n                  >\n                    \"Pablo brought clarity to complex problems and delivered\n                    innovative solutions.\"\n                  </blockquote>\n                  <div>\n                    <p class=\"text-fg font-semibold\">John Doe</p>\n                    <p class=\"text-fg-sub text-sm\">CEO, Tech Innovations</p>\n                  </div>\n                </div>\n                <!-- Right: Image -->\n                <div class=\"relative h-64 lg:h-auto\">\n                  <img\n                    src={myImage.src}\n                    width={myImage.width}\n                    height={myImage.height}\n                    alt=\"Product screenshot\"\n                    class=\"h-full w-full object-cover\"\n                  />\n                </div>\n              </div>\n            </Card>\n          </div>\n\n          {/** Slide 2 **/}\n          <div\n            data-slide=\"1\"\n            data-slide-original\n            class=\"flex w-[80vw] min-w-[80vw] shrink-0\"\n          >\n            <Card\n              className=\"shadow-8 h-full w-full flex-1 overflow-hidden lg:rounded-2xl\"\n            >\n              <div class=\"grid h-full grid-cols-1 lg:grid-cols-2\">\n                <!-- Left: Text Content -->\n                <div\n                  class=\"flex flex-col justify-center p-6 sm:p-8 md:p-10 lg:p-12 xl:p-16\"\n                >\n                  <blockquote\n                    class=\"text-fg mb-8 text-xl font-medium sm:text-2xl lg:text-3xl\"\n                  >\n                    \"Turned insights into tangible outcomes incredibly fast.\n                    Highly recommended.\"\n                  </blockquote>\n                  <div>\n                    <p class=\"text-fg font-semibold\">Jane Smith</p>\n                    <p class=\"text-fg-sub text-sm\">Product Lead, Orbit</p>\n                  </div>\n                </div>\n                <!-- Right: Image -->\n                <div class=\"relative h-64 lg:h-auto\">\n                  <img\n                    src={myImage.src}\n                    width={myImage.width}\n                    height={myImage.height}\n                    alt=\"Product screenshot\"\n                    class=\"h-full w-full object-cover\"\n                  />\n                </div>\n              </div>\n            </Card>\n          </div>\n\n          {/** Slide 3 **/}\n          <div\n            data-slide=\"2\"\n            data-slide-original\n            class=\"flex w-[80vw] min-w-[80vw] shrink-0\"\n          >\n            <Card\n              className=\"shadow-8 h-full w-full flex-1 overflow-hidden lg:rounded-2xl\"\n            >\n              <div class=\"grid h-full grid-cols-1 lg:grid-cols-2\">\n                <!-- Left: Text Content -->\n                <div\n                  class=\"flex flex-col justify-center p-6 sm:p-8 md:p-10 lg:p-12 xl:p-16\"\n                >\n                  <blockquote\n                    class=\"text-fg mb-8 text-xl font-medium sm:text-2xl lg:text-3xl\"\n                  >\n                    \"Practical systems thinking that drives measurable growth\n                    and success.\"\n                  </blockquote>\n                  <div>\n                    <p class=\"text-fg font-semibold\">Alex Walker</p>\n                    <p class=\"text-fg-sub text-sm\">Founder, Nova Labs</p>\n                  </div>\n                </div>\n                <!-- Right: Image -->\n                <div class=\"relative h-64 lg:h-auto\">\n                  <img\n                    src={myImage.src}\n                    width={myImage.width}\n                    height={myImage.height}\n                    alt=\"Product screenshot\"\n                    class=\"h-full w-full object-cover\"\n                  />\n                </div>\n              </div>\n            </Card>\n          </div>\n        </div>\n      </div>\n\n      <!-- Controls -->\n      <div class=\"mt-6 flex items-center justify-center gap-2 px-6 lg:px-8\">\n        <button\n          type=\"button\"\n          data-action=\"prev\"\n          aria-label=\"Previous\"\n          class=\"carousel-btn group\"\n        >\n          <span\n            data-scheme=\"bg\"\n            class=\"shadow-2 inline-flex h-10 w-10 items-center justify-center rounded-full\"\n          >\n            <Icon name=\"lucide:chevron-left\" size={18} />\n          </span>\n        </button>\n        <button\n          type=\"button\"\n          data-action=\"next\"\n          aria-label=\"Next\"\n          class=\"carousel-btn group\"\n        >\n          <span\n            data-scheme=\"bg\"\n            class=\"shadow-2 inline-flex h-10 w-10 items-center justify-center rounded-full\"\n          >\n            <Icon name=\"lucide:chevron-right\" size={18} />\n          </span>\n        </button>\n      </div>\n    </div>\n  </div>\n</section>\n\n<style>\n  .carousel-btn {\n    cursor: pointer;\n    transition:\n      transform 0.15s cubic-bezier(0.4, 0, 0.2, 1),\n      opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);\n  }\n\n  .carousel-btn:hover:not(:disabled) {\n    transform: translateY(1px) scale(0.99);\n    opacity: 0.9;\n  }\n\n  .carousel-btn:active:not(:disabled) {\n    transform: translateY(2px) scale(0.98);\n    opacity: 0.8;\n  }\n\n  .carousel-btn:disabled {\n    opacity: 0.5;\n    cursor: not-allowed;\n    pointer-events: none;\n  }\n</style>\n\n<script>\n  function initTestimonialCarousel() {\n    const root = document.querySelector(\"[data-carousel-root]\");\n    if (!root) return;\n\n    const track = root.querySelector(\n      \"[data-carousel-track]\",\n    ) as HTMLElement | null;\n    const prev = root.querySelector(\n      '[data-action=\"prev\"]',\n    ) as HTMLButtonElement | null;\n    const next = root.querySelector(\n      '[data-action=\"next\"]',\n    ) as HTMLButtonElement | null;\n\n    if (!track) return;\n\n    const slides = Array.from(\n      track.querySelectorAll(\"[data-slide-original]\"),\n    ) as HTMLElement[];\n    if (slides.length === 0) return;\n\n    let index = 0;\n    let active = 0;\n\n    // インデックスを循環させる\n    const normalizeIndex = (i: number) => {\n      const len = slides.length;\n      return ((i % len) + len) % len;\n    };\n\n    // スライドを更新（ピクセルベースで計算）\n    const updateSlide = () => {\n      if (slides.length === 0) return;\n\n      const firstSlide = slides[0];\n      const slideWidth = firstSlide.offsetWidth;\n      const gap = window.innerWidth >= 640 ? 24 : 16; // sm:gap-6 = 24px, gap-4 = 16px\n      const moveDistance = slideWidth + gap;\n      const offset = -active * moveDistance;\n\n      track.style.transform = `translateX(${offset}px)`;\n    };\n\n    // ボタンの状態を更新（スライドが1つの場合は無効化）\n    const updateButtonStates = () => {\n      if (!prev || !next) return;\n      const shouldDisable = slides.length <= 1;\n      prev.disabled = shouldDisable;\n      next.disabled = shouldDisable;\n    };\n\n    // インデックスを設定\n    const setIndex = (newIndex: number) => {\n      index = newIndex;\n      active = normalizeIndex(index);\n      updateSlide();\n    };\n\n    // 前へ\n    const goPrev = () => {\n      setIndex(index - 1);\n    };\n\n    // 次へ\n    const goNext = () => {\n      setIndex(index + 1);\n    };\n\n    prev?.addEventListener(\"click\", goPrev);\n    next?.addEventListener(\"click\", goNext);\n\n    // ウィンドウリサイズ時に再計算\n    window.addEventListener(\"resize\", () => {\n      updateSlide();\n    });\n\n    // 初期表示\n    updateSlide();\n    updateButtonStates();\n  }\n\n  if (document.readyState === \"loading\") {\n    document.addEventListener(\"DOMContentLoaded\", initTestimonialCarousel);\n  } else {\n    initTestimonialCarousel();\n  }\n</script>\n"
    }
  ],
  "category": "example",
  "registryDependencies": [
    "carousel"
  ]
}