Skip to content

Commit 1739f89

Browse files
author
TechStack Global
committed
style: fix arrow buttons placement on animated deck
1 parent 4e1e328 commit 1739f89

1 file changed

Lines changed: 167 additions & 65 deletions

File tree

index.html

Lines changed: 167 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ <h1>Make Smarter <br /><span class="gradient-text">Tech Decisions.</span>
107107
Just clear guidance on the tech that powers modern work.</p>
108108

109109
</div>
110-
<!-- Pull-Out Animated Deck -->
110+
<!-- Pull-Out Animated Deck -->
111111
<div class="hero-visual">
112112
<style>
113113
.deck-container {
@@ -119,9 +119,12 @@ <h1>Make Smarter <br /><span class="gradient-text">Tech Decisions.</span>
119119
perspective: 1200px;
120120
transform-style: preserve-3d;
121121
}
122+
122123
.deck-card {
123124
position: absolute;
124-
top: 0; left: 0; right: 0;
125+
top: 0;
126+
left: 0;
127+
right: 0;
125128
background: rgba(15, 23, 42, 0.7);
126129
backdrop-filter: blur(16px);
127130
border: 1px solid var(--border-glass);
@@ -138,45 +141,134 @@ <h1>Make Smarter <br /><span class="gradient-text">Tech Decisions.</span>
138141
/* Smooth transitions when dropping or clicking next */
139142
transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.4s linear;
140143
}
144+
141145
.deck-card:active {
142146
cursor: grabbing;
143147
}
148+
144149
.deck-card img {
145-
width: 100%; height: auto; border-radius: 8px; margin-bottom: 1rem; aspect-ratio: 16/9; object-fit: cover; pointer-events: none;
150+
width: 100%;
151+
height: auto;
152+
border-radius: 8px;
153+
margin-bottom: 1rem;
154+
aspect-ratio: 16/9;
155+
object-fit: cover;
156+
pointer-events: none;
157+
}
158+
159+
.deck-card h3 {
160+
font-size: 1.4rem;
161+
margin-bottom: 0.5rem;
162+
line-height: 1.3;
163+
color: white;
164+
}
165+
166+
.deck-card p {
167+
color: var(--text-secondary);
168+
font-size: 0.95rem;
169+
margin-bottom: 1.5rem;
170+
line-height: 1.5;
171+
pointer-events: none;
172+
flex-grow: 1;
146173
}
147-
.deck-card h3 { font-size: 1.4rem; margin-bottom: 0.5rem; line-height: 1.3; color: white; }
148-
.deck-card p { color: var(--text-secondary); font-size: 0.95rem; margin-bottom: 1.5rem; line-height: 1.5; pointer-events: none; flex-grow: 1; }
149-
174+
150175
/* The pull indicator */
151176
.pull-indicator {
152-
position: absolute; top: -30px; right: 10px; font-size: 0.85rem; color: var(--accent); opacity: 0;
153-
font-weight: 600; text-transform: uppercase; letter-spacing: 1px; z-index: 10;
177+
position: absolute;
178+
top: -30px;
179+
right: 10px;
180+
font-size: 0.85rem;
181+
color: var(--accent);
182+
opacity: 0;
183+
font-weight: 600;
184+
text-transform: uppercase;
185+
letter-spacing: 1px;
186+
z-index: 10;
154187
animation: bounceX 2s infinite ease-in-out;
155188
pointer-events: none;
156189
}
190+
157191
@keyframes bounceX {
158-
0%, 100% { transform: translateX(0); opacity: 0.8;}
159-
50% { transform: translateX(-10px); opacity: 0.4;}
192+
193+
0%,
194+
100% {
195+
transform: translateX(0);
196+
opacity: 0.8;
197+
}
198+
199+
50% {
200+
transform: translateX(-10px);
201+
opacity: 0.4;
202+
}
160203
}
161-
204+
162205
/* Deck states based on data-depth attributes controlled by JS */
163-
.deck-card[data-depth="0"] { transform: translateZ(0) translateY(0) scale(1); z-index: 3; opacity: 1; }
164-
.deck-card[data-depth="1"] { transform: translateZ(-80px) translateY(25px) scale(0.95); z-index: 2; opacity: 0.8; }
165-
.deck-card[data-depth="2"] { transform: translateZ(-160px) translateY(50px) scale(0.9); z-index: 1; opacity: 0.4; }
166-
206+
.deck-card[data-depth="0"] {
207+
transform: translateZ(0) translateY(0) scale(1);
208+
z-index: 3;
209+
opacity: 1;
210+
}
211+
212+
.deck-card[data-depth="1"] {
213+
transform: translateZ(-80px) translateY(25px) scale(0.95);
214+
z-index: 2;
215+
opacity: 0.8;
216+
}
217+
218+
.deck-card[data-depth="2"] {
219+
transform: translateZ(-160px) translateY(50px) scale(0.9);
220+
z-index: 1;
221+
opacity: 0.4;
222+
}
223+
167224
/* Thrown away states */
168-
.deck-card.throw-left { transform: translateZ(0) translateX(-150%) rotate(-15deg) !important; opacity: 0 !important; }
169-
.deck-card.throw-right { transform: translateZ(0) translateX(150%) rotate(15deg) !important; opacity: 0 !important; }
225+
.deck-card.throw-left {
226+
transform: translateZ(0) translateX(-150%) rotate(-15deg) !important;
227+
opacity: 0 !important;
228+
}
229+
230+
.deck-card.throw-right {
231+
transform: translateZ(0) translateX(150%) rotate(15deg) !important;
232+
opacity: 0 !important;
233+
}
170234

