Login Logout

This commit is contained in:
Jevinca Marvella 2025-12-05 15:10:47 +07:00
parent 1736e2f4ab
commit f8f7232179
6 changed files with 455 additions and 87 deletions

View File

@ -361,25 +361,6 @@ header {
box-shadow: 0 12px 50px rgba(255, 215, 0, 0.9), 0 0 40px rgba(255, 170, 0, 0.7); box-shadow: 0 12px 50px rgba(255, 215, 0, 0.9), 0 0 40px rgba(255, 170, 0, 0.7);
} }
/* Footer */
footer {
position: relative;
z-index: 10;
text-align: center;
padding: 50px 20px;
margin-top: 150px;
background: rgba(20, 0, 40, 0.7);
backdrop-filter: blur(15px);
border-top: 3px solid rgba(0, 234, 255, 0.4);
box-shadow: 0 -4px 30px rgba(0, 234, 255, 0.2);
}
footer p {
color: rgba(255, 255, 255, 0.65);
font-size: 15px;
font-family: 'Exo 2', sans-serif;
letter-spacing: 1.5px;
}
/* Floating Decoration Elements */ /* Floating Decoration Elements */
.hero::before { .hero::before {

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Homepage</title> <title>Homepage</title>
<link rel="stylesheet" href="Homepage.css"> <link rel="stylesheet" href="Homepage.css">
<link rel="stylesheet" href="Homepage_Credit.css">
</head> </head>
<body> <body>
<!-- Neon Particles Background --> <!-- Neon Particles Background -->
@ -28,11 +29,21 @@
</div> </div>
</section> </section>
<!-- Footer --> <!-- Spacer -->
<br><br><br>
<!-- Footer with Credits -->
<footer>
<hr class="footer-hr">
<div class="credits">
<p class="credits-text">
<strong>2048</strong> - Created by Evelyn Sucitro, Jevinca Marvella Widjaya, and Michelle Aquilera
</p>
</div>
</footer>
<!-- Logout Confirmation Modal --> <!-- Logout Confirmation Modal -->
<div class="logout-overlay" id="logout-overlay" style="display: none"> <div class="logout-overlay" id="logout-overlay" style="display: none">
<div class="logout-modal"> <div class="logout-modal">
<div class="logout-icon"> <div class="logout-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
@ -49,10 +60,10 @@
<button class="btn-logout-confirm" id="btn-logout-confirm">Logout</button> <button class="btn-logout-confirm" id="btn-logout-confirm">Logout</button>
</div> </div>
</div> </div>
</div> </div>
<!-- Logout Success Modal --> <!-- Logout Success Modal -->
<div class="logout-success-overlay" id="logout-success-overlay" style="display: none"> <div class="logout-success-overlay" id="logout-success-overlay" style="display: none">
<div class="logout-success-modal"> <div class="logout-success-modal">
<div class="success-icon"> <div class="success-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
@ -62,10 +73,14 @@
<h2 class="success-title">Logout Successful!</h2> <h2 class="success-title">Logout Successful!</h2>
<p class="success-message">You have been logged out successfully</p> <p class="success-message">You have been logged out successfully</p>
</div> </div>
</div> </div>
<script src="Animation_Homepage.js"></script> <script>
<script src="logout.js"></script> // Auto-update copyright year
<script src="Homepage.js"></script> document.getElementById('currentYear').textContent = new Date().getFullYear();
</script>
<script src="Animation_Homepage.js"></script>
<script src="Homepage.js"></script>
<script src="logout.js"></script>
</body> </body>
</html> </html>

View File

@ -4,7 +4,7 @@
// ==================== DOM ELEMENTS ==================== // ==================== DOM ELEMENTS ====================
const elements = { const elements = {
logo: null, logo: null,
loginBtn: null, loginBtn: null, // Ini akan di-update oleh logout.js
playBtn: null, playBtn: null,
leaderboardBtn: null, leaderboardBtn: null,
heroTitle: null, heroTitle: null,
@ -46,7 +46,9 @@
// ==================== CACHE ELEMENTS ==================== // ==================== CACHE ELEMENTS ====================
function cacheElements() { function cacheElements() {
elements.logo = document.querySelector('.logo'); elements.logo = document.querySelector('.logo');
elements.loginBtn = document.querySelector('a[href="Login.html"]'); // ✅ PERBAIKAN: Jangan cache loginBtn, biar logout.js yang handle
// Cek apakah button Login atau Logout
elements.loginBtn = document.querySelector('.btn-login') || document.querySelector('.btn-logout');
elements.playBtn = document.querySelector('a[href="2048.html"]'); elements.playBtn = document.querySelector('a[href="2048.html"]');
elements.leaderboardBtn = document.querySelector('a[href="leaderboard.html"]'); elements.leaderboardBtn = document.querySelector('a[href="leaderboard.html"]');
elements.heroTitle = document.querySelector('.hero-title'); elements.heroTitle = document.querySelector('.hero-title');
@ -73,10 +75,8 @@
elements.logo.addEventListener('click', handleLogoClick); elements.logo.addEventListener('click', handleLogoClick);
} }
// Login button // ✅ PERBAIKAN: JANGAN tambah event listener ke loginBtn
if (elements.loginBtn) { // Biar logout.js yang handle login/logout button
elements.loginBtn.addEventListener('click', handleLoginClick);
}
// Play button // Play button
if (elements.playBtn) { if (elements.playBtn) {
@ -99,12 +99,7 @@
// ==================== EVENT HANDLERS ==================== // ==================== EVENT HANDLERS ====================
function handleLogoClick(e) { function handleLogoClick(e) {
e.preventDefault(); e.preventDefault();
window.location.href = 'index.html'; window.location.href = 'Homepage.html';
}
function handleLoginClick(e) {
// Allow default behavior (navigate to Login.html)
console.log('Navigating to Login page...');
} }
function handlePlayClick(e) { function handlePlayClick(e) {
@ -125,10 +120,11 @@
} }
} }
// Press 'L' to login // Press 'L' to login (hanya jika belum login)
if (e.key === 'l' || e.key === 'L') { if (e.key === 'l' || e.key === 'L') {
if (elements.loginBtn) { const loginBtn = document.querySelector('.btn-login');
elements.loginBtn.click(); if (loginBtn) {
loginBtn.click();
} }
} }
@ -208,10 +204,6 @@
elements.logo.removeEventListener('click', handleLogoClick); elements.logo.removeEventListener('click', handleLogoClick);
} }
if (elements.loginBtn) {
elements.loginBtn.removeEventListener('click', handleLoginClick);
}
if (elements.playBtn) { if (elements.playBtn) {
elements.playBtn.removeEventListener('click', handlePlayClick); elements.playBtn.removeEventListener('click', handlePlayClick);
} }

354
Homepage_Credit.css Normal file
View File

@ -0,0 +1,354 @@
/* ===========================
HOMEPAGE CREDIT STYLES
File: homepage credit.css
=========================== */
/* HR Line Above Footer */
.footer-hr {
width: 80%;
max-width: 1000px;
height: 3px;
margin: 100px auto 0;
background: linear-gradient(90deg,
transparent 0%,
#00eaff 20%,
#ff00ff 50%,
#00eaff 80%,
transparent 100%);
border: none;
box-shadow:
0 0 20px rgba(0, 234, 255, 0.6),zzz
0 0 40px rgba(255, 0, 255, 0.4);
animation: hrGlow 2s ease-in-out infinite alternate;
position: relative;
z-index: 10;
}
@keyframes hrGlow {
0% {
box-shadow: 0 0 20px rgba(0, 234, 255, 0.6), 0 0 40px rgba(255, 0, 255, 0.4);
}
100% {
box-shadow: 0 0 30px rgba(0, 234, 255, 0.9), 0 0 60px rgba(255, 0, 255, 0.6);
}
}
/* Footer Section - Futuristic Design */
footer {
position: relative;
z-index: 10;
text-align: center;
padding: 80px 40px 60px;
margin-top: 80px;
background: linear-gradient(180deg, rgba(20, 0, 40, 0.4) 0%, rgba(20, 0, 40, 0.9) 100%);
backdrop-filter: blur(25px);
box-shadow: 0 -8px 40px rgba(0, 234, 255, 0.3);
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
min-height: 400px;
}
/* Background Animations */
/* Glowing Orbs Background */
footer::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(0, 234, 255, 0.08), transparent 70%);
border-radius: 50%;
filter: blur(80px);
animation: orbPulse 6s ease-in-out infinite;
pointer-events: none;
}
@keyframes orbPulse {
0%, 100% {
transform: translate(-50%, -50%) scale(1);
opacity: 0.3;
}
50% {
transform: translate(-50%, -50%) scale(1.2);
opacity: 0.5;
}
}
/* Footer Content Container */
.footer-content {
position: relative;
z-index: 2;
max-width: 900px;
margin: 0 auto;
}
/* Credits Container */
.credits {
background: rgba(0, 234, 255, 0.05);
border: 2px solid rgba(0, 234, 255, 0.2);
border-radius: 20px;
padding: 40px 40px 35px;
margin: 0 auto;
max-width: 700px;
backdrop-filter: blur(10px);
box-shadow:
0 8px 32px rgba(0, 234, 255, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
transition: all 0.4s ease;
}
.credits:hover {
transform: translateY(-5px);
border-color: rgba(0, 234, 255, 0.4);
box-shadow:
0 15px 45px rgba(0, 234, 255, 0.25),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
/* Game Title in Credits */
.credits-title {
font-size: 28px;
font-weight: 900;
font-family: 'Orbitron', sans-serif;
background: linear-gradient(135deg, #00d9ff 0%, #ff00ff 50%, #00d9ff 100%);
background-size: 200% 200%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: 4px;
margin-bottom: 25px;
animation: gradientShift 4s ease infinite;
filter: drop-shadow(0 0 20px rgba(0, 234, 255, 0.5));
}
/* "Created by" Label */
.credits-intro {
color: rgba(255, 255, 255, 0.5);
font-size: 12px;
letter-spacing: 3px;
margin-bottom: 20px;
text-transform: uppercase;
font-weight: 600;
font-family: 'Orbitron', sans-serif;
}
/* Creator Names Container */
.creator-names {
display: flex;
flex-direction: column;
gap: 15px;
align-items: center;
margin-bottom: 35px;
}
/* Individual Creator Name */
.creator-name {
background: linear-gradient(135deg, #00d9ff 0%, #ff00ff 50%, #00d9ff 100%);
background-size: 200% 200%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-weight: 900;
font-size: 18px;
letter-spacing: 2px;
font-family: 'Orbitron', sans-serif;
animation: gradientShift 4s ease infinite;
filter: drop-shadow(0 0 15px rgba(0, 234, 255, 0.5));
transition: all 0.3s ease;
position: relative;
padding: 8px 20px;
cursor: default;
}
.creator-name::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(0, 234, 255, 0.1), rgba(255, 0, 255, 0.1));
border-radius: 10px;
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
}
.creator-name:hover::before {
opacity: 1;
}
.creator-name:hover {
transform: scale(1.08);
filter: drop-shadow(0 0 25px rgba(0, 234, 255, 0.9));
animation: gradientShift 1.5s ease infinite, nameFloat 0.6s ease;
}
@keyframes gradientShift {
0%, 100% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
}
@keyframes nameFloat {
0%, 100% {
transform: scale(1.08) translateY(0);
}
50% {
transform: scale(1.08) translateY(-5px);
}
}
/* Separator Dots */
.separator {
color: rgba(0, 234, 255, 0.4);
font-size: 8px;
margin: 0;
animation: separatorPulse 2s ease-in-out infinite;
}
@keyframes separatorPulse {
0%, 100% {
opacity: 0.4;
transform: scale(1);
}
50% {
opacity: 0.8;
transform: scale(1.3);
}
}
/* Divider Line Above Copyright */
.copyright-divider {
width: 100%;
height: 2px;
background: linear-gradient(90deg,
transparent 0%,
rgba(0, 234, 255, 0.3) 20%,
rgba(255, 0, 255, 0.3) 50%,
rgba(0, 234, 255, 0.3) 80%,
transparent 100%);
margin-bottom: 20px;
box-shadow: 0 0 10px rgba(0, 234, 255, 0.3);
}
/* Copyright Text */
.copyright {
color: rgba(255, 255, 255, 0.45);
font-size: 13px;
font-family: 'Exo 2', sans-serif;
letter-spacing: 1.5px;
font-weight: 300;
}
/* Responsive Design */
@media (max-width: 768px) {
.footer-hr {
width: 85%;
margin: 80px auto 0;
}
footer {
padding: 60px 30px 50px;
margin-top: 60px;
min-height: 350px;
}
.credits {
padding: 35px 25px 30px;
max-width: 90%;
}
.credits-title {
font-size: 24px;
letter-spacing: 3px;
}
.creator-name {
font-size: 16px;
letter-spacing: 1.5px;
}
.creator-names {
margin-bottom: 30px;
}
}
@media (max-width: 480px) {
.footer-hr {
width: 90%;
height: 2px;
margin: 60px auto 0;
}
footer {
padding: 50px 20px 40px;
margin-top: 50px;
min-height: 320px;
}
.credits {
padding: 30px 20px 25px;
border-radius: 15px;
}
.credits-title {
font-size: 22px;
letter-spacing: 2px;
margin-bottom: 20px;
}
.credits-intro {
font-size: 11px;
letter-spacing: 2px;
margin-bottom: 15px;
}
.creator-names {
gap: 12px;
margin-bottom: 25px;
}
.creator-name {
font-size: 14px;
letter-spacing: 1px;
padding: 6px 15px;
}
.separator {
font-size: 6px;
}
.copyright {
font-size: 11px;
letter-spacing: 1px;
}
.copyright-divider {
margin-bottom: 15px;
}
}
@media (max-width: 360px) {
.credits-title {
font-size: 20px;
}
.creator-name {
font-size: 13px;
padding: 5px 12px;
}
.credits-intro {
font-size: 10px;
}
.copyright {
font-size: 10px;
}
}

View File

@ -1,7 +1,7 @@
import { showModal, setupModalOk, setupOutsideClose } from "./Modal_Login.js"; import { showModal, setupModalOk, setupOutsideClose } from "./Modal_Login.js";
import { loginRequest } from "./Login_Request.js"; import { loginRequest } from "./Login_Request.js";
// ✅ PENTING: Setup modal saat halaman load // ✅ Setup modal saat halaman load
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
setupModalOk(); setupModalOk();
setupOutsideClose(); setupOutsideClose();
@ -24,13 +24,20 @@ document.getElementById('loginForm').addEventListener('submit', async function(e
try { try {
const data = await loginRequest(username, password); const data = await loginRequest(username, password);
console.log('Response dari server:', data); // Debug console.log('Response dari server:', data);
if (data.success) { if (data.success) {
localStorage.setItem('authToken', data.token); // ✅ PERBAIKAN: Gunakan sessionStorage (sama dengan logout.js)
localStorage.setItem('username', data.username); sessionStorage.setItem('authToken', data.token);
sessionStorage.setItem('loggedInUser', data.username);
showModal('success', 'Login Successful', `Welcome, ${data.username}!`); showModal('success', 'Login Successful', `Welcome, ${data.username}!`);
// ✅ PERBAIKAN: Redirect ke Homepage setelah 1.5 detik
setTimeout(() => {
window.location.href = 'Homepage.html';
}, 1500);
} else { } else {
showModal('error', 'Login Failed', data.message || 'Incorrect username or password'); showModal('error', 'Login Failed', data.message || 'Incorrect username or password');
} }

View File

@ -13,8 +13,14 @@
loginBtn.classList.add('btn-logout'); loginBtn.classList.add('btn-logout');
loginBtn.href = '#'; // Prevent navigation loginBtn.href = '#'; // Prevent navigation
// Add logout click handler // Remove existing click listeners (untuk menghindari duplikat)
loginBtn.addEventListener('click', handleLogoutClick); loginBtn.replaceWith(loginBtn.cloneNode(true));
// Get new reference dan add logout handler
const newLogoutBtn = document.querySelector('.btn-logout');
if (newLogoutBtn) {
newLogoutBtn.addEventListener('click', handleLogoutClick);
}
console.log('✅ User logged in:', loggedInUser); console.log('✅ User logged in:', loggedInUser);
} else { } else {
@ -44,33 +50,42 @@
function setupModalButtons() { function setupModalButtons() {
const cancelBtn = document.getElementById('btn-logout-cancel'); const cancelBtn = document.getElementById('btn-logout-cancel');
const confirmBtn = document.getElementById('btn-logout-confirm'); const confirmBtn = document.getElementById('btn-logout-confirm');
const overlay = document.getElementById('logout-overlay');
// Cancel button // Remove previous listeners
if (cancelBtn) { if (cancelBtn) {
cancelBtn.onclick = closeLogoutModal; const newCancelBtn = cancelBtn.cloneNode(true);
cancelBtn.replaceWith(newCancelBtn);
newCancelBtn.onclick = closeLogoutModal;
} }
// Confirm button
if (confirmBtn) { if (confirmBtn) {
confirmBtn.onclick = confirmLogout; const newConfirmBtn = confirmBtn.cloneNode(true);
confirmBtn.replaceWith(newConfirmBtn);
newConfirmBtn.onclick = confirmLogout;
} }
// Close on overlay click // Close on overlay click
const overlay = document.getElementById('logout-overlay');
if (overlay) { if (overlay) {
overlay.addEventListener('click', function(e) { overlay.onclick = function(e) {
if (e.target === overlay) { if (e.target === overlay) {
closeLogoutModal(); closeLogoutModal();
} }
}); };
} }
// ESC key to close // ESC key to close (gunakan named function agar bisa di-remove)
document.addEventListener('keydown', function(e) { document.addEventListener('keydown', handleEscapeKey);
}
// ==================== HANDLE ESCAPE KEY ====================
function handleEscapeKey(e) {
if (e.key === 'Escape') { if (e.key === 'Escape') {
const overlay = document.getElementById('logout-overlay');
if (overlay && overlay.classList.contains('active')) {
closeLogoutModal(); closeLogoutModal();
} }
}); }
} }
// ==================== CLOSE LOGOUT MODAL ==================== // ==================== CLOSE LOGOUT MODAL ====================
@ -82,12 +97,16 @@
overlay.style.display = 'none'; overlay.style.display = 'none';
}, 300); }, 300);
} }
// Remove escape key listener
document.removeEventListener('keydown', handleEscapeKey);
} }
// ==================== CONFIRM LOGOUT ==================== // ==================== CONFIRM LOGOUT ====================
function confirmLogout() { function confirmLogout() {
// Clear session // Clear semua session data
sessionStorage.removeItem("loggedInUser"); sessionStorage.removeItem("loggedInUser");
sessionStorage.removeItem("authToken");
// Close logout modal // Close logout modal
closeLogoutModal(); closeLogoutModal();
@ -98,7 +117,7 @@
// Redirect after 1.5 seconds // Redirect after 1.5 seconds
setTimeout(() => { setTimeout(() => {
window.location.href = 'Homepage.html'; window.location.href = 'Homepage.html';
}, 2000); }, 1500);
} }
// ==================== SHOW SUCCESS MODAL ==================== // ==================== SHOW SUCCESS MODAL ====================