fix(ui): align download list and live properties

This commit is contained in:
NimBold
2026-06-19 07:42:59 +03:30
parent 8a1619f056
commit 28df7ca809
3 changed files with 49 additions and 42 deletions
+20 -22
View File
@@ -7,15 +7,16 @@ import { open } from '@tauri-apps/plugin-dialog';
type LoginMode = 'matching' | 'custom' | 'none';
export const PropertiesModal = () => {
const {
selectedPropertiesDownloadId,
setSelectedPropertiesDownloadId,
updateDownload
} = useDownloadStore();
const selectedPropertiesDownloadId = useDownloadStore(state => state.selectedPropertiesDownloadId);
const setSelectedPropertiesDownloadId = useDownloadStore(state => state.setSelectedPropertiesDownloadId);
const updateDownload = useDownloadStore(state => state.updateDownload);
const item = useDownloadStore(state =>
selectedPropertiesDownloadId
? state.downloads.find(d => d.id === selectedPropertiesDownloadId) ?? null
: null
);
const { defaultDownloadPath } = useSettingsStore();
const [item, setItem] = useState<DownloadItem | null>(null);
const { defaultDownloadPath, perServerConnections } = useSettingsStore();
// Form states
const [url, setUrl] = useState('');
@@ -44,7 +45,6 @@ export const PropertiesModal = () => {
if (selectedPropertiesDownloadId) {
const activeItem = useDownloadStore.getState().downloads.find(d => d.id === selectedPropertiesDownloadId);
if (activeItem) {
setItem(activeItem);
setUrl(activeItem.url);
setFileName(activeItem.fileName);
setSaveLocation(activeItem.destination || defaultDownloadPath || '~/Downloads');
@@ -83,12 +83,10 @@ export const PropertiesModal = () => {
setMirrors(activeItem.mirrors || '');
setErrorMessage('');
} else {
setItem(null);
setSelectedPropertiesDownloadId(null);
}
} else {
setItem(null);
}
}, [selectedPropertiesDownloadId, defaultDownloadPath]);
}, [selectedPropertiesDownloadId, defaultDownloadPath, setSelectedPropertiesDownloadId]);
if (!selectedPropertiesDownloadId || !item) return null;
@@ -165,15 +163,15 @@ export const PropertiesModal = () => {
<div className={`h-1.5 rounded-full transition-all duration-300 ${item.status === 'completed' ? 'bg-green-500' : item.status === 'paused' ? 'bg-orange-500' : item.status === 'failed' ? 'bg-red-500' : 'bg-blue-500'}`} style={{ width: `${(item.status === 'completed' ? 1 : item.fraction || 0) * 100}%` }}></div>
</div>
<div className="grid grid-cols-4 gap-y-2 gap-x-4 text-[11px] leading-tight">
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[90px]">Progress</span><span className="text-text-secondary truncate">{item.status === 'completed' ? '100%' : ((item.fraction || 0) * 100).toFixed(0) + '%'}</span></div>
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[40px]">Size</span><span className="text-text-secondary truncate">-</span></div>
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[40px]">Speed</span><span className="text-text-secondary truncate">{item.status === 'completed' ? '-' : item.speed || '-'}</span></div>
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[30px]">ETA</span><span className="text-text-secondary truncate">{item.status === 'completed' ? '-' : item.eta || '-'}</span></div>
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[90px]">Live connections</span><span className="text-text-secondary truncate">-</span></div>
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[60px]">Speed cap</span><span className="text-text-secondary truncate">{item.speedLimit || '-'}</span></div>
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[55px]">Category</span><span className="text-text-secondary truncate">{item.category}</span></div>
<div className="grid grid-cols-4 gap-y-2 gap-x-4 text-[11px] leading-tight">
<div className="flex gap-1.5 min-w-0"><span className="text-text-muted font-medium w-[90px] shrink-0">Progress</span><span className="text-text-secondary truncate">{item.status === 'completed' ? '100%' : ((item.fraction || 0) * 100).toFixed(0) + '%'}</span></div>
<div className="flex gap-1.5 min-w-0"><span className="text-text-muted font-medium w-[40px] shrink-0">Size</span><span className="text-text-secondary truncate">{item.size || '-'}</span></div>
<div className="flex gap-1.5 min-w-0"><span className="text-text-muted font-medium w-[40px] shrink-0">Speed</span><span className="text-text-secondary truncate">{item.status === 'completed' ? '-' : item.speed || '-'}</span></div>
<div className="flex gap-1.5 min-w-0"><span className="text-text-muted font-medium w-[30px] shrink-0">ETA</span><span className="text-text-secondary truncate">{item.status === 'completed' ? '-' : item.eta || '-'}</span></div>
<div className="flex gap-1.5 min-w-0"><span className="text-text-muted font-medium w-[90px] shrink-0">Connections</span><span className="text-text-secondary truncate">{item.connections || perServerConnections || '-'}</span></div>
<div className="flex gap-1.5 min-w-0"><span className="text-text-muted font-medium w-[60px] shrink-0">Speed cap</span><span className="text-text-secondary truncate">{item.speedLimit || '-'}</span></div>
<div className="flex gap-1.5 min-w-0"><span className="text-text-muted font-medium w-[55px] shrink-0">Category</span><span className="text-text-secondary truncate">{item.category}</span></div>
<div className="flex gap-1.5"><span className="text-text-muted font-medium w-[50px]">Last try</span><span className="text-text-secondary truncate">-</span></div>
<div className="flex gap-1.5 col-span-2"><span className="text-text-muted font-medium w-[90px]">Date added</span><span className="text-text-secondary truncate">{new Date(item.dateAdded).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' })}</span></div>
+22 -18
View File
@@ -962,10 +962,9 @@
white-space: nowrap;
}
.download-table-header > div:not(:first-child) {
border-left: 1px solid hsl(var(--border-color));
padding-left: 12px;
}
.download-table-header > div:not(:first-child) {
padding-left: 0;
}
.column-resize-handle {
position: absolute;
@@ -990,9 +989,9 @@
height: 32px;
display: grid;
align-items: center;
width: auto;
width: 100%;
padding: 0 16px;
margin: 2px 12px;
margin: 2px 0;
border-radius: 6px;
color: hsl(var(--text-primary));
font-size: 12px;
@@ -1069,12 +1068,12 @@
font-weight: 500;
}
.download-ghost-row {
height: 32px;
margin: 2px 12px;
border-radius: 6px;
flex-shrink: 0;
}
.download-ghost-row {
height: 32px;
margin: 2px 0;
border-radius: 6px;
flex-shrink: 0;
}
.download-ghost-row.striped,
.download-row.striped {
@@ -1085,7 +1084,6 @@
display: flex;
align-items: center;
gap: 8px;
padding-right: 12px;
min-width: 0;
overflow: hidden;
}
@@ -1093,16 +1091,18 @@
.download-status-cell > span {
min-width: 0;
max-width: 100%;
flex: 0 1 auto;
flex: 0 0 72px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 10px;
line-height: 1.2;
font-variant-numeric: tabular-nums;
}
.download-progress-track {
width: 100%;
flex: 1 1 auto;
width: auto;
min-width: 0;
height: 14px;
border-radius: 4px;
@@ -1134,9 +1134,13 @@
animation: pulse-progress 1.5s ease-in-out infinite;
}
.download-status {
font-weight: 500;
}
.download-status {
font-weight: 500;
}
.download-status .truncate {
min-width: 0;
}
.download-status-paused {
color: hsl(var(--status-paused));
+7 -2
View File
@@ -34,8 +34,13 @@ export async function initDownloadListener() {
const mainStore = useDownloadStore.getState();
const current = mainStore.downloads.find(d => d.id === payload.id);
if (current && payload.size && current.size !== payload.size) {
mainStore.updateDownload(payload.id, { size: payload.size });
if (current) {
mainStore.updateDownload(payload.id, {
fraction: payload.fraction,
speed: payload.speed,
eta: payload.eta,
...(payload.size ? { size: payload.size } : {}),
});
}
});