01自動送りのレビューカルーセル
レビューカード3枚が同じ場所で順に出入りし、ドットインジケーターが合わせて広がり、停止ボタンを押すとその場で送りが止まります。
使いどころレビューが3〜4件だけのランディング中段の帯
translateXanimation-play-statearia-live

<main class="stage">
<section class="pc is-demo" aria-label="お客様の声の自動送り">
<div class="pc__window" aria-live="off">
<article class="pc__card pc__card--1 is-on">
<p class="pc__stars" role="img" aria-label="5点満点で5点">
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
</p>
<p class="pc__quote">導入初週に問い合わせの回答時間が半分になりました。チーム全員が同じ画面を見ています。</p>
<p class="pc__who">
<span class="pc__avatar" aria-hidden="true">J</span>
<span class="pc__name">デザインチームリーダー<span class="pc__role">オンライン書店</span></span>
</p>
</article>
<article class="pc__card pc__card--2">
<p class="pc__stars" role="img" aria-label="5点満点で4点">
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star pc__star--off" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
</p>
<p class="pc__quote">表をそのまま貼り付けましたが、手を入れるところがありませんでした。次のリニューアルでもそのまま使います。</p>
<p class="pc__who">
<span class="pc__avatar" aria-hidden="true">M</span>
<span class="pc__name">運営チーム マネージャー<span class="pc__role">街のパン屋</span></span>
</p>
</article>
<article class="pc__card pc__card--3">
<p class="pc__stars" role="img" aria-label="5点満点で5点">
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
<svg class="pc__star" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2"/><path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/></svg>
</p>
<p class="pc__quote">説明書を読まずに注文まで済ませました。返品の問い合わせが目に見えて減りました。</p>
<p class="pc__who">
<span class="pc__avatar" aria-hidden="true">S</span>
<span class="pc__name">工房 代表<span class="pc__role">手作り家具の工房</span></span>
</p>
</article>
</div>
<div class="pc__bar">
<span class="pc__dots">
<button class="pc__dot is-on" type="button" aria-label="1つ目のレビューを表示" aria-current="true"><span class="pc__pip" aria-hidden="true"></span></button>
<button class="pc__dot" type="button" aria-label="2つ目のレビューを表示" aria-current="false"><span class="pc__pip" aria-hidden="true"></span></button>
<button class="pc__dot" type="button" aria-label="3つ目のレビューを表示" aria-current="false"><span class="pc__pip" aria-hidden="true"></span></button>
</span>
<button class="pc__toggle" type="button" aria-pressed="false" aria-label="自動送りを停止">
<svg class="pc__ico pc__ico--pause" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M208,48V208a8,8,0,0,1-8,8H160a8,8,0,0,1-8-8V48a8,8,0,0,1,8-8h40A8,8,0,0,1,208,48ZM96,40H56a8,8,0,0,0-8,8V208a8,8,0,0,0,8,8H96a8,8,0,0,0,8-8V48A8,8,0,0,0,96,40Z" opacity="0.2"/><path d="M200,32H160a16,16,0,0,0-16,16V208a16,16,0,0,0,16,16h40a16,16,0,0,0,16-16V48A16,16,0,0,0,200,32Zm0,176H160V48h40ZM96,32H56A16,16,0,0,0,40,48V208a16,16,0,0,0,16,16H96a16,16,0,0,0,16-16V48A16,16,0,0,0,96,32Zm0,176H56V48H96Z"/></svg>
<svg class="pc__ico pc__ico--play" viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor"><path d="M228.23,134.69,84.15,222.81A8,8,0,0,1,72,216.12V39.88a8,8,0,0,1,12.15-6.69l144.08,88.12A7.82,7.82,0,0,1,228.23,134.69Z" opacity="0.2"/><path d="M232.4,114.49,88.32,26.35a16,16,0,0,0-16.2-.3A15.86,15.86,0,0,0,64,39.87V216.13A15.94,15.94,0,0,0,80,232a16.07,16.07,0,0,0,8.36-2.35L232.4,141.51a15.81,15.81,0,0,0,0-27ZM80,215.94V40l143.83,88Z"/></svg>
</button>
</div>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 276 소셜 프루프 팔레트 — 아홉 항목이 같은 값을 쓴다
$pf-ink: #1c1b22; // 어두운 면 (무대)
$pf-cream: #fbf7ef; // 카드 바탕 — ink 위 15.99:1
$pf-paper: $stage-paper;
$pf-stone: #565062; // 크림 위 보조 글자 7.23:1
$pf-teal: #479089; // 아바타 면 (흰 글자 5.79:1)
$pf-flame: $stage-orange; // 채워진 별
$pf-mint: #b3dad5; // 잉크 위 강조 11.45:1
$duration: $dur-loop; // 카드 석 장이 한 바퀴 도는 시간
$easing: $ease-spring; // 카드가 들고 나는 곡선
$color: $pf-ink; // 무대
@include stage($color);
.pc {
box-sizing: border-box;
display: grid;
gap: $sp-3;
width: clamp(288px, 92vw, 400px);
}
// 창 하나에 카드 석 장을 전부 겹쳐 둔다 — 복제본도, 텔레포트도 없다
.pc__window {
display: grid;
overflow: hidden;
border-radius: $r-card;
}
// 기본(정적) 상태: 카드는 창 밖 오른쪽. .is-on 한 장만 들어와 선다
.pc__card {
box-sizing: border-box;
grid-area: 1 / 1;
display: grid;
align-content: start;
gap: $sp-3;
padding: $sp-4;
border-radius: $r-card;
background: $pf-cream;
color: $pf-ink;
transform: translateX(100%);
}
.pc__card.is-on { transform: translateX(0); }
.pc__stars {
display: flex;
gap: $sp-1;
margin: 0;
color: $pf-flame;
}
.pc__star--off {
color: $pf-stone;
opacity: .72;
}
.pc__quote {
margin: 0;
font-weight: 600;
font-size: clamp(12px, 3vw, 14px);
line-height: 1.45;
}
.pc__who {
display: flex;
align-items: center;
gap: $sp-2;
margin: 0;
}
.pc__avatar {
display: grid;
place-items: center;
width: 32px;
height: 32px;
border-radius: 50%;
background: $pf-teal;
color: $pf-paper;
font-weight: 700;
font-size: 13px;
line-height: 1;
}
.pc__name {
display: grid;
font-weight: 700;
font-size: 12px;
line-height: 1.3;
}
.pc__role {
color: $pf-stone;
font-weight: 500;
font-size: 11px;
line-height: 1.3;
}
.pc__bar {
display: flex;
align-items: center;
justify-content: space-between;
}
// 점 세 개 — 겹치는 칸이 아니라 균등 격자. 활성 점은 알약으로 "넓어진다"(scaleX)
.pc__dots {
display: grid;
grid-template-columns: repeat(3, 24px);
gap: $sp-1;
align-items: center;
}
.pc__dot {
display: grid;
align-items: center;
justify-items: start;
height: 20px;
padding: 0;
border: 0;
border-radius: $r-xs;
background: none;
cursor: pointer;
}
.pc__pip {
display: block;
width: 8px;
height: 8px;
border-radius: $r-pill;
background-color: rgba($pf-cream, .32);
transform: scaleX(1);
transform-origin: left center; // 규칙8: 캐러셀 점 알약 좌변 확장
transition: transform $dur-quick $easing, background-color $dur-quick $ease-out;
}
.pc__dot.is-on .pc__pip {
background-color: $pf-mint;
transform: scaleX(2.5);
}
.pc__dot:focus-visible {
outline: 2px solid $pf-mint;
outline-offset: 2px;
}
.pc__toggle {
display: grid;
width: 28px;
height: 28px;
padding: 0;
border: 1px solid rgba($pf-cream, .34);
border-radius: $r-control;
background: none;
color: $pf-cream;
cursor: pointer;
}
.pc__ico {
grid-area: 1 / 1;
place-self: center;
}
.pc__ico--play { display: none; }
.pc__toggle[aria-pressed="true"] .pc__ico--pause { display: none; }
.pc__toggle[aria-pressed="true"] .pc__ico--play { display: block; }
.pc__toggle:focus-visible {
outline: 2px solid $pf-mint;
outline-offset: 2px;
}
// ── 자동 순환 ────────────────────────────────────────────────
// 석 장이 같은 키프레임을 33.333% 씩 어긋난 음수 delay 로 돈다.
// 한 장이 왼쪽으로 나가는 8% 동안 다음 장이 동시에 들어오므로 빈 화면이 없고,
// 자리를 되돌리는 순간(70%)은 창 밖이라 보이지 않는다.
// animation 단축은 delay 를 0 으로 리셋하므로 낱개 속성으로 쓴다
.pc.is-demo .pc__card {
animation-name: pcSlide;
animation-duration: $duration;
animation-timing-function: $easing;
animation-iteration-count: infinite;
animation-fill-mode: backwards;
}
// t=0 에서 1번은 8%(막 섰다) · 2번은 74.667%(오른쪽 대기) · 3번은 41.333%(막 나갔다)
.pc.is-demo .pc__card--1 { animation-delay: -.16s; }
.pc.is-demo .pc__card--2 { animation-delay: -1.4933s; }
.pc.is-demo .pc__card--3 { animation-delay: -.8267s; }
.pc.is-demo .pc__pip {
animation-name: pcPip, pcPipTone;
animation-duration: $duration, $duration;
animation-timing-function: $easing, steps(1, end);
animation-iteration-count: infinite, infinite;
animation-fill-mode: backwards, backwards;
transition: none;
}
.pc.is-demo .pc__dot:nth-child(1) .pc__pip { animation-delay: -.16s, -.16s; }
.pc.is-demo .pc__dot:nth-child(2) .pc__pip { animation-delay: -1.4933s, -1.4933s; }
.pc.is-demo .pc__dot:nth-child(3) .pc__pip { animation-delay: -.8267s, -.8267s; }
// 정지 버튼 — 순환을 그 자리에 세운다
.pc.is-paused .pc__card,
.pc.is-paused .pc__pip { animation-play-state: paused; }
@keyframes pcSlide {
0% { transform: translateX(100%); }
8% { transform: translateX(0); }
33.33% { transform: translateX(0); }
41.33% { transform: translateX(-100%); }
70% { transform: translateX(-100%); }
70.01% { transform: translateX(100%); }
100% { transform: translateX(100%); }
}
@keyframes pcPip {
0% { transform: scaleX(1); }
8% { transform: scaleX(2.5); }
33.33% { transform: scaleX(2.5); }
41.33% { transform: scaleX(1); }
100% { transform: scaleX(1); }
}
// 색은 컷으로 갈아 끼운다 — 크로스페이드는 poster 에 반투명 유령을 남긴다
@keyframes pcPipTone {
0% { background-color: rgba($pf-cream, .32); }
8% { background-color: $pf-mint; }
33.33% { background-color: $pf-mint; }
41.33% { background-color: rgba($pf-cream, .32); }
100% { background-color: rgba($pf-cream, .32); }
}
// 좁은 화면 — 글자와 간격만 줄이고 구조는 그대로
@media (max-width: 340px), (max-height: 220px) {
.pc { gap: $sp-2; width: 100%; }
.pc__card { gap: $sp-2; padding: $sp-2; }
.pc__star { width: 13px; height: 13px; }
.pc__quote { font-size: 11px; line-height: 1.4; }
.pc__avatar { width: 24px; height: 24px; font-size: 11px; }
.pc__name { font-size: 11px; }
.pc__role { font-size: 10px; }
.pc__dots { grid-template-columns: repeat(3, 22px); }
.pc__dot { height: 16px; }
.pc__toggle { width: 24px; height: 24px; }
}
@media (prefers-reduced-motion: reduce) {
// .pc.is-demo .pc__card (0,3,0) 를 이기려면 !important 가 필요하다.
// 움직임만 끄고 .is-on 카드와 활성 점은 그대로 보인다
.pc__card, .pc__pip { animation: none !important; transition: none !important; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #1c1b22;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.pc {
box-sizing: border-box;
display: grid;
gap: 12px;
width: clamp(288px, 92vw, 400px);
}
.pc__window {
display: grid;
overflow: hidden;
border-radius: 16px;
}
.pc__card {
box-sizing: border-box;
grid-area: 1/1;
display: grid;
align-content: start;
gap: 12px;
padding: 16px;
border-radius: 16px;
background: #fbf7ef;
color: #1c1b22;
transform: translateX(100%);
}
.pc__card.is-on {
transform: translateX(0);
}
.pc__stars {
display: flex;
gap: 4px;
margin: 0;
color: #ff4d1f;
}
.pc__star--off {
color: #565062;
opacity: 0.72;
}
.pc__quote {
margin: 0;
font-weight: 600;
font-size: clamp(12px, 3vw, 14px);
line-height: 1.45;
}
.pc__who {
display: flex;
align-items: center;
gap: 8px;
margin: 0;
}
.pc__avatar {
display: grid;
place-items: center;
width: 32px;
height: 32px;
border-radius: 50%;
background: #479089;
color: #ffffff;
font-weight: 700;
font-size: 13px;
line-height: 1;
}
.pc__name {
display: grid;
font-weight: 700;
font-size: 12px;
line-height: 1.3;
}
.pc__role {
color: #565062;
font-weight: 500;
font-size: 11px;
line-height: 1.3;
}
.pc__bar {
display: flex;
align-items: center;
justify-content: space-between;
}
.pc__dots {
display: grid;
grid-template-columns: repeat(3, 24px);
gap: 4px;
align-items: center;
}
.pc__dot {
display: grid;
align-items: center;
justify-items: start;
height: 20px;
padding: 0;
border: 0;
border-radius: 4px;
background: none;
cursor: pointer;
}
.pc__pip {
display: block;
width: 8px;
height: 8px;
border-radius: 999px;
background-color: rgba(251, 247, 239, 0.32);
transform: scaleX(1);
transform-origin: left center;
transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1), background-color 220ms ease-out;
}
.pc__dot.is-on .pc__pip {
background-color: #b3dad5;
transform: scaleX(2.5);
}
.pc__dot:focus-visible {
outline: 2px solid #b3dad5;
outline-offset: 2px;
}
.pc__toggle {
display: grid;
width: 28px;
height: 28px;
padding: 0;
border: 1px solid rgba(251, 247, 239, 0.34);
border-radius: 12px;
background: none;
color: #fbf7ef;
cursor: pointer;
}
.pc__ico {
grid-area: 1/1;
place-self: center;
}
.pc__ico--play {
display: none;
}
.pc__toggle[aria-pressed=true] .pc__ico--pause {
display: none;
}
.pc__toggle[aria-pressed=true] .pc__ico--play {
display: block;
}
.pc__toggle:focus-visible {
outline: 2px solid #b3dad5;
outline-offset: 2px;
}
.pc.is-demo .pc__card {
animation-name: pcSlide;
animation-duration: 2s;
animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
animation-iteration-count: infinite;
animation-fill-mode: backwards;
}
.pc.is-demo .pc__card--1 {
animation-delay: -0.16s;
}
.pc.is-demo .pc__card--2 {
animation-delay: -1.4933s;
}
.pc.is-demo .pc__card--3 {
animation-delay: -0.8267s;
}
.pc.is-demo .pc__pip {
animation-name: pcPip, pcPipTone;
animation-duration: 2s, 2s;
animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1), steps(1, end);
animation-iteration-count: infinite, infinite;
animation-fill-mode: backwards, backwards;
transition: none;
}
.pc.is-demo .pc__dot:nth-child(1) .pc__pip {
animation-delay: -0.16s, -0.16s;
}
.pc.is-demo .pc__dot:nth-child(2) .pc__pip {
animation-delay: -1.4933s, -1.4933s;
}
.pc.is-demo .pc__dot:nth-child(3) .pc__pip {
animation-delay: -0.8267s, -0.8267s;
}
.pc.is-paused .pc__card,
.pc.is-paused .pc__pip {
animation-play-state: paused;
}
@keyframes pcSlide {
0% {
transform: translateX(100%);
}
8% {
transform: translateX(0);
}
33.33% {
transform: translateX(0);
}
41.33% {
transform: translateX(-100%);
}
70% {
transform: translateX(-100%);
}
70.01% {
transform: translateX(100%);
}
100% {
transform: translateX(100%);
}
}
@keyframes pcPip {
0% {
transform: scaleX(1);
}
8% {
transform: scaleX(2.5);
}
33.33% {
transform: scaleX(2.5);
}
41.33% {
transform: scaleX(1);
}
100% {
transform: scaleX(1);
}
}
@keyframes pcPipTone {
0% {
background-color: rgba(251, 247, 239, 0.32);
}
8% {
background-color: #b3dad5;
}
33.33% {
background-color: #b3dad5;
}
41.33% {
background-color: rgba(251, 247, 239, 0.32);
}
100% {
background-color: rgba(251, 247, 239, 0.32);
}
}
@media (max-width: 340px), (max-height: 220px) {
.pc {
gap: 8px;
width: 100%;
}
.pc__card {
gap: 8px;
padding: 8px;
}
.pc__star {
width: 13px;
height: 13px;
}
.pc__quote {
font-size: 11px;
line-height: 1.4;
}
.pc__avatar {
width: 24px;
height: 24px;
font-size: 11px;
}
.pc__name {
font-size: 11px;
}
.pc__role {
font-size: 10px;
}
.pc__dots {
grid-template-columns: repeat(3, 22px);
}
.pc__dot {
height: 16px;
}
.pc__toggle {
width: 24px;
height: 24px;
}
}
@media (prefers-reduced-motion: reduce) {
.pc__card, .pc__pip {
animation: none !important;
transition: none !important;
}
}(function () {
var root = document.querySelector('.pc');
var cards = [].slice.call(root.querySelectorAll('.pc__card'));
var dots = [].slice.call(root.querySelectorAll('.pc__dot'));
var toggle = root.querySelector('.pc__toggle');
// 정적 경로 — .is-demo 를 떼면 .is-on 한 장만 보이고 점이 그 장을 가리킨다
function show(i) {
root.classList.remove('is-demo');
cards.forEach(function (c, n) { c.classList.toggle('is-on', n === i); });
dots.forEach(function (d, n) {
d.classList.toggle('is-on', n === i);
d.setAttribute('aria-current', n === i ? 'true' : 'false');
});
}
dots.forEach(function (d, i) {
d.addEventListener('click', function () { show(i); });
d.addEventListener('keydown', function (e) {
var to = -1;
if (e.key === 'ArrowRight') { to = (i + 1) % dots.length; }
if (e.key === 'ArrowLeft') { to = (i - 1 + dots.length) % dots.length; }
if (to < 0) { return; }
e.preventDefault();
show(to);
dots[to].focus({ preventScroll: true });
});
});
// 정지 버튼 — 순환을 그 자리에 세운다 (animation-play-state: paused)
toggle.addEventListener('click', function () {
var on = toggle.getAttribute('aria-pressed') === 'true';
toggle.setAttribute('aria-pressed', on ? 'false' : 'true');
root.classList.toggle('is-paused', !on);
});
})();import { useRef, useState } from "react";
import type { CSSProperties, ReactNode } from "react";
import styles from "./ProofCarousel.module.scss";
/* ambient 에 React 이벤트 제네릭이 없어 파일 안에 필요한 만큼만 선언한다 */
type KeyEvt = { key: string; preventDefault(): void };
type Box<T> = { current: T };
export type ReviewCard = {
/** 별 개수 (1~5) */
stars: number;
quote: string;
/** 아바타 이니셜 한 글자 */
initial: string;
name: string;
role: string;
};
export type ProofCarouselProps = {
sectionLabel?: string;
cards?: ReviewCard[];
starLabels?: [string, string];
dotLabels?: string[];
toggleLabel?: string;
/** 카드 석 장이 한 바퀴 도는 시간(ms) */
duration?: number;
easing?: string;
/** 무대 색 */
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
const StarIcon = (): ReactNode => (
<svg viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor">
<path d="M229.06,108.79l-48.7,42,14.88,62.79a8.4,8.4,0,0,1-12.52,9.17L128,189.09,73.28,222.74a8.4,8.4,0,0,1-12.52-9.17l14.88-62.79-48.7-42A8.46,8.46,0,0,1,31.73,94L95.64,88.8l24.62-59.6a8.36,8.36,0,0,1,15.48,0l24.62,59.6L224.27,94A8.46,8.46,0,0,1,229.06,108.79Z" opacity="0.2" />
<path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z" />
</svg>
);
const PauseIcon = (): ReactNode => (
<svg viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor">
<path d="M208,48V208a8,8,0,0,1-8,8H160a8,8,0,0,1-8-8V48a8,8,0,0,1,8-8h40A8,8,0,0,1,208,48ZM96,40H56a8,8,0,0,0-8,8V208a8,8,0,0,0,8,8H96a8,8,0,0,0,8-8V48A8,8,0,0,0,96,40Z" opacity="0.2" />
<path d="M200,32H160a16,16,0,0,0-16,16V208a16,16,0,0,0,16,16h40a16,16,0,0,0,16-16V48A16,16,0,0,0,200,32Zm0,176H160V48h40ZM96,32H56A16,16,0,0,0,40,48V208a16,16,0,0,0,16,16H96a16,16,0,0,0,16-16V48A16,16,0,0,0,96,32Zm0,176H56V48H96Z" />
</svg>
);
const PlayIcon = (): ReactNode => (
<svg viewBox="0 0 256 256" width="16" height="16" aria-hidden="true" focusable="false" fill="currentColor">
<path d="M228.23,134.69,84.15,222.81A8,8,0,0,1,72,216.12V39.88a8,8,0,0,1,12.15-6.69l144.08,88.12A7.82,7.82,0,0,1,228.23,134.69Z" opacity="0.2" />
<path d="M232.4,114.49,88.32,26.35a16,16,0,0,0-16.2-.3A15.86,15.86,0,0,0,64,39.87V216.13A15.94,15.94,0,0,0,80,232a16.07,16.07,0,0,0,8.36-2.35L232.4,141.51a15.81,15.81,0,0,0,0-27ZM80,215.94V40l143.83,88Z" />
</svg>
);
const DEFAULT_CARDS: ReviewCard[] = [
{ stars: 5, quote: "도입 첫 주에 문의 응답 시간이 절반으로 줄었습니다. 팀 전체가 같은 화면을 봅니다.", initial: "J", name: "디자인팀 팀장", role: "온라인 서점" },
{ stars: 4, quote: "표를 그대로 붙여 넣었는데 손볼 곳이 없었습니다. 다음 개편에도 그대로 씁니다.", initial: "M", name: "운영팀 매니저", role: "동네 빵집" },
{ stars: 5, quote: "설명서를 읽지 않고도 주문까지 끝냈습니다. 반품 문의가 눈에 띄게 줄었습니다.", initial: "S", name: "공방 대표", role: "수제 가구 공방" },
];
export default function ProofCarousel({
sectionLabel = "고객 후기 자동 순환",
cards = DEFAULT_CARDS,
starLabels = ["5점 만점에 5점", "5점 만점에 4점"],
dotLabels = ["첫째 후기 보기", "둘째 후기 보기", "셋째 후기 보기"],
toggleLabel = "자동 순환 멈춤",
duration = 2000,
easing = "cubic-bezier(.2,.8,.2,1)",
color = "#17141a",
}: ProofCarouselProps): ReactNode {
const [loop, setLoop] = useState<boolean>(true);
const [paused, setPaused] = useState<boolean>(false);
const [active, setActive] = useState<number>(0);
const dotRefs = useRef<Array<HTMLButtonElement | null>>([]) as Box<Array<HTMLButtonElement | null>>;
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
const tone = [styles.card1, styles.card2, styles.card3];
/* 정적 경로 — 점을 고르면 자동 순환을 끄고 그 카드 하나만 세운다 */
const show = (i: number): void => {
setLoop(false);
setActive(i);
};
const onDotKey = (e: KeyEvt, i: number): void => {
const list = dotRefs.current;
if (!list) { return; }
const n = list.length;
let to = -1;
if (e.key === "ArrowRight") { to = (i + 1) % n; }
if (e.key === "ArrowLeft") { to = (i - 1 + n) % n; }
if (to < 0) { return; }
e.preventDefault();
show(to);
const btn = list[to];
if (btn) { btn.focus({ preventScroll: true }); }
};
return (
<section
className={[styles.pc, loop ? styles.isDemo : "", paused ? styles.isPaused : ""].filter(Boolean).join(" ")}
style={vars}
aria-label={sectionLabel}
>
<div className={styles.window} aria-live="off">
{cards.map((c: ReviewCard, i: number) => (
<article
className={[styles.card, tone[i % tone.length], active === i ? styles.isOn : ""].filter(Boolean).join(" ")}
key={c.name}
>
<p className={styles.stars} role="img" aria-label={starLabels[c.stars >= 5 ? 0 : 1]}>
{[0, 1, 2, 3, 4].map((k: number) => (
<span className={k < c.stars ? styles.star : styles.starOff} key={k}>
<StarIcon />
</span>
))}
</p>
<p className={styles.quote}>{c.quote}</p>
<p className={styles.who}>
<span className={styles.avatar} aria-hidden="true">{c.initial}</span>
<span className={styles.name}>
{c.name}
<span className={styles.role}>{c.role}</span>
</span>
</p>
</article>
))}
</div>
<div className={styles.bar}>
<span className={styles.dots}>
{cards.map((c: ReviewCard, i: number) => (
<button
className={[styles.dot, active === i ? styles.isOn : ""].filter(Boolean).join(" ")}
type="button"
key={c.name}
aria-label={dotLabels[i % dotLabels.length]}
aria-current={active === i ? "true" : "false"}
ref={(el: HTMLButtonElement | null) => { dotRefs.current[i] = el; }}
onClick={() => show(i)}
onKeyDown={(e: KeyEvt) => onDotKey(e, i)}
>
<span className={styles.pip} aria-hidden="true" />
</button>
))}
</span>
<button
className={styles.toggle}
type="button"
aria-pressed={paused}
aria-label={toggleLabel}
onClick={() => setPaused(!paused)}
>
<span className={styles.icoPause}><PauseIcon /></span>
<span className={styles.icoPlay}><PlayIcon /></span>
</button>
</div>
</section>
);
}01 自動送りのレビューカルーセル — 計測 累積面積 8.115% · 動いたフレーム 6/23GODRICH オリジナル · SCSS と React は zip に同梱 · お客様の声 デザインの型9選、そのまま貼れる
このデモが属する記事
お客様の声 デザインの型9選、そのまま貼れるお客様の声 デザインで探しているのは、紹介文を並べただけでは伝わらない信頼を、画面の動きで示す区画のひな形です。ここにはレビュー3件の小さな帯から料金表の横の指標まで、九つの型をそのまま貼れるHTMLとSCSSでまとめました。どれもこの画面 この記事のデモをすべて見る


