Skip to content

Commit

Permalink
♻️ refactor: organiza e separa funções
Browse files Browse the repository at this point in the history
  • Loading branch information
aliine98 committed Sep 22, 2023
1 parent a27bf43 commit 5caa32c
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 89 deletions.
34 changes: 34 additions & 0 deletions src/js/init-swiper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Swiper from "https://cdn.jsdelivr.net/npm/swiper@10/swiper-bundle.min.mjs";
export { initSwiperCarousel };

/**
* Initializes a Swiper carousel with the given autoplay value.
*
* @param {boolean | Object} autoplayValue - The value indicating whether the carousel should autoplay.
*/
function initSwiperCarousel(autoplayValue) {
new Swiper(".swiper", {
effect: "cards",
cardsEffect: {
perSlideOffset: 7,
perSlideRotate: 1,
},
a11y: {
prevSlideMessage: "Projeto anterior",
nextSlideMessage: "Próximo projeto",
paginationBulletMessage: "Ir para projeto {{index}}",
},
grabCursor: true,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
autoplay: autoplayValue,
rewind: true,
keyboard: true,
});
}
86 changes: 12 additions & 74 deletions src/js/main.js
Original file line number Diff line number Diff line change
@@ -1,63 +1,26 @@
import { typing, textElement, text } from "./typing-animation.js";
import Swiper from "https://cdn.jsdelivr.net/npm/swiper@10/swiper-bundle.min.mjs";
import { typing } from "./typing-animation.js";
import { toggleNavMenu, closeNavMenu, markActiveLink } from "./nav-menu.js";
import { initSwiperCarousel } from "./init-swiper.js";

document.querySelector("body").classList.remove("no-js");

function setAriaAttributes() {
const ariaExpanded = menuButton.getAttribute("aria-expanded") === "true";
menuButton.setAttribute("aria-expanded", !ariaExpanded);
nav.setAttribute("aria-hidden", ariaExpanded);
}

function initSwiperCarousel(autoplayValue) {
new Swiper(".swiper", {
effect: "cards",
cardsEffect: {
perSlideOffset: 7,
perSlideRotate: 1,
},
a11y: {
prevSlideMessage: "Projeto anterior",
nextSlideMessage: "Próximo projeto",
paginationBulletMessage: "Ir para projeto {{index}}",
},
grabCursor: true,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
autoplay: autoplayValue,
rewind: true,
keyboard: true,
});
}

const menuButton = document.querySelector(".header__burger-menu");
const nav = document.querySelector(".header__nav");
const navLinks = document.querySelectorAll(".header__nav-item a");
const textElement = document.querySelector(".home__title--highlight");
const text = textElement.dataset.text;
const lightSwitch = document.querySelector(".header__dark-light-switch");

//change theme
lightSwitch.addEventListener("click", () => {
document.body.classList.toggle("light");
});

//open nav menu
menuButton.addEventListener("click", () => {
nav.classList.toggle("open");
setAriaAttributes();
});
//open/close nav menu upon clicking on burger menu
toggleNavMenu(menuButton, nav);

//close nav menu after clicking on a link
const navLinks = document.querySelectorAll(".header__nav-item a");
navLinks.forEach(link => {
link.addEventListener("click", () => {
nav.classList.remove("open");
setAriaAttributes();
});
});
closeNavMenu(navLinks, menuButton, nav);

