Initial Commit
This commit is contained in:
commit
6d2e379a0c
41 changed files with 5064 additions and 0 deletions
118
public/scripts/common.js
Normal file
118
public/scripts/common.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
const API_KEY_STORAGE_KEY = "palico-api-key";
|
||||
const DISPLAY_NAME_STORAGE_KEY = "palico-display-name";
|
||||
|
||||
export function getStoredApiKey() {
|
||||
return localStorage.getItem(API_KEY_STORAGE_KEY) || "";
|
||||
}
|
||||
|
||||
export function setStoredApiKey(value) {
|
||||
localStorage.setItem(API_KEY_STORAGE_KEY, value || "");
|
||||
}
|
||||
|
||||
export function getStoredDisplayName() {
|
||||
return localStorage.getItem(DISPLAY_NAME_STORAGE_KEY) || "";
|
||||
}
|
||||
|
||||
export function setStoredDisplayName(value) {
|
||||
localStorage.setItem(DISPLAY_NAME_STORAGE_KEY, value || "");
|
||||
}
|
||||
|
||||
export function createStatusManager(statusElement) {
|
||||
let hideTimeout;
|
||||
|
||||
function setStatus(message, type = "info", autoHide = true) {
|
||||
if (!statusElement) return;
|
||||
statusElement.textContent = message;
|
||||
statusElement.className = `status status--${type}`;
|
||||
statusElement.hidden = false;
|
||||
|
||||
if (autoHide) {
|
||||
clearTimeout(hideTimeout);
|
||||
hideTimeout = setTimeout(() => {
|
||||
statusElement.hidden = true;
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function clearStatus() {
|
||||
if (!statusElement) return;
|
||||
statusElement.hidden = true;
|
||||
statusElement.textContent = "";
|
||||
clearTimeout(hideTimeout);
|
||||
}
|
||||
|
||||
return { setStatus, clearStatus };
|
||||
}
|
||||
|
||||
export function escapeHtml(text = "") {
|
||||
return text
|
||||
.toString()
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
export function formatBytes(bytes = 0) {
|
||||
if (!Number(bytes)) return "0 B";
|
||||
const units = ["B", "KB", "MB", "GB", "TB"];
|
||||
const index = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
return `${(bytes / Math.pow(1024, index)).toFixed(1)} ${units[index]}`;
|
||||
}
|
||||
|
||||
export function formatDate(value) {
|
||||
if (!value) return "?";
|
||||
try {
|
||||
return new Date(value).toLocaleString();
|
||||
} catch (_) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
export function createApiClient({ getApiKey, basePath = "" } = {}) {
|
||||
const normalizedBase = (basePath || "").replace(/\/$/, "");
|
||||
|
||||
return async function apiFetch(path, options = {}) {
|
||||
const url = path.startsWith("http")
|
||||
? path
|
||||
: `${normalizedBase}${path.startsWith("/") ? "" : "/"}${path}`;
|
||||
|
||||
const fetchOptions = {
|
||||
method: options.method || "GET",
|
||||
headers: new Headers(options.headers || {}),
|
||||
};
|
||||
|
||||
const apiKey = typeof getApiKey === "function" ? getApiKey() : null;
|
||||
if (apiKey) {
|
||||
fetchOptions.headers.set("Authorization", `Bearer ${apiKey}`);
|
||||
}
|
||||
|
||||
if (options.body instanceof FormData) {
|
||||
fetchOptions.body = options.body;
|
||||
} else if (options.body) {
|
||||
if (!fetchOptions.headers.has("Content-Type")) {
|
||||
fetchOptions.headers.set("Content-Type", "application/json");
|
||||
}
|
||||
fetchOptions.body =
|
||||
typeof options.body === "string" ? options.body : JSON.stringify(options.body);
|
||||
}
|
||||
|
||||
const response = await fetch(url, fetchOptions);
|
||||
const contentType = response.headers.get("content-type") || "";
|
||||
let payload = null;
|
||||
|
||||
if (contentType.includes("application/json")) {
|
||||
payload = await response.json();
|
||||
} else {
|
||||
payload = await response.text();
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const errorMessage = payload?.error || payload?.message || response.statusText;
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
return payload;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue