diff --git a/js/app.js b/js/app.js index d319cbf..912bd69 100644 --- a/js/app.js +++ b/js/app.js @@ -1,69 +1,80 @@ -// by default, the dark mode is switched off -var darkMode = false; -document.documentElement.setAttribute('data-theme', ['dark', 'light'][darkMode]); -if (darkMode) { - $('#theme-switch').html('🌙') -} else { - $('#theme-switch').html('☀️') +//HELPERS +const $id = id => document.getElementById(id); +const $ = (selector, parent = document) => parent.querySelector(selector); +const $$ = (selector, parent = document) => Array.from(parent.querySelectorAll(selector)); +const afterLoading = callback => document.addEventListener('DOMContentLoaded', callback) +function fetchAdv(responseHandler, path, onSuccess = x => x, onError = console.error) { + fetch(path).then(response => { + if (!response.ok) throw new Error('Network response was not ok'); + return responseHandler(response); + }) + .then(data => onSuccess(data)) + .catch(err => onError(err)); } - -function darkModeSwitcher () { - document.documentElement.setAttribute('data-theme', ['dark', 'light'][+darkMode]); - darkMode = !darkMode; - - if (darkMode) { - $('#theme-switch').html('🌙') - } else { - $('#theme-switch').html('☀️') - } +const getJSON = (path, onSuccess, onError) => fetchAdv(res => res.json(), path, onSuccess, onError); +const getHTML = (path, onSuccess, onError) => fetchAdv( + res => res.text().then(str => new DOMParser().parseFromString(str, 'text/html')), + path, onSuccess, onError +); +//EFFECTS +function fadeOut(el, duration = 400) { + return new Promise(resolve => { + el.style.transition = `opacity ${duration}ms ease`; + el.style.opacity = 0; + setTimeout(() => resolve(el.style.display = 'none'), duration); + }); +} +function fadeIn(el, duration = 400, display = 'block') { + return new Promise(resolve => { + el.style.display = display; + el.style.opacity = 0; + el.style.transition = `opacity ${duration}ms ease`; + requestAnimationFrame(() => el.style.opacity = 1); + setTimeout(() => resolve(), duration); + }); +} +function hide(el) { el.style.display = 'none'; } +function switchClass(el, prevClass, newClass) { + el.classList.remove(prevClass) + el.classList.add(newClass) } -$('#theme-switch').click(function () { - darkModeSwitcher() -}) -const elem = selector => { - return document.querySelector(selector) +// by default, the dark mode is switched off +const themeSwitch = $id('theme-switch'); +let darkMode = false; +function updateTheme() { + document.documentElement.dataset.theme = darkMode ? 'dark' : 'light'; + themeSwitch.innerHTML = darkMode ? '🌙' : '☀️'; } +themeSwitch.onclick = () => updateTheme(darkMode = !darkMode) +updateTheme(); -const today = new Date() -document.getElementById('year').innerHTML = today.getFullYear() +$id('year').innerHTML = new Date().getFullYear() // PROJECTS SECTION -------------------- -$(function () { - $.getJSON('data/projects.json', function (data) { +afterLoading(() => { + getJSON('data/projects.json', data => { console.log('projects loaded'); - $.each(data.projects, function (i, project) { - let figure = `` - - $('.carousel-items').append(figure); - }); - - let list = Object.values(document.querySelectorAll('.carousel-item')) - let length = list.length - - slider = tns({ + $('.carousel-items').innerHTML = data.projects.map(project => + `` + ).join(''); + + tns({ container: '.carousel-items', items: 1, viewportMax: 300, responsive: { - 350: { - // fixedWidth: 400, - items: 2, - gutter: 20 - }, - 500: { - items: 3, - gutter: 20 - } + 350: { items: 2, gutter: 20 }, + 500: { items: 3, gutter: 20 } }, center: true, rewind: true, @@ -74,36 +85,8 @@ $(function () { autoplayButton: "#autoplay-btn", controlsContainer: "#controls-container", navAsThumbnails: true - // prevButton: 'previous', - // nextButton: true }); - - // console.log(list) - // let translate, caption, spotlight; - // let middleTerm = Math.ceil((length - 1) / 2) - // let spotlightIndex = middleTerm - // left.addEventListener('click', _ => { - // spotlightIndex = (spotlightIndex == 0) ? (list.length - 1) : (spotlightIndex - 1); - // spotlight = list[spotlightIndex] - // caption = spotlight.querySelector('figcaption') - // translate = (middleTerm - spotlightIndex) * 100; - // Object.keys(list).forEach(function (key) { - // list[key].style.transform = 'translateX(' + translate + '%)'; - // }) - // }) - // right.addEventListener('click', _ => { - // spotlightIndex = (spotlightIndex == (list.length - 1)) ? 0 : (spotlightIndex + 1); - // spotlight = list[spotlightIndex] - // caption = spotlight.querySelector('figcaption') - // translate = (middleTerm - spotlightIndex) * 100; - // Object.keys(list).forEach(function (key) { - // list[key].style.transform = 'translateX(' + translate + '%)'; - // }) - // }) - }).error(function () { - console.log('error'); - } - ); + }) }); // TEAM SECTION -------------------- @@ -112,301 +95,149 @@ const icon_mail = ' -
- ${member.name}.jpg -
-
-

