templates/website/page/indexes/test-sat-selection.html.twig line 1
<!-- FILE: /sat/test-selection.html --><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Select a SAT Test - Vrshikyans</title><link rel="icon" href="/students/Vrshikyan_logo.ico" /><style>:root {--bg: #0f1320;--bg-2: #101626;--surface: rgba(255, 255, 255, 0.06);--surface-strong: rgba(255, 255, 255, 0.10);--border: rgba(255, 255, 255, 0.18);--text: #eef3ff;--muted: #b8c2e6;--accent: #74a3ff;--accent-2: #66e6d2;--green: #35d49f;--amber: #ffd166;--red: #ff6b7c;--radius-sm: 10px;--radius-md: 14px;--radius-lg: 18px;--shadow-1: 0 6px 20px rgba(0, 0, 0, .25);--shadow-2: 0 14px 40px rgba(0, 0, 0, .35);--blur: 14px;--speed-fast: .15s;--speed: .25s;--font: system-ui, -apple-system, Segoe UI, Roboto, Inter, "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji";}@media (prefers-color-scheme: light) {:root {--bg: #f7f8fd;--bg-2: #eef1fb;--surface: rgba(255, 255, 255, .65);--surface-strong: rgba(255, 255, 255, .9);--border: rgba(23, 32, 58, .10);--text: #0f1428;--muted: #475070;--shadow-1: 0 8px 18px rgba(23, 32, 58, .08);--shadow-2: 0 18px 40px rgba(23, 32, 58, .12);}}* {box-sizing: border-box;}html,body {margin: 0;padding: 0;min-height: 100%;color: var(--text);font-family: var(--font);background: radial-gradient(1000px 1000px at 10% -10%, #1a2240, transparent 60%), radial-gradient(1400px 800px at 100% 10%, #18244a, transparent 40%), linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);background-attachment: fixed;}body::before {content: "";position: fixed;inset: 0;background-image:radial-gradient(2px 2px at 10% 20%, rgba(255, 255, 255, .14) 50%, transparent 51%),radial-gradient(2px 2px at 70% 30%, rgba(255, 255, 255, .09) 50%, transparent 51%),radial-gradient(2px 2px at 30% 80%, rgba(255, 255, 255, .07) 50%, transparent 51%),radial-gradient(2px 2px at 80% 60%, rgba(255, 255, 255, .10) 50%, transparent 51%);pointer-events: none;opacity: .35;z-index: 0;}.topp {margin: auto;/* border: 2px solid whitesmoke; */backdrop-filter: blur(8px);-webkit-backdrop-filter: blur(9px);width: min(1200px, 94%);height: 10vh;border-bottom-left-radius: 15px;border-bottom-right-radius: 15px;}.topp button {min-width: 35%;background: linear-gradient(180deg, #35d49f, #18b98a);color: #041b12;box-shadow: 0 10px 20px rgba(24, 185, 138, .18), inset 0 1px 0 rgba(255, 255, 255, .5);height: 46px;min-width: 160px;padding: 0 18px;border: 0;border-radius: 14px;font-weight: 900;letter-spacing: .2px;cursor: pointer;transition: transform var(--speed-fast), box-shadow var(--speed)}.topp button:hover {transform: translateY(-1px)}.shell {width: min(1200px, 94%);margin: 32px auto 80px;position: relative;z-index: 1;}.header {background: var(--surface);border: 1px solid var(--border);border-radius: var(--radius-lg);padding: 16px;box-shadow: var(--shadow-2);backdrop-filter: blur(var(--blur));display: grid;grid-template-columns: 1fr auto;gap: 12px;align-items: center;}.header h2 {margin: 0;font-size: 28px;letter-spacing: .2px;}.tools {display: flex;gap: 10px;align-items: center;}.search {position: relative;}.search input {width: 220px;height: 40px;padding: 0 12px;border-radius: 12px;border: 1px solid var(--border);background: var(--surface-strong);color: var(--text);outline: none;transition: box-shadow var(--speed), transform var(--speed-fast);}.search input::placeholder {color: rgba(255, 255, 255, .55);}.search input:focus {box-shadow: 0 0 0 3px rgba(116, 163, 255, .25);transform: translateY(-1px);}.filter {height: 40px;border-radius: 12px;border: 1px solid var(--border);background: var(--surface-strong);color: var(--text);padding: 0 12px;color: gray;outline: none;}#testList {display: grid;grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));gap: 14px;margin-top: 16px;background: var(--surface);border: 1px solid var(--border);border-radius: var(--radius-lg);padding: 16px;box-shadow: var(--shadow-2);backdrop-filter: blur(var(--blur));}.testButton {height: 120px;border: 1px solid var(--border);border-radius: 16px;background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, .02));color: var(--text);font-weight: 900;font-size: 22px;letter-spacing: .3px;display: flex;align-items: center;justify-content: center;cursor: pointer;position: relative;overflow: hidden;transition: transform var(--speed-fast), box-shadow var(--speed), border-color var(--speed), background var(--speed);box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255, 255, 255, .06);user-select: none;animation: popIn .35s ease forwards;opacity: 0;transform: translateY(4px) scale(.98);}.testButton::before {content: "";position: absolute;inset: 0;background: radial-gradient(600px 300px at -10% -10%, rgba(116, 163, 255, .15), transparent 60%);opacity: .4;pointer-events: none;}.testButton:hover {transform: translateY(-2px) scale(1.02);box-shadow: 0 16px 36px rgba(0, 0, 0, .30), inset 0 1px 0 rgba(255, 255, 255, .08);border-color: rgba(116, 163, 255, .55);background: linear-gradient(180deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, .04));}@keyframes popIn {to {opacity: 1;transform: translateY(0) scale(1);}}.ribbon {position: absolute;top: 10px;right: -38px;width: 140px;text-align: center;transform: rotate(35deg);font-size: 11px;font-weight: 900;letter-spacing: .3px;color: #071b14;padding: 4px 0;box-shadow: 0 4px 14px rgba(0, 0, 0, .20);border: 1px solid rgba(0, 0, 0, .1);}.ribbon.done {background: linear-gradient(180deg, #35d49f, #18b98a);}.ribbon.part {background: linear-gradient(180deg, #ffd166, #ffbf55);}.ribbon.none {background: linear-gradient(180deg, #ff9aa8, #ff6b7c);}.testButton.completed {box-shadow: 0 12px 26px rgba(53, 212, 159, .20), inset 0 1px 0 rgba(255, 255, 255, .08);border-color: rgba(53, 212, 159, .45);}.testButton.partial {box-shadow: 0 12px 26px rgba(255, 209, 102, .20), inset 0 1px 0 rgba(255, 255, 255, .08);border-color: rgba(255, 209, 102, .45);}.testButton.not-started {box-shadow: 0 12px 26px rgba(255, 107, 124, .20), inset 0 1px 0 rgba(255, 255, 255, .08);border-color: rgba(255, 107, 124, .45);}.legend {display: flex;gap: 10px;align-items: center;margin-top: 10px;color: var(--muted);font-size: 13px;}.dot {width: 10px;height: 10px;border-radius: 50%;display: inline-block;margin-right: 6px;}.dot.done {background: var(--green);}.dot.part {background: var(--amber);}.dot.none {background: var(--red);}.testButton[title] {position: relative;}.testButton[title]:hover::after {content: attr(title);position: absolute;bottom: -34px;left: 50%;transform: translateX(-50%);background: rgba(0, 0, 0, .75);color: #fff;padding: 6px 10px;border-radius: 8px;font-size: 12px;white-space: nowrap;pointer-events: none;}#go{height:40px;width:20%;text-align:center; padding:0 18px;border:0;border-radius:14px;font-weight:900;letter-spacing:.2px;cursor:pointer;transition:transform var(--speed-fast), box-shadow var(--speed), filter var(--speed); background:linear-gradient(180deg, rgb(244, 228, 228), rgb(98, 91, 91));color:#041b12;box-shadow:0 10px 24px rgba(24,185,138,.22), inset 0 1px 0 rgba(255,255,255,.5)}#go:hover{transform: translateY(-5px);}@media (max-width: 640px) {.header {grid-template-columns: 1fr;}.tools {justify-content: stretch;}.search input {width: 100%;}}</style><link rel="stylesheet" href="{{ asset('css/navbar.css') }}" /><script>(() => {const saved = localStorage.getItem('theme');if (saved) {document.documentElement.setAttribute('data-theme', saved);} else {document.documentElement.setAttribute('data-theme',matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');}})();</script></head><body><nav class="nav" role="navigation" aria-label="Primary"><div class="nav-inner"><a class="brand" href="/" aria-label="Exam-hub"><span class="logo" aria-hidden="true" style="overflow: hidden;"><img src="../students/Vrshikyan_logo.ico" width="39px" alt="Vrshikyans logo"></span><span>Vrshikyans</span> </a><div class="nav-links"><a class="nav-link" data-section="toefl" href="./test-selection?type=toefl" id="toeflNav">TOEFL</a><a class="nav-link" data-section="sat" href="./test-sat-selection#sat" id="satNav">SAT</a><a class="nav-link" data-section="act" href="./test-sat-selection#act"id="actNav">ACT</a><a class="nav-link" data-section="reading" href="./test-selection?type=readingPractice" id="readingPrNav">Reading Practice</a><a class="nav-link" data-section="support" href="./support">Support</a><a class="nav-link" data-section="reviews" href="./reviews">Reviews</a></div><button class="mobile-menu-btn" id="mobileMenuBtn">☰</button><div class="spacer"></div><button id="themeToggle" class="theme-btn" aria-label="Toggle theme">🌑</button><a class="cta" id="startTop" href="../indexes/account" aria-label="Account"style="width: 40px; height: 40px; background: whitesmoke;">👤</a></div></nav><div class="mobile-menu" id="mobileMenu"><div class="mobile-nav-links"><a class="mobile-nav-link" href="./test-selection?type=toefl">TOEFL</a><a class="mobile-nav-link" href="./test-sat-selection#sat">SAT</a><a class="mobile-nav-link" href="./test-sat-selection#act">ACT</a><a class="mobile-nav-link" href="./test-selection?type=readingPractice">Reading Practice</a><a class="mobile-nav-link" href="./support">Support</a><a class="mobile-nav-link" href="./reviews">Reviews</a></div></div><div class="shell"><div class="header"><h2 id="pageTitle">Select a SAT Test</h2><div class="tools"><!-- SAT/ACT selector --><select id="examPicker" class="filter" title="Choose exam"><option value="sat" selected>SAT</option><option value="act">ACT</option></select><div class="search"><input id="quickFind" type="number" min="1" placeholder="Go to test #" /></div><button id="go">Go</button><select id="statusFilter" class="filter" title="Filter by status"><option value="all">All</option><option value="completed">Completed</option><option value="partial">In progress</option><option value="not-started">Not started</option></select></div></div><div class="legend"><span><span class="dot done"></span>Completed</span><span><span class="dot part"></span>In progress</span><span><span class="dot none"></span>Not started</span></div><div id="testList"></div></div><script src="{{ asset('js/navbar.js') }}"></script><script>// === SAT/ACT Test Selection — SAME DESIGN, now hash-aware (#sat / #act) ===const testListEl = document.getElementById("testList");const quickFind = document.getElementById("quickFind");const statusFilter = document.getElementById("statusFilter");const examPicker = document.getElementById("examPicker");const pageTitle = document.getElementById("pageTitle");// You can change counts as neededconst TOTAL_SAT_TESTS = 52;const TOTAL_ACT_TESTS = 31;// SAT: math-only tests (keep your list)const MATH_ONLY_TESTS = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,45, 46, 47, 48, 49, 50, 51, 52]);function sectionsForSAT(id) {return MATH_ONLY_TESTS.has(id) ? ['math'] : ['english', 'math'];}function getSATStatusForTest(id) {const required = sectionsForSAT(id);let doneCount = 0;for (const sec of required) {const key = `result_sat_${id}_${sec}`;const val = localStorage.getItem(key);if (val !== null && String(val).trim() !== "") doneCount++;}if (doneCount === 0) return "not-started";if (doneCount === required.length) return "completed";return "partial";}// ACT: single-section (Math) statusfunction getACTStatusForTest(id) {const key = `result_act_${id}_math`;const val = localStorage.getItem(key);if (val && String(val).trim() !== "") return "completed";return "not-started";}function ribbonFor(status) {if (status === "completed") return '<span class="ribbon done">COMPLETED</span>';if (status === "partial") return '<span class="ribbon part">IN PROGRESS</span>';return '<span class="ribbon none">NOT STARTED</span>';}function titleFor(status, exam) {if (exam === 'sat') {if (status === "completed") return "All required sections recorded for this SAT test";if (status === "partial") return "Some required sections recorded";return "No sections done yet";} else {if (status === "completed") return "ACT Math completed";return "Not started";}}function selectedExam() {return (examPicker?.value || "sat").toLowerCase();}// 🔹 Sync URL hash with exam (#sat / #act)function syncHashWithExam(exam) {const desiredHash = '#' + exam;if (window.location.hash !== desiredHash) {const base = window.location.pathname + window.location.search;history.replaceState(null, '', base + desiredHash);}}function updateActiveNav() {const satNav = document.getElementById('satNav');const actNav = document.getElementById('actNav');satNav.classList.toggle('active', examPicker.value === 'sat');actNav.classList.toggle('active', examPicker.value === 'act');}// 🔹 Initial exam: from hash -> session -> SAT(function initExamFromHash() {const hashExamRaw = (window.location.hash || '').replace('#','').toLowerCase();let initialExam = hashExamRaw || (sessionStorage.getItem('EXAM_SELECTION') || 'sat');if (!['sat','act'].includes(initialExam)) initialExam = 'sat';if (examPicker) examPicker.value = initialExam;sessionStorage.setItem('EXAM_SELECTION', initialExam);syncHashWithExam(initialExam);})();function applyExam(exam) {if (!['sat', 'act'].includes(exam)) exam = 'sat';examPicker.value = exam;sessionStorage.setItem('EXAM_SELECTION', exam);syncHashWithExam(exam);updateActiveNav();renderGrid();}// 🔹 Initial exam: from hash -> session -> SAT(function initExamFromHash() {const hashExamRaw = (window.location.hash || '').replace('#','').toLowerCase();let initialExam = hashExamRaw || (sessionStorage.getItem('EXAM_SELECTION') || 'sat');applyExam(initialExam);})();// 🔹 If user navigates between #sat and #act without reloadwindow.addEventListener('hashchange', () => {const hashExam = (window.location.hash || '').replace('#','').toLowerCase();applyExam(hashExam || 'sat');});function renderGrid() {const exam = selectedExam();const total = exam === "sat" ? TOTAL_SAT_TESTS : TOTAL_ACT_TESTS;pageTitle.textContent = exam === "sat" ? "Select a SAT Test" : "Select an ACT Test";testListEl.innerHTML = "";for (let i = 1; i <= total; i++) {const status = (exam === "sat") ? getSATStatusForTest(i) : getACTStatusForTest(i);if (statusFilter.value !== "all" && statusFilter.value !== status) continue;const btn = document.createElement("button");btn.className = `testButton ${status}`;btn.title = titleFor(status, exam);btn.style.animationDelay = `${i * 8}ms`;btn.innerHTML = `${ribbonFor(status)}${exam.toUpperCase()} ${i}`;// ✅ Common section-selection page for BOTH SAT and ACT:btn.onclick = () => {const dest = `section-sat-selection?exam=${encodeURIComponent(exam)}&test=${i}`;if (exam === "sat") {sessionStorage.setItem("SAT_TEST_ID", String(i));} else {sessionStorage.setItem("ACT_TEST_ID", String(i));}window.location.href = dest;};testListEl.appendChild(btn);}}// Quick "Go" uses current exam + range and same section-selection pageconst go = document.getElementById("go");function find() {const exam = selectedExam();const total = exam === "sat" ? TOTAL_SAT_TESTS : TOTAL_ACT_TESTS;const n = parseInt(quickFind.value, 10);if (!Number.isNaN(n) && n >= 1 && n <= total) {if (exam === "sat") {sessionStorage.setItem("SAT_TEST_ID", String(n));} else {sessionStorage.setItem("ACT_TEST_ID", String(n));}window.location.href = `/indexes/section-sat-selection?exam=${encodeURIComponent(exam)}&test=${n}`;} else {quickFind.style.transition = "0.5s";quickFind.style.color = "red";setTimeout(() => quickFind.style.color = "white", 1600);}}quickFind.addEventListener("keydown", (e) => { if (e.key === "Enter") find(); });go.onclick = find;statusFilter.addEventListener("change", renderGrid);// When exam changes via picker → update hash + session + gridexamPicker.addEventListener("change", () => {applyExam(selectedExam());});// Initial render using exam already set from hash/sessionrenderGrid();document.addEventListener("contextmenu", (e) => e.preventDefault());</script></body></html>