<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app-container">
<h1>Chọn đại diện nhóm ngẫu nhiên ????</h1>
<p>Nhập tên các thành viên, mỗi tên một dòng:</p>
<textarea id="team-members"></textarea>
<button id="select-button">Chọn Ngẫu nhiên</button>
<div id="roll-display">
<div id="rolling-list"></div>
</div>
<div id="result">
<p id="result-text">Người được chọn sẽ hiện ở đây!</p>
<div id="winner-name"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
#app-container {
background-color: #ffffff;
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
width: 90%;
max-width: 500px;
}
textarea {
width: 100%;
height: 150px;
padding: 10px;
margin-bottom: 20px;
border: 2px solid #ccc;
border-radius: 8px;
resize: vertical;
font-size: 16px;
box-sizing: border-box; /* Quan trọng để padding không làm tăng chiều rộng */
}
button {
background-color: #007bff;
color: white;
padding: 12px 25px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 18px;
font-weight: bold;
transition: background-color 0.3s ease, transform 0.1s;
width: 100%;
}
button:hover {
background-color: #0056b3;
}
button:active {
transform: scale(0.98);
}
#result {
margin-top: 25px;
text-align: center;
min-height: 50px; /* Đảm bảo chiều cao không bị nhảy */
}
#result p {
font-size: 20px;
color: #555;
font-weight: 500;
}
#winner-name {
font-size: 36px;
color: #28a745;
font-weight: bold;
margin-top: 10px;
/* Hiệu ứng ban đầu */
opacity: 0;
transform: scale(0.5);
transition: opacity 0.5s ease, transform 0.5s ease;
}
/* Hiệu ứng khi tên người chiến thắng hiện ra */
.show-winner {
opacity: 1 !important;
transform: scale(1) !important;
animation: pulse 1s infinite alternate; /* Hiệu ứng nhấp nháy nhẹ */
}
/* Khung hiển thị hiệu ứng "cuộn" */
#roll-display {
display: none; /* Ban đầu ẩn */
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 20px;
height: 100px; /* Chiều cao cố định */
overflow: hidden;
border: 2px solid #007bff;
border-radius: 8px;
background-color: #e9f5ff;
font-size: 24px;
font-weight: bold;
color: #333;
width: 100%;
position: relative;
}
/* Hiệu ứng cuộn sử dụng TranslateY */
#rolling-list {
position: absolute;
top: 0;
left: 0;
width: 100%;
text-align: center;
}
.rolling {
animation: roll-animation 3s forwards cubic-bezier(0.25, 0.1, 0.25, 1);
}
@keyframes roll-animation {
0% { transform: translateY(0); opacity: 1; }
50% { opacity: 1; }
90% { opacity: 0.5; }
100% { transform: translateY(var(--final-y)); opacity: 0; }
}
/* Hiệu ứng nhấp nháy nhẹ cho tên người chiến thắng */
@keyframes pulse {
from {
box-shadow: 0 0 5px #28a745, 0 0 10px #28a745;
}
to {
box-shadow: none;
}
}
const textarea = document.getElementById('team-members');
const selectButton = document.getElementById('select-button');
const resultText = document.getElementById('result-text');
const winnerNameDiv = document.getElementById('winner-name');
const rollDisplay = document.getElementById('roll-display');
const rollingListDiv = document.getElementById('rolling-list');
let isSelecting = false; // Trạng thái để ngăn chặn nhấn liên tục
selectButton.addEventListener('click', selectRandomMember);
function selectRandomMember() {
if (isSelecting) return;
// 1. Lấy danh sách tên
const names = textarea.value
.split('\n')
.map(name => name.trim())
.filter(name => name.length > 0);
if (names.length === 0) {
alert('Vui lòng nhập tên các thành viên!');
return;
}
isSelecting = true;
selectButton.disabled = true;
resultText.textContent = 'Đang chọn...';
winnerNameDiv.textContent = '';
winnerNameDiv.classList.remove('show-winner');
rollDisplay.style.display = 'flex'; // Hiện khung cuộn
// 2. Tạo danh sách cuộn tạm thời
rollingListDiv.innerHTML = '';
// Lặp lại danh sách vài lần để tạo hiệu ứng cuộn dài
const rollCount = 15;
for (let i = 0; i < rollCount; i++) {
names.forEach(name => {
const item = document.createElement('div');
item.textContent = name;
item.style.padding = '5px 0';
rollingListDiv.appendChild(item);
});
}
// 3. Chọn ngẫu nhiên người chiến thắng
const randomIndex = Math.floor(Math.random() * names.length);
const winner = names[randomIndex];
// 4. Tính toán vị trí dừng của hiệu ứng cuộn (ở đầu danh sách lặp thứ 4)
// Ta muốn dừng ở tên người chiến thắng
// Vị trí của người chiến thắng trong *một lần* lặp danh sách
const winnerIndexInList = names.indexOf(winner);
// Giả sử mỗi item cao khoảng 34px (padding 5px + font-size 24px) - Cần điều chỉnh nếu CSS thay đổi
const itemHeight = 34;
const fullListHeight = names.length * itemHeight;
// Vị trí cuộn để tên chiến thắng nằm ngay dưới điểm cuộn ban đầu.
// Ta chọn một vòng lặp bất kỳ (ví dụ: vòng lặp thứ 4) để kết thúc
const stopLoop = Math.floor(rollCount / 2); // Dừng ở giữa danh sách lặp
// Vị trí Y cuối cùng (âm vì cuộn lên)
const finalY = -(fullListHeight * stopLoop + winnerIndexInList * itemHeight);
// 5. Bắt đầu hiệu ứng cuộn
rollingListDiv.style.setProperty('--final-y', `${finalY}px`);
rollingListDiv.classList.add('rolling');
// 6. Kết thúc hiệu ứng và hiển thị kết quả sau 3.5 giây (lớn hơn thời gian animation)
setTimeout(() => {
rollingListDiv.classList.remove('rolling');
rollDisplay.style.display = 'none'; // Ẩn khung cuộn
resultText.textContent = 'Người đại diện nhóm là:';
winnerNameDiv.textContent = winner;
winnerNameDiv.classList.add('show-winner'); // Hiện tên người chiến thắng
isSelecting = false;
selectButton.disabled = false;
}, 3500); // 3.5 giây cho hiệu ứng hồi hộp
}
// Tải code mẫu khi ứng dụng được mở
window.onload = function() {
// Đã có dữ liệu mẫu trong textarea
};