Files
ARCHITECT 9b244138b5 Add pending apps and frontend components
- 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>
2026-01-16 18:26:59 +00:00

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();
});