@@ -338,6 +439,9 @@ class PeerUI {
this.$el.querySelector('svg use').setAttribute('xlink:href', this._icon());
this.$el.querySelector('.name').textContent = this._displayName();
this.$el.querySelector('.device-name').textContent = this._deviceName();
+
+ this.$label = this.$el.querySelector('label');
+ this.$input = this.$el.querySelector('input');
}
addTypesToClassList() {
@@ -360,32 +464,51 @@ class PeerUI {
this.html();
- this._callbackInput = e => this._onFilesSelected(e)
- this._callbackClickSleep = _ => NoSleepUI.enable()
- this._callbackTouchStartSleep = _ => NoSleepUI.enable()
- this._callbackDrop = e => this._onDrop(e)
- this._callbackDragEnd = e => this._onDragEnd(e)
- this._callbackDragLeave = e => this._onDragEnd(e)
- this._callbackDragOver = e => this._onDragOver(e)
- this._callbackContextMenu = e => this._onRightClick(e)
- this._callbackTouchStart = e => this._onTouchStart(e)
- this._callbackTouchEnd = e => this._onTouchEnd(e)
- this._callbackPointerDown = e => this._onPointerDown(e)
+ this._createCallbacks();
- // PasteMode
- Events.on('paste-mode-changed', e => this._onPasteModeChanged(e.detail.active, e.detail.descriptor));
- }
-
- _onPasteModeChanged(active, descriptor) {
- this.pasteMode.active = active
- this.pasteMode.descriptor = descriptor
- this.html();
+ this._evaluateShareMode();
this._bindListeners();
}
+ _onShareModeChanged(active = false, descriptor = "") {
+ // This is needed if the ShareMode is started AFTER the PeerUI is drawn.
+ PeerUI._shareMode.active = active;
+ PeerUI._shareMode.descriptor = descriptor;
+
+ this._evaluateShareMode();
+ this._bindListeners();
+ }
+
+ _evaluateShareMode() {
+ let title;
+ if (!PeerUI._shareMode.active) {
+ title = Localization.getTranslation("peer-ui.click-to-send");
+ this.$input.removeAttribute('disabled');
+ }
+ else {
+ title = Localization.getTranslation("peer-ui.click-to-send-share-mode", null, {descriptor: PeerUI._shareMode.descriptor});
+ this.$input.setAttribute('disabled', true);
+ }
+ this.$label.setAttribute('title', title);
+ }
+
+ _createCallbacks() {
+ this._callbackInput = e => this._onFilesSelected(e);
+ this._callbackClickSleep = _ => NoSleepUI.enable();
+ this._callbackTouchStartSleep = _ => NoSleepUI.enable();
+ this._callbackDrop = e => this._onDrop(e);
+ this._callbackDragEnd = e => this._onDragEnd(e);
+ this._callbackDragLeave = e => this._onDragEnd(e);
+ this._callbackDragOver = e => this._onDragOver(e);
+ this._callbackContextMenu = e => this._onRightClick(e);
+ this._callbackTouchStart = e => this._onTouchStart(e);
+ this._callbackTouchEnd = e => this._onTouchEnd(e);
+ this._callbackPointerDown = e => this._onPointerDown(e);
+ }
+
_bindListeners() {
- if(!this.pasteMode.activated) {
- // Remove Events Paste Mode
+ if(!PeerUI._shareMode.active) {
+ // Remove Events Share mode
this.$el.removeEventListener('pointerdown', this._callbackPointerDown);
// Add Events Normal Mode
@@ -412,7 +535,7 @@ class PeerUI {
this.$el.removeEventListener('touchstart', this._callbackTouchStart);
this.$el.removeEventListener('touchend', this._callbackTouchEnd);
- // Add Events Paste Mode
+ // Add Events Share mode
this.$el.addEventListener('pointerdown', this._callbackPointerDown);
}
}
@@ -421,7 +544,7 @@ class PeerUI {
// Prevents triggering of event twice on touch devices
e.stopPropagation();
e.preventDefault();
- Events.fire('paste-pointerdown', {
+ Events.fire('share-mode-pointerdown', {
peerId: this._peer.id
});
}
@@ -498,10 +621,27 @@ class PeerUI {
_onDrop(e) {
e.preventDefault();
- Events.fire('files-selected', {
- files: e.dataTransfer.files,
- to: this._peer.id
- });
+
+ if (PeerUI._shareMode.active || Dialog.anyDialogShown()) return;
+
+ if (e.dataTransfer.files.length > 0) {
+ Events.fire('files-selected', {
+ files: e.dataTransfer.files,
+ to: this._peer.id
+ });
+ } else {
+ for (let i=0; i {
+ Events.fire('send-text', {
+ text: text,
+ to: this._peer.id
+ });
+ });
+ }
+ }
+ }
+
this._onDragEnd();
}
@@ -554,6 +694,10 @@ class Dialog {
Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail));
}
+ static anyDialogShown() {
+ return document.querySelectorAll('x-dialog[show]').length > 0;
+ }
+
show() {
this.$el.setAttribute('show', true);
if (!window.isMobile && this.$autoFocus) this.$autoFocus.focus();
@@ -580,6 +724,15 @@ class Dialog {
Events.fire('notify-user', Localization.getTranslation("notifications.selected-peer-left"));
}
}
+
+ _evaluateOverflowing(element) {
+ if (element.clientHeight < element.scrollHeight) {
+ element.classList.add('overflowing');
+ }
+ else {
+ element.classList.remove('overflowing');
+ }
+ }
}
class LanguageSelectDialog extends Dialog {
@@ -598,7 +751,9 @@ class LanguageSelectDialog extends Dialog {
}
_onKeyDown(e) {
- if (this.isShown() && e.code === "Escape") {
+ if (!this.isShown()) return;
+
+ if (e.code === "Escape") {
this.hide();
}
}
@@ -707,7 +862,7 @@ class ReceiveFileDialog extends ReceiveDialog {
this._filesQueue = [];
}
- _onFilesReceived(peerId, files, imagesOnly, totalSize) {
+ async _onFilesReceived(peerId, files, imagesOnly, totalSize) {
const displayName = $(peerId).ui._displayName();
const connectionHash = $(peerId).ui._connectionHash;
const badgeClassName = $(peerId).ui._badgeClassName();
@@ -722,28 +877,16 @@ class ReceiveFileDialog extends ReceiveDialog {
badgeClassName: badgeClassName
});
- this._nextFiles();
-
window.blop.play();
+
+ await this._nextFiles();
}
- _nextFiles() {
- if (this._busy) return;
+ async _nextFiles() {
+ if (this._busy || !this._filesQueue.length) return;
this._busy = true;
const {peerId, displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName} = this._filesQueue.shift();
- this._displayFiles(peerId, displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName);
- }
-
- _dequeueFile() {
- if (!this._filesQueue.length) { // nothing to do
- this._busy = false;
- return;
- }
- // dequeue next file
- setTimeout(() => {
- this._busy = false;
- this._nextFiles();
- }, 300);
+ await this._displayFiles(peerId, displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName);
}
createPreviewElement(file) {
@@ -845,6 +988,7 @@ class ReceiveFileDialog extends ReceiveDialog {
}
}
+ this.$downloadBtn.removeAttribute('disabled');
this.$downloadBtn.innerText = Localization.getTranslation("dialogs.download");
this.$downloadBtn.onclick = _ => {
if (downloadZipped) {
@@ -861,6 +1005,8 @@ class ReceiveFileDialog extends ReceiveDialog {
this.$downloadBtn.innerText = Localization.getTranslation("dialogs.download-again");
}
Events.fire('notify-user', Localization.getTranslation("notifications.download-successful", null, {descriptor: descriptor}));
+
+ // Prevent clicking the button multiple times
this.$downloadBtn.style.pointerEvents = "none";
setTimeout(() => this.$downloadBtn.style.pointerEvents = "unset", 2000);
};
@@ -874,6 +1020,7 @@ class ReceiveFileDialog extends ReceiveDialog {
this.show();
setTimeout(() => {
+ // wait for the dialog to be shown
if (canShare) {
this.$shareBtn.click();
}
@@ -904,10 +1051,14 @@ class ReceiveFileDialog extends ReceiveDialog {
}
hide() {
- this.$shareBtn.setAttribute('hidden', true);
- this.$previewBox.innerHTML = '';
super.hide();
- this._dequeueFile();
+ setTimeout(async () => {
+ this.$shareBtn.setAttribute('hidden', true);
+ this.$downloadBtn.setAttribute('disabled', true);
+ this.$previewBox.innerHTML = '';
+ this._busy = false;
+ await this._nextFiles();
+ }, 300);
}
}
@@ -927,7 +1078,9 @@ class ReceiveRequestDialog extends ReceiveDialog {
}
_onKeyDown(e) {
- if (this.isShown() && e.code === "Escape") {
+ if (!this.isShown()) return;
+
+ if (e.code === "Escape") {
this._respondToFileTransferRequest(false);
}
}
@@ -968,6 +1121,8 @@ class ReceiveRequestDialog extends ReceiveDialog {
document.title = `${transferRequestTitle} - PairDrop`;
changeFavicon("images/favicon-96x96-notification.png");
+
+ this.$acceptRequestBtn.removeAttribute('disabled');
this.show();
}
@@ -985,12 +1140,15 @@ class ReceiveRequestDialog extends ReceiveDialog {
hide() {
// clear previewBox after dialog is closed
- setTimeout(() => this.$previewBox.innerHTML = '', 300);
+ setTimeout(() => {
+ this.$previewBox.innerHTML = '';
+ this.$acceptRequestBtn.setAttribute('disabled', true);
+ }, 300);
super.hide();
// show next request
- setTimeout(() => this._dequeueRequests(), 500);
+ setTimeout(() => this._dequeueRequests(), 300);
}
}
@@ -1152,8 +1310,10 @@ class PairDeviceDialog extends Dialog {
}
_onKeyDown(e) {
- if (this.isShown() && e.code === "Escape") {
- // Timeout to prevent paste mode from getting cancelled simultaneously
+ if (!this.isShown()) return;
+
+ if (e.code === "Escape") {
+ // Timeout to prevent share mode from getting cancelled simultaneously
setTimeout(() => this._close(), 50);
}
}
@@ -1366,7 +1526,9 @@ class EditPairedDevicesDialog extends Dialog {
}
_onKeyDown(e) {
- if (this.isShown() && e.code === "Escape") {
+ if (!this.isShown()) return;
+
+ if (e.code === "Escape") {
this.hide();
}
}
@@ -1435,19 +1597,11 @@ class EditPairedDevicesDialog extends Dialog {
_onEditPairedDevices() {
this._initDOM()
.then(_ => {
- this._evaluateOverflowing();
+ this._evaluateOverflowing(this.$pairedDevicesWrapper);
this.show();
});
}
- _evaluateOverflowing() {
- if (this.$pairedDevicesWrapper.clientHeight < this.$pairedDevicesWrapper.scrollHeight) {
- this.$pairedDevicesWrapper.classList.add('overflowing');
- } else {
- this.$pairedDevicesWrapper.classList.remove('overflowing');
- }
- }
-
_clearRoomSecrets() {
PersistentStorage
.getAllRoomSecrets()
@@ -1526,7 +1680,9 @@ class PublicRoomDialog extends Dialog {
}
_onKeyDown(e) {
- if (this.isShown() && e.code === "Escape") {
+ if (!this.isShown()) return;
+
+ if (e.code === "Escape") {
this.hide();
}
}
@@ -1719,34 +1875,37 @@ class PublicRoomDialog extends Dialog {
class SendTextDialog extends Dialog {
constructor() {
super('send-text-dialog');
- Events.on('text-recipient', e => this._onRecipient(e.detail.peerId, e.detail.deviceName));
- this.$text = this.$el.querySelector('#text-input');
+
+ this.$text = this.$el.querySelector('.textarea');
this.$peerDisplayName = this.$el.querySelector('.display-name');
this.$form = this.$el.querySelector('form');
this.$submit = this.$el.querySelector('button[type="submit"]');
this.$form.addEventListener('submit', e => this._onSubmit(e));
- this.$text.addEventListener('input', _ => this._onChange());
+ this.$text.addEventListener('input', _ => this._onInput());
+
+ Events.on('text-recipient', e => this._onRecipient(e.detail.peerId, e.detail.deviceName));
Events.on('keydown', e => this._onKeyDown(e));
}
- async _onKeyDown(e) {
+ _onKeyDown(e) {
if (!this.isShown()) return;
if (e.code === "Escape") {
this.hide();
}
else if (e.code === "Enter" && (e.ctrlKey || e.metaKey)) {
- if (this._textInputEmpty()) return;
+ if (this._textEmpty()) return;
+
this._send();
}
}
- _textInputEmpty() {
+ _textEmpty() {
return !this.$text.innerText || this.$text.innerText === "\n";
}
- _onChange() {
- if (this._textInputEmpty()) {
+ _onInput() {
+ if (this._textEmpty()) {
this.$submit.setAttribute('disabled', true);
// remove remaining whitespace on Firefox on text deletion
this.$text.innerText = "";
@@ -1754,15 +1913,7 @@ class SendTextDialog extends Dialog {
else {
this.$submit.removeAttribute('disabled');
}
- this._evaluateOverflowing();
- }
-
- _evaluateOverflowing() {
- if (this.$text.clientHeight < this.$text.scrollHeight) {
- this.$text.classList.add('overflowing');
- } else {
- this.$text.classList.remove('overflowing');
- }
+ this._evaluateOverflowing(this.$text);
}
_onRecipient(peerId, deviceName) {
@@ -1814,14 +1965,14 @@ class ReceiveTextDialog extends Dialog {
}
async _onKeyDown(e) {
- if (this.isShown()) {
- if (e.code === "KeyC" && (e.ctrlKey || e.metaKey)) {
- await this._onCopy()
- this.hide();
- }
- else if (e.code === "Escape") {
- this.hide();
- }
+ if (!this.isShown()) return
+
+ if (e.code === "KeyC" && (e.ctrlKey || e.metaKey)) {
+ await this._onCopy()
+ this.hide();
+ }
+ else if (e.code === "Escape") {
+ this.hide();
}
}
@@ -1855,7 +2006,7 @@ class ReceiveTextDialog extends Dialog {
});
}
- this._evaluateOverflowing();
+ this._evaluateOverflowing(this.$text);
this._setDocumentTitleMessages();
@@ -1863,14 +2014,6 @@ class ReceiveTextDialog extends Dialog {
this.show();
}
- _evaluateOverflowing() {
- if (this.$text.clientHeight < this.$text.scrollHeight) {
- this.$text.classList.add('overflowing');
- } else {
- this.$text.classList.remove('overflowing');
- }
- }
-
_setDocumentTitleMessages() {
document.title = !this._receiveTextQueue.length
? `${ Localization.getTranslation("document-titles.message-received") } - PairDrop`
@@ -1896,6 +2039,83 @@ class ReceiveTextDialog extends Dialog {
}
}
+class ShareTextDialog extends Dialog {
+ constructor() {
+ super('share-text-dialog');
+
+ this.$text = this.$el.querySelector('.textarea');
+ this.$approveMsgBtn = this.$el.querySelector('button[type="submit"]');
+ this.$checkbox = this.$el.querySelector('input[type="checkbox"]')
+
+ this.$approveMsgBtn.addEventListener('click', _ => this._approveShareText());
+
+ // Only show this per default if user sets checkmark
+ this.$checkbox.checked = localStorage.getItem("approve_share_text")
+ ? ShareTextDialog.isApproveShareTextSet()
+ : false;
+
+ this._setCheckboxValueToLocalStorage();
+
+ this.$checkbox.addEventListener('change', _ => this._setCheckboxValueToLocalStorage());
+ Events.on('share-text-dialog', e => this._onShareText(e.detail));
+ Events.on('keydown', e => this._onKeyDown(e));
+ this.$text.addEventListener('input', _ => this._evaluateEmptyText());
+ }
+
+ static isApproveShareTextSet() {
+ return localStorage.getItem("approve_share_text") === "true";
+ }
+
+ _setCheckboxValueToLocalStorage() {
+ localStorage.setItem("approve_share_text", this.$checkbox.checked ? "true" : "false");
+ }
+
+ _onKeyDown(e) {
+ if (!this.isShown()) return;
+
+ if (e.code === "Escape") {
+ this._approveShareText();
+ }
+ else if (e.code === "Enter" && (e.ctrlKey || e.metaKey)) {
+ if (this._textEmpty()) return;
+
+ this._approveShareText();
+ }
+ }
+
+ _textEmpty() {
+ return !this.$text.innerText || this.$text.innerText === "\n";
+ }
+
+ _evaluateEmptyText() {
+ if (this._textEmpty()) {
+ this.$approveMsgBtn.setAttribute('disabled', true);
+ // remove remaining whitespace on Firefox on text deletion
+ this.$text.innerText = "";
+ }
+ else {
+ this.$approveMsgBtn.removeAttribute('disabled');
+ }
+ this._evaluateOverflowing(this.$text);
+ }
+
+ _onShareText(text) {
+ this.$text.innerText = text;
+ this._evaluateEmptyText();
+ this.show();
+ }
+
+ _approveShareText() {
+ Events.fire('activate-share-mode', {text: this.$text.innerText});
+ this.hide();
+ }
+
+ hide() {
+ super.hide();
+ setTimeout(() => this.$text.innerText = "", 500);
+ }
+}
+
class Base64ZipDialog extends Dialog {
constructor() {
@@ -2027,7 +2247,11 @@ class Base64ZipDialog extends Dialog {
return new Promise((resolve) => {
this._setPasteBtnToProcessing();
let decodedText = decodeURIComponent(escape(window.atob(base64Text)));
- Events.fire('activate-paste-mode', {files: [], text: decodedText});
+ if (ShareTextDialog.isApproveShareTextSet()) {
+ Events.fire('share-text-dialog', decodedText);
+ } else {
+ Events.fire('activate-share-mode', {text: decodedText});
+ }
resolve();
});
}
@@ -2047,7 +2271,7 @@ class Base64ZipDialog extends Dialog {
let fileBlob = await zipper.getData(zipEntries[i]);
files.push(new File([fileBlob], zipEntries[i].filename));
}
- Events.fire('activate-paste-mode', {files: files, text: ""});
+ Events.fire('activate-share-mode', {files: files});
}
clearBrowserHistory() {
@@ -2066,18 +2290,28 @@ class Base64ZipDialog extends Dialog {
class Toast extends Dialog {
constructor() {
super('toast');
+ this.$closeBtn = this.$el.querySelector('.icon-button');
+ this.$text = this.$el.querySelector('span');
+
+ this.$closeBtn.addEventListener('click', _ => this.hide());
Events.on('notify-user', e => this._onNotify(e.detail));
+ Events.on('share-mode-changed', _ => this.hide());
}
_onNotify(message) {
if (this.hideTimeout) clearTimeout(this.hideTimeout);
- this.$el.innerText = typeof message === "object" ? message.message : message;
+ this.$text.innerText = typeof message === "object" ? message.message : message;
this.show();
if (typeof message === "object" && message.persistent) return;
this.hideTimeout = setTimeout(() => this.hide(), 5000);
}
+
+ hide() {
+ if (this.hideTimeout) clearTimeout(this.hideTimeout);
+ super.hide();
+ }
}
class Notifications {
@@ -2087,6 +2321,7 @@ class Notifications {
if (!('Notification' in window)) return;
this.$headerNotificationButton = $('notification');
+ this.$downloadBtn = $('download-btn');
this.$headerNotificationButton.addEventListener('click', _ => this._requestPermission());
@@ -2216,7 +2451,7 @@ class Notifications {
}
_download(notification) {
- $('download-btn').click();
+ this.$downloadBtn.click();
notification.close();
}
@@ -2287,7 +2522,11 @@ class WebShareTargetUI {
shareTargetText = title + text;
}
- Events.fire('activate-paste-mode', {files: [], text: shareTargetText})
+ if (ShareTextDialog.isApproveShareTextSet()) {
+ Events.fire('share-text-dialog', shareTargetText);
+ } else {
+ Events.fire('activate-share-mode', {text: shareTargetText});
+ }
}
else if (share_target_type === "files") {
let openRequest = window.indexedDB.open('pairdrop_store')
@@ -2305,7 +2544,7 @@ class WebShareTargetUI {
const clearRequest = store.clear()
clearRequest.onsuccess = _ => db.close();
- Events.fire('activate-paste-mode', {files: filesReceived, text: ""})
+ Events.fire('activate-share-mode', {files: filesReceived})
}
}
}
@@ -2331,7 +2570,7 @@ class WebFileHandlersUI {
const file = await fileHandle.getFile();
files.push(file);
}
- Events.fire('activate-paste-mode', {files: files, text: ""})
+ Events.fire('activate-share-mode', {files: files})
launchParams = null;
});
const url = getUrlWithoutArguments();
diff --git a/public/scripts/util.js b/public/scripts/util.js
index 6dba206..3ef5488 100644
--- a/public/scripts/util.js
+++ b/public/scripts/util.js
@@ -457,4 +457,41 @@ function base64ToArrayBuffer(base64) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
+}
+
+function getResizedImageDataUrl(file, width = undefined, height = undefined, quality = 0.7) {
+ return new Promise((resolve, reject) => {
+ let image = new Image();
+ image.src = URL.createObjectURL(file);
+ image.onload = _ => {
+ let imageWidth = image.width;
+ let imageHeight = image.height;
+ let canvas = document.createElement('canvas');
+
+ // resize the canvas and draw the image data into it
+ if (width && height) {
+ canvas.width = width;
+ canvas.height = height;
+ }
+ else if (width) {
+ canvas.width = width;
+ canvas.height = Math.floor(imageHeight * width / imageWidth)
+ }
+ else if (height) {
+ canvas.width = Math.floor(imageWidth * height / imageHeight);
+ canvas.height = height;
+ }
+ else {
+ canvas.width = imageWidth;
+ canvas.height = imageHeight
+ }
+
+ let ctx = canvas.getContext("2d");
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
+
+ let dataUrl = canvas.toDataURL("image/jpeg", quality);
+ resolve(dataUrl);
+ }
+ image.onerror = _ => reject(`Could not create an image thumbnail from type ${file.type}`);
+ })
}
\ No newline at end of file
diff --git a/public/styles/deferred-styles.css b/public/styles/deferred-styles.css
index bef550c..3613377 100644
--- a/public/styles/deferred-styles.css
+++ b/public/styles/deferred-styles.css
@@ -1,20 +1,5 @@
/* All styles in this sheet are not needed on page load and deferred */
-/* Paste mode */
-#cancel-paste-mode {
- z-index: 21;
- margin: 0;
- padding: 0;
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- width: 100vw;
- height: 56px;
- background-color: var(--primary-color);
- color: rgb(238, 238, 238);
-}
-
/* Text Input */
.textarea {
box-sizing: border-box;
@@ -22,7 +7,7 @@
outline: none;
padding: 16px 24px;
border-radius: 12px;
- font-size: inherit;
+ font-size: 16px;
font-family: inherit;
display: block;
overflow: auto;
@@ -33,6 +18,10 @@
word-wrap: anywhere;
}
+.textarea:before {
+ opacity: 0.5;
+}
+
/* Peers */
x-peers:has(> x-peer) {
@@ -529,30 +518,19 @@ x-dialog hr {
}
/* button row*/
-x-paper > .button-row {
- height: 50px;
- margin: 5px 10px 10px;
-}
-
-x-paper > .button-row > .btn {
+.btn-row > .btn {
height: 100%;
width: 100%;
}
-html:not([dir="rtl"]) x-paper > .button-row > .btn:not(:first-child) {
+.btn-row > .btn {
margin-right: 5px;
-}
-
-html:not([dir="rtl"]) x-paper > .button-row > .btn:not(:last-child) {
margin-left: 5px;
}
-html[dir="rtl"] x-paper > .button-row > .btn:not(:first-child) {
- margin-right: 5px;
-}
-
-html[dir="rtl"] x-paper > .button-row > .btn:not(:last-child) {
- margin-left: 5px;
+x-paper > .btn-row {
+ height: 50px;
+ margin: 5px 10px 10px;
}
.language-buttons > button > span {
@@ -597,7 +575,10 @@ x-dialog .dialog-subheader {
#send-text-dialog,
#receive-text-dialog {
- font-size: 16px; /* prevents auto-zoom on edit */
+ font-size: 16px; /* prevents auto-zoom on edit */
+}
+
+.textarea.overflowing {
--shadow-color-rgb: var(--shadow-color-secondary-rgb);
--shadow-color-cover-rgb: var(--shadow-color-secondary-cover-rgb);
}
@@ -607,10 +588,6 @@ x-dialog .dialog-subheader {
--shadow-color-cover-rgb: var(--shadow-color-dialog-cover-rgb);
}
-#text-input:before {
- opacity: 0.5;
-}
-
/* Receive Text Dialog */
#receive-text-dialog #text {
@@ -634,6 +611,69 @@ x-dialog .dialog-subheader {
pointer-events: none;
}
+.share-panel {
+ max-width: calc(100vw - 20px);
+ overflow: hidden;
+ background-color: var(--primary-color);
+ color: white;
+ background-image: linear-gradient(225deg, var(--accent-color) 0%, color-mix(in srgb, var(--accent-color) 60%, black) 100%);
+}
+
+.share-panel > div {
+ margin: 4px 2px;
+}
+
+.share-panel > div:not(:first-child) {
+ margin-top: 2px;
+}
+
+.share-panel .thumb > div {
+ width: 36px;
+ height: 36px;
+ background: white;
+ border-radius: 6px;
+ margin-right: 6px;
+}
+
+.share-panel .text-thumb svg {
+ width: 18px;
+ height: 36px;
+}
+
+.share-panel .file-thumb svg {
+ width: 36px;
+ height: 36px;
+}
+
+.share-panel .thumb .image-thumb {
+ background-size: cover;
+ border-radius: 6px;
+ background-position: center;
+}
+
+.share-descriptor {
+ justify-content: center;
+}
+
+.share-descriptor > span {
+ display: inline;
+ margin-bottom: 0;
+ margin-top: 0;
+ height: 20px;
+ max-width: 15rem;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.share-descriptor > span:first-child {
+ font-weight: bold;
+}
+
+.share-descriptor > span:not(:first-child) {
+ font-size: small;
+}
+
#base64-paste-btn,
#base64-paste-dialog .textarea {
width: 100%;
diff --git a/public/styles/styles-main.css b/public/styles/styles-main.css
index 8c74194..b1ca12c 100644
--- a/public/styles/styles-main.css
+++ b/public/styles/styles-main.css
@@ -34,6 +34,10 @@ html {
padding: 10px;
}
+.cursive {
+ font-style: italic;
+}
+
.row-reverse {
display: flex;
flex-direction: row-reverse;
@@ -86,29 +90,29 @@ header {
right: 0;
}
-header > * {
+header > .row-reverse > * {
margin-left: 4px;
margin-right: 4px;
}
-header > div {
+header > .row-reverse > div {
display: flex;
flex-direction: column;
align-self: flex-start;
touch-action: manipulation;
}
-header > div .icon-button {
+header > .row-reverse > div .icon-button {
height: 40px;
transition: all 300ms;
}
-header > div > div {
+header > .row-reverse > div > div {
display: flex;
flex-direction: column;
}
-header > div:not(:hover) .icon-button:not(.selected) {
+header > .row-reverse > div:not(:hover) .icon-button:not(.selected) {
height: 0;
opacity: 0;
}
@@ -127,22 +131,22 @@ header > div:not(:hover) .icon-button:not(.selected) {
margin-bottom: 8px;
}
-header > div:hover .icon-button.selected::before {
+header > .row-reverse > div:hover .icon-button.selected::before {
opacity: 0.1;
}
@media (pointer: coarse) {
- header > div:hover .icon-button.selected:hover::before {
+ header > .row-reverse > div:hover .icon-button.selected:hover::before {
opacity: 0.2;
}
- header > div .icon-button:not(.selected) {
+ header > .row-reverse > div .icon-button:not(.selected) {
height: 0;
opacity: 0;
pointer-events: none;
}
- header > div > div {
+ header > .row-reverse > div > div {
flex-direction: column-reverse;
}
}
@@ -201,6 +205,10 @@ h3 {
text-align: center;
}
+.text-white {
+ color: white !important;
+}
+
.font-body1,
body {
font-size: 14px;
@@ -382,30 +390,35 @@ footer .logo {
margin-top: -10px;
}
-.discovery-wrapper {
- font-size: 14px;
- margin: 15px auto auto;
+.border {
border: 2px solid var(--border-color);
+}
+
+.panel {
+ font-size: 14px;
padding: 2px;
background-color: rgb(var(--bg-color));
transition: background-color 0.5s ease;
min-height: 24px;
}
-.discovery-wrapper.column {
+.panel.column {
border-radius: 16px;
}
-.discovery-wrapper.row {
+.panel.row {
border-radius: 12px;
}
-/*You can be discovered wrapper*/
-.discovery-wrapper > div:first-of-type {
+.panel > div:first-of-type {
padding-left: 4px;
padding-right: 4px;
}
+/* You can be discovered wrapper */
+.discovery-wrapper {
+ margin: 15px auto auto;
+}
.discovery-wrapper .badge {
word-break: keep-all;
@@ -447,8 +460,11 @@ footer .logo {
text-align: left;
border: none;
outline: none;
+ height: 20px;
max-width: 15em;
text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
cursor: text;
margin-bottom: -6px;
padding-bottom: 0.1rem;
@@ -456,11 +472,10 @@ footer .logo {
border-right: solid 1rem transparent;
border-left: solid 1rem transparent;
background-clip: padding-box;
- overflow: hidden;
z-index: 1;
}
-#edit-pen {
+.edit-pen {
width: 1rem;
height: 1rem;
margin-bottom: -2px;
@@ -468,16 +483,16 @@ footer .logo {
}
html:not([dir="rtl"]) #display-name,
-html:not([dir="rtl"]) #edit-pen {
+html:not([dir="rtl"]) .edit-pen {
margin-left: -1rem;
}
html[dir="rtl"] #display-name,
-html[dir="rtl"] #edit-pen {
+html[dir="rtl"] .edit-pen {
margin-right: -1rem;
}
-html[dir="rtl"] #edit-pen {
+html[dir="rtl"] .edit-pen {
transform: rotateY(180deg);
}
@@ -505,6 +520,11 @@ x-dialog:not([show]) x-background {
overflow: hidden;
}
+.btn-small {
+ font-size: 12px;
+ line-height: 22px;
+}
+
.btn[disabled] {
color: var(--btn-disabled-color);
cursor: not-allowed;
@@ -551,14 +571,31 @@ x-dialog:not([show]) x-background {
opacity: 0.2;
}
+.btn-round {
+ border-radius: 50%;
+}
+
.btn-rounded {
border-radius: 12px;
}
+.btn-small.btn-rounded {
+ border-radius: 6px;
+}
+
.btn-grey {
background-color: var(--bg-color-secondary);
}
+.btn-dark {
+ background-color: #262628;
+}
+
+.btn-primary {
+ background: var(--primary-color);
+ color: rgb(var(--bg-color));
+}
+
button::-moz-focus-inner {
border: 0;
}
@@ -686,6 +723,8 @@ canvas.circles {
}
x-toast {
+ display: flex;
+ justify-content: space-between;
position: absolute;
min-height: 48px;
top: 50px;
@@ -695,7 +734,7 @@ x-toast {
color: var(--dialog-bg-color);
align-items: center;
box-sizing: border-box;
- padding: 8px 24px;
+ padding: 8px;
z-index: 40;
transition: opacity 200ms, transform 300ms ease-out;
cursor: default;
@@ -704,9 +743,17 @@ x-toast {
pointer-events: all;
}
-x-toast:not([show]):not(:hover) {
+x-toast.top-row {
+ top: 3px;
+}
+
+x-toast:not([show]) {
opacity: 0;
- transform: translateY(-100px);
+ transform: translateY(calc(-100% + -55px));
+}
+
+x-toast span {
+ flex-grow: 1;
}
/* Instructions */
@@ -735,9 +782,6 @@ x-instructions[drop-bg]:not([drop-peer]):before {
content: attr(data-drop-bg);
}
-x-instructions p {
- display: none;
-}
x-peers:empty~x-instructions {
opacity: 0 !important;
@@ -864,7 +908,7 @@ body.dark-theme {
--badge-color: #a5a5a5;
--shadow-color-secondary-rgb: 0,0,0;
- --shadow-color-secondary-cover-rgb: 242,242,242;
+ --shadow-color-secondary-cover-rgb: 255,255,255;
--shadow-color-dialog-rgb: 0,0,0;
--shadow-color-dialog-cover-rgb: 242,242,242;
}
@@ -877,28 +921,6 @@ body {
transition: background-color 0.5s ease;
}
-x-dialog x-paper {
- background-color: var(--dialog-bg-color);
-}
-
-.textarea {
- color: rgb(var(--text-color)) !important;
- background-color: var(--bg-color-secondary) !important;
-}
-
-.textarea * {
- margin: 0 !important;
- padding: 0 !important;
- color: unset !important;
- background: unset !important;
- border: unset !important;
- opacity: unset !important;
- font-family: inherit !important;
- font-size: inherit !important;
- font-style: unset !important;
- font-weight: unset !important;
-}
-
/* Gradient for wifi-tether icon */
#primaryGradient .start-color {
stop-color: var(--primary-color);
@@ -946,8 +968,8 @@ html {
/* webkit scrollbar style*/
::-webkit-scrollbar{
- width: 4px;
- height: 4px;
+ width: 0;
+ height: 0;
}
::-webkit-scrollbar-thumb{