diff --git a/client/src/app/torrent-table/torrent-table.component.html b/client/src/app/torrent-table/torrent-table.component.html index 7c170d8..7674e0c 100644 --- a/client/src/app/torrent-table/torrent-table.component.html +++ b/client/src/app/torrent-table/torrent-table.component.html @@ -24,68 +24,99 @@ }
- - - - - - - - - - - - - - - - - @for (torrent of torrents | sort: sortProperty : sortDirection; track torrent.torrentId) { + @if (!isMobile) { +
- - NameCategoryPrioritySeedersFilesDownloadsSizeRequestedStatus
+ - + + + + + + + + + + + + + @for (torrent of torrents | sort: sortProperty : sortDirection; track torrent.torrentId) { + + + + + + + + + + + + + } + +
+ + + NameCategoryPrioritySeedersFilesDownloadsSizeRequestedStatus
+ + + {{ torrent.rdName }} + + {{ torrent.category }} + + {{ torrent.priority }} + + {{ torrent.rdSeeders }} + + {{ torrent.files.length | number }} + + {{ torrent.downloads.length | number }} + + {{ torrent.rdSize | filesize }} + + {{ torrent.added | date: "medium" }} + + {{ torrent | status }} +
+ } @else { +
+ @for (torrent of torrents | sort: sortProperty : sortDirection; track torrent.torrentId) { +
+
- - - {{ torrent.rdName }} - - - {{ torrent.category }} - - - {{ torrent.priority }} - - - {{ torrent.rdSeeders }} - - - {{ torrent.files.length | number }} - - - {{ torrent.downloads.length | number }} - - - {{ torrent.rdSize | filesize }} - - - {{ torrent.added | date: "medium" }} - - - {{ torrent | status }} - - +
+
+

{{ torrent.rdName }}

+
+ {{ torrent | status }} + @if (torrent.category) { + {{ torrent.category }} + } +
+
+ Size {{ torrent.rdSize | filesize }} + Seeders {{ torrent.rdSeeders }} + Files {{ torrent.files.length | number }} + Downloads {{ torrent.downloads.length | number }} +
+
+
} - - +
+ }
@if (torrents.length > 0) { diff --git a/client/src/app/torrent-table/torrent-table.component.scss b/client/src/app/torrent-table/torrent-table.component.scss index 071fdc9..f741d20 100644 --- a/client/src/app/torrent-table/torrent-table.component.scss +++ b/client/src/app/torrent-table/torrent-table.component.scss @@ -5,12 +5,74 @@ table { word-break: break-all; } } - // Make table horizontally scrollable on small screens - @media screen and (max-width: 768px) { - display: block; - overflow-x: auto; - white-space: nowrap; - } +} + +.mobile-cards { + display: block; +} + +.mobile-card { + display: flex; + align-items: flex-start; + gap: 0.75rem; + padding: 0.875rem 0.75rem !important; + margin-bottom: 0.5rem !important; + cursor: pointer; + + &.is-selected { + border-left: 3px solid hsl(217, 71%, 53%); + } + + &:active { + background-color: hsl(0, 0%, 96%); + } +} + +.mobile-card-checkbox { + flex-shrink: 0; + padding-top: 0.125rem; + + input[type='checkbox'] { + width: 1.1rem; + height: 1.1rem; + cursor: pointer; + } +} + +.mobile-card-body { + flex: 1; + min-width: 0; +} + +.mobile-card-name { + font-weight: 600; + font-size: 0.9rem; + line-height: 1.3; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-bottom: 0.375rem; + color: hsl(0, 0%, 21%); +} + +.mobile-card-details { + display: flex; + flex-wrap: wrap; + gap: 0.25rem 1rem; +} + +.mobile-card-detail { + font-size: 0.8rem; + color: hsl(0, 0%, 29%); + white-space: nowrap; + + .detail-label { + color: hsl(0, 0%, 48%); + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.03em; + margin-right: 0.2em; + } } .flex-container { @@ -18,6 +80,7 @@ table { flex: 1 1 0; gap: 20px; flex-direction: row; + margin-top: 1rem; @media screen and (max-width: 1279px) { flex-direction: column; diff --git a/client/src/app/torrent-table/torrent-table.component.ts b/client/src/app/torrent-table/torrent-table.component.ts index 4b5100e..44d9bbd 100644 --- a/client/src/app/torrent-table/torrent-table.component.ts +++ b/client/src/app/torrent-table/torrent-table.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { Torrent } from '../models/torrent.model'; import { DiskSpaceStatus } from '../models/disk-space-status.model'; @@ -18,7 +18,7 @@ import { FileSizePipe } from '../filesize.pipe'; imports: [FormsModule, NgClass, DecimalPipe, DatePipe, TorrentStatusPipe, SortPipe, FileSizePipe], standalone: true, }) -export class TorrentTableComponent implements OnInit { +export class TorrentTableComponent implements OnInit, OnDestroy { public torrents: Torrent[] = []; public selectedTorrents: string[] = []; public error: string; @@ -53,12 +53,23 @@ export class TorrentTableComponent implements OnInit { public diskSpaceStatus: DiskSpaceStatus | null = null; public rateLimitStatus: RateLimitStatus | null = null; + public isMobile = false; + private mobileQuery: MediaQueryList; + private mobileQueryListener: (e: MediaQueryListEvent) => void; + constructor( private router: Router, private torrentService: TorrentService, ) {} ngOnInit(): void { + this.mobileQuery = window.matchMedia('(max-width: 768px)'); + this.isMobile = this.mobileQuery.matches; + this.mobileQueryListener = (e: MediaQueryListEvent) => { + this.isMobile = e.matches; + }; + this.mobileQuery.addEventListener('change', this.mobileQueryListener); + // Load persisted sort settings (if any) try { const sp = localStorage.getItem('torrentTable.sortProperty'); @@ -320,4 +331,8 @@ export class TorrentTableComponent implements OnInit { updateDeleteSelectAll() { this.deleteSelectAll = this.deleteData && this.deleteRdTorrent && this.deleteLocalFiles; } + + ngOnDestroy(): void { + this.mobileQuery?.removeEventListener('change', this.mobileQueryListener); + } }