Skip to content

Commit ae43fbd

Browse files
authored
Merge pull request #75 from BeJUG/raffle
Add the raffle feature on the BeJUG Website
2 parents 24ad3b2 + c8ad1e4 commit ae43fbd

2 files changed

Lines changed: 190 additions & 0 deletions

File tree

assets/duke-celebration.png

138 KB
Loading

assets/raffle.html

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>beJUG Raffle</title>
7+
<style>
8+
body {
9+
margin: 0;
10+
font-family: Arial, sans-serif;
11+
background-color: #121212;
12+
color: #ffffff;
13+
display: flex;
14+
flex-direction: column;
15+
align-items: center;
16+
padding: 2rem;
17+
}
18+
img {
19+
max-width: 200px;
20+
margin-bottom: 1rem;
21+
}
22+
input {
23+
width: 100%;
24+
max-width: 500px;
25+
padding: 0.5rem;
26+
margin-bottom: 1rem;
27+
background-color: #1e1e1e;
28+
color: #ffffff;
29+
border: 1px solid #333;
30+
}
31+
button {
32+
background-color: #ff4081;
33+
color: white;
34+
border: none;
35+
padding: 0.75rem 1.5rem;
36+
cursor: pointer;
37+
font-size: 1rem;
38+
border-radius: 5px;
39+
margin: 0.5rem;
40+
}
41+
button:hover {
42+
background-color: #e91e63;
43+
}
44+
button:disabled {
45+
background-color: #777;
46+
cursor: not-allowed;
47+
}
48+
#participantsList {
49+
display: flex;
50+
flex-wrap: wrap;
51+
gap: 0.5rem;
52+
max-width: 500px;
53+
width: 100%;
54+
margin-bottom: 1rem;
55+
}
56+
.tag {
57+
background-color: #333;
58+
padding: 0.4rem 0.75rem;
59+
border-radius: 20px;
60+
font-size: 0.9rem;
61+
display: flex;
62+
align-items: center;
63+
}
64+
.tag span {
65+
margin-left: 0.5rem;
66+
color: #ff4081;
67+
cursor: pointer;
68+
}
69+
.tag span:hover {
70+
color: #f44336;
71+
}
72+
#winner {
73+
margin-top: 1rem;
74+
font-size: 1.5rem;
75+
font-weight: bold;
76+
color: #4caf50;
77+
}
78+
#animation {
79+
font-size: 2rem;
80+
margin-top: 2rem;
81+
min-height: 2rem;
82+
color: #ffeb3b;
83+
font-weight: bold;
84+
}
85+
#winnerImage {
86+
margin-top: 2rem;
87+
display: none;
88+
min-width: 450px;
89+
}
90+
</style>
91+
</head>
92+
<body>
93+
<img src="logo.png" alt="BeJUG Logo" />
94+
<h1>BeJUG Raffle</h1>
95+
<input type="text" id="nameInput" placeholder="Type a name and press Enter" aria-label="Add participant name" />
96+
<div id="participantsList" role="list"></div>
97+
<div>
98+
<button id="drawButton" onclick="drawWinner()" disabled>Draw Winner</button>
99+
</div>
100+
<div id="animation"></div>
101+
<div id="winner"></div>
102+
<img id="winnerImage" src="duke-celebration.png" alt="Winner Celebration Image" />
103+
104+
<!-- Confetti library -->
105+
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.5.1/dist/confetti.browser.min.js"></script>
106+
107+
<script>
108+
const participants = [];
109+
110+
const nameInput = document.getElementById("nameInput");
111+
const participantsList = document.getElementById("participantsList");
112+
const drawButton = document.getElementById("drawButton");
113+
const winnerDiv = document.getElementById("winner");
114+
const animationDiv = document.getElementById("animation");
115+
const winnerImage = document.getElementById("winnerImage");
116+
117+
nameInput.addEventListener("keypress", function (e) {
118+
if (e.key === "Enter") {
119+
e.preventDefault();
120+
const name = e.target.value.trim();
121+
if (name && !participants.includes(name)) {
122+
participants.push(name);
123+
updateParticipantList();
124+
}
125+
e.target.value = "";
126+
}
127+
});
128+
129+
function updateParticipantList() {
130+
participantsList.innerHTML = "";
131+
132+
participants.forEach(name => {
133+
const tag = document.createElement("div");
134+
tag.className = "tag";
135+
tag.setAttribute("role", "listitem");
136+
tag.textContent = name;
137+
138+
const x = document.createElement("span");
139+
x.textContent = "×";
140+
x.setAttribute("title", "Remove " + name);
141+
x.addEventListener("click", () => {
142+
const index = participants.indexOf(name);
143+
if (index > -1) {
144+
participants.splice(index, 1);
145+
updateParticipantList();
146+
}
147+
});
148+
149+
tag.appendChild(x);
150+
participantsList.appendChild(tag);
151+
});
152+
153+
drawButton.disabled = participants.length === 0;
154+
}
155+
156+
function getRandomParticipant() {
157+
return participants[Math.floor(Math.random() * participants.length)];
158+
}
159+
160+
function drawWinner() {
161+
if (participants.length === 0) return;
162+
163+
winnerDiv.textContent = "";
164+
animationDiv.textContent = "Spinning...";
165+
winnerImage.style.display = "none";
166+
167+
let i = 0;
168+
const spinCount = 20;
169+
170+
const interval = setInterval(() => {
171+
animationDiv.textContent = getRandomParticipant();
172+
i++;
173+
if (i >= spinCount) {
174+
clearInterval(interval);
175+
const winner = getRandomParticipant();
176+
animationDiv.textContent = "";
177+
winnerDiv.textContent = `🎉 Winner: ${winner} 🎉`;
178+
winnerImage.style.display = "block";
179+
180+
confetti({
181+
particleCount: 150,
182+
spread: 100,
183+
origin: { y: 0.6 }
184+
});
185+
}
186+
}, 100);
187+
}
188+
</script>
189+
</body>
190+
</html>

0 commit comments

Comments
 (0)