mirror of
https://github.com/transmission/transmission
synced 2025-03-04 02:28:03 +00:00
feat: add drag-and-drop in web interface (#5082)
This commit is contained in:
parent
06c784f639
commit
60d4bedf33
4 changed files with 64 additions and 34 deletions
|
@ -4,9 +4,11 @@
|
||||||
// Colors related to torrent status
|
// Colors related to torrent status
|
||||||
$blue-100: #dbedff;
|
$blue-100: #dbedff;
|
||||||
$blue-300: #79b8ff;
|
$blue-300: #79b8ff;
|
||||||
|
$blue-500: #0366d6;
|
||||||
$green-200: #bef5cb;
|
$green-200: #bef5cb;
|
||||||
$green-300: #85e89d;
|
$green-300: #85e89d;
|
||||||
$green-500: #28a745;
|
$green-500: #28a745;
|
||||||
|
$green-700: #22863a;
|
||||||
$grey-200: #e1e4e8;
|
$grey-200: #e1e4e8;
|
||||||
$grey-500: #828282;
|
$grey-500: #828282;
|
||||||
$grey-700: #373737;
|
$grey-700: #373737;
|
||||||
|
@ -14,6 +16,7 @@ $grey-800: #292929;
|
||||||
$grey-900: #191919;
|
$grey-900: #191919;
|
||||||
$red-500: #d73a49;
|
$red-500: #d73a49;
|
||||||
$white: #fff;
|
$white: #fff;
|
||||||
|
$dark-mode-white: #c9d1d9;
|
||||||
$yellow-300: #ffea7f;
|
$yellow-300: #ffea7f;
|
||||||
$grey-40: #666;
|
$grey-40: #666;
|
||||||
$nice-grey: #f8f8f8;
|
$nice-grey: #f8f8f8;
|
||||||
|
@ -82,7 +85,7 @@ $image-play-circle-idle: '../img/play-circle-idle.svg';
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
--color-bg-hover: #{$grey-40};
|
--color-bg-hover: #{$grey-40};
|
||||||
--color-fg-primary: #fff;
|
--color-fg-primary: #{$dark-mode-white};
|
||||||
--color-bg-primary: #{$grey-800};
|
--color-bg-primary: #{$grey-800};
|
||||||
--color-bg-primary-hover: #{$grey-700};
|
--color-bg-primary-hover: #{$grey-700};
|
||||||
--color-bg-odd: #{$grey-900};
|
--color-bg-odd: #{$grey-900};
|
||||||
|
@ -90,29 +93,38 @@ $image-play-circle-idle: '../img/play-circle-idle.svg';
|
||||||
--color-bg-menu: #{$grey-800};
|
--color-bg-menu: #{$grey-800};
|
||||||
--color-fg-secondary: #{$nice-grey};
|
--color-fg-secondary: #{$nice-grey};
|
||||||
--color-fg-on-popup: #{$nice-grey};
|
--color-fg-on-popup: #{$nice-grey};
|
||||||
--color-fg-disabled: #{$nice-grey};
|
--color-fg-disabled: #{$dark-mode-white};
|
||||||
--color-bg-popup: #{$grey-800};
|
--color-bg-popup: #{$grey-800};
|
||||||
--color-bg-warn: #cf6679;
|
--color-bg-warn: #cf6679;
|
||||||
--color-fg-warn: #{$dark-mode-black};
|
--color-fg-warn: #{$dark-mode-black};
|
||||||
--color-border: #{$nice-grey};
|
--color-border: #{$dark-mode-white};
|
||||||
--color-border-selected: #d0d7de;
|
--color-border-selected: #{$grey-500};
|
||||||
--color-fg-tertiary: #{$grey-500};
|
--color-fg-tertiary: #{$grey-500};
|
||||||
--color-toolbar-background: #{$grey-800};
|
--color-toolbar-background: #{$grey-800};
|
||||||
--color-inspector-background: #{$grey-800};
|
--color-inspector-background: #{$grey-800};
|
||||||
--color-inspector-tabs: #{$nice-grey};
|
--color-inspector-tabs: #{$nice-grey};
|
||||||
--color-bg-selected: #{$default-accent-color-dark};
|
--color-bg-selected: #{$default-accent-color-dark};
|
||||||
--color-bg-tabs: #{$grey-700};
|
--color-bg-tabs: #{$grey-700};
|
||||||
--color-progressbar-background-1: #426389;
|
|
||||||
--color-default-border: #{$default-border-dark};
|
--color-default-border: #{$default-border-dark};
|
||||||
--color-progressbar-seed-1: #{$green-500};
|
--color-progressbar-seed-1: #{$green-700};
|
||||||
--color-progressbar-seed-2: #{$green-300};
|
--color-progressbar-seed-2: #{$green-500};
|
||||||
--color-progressbar-paused: #{$grey-500};
|
--color-progressbar-paused: #{$grey-500};
|
||||||
|
--color-progressbar-leech: #{$blue-500};
|
||||||
--color-progressbar-seed-paused: #{$grey-500};
|
--color-progressbar-seed-paused: #{$grey-500};
|
||||||
}
|
}
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
|
--progress: 100%;
|
||||||
|
--color-fg-error: #{$red-500};
|
||||||
|
--color-fg-port-closed: #{$red-500};
|
||||||
|
--color-fg-port-open: #{$green-500};
|
||||||
|
--color-progressbar-verify: #{$yellow-300};
|
||||||
|
--color-progressbar-magnet: #{$yellow-300};
|
||||||
|
--color-progressbar-paused: #{$grey-200};
|
||||||
|
--color-progressbar-leech: #{$blue-300};
|
||||||
|
--color-progressbar-queued: #{$blue-100};
|
||||||
--color-bg-hover: #{$nice-grey};
|
--color-bg-hover: #{$nice-grey};
|
||||||
--color-fg-primary: #404040;
|
--color-fg-primary: #404040;
|
||||||
--color-bg-primary: #fff;
|
--color-bg-primary: #{$white};
|
||||||
--color-bg-even: #{$white};
|
--color-bg-even: #{$white};
|
||||||
--color-bg-odd: #{$nice-grey};
|
--color-bg-odd: #{$nice-grey};
|
||||||
--color-bg-menu: #{$nice-grey};
|
--color-bg-menu: #{$nice-grey};
|
||||||
|
@ -130,7 +142,6 @@ $image-play-circle-idle: '../img/play-circle-idle.svg';
|
||||||
--color-bg-tabs: #{$nice-grey-darker};
|
--color-bg-tabs: #{$nice-grey-darker};
|
||||||
--color-inspector-tabs: #{$nice-grey};
|
--color-inspector-tabs: #{$nice-grey};
|
||||||
--color-bg-selected: #{$default-accent-color};
|
--color-bg-selected: #{$default-accent-color};
|
||||||
--color-progressbar-background-1: #{$nice-grey};
|
|
||||||
--color-default-border: #{$default-border-light};
|
--color-default-border: #{$default-border-light};
|
||||||
--color-dialog-border: #{$nice-grey};
|
--color-dialog-border: #{$nice-grey};
|
||||||
--color-progressbar-seed-1: #{$green-300};
|
--color-progressbar-seed-1: #{$green-300};
|
||||||
|
@ -467,7 +478,7 @@ $video-image: '../img/film.svg';
|
||||||
.torrent-progress-details,
|
.torrent-progress-details,
|
||||||
.torrent-peer-details {
|
.torrent-peer-details {
|
||||||
color: var(--color-fg-primary);
|
color: var(--color-fg-primary);
|
||||||
font-size: x-small;
|
font-size: small;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.compact {
|
&.compact {
|
||||||
|
@ -880,6 +891,7 @@ $video-image: '../img/film.svg';
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
color: var(--color-fg-primary);
|
color: var(--color-fg-primary);
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -908,7 +920,6 @@ $video-image: '../img/film.svg';
|
||||||
background-color: var(--color-bg-even);
|
background-color: var(--color-bg-even);
|
||||||
border: 1px solid var(--color-fg-primary);
|
border: 1px solid var(--color-fg-primary);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,6 +1325,7 @@ $video-image: '../img/film.svg';
|
||||||
a,
|
a,
|
||||||
button,
|
button,
|
||||||
label {
|
label {
|
||||||
|
color: var(--color-fg-primary);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -1646,18 +1658,28 @@ dialog {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
#torrent-upload-frame {
|
|
||||||
border: 0;
|
|
||||||
display: block; /* Don't change this : safari forms won't target hidden frames (they open a new window) */
|
|
||||||
height: 0;
|
|
||||||
left: -1000px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: -1000px;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui-menu {
|
.ui-menu {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.upload-div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone {
|
||||||
|
background: var(--color-bg-primary);
|
||||||
|
border: 2px dashed var(--color-border);
|
||||||
|
border-radius: 5px;
|
||||||
|
color: var(--color-fg-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -212,12 +212,9 @@
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<iframe
|
<div class="upload-div">
|
||||||
name="torrent-upload-frame"
|
<h2>Drag your torrent files here to add them to Transmission.</h2>
|
||||||
id="torrent-upload-frame"
|
</div>
|
||||||
src="about:blank"
|
|
||||||
title="Add Torrent"
|
|
||||||
></iframe>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { Formatter } from './formatter.js';
|
||||||
import { createDialogContainer, makeUUID } from './utils.js';
|
import { createDialogContainer, makeUUID } from './utils.js';
|
||||||
|
|
||||||
export class OpenDialog extends EventTarget {
|
export class OpenDialog extends EventTarget {
|
||||||
constructor(controller, remote, url = '') {
|
constructor(controller, remote, url = '', files = []) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
@ -17,8 +17,11 @@ export class OpenDialog extends EventTarget {
|
||||||
this.elements = this._create(url);
|
this.elements = this._create(url);
|
||||||
this.elements.dismiss.addEventListener('click', () => this._onDismiss());
|
this.elements.dismiss.addEventListener('click', () => this._onDismiss());
|
||||||
this.elements.confirm.addEventListener('click', () => this._onConfirm());
|
this.elements.confirm.addEventListener('click', () => this._onConfirm());
|
||||||
this._updateFreeSpaceInAddDialog();
|
|
||||||
document.body.append(this.elements.root);
|
document.body.append(this.elements.root);
|
||||||
|
if (files.length > 0) {
|
||||||
|
this.elements.file_input.files = files;
|
||||||
|
}
|
||||||
|
this._updateFreeSpaceInAddDialog();
|
||||||
this.elements.url_input.focus();
|
this.elements.url_input.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -557,7 +557,10 @@ export class Transmission extends EventTarget {
|
||||||
static _dragenter(event_) {
|
static _dragenter(event_) {
|
||||||
if (event_.dataTransfer && event_.dataTransfer.types) {
|
if (event_.dataTransfer && event_.dataTransfer.types) {
|
||||||
const copy_types = new Set(['text/uri-list', 'text/plain']);
|
const copy_types = new Set(['text/uri-list', 'text/plain']);
|
||||||
if (event_.dataTransfer.types.some((type) => copy_types.has(type))) {
|
if (
|
||||||
|
event_.dataTransfer.types.some((type) => copy_types.has(type)) ||
|
||||||
|
event_.dataTransfer.types.includes('Files')
|
||||||
|
) {
|
||||||
event_.stopPropagation();
|
event_.stopPropagation();
|
||||||
event_.preventDefault();
|
event_.preventDefault();
|
||||||
event_.dataTransfer.dropEffect = 'copy';
|
event_.dataTransfer.dropEffect = 'copy';
|
||||||
|
@ -589,8 +592,8 @@ export class Transmission extends EventTarget {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const type = event_.data.Transfer.types
|
const type = event_.dataTransfer.types
|
||||||
.filter((t) => ['text/uri-list', 'text/plain'].contains(t))
|
.filter((t) => ['text/uri-list', 'text/plain'].includes(t))
|
||||||
.pop();
|
.pop();
|
||||||
for (const uri of event_.dataTransfer
|
for (const uri of event_.dataTransfer
|
||||||
.getData(type)
|
.getData(type)
|
||||||
|
@ -600,6 +603,11 @@ export class Transmission extends EventTarget {
|
||||||
this.remote.addTorrentByUrl(uri, paused);
|
this.remote.addTorrentByUrl(uri, paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { files } = event_.dataTransfer;
|
||||||
|
|
||||||
|
if (files.length > 0) {
|
||||||
|
this.openDialog = new OpenDialog(this, this.remote, '', files);
|
||||||
|
}
|
||||||
event_.preventDefault();
|
event_.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue