summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-05 21:26:18 +0100
committerskal <pascal.massimino@gmail.com>2026-02-05 21:26:18 +0100
commit386c184a848815928657c4da83aa821b8b08f5d8 (patch)
tree724bc7f718e4e7a385b2ebf3d75b8711c81b1468
parentf49e7131c59ff3dd4dea02c34e713227011f7683 (diff)
feat(timeline-editor): Add floating properties panel and effect tooltips
UI improvements: - Properties panel now floats in top-right corner (fixed position) - Added collapse/expand button for properties panel - Panel slides out of view when collapsed, button appears to restore - Effects now show only class name, full details on hover (tooltip) - Tooltip shows: ClassName, Time, Priority, Args - Effect bars reduced from 35px to 26px height (cleaner appearance) - Effect spacing reduced from 40px to 30px (more compact stacking) - Effects use flexbox centering for better text alignment - Added hover highlight for better visual feedback CSS changes: - Properties panel: position fixed, z-index 1000, slide animation - Collapse button appears at top-right when panel hidden - Effects: single-line display with ellipsis overflow - Improved padding and font sizing for compact effect bars The properties panel is now always accessible without scrolling to the bottom of the page, and effect bars are much cleaner while still showing all information on hover.
-rw-r--r--tools/timeline_editor/index.html119
1 files changed, 105 insertions, 14 deletions
diff --git a/tools/timeline_editor/index.html b/tools/timeline_editor/index.html
index b84908a..c77ae41 100644
--- a/tools/timeline_editor/index.html
+++ b/tools/timeline_editor/index.html
@@ -154,14 +154,20 @@
background: #3a3d41;
border: 1px solid #858585;
border-radius: 3px;
- padding: 6px;
+ padding: 4px 8px;
cursor: move;
- font-size: 12px;
+ font-size: 11px;
transition: box-shadow 0.2s;
+ display: flex;
+ align-items: center;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.effect:hover {
box-shadow: 0 0 8px rgba(133, 133, 133, 0.5);
+ background: #45484d;
}
.effect.selected {
@@ -169,16 +175,80 @@
box-shadow: 0 0 8px rgba(206, 145, 120, 0.5);
}
+ .effect small {
+ font-size: 11px;
+ color: #d4d4d4;
+ }
+
.properties-panel {
+ position: fixed;
+ top: 80px;
+ right: 20px;
+ width: 350px;
+ max-height: 80vh;
background: #252526;
- padding: 20px;
+ padding: 15px;
border-radius: 8px;
- margin-top: 20px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
+ z-index: 1000;
+ overflow-y: auto;
+ transition: transform 0.3s ease;
+ }
+
+ .properties-panel.collapsed {
+ transform: translateX(370px);
}
- .properties-panel h2 {
+ .panel-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
margin-bottom: 15px;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #3c3c3c;
+ }
+
+ .panel-header h2 {
+ margin: 0;
color: #4ec9b0;
+ font-size: 16px;
+ }
+
+ .panel-toggle {
+ background: transparent;
+ border: 1px solid #858585;
+ color: #d4d4d4;
+ padding: 4px 8px;
+ border-radius: 3px;
+ cursor: pointer;
+ font-size: 12px;
+ }
+
+ .panel-toggle:hover {
+ background: #3c3c3c;
+ }
+
+ .panel-collapse-btn {
+ position: fixed;
+ top: 80px;
+ right: 20px;
+ background: #252526;
+ border: 1px solid #858585;
+ color: #d4d4d4;
+ padding: 8px 12px;
+ border-radius: 4px;
+ cursor: pointer;
+ z-index: 999;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
+ display: none;
+ }
+
+ .panel-collapse-btn:hover {
+ background: #3c3c3c;
+ }
+
+ .panel-collapse-btn.visible {
+ display: block;
}
.property-group {
@@ -267,8 +337,13 @@
<div class="timeline" id="timeline"></div>
</div>
+ <button class="panel-collapse-btn" id="panelCollapseBtn">◀ Properties</button>
+
<div class="properties-panel" id="propertiesPanel" style="display: none;">
- <h2>Properties</h2>
+ <div class="panel-header">
+ <h2>Properties</h2>
+ <button class="panel-toggle" id="panelToggle">▶ Collapse</button>
+ </div>
<div id="propertiesContent"></div>
</div>
@@ -476,7 +551,8 @@
// Calculate sequence height based on number of effects (stacked vertically)
const numEffects = seq.effects.length;
- const seqHeight = Math.max(70, 25 + numEffects * 40 + 5);
+ const effectSpacing = 30; // Reduced from 40px
+ const seqHeight = Math.max(70, 20 + numEffects * effectSpacing + 5);
seqDiv.style.left = `${seq.startTime * pixelsPerSecond}px`;
seqDiv.style.top = `${seqIndex * 80}px`;
@@ -521,11 +597,11 @@
const effectWidth = (effect.endTime - effect.startTime) * pixelsPerSecond;
effectDiv.style.left = `${effectStart}px`;
- effectDiv.style.top = `${seqIndex * 80 + 25 + effectIndex * 40}px`;
+ effectDiv.style.top = `${seqIndex * 80 + 20 + effectIndex * 30}px`;
effectDiv.style.width = `${effectWidth}px`;
- effectDiv.style.height = '35px';
+ effectDiv.style.height = '26px';
- // Format time display based on mode
+ // Format time display based on mode (for tooltip)
let timeDisplay;
if (showBeats) {
const beatDuration = 60.0 / bpm;
@@ -536,10 +612,9 @@
timeDisplay = `${effect.startTime.toFixed(1)}-${effect.endTime.toFixed(1)}s`;
}
- effectDiv.innerHTML = `
- ${effect.className}<br>
- <small>${timeDisplay}</small>
- `;
+ // Show only class name, full info on hover
+ effectDiv.innerHTML = `<small>${effect.className}</small>`;
+ effectDiv.title = `${effect.className}\n${timeDisplay}\nPriority: ${effect.priority}\n${effect.args || '(no args)'}`;
if (selectedItem && selectedItem.type === 'effect' &&
selectedItem.seqIndex === seqIndex && selectedItem.effectIndex === effectIndex) {
@@ -771,6 +846,22 @@
renderTimeline();
});
+ // Properties panel collapse/expand
+ const panelToggle = document.getElementById('panelToggle');
+ const panelCollapseBtn = document.getElementById('panelCollapseBtn');
+
+ panelToggle.addEventListener('click', () => {
+ propertiesPanel.classList.add('collapsed');
+ panelCollapseBtn.classList.add('visible');
+ panelToggle.textContent = '◀ Expand';
+ });
+
+ panelCollapseBtn.addEventListener('click', () => {
+ propertiesPanel.classList.remove('collapsed');
+ panelCollapseBtn.classList.remove('visible');
+ panelToggle.textContent = '▶ Collapse';
+ });
+
// Click outside to deselect
timeline.addEventListener('click', () => {
selectedItem = null;