BOU_2026 / index.html
Ansaribinhyder's picture
Upload 2 files
66dca15 verified
Raw History Blame Contribute Delete
4.76 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Best Project – BOU 2026</title>
<style>
:root{
--bg:#f4f5f7; --card:#ffffff; --text:#1b1e24; --muted:#636a76;
--accent:#2f5ed1; --accent-bg:#e9efff; --border:#dfe2e8; --error:#c2302c;
}
@media (prefers-color-scheme: dark){
:root{
--bg:#14161b; --card:#1d2027; --text:#eef0f3; --muted:#9aa1ad;
--accent:#6e94f2; --accent-bg:#232a3d; --border:#2b2f38; --error:#ff8a84;
}
}
*{box-sizing:border-box;}
body{
margin:0; background:var(--bg); color:var(--text);
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
}
.wrap{max-width:560px; margin:0 auto; padding:32px 18px 70px;}
h1{font-size:1.4rem; margin:0 0 2px;}
.sub{color:var(--muted); font-size:.9rem; margin:0 0 24px;}
section{margin-bottom:24px;}
label{display:block; font-size:.85rem; font-weight:600; margin-bottom:6px;}
input{
width:100%; padding:10px 12px; border-radius:10px; border:1px solid var(--border);
background:var(--card); color:var(--text); font-size:.95rem; margin-bottom:14px;
}
input:focus{outline:2px solid var(--accent); outline-offset:1px;}
.card{
background:var(--card); border:1px solid var(--border); border-radius:14px;
padding:14px 16px; margin-bottom:10px; cursor:pointer;
}
.card:hover{border-color:var(--accent);}
.card.selected{border-color:var(--accent); background:var(--accent-bg);}
.proj{font-weight:600; font-size:1rem;}
.presenter{color:var(--muted); font-size:.85rem; margin-top:2px;}
button{
width:100%; padding:13px; border:none; border-radius:10px; background:var(--accent);
color:#fff; font-size:1rem; font-weight:600; cursor:pointer;
}
button:disabled{opacity:.5; cursor:not-allowed;}
.msg{font-size:.88rem; margin-top:12px; min-height:1.2em;}
.msg.error{color:var(--error);}
.msg.ok{color:#1f9254;}
</style>
</head>
<body>
<div class="wrap">
<h1>Best Project — BOU 2026</h1>
<p class="sub">Enter your details, pick a project, then submit your vote.</p>
<section>
<label for="name">Name</label>
<input id="name" type="text" autocomplete="name" placeholder="Your full name">
<label for="uid">UID / Employee ID</label>
<input id="uid" type="text" autocomplete="off" placeholder="e.g. E123456">
<label for="email">Email</label>
<input id="email" type="email" autocomplete="email" placeholder="you@company.com">
</section>
<section id="projectList"></section>
<button id="submitBtn" disabled>Submit vote</button>
<div class="msg" id="msg"></div>
</div>
<script>
const nameEl = document.getElementById("name");
const uidEl = document.getElementById("uid");
const emailEl = document.getElementById("email");
const listEl = document.getElementById("projectList");
const btn = document.getElementById("submitBtn");
const msgEl = document.getElementById("msg");
let projects = [];
let selected = null;
function setMsg(text, kind){
msgEl.textContent = text || "";
msgEl.className = "msg" + (kind ? " " + kind : "");
}
function renderProjects(){
listEl.innerHTML = "";
projects.forEach(p => {
const div = document.createElement("div");
div.className = "card" + (selected === p.id ? " selected" : "");
div.innerHTML = `<div class="proj">${p.name}</div><div class="presenter">${p.who}</div>`;
div.addEventListener("click", () => { selected = p.id; renderProjects(); updateButton(); });
listEl.appendChild(div);
});
}
function updateButton(){
const valid = nameEl.value.trim() && uidEl.value.trim() &&
/^\S+@\S+\.\S+$/.test(emailEl.value.trim()) && selected;
btn.disabled = !valid;
}
[nameEl, uidEl, emailEl].forEach(el => el.addEventListener("input", updateButton));
fetch("/api/projects")
.then(r => r.json())
.then(data => { projects = data; renderProjects(); })
.catch(() => setMsg("Couldn't load the project list. Refresh the page.", "error"));
btn.addEventListener("click", async () => {
btn.disabled = true;
setMsg("Submitting…");
try{
const res = await fetch("/api/vote", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: nameEl.value.trim(),
uid: uidEl.value.trim(),
email: emailEl.value.trim(),
projectId: selected,
}),
});
const data = await res.json();
if (data.ok){
setMsg("Your vote has been recorded. Thank you!", "ok");
} else {
setMsg(data.error || "Something went wrong.", "error");
btn.disabled = false;
}
} catch (e){
setMsg("Network error — please try again.", "error");
btn.disabled = false;
}
});
</script>
</body>
</html>