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>
This commit is contained in:
ARCHITECT
2026-01-16 18:26:59 +00:00
parent 17506aaee2
commit 9b244138b5
177 changed files with 15063 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
// === HELPER FUNCTIONS ===
function getName(t) {
return state.lang === "en"
? (t.name_en || t.name_es || t.ref)
: state.lang === "ch"
? (t.name_ch || t.name_en || t.name_es || t.ref)
: (t.name_es || t.name_en || t.ref);
}
function getImg(t) {
return t.img_thumb_url || t.img_url || "";
}
function getFullImg(t) {
return t.img_url || t.img_thumb_url || "";
}
function filterTags() {
let f = [...state.tags];
// Search filter
if (state.search) {
const q = state.search.toLowerCase();
f = f.filter(t =>
(t.ref||"").toLowerCase().includes(q) ||
(t.name_es||"").toLowerCase().includes(q) ||
(t.name_en||"").toLowerCase().includes(q) ||
(t.mrf||"").toLowerCase().includes(q)
);
}
// Group filter
if (state.group !== "all") {
f = f.filter(t => t.set_hst === state.group);
}
// Library filter
if (state.library !== "all" && state.libraryMembers.size) {
f = f.filter(t => state.libraryMembers.has(t.mrf));
}
return f;
}
function toast(msg) {
const t = document.getElementById("toast");
t.textContent = msg;
t.classList.add("show");
setTimeout(() => t.classList.remove("show"), 2500);
}
function copyMrf(mrf) {
navigator.clipboard.writeText(mrf).then(() => toast(`Copiado: ${mrf.slice(0,16)}...`));
}
function closeDetail() {
document.getElementById("right-panel").classList.remove("open");
state.selectedTag = null;
}
function toggleSel(mrf) {
state.selected.has(mrf) ? state.selected.delete(mrf) : state.selected.add(mrf);
updateSelCount();
renderView();
}
function updateSelCount() {
document.getElementById("sel-count").textContent = state.selected.size ? `(${state.selected.size})` : "";
}
function clearSelection() {
state.selected.clear();
state.selectionMode = false;
document.getElementById("btn-sel").classList.remove("active");
updateSelCount();
}