171235
/* Controls */
172236
.deck-controls {
173-
display: flex; justify-content: space-between; align-items: center; max-width: 400px; margin: 0 auto; position: relative; z-index: 10;
237+
display: flex;
238+
justify-content: center;
239+
align-items: center;
240+
gap: 1.5rem;
241+
max-width: 400px;
242+
margin: 0.5rem auto 0;
243+
position: relative;
244+
z-index: 10;
174245
}
246+
175247
.deck-controls button {
176-
background: rgba(255,255,255,0.05); border: 1px solid var(--border-glass); color: white; width: 45px; height: 45px; border-radius: 50%; cursor: pointer; transition: 0.2s; display: flex; align-items: center; justify-content: center;
248+
background: rgba(15, 23, 42, 0.8);
249+
backdrop-filter: blur(10px);
250+
border: 1px solid var(--border-glass);
251+
color: white;
252+
width: 45px;
253+
height: 45px;
254+
border-radius: 50%;
255+
cursor: pointer;
256+
transition: 0.2s;
257+
display: flex;
258+
align-items: center;
259+
justify-content: center;
260+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
261+
}
262+
263+
.deck-controls button:hover {
264+
background: var(--accent);
265+
color: #000;
266+
transform: scale(1.1);
267+
}
268+
269+
.deck-controls button i {
270+
font-size: 1.1rem;
177271
}
178-
.deck-controls button:hover { background: var(--accent); color: #000; }
179-
.deck-controls button i { font-size: 1.1rem; }
180272
</style>
181273

182274
<div class="deck-container" id="reviewDeck">
@@ -185,67 +277,77 @@ <h1>Make Smarter <br /><span class="gradient-text">Tech Decisions.</span>
185277

186278
<!-- Card 0: Sony -->
187279
<div class="deck-card" data-index="0">
188-
<div style="font-size: 0.75rem; color: var(--accent); font-weight: bold; text-transform: uppercase; margin-bottom: 0.5rem;">
280+
<div
281+
style="font-size: 0.75rem; color: var(--accent); font-weight: bold; text-transform: uppercase; margin-bottom: 0.5rem;">
189282
<i class="fa-solid fa-headphones"></i> Audio
190283
</div>
191284
<img src="posts/images/sony-wh-1000xm5-front.jpg" alt="Sony WH-1000XM5" loading="lazy">
192285
<h3>Sony WH-1000XM5</h3>
193286
<p>Top-tier active noise cancellation and supreme all-day comfort for deep focus sessions.</p>
194-
<a class="read-more" href="posts/sony-wh-1000xm5-review.html" style="font-weight: 700; display:inline-block; margin-top: auto;">Read Review <i class="fa-solid fa-arrow-right" style="margin-left: 5px;"></i></a>
287+
<a class="read-more" href="posts/sony-wh-1000xm5-review.html"
288+
style="font-weight: 700; display:inline-block; margin-top: auto;">Read Review <i
289+
class="fa-solid fa-arrow-right" style="margin-left: 5px;"></i></a>
195290
</div>
196291

197292
<!-- Card 1: Shure -->
198293
<div class="deck-card" data-index="1">
199-
<div style="font-size: 0.75rem; color: var(--accent); font-weight: bold; text-transform: uppercase; margin-bottom: 0.5rem;">
294+
<div
295+
style="font-size: 0.75rem; color: var(--accent); font-weight: bold; text-transform: uppercase; margin-bottom: 0.5rem;">
200296
<i class="fa-solid fa-microphone"></i> Broadcasting
201297
</div>
202298
<img src="posts/images/shure-sm7db-primary.jpg" alt="Shure SM7dB Microphone" loading="lazy">
203299
<h3>Shure SM7dB</h3>
204300
<p>The industry standard podcast microphone, now powered with a built-in clean preamp.</p>
205-
<a class="read-more" href="posts/shure-sm7db-review.html" style="font-weight: 700; display:inline-block; margin-top: auto;">Read Review <i class="fa-solid fa-arrow-right" style="margin-left: 5px;"></i></a>
301+
<a class="read-more" href="posts/shure-sm7db-review.html"
302+
style="font-weight: 700; display:inline-block; margin-top: auto;">Read Review <i
303+
class="fa-solid fa-arrow-right" style="margin-left: 5px;"></i></a>
206304
</div>
207305

208306
<!-- Card 2: Alienware -->
209307
<div class="deck-card" data-index="2">
210-
<div style="font-size: 0.75rem; color: var(--accent); font-weight: bold; text-transform: uppercase; margin-bottom: 0.5rem;">
308+
<div
309+
style="font-size: 0.75rem; color: var(--accent); font-weight: bold; text-transform: uppercase; margin-bottom: 0.5rem;">
211310
<i class="fa-solid fa-desktop"></i> Displays
212311
</div>
213312
<img src="posts/images/alienware-aw3423dwf-front.jpg" alt="Alienware AW3423DWF" loading="lazy">
214313
<h3>Alienware AW3423DWF</h3>
215314
<p>Stunning QD-OLED ultrawide performance delivering flawless visual immersion.</p>
216-
<a class="read-more" href="posts/alienware-aw3423dwf-review.html" style="font-weight: 700; display:inline-block; margin-top: auto;">Read Review <i class="fa-solid fa-arrow-right" style="margin-left: 5px;"></i></a>
315+
<a class="read-more" href="posts/alienware-aw3423dwf-review.html"
316+
style="font-weight: 700; display:inline-block; margin-top: auto;">Read Review <i
317+
class="fa-solid fa-arrow-right" style="margin-left: 5px;"></i></a>
217318
</div>
218319
</div>
219-
320+
220321
<div class="deck-controls">
221322
<button id="deckPrev" aria-label="Previous Review"><i class="fa-solid fa-arrow-left"></i></button>
222-
<span style="font-size: 0.9rem; color: var(--text-muted); font-weight: 600; letter-spacing: 1px;" id="deckCount">1 / 3</span>
323+
<span style="font-size: 0.9rem; color: var(--text-muted); font-weight: 600; letter-spacing: 1px;"
324+
id="deckCount">1 / 3</span>
223325
<button id="deckNext" aria-label="Next Review"><i class="fa-solid fa-arrow-right"></i></button>
224326
</div>
225327

226328
<script>
227329
document.addEventListener('DOMContentLoaded', () => {
228330
const deck = document.getElementById('reviewDeck');
229-
if(!deck) return;
230-
331+
if (!deck) return;
332+
231333
const cards = Array.from(deck.querySelectorAll('.deck-card'));
232334
const prevBtn = document.getElementById('deckPrev');
233335
const nextBtn = document.getElementById('deckNext');
234336
const countEl = document.getElementById('deckCount');
235337
const hint = document.getElementById('pullHint');
236-
237-
let topIndex = 0;
338+
339+
let topIndex = 0;
238340
const total = cards.length;
239341

240342
function updateDeck() {
241343
cards.forEach((card, i) => {
242-
card.classList.remove('throw-left', 'throw-right');
243-
card.style.transition = ''; // reset to CSS transition
244-
card.style.transform = ''; // clears inline drag transforms
245-
246-
// Distance from current top card
247-
let depth = (i - topIndex + total) % total;
248-
card.setAttribute('data-depth', depth.toString());
344+
card.classList.remove('throw-left', 'throw-right');
345+
card.style.transition = ''; // reset to CSS transition
346+
card.style.transform = ''; // clears inline drag transforms
347+
348+
// Distance from current top card
349+
let depth = (i - topIndex + total) % total;
350+
card.setAttribute('data-depth', depth.toString());
249351
});
250352
countEl.textContent = `${topIndex + 1} / ${total}`;
251353
}
@@ -254,18 +356,18 @@ <h3>Alienware AW3423DWF</h3>
254356
const currentTopCard = cards[topIndex];
255357
// Apply the throw animation class
256358
currentTopCard.classList.add(direction === 'left' ? 'throw-left' : 'throw-right');
257-
359+
258360
// Hide hint after first interaction
259-
if(hint) hint.style.display = 'none';
361+
if (hint) hint.style.display = 'none';
260362

261363
// Wait enough time for the throw animation to clear visually before re-stacking
262364
setTimeout(() => {
263-
if(direction === 'left' || direction === 'next') {
264-
topIndex = (topIndex + 1) % total;
265-
} else {
266-
topIndex = (topIndex - 1 + total) % total;
267-
}
268-
updateDeck();
365+
if (direction === 'left' || direction === 'next') {
366+
topIndex = (topIndex + 1) % total;
367+
} else {
368+
topIndex = (topIndex - 1 + total) % total;
369+
}
370+
updateDeck();
269371
}, 300); // 300ms matches CSS transition timing
270372
}
271373

@@ -279,53 +381,53 @@ <h3>Alienware AW3423DWF</h3>
279381

280382
function onStart(x, y, target) {
281383
// Ignore clicks on links/buttons
282-
if(target.closest('a') || target.closest('button')) return;
384+
if (target.closest('a') || target.closest('button')) return;
283385
isDragging = true;
284386
startX = x;
285387
currentX = x;
286388
// Remove transition visually to make dragging instantaneous
287389
cards[topIndex].style.transition = 'none';
288-
289-
if(hint) hint.style.display = 'none';
390+
391+
if (hint) hint.style.display = 'none';
290392
}
291393

292394
function onMove(x) {
293-
if(!isDragging) return;
395+
if (!isDragging) return;
294396
currentX = x;
295397
const diffX = currentX - startX;
296-
const rotate = diffX * 0.05;
398+
const rotate = diffX * 0.05;
297399
// Instantly update transform
298400
cards[topIndex].style.transform = `translateZ(0) translateY(0) translateX(${diffX}px) rotate(${rotate}deg)`;
299401
}
300402

301403
function onEnd() {
302-
if(!isDragging) return;
404+
if (!isDragging) return;
303405
isDragging = false;
304406
const diffX = currentX - startX;
305-
306-
if(Math.abs(diffX) > 80) { // threshold passed
307-
throwCard(diffX < 0 ? 'left' : 'right');
407+
408+
if (Math.abs(diffX) > 80) { // threshold passed
409+
throwCard(diffX < 0 ? 'left' : 'right');
308410
} else {
309-
// return to center smoothly
310-
updateDeck();
411+
// return to center smoothly
412+
updateDeck();
311413
}
312414
}
313415

314416
deck.addEventListener('mousedown', (e) => onStart(e.clientX, e.clientY, e.target));
315417
window.addEventListener('mousemove', (e) => onMove(e.clientX));
316418
window.addEventListener('mouseup', onEnd);
317-
318-
deck.addEventListener('touchstart', (e) => onStart(e.touches[0].clientX, e.touches[0].clientY, e.target), {passive: false});
419+
420+
deck.addEventListener('touchstart', (e) => onStart(e.touches[0].clientX, e.touches[0].clientY, e.target), { passive: false });
319421
deck.addEventListener('touchmove', (e) => {
320-
if(isDragging) { e.preventDefault(); onMove(e.touches[0].clientX); }
321-
}, {passive: false});
422+
if (isDragging) { e.preventDefault(); onMove(e.touches[0].clientX); }
423+
}, { passive: false });
322424
deck.addEventListener('touchend', onEnd);
323425

324426
// Init
325427
updateDeck();
326-
428+
327429
// Show hint briefly on load
328-
setTimeout(() => { if(hint) hint.style.opacity = '1'; }, 1500);
430+
setTimeout(() => { if (hint) hint.style.opacity = '1'; }, 1500);
329431
});
330432
</script>
331433
</div>

0 commit comments

Comments
 (0)