mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-27 11:07:08 +00:00
fix(ui): align download list and live properties
This commit is contained in:
@@ -7,15 +7,16 @@ import { open } from '@tauri-apps/plugin-dialog';
|
|||||||
type LoginMode = 'matching' | 'custom' | 'none';
|
type LoginMode = 'matching' | 'custom' | 'none';
|
||||||
|
|
||||||
export const PropertiesModal = () => {
|
export const PropertiesModal = () => {
|
||||||
const {
|
const selectedPropertiesDownloadId = useDownloadStore(state => state.selectedPropertiesDownloadId);
|
||||||
selectedPropertiesDownloadId,
|
const setSelectedPropertiesDownloadId = useDownloadStore(state => state.setSelectedPropertiesDownloadId);
|
||||||
setSelectedPropertiesDownloadId,
|
const updateDownload = useDownloadStore(state => state.updateDownload);
|
||||||
updateDownload
|
const item = useDownloadStore(state =>
|
||||||
} = useDownloadStore();
|
selectedPropertiesDownloadId
|
||||||
|
? state.downloads.find(d => d.id === selectedPropertiesDownloadId) ?? null
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
const { defaultDownloadPath } = useSettingsStore();
|
const { defaultDownloadPath, perServerConnections } = useSettingsStore();
|
||||||
|
|
||||||
const [item, setItem] = useState<DownloadItem | null>(null);
|
|
||||||
|
|
||||||
// Form states
|
// Form states
|
||||||
const [url, setUrl] = useState('');
|
const [url, setUrl] = useState('');
|
||||||
@@ -44,7 +45,6 @@ export const PropertiesModal = () => {
|
|||||||
if (selectedPropertiesDownloadId) {
|
if (selectedPropertiesDownloadId) {
|
||||||
const activeItem = useDownloadStore.getState().downloads.find(d => d.id === selectedPropertiesDownloadId);
|
const activeItem = useDownloadStore.getState().downloads.find(d => d.id === selectedPropertiesDownloadId);
|
||||||
if (activeItem) {
|
if (activeItem) {
|
||||||
setItem(activeItem);
|
|
||||||
setUrl(activeItem.url);
|
setUrl(activeItem.url);
|
||||||
setFileName(activeItem.fileName);
|
setFileName(activeItem.fileName);
|
||||||
setSaveLocation(activeItem.destination || defaultDownloadPath || '~/Downloads');
|
setSaveLocation(activeItem.destination || defaultDownloadPath || '~/Downloads');
|
||||||
@@ -83,12 +83,10 @@ export const PropertiesModal = () => {
|
|||||||
setMirrors(activeItem.mirrors || '');
|
setMirrors(activeItem.mirrors || '');
|
||||||
setErrorMessage('');
|
setErrorMessage('');
|
||||||
} else {
|
} else {
|
||||||
setItem(null);
|
setSelectedPropertiesDownloadId(null);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
setItem(null);
|
|
||||||
}
|
}
|
||||||
}, [selectedPropertiesDownloadId, defaultDownloadPath]);
|
}, [selectedPropertiesDownloadId, defaultDownloadPath, setSelectedPropertiesDownloadId]);
|
||||||
|
|
||||||
if (!selectedPropertiesDownloadId || !item) return null;
|
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 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>
|
||||||
|
|
||||||
<div className="grid grid-cols-4 gap-y-2 gap-x-4 text-[11px] leading-tight">
|
<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 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"><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 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"><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 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"><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 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"><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 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"><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 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"><span className="text-text-muted font-medium w-[55px]">Category</span><span className="text-text-secondary truncate">{item.category}</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"><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>
|
<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
@@ -962,10 +962,9 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-table-header > div:not(:first-child) {
|
.download-table-header > div:not(:first-child) {
|
||||||
border-left: 1px solid hsl(var(--border-color));
|
padding-left: 0;
|
||||||
padding-left: 12px;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.column-resize-handle {
|
.column-resize-handle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -990,9 +989,9 @@
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: auto;
|
width: 100%;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
margin: 2px 12px;
|
margin: 2px 0;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
color: hsl(var(--text-primary));
|
color: hsl(var(--text-primary));
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -1069,12 +1068,12 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-ghost-row {
|
.download-ghost-row {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
margin: 2px 12px;
|
margin: 2px 0;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-ghost-row.striped,
|
.download-ghost-row.striped,
|
||||||
.download-row.striped {
|
.download-row.striped {
|
||||||
@@ -1085,7 +1084,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding-right: 12px;
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -1093,16 +1091,18 @@
|
|||||||
.download-status-cell > span {
|
.download-status-cell > span {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
flex: 0 1 auto;
|
flex: 0 0 72px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
line-height: 1.2;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-progress-track {
|
.download-progress-track {
|
||||||
width: 100%;
|
flex: 1 1 auto;
|
||||||
|
width: auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -1134,9 +1134,13 @@
|
|||||||
animation: pulse-progress 1.5s ease-in-out infinite;
|
animation: pulse-progress 1.5s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-status {
|
.download-status {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.download-status .truncate {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.download-status-paused {
|
.download-status-paused {
|
||||||
color: hsl(var(--status-paused));
|
color: hsl(var(--status-paused));
|
||||||
|
|||||||
@@ -34,8 +34,13 @@ export async function initDownloadListener() {
|
|||||||
|
|
||||||
const mainStore = useDownloadStore.getState();
|
const mainStore = useDownloadStore.getState();
|
||||||
const current = mainStore.downloads.find(d => d.id === payload.id);
|
const current = mainStore.downloads.find(d => d.id === payload.id);
|
||||||
if (current && payload.size && current.size !== payload.size) {
|
if (current) {
|
||||||
mainStore.updateDownload(payload.id, { size: payload.size });
|
mainStore.updateDownload(payload.id, {
|
||||||
|
fraction: payload.fraction,
|
||||||
|
speed: payload.speed,
|
||||||
|
eta: payload.eta,
|
||||||
|
...(payload.size ? { size: payload.size } : {}),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user