diff --git a/assets/scripts/application.js b/assets/scripts/application.js index 64c8f6f..f79e4b0 100644 --- a/assets/scripts/application.js +++ b/assets/scripts/application.js @@ -2,3 +2,7 @@ import 'jquery'; import 'popper.js'; import 'bootstrap'; import '@fortawesome/fontawesome-free'; + +import './core'; +import './features'; +import './sections'; diff --git a/assets/scripts/core/device.js b/assets/scripts/core/device.js new file mode 100644 index 0000000..9feefd0 --- /dev/null +++ b/assets/scripts/core/device.js @@ -0,0 +1,36 @@ +let deviceState = { + isMobile: false, + isTablet: false, + isLaptop: false, +}; + +function detectDeviceState() { + if (window.innerWidth <= 425) { + deviceState = { + isMobile: true, + isTablet: false, + isLaptop: false, + }; + } else if (window.innerWidth <= 768) { + deviceState = { + isMobile: false, + isTablet: true, + isLaptop: false, + }; + } else { + deviceState = { + isMobile: false, + isTablet: false, + isLaptop: true, + }; + } +} + +detectDeviceState(); +window.addEventListener('resize', detectDeviceState); + +// returns a copy of the device state +// so other parts of code can't override this. +export function getDeviceState() { + return { ... deviceState }; +} diff --git a/assets/scripts/core/index.js b/assets/scripts/core/index.js new file mode 100644 index 0000000..0ce9c17 --- /dev/null +++ b/assets/scripts/core/index.js @@ -0,0 +1 @@ +export * from './device'; diff --git a/assets/scripts/features/index.js b/assets/scripts/features/index.js new file mode 100644 index 0000000..6f71516 --- /dev/null +++ b/assets/scripts/features/index.js @@ -0,0 +1,7 @@ +if (process.env.FEATURE_VIDEOPLAYER) { + import('./videoplayer'); +} + +if (process.env.FEATURE_TOC) { + import('./toc'); +} diff --git a/assets/scripts/features/toc/index.js b/assets/scripts/features/toc/index.js new file mode 100644 index 0000000..3ca28fa --- /dev/null +++ b/assets/scripts/features/toc/index.js @@ -0,0 +1,48 @@ +import { getDeviceState } from '../../core'; + +// Toggle Table of Contents on click. Here, class "hide" open the toc +function toggleTOC() { + let toc = document.getElementById("toc-section"); + if (toc == null) { + return + } + + if (toc.classList.contains("hide")) { + toc.classList.remove("hide"); + } else { + // if sidebar-section is open, then close it first + let sidebar = document.getElementById("sidebar-section"); + if (sidebar != null && sidebar.classList.contains("hide")) { + sidebar.classList.remove("hide"); + } + // add "hide" class + toc.classList.add("hide"); + // if it is mobile device. then scroll to top. + const { isMobile } = getDeviceState(); + if (isMobile && toc.classList.contains("hide")) { + document.body.scrollTop = 0; + document.documentElement.scrollTop = 0; + } + } + if (document.getElementById("hero-area") != null) { + document.getElementById("hero-area").classList.toggle("hide"); + } +} + +window.addEventListener('DOMContentLoaded', () => { + // bind click event to #toc-toggle in navbar-2.html + const $toggle = document.getElementById('toc-toggler'); + if ($toggle) $toggle.addEventListener('click', toggleTOC); + + // hide TOC when user clicks on a TOC link. + // Only applies if it's mobile. + const $toc = document.getElementById("TableOfContents"); + if ($toc) { + $toc.addEventListener('click', (event) => { + const { isMobile } = getDeviceState(); + if (isMobile && event.target.nodeName === 'A') { + toggleTOC(); + } + }); + } +}); diff --git a/assets/scripts/features/videoplayer/index.js b/assets/scripts/features/videoplayer/index.js new file mode 100644 index 0000000..76c2a3d --- /dev/null +++ b/assets/scripts/features/videoplayer/index.js @@ -0,0 +1,3 @@ +if (process.env.FEATURE_VIDEOPLAYER_PLYR) { + import('./plyr'); +} diff --git a/assets/scripts/features/videoplayer/plyr.js b/assets/scripts/features/videoplayer/plyr.js new file mode 100644 index 0000000..8daf8d9 --- /dev/null +++ b/assets/scripts/features/videoplayer/plyr.js @@ -0,0 +1,5 @@ +import Plyr from 'plyr'; +import { videoplayer } from '@params'; + +const { plyr: options } = videoplayer; +window.addEventListener('DOMContentLoaded', () => Plyr.setup('.js-player', options)); diff --git a/assets/scripts/sections/education.js b/assets/scripts/sections/education.js new file mode 100644 index 0000000..6fa0c0c --- /dev/null +++ b/assets/scripts/sections/education.js @@ -0,0 +1,34 @@ +// Show more rows in the taken courses table +function toggleCourseVisibility(elem) { + + // find the courses + let courses = elem.parentNode.getElementsByClassName("course"); + if (courses == null) { + return + } + + // toggle hidden-course class from the third elements + for (const course of courses) { + if (course.classList.contains("hidden-course") || course.classList.contains("toggled-hidden-course")) { + course.classList.toggle("hidden-course"); + course.classList.add("toggled-hidden-course"); + } + } + + // toggle the buttons visibility + let buttonsToToggle = elem.parentNode.getElementsByClassName("show-more-btn"); + for (const buttonToToggle of buttonsToToggle) { + buttonToToggle.classList.toggle("hidden"); + } +} + +window.addEventListener('DOMContentLoaded', () => { + const $els = [ + document.getElementById('show-more-btn'), + document.getElementById('show-less-btn'), + ]; + + $els.filter(($el) => $el != null).forEach(($el) => + $el.addEventListener('click', ({target}) => + toggleCourseVisibility(target))); +}); diff --git a/assets/scripts/sections/index.js b/assets/scripts/sections/index.js new file mode 100644 index 0000000..89da2dd --- /dev/null +++ b/assets/scripts/sections/index.js @@ -0,0 +1,4 @@ +import './navbar'; +import './sidebar'; + +import './education'; diff --git a/static/js/navbar.js b/assets/scripts/sections/navbar.js similarity index 64% rename from static/js/navbar.js rename to assets/scripts/sections/navbar.js index 0ed7394..a311b38 100644 --- a/static/js/navbar.js +++ b/assets/scripts/sections/navbar.js @@ -1,4 +1,4 @@ -"use strict"; +import $ from 'jquery'; const updateNavBar = () => { if ($(document).scrollTop() > 40) { @@ -37,27 +37,25 @@ const updateNavBar = () => { } }; -(function ($) { - jQuery(document).ready(function () { - - // change navbar style on scroll - // ================================================== - // When the user scrolls down 80px from the top of the document, resize the navbar's padding and the logo's font size - // $.onscroll = function() {scrollFunction()}; - $(document).scroll(function () { - updateNavBar(); - }); - - // Creates a click handler to collapse the navigation when - // anchors in the mobile nav pop up are clicked - var navMain = $(".navbar-collapse"); - if (navMain) { - navMain.on("click", "a", null, function (e) { - $('.navbar-collapse').collapse('hide'); - }); - } +$(document).ready(function () { + // change navbar style on scroll + // ================================================== + // When the user scrolls down 80px from the top of the document, resize the navbar's padding and the logo's font size + // $.onscroll = function() {scrollFunction()}; + $(document).scroll(function () { updateNavBar(); }); -})(jQuery); + // Creates a click handler to collapse the navigation when + // anchors in the mobile nav pop up are clicked + var navMain = $(".navbar-collapse"); + if (navMain) { + navMain.on("click", "a", null, function (e) { + $('.navbar-collapse').collapse('hide'); + }); + } + + updateNavBar(); +}); + diff --git a/assets/scripts/sections/sidebar.js b/assets/scripts/sections/sidebar.js new file mode 100644 index 0000000..ea3763a --- /dev/null +++ b/assets/scripts/sections/sidebar.js @@ -0,0 +1,39 @@ +import { getDeviceState } from '../core/device'; + +// Toggle sidebar on click. Here, class "hide" open the sidebar +function toggleSidebar() { + let sidebar = document.getElementById("sidebar-section"); + if (sidebar == null) { + return + } + if (sidebar.classList.contains("hide")) { + sidebar.classList.remove("hide") + } else { + // if toc-section is open, then close it first + let toc = document.getElementById("toc-section"); + if (toc != null && toc.classList.contains("hide")) { + toc.classList.remove("hide"); + } + // add "hide" class + sidebar.classList.add("hide"); + // if it is mobile device. then scroll to top. + const { isMobile } = getDeviceState(); + if (isMobile && sidebar.classList.contains("hide")) { + document.body.scrollTop = 0; + document.documentElement.scrollTop = 0; + if (document.getElementById("hero-area") != null) { + document.getElementById("hero-area").classList.toggle("hide"); + } + } + } + if (document.getElementById("content-section") != null) { + document.getElementById("content-section").classList.toggle("hide"); + } +} + +window.addEventListener('DOMContentLoaded', () => { + // bind click event to #sidebar-toggler in navbar-2.html + const $toggle = document.getElementById('sidebar-toggler'); + if ($toggle) $toggle.addEventListener('click', toggleSidebar); +}); + diff --git a/layouts/_default/single.html b/layouts/_default/single.html index 8b4f608..bed0188 100644 --- a/layouts/_default/single.html +++ b/layouts/_default/single.html @@ -179,7 +179,7 @@ {{ define "toc" }}
- {{ if and site.Params.enableTOC ( .Params.enableTOC | default true ) }} + {{ if and site.Params.features.toc.enable ( .Params.enableTOC | default true ) }}
{{ i18n "toc_heading" }}