${member.name}

-

${member.desc}

-

` - - if (member.email) { - figure += `${icon_mail}` - } - if (member.github) { - figure += `${icon_github}` - } - if (member.website) { - figure += `${icon_website}` - } - if (member.linkedin) { - figure += `${icon_linkedin}` - } - - figure += `

` - return figure; +function getMembersDetails(members) { + return members.map(member => ` +
+
+ ${member.name}.jpg +
+
+

${member.name}

+

${member.desc}

+

+ ${member.email ? `${icon_mail}` : ''} + ${member.github ? `${icon_github}` : ''} + ${member.website ? `${icon_website}` : ''} + ${member.linkedin ? `${icon_linkedin}` : ''} +

+
+
` + ).join(''); }; -$(function () { - $.getJSON('data/members.json', function (data) { - console.log('success'); - $.each(data.current_members, function (i, member) { - let figure = getMemberDetails(member) - $('.team-current').append(figure); - }); - $.each(data.older_members, function (i, member) { - let figure = getMemberDetails(member) - $('.team-alumni').append(figure); - }); - }).error(function () { - console.log('error'); - }); +afterLoading(() => { + getJSON('data/members.json', + data => { + console.log('success'); + $('.team-current').innerHTML += getMembersDetails(data.current_members); + $('.team-alumni').innerHTML += getMembersDetails(data.older_members); + }, + err => console.log(`error: ${err}`) + ); }); -// BLOGS SECTION -------------------- -// $(function () { -// const blogsUrl = "https://sdgniser.github.io/coding_club_blogs/"; -// $.getJSON('data/blogs.json', function (data) { -// console.log('success'); -// $.each(data.blogs, function (i, blog) { -// let blog_item = `
-//
-//

${blog.date}

-//

${blog.title}

-//

${blog.abstract}

-//

by ${blog.author}

-//
-// -//
` -// $('.blogs').append(blog_item); -// }); -// }).error(function () { -// console.log('error'); -// }); -// }); - -// $(function () { -// const blogsUrl = "https://sdgniser.github.io/coding_club_blogs/"; - -// $.get(blogsUrl, function (html) { -// console.log('Fetched blogs webpage successfully.'); -// const $html = $(html); -// const blogs = $html.find('ul.post-list > li'); - -// blogs.each(function () { -// const $blog = $(this); -// const date = $blog.find('.post-meta').first().text(); -// const title = $blog.find('h3.post-h3 > a').text(); -// let link = $blog.find('h3.post-h3 > a').attr('href'); -// if (link.startsWith('/')) { -// link = blogsUrl + link.slice(1); -// } -// const url = new URL(link); -// let linkArray = url.pathname.split('/').filter(component => component); -// const complete_link_path = `${blogsUrl}${linkArray.slice(2).join("/")}`; -// const author = $blog.find('.post-meta').last().text(); -// const abstract = $blog.find('p.post-abstract').text() || 'No abstract available.'; - -// // Create the blog item once the abstract is fetched -// const blog_item = ` -//
-//
-//

${date}

-//

${title}

-//

by ${author}

-//

${abstract}

