Design language

This commit is contained in:
2026-05-13 09:39:52 +12:00
parent 6c943b14bd
commit de8b60b9c3
11 changed files with 329 additions and 236 deletions
+68 -6
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import { onMount, tick } from 'svelte';
import { reveal } from '$lib/actions/reveal';
import Icon from '$lib/components/Icon.svelte';
import { getEnhancedImage } from '$lib/enhanced-images';
@@ -52,6 +52,7 @@
let inView = false;
let prefersReducedMotion = false;
let carouselEl: HTMLDivElement | undefined;
let stageEl: HTMLDivElement | undefined;
let slideSignature = '';
$: slides = testimonials
@@ -89,6 +90,7 @@
}
activeIndex = (activeIndex - 1 + slides.length) % slides.length;
syncMobileStage();
}
function showNext() {
@@ -97,6 +99,34 @@
}
activeIndex = (activeIndex + 1) % slides.length;
syncMobileStage();
}
function isMobileViewport() {
return typeof window !== 'undefined' && window.innerWidth <= 767;
}
async function syncMobileStage(behavior: ScrollBehavior = 'smooth') {
if (!stageEl || !isMobileViewport()) {
return;
}
await tick();
stageEl.scrollTo({
left: stageEl.clientWidth * activeIndex,
behavior
});
}
function handleStageScroll() {
if (!stageEl || !isMobileViewport()) {
return;
}
const nextIndex = Math.round(stageEl.scrollLeft / Math.max(stageEl.clientWidth, 1));
if (nextIndex !== activeIndex) {
activeIndex = nextIndex;
}
}
onMount(() => {
@@ -120,6 +150,13 @@
observer.observe(carouselEl);
}
const handleResize = () => {
syncMobileStage('auto');
};
window.addEventListener('resize', handleResize);
syncMobileStage('auto');
const interval = window.setInterval(() => {
if (!paused && !prefersReducedMotion && inView && slides.length > 1) {
showNext();
@@ -128,6 +165,7 @@
return () => {
window.clearInterval(interval);
window.removeEventListener('resize', handleResize);
motionQuery.removeEventListener('change', onMotionChange);
observer?.disconnect();
};
@@ -162,7 +200,7 @@
<Icon name="fas fa-chevron-left" />
</button>
<div class="testimonial-stage">
<div bind:this={stageEl} class="testimonial-stage" on:scroll={handleStageScroll}>
<div class="testimonial-woof" aria-hidden="true">
<span class="testimonial-woof-text">WOOF</span>
<span class="testimonial-ray testimonial-ray-1"></span>
@@ -640,14 +678,28 @@
.testimonial-stage {
min-height: unset;
display: flex;
padding-bottom: 0;
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x proximity;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
}
.testimonial-stage::-webkit-scrollbar {
display: none;
}
.testimonial-slide {
position: relative;
display: none;
display: grid;
flex: 0 0 100%;
grid-template-columns: 1fr;
opacity: 1;
pointer-events: auto;
transform: none;
scroll-snap-align: start;
}
.testimonial-slide-active {
@@ -689,17 +741,27 @@
.testimonial-mobile-controls {
display: inline-flex;
align-items: center;
justify-content: flex-end;
width: 100%;
gap: 12px;
margin-top: 20px;
}
.testimonial-arrow-inline {
position: static;
width: 48px;
height: 48px;
width: 46px;
height: 46px;
border: none;
border-radius: 50%;
background: rgba(33, 48, 33, 0.08);
color: var(--gw-green);
font-size: 18px;
transform: none;
box-shadow: 0 10px 22px rgba(20, 24, 20, 0.08);
box-shadow: none;
}
.testimonial-arrow-inline:active {
transform: scale(0.95);
}
.testimonial-google {