Skip to content

Commit fcb2a22

Browse files
ferr079claude
andcommitted
fix: TapeCarousel — viewport overflow clip, arrow positioning inside
Added tc-viewport wrapper with overflow:hidden + position:relative. Arrows now inside the visible area (0.75rem from edges, not -0.5rem). Touch events on viewport instead of track. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d997d80 commit fcb2a22

1 file changed

Lines changed: 27 additions & 17 deletions

File tree

src/components/TapeCarousel.astro

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,24 @@ const { tapes, id } = Astro.props;
1818
---
1919

2020
<div class="tape-carousel" id={id} data-tape-carousel>
21-
<div class="tc-track">
22-
{tapes.map((tape) => (
23-
<div class="tc-slide">
24-
<div class="tape-block">
25-
<div class="tape-header">
26-
{tape.icon && <img src={tape.icon} alt="" class="tape-logo" loading="lazy" aria-hidden="true" onerror="this.style.display='none'" />}
27-
<h4>{tape.title}</h4>
21+
<div class="tc-viewport">
22+
<div class="tc-track">
23+
{tapes.map((tape) => (
24+
<div class="tc-slide">
25+
<div class="tape-block">
26+
<div class="tape-header">
27+
{tape.icon && <img src={tape.icon} alt="" class="tape-logo" loading="lazy" aria-hidden="true" onerror="this.style.display='none'" />}
28+
<h4>{tape.title}</h4>
29+
</div>
30+
<p class="tape-desc">{tape.description}</p>
31+
<Video src={tape.src} title={tape.title} caption={tape.caption} />
2832
</div>
29-
<p class="tape-desc">{tape.description}</p>
30-
<Video src={tape.src} title={tape.title} caption={tape.caption} />
3133
</div>
32-
</div>
33-
))}
34+
))}
35+
</div>
36+
<button class="tc-btn tc-prev" aria-label="Previous">&larr;</button>
37+
<button class="tc-btn tc-next" aria-label="Next">&rarr;</button>
3438
</div>
35-
<button class="tc-btn tc-prev" aria-label="Previous">&larr;</button>
36-
<button class="tc-btn tc-next" aria-label="Next">&rarr;</button>
3739
<div class="tc-dots">
3840
{tapes.map((tape, i) => (
3941
<button class:list={['tc-dot', { active: i === 0 }]} aria-label={tape.title} data-index={i}></button>
@@ -43,6 +45,7 @@ const { tapes, id } = Astro.props;
4345

4446
<script>
4547
document.querySelectorAll('[data-tape-carousel]').forEach((carousel) => {
48+
const viewport = carousel.querySelector('.tc-viewport') as HTMLElement;
4649
const track = carousel.querySelector('.tc-track') as HTMLElement;
4750
const slides = carousel.querySelectorAll('.tc-slide');
4851
const dots = carousel.querySelectorAll('.tc-dot');
@@ -68,8 +71,8 @@ const { tapes, id } = Astro.props;
6871
dots.forEach((dot) => dot.addEventListener('click', () => goTo(Number((dot as HTMLElement).dataset.index))));
6972

7073
let startX = 0;
71-
track.addEventListener('touchstart', (e) => { startX = (e as TouchEvent).touches[0].clientX; }, { passive: true });
72-
track.addEventListener('touchend', (e) => {
74+
viewport.addEventListener('touchstart', (e) => { startX = (e as TouchEvent).touches[0].clientX; }, { passive: true });
75+
viewport.addEventListener('touchend', (e) => {
7376
const dx = (e as TouchEvent).changedTouches[0].clientX - startX;
7477
if (Math.abs(dx) > 50) goTo(current + (dx < 0 ? 1 : -1));
7578
});
@@ -80,7 +83,12 @@ const { tapes, id } = Astro.props;
8083
.tape-carousel {
8184
position: relative;
8285
margin: 2rem 0;
86+
}
87+
88+
.tc-viewport {
89+
position: relative;
8390
overflow: hidden;
91+
border-radius: 8px;
8492
}
8593

8694
.tc-track {
@@ -91,6 +99,8 @@ const { tapes, id } = Astro.props;
9199
.tc-slide {
92100
min-width: 100%;
93101
flex-shrink: 0;
102+
box-sizing: border-box;
103+
padding: 0 0.25rem;
94104
}
95105

96106
/* Tape block styling (inline — no separate component needed in carousel) */
@@ -152,8 +162,8 @@ const { tapes, id } = Astro.props;
152162
background: var(--color-bg);
153163
}
154164

155-
.tc-prev { left: -0.5rem; }
156-
.tc-next { right: -0.5rem; }
165+
.tc-prev { left: 0.75rem; }
166+
.tc-next { right: 0.75rem; }
157167

158168
.tc-dots {
159169
display: flex;

0 commit comments

Comments
 (0)