Skip to content

Commit 1090886

Browse files
ozgesolidkeyclaude
andcommitted
Fix minimap preview escape and merge recent files into Open File button
Minimap preview: - Preview stays visible when mouse moves into it (200ms hide delay) - Listeners on preview box cancel hide timer on mouseenter - Can now scroll horizontally inside the preview without it vanishing Recent files: - Merged separate chevron button into Open File button as inline ▾ - Click the chevron OR right-click the button to open recent files - Regular left-click still opens the file dialog Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3f81b37 commit 1090886

3 files changed

Lines changed: 38 additions & 8 deletions

File tree

src/renderer/index.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@
2828
<div class="toolbar">
2929
<div class="toolbar-left">
3030
<div class="open-file-wrapper">
31-
<button id="btn-open-file" class="toolbar-btn" title="Open file" data-help="Open a log file for analysis.&#10;Supports text logs, JSON logs, CSV, and large files (100K+ lines).&#10;Drag & drop also works.">
32-
<span class="icon">&#128194;</span> Open File
31+
<button id="btn-open-file" class="toolbar-btn" title="Open file (click) | Recent files (right-click)" data-help="Open a log file for analysis.&#10;Right-click or use the dropdown for recent files.&#10;Supports text logs, JSON logs, CSV, and large files (100K+ lines).&#10;Drag & drop also works.">
32+
<span class="icon">&#128194;</span> Open File <span id="btn-recent-files" class="open-file-chevron" title="Recent files">&#9662;</span>
3333
</button>
34-
<button id="btn-recent-files" class="toolbar-btn small recent-files-chevron" title="Recent files">&#9662;</button>
3534
<div id="recent-files-popup" class="recent-files-popup hidden"></div>
3635
</div>
3736
<div class="separator"></div>

