Swap @ng-icons/mynaui for @ng-icons/tdesign-icons (34.0.0, the release matching @ng-icons/core), drawn at TDesign's native stroke. Each former mynaui name maps to one TDesign name everywhere it was used; the unused ArrowLeftRight is dropped. The options button's ellipsis goes from 1.5rem to 0.8rem: TDesign's dots span 18 of 24 units against mynaui's 8, so this keeps today's footprint. Co-Authored-By: Claude <noreply@anthropic.com>
79 lines
3.3 KiB
TypeScript
79 lines
3.3 KiB
TypeScript
import { Component, computed, inject } from '@angular/core';
|
|
import { NgIcon } from '@ng-icons/core';
|
|
import { I18nService } from '@core/i18n.service';
|
|
import type { TransferSnapshot } from '@shared/types';
|
|
import { formatSpeed } from '@core/format';
|
|
import { PanelsService } from '@core/panels.service';
|
|
import { SettingsService } from '@core/settings.service';
|
|
import { TransfersService } from '@core/transfers.service';
|
|
|
|
@Component({
|
|
selector: 'app-status-bar',
|
|
imports: [NgIcon],
|
|
template: `
|
|
<div
|
|
class="flex h-6 items-center justify-between gap-4 border-t border-border bg-chrome px-3 text-[0.6875rem] text-muted-foreground select-none"
|
|
>
|
|
<!-- transfers summary; click toggles the detailed list -->
|
|
<button
|
|
(click)="transfers.expanded.set(!transfers.expanded())"
|
|
class="flex min-w-0 items-center gap-1.5 hover:text-foreground"
|
|
[title]="i18n.t('transfer.showDetails')"
|
|
>
|
|
@if (transfers.currentJob(); as job) {
|
|
<ng-icon name="tdesignLoading" size="0.8rem" class="shrink-0 animate-spin text-primary" />
|
|
<span class="truncate">
|
|
{{ i18n.t('transfer.copying', { name: job.name, percent: percent(job), speed: speedSuffix(job) }) }}
|
|
@if (transfers.queuedCount(); as queued) {
|
|
· {{ i18n.t('transfer.queued', { count: queued }) }}
|
|
}
|
|
</span>
|
|
} @else if (transfers.failedJobs().length; as failed) {
|
|
<ng-icon name="tdesignCloseCircle" size="0.8rem" class="shrink-0 text-destructive" />
|
|
<span class="text-destructive">
|
|
{{ i18n.t('transfer.failed', { count: failed }) }}
|
|
</span>
|
|
} @else if (transfers.hasJobs()) {
|
|
<ng-icon name="tdesignCheckCircle" size="0.8rem" class="shrink-0 text-success" />
|
|
<span>{{ i18n.t('transfer.finished') }}</span>
|
|
} @else {
|
|
<span>{{ i18n.t('transfer.ready') }}</span>
|
|
}
|
|
</button>
|
|
|
|
<!-- active panel info -->
|
|
<div class="flex shrink-0 items-center gap-1.5">
|
|
<ng-icon
|
|
[name]="activePanel().sessionId() === 'local' ? 'tdesignHardDrive' : 'tdesignServer'"
|
|
size="0.8rem"
|
|
[class.text-primary]="activePanel().sessionId() !== 'local'"
|
|
/>
|
|
<span class="max-w-56 truncate">
|
|
{{ activePanel().sessionId() === 'local' ? i18n.t('common.local') : activePanel().title() }}
|
|
</span>
|
|
<span>· {{ i18n.t('transfer.items', { count: activePanel().sorted().length }) }}</span>
|
|
@if (activePanel().selected().size; as count) {
|
|
<span>· {{ i18n.t('transfer.selected', { count }) }}</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
`,
|
|
})
|
|
export class StatusBar {
|
|
readonly i18n = inject(I18nService);
|
|
readonly transfers = inject(TransfersService);
|
|
readonly panels = inject(PanelsService);
|
|
readonly settings = inject(SettingsService);
|
|
readonly activePanel = computed(() => this.panels.get(this.panels.activeSide()));
|
|
|
|
percent(job: TransferSnapshot): number {
|
|
if (!job.totalBytes) return 0;
|
|
return Math.min(100, Math.round((job.doneBytes / job.totalBytes) * 100));
|
|
}
|
|
|
|
speedSuffix(job: TransferSnapshot): string {
|
|
const speed = this.transfers.speeds().get(job.id);
|
|
return speed ? ` · ${formatSpeed(speed, this.settings.speedUnit())}` : '';
|
|
}
|
|
}
|