diff --git a/deck-frontend/index.html b/deck-frontend/index.html
index 8d66720..ae18091 100644
--- a/deck-frontend/index.html
+++ b/deck-frontend/index.html
@@ -55,11 +55,15 @@
ALL
@@ -167,6 +176,169 @@ class App {
});
}
+ private renderGraphOptions(container: HTMLElement): void {
+ const state = store.getState();
+ const { graphFilters, graphSettings, tags, graphEdges } = state;
+
+ // Count nodes and edges
+ const nodeCount = tags.length;
+ const edgeCount = graphEdges.length;
+
+ container.innerHTML = `
+
+
+
+
+ Nodos
+ ${nodeCount}
+
+
+ Edges
+ ${edgeCount}
+
+
+
+
+
+
Categorias
+ ${Object.entries(CATS).map(([key, config]) => `
+
+ `).join('')}
+
+
+
+
+
Relaciones
+ ${Object.entries(EDGE_COLORS).map(([key, color]) => `
+
+ `).join('')}
+
+
+
+
+
Visualizacion
+
+
+
+
+ Nodo
+ ${graphSettings.nodeSize}px
+
+
+
+
+
+ Distancia
+ ${graphSettings.linkDist}px
+
+
+
+
+
+ `;
+
+ // Bind events
+ this.bindGraphOptionEvents(container);
+ }
+
+ private bindGraphOptionEvents(container: HTMLElement): void {
+ // Category checkboxes
+ container.querySelectorAll
('[data-cat]').forEach(cb => {
+ cb.addEventListener('change', () => {
+ const cat = cb.dataset.cat as CategoryKey;
+ const state = store.getState();
+ const newCats = new Set(state.graphFilters.cats);
+ if (cb.checked) {
+ newCats.add(cat);
+ } else {
+ newCats.delete(cat);
+ }
+ store.setState({
+ graphFilters: { ...state.graphFilters, cats: newCats }
+ });
+ this.renderView();
+ });
+ });
+
+ // Edge checkboxes
+ container.querySelectorAll('[data-edge]').forEach(cb => {
+ cb.addEventListener('change', () => {
+ const edge = cb.dataset.edge as EdgeType;
+ const state = store.getState();
+ const newEdges = new Set(state.graphFilters.edges);
+ if (cb.checked) {
+ newEdges.add(edge);
+ } else {
+ newEdges.delete(edge);
+ }
+ store.setState({
+ graphFilters: { ...state.graphFilters, edges: newEdges }
+ });
+ this.renderView();
+ });
+ });
+
+ // Show images checkbox
+ const showImgCb = container.querySelector('#graph-show-img');
+ showImgCb?.addEventListener('change', () => {
+ const state = store.getState();
+ store.setState({
+ graphSettings: { ...state.graphSettings, showImg: showImgCb.checked }
+ });
+ this.renderView();
+ });
+
+ // Show labels checkbox
+ const showLblCb = container.querySelector('#graph-show-lbl');
+ showLblCb?.addEventListener('change', () => {
+ const state = store.getState();
+ store.setState({
+ graphSettings: { ...state.graphSettings, showLbl: showLblCb.checked }
+ });
+ this.renderView();
+ });
+
+ // Node size slider
+ const nodeSizeSlider = container.querySelector('#graph-node-size');
+ const nodeSizeVal = container.querySelector('#node-size-val');
+ nodeSizeSlider?.addEventListener('input', () => {
+ const size = parseInt(nodeSizeSlider.value, 10);
+ if (nodeSizeVal) nodeSizeVal.textContent = `${size}px`;
+ const state = store.getState();
+ store.setState({
+ graphSettings: { ...state.graphSettings, nodeSize: size }
+ });
+ this.renderView();
+ });
+
+ // Link distance slider
+ const linkDistSlider = container.querySelector('#graph-link-dist');
+ const linkDistVal = container.querySelector('#link-dist-val');
+ linkDistSlider?.addEventListener('input', () => {
+ const dist = parseInt(linkDistSlider.value, 10);
+ if (linkDistVal) linkDistVal.textContent = `${dist}px`;
+ const state = store.getState();
+ store.setState({
+ graphSettings: { ...state.graphSettings, linkDist: dist }
+ });
+ this.renderView();
+ });
+ }
+
private updateBaseButtons(): void {
const state = store.getState();
$$('.base-btn').forEach(btn => {
@@ -212,6 +384,7 @@ class App {
this.router.updateHash();
this.detailPanel?.close();
this.updateViewTabs();
+ this.renderLibraries(); // Update left panel (graph options vs libraries)
this.renderView();
});
diff --git a/deck-frontend/src/styles/main.css b/deck-frontend/src/styles/main.css
index 9d41657..12fed62 100644
--- a/deck-frontend/src/styles/main.css
+++ b/deck-frontend/src/styles/main.css
@@ -87,6 +87,18 @@ body {
.base-btn:hover { color: var(--text); }
.base-btn.active { background: var(--accent); color: #fff; }
+/* === VIEW BAR === */
+.view-bar {
+ height: 40px;
+ background: var(--bg-secondary);
+ border-bottom: 1px solid var(--border);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 16px;
+ gap: 8px;
+}
+
/* === GROUPS BAR === */
.groups-bar {
height: 44px;
@@ -573,3 +585,89 @@ select {
cursor: pointer;
}
select:focus { outline: none; border-color: var(--accent); }
+
+/* === GRAPH OPTIONS PANEL === */
+.graph-options {
+ padding: 10px;
+ overflow-y: auto;
+ width: 180px;
+}
+.graph-section {
+ margin-bottom: 16px;
+}
+.graph-section-title {
+ font-size: 0.7em;
+ font-weight: 600;
+ color: var(--accent);
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ margin-bottom: 8px;
+ padding-bottom: 4px;
+ border-bottom: 1px solid var(--border);
+}
+.graph-stat {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.75em;
+ color: var(--text-muted);
+ margin-bottom: 4px;
+}
+.graph-stat-value {
+ color: var(--text);
+ font-weight: 600;
+}
+.graph-checkbox {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 0.75em;
+ color: var(--text-muted);
+ margin-bottom: 6px;
+ cursor: pointer;
+}
+.graph-checkbox:hover { color: var(--text); }
+.graph-checkbox input[type="checkbox"] {
+ width: 14px;
+ height: 14px;
+ accent-color: var(--accent);
+ cursor: pointer;
+}
+.graph-checkbox .color-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ margin-right: 4px;
+}
+.graph-slider {
+ margin-bottom: 12px;
+}
+.graph-slider-label {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.7em;
+ color: var(--text-muted);
+ margin-bottom: 4px;
+}
+.graph-slider-value {
+ color: var(--text);
+ font-weight: 600;
+}
+.graph-slider input[type="range"] {
+ width: 100%;
+ height: 4px;
+ background: var(--border);
+ border-radius: 2px;
+ -webkit-appearance: none;
+ cursor: pointer;
+}
+.graph-slider input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ width: 14px;
+ height: 14px;
+ background: var(--accent);
+ border-radius: 50%;
+ cursor: pointer;
+}
+.left-panel.graph-mode {
+ width: 180px;
+}