Skip to content

Commit 6cac69f

Browse files
committed
Preview Popup fix and Alertbox
1 parent fb7511b commit 6cac69f

File tree

5 files changed

+104
-92
lines changed

5 files changed

+104
-92
lines changed

src/main/java/de/jadenk/springcloud/security/CustomAuthenticationFailureHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ public void onAuthenticationFailure(HttpServletRequest request,
6868
}
6969

7070
if (locked.get()) {
71-
response.sendRedirect("/login?error=locked");
71+
response.sendRedirect(request.getContextPath() + "/login?error=locked");
7272
} else {
73-
response.sendRedirect("/login?error");
73+
response.sendRedirect(request.getContextPath() + "/login?error");
7474
}
7575
}
7676

src/main/resources/static/css/input.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,13 @@
3535

3636
.popup-container {
3737
@apply bg-[var(--color-bg-alt)] rounded-2xl shadow-2xl p-6 w-[95vw] max-w-lg flex flex-col gap-4;
38+
width: 90vw;
39+
max-height: 80vh;
40+
overflow-y: auto;
41+
}
42+
43+
#previewContainer {
44+
@apply w-full flex justify-center items-center;
45+
max-height: 60vh;
46+
overflow: auto;
3847
}

src/main/resources/static/css/settings.css

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,6 @@ video {
590590

591591
.popup-container {
592592
display: flex;
593-
width: 95vw;
594593
max-width: 32rem;
595594
flex-direction: column;
596595
gap: 1rem;
@@ -600,4 +599,16 @@ video {
600599
--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
601600
--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
602601
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
602+
width: 90vw;
603+
max-height: 80vh;
604+
overflow-y: auto;
605+
}
606+
607+
#previewContainer {
608+
display: flex;
609+
width: 100%;
610+
align-items: center;
611+
justify-content: center;
612+
max-height: 60vh;
613+
overflow: auto;
603614
}

src/main/resources/templates/dashboard.html

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -291,31 +291,33 @@ <h2 class="text-xl font-bold text-[var(--color-primary)]">Upload Your Files</h2>
291291
function closeEditPopup() { editModal.classList.add('hidden'); }
292292

293293
// --- Preview Modal ---
294-
function showPreviewPopup(fileId, fileType, fileName) {
295-
previewContainer.innerHTML = '';
296-
if(fileType.startsWith('image')) {
297-
const img = document.createElement('img');
298-
img.src = '/springcloud/file/' + fileId;
299-
img.className = 'w-full h-auto';
300-
previewContainer.appendChild(img);
301-
} else if(fileType.startsWith('video')) {
302-
const video = document.createElement('video');
303-
video.src = '/springcloud/file/' + fileId;
304-
video.controls = true;
305-
video.className = 'w-full h-auto';
306-
previewContainer.appendChild(video);
307-
} else if(fileType === 'application/pdf') {
308-
const iframe = document.createElement('iframe');
309-
iframe.src = '/springcloud/file/' + fileId;
310-
iframe.className = 'w-full h-full';
311-
previewContainer.appendChild(iframe);
312-
} else {
313-
const pre = document.createElement('pre');
314-
fetch('/springcloud/file/' + fileId).then(r => r.text()).then(t => pre.innerText = t);
315-
previewContainer.appendChild(pre);
316-
}
317-
previewPopup.classList.remove('hidden');
294+
function showPreviewPopup(fileId, fileType, fileName) {
295+
previewContainer.innerHTML = '';
296+
if(fileType.startsWith('image')) {
297+
const img = document.createElement('img');
298+
img.src = '/springcloud/file/' + fileId;
299+
img.className = 'w-auto max-w-full h-auto max-h-[70vh] object-contain';
300+
previewContainer.appendChild(img);
301+
} else if(fileType.startsWith('video')) {
302+
const video = document.createElement('video');
303+
video.src = '/springcloud/file/' + fileId;
304+
video.controls = true;
305+
video.className = 'w-auto max-w-full h-auto max-h-[70vh]';
306+
previewContainer.appendChild(video);
307+
} else if(fileType === 'application/pdf') {
308+
const iframe = document.createElement('iframe');
309+
iframe.src = '/springcloud/file/' + fileId;
310+
iframe.className = 'w-full h-[70vh]';
311+
previewContainer.appendChild(iframe);
312+
} else {
313+
const pre = document.createElement('pre');
314+
pre.className = 'max-h-[70vh] overflow-auto';
315+
fetch('/springcloud/file/' + fileId).then(r => r.text()).then(t => pre.innerText = t);
316+
previewContainer.appendChild(pre);
318317
}
318+
previewPopup.classList.remove('hidden');
319+
}
320+
319321
function closePreviewPopup() { previewPopup.classList.add('hidden'); }
320322

321323
// --- Share Modal ---
Lines changed: 55 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,65 @@
1-
<div th:if="${error}" class="error-box" id="errorBox" th:text="${error}">
2-
<svg class="error-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3-
<circle cx="12" cy="12" r="10"></circle>
4-
<line x1="12" y1="8" x2="12" y2="12"></line>
5-
<line x1="12" y1="16" x2="12" y2="16"></line>
6-
</svg>
7-
<span class="error-message" th:text="${error}">An error has occurred</span>
8-
</div>
1+
<!-- Notification Container -->
2+
<div id="notificationContainer" class="fixed top-5 left-1/2 transform -translate-x-1/2 flex flex-col gap-3 z-[9999]"></div>
93

10-
<style>
11-
.error-box {
12-
position: fixed;
13-
top: -120px;
14-
left: 50%;
15-
transform: translateX(-50%);
16-
background: linear-gradient(135deg, #ff6a6a, #ff3b3b);
17-
color: #fff;
18-
padding: 1rem 2.5rem 1rem 3.5rem;
19-
border-radius: 12px;
20-
box-shadow: 0 8px 20px rgba(255, 59, 59, 0.6);
21-
font-weight: 700;
22-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
23-
z-index: 10000;
24-
opacity: 0;
25-
pointer-events: none;
26-
transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
27-
display: flex;
28-
align-items: center;
29-
gap: 0.8rem;
30-
min-width: 300px;
31-
max-width: 90vw;
32-
}
4+
<!-- Tailwind + Thymeleaf Error Example -->
5+
<div th:if="${error}" class="hidden" data-message-type="error" th:data-message-text="${error}"></div>
6+
<div th:if="${success}" class="hidden" data-message-type="success" th:data-message-text="${success}"></div>
337

34-
.error-box.show {
35-
top: 25px;
36-
opacity: 1;
37-
pointer-events: auto;
38-
animation: slideBounce 0.6s ease forwards;
39-
}
8+
<script>
9+
function createNotification(message, type = 'error', duration = 5000) {
10+
const container = document.getElementById('notificationContainer');
4011

41-
.error-icon {
42-
width: 24px;
43-
height: 24px;
44-
stroke: #fff;
45-
flex-shrink: 0;
46-
animation: pulse 1.5s infinite;
47-
}
12+
// Farben und Icons
13+
const config = {
14+
error: {
15+
bg: 'bg-gradient-to-r from-red-600 to-red-500',
16+
icon: `<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
17+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M12 2a10 10 0 11-0 20 10 10 0 010-20z" />
18+
</svg>`
19+
},
20+
success: {
21+
bg: 'bg-gradient-to-r from-green-500 to-green-400',
22+
icon: `<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
23+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
24+
</svg>`
25+
}
26+
};
4827

49-
.error-message {
50-
font-size: 1.1rem;
51-
line-height: 1.3;
52-
user-select: none;
53-
}
28+
const notif = document.createElement('div');
29+
notif.className = `${config[type].bg} text-white rounded-xl shadow-lg p-4 flex items-center gap-3 pointer-events-auto transform transition duration-500 scale-95 opacity-0`;
30+
notif.innerHTML = `
31+
${config[type].icon}
32+
<span class="font-semibold text-sm md:text-base">${message}</span>
33+
<button class="ml-auto text-white hover:text-gray-200">&times;</button>
34+
`;
5435

55-
@keyframes slideBounce {
56-
0% { top: -120px; }
57-
70% { top: 30px; }
58-
100% { top: 25px; }
59-
}
36+
// Close Button
37+
notif.querySelector('button').addEventListener('click', () => {
38+
notif.classList.remove('scale-100', 'opacity-100');
39+
notif.classList.add('scale-95', 'opacity-0');
40+
setTimeout(() => notif.remove(), 400);
41+
});
42+
43+
container.appendChild(notif);
6044

61-
@keyframes pulse {
62-
0%, 100% { opacity: 1; }
63-
50% { opacity: 0.6; }
45+
// Animate in
46+
setTimeout(() => {
47+
notif.classList.remove('scale-95', 'opacity-0');
48+
notif.classList.add('scale-100', 'opacity-100');
49+
}, 50);
50+
51+
// Auto-remove after duration
52+
setTimeout(() => {
53+
notif.classList.remove('scale-100', 'opacity-100');
54+
notif.classList.add('scale-95', 'opacity-0');
55+
setTimeout(() => notif.remove(), 400);
56+
}, duration);
6457
}
65-
</style>
6658

67-
<script>
68-
window.addEventListener('DOMContentLoaded', () => {
69-
const box = document.getElementById('errorBox');
70-
if (box) {
71-
setTimeout(() => box.classList.add('show'), 100);
72-
setTimeout(() => box.classList.remove('show'), 5100);
73-
}
59+
// --- Auto-detect Thymeleaf messages ---
60+
document.querySelectorAll('[data-message-text]').forEach(el => {
61+
const type = el.getAttribute('data-message-type');
62+
const msg = el.getAttribute('data-message-text');
63+
if(msg) createNotification(msg, type);
7464
});
7565
</script>

0 commit comments

Comments
 (0)