Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .docker/nginx/app.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ server {
root /var/www/html;

location ~ \.(ico|css|js|gif|jpe?g|png|woff2?|ttf|otf|svg|eot)$ {
try_files $uri /$request_uri;
try_files $uri =404;
# Optional: Don't log access to other assets
access_log off;
}
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ npm-debug.log
# Optional ignores
# /build_staging/
/build_production/
/source/assets/build/
/source/assets/compiled/

.env
1,002 changes: 629 additions & 373 deletions composer.lock

Large diffs are not rendered by default.

264 changes: 260 additions & 4 deletions lang/cs/main.json

Large diffs are not rendered by default.

191 changes: 150 additions & 41 deletions lang/en/main.json

Large diffs are not rendered by default.

252 changes: 186 additions & 66 deletions lang/fr/main.json

Large diffs are not rendered by default.

308 changes: 214 additions & 94 deletions lang/nb-NO/main.json

Large diffs are not rendered by default.

394 changes: 257 additions & 137 deletions lang/pt-BR/main.json

Large diffs are not rendered by default.

427 changes: 287 additions & 140 deletions lang/ta/main.json

Large diffs are not rendered by default.

3,228 changes: 2,651 additions & 577 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@
"browser-sync-webpack-plugin": "https://github.com/madbucket/browser-sync-webpack-plugin",
"laravel-mix": "^6.0.49",
"laravel-mix-jigsaw": "^2.1.1",
"postcss": "^8.5.3",
"postcss-import": "^16.1.0",
"sass": "^1.85.1",
"sass-loader": "^12",
"tailwindcss": "^4.0.12"
"sass-loader": "^12"
},
"dependencies": {
"@fontsource/montserrat": "^5.2.8",
"animate.css": "^4.1.1",
"aos": "^2.3.4",
"bootstrap": "^5.3.3",
Expand Down
24 changes: 0 additions & 24 deletions source/_assets/css/main.css

This file was deleted.

47 changes: 0 additions & 47 deletions source/_assets/css/main.scss

This file was deleted.

185 changes: 155 additions & 30 deletions source/_assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,49 @@ require('aos/dist/aos.css');
(function () {
"use strict";

// ======= Sticky
window.onscroll = function () {
const ud_header = document.querySelector(".ud-header");
const sticky = ud_header.offsetTop;
const logo = document.querySelector(".navbar-brand img");

if (window.pageYOffset > sticky) {
ud_header.classList.add("sticky");
} else {
ud_header.classList.remove("sticky");
}
// Debounce function to improve performance
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}

// === logo change
if (ud_header.classList.contains("sticky")) {
logo.src = window.baseUrl + "/assets/images/logo/logo-2.svg";
} else {
logo.src = window.baseUrl + "/assets/images/logo/logo.svg";
// Show or hide scroll-dependent elements
function handleScrollElements() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const backToTop = document.querySelector("#back-to-top");
const footerContact = document.querySelector("#footer-contact");
const shouldShow = scrollTop > 50;

if (backToTop) {
if (shouldShow) {
backToTop.classList.add("visible");
backToTop.setAttribute("aria-hidden", "false");
} else {
backToTop.classList.remove("visible");
backToTop.setAttribute("aria-hidden", "true");
}
}

// show or hide the back-top-top button
const backToTop = document.querySelector(".back-to-top");
if (
document.body.scrollTop > 50 ||
document.documentElement.scrollTop > 50
) {
backToTop.style.display = "flex";
} else {
backToTop.style.display = "none";
if (footerContact) {
if (shouldShow) {
footerContact.classList.add("visible");
footerContact.setAttribute("aria-hidden", "false");
} else {
footerContact.classList.remove("visible");
footerContact.setAttribute("aria-hidden", "true");
}
}
};
}

// Attach scroll handler with debounce
window.addEventListener("scroll", debounce(handleScrollElements, 10));

//===== close navbar-collapse when a clicked
let navbarToggler = document.querySelector(".navbar-toggler");
Expand All @@ -43,11 +56,14 @@ require('aos/dist/aos.css');
e.addEventListener("click", () => {
navbarToggler.classList.remove("active");
navbarCollapse.classList.remove("show");
navbarToggler.setAttribute("aria-expanded", "false");
})
);

navbarToggler.addEventListener("click", function () {
navbarToggler.classList.toggle("active");
const isExpanded = navbarToggler.classList.toggle("active");
navbarCollapse.classList.toggle("show");
navbarToggler.setAttribute("aria-expanded", isExpanded ? "true" : "false");
});

// ===== submenu
Expand All @@ -58,6 +74,76 @@ require('aos/dist/aos.css');
});
});