-//
-//
`; -// $('.blogs').append(blog_item); -// }).fail(function () { -// console.log(`Error fetching blog page: ${complete_link_path}`); -// }); -// }); -// }).fail(function () { -// console.log('Error fetching blogs webpage.'); -// }); -$(function () { +afterLoading(() => { const blogsUrl = "https://sdgniser.github.io/coding_club_blogs/"; - $.get(blogsUrl, function (html) { + getHTML(blogsUrl, html => { console.log('Fetched blogs webpage successfully.'); - const $html = $(html); - const blogs = $html.find('ul.post-list > li'); - - const blogData = []; - - blogs.each(function () { - const $blog = $(this); - const date = $blog.find('.post-meta').first().text(); - const title = $blog.find('h3.post-h3 > a').text(); - let link = $blog.find('h3.post-h3 > a').attr('href'); - if (link.startsWith('/')) { - link = blogsUrl + link.slice(1); - } - const url = new URL(link); - let linkArray = url.pathname.split('/').filter(component => component); - const complete_link_path = `${blogsUrl}${linkArray.slice(2).join("/")}`; - const abstract = $blog.find('p.post-abstract').text() || 'No abstract available.'; - const author = $blog.find('.post-meta').last().text(); - blogData.push({ date, title, complete_link_path, abstract, author }); - }); - - // Generate blog items and append to the DOM - $.each(blogData.slice(1), function (i, blog) { - const blog_item = ` + $('.blogs').innerHTML += $$('ul.post-list > li', html).map(blog => { + const _$ = query => $(query, blog); + const authors = $$('.post-meta', blog); + return `
-

${blog.date}

- -

${blog.title}

+

${_$('.post-meta').innerText}

+
+

${_$('h3.post-h3 > a').innerText}

-

${blog.abstract}

-

by ${blog.author}

+

${_$('p.post-abstract').innerText || 'No abstract available.'}

+

by ${authors[authors.length-1].innerText}

-
`; - $('.blogs').append(blog_item); - }); - }).fail(function () { - console.log('Error fetching blogs webpage.'); - }); + ` + }).join(''); + }, + () => console.log('Error fetching blogs webpage.') + ); }); // NEWS SECTION -------------------- -$(function () { - $.getJSON('data/news.json', function (data) { +/* +afterLoading(() => { + getJSON('data/news.json', data => { console.log('success'); - $.each(data.news, function (i, news_item) { - let article = `
-
${news_item.date}
-
${news_item.content}
- Know More -
` - $('.articles').append(article); - }); - }).error(function () { - console.log('error'); - }); + $('.articles').innerHTML += data.news.map(news_item => + `
+
${news_item.date}
+
${news_item.content}
+ Know More +
` + ).join(''); + }, + err => console.warn(`${err} + """ + This error is being shown probably because '.articles' is commented out + if you don't need it anymore consider removing this part of the code! + """`)) }); - -// SMOOTH SCROLLING -------------------- -// let scrollLink = $('.scroll'); -// scrollLink.click(function (e) { -// e.preventDefault(); -// $('body,html').animate({ -// scrollTop: $(this.hash).offset().top - $('nav').height() - 20 -// }, 1000); -// }); +*/ // PARALLAX -------------------- -let nav = elem('nav') -let introHeight = elem('.section--intro').offsetHeight -let aboutOffset = $('#about').offset().top - ($(window).height() / 1.2) -let teamOffset = $('#team').offset().top - ($(window).height() / 1.5) -let projectsOffset = elem('#projects').offsetTop - ($(window).height() / 1.6) -let footerOffset = elem('footer').offsetTop //- ($(window).height() / 1) - -$(window).scroll(function () { - let wScroll = $(window).scrollTop() - - // NAVIGATION - if (wScroll > introHeight) { - nav.classList.add('alone') - // $('#niser-logo').attr("src", "images/n_logo_color.png") - } - if (wScroll < introHeight) { - nav.classList.remove('alone') - // $('#niser-logo').attr("src", "images/n_logo.png") - } - - // LANDING ELEMENTS - if (wScroll > projectsOffset) { $('#projects .section__title').addClass('is-showing'); } - if (wScroll > teamOffset) { $('#team .section__title').addClass('is-showing'); } - - if (wScroll > aboutOffset * 1.2) { elem('#about .section__title').classList.add('is-showing'); } - if (wScroll > aboutOffset) { elem('#about .section__image').classList.add('is-showing'); } - // if (wScroll > footerOffset) { - // elem('footer .logo').classList.add('is-showing'); - // // console.log('shownmf') - // } - // console.log(wScroll, footerOffset) - +let nav = $('nav') +let introHeight = $('.section--intro').offsetHeight +let aboutOffset = $id('about').offsetTop - (window.innerHeight / 1.2) +let teamOffset = $id('team').offsetTop - (window.innerHeight / 1.5) +let projectsOffset = $id('projects').offsetTop - (window.innerHeight / 1.6) +let footerOffset = $('footer').offsetTop //- ($(window).height() / 1) + +window.addEventListener('scroll', () => { + const wScroll = window.scrollY + nav.classList.toggle('alone', wScroll > introHeight); + [ // LANDING ELEMENTS + [projectsOffset, '#projects .section__title'], + [teamOffset, '#team .section__title'], + [aboutOffset * 1.2, '#about .section__title'], + [aboutOffset, '#about .section__image'] + ].forEach(([offset, query]) => { if (wScroll > offset) $(query).classList.add('is-showing'); }); + // use $(query).classList.toggle('is-showing', wScroll > offset); if you want to get the effects if scrolled from the top again }) -// CAROUSEL -------------------- -const left = document.getElementById('js-left') -const right = document.getElementById('js-right') - // ONLOAD ANIMATION -------------------- -window.onload = function () { +function typingAnimation(txt, containerId, speed = 100) { + let i = 0; + const typing = setInterval(() => { + if (i >= txt.length) return clearInterval(typing); + let char = txt[i++]; + $id(containerId).innerHTML += char === ' ' ? '
' : char; + }, speed) +} +window.onload = () => { checkNav() - - typingAnimation('CODING CLUB', 100, "typing") - typingAnimation('NISER', 100, "typing-2") - + typingAnimation('CODING CLUB', "typing") + typingAnimation('NISER', "typing-2") } -function typingAnimation(txt, speed, container) { - var i = 0; - - function typeWriter() { - if (i < txt.length) { - let char = txt.charAt(i) - if (char == ' ') { - char = '
' - } - document.getElementById(container).innerHTML += char; - i++; - setTimeout(typeWriter, speed); - } - } - - typeWriter() -} // TEAM SECTION SWITCH FUNCTIONALITY -------------------- -$('.team-switch-current').click(function () { - $('.team-alumni').fadeOut() - $('.team-current').fadeIn() - $('.team-switch-current').addClass('active') - $('.team-switch-alumni').removeClass('active') -}) -$('.team-switch-alumni').click(function () { - $('.team-current').fadeOut() - $('.team-alumni').fadeIn() - $('.team-switch-current').removeClass('active') - $('.team-switch-alumni').addClass('active') -}) +async function switchTeam(prevteam, newTeam) { + await fadeOut($(`.team-${prevteam}`)) + await fadeIn($(`.team-${newTeam}`), 400, "flex") + $(`.team-switch-${newTeam}`).classList.add('active') + $(`.team-switch-${prevteam}`).classList.remove('active') +} +$('.team-switch-current').onclick = () => switchTeam("alumni", "current"); +$('.team-switch-alumni').onclick = () => switchTeam("current", "alumni") // MOBILE NAVIGATION BAR -------------------- -$('#nav-close').click(function () { - $('.logo-2').hide() - $('nav ul').hide() - $('#nav-close').hide() - $('nav').addClass('small') - $('nav').removeClass('small-open') -}) - -$('#nav-open').click(function () { - $('nav').removeClass('small') - $('nav').addClass('small-open') - $('.logo-2').fadeIn() - $('nav ul').fadeIn() - $('#nav-close').fadeIn() - $('#nav-close').attr('style', 'display:block') -}) +$id('nav-close').onclick = () => { + Promise.all([ $('.logo-2'), $('nav ul'), $id('nav-close') ].map(fadeOut)) + .then(() => switchClass(nav, 'small-open', 'small')); +} -$('nav ul li').click(function () { - if ($('nav').hasClass('small-open')) { - $('.logo-2').hide() - $('nav ul').fadeOut() - $('#nav-close').hide() - $('nav').addClass('small') - $('nav').removeClass('small-open') - } -}) +$id('nav-open').onclick = () => { + switchClass(nav, 'small', 'small-open'); + Promise.all([ fadeIn($('.logo-2')), fadeIn($('nav ul'), 400, 'flex'), fadeIn($id('nav-close'), 400, 'inline') ]); +} -$(window).resize(checkNav()) +$('nav ul li').onclick = () => { + if (!nav.classList.includes('small-open')) return; + [$('.logo-2'), $id('nav-close')].forEach(hide) + switchClass(nav, 'small-open', 'small') + await fadeOut($('nav ul')) +}; -function checkNav() { - if ($(window).width() > 700) { - $('nav').removeClass('small') - } - else { - $('nav').addClass('small') - } -} \ No newline at end of file +window.onresize = checkNav; +function checkNav() { nav.classList.toggle('small', window.innerWidth <= 700) }