Create templates/base.html
Browse files- templates/base.html +86 -0
templates/base.html
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="id">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Galeri Angkatan</title>
|
| 7 |
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
| 8 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
| 9 |
+
<style>
|
| 10 |
+
body { background: linear-gradient(135deg, #667eea, #764ba2); min-height: 100vh; }
|
| 11 |
+
.navbar { background: rgba(255,255,255,0.95); backdrop-filter: blur(10px); }
|
| 12 |
+
.loading-screen {
|
| 13 |
+
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
| 14 |
+
background: linear-gradient(135deg, #667eea, #764ba2);
|
| 15 |
+
z-index: 9999; display: flex; justify-content: center; align-items: center;
|
| 16 |
+
transition: opacity 0.5s;
|
| 17 |
+
}
|
| 18 |
+
.loading-screen.hidden { opacity: 0; pointer-events: none; }
|
| 19 |
+
.loading-slideshow { width: 100%; max-width: 600px; height: 300px;
|
| 20 |
+
border-radius: 15px; overflow: hidden; margin: 20px auto;
|
| 21 |
+
background-size: cover; background-position: center; }
|
| 22 |
+
.photo-card { transition: transform 0.3s; border: none; border-radius: 15px; overflow: hidden; }
|
| 23 |
+
.photo-card:hover { transform: translateY(-10px); box-shadow: 0 10px 30px rgba(0,0,0,0.2); }
|
| 24 |
+
.photo-card img { height: 250px; object-fit: cover; }
|
| 25 |
+
@media (max-width: 768px) {
|
| 26 |
+
.photo-card img { height: 200px; }
|
| 27 |
+
.loading-slideshow { height: 200px; }
|
| 28 |
+
}
|
| 29 |
+
</style>
|
| 30 |
+
</head>
|
| 31 |
+
<body>
|
| 32 |
+
<div id="loadingScreen" class="loading-screen">
|
| 33 |
+
<div class="text-center text-white">
|
| 34 |
+
<h3>Loading Galeri Angkatan...</h3>
|
| 35 |
+
<div id="slideshow" class="loading-slideshow"></div>
|
| 36 |
+
<div class="spinner-border mt-3" role="status"></div>
|
| 37 |
+
</div>
|
| 38 |
+
</div>
|
| 39 |
+
|
| 40 |
+
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
| 41 |
+
<div class="container">
|
| 42 |
+
<a class="navbar-brand" href="/"><i class="bi bi-images"></i> Galeri Angkatan</a>
|
| 43 |
+
<div class="navbar-nav ms-auto">
|
| 44 |
+
{% if user %}
|
| 45 |
+
<span class="nav-link text-white"><i class="bi bi-person-circle"></i> {{ user.username }}</span>
|
| 46 |
+
{% if user.is_admin %}
|
| 47 |
+
<a class="nav-link" href="/admin"><i class="bi bi-shield-lock"></i> Admin</a>
|
| 48 |
+
{% endif %}
|
| 49 |
+
<a class="nav-link" href="/logout"><i class="bi bi-box-arrow-right"></i> Logout</a>
|
| 50 |
+
{% else %}
|
| 51 |
+
<a class="nav-link" href="/login"><i class="bi bi-box-arrow-in-right"></i> Login Admin</a>
|
| 52 |
+
{% endif %}
|
| 53 |
+
</div>
|
| 54 |
+
</div>
|
| 55 |
+
</nav>
|
| 56 |
+
|
| 57 |
+
<div class="container mt-3">
|
| 58 |
+
{% with messages = get_flashed_messages(with_categories=true) %}
|
| 59 |
+
{% if messages %}
|
| 60 |
+
{% for category, message in messages %}
|
| 61 |
+
<div class="alert alert-{{ category }} alert-dismissible fade show">{{ message }}</div>
|
| 62 |
+
{% endfor %}
|
| 63 |
+
{% endif %}
|
| 64 |
+
{% endwith %}
|
| 65 |
+
</div>
|
| 66 |
+
|
| 67 |
+
<main class="container my-4">
|
| 68 |
+
{% block content %}{% endblock %}
|
| 69 |
+
</main>
|
| 70 |
+
|
| 71 |
+
<script>
|
| 72 |
+
fetch('/slideshow').then(r=>r.json()).then(photos=>{
|
| 73 |
+
if(photos.length){
|
| 74 |
+
let i=0;
|
| 75 |
+
const s=document.getElementById('slideshow');
|
| 76 |
+
s.style.backgroundImage=`url(/static/uploads/${photos[0]})`;
|
| 77 |
+
setInterval(()=>{
|
| 78 |
+
i=(i+1)%photos.length;
|
| 79 |
+
s.style.backgroundImage=`url(/static/uploads/${photos[i]})`;
|
| 80 |
+
},2000);
|
| 81 |
+
}
|
| 82 |
+
});
|
| 83 |
+
setTimeout(()=>document.getElementById('loadingScreen').classList.add('hidden'),3000);
|
| 84 |
+
</script>
|
| 85 |
+
</body>
|
| 86 |
+
</html>
|