Added Events module for inter-component communication:
- Events.on(event, handler) - subscribe
- Events.off(event, handler) - unsubscribe
- Events.emit(event, data) - publish
Decoupled:
- GroupsBar → Events.emit('render') instead of App.renderView()
- LibrariesPanel → Events.emit('render')
- GraphView sidebar → Events.emit('render')
- GraphView node click → Events.emit('detail:show', mrf)
App subscribes to events in init():
- Events.on('render', () => this.renderView())
- Events.on('detail:show', (mrf) => DetailPanel.show(mrf))
Now modules don't know about each other - changes are isolated.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
DECK Frontend - Vite + TypeScript
Frontend modular para visualización de tags semánticos TZZR (HST/FLG/ITM/LOC/PLY).
Stack
- Vite - Bundler con HMR
- TypeScript - Tipado estático
- ES6 Modules - import/export
- D3.js - Lazy loading solo en GraphView
Estructura
src/
├── main.ts # Bootstrap y App principal
├── types/ # Interfaces TypeScript
│ ├── tag.ts # Tag, Group, Library, ChildTag, RelatedTag
│ ├── state.ts # AppState, ViewType, BaseType
│ └── graph.ts # GraphNode, GraphEdge, EdgeType
├── config/ # Constantes
│ ├── api.ts # API_BASE
│ ├── categories.ts # CATS (colores por categoría)
│ └── edges.ts # EDGE_COLORS
├── state/ # Store reactivo
│ ├── store.ts # createStore<T>()
│ └── index.ts # Estado inicial
├── api/ # Fetch tipado
│ ├── client.ts # apiClient<T>(), apiClientSafe<T>()
│ ├── tags.ts # fetchTags, fetchHstTags, fetchChildren, fetchRelated
│ ├── groups.ts # fetchGroups
│ ├── libraries.ts # fetchLibraries, fetchLibraryMembers
│ └── graph.ts # fetchGraphEdges, fetchTreeEdges
├── utils/ # Helpers puros
│ ├── dom.ts # $, $$, createElement, delegateEvent
│ ├── i18n.ts # getName, getImg, createNameMap, resolveGroupName
│ ├── filters.ts # filterTags
│ ├── clipboard.ts # copyToClipboard, copyMrf
│ └── toast.ts # toast()
├── components/ # Componentes reutilizables
│ ├── Component.ts # Clase base
│ ├── Card/
│ ├── TagChip/
│ └── Toast/
├── views/ # Vistas principales
│ ├── View.ts # Clase base
│ ├── GridView/ # Vista de tarjetas
│ ├── TreeView/ # Vista de árbol agrupado
│ ├── GraphView/ # Grafo D3 (lazy load)
│ └── DetailPanel/ # Panel lateral de detalle
├── router/ # Hash routing
│ └── index.ts # Router con parseHash/updateHash
└── styles/
└── main.css # Estilos globales
Resolución de Nombres
Prioridad de campos para mostrar nombres
name_es/name_en/name_ch(según idioma)aliasrefmrf.slice(0, 8)(fallback a hash truncado)
Resolución de grupos (set_hst)
El campo set_hst contiene el MRF de un tag HST que representa la categoría.
Para resolver el nombre del grupo:
- Se cargan siempre los tags de HST (
fetchHstTags) - Se crea un mapa
mrf → nombreconcreateNameMap(hstTags, lang) - Se resuelve el nombre con
resolveGroupName(set_hst, nameMap)
Esto permite que al ver cualquier base (flg, itm, loc, ply), los grupos muestren nombres legibles en lugar de hashes.
API Endpoints
| Endpoint | Descripción |
|---|---|
GET /api/{base} |
Lista tags (hst, flg, itm, loc, ply) |
GET /api/hst?select=... |
Tags HST para resolver nombres |
POST /api/rpc/api_children |
Hijos de un tag |
POST /api/rpc/api_related |
Tags relacionados |
GET /api/graph_hst |
Relaciones del grafo |
GET /api/tree_hst |
Jerarquías |
GET /api/groups |
Grupos disponibles |
GET /api/library_hst |
Bibliotecas |
POST /api/rpc/library_members |
Miembros de biblioteca |
Comandos
# Desarrollo
npm run dev
# Build producción
npm run build
# Preview build
npm run preview
# Lint
npm run lint
Despliegue
# Build
npm run build
# Deploy a DECK
scp -r dist/* root@72.62.1.113:/opt/hst/web/
URLs
- DECK: https://tzzrdeck.me
- HST: https://hst.tzzrdeck.me
- API: https://tzzrdeck.me/api/
Layout
┌─────────────────────────────────────────────────────────────┐
│ TOPBAR: Logo | Lang | API | SEL | GET | Bases | Search | View │
├─────────────────────────────────────────────────────────────┤
│ GROUPS BAR: Todos | Grupo1 | Grupo2 | ... │
├────────┬────────────────────────────────────┬───────────────┤
│ │ │ │
│ LEFT │ CONTENT AREA │ DETAIL │
│ PANEL │ (Grid / Tree / Graph) │ PANEL │
│ │ │ │
│ Libs │ │ (slide-in) │
│ │ │ │
└────────┴────────────────────────────────────┴───────────────┘
State
interface AppState {
// Navegación
base: 'hst' | 'flg' | 'itm' | 'loc' | 'ply';
lang: 'es' | 'en' | 'ch';
view: 'grid' | 'tree' | 'graph';
// Filtros
search: string;
group: string; // MRF del grupo o 'all'
library: string; // MRF de biblioteca o 'all'
libraryMembers: Set<string>;
// Selección
selectionMode: boolean;
selected: Set<string>;
selectedTag: Tag | null;
// Datos
tags: Tag[]; // Tags de la base actual
hstTags: Tag[]; // Tags HST para resolver nombres de grupos
groups: Group[];
libraries: Library[];
graphEdges: GraphEdge[];
treeEdges: TreeEdge[];
// Grafo
graphFilters: { cats: Set, edges: Set };
graphSettings: { nodeSize, linkDist, showImg, showLbl };
}
Changelog
2026-01-13
- Migrado de vanilla JS a Vite + TypeScript
- Añadido panel izquierdo de bibliotecas
- Implementada resolución de nombres para grupos (set_hst → nombre)
- Prioridad de nombres: name_es → alias → ref → hash
- D3 lazy loading en GraphView
- Layout de 3 paneles (left, center, detail)