src/renderer/renderer.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ const SLOW_SCROLL_FRAME_COUNT = 10; // Number of slow frames before warning
688688
const elements = {
689689
logo: document.getElementById('logo') as HTMLImageElement,
690690
btnOpenFile: document.getElementById('btn-open-file') as HTMLButtonElement,
691-
btnRecentFiles: document.getElementById('btn-recent-files') as HTMLButtonElement,
691+
btnRecentFiles: document.getElementById('btn-recent-files') as HTMLSpanElement,
692692
recentFilesPopup: document.getElementById('recent-files-popup') as HTMLDivElement,
693693
btnOpenWelcome: document.getElementById('btn-open-welcome') as HTMLButtonElement,
694694
btnSearch: document.getElementById('btn-search') as HTMLButtonElement,
@@ -1963,6 +1963,7 @@ function createLogViewer(): void {
19631963
previewEl.className = 'minimap-preview hidden';
19641964
previewEl.id = 'minimap-preview';
19651965
minimapElement.appendChild(previewEl);
1966+
setupMinimapPreviewListeners(previewEl);
19661967

19671968
// Add to wrapper
19681969
logViewerWrapper.appendChild(logViewerElement);
@@ -3291,14 +3292,28 @@ function handleMinimapClick(event: MouseEvent): void {
32913292
// ─── Minimap Hover Preview ──────────────────────────────────────────────
32923293

32933294
let minimapPreviewTimer: ReturnType<typeof setTimeout> | null = null;
3295+
let minimapPreviewHideTimer: ReturnType<typeof setTimeout> | null = null;
32943296
let minimapPreviewLine = -1;
32953297

32963298
function isMinimapPreviewEnabled(): boolean {
32973299
return userSettings.minimapPreview;
32983300
}
32993301

3302+
function setupMinimapPreviewListeners(previewEl: HTMLElement): void {
3303+
previewEl.addEventListener('mouseenter', () => {
3304+
// Cancel any pending hide when mouse enters preview
3305+
if (minimapPreviewHideTimer) { clearTimeout(minimapPreviewHideTimer); minimapPreviewHideTimer = null; }
3306+
});
3307+
previewEl.addEventListener('mouseleave', () => {
3308+
// Hide after a short delay when mouse leaves preview
3309+
minimapPreviewHideTimer = setTimeout(() => hideMinimapPreviewNow(), 200);
3310+
});
3311+
}
3312+
33003313
function handleMinimapHover(event: MouseEvent): void {
33013314
if (!minimapElement || isDraggingMinimap || !isMinimapPreviewEnabled()) return;
3315+
// Cancel any pending hide
3316+
if (minimapPreviewHideTimer) { clearTimeout(minimapPreviewHideTimer); minimapPreviewHideTimer = null; }
33023317

33033318
const rect = minimapElement.getBoundingClientRect();
33043319
const hoverY = event.clientY - rect.top;
@@ -3307,10 +3322,9 @@ function handleMinimapHover(event: MouseEvent): void {
33073322
if (totalLines === 0) return;
33083323

33093324
const targetLine = Math.floor((hoverY / minimapHeight) * totalLines);
3310-
if (targetLine === minimapPreviewLine) return; // Same line, skip
3325+
if (targetLine === minimapPreviewLine) return;
33113326
minimapPreviewLine = targetLine;
33123327

3313-
// Debounce to avoid hammering getLines
33143328
if (minimapPreviewTimer) clearTimeout(minimapPreviewTimer);
33153329
minimapPreviewTimer = setTimeout(async () => {
33163330
const preview = document.getElementById('minimap-preview');
@@ -3333,7 +3347,6 @@ function handleMinimapHover(event: MouseEvent): void {
33333347
html += `</div>`;
33343348
preview.innerHTML = html;
33353349

3336-
// Position: vertically centered on hover Y, to the left of the minimap
33373350
const previewHeight = Math.max(120, (PREVIEW_LINES + 1) * 16 + 8);
33383351
const top = Math.max(0, Math.min(hoverY - previewHeight / 2, minimapHeight - previewHeight));
33393352
preview.style.top = `${top}px`;
@@ -3342,7 +3355,14 @@ function handleMinimapHover(event: MouseEvent): void {
33423355
}
33433356

33443357
function hideMinimapPreview(): void {
3358+
// Delay hide to allow mouse to move into the preview box
3359+
if (minimapPreviewHideTimer) clearTimeout(minimapPreviewHideTimer);
3360+
minimapPreviewHideTimer = setTimeout(() => hideMinimapPreviewNow(), 200);
3361+
}
3362+
3363+
function hideMinimapPreviewNow(): void {
33453364
if (minimapPreviewTimer) { clearTimeout(minimapPreviewTimer); minimapPreviewTimer = null; }
3365+
if (minimapPreviewHideTimer) { clearTimeout(minimapPreviewHideTimer); minimapPreviewHideTimer = null; }
33463366
minimapPreviewLine = -1;
33473367
const preview = document.getElementById('minimap-preview');
33483368
if (preview) preview.classList.add('hidden');
@@ -12687,6 +12707,11 @@ function init(): void {
1268712707
elements.btnOpenFile.addEventListener('click', openFile);
1268812708
elements.btnRecentFiles.addEventListener('click', (e) => {
1268912709
e.stopPropagation();
12710+
e.preventDefault();
12711+
toggleRecentFilesPopup();
12712+
});
12713+
elements.btnOpenFile.addEventListener('contextmenu', (e) => {
12714+
e.preventDefault();
1269012715
toggleRecentFilesPopup();
1269112716
});
1269212717
document.addEventListener('click', (e) => {

src/renderer/styles.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,13 @@ body.platform-darwin .titlebar {
290290

291291
/* Recent Files dropdown */
292292
.open-file-wrapper { position: relative; display: inline-flex; align-items: center; }
293-
.recent-files-chevron { padding: 4px 6px; margin-left: -2px; font-size: 10px; }
293+
.open-file-chevron {
294+
margin-left: 4px;
295+
font-size: 10px;
296+
opacity: 0.6;
297+
cursor: pointer;
298+
}
299+
.open-file-chevron:hover { opacity: 1; }
294300

295301
.recent-files-popup {
296302
position: absolute;

0 commit comments

Comments
 (0)