From e0bacce10abc25492fbd15cd189647bfce90ed7c Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Tue, 31 Mar 2026 19:17:37 +0200 Subject: [PATCH] Apply sleek black theme and table format for chord panels --- webapp/path_navigator.html | 211 ++++++++++++++++++++++--------------- 1 file changed, 126 insertions(+), 85 deletions(-) diff --git a/webapp/path_navigator.html b/webapp/path_navigator.html index 8401c16..4b05635 100644 --- a/webapp/path_navigator.html +++ b/webapp/path_navigator.html @@ -135,8 +135,8 @@ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; - background: #1a1a2e; - color: #eee; + background: #000000; + color: #cccccc; } .container { @@ -147,6 +147,9 @@ h1 { text-align: center; margin-bottom: 10px; + font-weight: 300; + letter-spacing: 2px; + color: #ffffff; } .controls { @@ -158,35 +161,39 @@ } .controls button { - padding: 10px 20px; - font-size: 16px; + padding: 8px 16px; + font-size: 14px; cursor: pointer; - background: #16213e; - color: #eee; - border: 1px solid #0f3460; - border-radius: 5px; + background: #0a0a0a; + color: #888888; + border: 1px solid #222222; + border-radius: 4px; + transition: all 0.2s ease; } .controls button:hover { - background: #0f3460; + background: #151515; + color: #ffffff; + border-color: #444444; } .controls button:disabled { - opacity: 0.5; + opacity: 0.3; cursor: not-allowed; } .index-display { - font-size: 18px; - font-weight: bold; + font-size: 14px; + color: #666666; + letter-spacing: 1px; } #graph-container { width: 100%; height: 450px; - border: 1px solid #0f3460; - border-radius: 8px; - background: #16213e; + border: 1px solid #1a1a1a; + border-radius: 4px; + background: #050505; position: relative; } @@ -197,33 +204,44 @@ } .chord-panel { - background: #16213e; + background: #0a0a0a; padding: 15px; - border-radius: 8px; - min-width: 250px; + border-radius: 4px; + min-width: 200px; + border: 1px solid #1a1a1a; } .chord-panel h3 { margin-top: 0; - color: #e94560; + color: #666666; + font-size: 12px; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 500; } .chord-panel.current { - border: 2px solid #e94560; + border: 1px solid #333333; + } + + .chord-panel.current h3 { + color: #00d4ff; } .chord-panel.prev, .chord-panel.next { - opacity: 0.7; + opacity: 0.6; } .pitch-list { list-style: none; padding: 0; + font-size: 12px; } .pitch-list li { - padding: 5px 0; - font-family: monospace; + padding: 4px 0; + color: #888888; + font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace; } .file-input { @@ -232,44 +250,20 @@ } .file-input input { - padding: 10px; - background: #16213e; - color: #eee; - border: 1px solid #0f3460; - border-radius: 5px; + padding: 8px; + background: #0a0a0a; + color: #888888; + border: 1px solid #222222; + border-radius: 4px; } - svg { - width: 100%; - height: 100%; - } - - .node circle { - stroke: #fff; - stroke-width: 2px; - } - - .node.current circle { - stroke: #e94560; - stroke-width: 3px; - } - - .link { - stroke: #4a5568; - stroke-width: 2px; - } - - .link-label { - fill: #a0aec0; - font-size: 12px; - font-family: monospace; - } - - .node-label { - fill: #eee; - font-size: 11px; - font-family: monospace; - text-anchor: middle; + .file-select { + padding: 8px; + background: #0a0a0a; + color: #888888; + border: 1px solid #222222; + border-radius: 4px; + margin-left: 10px; } @@ -326,7 +320,7 @@ const graphHeight = 450; // Voice colors - sleek pastel scheme - const voiceColors = ['#5EAFD6', '#CE8E94', '#8FCEA4', '#E5C686']; + const voiceColors = ['#7eb5a6', '#c5a3ff', '#ffb3b3', '#ffd700']; // Create Cytoscape instance function initCytoscape() { @@ -337,40 +331,41 @@ selector: 'node', style: { 'background-color': 'data(color)', - 'width': 36, - 'height': 36, + 'width': 32, + 'height': 32, 'label': 'data(cents)', 'text-valign': 'center', 'text-halign': 'center', - 'color': '#eee', - 'font-size': '9px', - 'text-outline-width': 2, - 'text-outline-color': 'data(color)', + 'color': '#000000', + 'font-size': '10px', + 'font-family': 'monospace', + 'font-weight': 'bold', + 'text-outline-width': 0, 'border-width': 0, } }, { selector: 'edge', style: { - 'width': 2, - 'line-color': '#556', + 'width': 1.5, + 'line-color': '#555555', 'curve-style': 'straight', 'target-arrow-shape': 'none', 'label': 'data(ratio)', - 'font-size': '10px', - 'color': '#aaa', + 'font-size': '12px', + 'color': '#ffffff', 'text-rotation': 'autorotate', - 'text-margin-y': -12, - 'text-background-color': '#16213e', + 'text-margin-y': -10, + 'text-background-color': '#000000', 'text-background-opacity': 0.8, - 'text-background-padding': '3px', + 'text-background-padding': '2px', } }, { selector: ':selected', style: { - 'border-width': 3, - 'border-color': '#fff', + 'border-width': 2, + 'border-color': '#00d4ff', } } ], @@ -598,24 +593,70 @@ } function updateChordPanel(elementId, data) { - const ul = document.getElementById(elementId); - ul.innerHTML = ""; + const container = document.getElementById(elementId); + container.innerHTML = ""; if (!data || (Array.isArray(data) && data.length === 0)) { - ul.innerHTML = "
  • (none)
  • "; + container.innerHTML = "
    (none)
    "; return; } - // Handle both formats: raw chord array or nodes array from graph API const items = Array.isArray(data) ? data : (data.nodes || []); - items.forEach(item => { - const li = document.createElement("li"); - const fraction = item.fraction || item.fraction; - const hs_array = item.hs_array || []; - li.textContent = `${fraction} (${hs_array.join(", ")})`; - ul.appendChild(li); + if (items.length === 0) return; + + // Determine number of columns from first node's hs_array + const cols = items[0].hs_array ? items[0].hs_array.length : 0; + if (cols === 0) return; + + // Create table - let it size based on content + const table = document.createElement("table"); + table.style.fontFamily = "monospace"; + table.style.fontSize = "10px"; + table.style.borderCollapse = "collapse"; + table.style.tableLayout = "auto"; + table.style.lineHeight = "1.2"; + table.style.margin = "0 auto"; + + // Header row - split into separate cells to match row structure + const headerRow = document.createElement("tr"); + const headerParts = ["2", "3", "5", "7"]; + headerParts.forEach((part, idx) => { + const th = document.createElement("th"); + th.textContent = part; + th.style.padding = "0px 4px"; + th.style.textAlign = idx === 0 ? "left" : "right"; + th.style.borderBottom = "1px solid #444"; + th.style.paddingBottom = "1px"; + th.style.fontWeight = "normal"; + th.style.color = "#666"; + th.style.whiteSpace = "nowrap"; + headerRow.appendChild(th); }); + table.appendChild(headerRow); + + // Data rows (all nodes) + items.forEach((item) => { + const row = document.createElement("tr"); + const hs = item.hs_array || []; + + hs.forEach((val, j) => { + const td = document.createElement("td"); + td.textContent = val; + td.style.padding = "0px 4px"; + td.style.textAlign = "right"; + td.style.color = "#888"; + td.style.whiteSpace = "nowrap"; + if (j === 0) { + td.style.textAlign = "left"; + } + row.appendChild(td); + }); + + table.appendChild(row); + }); + + container.appendChild(table); } // Update display - now handled by loadFromAPI