Initial commit

This commit is contained in:
Porawit Dongwang
2026-09-16 23:20:08 +07:00
commit 0041668dbb
32577 changed files with 3687927 additions and 0 deletions
@@ -0,0 +1,114 @@
/* Floating Background Animation */
.bg-floating {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
overflow: hidden;
background: #e2e8f0;
}
.dark .bg-floating {
background: #0f172a;
}
.bg-orb {
position: absolute;
border-radius: 50%;
filter: blur(80px);
opacity: 0.35;
animation: float 20s infinite ease-in-out alternate;
}
.bg-orb-1 {
width: 600px;
height: 600px;
top: -100px;
left: -100px;
background: radial-gradient(circle, rgba(16,185,129,0.3) 0%, rgba(16,185,129,0) 70%);
animation-delay: 0s;
}
.bg-orb-2 {
width: 500px;
height: 500px;
bottom: -50px;
right: -50px;
background: radial-gradient(circle, rgba(20,184,166,0.3) 0%, rgba(20,184,166,0) 70%);
animation-delay: -5s;
}
.bg-orb-3 {
width: 400px;
height: 400px;
top: 40%;
left: 30%;
background: radial-gradient(circle, rgba(56,189,248,0.2) 0%, rgba(56,189,248,0) 70%);
animation-delay: -10s;
}
@keyframes float {
0% { transform: translate(0, 0) scale(1); }
33% { transform: translate(30px, -50px) scale(1.1); }
66% { transform: translate(-20px, 20px) scale(0.9); }
100% { transform: translate(0, 0) scale(1); }
}
/* Loading Spinner for Buttons */
.btn-loading {
position: relative;
pointer-events: none;
opacity: 0.8;
}
.btn-loading .text {
visibility: hidden;
}
.btn-loading::after {
content: "";
position: absolute;
width: 1.25rem;
height: 1.25rem;
top: 0; left: 0; bottom: 0; right: 0;
margin: auto;
border: 2px solid transparent;
border-top-color: currentColor;
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Page Transition */
.page-enter {
animation: fadeUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes fadeUp {
0% {
opacity: 0;
transform: translateY(20px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
/* Hide SweetAlert background blur conflicts */
.swal2-backdrop-show {
backdrop-filter: blur(4px);
background: rgba(0,0,0,0.4) !important;
}
.dark .swal2-popup {
background: #1e293b;
color: #f1f5f9;
}
.dark .swal2-title {
color: #f8fafc;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

@@ -0,0 +1,50 @@
// assets/js/location.js
document.addEventListener('DOMContentLoaded', function() {
// Check if the current page is a staff page and if geolocation is supported
if (window.location.search.includes('page=staff')) {
if ("geolocation" in navigator) {
console.log("Geolocation supported. Starting GPS tracking...");
// Watch position updates continuously
navigator.geolocation.watchPosition(
function(position) {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
// Send to server
sendLocationToServer(lat, lng);
},
function(error) {
console.error("Error getting location: ", error);
},
{
enableHighAccuracy: true,
maximumAge: 10000, // 10 seconds
timeout: 5000
}
);
} else {
console.warn("Geolocation is not supported by this browser.");
}
}
});
function sendLocationToServer(lat, lng) {
const formData = new FormData();
formData.append('action', 'update_location');
formData.append('lat', lat);
formData.append('lng', lng);
fetch('api/location.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
// Silently succeed
// console.log("Location updated", data);
})
.catch(error => {
console.error('Error updating location:', error);
});
}
@@ -0,0 +1,53 @@
// assets/js/main.js
document.addEventListener('DOMContentLoaded', function() {
// --- Dark Mode System ---
const themeToggleBtn = document.getElementById('themeToggle');
const htmlElement = document.documentElement;
// Check local storage or system preference
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
htmlElement.classList.add('dark');
} else {
htmlElement.classList.remove('dark');
}
if (themeToggleBtn) {
themeToggleBtn.addEventListener('click', function() {
htmlElement.classList.toggle('dark');
if (htmlElement.classList.contains('dark')) {
localStorage.setItem('theme', 'dark');
} else {
localStorage.setItem('theme', 'light');
}
});
}
// --- Loading Button Global Handling ---
// If a button has 'data-loading-text', it will show a spinner when clicked within a form
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
const submitBtn = form.querySelector('button[type="submit"]');
if (submitBtn) {
// Don't disable immediately if validation is required and fails, but assuming HTML5 validation passes here
submitBtn.classList.add('btn-loading');
// Optional: revert loading state if the form submission is prevented via AJAX in specific page scripts
}
});
});
// --- PWA Service Worker Registration ---
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('sw.js')
.then(registration => {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(err => {
console.log('ServiceWorker registration failed: ', err);
});
});
}
});