built with ai (cursor/claude)
tinder clone for rating bricks 16 brick images, swipe left/right functionality match modal with profile pics auto-dismisses after 2s background image fades in on swipe end screen with youtube video link styling and animations complete joke website but functional
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
// Brick data - loaded from Pexels API downloads
|
||||
const bricks = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Old Brick Wall",
|
||||
image: "images/brick_01.jpg",
|
||||
description: "A moody close-up of an old brick wall with character.",
|
||||
color: "Brown",
|
||||
texture: "Weathered"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Dark Brick Wall",
|
||||
image: "images/brick_02.jpg",
|
||||
description: "Close-up texture of a dark, rough brick wall.",
|
||||
color: "Dark Brown",
|
||||
texture: "Rough"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "White Brick Wall",
|
||||
image: "images/brick_03.jpg",
|
||||
description: "A minimalist white brick wall casting shadows.",
|
||||
color: "White",
|
||||
texture: "Smooth"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Red Brick Building",
|
||||
image: "images/brick_04.jpg",
|
||||
description: "Red-brick modern building against a vibrant blue sky.",
|
||||
color: "Red",
|
||||
texture: "Modern"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Weathered Red Brick",
|
||||
image: "images/brick_05.jpg",
|
||||
description: "A detailed view of a weathered red brick wall.",
|
||||
color: "Red",
|
||||
texture: "Weathered"
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Ancient Brick Archway",
|
||||
image: "images/brick_06.jpg",
|
||||
description: "The timeless beauty of an ancient brick archway.",
|
||||
color: "Brown",
|
||||
texture: "Aged"
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Vintage Brick Door",
|
||||
image: "images/brick_07.jpg",
|
||||
description: "A vintage wooden door set in historic brickwork.",
|
||||
color: "Brown",
|
||||
texture: "Vintage"
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Brick Archway",
|
||||
image: "images/brick_08.jpg",
|
||||
description: "Captivating brick archway showcasing architectural beauty.",
|
||||
color: "Brown",
|
||||
texture: "Textured"
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Ancient Stone Masonry",
|
||||
image: "images/brick_09.jpg",
|
||||
description: "Explore the timeless beauty of ancient stone masonry with a view through a historic window in ruins.",
|
||||
color: "Brown",
|
||||
texture: "Ancient"
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Pink Brick Wall",
|
||||
image: "images/brick_10.jpg",
|
||||
description: "Light pink textured brick wall corner perfect for backgrounds and design.",
|
||||
color: "Pink",
|
||||
texture: "Textured"
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Urban Brick Alley",
|
||||
image: "images/brick_11.jpg",
|
||||
description: "Explore the character of a narrow urban alley lined with rustic brick walls and faded graffiti.",
|
||||
color: "Brown",
|
||||
texture: "Rustic"
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Red Brick Wall",
|
||||
image: "images/brick_12.jpg",
|
||||
description: "High-resolution image of a red brick wall with white mortar lines, perfect for backgrounds.",
|
||||
color: "Red",
|
||||
texture: "Classic"
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "Aged Brick Window",
|
||||
image: "images/brick_13.jpg",
|
||||
description: "A cat peeks through a wooden window of an aged building, adding charm.",
|
||||
color: "Brown",
|
||||
texture: "Aged"
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: "Roman Stone Arch",
|
||||
image: "images/brick_14.jpg",
|
||||
description: "Detailed view of an ancient Roman stone arch with ornate decorative carvings.",
|
||||
color: "Brown",
|
||||
texture: "Ornate"
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: "Cozy Brick Fireplace",
|
||||
image: "images/brick_15.jpg",
|
||||
description: "Cozy winter fireplace with brickwork showcasing warm textures.",
|
||||
color: "Brown",
|
||||
texture: "Cozy"
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
name: "Classic Brick Doorway",
|
||||
image: "images/brick_16.jpg",
|
||||
description: "A classic wooden door set in an ancient stone wall with a decorative flower wreath.",
|
||||
color: "Brown",
|
||||
texture: "Classic"
|
||||
}
|
||||
];
|
||||
|
||||
let currentIndex = 0;
|
||||
let likedCount = 0;
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let currentX = 0;
|
||||
let currentY = 0;
|
||||
let isDragging = false;
|
||||
|
||||
const card = document.getElementById('currentCard');
|
||||
const brickImage = document.getElementById('brickImage');
|
||||
const brickName = document.getElementById('brickName');
|
||||
const brickDescription = document.getElementById('brickDescription');
|
||||
const brickColor = document.getElementById('brickColor');
|
||||
const brickTexture = document.getElementById('brickTexture');
|
||||
const likeBtn = document.getElementById('likeBtn');
|
||||
const nopeBtn = document.getElementById('nopeBtn');
|
||||
const likedCountEl = document.getElementById('likedCount');
|
||||
const remainingCountEl = document.getElementById('remainingCount');
|
||||
const endScreen = document.getElementById('endScreen');
|
||||
const finalLikedCount = document.getElementById('finalLikedCount');
|
||||
const restartBtn = document.getElementById('restartBtn');
|
||||
const backgroundImage = document.querySelector('.background-image');
|
||||
const matchPopup = document.getElementById('matchPopup');
|
||||
|
||||
function loadBrick(index) {
|
||||
if (index >= bricks.length) {
|
||||
showEndScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
const brick = bricks[index];
|
||||
|
||||
// Reset card position and opacity for smooth entry
|
||||
card.style.transition = 'none';
|
||||
card.style.transform = 'translate(0, 0) rotate(0deg)';
|
||||
card.style.opacity = '0';
|
||||
|
||||
// Hide background image when new card loads
|
||||
if (backgroundImage) {
|
||||
backgroundImage.style.transition = 'opacity 0.3s ease-in';
|
||||
backgroundImage.style.opacity = '0';
|
||||
}
|
||||
|
||||
// Update content
|
||||
brickImage.src = brick.image;
|
||||
brickImage.alt = brick.name;
|
||||
brickName.textContent = brick.name;
|
||||
brickDescription.textContent = brick.description;
|
||||
brickColor.textContent = brick.color;
|
||||
brickTexture.textContent = brick.texture;
|
||||
card.querySelector('.card-overlay').classList.remove('active');
|
||||
|
||||
updateStats();
|
||||
|
||||
// Fade in the new card smoothly
|
||||
setTimeout(() => {
|
||||
card.style.transition = 'opacity 0.3s ease-in';
|
||||
card.style.opacity = '1';
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
likedCountEl.textContent = likedCount;
|
||||
remainingCountEl.textContent = bricks.length - currentIndex;
|
||||
}
|
||||
|
||||
function swipeCard(direction) {
|
||||
const overlay = card.querySelector('.card-overlay');
|
||||
const likeBadge = overlay.querySelector('.like-badge');
|
||||
const nopeBadge = overlay.querySelector('.nope-badge');
|
||||
|
||||
overlay.classList.add('active');
|
||||
|
||||
// Set transition for smooth animation
|
||||
card.style.transition = 'transform 0.4s ease-out, opacity 0.4s ease-out';
|
||||
|
||||
// Show background image as card swipes away
|
||||
if (backgroundImage) {
|
||||
backgroundImage.style.transition = 'opacity 0.4s ease-out';
|
||||
backgroundImage.style.opacity = '0.10';
|
||||
}
|
||||
|
||||
if (direction === 'right') {
|
||||
likeBadge.style.display = 'block';
|
||||
nopeBadge.style.display = 'none';
|
||||
likedCount++;
|
||||
updateStats();
|
||||
|
||||
// Smoothly animate card off screen
|
||||
card.style.transform = `translate(400px, 0) rotate(25deg)`;
|
||||
card.style.opacity = '0';
|
||||
|
||||
// Show match popup after card animation, then auto-continue
|
||||
setTimeout(() => {
|
||||
showMatchPopup();
|
||||
// Auto-hide and continue after 2 seconds
|
||||
setTimeout(() => {
|
||||
hideMatchPopup();
|
||||
nextBrick();
|
||||
}, 2000);
|
||||
}, 400);
|
||||
} else {
|
||||
nopeBadge.style.display = 'block';
|
||||
likeBadge.style.display = 'none';
|
||||
|
||||
// Smoothly animate card off screen
|
||||
card.style.transform = `translate(-400px, 0) rotate(-25deg)`;
|
||||
card.style.opacity = '0';
|
||||
|
||||
// Load next brick after animation completes
|
||||
setTimeout(() => {
|
||||
nextBrick();
|
||||
}, 400);
|
||||
}
|
||||
}
|
||||
|
||||
function showMatchPopup() {
|
||||
if (matchPopup) {
|
||||
// Set the right profile image to the current brick
|
||||
const rightProfileImg = document.getElementById('rightProfileImg');
|
||||
if (rightProfileImg && currentIndex < bricks.length) {
|
||||
rightProfileImg.src = bricks[currentIndex].image;
|
||||
}
|
||||
matchPopup.classList.add('show');
|
||||
}
|
||||
}
|
||||
|
||||
function hideMatchPopup() {
|
||||
if (matchPopup) {
|
||||
matchPopup.classList.remove('show');
|
||||
}
|
||||
}
|
||||
|
||||
function nextBrick() {
|
||||
currentIndex++;
|
||||
loadBrick(currentIndex);
|
||||
}
|
||||
|
||||
function showEndScreen() {
|
||||
endScreen.classList.add('show');
|
||||
finalLikedCount.textContent = likedCount;
|
||||
}
|
||||
|
||||
function restart() {
|
||||
currentIndex = 0;
|
||||
likedCount = 0;
|
||||
endScreen.classList.remove('show');
|
||||
loadBrick(0);
|
||||
}
|
||||
|
||||
// Touch/Mouse events for swiping
|
||||
card.addEventListener('mousedown', startDrag);
|
||||
card.addEventListener('touchstart', startDrag);
|
||||
|
||||
card.addEventListener('mousemove', drag);
|
||||
card.addEventListener('touchmove', drag);
|
||||
|
||||
card.addEventListener('mouseup', endDrag);
|
||||
card.addEventListener('touchend', endDrag);
|
||||
card.addEventListener('mouseleave', endDrag);
|
||||
|
||||
function startDrag(e) {
|
||||
isDragging = true;
|
||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
|
||||
startX = clientX - card.offsetLeft;
|
||||
startY = clientY - card.offsetTop;
|
||||
card.style.transition = 'none';
|
||||
}
|
||||
|
||||
function drag(e) {
|
||||
if (!isDragging) return;
|
||||
e.preventDefault();
|
||||
|
||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
|
||||
currentX = clientX - startX;
|
||||
currentY = clientY - startY;
|
||||
|
||||
const rotate = currentX / 20;
|
||||
card.style.transform = `translate(${currentX}px, ${currentY}px) rotate(${rotate}deg)`;
|
||||
|
||||
const overlay = card.querySelector('.card-overlay');
|
||||
if (Math.abs(currentX) > 50) {
|
||||
overlay.classList.add('active');
|
||||
if (currentX > 0) {
|
||||
overlay.querySelector('.like-badge').style.display = 'block';
|
||||
overlay.querySelector('.nope-badge').style.display = 'none';
|
||||
} else {
|
||||
overlay.querySelector('.nope-badge').style.display = 'block';
|
||||
overlay.querySelector('.like-badge').style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
overlay.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
function endDrag() {
|
||||
if (!isDragging) return;
|
||||
isDragging = false;
|
||||
card.style.transition = 'transform 0.4s ease-out, opacity 0.4s ease-out';
|
||||
|
||||
if (Math.abs(currentX) > 100) {
|
||||
if (currentX > 0) {
|
||||
swipeCard('right');
|
||||
} else {
|
||||
swipeCard('left');
|
||||
}
|
||||
} else {
|
||||
card.style.transform = 'translate(0, 0) rotate(0deg)';
|
||||
card.style.opacity = '1';
|
||||
card.querySelector('.card-overlay').classList.remove('active');
|
||||
}
|
||||
|
||||
currentX = 0;
|
||||
currentY = 0;
|
||||
}
|
||||
|
||||
// Button events
|
||||
likeBtn.addEventListener('click', () => swipeCard('right'));
|
||||
nopeBtn.addEventListener('click', () => swipeCard('left'));
|
||||
restartBtn.addEventListener('click', restart);
|
||||
|
||||
// Initialize
|
||||
loadBrick(0);
|
||||
Reference in New Issue
Block a user