mirror of
https://github.com/wowlikon/LiB.git
synced 2026-02-04 04:31:09 +00:00
124 lines
3.1 KiB
JavaScript
124 lines
3.1 KiB
JavaScript
const Utils = {
|
|
escapeHtml: (text) => {
|
|
if (!text) return "";
|
|
return text.replace(/[&<>"']/g, function (m) {
|
|
return {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
}[m];
|
|
});
|
|
},
|
|
|
|
showToast: (message, type = "info") => {
|
|
const container = document.getElementById("toast-container");
|
|
if (!container) return;
|
|
|
|
const el = document.createElement("div");
|
|
const colors =
|
|
type === "error"
|
|
? "bg-red-500"
|
|
: type === "success"
|
|
? "bg-green-500"
|
|
: "bg-blue-500";
|
|
el.className = `${colors} text-white px-6 py-3 rounded shadow-lg transform transition-all duration-300 translate-y-10 opacity-0 mb-3`;
|
|
el.textContent = message;
|
|
|
|
container.appendChild(el);
|
|
|
|
requestAnimationFrame(() => {
|
|
el.classList.remove("translate-y-10", "opacity-0");
|
|
});
|
|
|
|
setTimeout(() => {
|
|
el.classList.add("translate-y-10", "opacity-0");
|
|
setTimeout(() => el.remove(), 300);
|
|
}, 3000);
|
|
},
|
|
|
|
getGravatarUrl: async (email) => {
|
|
if (!email) return "";
|
|
const msgBuffer = new TextEncoder().encode(email.trim().toLowerCase());
|
|
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
|
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
const hashHex = hashArray
|
|
.map((b) => b.toString(16).padStart(2, "0"))
|
|
.join("");
|
|
return `https://www.gravatar.com/avatar/${hashHex}?d=identicon&s=200`;
|
|
},
|
|
};
|
|
|
|
const Api = {
|
|
async request(endpoint, options = {}) {
|
|
const token = localStorage.getItem("access_token");
|
|
const headers = {
|
|
"Content-Type": "application/json",
|
|
...options.headers,
|
|
};
|
|
|
|
if (token) {
|
|
headers["Authorization"] = `Bearer ${token}`;
|
|
}
|
|
|
|
const config = { ...options, headers };
|
|
|
|
try {
|
|
const response = await fetch(endpoint, config);
|
|
if (response.status === 401) {
|
|
Auth.logout();
|
|
return null;
|
|
}
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(errorData.detail || `Error ${response.status}`);
|
|
}
|
|
return response.json();
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
get(endpoint) {
|
|
return this.request(endpoint, { method: "GET" });
|
|
},
|
|
|
|
post(endpoint, body) {
|
|
return this.request(endpoint, {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
});
|
|
},
|
|
|
|
postForm(endpoint, formData) {
|
|
return this.request(endpoint, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
body: formData.toString(),
|
|
});
|
|
},
|
|
};
|
|
|
|
const Auth = {
|
|
logout: () => {
|
|
localStorage.removeItem("access_token");
|
|
localStorage.removeItem("refresh_token");
|
|
window.location.reload();
|
|
},
|
|
|
|
init: async () => {
|
|
const token = localStorage.getItem("access_token");
|
|
if (!token) return;
|
|
|
|
try {
|
|
const user = await Api.get("/api/auth/me");
|
|
if (user) {
|
|
document.dispatchEvent(new CustomEvent("auth:login", { detail: user }));
|
|
}
|
|
} catch (e) {
|
|
console.error("Auth check failed", e);
|
|
}
|
|
},
|
|
};
|