Skip to content

Commit 334a014

Browse files
committed
v3.0.0
1 parent f283e90 commit 334a014

File tree

5 files changed

+221
-6
lines changed

5 files changed

+221
-6
lines changed

frontend/css/home.css

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,114 @@ td a:hover {
257257
margin-bottom: 10px;
258258
}
259259

260+
.toast-container {
261+
position: fixed;
262+
top: 20px;
263+
right: 20px;
264+
z-index: 1000;
265+
display: flex;
266+
flex-direction: column;
267+
gap: 10px;
268+
max-width: 400px;
269+
}
270+
271+
.toast {
272+
padding: 12px 16px;
273+
border-radius: 8px;
274+
box-shadow: var(--shadow-lg);
275+
display: flex;
276+
align-items: center;
277+
gap: 12px;
278+
animation: slideInRight 0.3s ease-out;
279+
transition: all 0.3s ease;
280+
transform: translateX(0);
281+
background: white;
282+
border-left: 4px solid;
283+
}
284+
285+
.toast.hiding {
286+
animation: slideOutRight 0.3s ease-in forwards;
287+
}
288+
289+
.toast-success {
290+
border-left-color: var(--success);
291+
color: var(--text);
292+
}
293+
294+
.toast-error {
295+
border-left-color: var(--error);
296+
color: var(--text);
297+
}
298+
299+
.toast-info {
300+
border-left-color: var(--accent-1);
301+
color: var(--text);
302+
}
303+
304+
.toast-icon {
305+
font-size: 1.2rem;
306+
flex-shrink: 0;
307+
}
308+
309+
.toast-success .toast-icon {
310+
color: var(--success);
311+
}
312+
313+
.toast-error .toast-icon {
314+
color: var(--error);
315+
}
316+
317+
.toast-info .toast-icon {
318+
color: var(--accent-1);
319+
}
320+
321+
.toast-content {
322+
flex: 1;
323+
font-size: 0.9rem;
324+
font-weight: 500;
325+
}
326+
327+
.toast-close {
328+
background: none;
329+
border: none;
330+
font-size: 1rem;
331+
cursor: pointer;
332+
opacity: 0.7;
333+
padding: 4px;
334+
border-radius: 4px;
335+
transition: opacity 0.2s ease;
336+
color: inherit;
337+
}
338+
339+
.toast-close:hover {
340+
opacity: 1;
341+
background: rgba(0, 0, 0, 0.1);
342+
}
343+
344+
@keyframes slideInRight {
345+
from {
346+
transform: translateX(100%);
347+
opacity: 0;
348+
}
349+
350+
to {
351+
transform: translateX(0);
352+
opacity: 1;
353+
}
354+
}
355+
356+
@keyframes slideOutRight {
357+
from {
358+
transform: translateX(0);
359+
opacity: 1;
360+
}
361+
362+
to {
363+
transform: translateX(100%);
364+
opacity: 0;
365+
}
366+
}
367+
260368
@media (max-width: 768px) {
261369
body {
262370
padding: 10px;
@@ -299,6 +407,17 @@ td a:hover {
299407
td {
300408
padding: 10px 8px;
301409
}
410+
411+
.toast-container {
412+
top: 10px;
413+
right: 10px;
414+
left: 10px;
415+
max-width: none;
416+
}
417+
418+
.toast {
419+
padding: 10px 14px;
420+
}
302421
}
303422

304423
@media (max-width: 480px) {
@@ -332,6 +451,20 @@ td a:hover {
332451
.loading {
333452
padding: 20px 10px;
334453
}
454+
455+
.toast-container {
456+
top: 5px;
457+
right: 5px;
458+
left: 5px;
459+
}
460+
461+
.toast {
462+
padding: 8px 12px;
463+
}
464+
465+
.toast-content {
466+
font-size: 0.85rem;
467+
}
335468
}
336469

337470
@media (min-width: 769px) and (max-width: 1024px) {

frontend/home.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@
6666
</table>
6767
</div>
6868
</div>
69+
70+
<div id="toastContainer" class="toast-container"></div>
71+
6972
<script src="js/home.js"></script>
7073
</body>
7174
</html>

frontend/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ <h2 class="section-title">Ready to Get Started?</h2>
135135
Simple, secure, and completely under your control.
136136
</p>
137137
<a
138-
href="https://github.com/8gudbits/QuickServe/releases"
138+
href="https://github.com/8gudbits/QuickServe"
139139
class="btn btn-primary"
140140
style="font-size: 1.2rem; padding: 15px 40px"
141141
target="_blank"

frontend/js/home.js

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class QuickServeClient {
6363
`${this.serverUrl}/api/files?path=${encodeURIComponent(path)}`,
6464
{
6565
headers: this.getAuthHeaders(),
66+
credentials: "include",
6667
}
6768
);
6869

@@ -154,6 +155,7 @@ class QuickServeClient {
154155
)}`,
155156
{
156157
headers: this.getAuthHeaders(),
158+
credentials: "include",
157159
}
158160
);
159161

@@ -186,13 +188,13 @@ class QuickServeClient {
186188
try {
187189
const response = await fetch(`${this.serverUrl}/api/upload`, {
188190
method: "POST",
189-
headers: this.getAuthHeaders(false),
191+
credentials: "include",
190192
body: formData,
191193
});
192194

193195
if (response.ok) {
194196
await this.loadFiles(currentPath);
195-
this.showTempMessage("Upload successful!");
197+
this.showSuccess("Upload successful!");
196198
} else {
197199
throw new Error("Upload failed");
198200
}
@@ -206,6 +208,10 @@ class QuickServeClient {
206208
if (isJson) {
207209
headers["Content-Type"] = "application/json";
208210
}
211+
212+
const authString = btoa(`${this.username}:${this.password}`);
213+
headers["Authorization"] = `Basic ${authString}`;
214+
209215
return headers;
210216
}
211217

@@ -233,16 +239,75 @@ class QuickServeClient {
233239
}
234240

235241
showError(message) {
236-
alert(message);
242+
this.showToast(message, "error");
243+
}
244+
245+
showSuccess(message) {
246+
this.showToast(message, "success");
247+
}
248+
249+
showInfo(message) {
250+
this.showToast(message, "info");
251+
}
252+
253+
showToast(message, type = "info", duration = 5000) {
254+
const toastContainer = document.getElementById("toastContainer");
255+
256+
const toast = document.createElement("div");
257+
toast.className = `toast toast-${type}`;
258+
259+
let icon = "info-circle";
260+
if (type === "success") icon = "check-circle";
261+
if (type === "error") icon = "exclamation-circle";
262+
263+
toast.innerHTML = `
264+
<i class="fas fa-${icon} toast-icon"></i>
265+
<div class="toast-content">${message}</div>
266+
<button class="toast-close" aria-label="Close notification">
267+
<i class="fas fa-times"></i>
268+
</button>
269+
`;
270+
271+
toastContainer.appendChild(toast);
272+
273+
let removeTimeout;
274+
if (duration > 0) {
275+
removeTimeout = setTimeout(() => {
276+
this.removeToast(toast);
277+
}, duration);
278+
}
279+
280+
const closeBtn = toast.querySelector(".toast-close");
281+
closeBtn.addEventListener("click", () => {
282+
if (removeTimeout) clearTimeout(removeTimeout);
283+
this.removeToast(toast);
284+
});
285+
286+
return toast;
287+
}
288+
289+
removeToast(toast) {
290+
toast.classList.add("hiding");
291+
setTimeout(() => {
292+
if (toast.parentNode) {
293+
toast.parentNode.removeChild(toast);
294+
}
295+
}, 300);
237296
}
238297

239298
showTempMessage(message) {
240299
const uploadLabel = document.getElementById("uploadLabel");
241300
const originalText = uploadLabel.innerHTML;
242-
uploadLabel.innerHTML = `<i class="fas fa-check"></i> ${message}`;
301+
302+
this.showSuccess(message);
303+
304+
uploadLabel.innerHTML = `<i class="fas fa-check"></i> Uploaded`;
305+
uploadLabel.style.opacity = "0.7";
306+
243307
setTimeout(() => {
244308
uploadLabel.innerHTML = originalText;
245-
}, 2000);
309+
uploadLabel.style.opacity = "1";
310+
}, 1500);
246311
}
247312

248313
updateNavigation(currentPath) {

frontend/js/login.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ const loginForm = document.getElementById("loginForm");
55
const errorMessage = document.getElementById("errorMessage");
66
const submitBtn = document.getElementById("submitBtn");
77

8+
document.addEventListener("DOMContentLoaded", function () {
9+
resetSubmitButton();
10+
});
11+
812
togglePassword.addEventListener("click", function () {
913
const type =
1014
password.getAttribute("type") === "password" ? "text" : "password";
@@ -88,6 +92,7 @@ function showError(message) {
8892

8993
function resetSubmitButton() {
9094
submitBtn.disabled = false;
95+
submitBtn.textContent = "CONNECT TO SERVER";
9196
submitBtn.innerHTML = "CONNECT TO SERVER";
9297
}
9398

@@ -99,3 +104,12 @@ window.addEventListener("load", function () {
99104
}
100105
});
101106

107+
window.addEventListener("pageshow", function (event) {
108+
if (
109+
event.persisted ||
110+
(window.performance && window.performance.navigation.type === 2)
111+
) {
112+
resetSubmitButton();
113+
}
114+
});
115+

0 commit comments

Comments
 (0)