Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(xargs wc *)",
"Bash(xargs ls *)",
"Bash(git checkout *)"
]
}
}
22 changes: 15 additions & 7 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ interface ManagedDownload {
const MENU_WIDTH = 220;
const MENU_HEIGHT = 360;
const DOWNLOADS_POPOVER_WIDTH = 320;
const DOWNLOADS_POPOVER_HEIGHT = 280;
const DOWNLOADS_POPOVER_HEIGHT = 480;

let mainWindow: BrowserWindow | null = null;
let floatWindow: BrowserWindow | null = null;
Expand Down Expand Up @@ -483,9 +483,7 @@ function emitDownloadsChanged(): void {
if (downloadsPopoverWindow && !downloadsPopoverWindow.isDestroyed()) {
const downloadsPopoverPayload: DownloadsPopoverInitPayload = {
theme: downloadsPopoverTheme,
downloads: downloadsSnapshot.filter(download => {
return download.state === 'progressing' || download.state === 'paused';
}),
downloads: downloadsSnapshot.slice(0, 5),
};

downloadsPopoverWindow.webContents.send(
Expand Down Expand Up @@ -1359,9 +1357,7 @@ ipcMain.handle(IPC_CHANNELS.DOWNLOADS_POPOVER_SHOW, (_event, payload: unknown) =

const initPayload: DownloadsPopoverInitPayload = {
theme: downloadsPopoverTheme,
downloads: getDownloadsSnapshot().filter(download => {
return download.state === 'progressing' || download.state === 'paused';
}),
downloads: getDownloadsSnapshot().slice(0, 5),
};

const sendAndShow = (): void => {
Expand All @@ -1385,6 +1381,18 @@ ipcMain.handle(IPC_CHANNELS.DOWNLOADS_POPOVER_OPEN_PAGE, () => {
}
});

ipcMain.handle(IPC_CHANNELS.DOWNLOADS_POPOVER_RESIZE, (_event, height: unknown) => {
if (typeof height !== 'number' || height <= 0) return;
if (downloadsPopoverWindow && !downloadsPopoverWindow.isDestroyed()) {
const currentBounds = downloadsPopoverWindow.getBounds();
const newHeight = Math.min(Math.round(height), DOWNLOADS_POPOVER_HEIGHT);
downloadsPopoverWindow.setBounds({
...currentBounds,
height: newHeight,
});
}
});

ipcMain.handle(IPC_CHANNELS.FLOAT_NAVIGATE, (_event, payload: unknown) => {
const safeUrl = parseFloatNavigatePayload(payload);
if (!safeUrl) {
Expand Down
6 changes: 6 additions & 0 deletions src/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,12 @@ contextBridge.exposeInMainWorld('orb', {
.then(() => undefined);
},

resizeDownloadsPopover: (height: number) => {
return ipcRenderer
.invoke(IPC_CHANNELS.DOWNLOADS_POPOVER_RESIZE, height)
.then(() => undefined);
},

onDownloadsPopoverInit: (callback: (payload: DownloadsPopoverInitPayload) => void) => {
const handler = (_event: Electron.IpcRendererEvent, payload: unknown): void => {
const parsedPayload = parseDownloadsPopoverInitPayload(payload);
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/downloads-popover.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
<div class="flex items-center gap-2 border-b border-orb-border px-3 py-2">
<span class="font-mono text-[9px] uppercase tracking-[1.8px] text-orb-accent">// downloads</span>
</div>
<div id="downloads-list" class="max-h-[210px] overflow-y-auto px-2 py-1.5"></div>
<div id="downloads-empty" class="px-3 py-4 font-mono text-[11px] text-orb-text-dim">no active downloads.</div>
<div id="downloads-list" class="max-h-[380px] overflow-y-auto px-2 py-1.5"></div>
<div id="downloads-empty" class="px-3 py-4 font-mono text-[11px] text-orb-text-dim">no recent downloads.</div>
<div class="border-t border-orb-border px-2 py-2">
<button id="btn-open-downloads" class="w-full rounded-orb border border-orb-border bg-orb-bg px-2 py-1.5 font-mono text-[10px] text-orb-text-dim transition hover:border-orb-border-hi hover:bg-orb-surface-2 hover:text-orb-text">→ open downloads page</button>
</div>
Expand Down
57 changes: 35 additions & 22 deletions src/renderer/downloads-popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,27 +69,23 @@ function renderDownloads(downloads: DownloadSnapshot[]): void {
<div class="mt-1 font-mono text-[10px] text-orb-text-dim">${escapeHtml(formatBytes(download.receivedBytes))} / ${escapeHtml(totalBytesText)}</div>`
: '';

let actionsMarkup = '';
if (isCompleted) {
actionsMarkup = `
<div class="mt-1.5 flex gap-1">
<button data-popover-open-id="${id}" style="${ACTION_BTN}">open</button>
<button data-popover-show-id="${id}" style="${ACTION_BTN}">show in folder</button>
</div>`;
} else if (isActive) {
const pauseBtn = download.state === 'progressing'
? `<button data-popover-pause-id="${id}" style="${ACTION_BTN}">pause</button>`
: '';
const resumeBtn = download.state === 'paused' && download.canResume
? `<button data-popover-resume-id="${id}" style="${ACTION_BTN}">resume</button>`
: '';
actionsMarkup = `
<div class="mt-1.5 flex gap-1">
${pauseBtn}
${resumeBtn}
<button data-popover-cancel-id="${id}" style="${ACTION_BTN}">cancel</button>
</div>`;
}
const canPause = download.state === 'progressing';
const canResume = download.state === 'paused' && download.canResume;
const canCancel = isActive;
const canRemove = !isActive;

const actionBtn = (label: string, attr: string, recordId: string, disabled: boolean): string =>
disabled ? '' : `<button ${attr}="${recordId}" style="${ACTION_BTN}">${label}</button>`;

const actionsMarkup = `
<div class="mt-1.5 flex flex-wrap gap-1">
${actionBtn('pause', 'data-popover-pause-id', id, !canPause)}
${actionBtn('resume', 'data-popover-resume-id', id, !canResume)}
${actionBtn('cancel', 'data-popover-cancel-id', id, !canCancel)}
${actionBtn('open', 'data-popover-open-id', id, !isCompleted)}
${actionBtn('show in folder', 'data-popover-show-id', id, !isCompleted)}
${actionBtn('remove', 'data-popover-remove-id', id, !canRemove)}
</div>`;

item.innerHTML = `
<div class="flex items-center justify-between gap-2">
Expand All @@ -102,6 +98,20 @@ function renderDownloads(downloads: DownloadSnapshot[]): void {

downloadsList.appendChild(item);
});

requestAnimationFrame(() => {
const parentContainer = document.querySelector('.rounded-orb') as HTMLElement;
if (parentContainer) {
void window.orb.resizeDownloadsPopover(parentContainer.offsetHeight);
}
});

requestAnimationFrame(() => {
const parentContainer = document.querySelector('.rounded-orb') as HTMLElement;
if (parentContainer) {
void window.orb.resizeDownloadsPopover(parentContainer.offsetHeight);
}
});
}

// Event delegation for action buttons
Expand All @@ -122,7 +132,10 @@ downloadsList.addEventListener('click', event => {
if (resumeId) { void window.orb.resumeDownload(resumeId); return; }

const cancelId = target.closest<HTMLElement>('[data-popover-cancel-id]')?.getAttribute('data-popover-cancel-id');
if (cancelId) { void window.orb.cancelDownload(cancelId); }
if (cancelId) { void window.orb.cancelDownload(cancelId); return; }

const removeId = target.closest<HTMLElement>('[data-popover-remove-id]')?.getAttribute('data-popover-remove-id');
if (removeId) { void window.orb.removeDownload(removeId); }
});

window.orb.onDownloadsPopoverInit((payload: DownloadsPopoverInitPayload) => {
Expand Down
1 change: 1 addition & 0 deletions src/renderer/window.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ declare global {
onDownloadsChanged: (callback: (downloads: DownloadSnapshot[]) => void) => () => void;
showDownloadsPopover: (payload: DownloadsPopoverShowPayload) => Promise<void>;
openDownloadsPageFromPopover: () => Promise<void>;
resizeDownloadsPopover: (height: number) => Promise<void>;
onDownloadsPopoverInit: (
callback: (payload: DownloadsPopoverInitPayload) => void,
) => () => void;
Expand Down
1 change: 1 addition & 0 deletions src/shared/ipc-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export const IPC_CHANNELS = {
DOWNLOADS_SHOW_IN_FOLDER: 'downloads-show-in-folder',
DOWNLOADS_POPOVER_SHOW: 'downloads-popover-show',
DOWNLOADS_POPOVER_INIT: 'downloads-popover-init',
DOWNLOADS_POPOVER_RESIZE: 'downloads-popover-resize',
DOWNLOADS_POPOVER_OPEN_PAGE: 'downloads-popover-open-page',
MENU_SHOW: 'menu-show',
MENU_INIT: 'menu-init',
Expand Down
Loading