window.addEventListener("scroll", () => {
//change header style on scroll
Expand All @@ -67,32 +30,7 @@ window.addEventListener("scroll", () => {
document.querySelector(".scroll-to-top").classList.toggle("show", window.scrollY > 100);

//mark active link upon scrolling to it's ref section

function getYPosition(link) {
const targetSection = document.querySelector(link.getAttribute("href"));
return targetSection.getBoundingClientRect().top;
}

//returns correspondent link of the current visible section
function getLastVisibleLink(positions) {
const length = positions.length - 1;
for (let i = length; i >= 0; i--) {
if (positions[i] <= 50) {
return navLinks[i];
}
}
return navLinks[0];
}

const positions = [];
for (let i = 0; i < navLinks.length; i++) {
positions[i] = getYPosition(navLinks[i]);
}

const currentLink = getLastVisibleLink(positions);
const activeLink = document.querySelector(".active");
if (activeLink) activeLink.classList.remove("active");
currentLink.classList.add("active");
markActiveLink(navLinks);
});

const isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
Expand All @@ -105,7 +43,7 @@ if (isReducedMotion) {
initSwiperCarousel(false);
} else {
//init typing animation
typing();
typing(textElement, text);

//init swiper carousel with autoplay
initSwiperCarousel({
Expand Down
96 changes: 96 additions & 0 deletions src/js/nav-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
export { toggleNavMenu, closeNavMenu, markActiveLink };

/**
* Retrieves the vertical position of the target section associated with the given link.
*
* @param {HTMLElement} link - The link element that points to the target section.
* @return {number} The vertical position of the target section.
*/
function getYPosition(link) {
const targetSection = document.querySelector(link.getAttribute("href"));
return targetSection.getBoundingClientRect().top;
}

/**
* Generate the positions of each navigation link.
*
* @param {NodeListOf<HTMLElement>} navLinks - An array of navigation links.
* @return {Array<number>} An array of positions for each navigation link.
*/
function getPositions(navLinks) {
const positions = [];
for (let i = 0; i < navLinks.length; i++) {
positions[i] = getYPosition(navLinks[i]);
}
return positions;
}

/**
* Finds and returns the last visible link in the navigation menu.
*
* @param {Array<number>} positions - An array of positions for each navigation link.
* @param {NodeListOf<HTMLElement>} navLinks - An array of navigation links.
* @return {HTMLElement} The last visible link in the navigation menu.
*/
function getLastVisibleLink(positions, navLinks) {
const length = positions.length - 1;
for (let i = length; i >= 0; i--) {
if (positions[i] <= 100) {
return navLinks[i];
}
}
return navLinks[0];
}

/**
* Marks the active link in the navigation menu.
*
* @param {NodeListOf<HTMLElement>} navLinks - An array of navigation links.
*/
function markActiveLink(navLinks) {
const currentLink = getLastVisibleLink(getPositions(navLinks), navLinks);
const activeLink = document.querySelector(".active");
if (activeLink) activeLink.classList.remove("active");
currentLink.classList.add("active");
}

/**
* Toggles the visibility of the navigation menu when the menu button is clicked.
*
* @param {HTMLElement} menuButton - The menu button element.
* @param {HTMLElement} nav - The navigation element.
*/
function toggleNavMenu(menuButton, nav) {
menuButton.addEventListener("click", () => {
nav.classList.toggle("open");
setAriaAttributes(menuButton, nav);
});
}

/**
* Sets the ARIA attributes for menu button and navigation
*
* @param {HTMLElement} menuButton - The menu button element.
* @param {HTMLElement} nav - The navigation element.
*/
function setAriaAttributes(menuButton, nav) {
const ariaExpanded = menuButton.getAttribute("aria-expanded") === "true";
menuButton.setAttribute("aria-expanded", !ariaExpanded);
nav.setAttribute("aria-hidden", ariaExpanded);
}

/**
* Closes the navigation menu when a link is clicked.
*
* @param {NodeListOf<HTMLElement>} navLinks - An array of navigation links.
* @param {HTMLElement} menuButton - The menu button element.
* @param {HTMLElement} nav - The navigation element.
*/
function closeNavMenu(navLinks, menuButton, nav) {
navLinks.forEach(link => {
link.addEventListener("click", () => {
nav.classList.remove("open");
setAriaAttributes(menuButton, nav);
});
});
}
31 changes: 16 additions & 15 deletions src/js/typing-animation.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
export { typing, textElement, text };

const textElement = document.querySelector(".home__title--highlight");
const text = textElement.dataset.text;
export { typing };

/**
* Simulates typing effect by gradually displaying characters of a text from html data attribute.
* @returns None
* Generates a typing animation for a given text in the HTML element.
*
* @param {HTMLElement} textElement - The HTML element where the text will be typed.
* @param {string} text - The text to be typed.
*/
async function typing() {
async function typing(textElement, text) {
for (let i = 0; i < text.length; i++) {
await new Promise((resolve) => {
await new Promise(resolve => {
setTimeout(() => {
textElement.innerHTML += text[i];
resolve();
}, 100);
});
}
deleteTyping(text.length);
deleteTyping(text.length, textElement, text);
}

/**
* Deletes the typing effect by gradually removing characters from the text element.
* @param {number} textLength - The length of the text to delete.
* @returns None
* Deletes the text in the given textElement by removing characters one by one in a timed loop.
*
* @param {number} textLength - The length of the text to be deleted.
* @param {HTMLElement} textElement - The HTML element containing the text to be deleted.
* @param {string} text - The text to be deleted.
*/
async function deleteTyping(textLength) {
async function deleteTyping(textLength, textElement, text) {
for (let i = textLength; i >= 0; i--) {
await new Promise((resolve) => {
await new Promise(resolve => {
setTimeout(() => {
const deletingText = textElement.textContent.substring(0, i);
textElement.textContent = deletingText;
resolve();
}, 100);
});
}
typing();
typing(textElement, text);
}

0 comments on commit 5caa32c

Please sign in to comment.