diff --git a/static/app.js b/static/app.js index 13d8120..fb03437 100644 --- a/static/app.js +++ b/static/app.js @@ -1,4 +1,4 @@ -const { createApp, ref, computed, watch, onMounted, onUnmounted } = Vue; +const { createApp, ref, computed, watch, onMounted, onUnmounted, nextTick } = Vue; // Keep an existing token long enough to migrate an already-open browser to the // password session. Successful login removes it; new browsers never store the @@ -136,6 +136,7 @@ createApp({ const snap = ref(true); const selectedDrawing = ref(null); const selectedDrawings = ref([]); + const drawingList = ref(null); const alertPrice = ref(null); const alertNote = ref(''); const levelColor = ref('#e0a34a'); @@ -1125,11 +1126,42 @@ createApp({ sendPrefs(); }, { deep: true }); + function startDrawingListResize(event) { + const el = drawingList.value; + if (!el) return; + event.preventDefault(); + const origin = event.clientY; + const start = el.getBoundingClientRect().height; + const move = ev => { + el.style.height = `${Math.max(88, Math.round(start + ev.clientY - origin))}px`; + }; + const stop = () => { + window.removeEventListener('pointermove', move); + window.removeEventListener('pointerup', stop); + const height = Math.round(el.getBoundingClientRect().height); + if (height > 80) localStorage.setItem('chart-drawing-list-height', String(height)); + }; + window.addEventListener('pointermove', move); + window.addEventListener('pointerup', stop); + } + + function revealSelectedDrawing(id) { + if (!id) return; + const list = drawingList.value; + const section = list?.closest('details'); + if (section) section.open = true; + nextTick(() => { + const row = list?.querySelector(`[data-drawing-id="${CSS.escape(id)}"]`); + row?.scrollIntoView({ block: 'nearest' }); + }); + } + watch(selectedDrawing, id => { if (chartApi) { chartApi.setSelectedDrawing(id); chartApi.setSelectedLine(levels.value.some(level => level.id === id) ? id : null); } + revealSelectedDrawing(id); }); watch(snap, value => { @@ -1171,6 +1203,11 @@ createApp({ chartApi.setAutoScrollLivePrice(autoScrollLivePrice.value); chartApi.setCommentHandlers({ onToggle: toggleComment, onMove: moveComment, onSelect: selectComment }); window.addEventListener('keydown', handleKeydown); + nextTick(() => { + const el = drawingList.value; + const saved = Number(localStorage.getItem('chart-drawing-list-height')); + if (el && saved > 80) el.style.height = `${saved}px`; + }); await migrateLegacyToken(); await refreshStatus(); await refreshComments(); @@ -1186,6 +1223,6 @@ createApp({ window.removeEventListener('keydown', handleKeydown); }); - return { status, price, sessionOpen, quoteChange, animateCurrentPrice, autoScrollLivePrice, barAge, dataUpdatedAt, buildStamp, timeframe, timeframes, drawingColors, drawingColorRows, drawingColorName, colorRowLabels, symbolChoices, selectedSymbol, symbolColor, symbolScale, symbolScales, symbolPanelOpen, prefs, clusters, clustersByPrice, events, diagnosticMode, captureBusy, captureDiagnostic, armedTool, drawName, drawColor, drawWidth, drawSide, snap, selectedDrawing, selectedDrawings, manualLines, hasDrawingSelection, allShownSelected, selectedAreHidden, alertPrice, alertNote, alertEarlyPoints, levelColor, levelWidth, addPriceAlert, armTool, selectTimeframe, allEnabled, toggleGroup, deleteSelected, deleteLine, toggleDrawingSelection, toggleSelectAll, toggleSelectedVisibility, renameLine, updateLineStyle, updateLevelNumber, setArmed, commentText, commentFloat, comments, drawings, filteredDrawings, drawingFilter, drawingKind, deleteDrawing, toggleComment, togglePinned, chooseSymbol, toggleSymbolPanel, startSymbolDrag, dropSymbol, optionExpirations, optionExpiryId, optionSide, optionMode, optionMin, optionMax, optionContracts, optionUnderlying, optionBusy, optionError, optionSearched, optionCopied, onOptionsToggle, searchOptions, copyOption }; + return { status, price, sessionOpen, quoteChange, animateCurrentPrice, autoScrollLivePrice, barAge, dataUpdatedAt, buildStamp, timeframe, timeframes, drawingColors, drawingColorRows, drawingColorName, colorRowLabels, symbolChoices, selectedSymbol, symbolColor, symbolScale, symbolScales, symbolPanelOpen, prefs, clusters, clustersByPrice, events, diagnosticMode, captureBusy, captureDiagnostic, armedTool, drawName, drawColor, drawWidth, drawSide, snap, selectedDrawing, selectedDrawings, drawingList, startDrawingListResize, manualLines, hasDrawingSelection, allShownSelected, selectedAreHidden, alertPrice, alertNote, alertEarlyPoints, levelColor, levelWidth, addPriceAlert, armTool, selectTimeframe, allEnabled, toggleGroup, deleteSelected, deleteLine, toggleDrawingSelection, toggleSelectAll, toggleSelectedVisibility, renameLine, updateLineStyle, updateLevelNumber, setArmed, commentText, commentFloat, comments, drawings, filteredDrawings, drawingFilter, drawingKind, deleteDrawing, toggleComment, togglePinned, chooseSymbol, toggleSymbolPanel, startSymbolDrag, dropSymbol, optionExpirations, optionExpiryId, optionSide, optionMode, optionMin, optionMax, optionContracts, optionUnderlying, optionBusy, optionError, optionSearched, optionCopied, onOptionsToggle, searchOptions, copyOption }; }, }).mount('#app'); diff --git a/static/index.html b/static/index.html index d1c358e..465d1f3 100644 --- a/static/index.html +++ b/static/index.html @@ -221,7 +221,7 @@ -