mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-03 03:12:31 +00:00
Merge pull request #444 from PR0M3TH3AN/codex/refactor-torrent-layout-to-use-tailwind
Refactor beacon torrent UI to design system
This commit is contained in:
5 files changed
+389
-191
No files matched your search
@@ -229,6 +229,19 @@ We continue to expose aliases such as `.profile-switcher` and nested variations
|
||||
- Modal templates across the app now mount `.bv-modal`, `.bv-modal-backdrop`, and `.bv-modal__panel` primitives directly. Controllers such as `ProfileModalController` and the upload modal orchestrator were updated to expect these primitives, so any new modal should follow the same structure for consistent accessibility and animation hooks.
|
||||
- The compatibility shim keeps the `.profile-switcher` selector family alive temporarily so third-party embeds and cached HTML fragments continue to render while operators redeploy updated templates. Keep the aliases until the April 2025 removal window above, then delete the shim and update any last callers to the new `.card`/`.btn-ghost` structure.
|
||||
|
||||
## Beacon client migration
|
||||
|
||||
The torrent beacon now shares the Tailwind bundle used across bitvid. The standalone `torrent/beacon.html` drops Skeleton/FoA CDNs in favour of `css/tailwind.generated.css`, adopts the `.card`, `.btn`, `.btn-ghost`, and `.input` primitives, and relies on `.bv-stack` for spacing inside Angular partials. Inline SVG icons replace FontAwesome so controls stay lightweight while inheriting tokenised focus and hover states.
|
||||
|
||||
Angular templates under `torrent/views/` should follow the refreshed structure:
|
||||
|
||||
- Wrap primary sections in `.card` and layer Tailwind utilities for layout (`grid`, `gap-xl`, `overflow-auto`).
|
||||
- Use `.input`, `.select`, `.btn`, and `.btn-ghost` (with `data-variant="critical"` for destructive actions) instead of legacy `.u-full-width`, `.button`, or `.button-danger` classes.
|
||||
- Prefer token-backed utilities for spacing and typography (`px-6`, `py-6`, `text-muted`) over ad-hoc CSS.
|
||||
- Reuse the `.spinner-overlay` markup for async states so overlays stay consistent with the new palette.
|
||||
|
||||
When adding new torrent affordances, mirror the existing markup: inline 24×24 SVG strokes at 2px, `.focus-ring` on interactive anchors, and `.bv-stack` for vertical rhythm. This keeps the beacon aligned with the design system without reintroducing the deprecated Skeleton grid.
|
||||
|
||||
## When to Mix Utilities
|
||||
|
||||
Use the primitives for foundation and lean on Tailwind utilities for:
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ const app = angular.module("BTorrent", [
|
||||
const styleEl = document.createElement("style");
|
||||
styleEl.textContent = `
|
||||
.ui-grid-row {
|
||||
border-bottom: 1px solid var(--color-border-subtle, #d1d5db);
|
||||
border-bottom: 1px solid var(--color-border-subtle);
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(styleEl);
|
||||
|
||||
+39
-21
@@ -21,37 +21,34 @@
|
||||
<script src="bundle.min.js"></script>
|
||||
<!--<script src="https://cdn.jsdelivr.net/combine/npm/webtorrent/webtorrent.min.js,npm/moment@2,npm/[email protected]/angular.min.js,npm/angular-[email protected]/angular-route.min.js,npm/angular-[email protected]/angular-sanitize.min.js,npm/angular-ui-grid@3/ui-grid.min.js,gh/matowens/ng-notify/dist/ng-notify.min.js,npm/ng-file-[email protected]/dist/ng-file-upload.min.js"></script>-->
|
||||
|
||||
<!-- External styles -->
|
||||
<!-- Local styles -->
|
||||
<link rel="stylesheet" href="../css/tailwind.generated.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/g/normalize@3,skeleton@2,angular.ng-notify@0.8(ng-notify.min.css)"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/fontawesome/4/css/font-awesome.min.css"
|
||||
href="https://cdn.jsdelivr.net/gh/matowens/ng-notify/dist/ng-notify.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/angular.ui-grid/3/ui-grid.min.css"
|
||||
/>
|
||||
|
||||
<!-- Local CSS -->
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
|
||||
<body ng-controller="BTorrentCtrl" ng-cloak="">
|
||||
<body class="bg-surface font-sans text-text" ng-controller="BTorrentCtrl" ng-cloak="">
|
||||
<!-- Header with container -->
|
||||
<header class="header-torrent">
|
||||
<div class="container">
|
||||
<div class="logo-container">
|
||||
<a href="../index.html" aria-label="Return to the bitvid home page">
|
||||
<img
|
||||
src="../assets/svg/bitvid-logo-light-mode.svg"
|
||||
alt="bitvid logo"
|
||||
class="bitvid-logo"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-torrent__inner">
|
||||
<a
|
||||
class="header-torrent__logo focus-ring"
|
||||
href="../index.html"
|
||||
aria-label="Return to the bitvid home page"
|
||||
>
|
||||
<img
|
||||
src="../assets/svg/bitvid-logo-light-mode.svg"
|
||||
alt="bitvid logo"
|
||||
class="header-torrent__logo-image"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -60,8 +57,29 @@
|
||||
<div id="view" ng-view></div>
|
||||
|
||||
<!-- Processing Spinner -->
|
||||
<div class="spinner" ng-show="client.processing">
|
||||
<i class="fa fa-spinner fa-spin spinner-icon"></i>
|
||||
<div class="spinner-overlay" ng-show="client.processing">
|
||||
<svg
|
||||
class="spinner-overlay__icon"
|
||||
viewBox="0 0 24 24"
|
||||
role="img"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle
|
||||
class="spinner-overlay__track"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="9"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
></circle>
|
||||
<path
|
||||
class="spinner-overlay__indicator"
|
||||
d="M21 12a9 9 0 0 0-9-9"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- Local Angular code -->
|
||||
|
||||
+68
-35
@@ -1,58 +1,91 @@
|
||||
@import "../css/tokens.css";
|
||||
|
||||
html,
|
||||
body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--font-family-sans, system-ui, -apple-system, sans-serif);
|
||||
background-color: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
line-height: 1.5;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
line-height: var(--line-height-base, 1.5);
|
||||
}
|
||||
|
||||
/* Container used in header & footer */
|
||||
.container {
|
||||
width: 95%;
|
||||
max-width: 95%;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Header styling */
|
||||
.header-torrent {
|
||||
background-color: var(--color-surface);
|
||||
margin-bottom: 2rem;
|
||||
/* No extra horizontal padding so it lines up with .container */
|
||||
border-bottom: 1px solid var(--color-border-translucent-medium);
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
.header-torrent__inner {
|
||||
margin: 0 auto;
|
||||
max-width: 72rem;
|
||||
padding: var(--space-lg) var(--space-md);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bitvid-logo {
|
||||
height: 6rem;
|
||||
.header-torrent__logo {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-xs);
|
||||
border-radius: var(--radius-full);
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
transition: color var(--motion-duration-fast, 120ms)
|
||||
var(--motion-ease-out, ease-out),
|
||||
background-color var(--motion-duration-fast, 120ms)
|
||||
var(--motion-ease-out, ease-out);
|
||||
}
|
||||
|
||||
.header-torrent__logo:hover,
|
||||
.header-torrent__logo:focus-visible {
|
||||
background-color: var(--color-panel-hover);
|
||||
color: var(--color-text-strong);
|
||||
}
|
||||
|
||||
.header-torrent__logo-image {
|
||||
height: 3.5rem;
|
||||
width: auto;
|
||||
/* Adjust spacing around the logo if needed */
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 4rem;
|
||||
}
|
||||
|
||||
/* Footer styling */
|
||||
.footer-torrent {
|
||||
border-top: 1px solid var(--color-border-translucent-medium);
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
margin-top: 2rem;
|
||||
background-color: var(--color-surface);
|
||||
text-align: center;
|
||||
.spinner-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 60;
|
||||
background-color: var(--color-overlay-muted, rgba(15, 23, 42, 0.35));
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
/* If you want to override the generic footer rules, remove them or unify here:
|
||||
footer {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin-top: 4rem;
|
||||
padding-top: 2rem;
|
||||
.spinner-overlay__icon {
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
stroke: var(--color-info-strong);
|
||||
animation: spinner-rotate
|
||||
calc(var(--motion-duration-base, 160ms) * 6)
|
||||
linear
|
||||
infinite;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Additional styling remains unchanged... */
|
||||
.spinner-overlay__track {
|
||||
stroke: var(--color-border-translucent);
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
.spinner-overlay__indicator {
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
||||
@keyframes spinner-rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
+268
-134
@@ -1,153 +1,287 @@
|
||||
<!-- MAIN CONTENT AREA -->
|
||||
<div class="container">
|
||||
<div class="mx-auto max-w-5xl px-4 py-6 sm:px-6 lg:px-8 bv-stack">
|
||||
<!-- Input row for adding or opening torrents -->
|
||||
<div class="row">
|
||||
<div class="four columns">
|
||||
<input
|
||||
class="u-full-width"
|
||||
type="text"
|
||||
placeholder="magnet, hash or http(s) .torrent"
|
||||
ng-model="torrentInput"
|
||||
ng-disabled="$root.disabled"
|
||||
/>
|
||||
</div>
|
||||
<section class="card p-6">
|
||||
<form
|
||||
class="bv-stack bv-stack--tight md:flex md:flex-row md:items-end md:gap-md"
|
||||
ng-submit="addMagnet()"
|
||||
>
|
||||
<div class="bv-stack bv-stack--tight flex-1">
|
||||
<label
|
||||
class="text-xs font-semibold uppercase tracking-wide text-muted-strong"
|
||||
for="torrentInput"
|
||||
>
|
||||
Magnet, hash, or HTTPS .torrent URL
|
||||
</label>
|
||||
<input
|
||||
id="torrentInput"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="magnet:?xt=…"
|
||||
ng-model="torrentInput"
|
||||
ng-disabled="$root.disabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="two columns download-button">
|
||||
<!-- "Download" button for adding a magnet/torrent -->
|
||||
<button
|
||||
ng-click="addMagnet()"
|
||||
ng-disabled="!torrentInput.length || $root.disabled"
|
||||
class="button button-danger"
|
||||
>
|
||||
<i class="fa fa-download"></i> Download
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-3 md:justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn inline-flex items-center gap-2"
|
||||
ng-disabled="!torrentInput.length || $root.disabled"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M12 3v14"></path>
|
||||
<path d="m6 11 6 6 6-6"></path>
|
||||
<path d="M19 21H5"></path>
|
||||
</svg>
|
||||
Download
|
||||
</button>
|
||||
|
||||
<div class="three columns"></div>
|
||||
|
||||
<div class="three columns u-pull-right">
|
||||
<!-- "Seed files" button -->
|
||||
<button
|
||||
class="button button-danger u-pull-right"
|
||||
ngf-select="$root.seedFiles($files)"
|
||||
multiple="true"
|
||||
ng-disabled="$root.disabled"
|
||||
>
|
||||
<i class="fa fa-upload"></i> Seed files
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-ghost inline-flex items-center gap-2"
|
||||
ngf-select="$root.seedFiles($files)"
|
||||
multiple="true"
|
||||
ng-disabled="$root.disabled"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M12 21V7"></path>
|
||||
<path d="m6 13 6-6 6 6"></path>
|
||||
<path d="M5 21h14"></path>
|
||||
</svg>
|
||||
Seed files
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- ui-grid for active torrents (Name, Progress, Speeds, Peers, Ratio) -->
|
||||
<div
|
||||
class="row grid"
|
||||
<section
|
||||
class="card overflow-hidden"
|
||||
ui-grid="gridOptions"
|
||||
ui-grid-resize-columns="ui-grid-resize-columns"
|
||||
ui-grid-selection="ui-grid-selection"
|
||||
></div>
|
||||
aria-label="Active torrents"
|
||||
></section>
|
||||
|
||||
<!-- Selected torrent details: Pause/Resume, Download, Remove -->
|
||||
<div class="row" ng-if="selectedTorrent">
|
||||
<div class="six columns" style="overflow: auto">
|
||||
<h5>
|
||||
{{ selectedTorrent.name }}
|
||||
<section class="card p-6" ng-if="selectedTorrent">
|
||||
<div class="grid gap-xl lg:grid-cols-2">
|
||||
<div class="bv-stack bv-stack--tight overflow-auto">
|
||||
<div class="bv-stack bv-stack--tight">
|
||||
<h2 class="text-lg font-semibold text-text">
|
||||
{{ selectedTorrent.name }}
|
||||
</h2>
|
||||
|
||||
<!-- Pause/Resume buttons -->
|
||||
<button
|
||||
ng-if="!selectedTorrent.paused"
|
||||
ng-click="selectedTorrent.pause()"
|
||||
>
|
||||
<i class="fa fa-pause"></i> Pause
|
||||
</button>
|
||||
<button
|
||||
ng-if="selectedTorrent.paused"
|
||||
ng-click="selectedTorrent.resume()"
|
||||
>
|
||||
<i class="fa fa-play"></i> Resume
|
||||
</button>
|
||||
|
||||
<!-- Download ALL files (only if progress == 1) -->
|
||||
<button
|
||||
class="button button-danger"
|
||||
ng-click="$root.downloadAll(selectedTorrent)"
|
||||
ng-disabled="selectedTorrent.progress < 1"
|
||||
>
|
||||
<i class="fa fa-download"></i> Download
|
||||
</button>
|
||||
|
||||
<!-- Remove button -->
|
||||
<button
|
||||
class="button button-danger"
|
||||
ng-click="selectedTorrent.destroy($root.destroyedTorrent)"
|
||||
>
|
||||
<i class="fa fa-times"></i> Remove
|
||||
</button>
|
||||
</h5>
|
||||
|
||||
<h6>Share</h6>
|
||||
<ul>
|
||||
<li>
|
||||
<!-- Copy magnet button -->
|
||||
<button
|
||||
class="button button-small"
|
||||
ng-click="$root.copyMagnetURI(selectedTorrent)"
|
||||
>
|
||||
Copy Magnet
|
||||
</button>
|
||||
</li>
|
||||
<li><strong>Hash:</strong> {{ selectedTorrent.infoHash }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="six columns">
|
||||
<h5>Files</h5>
|
||||
<table class="u-full-width">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Size</th>
|
||||
<th>Priority</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="files" ng-repeat="file in selectedTorrent.files">
|
||||
<!-- If file isn't finished, just show the name. -->
|
||||
<td ng-hide="file.done">{{ file.name }}</td>
|
||||
<!-- If file is done, show direct link to download it. -->
|
||||
<td ng-show="file.done">
|
||||
<a ng-href="{{ file.url }}" download="{{ file.name }}">
|
||||
{{ file.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ file.length | pbytes }}</td>
|
||||
<td>
|
||||
<select
|
||||
class="no-margin"
|
||||
name="{{ file.name }}Priority"
|
||||
ng-model="file.priority"
|
||||
ng-init="file.priority = '0'"
|
||||
ng-change="$root.changePriority(file)"
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-ghost inline-flex items-center gap-2"
|
||||
ng-if="!selectedTorrent.paused"
|
||||
ng-click="selectedTorrent.pause()"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<option value="1">High Priority</option>
|
||||
<option value="0" selected="">Low Priority</option>
|
||||
<option value="-1">Don't download</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<rect x="6" y="4" width="4" height="16"></rect>
|
||||
<rect x="14" y="4" width="4" height="16"></rect>
|
||||
</svg>
|
||||
Pause
|
||||
</button>
|
||||
|
||||
<div class="center">
|
||||
<strong>
|
||||
Client Stats: ↓ {{ client.downloadSpeed | pbytes }}/s · ↑ {{
|
||||
client.uploadSpeed | pbytes }}/s · Ratio: {{ client.ratio | number:2 }}
|
||||
</strong>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-ghost inline-flex items-center gap-2"
|
||||
ng-if="selectedTorrent.paused"
|
||||
ng-click="selectedTorrent.resume()"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<polygon points="6 4 20 12 6 20 6 4"></polygon>
|
||||
</svg>
|
||||
Resume
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn inline-flex items-center gap-2"
|
||||
ng-click="$root.downloadAll(selectedTorrent)"
|
||||
ng-disabled="selectedTorrent.progress < 1"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M12 3v14"></path>
|
||||
<path d="m6 11 6 6 6-6"></path>
|
||||
</svg>
|
||||
Download all
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-ghost inline-flex items-center gap-2"
|
||||
data-variant="critical"
|
||||
ng-click="selectedTorrent.destroy($root.destroyedTorrent)"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M18 6L6 18"></path>
|
||||
<path d="M6 6l12 12"></path>
|
||||
</svg>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bv-stack bv-stack--tight">
|
||||
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted">
|
||||
Share
|
||||
</h3>
|
||||
<ul class="bv-stack bv-stack--tight text-sm text-muted-strong">
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-ghost inline-flex items-center gap-2 text-xs"
|
||||
ng-click="$root.copyMagnetURI(selectedTorrent)"
|
||||
>
|
||||
Copy magnet
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<strong class="font-semibold text-text">Hash:</strong>
|
||||
{{ selectedTorrent.infoHash }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bv-stack bv-stack--tight">
|
||||
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted">
|
||||
Files
|
||||
</h3>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-border-translucent text-sm">
|
||||
<thead class="bg-surface-alt text-muted-strong">
|
||||
<tr>
|
||||
<th class="px-3 py-2 text-left font-medium">Name</th>
|
||||
<th class="px-3 py-2 text-left font-medium">Size</th>
|
||||
<th class="px-3 py-2 text-left font-medium">Priority</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border-translucent bg-surface">
|
||||
<tr class="align-top" ng-repeat="file in selectedTorrent.files">
|
||||
<td class="px-3 py-2">
|
||||
<span ng-hide="file.done">{{ file.name }}</span>
|
||||
<a
|
||||
class="text-info hover:text-info-strong"
|
||||
ng-show="file.done"
|
||||
ng-href="{{ file.url }}"
|
||||
download="{{ file.name }}"
|
||||
>
|
||||
{{ file.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-3 py-2 text-muted-strong">
|
||||
{{ file.length | pbytes }}
|
||||
</td>
|
||||
<td class="px-3 py-2">
|
||||
<select
|
||||
class="select"
|
||||
name="{{ file.name }}Priority"
|
||||
ng-model="file.priority"
|
||||
ng-init="file.priority = '0'"
|
||||
ng-change="$root.changePriority(file)"
|
||||
aria-label="Set priority for {{ file.name }}"
|
||||
>
|
||||
<option value="1">High priority</option>
|
||||
<option value="0" selected="">Low priority</option>
|
||||
<option value="-1">Don't download</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="text-center text-sm font-semibold text-muted">
|
||||
Client stats: ↓ {{ client.downloadSpeed | pbytes }}/s · ↑ {{
|
||||
client.uploadSpeed | pbytes }}/s · Ratio: {{ client.ratio | number:2 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Processing Spinner -->
|
||||
<div class="spinner" ng-show="client.processing">
|
||||
<i class="fa fa-spinner fa-spin spinner-icon"></i>
|
||||
<div class="spinner-overlay" ng-show="client.processing">
|
||||
<svg
|
||||
class="spinner-overlay__icon"
|
||||
viewBox="0 0 24 24"
|
||||
role="img"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle
|
||||
class="spinner-overlay__track"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="9"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
></circle>
|
||||
<path
|
||||
class="spinner-overlay__indicator"
|
||||
d="M21 12a9 9 0 0 0-9-9"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
Reference in new issue
Block a user