- apps/captain-mobile: Mobile API service - apps/flow-ui: Flow UI application - apps/mindlink: Mindlink application - apps/storage: Storage API and workers - apps/tzzr-cli: TZZR CLI tool - deck-frontend/backups: Historical TypeScript versions - hst-frontend: Standalone HST frontend Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
149 lines
4.5 KiB
JavaScript
149 lines
4.5 KiB
JavaScript
// === APPLICATION INIT ===
|
|
|
|
function parseHash() {
|
|
const h = window.location.hash.replace(/^#\/?/, "").replace(/\/?$/, "").split("/").filter(Boolean);
|
|
if (h[0] && ["hst","flg","itm","loc","ply"].includes(h[0].toLowerCase())) {
|
|
state.base = h[0].toLowerCase();
|
|
}
|
|
if (h[1] && ["grid","tree","graph"].includes(h[1].toLowerCase())) {
|
|
state.view = h[1].toLowerCase();
|
|
}
|
|
}
|
|
|
|
function updateHash() {
|
|
const p = [state.base];
|
|
if (state.view !== "grid") p.push(state.view);
|
|
window.location.hash = "/" + p.join("/") + "/";
|
|
}
|
|
|
|
async function init() {
|
|
parseHash();
|
|
|
|
// Update UI to match state
|
|
document.querySelectorAll(".base-btn").forEach(b =>
|
|
b.classList.toggle("active", b.dataset.base === state.base)
|
|
);
|
|
document.querySelectorAll(".view-tab").forEach(t =>
|
|
t.classList.toggle("active", t.dataset.view === state.view)
|
|
);
|
|
|
|
// Show loading
|
|
document.getElementById("grid-view").innerHTML = '<div class="loading">Cargando</div>';
|
|
|
|
// Fetch initial data
|
|
await Promise.all([fetchTags(), fetchGroups(), fetchLibraries()]);
|
|
|
|
// Render UI
|
|
renderGroups();
|
|
renderLibraries();
|
|
renderView();
|
|
}
|
|
|
|
// === EVENT BINDINGS ===
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
// Base selector
|
|
document.querySelectorAll(".base-btn").forEach(b => b.onclick = async () => {
|
|
document.querySelectorAll(".base-btn").forEach(x => x.classList.remove("active"));
|
|
b.classList.add("active");
|
|
state.base = b.dataset.base;
|
|
|
|
// Reset state
|
|
state.group = "all";
|
|
state.library = "all";
|
|
state.libraryMembers.clear();
|
|
state.search = "";
|
|
state.graphEdges = [];
|
|
state.treeEdges = [];
|
|
clearSelection();
|
|
closeDetail();
|
|
document.getElementById("search").value = "";
|
|
updateHash();
|
|
|
|
// Reload
|
|
document.getElementById("grid-view").innerHTML = '<div class="loading">Cargando</div>';
|
|
await fetchTags();
|
|
await fetchGroups();
|
|
renderGroups();
|
|
renderView();
|
|
});
|
|
|
|
// View tabs
|
|
document.querySelectorAll(".view-tab").forEach(t => t.onclick = () => {
|
|
document.querySelectorAll(".view-tab").forEach(x => x.classList.remove("active"));
|
|
t.classList.add("active");
|
|
state.view = t.dataset.view;
|
|
updateHash();
|
|
closeDetail();
|
|
renderView();
|
|
});
|
|
|
|
// Search
|
|
let st;
|
|
document.getElementById("search").oninput = e => {
|
|
clearTimeout(st);
|
|
st = setTimeout(() => {
|
|
state.search = e.target.value;
|
|
renderView();
|
|
}, 200);
|
|
};
|
|
|
|
// Language selector
|
|
document.getElementById("lang-select").addEventListener("change", function(e) {
|
|
state.lang = this.value;
|
|
renderView();
|
|
if (state.selectedTag) showDetail(state.selectedTag.mrf);
|
|
});
|
|
|
|
// Selection mode
|
|
document.getElementById("btn-sel").onclick = () => {
|
|
state.selectionMode = !state.selectionMode;
|
|
document.getElementById("btn-sel").classList.toggle("active", state.selectionMode);
|
|
if (!state.selectionMode) {
|
|
state.selected.clear();
|
|
updateSelCount();
|
|
}
|
|
renderView();
|
|
};
|
|
|
|
// Get selected
|
|
document.getElementById("btn-get").onclick = () => {
|
|
if (!state.selected.size) return toast("No hay seleccionados");
|
|
navigator.clipboard.writeText([...state.selected].join("\n"))
|
|
.then(() => toast(`Copiados ${state.selected.size} mrfs`));
|
|
};
|
|
|
|
// API modal
|
|
document.getElementById("btn-api").onclick = () =>
|
|
document.getElementById("api-modal").classList.add("open");
|
|
document.getElementById("api-modal-close").onclick = () =>
|
|
document.getElementById("api-modal").classList.remove("open");
|
|
document.getElementById("api-modal").onclick = e => {
|
|
if (e.target.id === "api-modal") e.target.classList.remove("open");
|
|
};
|
|
|
|
// Hash change
|
|
window.onhashchange = () => {
|
|
parseHash();
|
|
init();
|
|
};
|
|
|
|
// Keyboard shortcuts
|
|
document.onkeydown = e => {
|
|
if (e.key === "Escape") {
|
|
closeDetail();
|
|
document.getElementById("api-modal").classList.remove("open");
|
|
if (state.selectionMode) {
|
|
clearSelection();
|
|
renderView();
|
|
}
|
|
}
|
|
if (e.key === "/" && document.activeElement.tagName !== "INPUT") {
|
|
e.preventDefault();
|
|
document.getElementById("search").focus();
|
|
}
|
|
};
|
|
|
|
// Start app
|
|
init();
|
|
});
|