Files
captain-claude/deck-frontend/src/views/GridView/GridView.ts
ARCHITECT 131e198851 Refactor GraphView with floating sidebar and zoom controls
- Move graph options from left panel to floating sidebar in GraphView
- Add zoom controls (fit, +, -) in top-right corner
- Add dynamic legend showing active categories
- Add cleanup system to View base class for event listeners
- Update delegateEvent to return cleanup function
- Filter nodes by category before rendering
- Fix text color variable (--text-primary to --text)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 00:07:26 +00:00

79 lines
2.2 KiB
TypeScript

import { View } from '../View.ts';
import { filterTags, getName, getImg, delegateEvent } from '@/utils/index.ts';
import type { Store } from '@/state/store.ts';
import type { AppState } from '@/types/index.ts';
export class GridView extends View {
private showDetail: (mrf: string) => void;
constructor(
container: HTMLElement,
store: Store<AppState>,
showDetail: (mrf: string) => void
) {
super(container, store);
this.showDetail = showDetail;
}
render(): void {
const state = this.getState();
const filtered = filterTags(state.tags, {
search: state.search,
group: state.group,
library: state.library,
libraryMembers: state.libraryMembers,
lang: state.lang
});
if (filtered.length === 0) {
this.container.innerHTML = '<div class="empty">Sin resultados</div>';
return;
}
this.container.innerHTML = filtered.map(tag => {
const img = getImg(tag);
const name = getName(tag, state.lang);
const isSelected = state.selected.has(tag.mrf);
return `
<div class="card ${isSelected ? 'selected' : ''}" data-mrf="${tag.mrf}">
${state.selectionMode ? `
<input type="checkbox" class="card-checkbox" ${isSelected ? 'checked' : ''}>
` : ''}
${img
? `<img class="card-img" src="${img}" alt="${tag.ref}" loading="lazy">`
: `<div class="card-placeholder">${tag.ref?.slice(0, 2) || 'T'}</div>`
}
<div class="card-name">${name}</div>
</div>
`;
}).join('');
this.bindEvents();
}
private bindEvents(): void {
this.cleanupListeners();
const cleanup = delegateEvent<MouseEvent>(this.container, '.card', 'click', (_, target) => {
const mrf = target.dataset.mrf;
if (!mrf) return;
// Obtener estado FRESCO en cada click (no del closure)
const state = this.getState();
if (state.selectionMode) {
const newSelected = new Set(state.selected);
if (newSelected.has(mrf)) {
newSelected.delete(mrf);
} else {
newSelected.add(mrf);
}
this.setState({ selected: newSelected });
} else {
this.showDetail(mrf);
}
});
this.addCleanup(cleanup);
}
}