templates/website/parts/footer.html.twig line 1

  1. <footer>
  2.     <div class="foot">
  3.         <div>
  4.             <b>Contact</b>
  5.             <p class="lead" style="margin:.4rem 0 0 0">vrshikyanstests@gmail.com</p>
  6.             <p class="lead" style="margin:.2rem 0 0 0">made by artyom19032008@gmail.com</p>
  7.             <a href="{{ path('page_privacy_policy') }}" class="lead" style="margin:.2rem 0 0 0">Privacy policy</a>
  8.         </div>
  9.         <div>
  10.             <b>Vrshikyans</b>
  11.             <p class="lead" style="margin:.4rem 0 0 0">Yerevan • Since 2025</p>
  12.             <small>© <span id="year"></span> Vrshikyans — All rights reserved.</small>
  13.             <a href="{{ path('page_return') }}" class="lead" style="margin:.2rem 0 0 0">Return policy</a>
  14.         </div>
  15.     </div>
  16. </footer>
  17. {% if '/order/' not in app.request.pathInfo %}
  18.     <script>
  19.         // DATA: students as objects (edit this to add/remove students)
  20.         const STUDENT_CARDS = [
  21.             {
  22.                 name: 'Artyom H.',
  23.                 photo: 'students/Tyom.jpg',
  24.                 alt: 'Ani, Vrshikyans student with a high TOEFL score',
  25.                 score: 'SAT math 800/800',
  26.                 tests: 'SAT(Verbal --, Math 800)',
  27.                 blurb: 'Started with basic knoweledge in math and weak English, and after a year reached excellent scores in both SAT and TOEFL'
  28.             },
  29.             {
  30.                 name: 'Arman V.',
  31.                 photo: 'students/student_arman.jpg',
  32.                 alt: 'Arman, SAT and TOEFL student at Vrshikyans',
  33.                 score: 'SAT — 1520 / 1600',
  34.                 tests: 'Math 790 • R&W 730',
  35.                 blurb: 'Balances school, olympiads and prep. Uses the SAT & TOEFL tests here to simulate real exam mornings and track every improvement.'
  36.             },
  37.             {
  38.                 name: 'Maria K.',
  39.                 photo: 'students/student_maria.jpg',
  40.                 alt: 'Maria, IELTS student',
  41.                 score: 'IELTS Academic — 8.0',
  42.                 tests: 'L 8.5 • R 8.0 • W 7.5 • S 8.0',
  43.                 blurb: 'Practises reading and listening on the platform, then refines writing and speaking with targeted feedback from Ms Hasmik.'
  44.             },
  45.             {
  46.                 name: 'Davit S.',
  47.                 photo: 'students/student_davit.jpg',
  48.                 alt: 'Davit, ACT student',
  49.                 score: 'ACT — 33 / 36',
  50.                 tests: 'English • Reading • Science',
  51.                 blurb: 'Uses the calm exam-style layout to practise full ACT sets without distractions, focusing on timing and accuracy in Reading and Science.'
  52.             },
  53.             {
  54.                 name: 'Lilit M.',
  55.                 photo: 'students/student_lilit.jpg',
  56.                 alt: 'Lilit, TOEFL 2026 student',
  57.                 score: 'TOEFL 2026 — 27 Reading • 26 Listening',
  58.                 tests: 'Working towards 110+',
  59.                 blurb: 'Takes TOEFL 2026-style tests here every Sunday morning. Loves the smooth reading timer and automatic results page.'
  60.             },
  61.             {
  62.                 name: 'Narek A.',
  63.                 photo: 'students/student_narek.jpg',
  64.                 alt: 'Narek, future CS student',
  65.                 score: 'TOEFL — 108 / 120',
  66.                 tests: 'Planning for CS abroad',
  67.                 blurb: 'Uses the platform to practise reading long scientific passages and listening to lectures without pausing — just like on test day.'
  68.             }
  69.         ];
  70.         function renderStudentCards() {
  71.             const container = document.getElementById('studentCards');
  72.             if (!container) return;
  73.             container.innerHTML = STUDENT_CARDS.map(s => `
  74.                 <article class="student-card">
  75.                     <div class="avatar">
  76.                         <img src="${s.photo}" alt="${s.alt}"
  77.                              onerror="this.remove();this.parentElement.textContent='${s.name.split(' ')[0]}';">
  78.                     </div>
  79.                     <div class="meta">
  80.                         <h3 class="name">${s.name}</h3>
  81.                         <p class="score">${s.score}</p>
  82.                         ${s.tests ? `<p class="test-type">${s.tests}</p>` : ''}
  83.                         <p class="desc">${s.blurb}</p>
  84.                     </div>
  85.                 </article>
  86.             `).join('');
  87.         }
  88.         // Theme toggle
  89.         let isSwitching = false;
  90.         const validSections = ['home', 'mentors', 'students', 'value', 'exams', 'pricing'];
  91.         const themeBtn = document.getElementById('themeToggle');
  92.         const htmlEl = document.documentElement;
  93.         function setTheme(next) {
  94.             htmlEl.setAttribute('data-theme', next);
  95.             localStorage.setItem('theme', next);
  96.             themeBtn.textContent = next === 'light' ? '🌕' : '🌑';
  97.             themeBtn.setAttribute('aria-label', next === 'light' ? 'Switch to dark theme' : 'Switch to light theme');
  98.         }
  99.         themeBtn.addEventListener('click', () => setTheme(htmlEl.getAttribute('data-theme') === 'light' ? 'dark' : 'light'));
  100.         setTheme(htmlEl.getAttribute('data-theme') || 'dark');
  101.         // Section navigation
  102.         const navLinks = document.querySelectorAll('.nav-link, .mobile-nav-link');
  103.         const mobileMenu = document.getElementById('mobileMenu');
  104.         const mobileMenuBtn = document.getElementById('mobileMenuBtn');
  105.         function showSection(sectionId) {
  106.             if (!validSections.includes(sectionId) || isSwitching) return;
  107.             const newSection = document.getElementById(`${sectionId}-section`);
  108.             const oldSection = document.querySelector('.page-section.active');
  109.             if (!newSection || newSection === oldSection) return;
  110.             isSwitching = true;
  111.             document.body.classList.add('switching');
  112.             window.scrollTo({ top: 0, behavior: 'auto' });
  113.             if (oldSection) {
  114.                 oldSection.classList.remove('active');
  115.                 oldSection.classList.add('leaving');
  116.             }
  117.             newSection.classList.remove('leaving');
  118.             newSection.classList.add('active');
  119.             document.querySelectorAll('.nav-link, .mobile-nav-link').forEach(link => {
  120.                 link.classList.toggle('active', link.dataset.section === sectionId);
  121.             });
  122.             if (mobileMenu) {
  123.                 mobileMenu.classList.remove('active');
  124.             }
  125.             setTimeout(() => {
  126.                 if (oldSection) {
  127.                     oldSection.classList.remove('leaving');
  128.                 }
  129.                 document.body.classList.remove('switching');
  130.                 isSwitching = false;
  131.             }, 500);
  132.         }
  133.         navLinks.forEach(link => {
  134.             link.addEventListener('click', (e) => {
  135.                 e.preventDefault();
  136.                 const sectionId = link.getAttribute('data-section');
  137.                 if (location.hash !== `#${sectionId}`) {
  138.                     location.hash = sectionId;
  139.                 } else {
  140.                     showSection(sectionId);
  141.                 }
  142.             });
  143.         });
  144.         function handleHashChange() {
  145.             const hash = (location.hash || '#home').replace('#', '');
  146.             const target = validSections.includes(hash) ? hash : 'home';
  147.             showSection(target);
  148.         }
  149.         window.addEventListener('hashchange', handleHashChange);
  150.         document.addEventListener('DOMContentLoaded', () => {
  151.             renderStudentCards();
  152.             handleHashChange();
  153.         });
  154.         // Mobile menu toggle
  155.         mobileMenuBtn.addEventListener('click', (e) => {
  156.             e.stopPropagation();
  157.             if (mobileMenu) {
  158.                 mobileMenu.classList.toggle('active');
  159.             }
  160.         });
  161.         document.addEventListener('click', (e) => {
  162.             if (
  163.                 mobileMenu &&
  164.                 !mobileMenu.contains(e.target) &&
  165.                 !mobileMenuBtn.contains(e.target)
  166.             ) {
  167.                 mobileMenu.classList.remove('active');
  168.             }
  169.         });
  170.         // Scroll reveal
  171.         const io = new IntersectionObserver((entries) => {
  172.             entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } });
  173.         }, { threshold: .14 });
  174.         document.querySelectorAll('.reveal').forEach(el => io.observe(el));
  175.         // Subtle 3D tilt on the hero card
  176.         const heroCard = document.getElementById('heroCard');
  177.         if (heroCard) {
  178.             let af;
  179.             heroCard.addEventListener('mousemove', (e) => {
  180.                 const r = heroCard.getBoundingClientRect();
  181.                 const x = (e.clientX - r.left) / r.width - .5;
  182.                 const y = (e.clientY - r.top) / r.height - .5;
  183.                 const rx = (-y * 6).toFixed(2), ry = (x * 6).toFixed(2);
  184.                 cancelAnimationFrame(af);
  185.                 af = requestAnimationFrame(() => heroCard.style.transform = `translateY(-2px) rotateX(${rx}deg) rotateY(${ry}deg)`);
  186.             });
  187.             heroCard.addEventListener('mouseleave', () => heroCard.style.transform = 'translateY(0) rotateX(0) rotateY(0)');
  188.         }
  189.         const yearEl = document.getElementById('year');
  190.         if (yearEl) {
  191.             yearEl.textContent = new Date().getFullYear();
  192.         }
  193.     </script>
  194. {% endif %}