diff --git a/layouts/partials/navigators/navbar-2.html b/layouts/partials/navigators/navbar-2.html index 94ed978..8d42365 100644 --- a/layouts/partials/navigators/navbar-2.html +++ b/layouts/partials/navigators/navbar-2.html @@ -29,7 +29,7 @@
{{ end }} diff --git a/static/css/layouts/main.css b/static/css/layouts/main.css index e2ed1ab..1e37c73 100644 --- a/static/css/layouts/main.css +++ b/static/css/layouts/main.css @@ -16,6 +16,13 @@ Yellow: #FFC212 body { background-color: #f9fafc; font-family: "Muli"; + + /* + Removed smooth scrolling implementation in main.js in favor of + simpler css approach. + See: https://css-tricks.com/snippets/jquery/smooth-scrolling/ + */ + scroll-behavior: smooth; } h1, diff --git a/static/js/main.js b/static/js/main.js deleted file mode 100644 index ff688dd..0000000 --- a/static/js/main.js +++ /dev/null @@ -1,173 +0,0 @@ -"use strict"; - -var projectCards; -var isMobile = false, isTablet = false, isLaptop = false; -(function ($) { - jQuery(document).ready(function () { - function detectDevice() { - if (window.innerWidth <= 425) { - isMobile = true; - isTablet = false; - isLaptop = false; - } else if (window.innerWidth <= 768) { - isMobile = false; - isTablet = true; - isLaptop = false; - } else { - isMobile = false; - isTablet = false; - isLaptop = true; - } - } - detectDevice(); - - // ================= Smooth Scroll =================== - function addSmoothScroll() { - // ref: https://css-tricks.com/snippets/jquery/smooth-scrolling/ - // Select all links with hashes - $('a[href*="#"]') - // Remove links that don't actually link to anything - .not('[href="#"]') - .not('[href="#0"]') - .click(function (event) { - // On-page links - if ( - location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') - && - location.hostname == this.hostname - ) { - // Figure out element to scroll to - var target = $(decodeURI(this.hash)); - target = target.length ? target : $('[name=' + this.hash.slice(1) + ']'); - // Does a scroll target exist? - if (target.length) { - // Only prevent default if animation is actually gonna happen - event.preventDefault(); - - let offset = 60; - if (isMobile) { - offset = 710; - } else if (isTablet) { - offset = 60; - } - $('html, body').animate({ - scrollTop: target.offset().top - offset - }, 1000, function () { - // Callback after animation - // Must change focus! - var $target = $(target); - $target.focus(); - if ($target.is(":focus")) { // Checking if the target was focused - return false; - } else { - $target.attr('tabindex', '-1'); // Adding tabindex for elements not focusable - $target.focus(); // Set focus again - }; - }); - // Add hash (#) to URL when done scrolling (default click behavior) - window.location.hash = this.hash - } - } - }); - } - addSmoothScroll(); - - // ===================== Video Player ================== - function renderVideoPlayer(){ - var videos = document.getElementsByClassName("video-player"); - for (var i =0; i< videos.length; i++ ){ - const player = new Plyr("#"+videos[i].id); - } - - } - renderVideoPlayer(); - - // re-render custom functions on window resize - window.onresize = function () { - detectDevice(); - addSmoothScroll(); - }; - }); -})(jQuery); - - -// Toggle sidebar on click. Here, class "hide" open the sidebar -function toggleSidebar() { - let sidebar = document.getElementById("sidebar-section"); - if (sidebar == null) { - return - } - if (sidebar.classList.contains("hide")) { - sidebar.classList.remove("hide") - } else { - // if toc-section is open, then close it first - let toc = document.getElementById("toc-section"); - if (toc != null && toc.classList.contains("hide")) { - toc.classList.remove("hide"); - } - // add "hide" class - sidebar.classList.add("hide") - // if it is mobile device. then scroll to top. - if (isMobile && sidebar.classList.contains("hide")) { - document.body.scrollTop = 0; - document.documentElement.scrollTop = 0; - if (document.getElementById("hero-area") != null) { - document.getElementById("hero-area").classList.toggle("hide"); - } - } - } - if (document.getElementById("content-section") != null) { - document.getElementById("content-section").classList.toggle("hide"); - } -} - -// Toggle Table of Contents on click. Here, class "hide" open the toc -function toggleTOC() { - let toc = document.getElementById("toc-section"); - if (toc == null) { - return - } - if (toc.classList.contains("hide")) { - toc.classList.remove("hide"); - } else { - // if sidebar-section is open, then close it first - let sidebar = document.getElementById("sidebar-section"); - if (sidebar != null && sidebar.classList.contains("hide")) { - sidebar.classList.remove("hide"); - } - // add "hide" class - toc.classList.add("hide") - // if it is mobile device. then scroll to top. - if (isMobile && toc.classList.contains("hide")) { - document.body.scrollTop = 0; - document.documentElement.scrollTop = 0; - } - } - if (document.getElementById("hero-area") != null) { - document.getElementById("hero-area").classList.toggle("hide"); - } -} - -// Show more rows in the taken courses table -function toggleCourseVisibility(elem) { - - // find the courses - let courses = elem.parentNode.getElementsByClassName("course"); - if (courses == null) { - return - } - - // toggle hidden-course class from the third elements - for (const course of courses) { - if (course.classList.contains("hidden-course") || course.classList.contains("toggled-hidden-course")) { - course.classList.toggle("hidden-course"); - course.classList.add("toggled-hidden-course"); - } - } - - // toggle the buttons visibility - let buttonsToToggle = elem.parentNode.getElementsByClassName("show-more-btn"); - for (const buttonToToggle of buttonsToToggle) { - buttonToToggle.classList.toggle("hidden"); - } -} diff --git a/static/js/single.js b/static/js/single.js index 149049f..f84e89f 100644 --- a/static/js/single.js +++ b/static/js/single.js @@ -49,9 +49,6 @@ var isMobile = false, isTablet = false, isLaptop = false; elems = toc.getElementsByTagName("li"); for (let i = 0; i < elems.length; i++) { elems[i].classList.add("nav-item"); - if (isMobile) { - elems[i].setAttribute("onclick", "toggleTOC()"); - } } // add "nav-link" class to the "a" elements elems = toc.getElementsByTagName("a");