// ===== selector
const selectorButton = document.querySelectorAll(".selector");
selectorButton.forEach((elem) => {
const button = elem.querySelector("button");
const submenu = elem.querySelector(".ud-submenu");

button.addEventListener("click", () => {
const isExpanded = submenu.classList.toggle("show");
button.setAttribute("aria-expanded", isExpanded ? "true" : "false");

// Focus first menu item when opened
if (isExpanded) {
const firstLink = submenu.querySelector("a");
if (firstLink) {
setTimeout(() => firstLink.focus(), 50);
}
}
});

button.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
button.click();
} else if (e.key === "ArrowDown" || e.key === "ArrowUp") {
e.preventDefault();
if (!submenu.classList.contains("show")) {
button.click();
}
} else if (e.key === "Escape") {
submenu.classList.remove("show");
button.setAttribute("aria-expanded", "false");
}
});

const menuLinks = submenu.querySelectorAll("a");
menuLinks.forEach((link, index) => {
link.addEventListener("keydown", (e) => {
if (e.key === "ArrowDown") {
e.preventDefault();
const nextLink = menuLinks[index + 1] || menuLinks[0];
nextLink.focus();
} else if (e.key === "ArrowUp") {
e.preventDefault();
const prevLink = menuLinks[index - 1] || menuLinks[menuLinks.length - 1];
prevLink.focus();
} else if (e.key === "Escape") {
e.preventDefault();
submenu.classList.remove("show");
button.setAttribute("aria-expanded", "false");
button.focus();
} else if (e.key === "Tab" && !e.shiftKey && index === menuLinks.length - 1) {
// Close menu when tabbing out of last item
submenu.classList.remove("show");
button.setAttribute("aria-expanded", "false");
} else if (e.key === "Tab" && e.shiftKey && index === 0) {
// Close menu when shift-tabbing out of first item
submenu.classList.remove("show");
button.setAttribute("aria-expanded", "false");
}
});
});

document.addEventListener("click", (e) => {
if (!elem.contains(e.target)) {
submenu.classList.remove("show");
button.setAttribute("aria-expanded", "false");
}
});
});

// ====== scroll top js
function scrollTo(element, to = 0, duration = 500) {
const start = element.scrollTop;
Expand Down Expand Up @@ -87,7 +173,46 @@ require('aos/dist/aos.css');
return (-c / 2) * (t * (t - 2) - 1) + b;
};

document.querySelector(".back-to-top").onclick = () => {
scrollTo(document.documentElement);
};
// Back to top button functionality
const backToTopBtn = document.querySelector(".back-to-top");
if (backToTopBtn) {
backToTopBtn.addEventListener("click", (e) => {
e.preventDefault();
scrollTo(document.documentElement);
});

// Keyboard support
backToTopBtn.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
scrollTo(document.documentElement);
}
});
}

// Footer contact functionality
const footerContact = document.querySelector("#footer-contact");
if (footerContact) {
const handleContactClick = () => {
// Add your contact/sales redirect logic here
// For example: window.location.href = '/contact-us' or open a modal
const contactLink = footerContact.getAttribute("data-contact-url");
if (contactLink) {
window.location.href = contactLink;
}
};

footerContact.addEventListener("click", handleContactClick);

// Keyboard support
footerContact.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleContactClick();
}
});
}

// Initialize scroll elements state
handleScrollElements();
})();
Loading
Loading