Merge branch 'master' into translate

This commit is contained in:
schlagmichdoch 2023-12-13 17:33:09 +01:00
commit 16921cb855
12 changed files with 131 additions and 115 deletions

View file

@ -36,7 +36,7 @@ If applicable, add screenshots to help explain your problem.
**Bug occurs on official PairDrop instance https://pairdrop.net/** **Bug occurs on official PairDrop instance https://pairdrop.net/**
No | Yes No | Yes
Version: v1.9.4 Version: v1.10.0
**Bug occurs on self-hosted PairDrop instance** **Bug occurs on self-hosted PairDrop instance**
No | Yes No | Yes
@ -44,7 +44,7 @@ No | Yes
**Self-Hosted Setup** **Self-Hosted Setup**
Proxy: Nginx | Apache2 Proxy: Nginx | Apache2
Deployment: docker run | docker compose | npm run start:prod Deployment: docker run | docker compose | npm run start:prod
Version: v1.9.4 Version: v1.10.0
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View file

@ -19,6 +19,8 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: write
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Archive Release - name: Archive Release

View file

@ -1,6 +1,6 @@
<div align="center"> <div align="center">
<a href="https://github.com/schlagmichdoch/PairDrop"> <a href="https://github.com/schlagmichdoch/PairDrop">
<img src="https://raw.githubusercontent.com/schlagmichdoch/PairDrop/master/public/images/android-chrome-512x512.png" alt="Logo" width="150" height="150"> <img src="public/images/android-chrome-512x512.png" alt="Logo" width="150" height="150">
</a> </a>
<h1>PairDrop</h1> <h1>PairDrop</h1>
@ -67,11 +67,11 @@ Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
* Multiple files are transferred at once with an overall progress indicator * Multiple files are transferred at once with an overall progress indicator
### Send Files or Text Directly From Share Menu, Context Menu or CLI ### Send Files or Text Directly From Share Menu, Context Menu or CLI
* [Send files directly from context menu on Windows](/docs/how-to.md#send-multiple-files-and-directories-directly-from-context-menu-on-windows) * [Send files directly from context menu on Windows](docs/how-to.md#send-multiple-files-and-directories-directly-from-context-menu-on-windows)
* [Send files directly from context menu on Ubuntu (using Nautilus)](/docs/how-to.md#send-multiple-files-and-directories-directly-from-context-menu-on-ubuntu-using-nautilus) * [Send files directly from context menu on Ubuntu (using Nautilus)](/docs/how-to.md#send-multiple-files-and-directories-directly-from-context-menu-on-ubuntu-using-nautilus)
* [Send files directly from share menu on iOS](/docs/how-to.md#send-directly-from-share-menu-on-ios) * [Send files directly from share menu on iOS](docs/how-to.md#send-directly-from-share-menu-on-ios)
* [Send files directly from share menu on Android](/docs/how-to.md#send-directly-from-share-menu-on-android) * [Send files directly from share menu on Android](docs/how-to.md#send-directly-from-share-menu-on-android)
* [Send files directly via command-line interface](/docs/how-to.md#send-directly-via-command-line-interface) * [Send files directly via command-line interface](docs/how-to.md#send-directly-via-command-line-interface)
### Other changes ### Other changes
* Change your display name permanently to easily differentiate your devices * Change your display name permanently to easily differentiate your devices
@ -85,14 +85,14 @@ Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
* Automatic restart on error (Thanks [@KaKi87](https://github.com/KaKi87)) * Automatic restart on error (Thanks [@KaKi87](https://github.com/KaKi87))
* Lots of stability fixes (Thanks [@MWY001](https://github.com/MWY001) [@skiby7](https://github.com/skiby7) and [@willstott101](https://github.com/willstott101)) * Lots of stability fixes (Thanks [@MWY001](https://github.com/MWY001) [@skiby7](https://github.com/skiby7) and [@willstott101](https://github.com/willstott101))
* To host PairDrop on your local network (e.g. on Raspberry Pi): [All peers connected with private IPs are discoverable by each other](https://github.com/RobinLinus/snapdrop/pull/558) * To host PairDrop on your local network (e.g. on Raspberry Pi): [All peers connected with private IPs are discoverable by each other](https://github.com/RobinLinus/snapdrop/pull/558)
* When hosting PairDrop yourself you can [set your own STUN/TURN servers](/docs/host-your-own.md#specify-stunturn-servers) * When hosting PairDrop yourself you can [set your own STUN/TURN servers](docs/host-your-own.md#specify-stunturn-servers)
* Built-in translations via [Weblate](https://hosted.weblate.org/engage/pairdrop/) * Built-in translations via [Weblate](https://hosted.weblate.org/engage/pairdrop/)
* Airy design (Thanks [@Avieshek](https://linktr.ee/avieshek/)) * Airy design (Thanks [@Avieshek](https://linktr.ee/avieshek/))
</details> </details>
## Screenshots ## Screenshots
<img src="https://raw.githubusercontent.com/schlagmichdoch/PairDrop/master/docs/pairdrop_screenshot_mobile.gif" style="max-height: 50vh"> <img src="docs/pairdrop_screenshot_mobile.gif" alt="Gif of Screenshots that show PairDrop in use" style="width: 300px">
## PairDrop is built with the following awesome technologies: ## PairDrop is built with the following awesome technologies:
* Vanilla HTML5 / ES6 / CSS3 frontend * Vanilla HTML5 / ES6 / CSS3 frontend
@ -106,9 +106,9 @@ Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
* [heic2any](https://github.com/alexcorvi/heic2any) JavaScript library to convert HEIC/HEIF images to PNG/GIF/JPEG ([MIT License](licenses/MIT-heic2any)) * [heic2any](https://github.com/alexcorvi/heic2any) JavaScript library to convert HEIC/HEIF images to PNG/GIF/JPEG ([MIT License](licenses/MIT-heic2any))
* [cyrb53](https://github.com/bryc) Super fast hash function * [cyrb53](https://github.com/bryc) Super fast hash function
Have any questions? Read our [FAQ](/docs/faq.md). Have any questions? Read our [FAQ](docs/faq.md).
You can [host your own instance with Docker](/docs/host-your-own.md). You can [host your own instance with Docker](docs/host-your-own.md).
## Support PairDrop ## Support PairDrop
@ -125,11 +125,11 @@ Thanks a lot for supporting free and open software!
## Translate PairDrop ## Translate PairDrop
<a href="https://hosted.weblate.org/engage/pairdrop/"> <a href="https://hosted.weblate.org/engage/pairdrop/">
<img src="https://hosted.weblate.org/widget/pairdrop/pairdrop-spa/open-graph.png" alt="Translation status" style="max-height: 30vh" /> <img src="https://hosted.weblate.org/widget/pairdrop/pairdrop-spa/open-graph.png" alt="Translation status" style="width: 300px" />
</a> </a>
## How to contribute ## How to contribute
Feel free to [open an issue](https://github.com/schlagmichdoch/pairdrop/issues/new/choose) or a Feel free to [open an issue](https://github.com/schlagmichdoch/pairdrop/issues/new/choose) or a
[pull request](https://github.com/schlagmichdoch/pairdrop/pulls) but follow [pull request](https://github.com/schlagmichdoch/pairdrop/pulls) but follow
[Contributing Guidelines](/CONTRIBUTING.md). [Contributing Guidelines](CONTRIBUTING.md).

51
package-lock.json generated
View file

@ -1,19 +1,19 @@
{ {
"name": "pairdrop", "name": "pairdrop",
"version": "1.9.4", "version": "1.10.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pairdrop", "name": "pairdrop",
"version": "1.9.4", "version": "1.10.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"express-rate-limit": "^7.1.1", "express-rate-limit": "^7.1.5",
"ua-parser-js": "^1.0.36", "ua-parser-js": "^1.0.37",
"unique-names-generator": "^4.3.0", "unique-names-generator": "^4.3.0",
"ws": "^8.14.2" "ws": "^8.15.0"
}, },
"engines": { "engines": {
"node": ">=15" "node": ">=15"
@ -204,14 +204,17 @@
} }
}, },
"node_modules/express-rate-limit": { "node_modules/express-rate-limit": {
"version": "7.1.1", "version": "7.1.5",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.1.1.tgz", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.1.5.tgz",
"integrity": "sha512-o5ye/a4EHCPQPju25Y4HChHybrCM9v37QtQDqXUDZGuD+HB7Cbu8ZhJP6/9RORcSNtkCpnEssa6oUgJgzc7ckQ==", "integrity": "sha512-/iVogxu7ueadrepw1bS0X0kaRC/U0afwiYRSLg68Ts+p4Dc85Q5QKsOnPS/QUjPMHvOJQtBDrZgvkOzf8ejUYw==",
"engines": { "engines": {
"node": ">= 16" "node": ">= 16"
}, },
"funding": {
"url": "https://github.com/sponsors/express-rate-limit"
},
"peerDependencies": { "peerDependencies": {
"express": "^4 || ^5" "express": "4 || 5 || ^5.0.0-beta.1"
} }
}, },
"node_modules/finalhandler": { "node_modules/finalhandler": {
@ -583,9 +586,9 @@
} }
}, },
"node_modules/ua-parser-js": { "node_modules/ua-parser-js": {
"version": "1.0.36", "version": "1.0.37",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
"integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -637,9 +640,9 @@
} }
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.14.2", "version": "8.15.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.0.tgz",
"integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "integrity": "sha512-H/Z3H55mrcrgjFwI+5jKavgXvwQLtfPCUEp6pi35VhoB0pfcHnSoyuTzkBEZpzq49g1193CUEwIvmsjcotenYw==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },
@ -805,9 +808,9 @@
} }
}, },
"express-rate-limit": { "express-rate-limit": {
"version": "7.1.1", "version": "7.1.5",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.1.1.tgz", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.1.5.tgz",
"integrity": "sha512-o5ye/a4EHCPQPju25Y4HChHybrCM9v37QtQDqXUDZGuD+HB7Cbu8ZhJP6/9RORcSNtkCpnEssa6oUgJgzc7ckQ==", "integrity": "sha512-/iVogxu7ueadrepw1bS0X0kaRC/U0afwiYRSLg68Ts+p4Dc85Q5QKsOnPS/QUjPMHvOJQtBDrZgvkOzf8ejUYw==",
"requires": {} "requires": {}
}, },
"finalhandler": { "finalhandler": {
@ -1074,9 +1077,9 @@
} }
}, },
"ua-parser-js": { "ua-parser-js": {
"version": "1.0.36", "version": "1.0.37",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
"integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==" "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ=="
}, },
"unique-names-generator": { "unique-names-generator": {
"version": "4.7.1", "version": "4.7.1",
@ -1099,9 +1102,9 @@
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
}, },
"ws": { "ws": {
"version": "8.14.2", "version": "8.15.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.0.tgz",
"integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "integrity": "sha512-H/Z3H55mrcrgjFwI+5jKavgXvwQLtfPCUEp6pi35VhoB0pfcHnSoyuTzkBEZpzq49g1193CUEwIvmsjcotenYw==",
"requires": {} "requires": {}
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "pairdrop", "name": "pairdrop",
"version": "1.9.4", "version": "1.10.0",
"type": "module", "type": "module",
"description": "", "description": "",
"main": "server/index.js", "main": "server/index.js",
@ -12,10 +12,10 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"express-rate-limit": "^7.1.1", "express-rate-limit": "^7.1.5",
"ua-parser-js": "^1.0.36", "ua-parser-js": "^1.0.37",
"unique-names-generator": "^4.3.0", "unique-names-generator": "^4.3.0",
"ws": "^8.14.2" "ws": "^8.15.0"
}, },
"engines": { "engines": {
"node": ">=15" "node": ">=15"

View file

@ -35,6 +35,7 @@
<meta property="og:image" content="images/logo_transparent_512x512.png"> <meta property="og:image" content="images/logo_transparent_512x512.png">
<!-- Resources --> <!-- Resources -->
<link rel="preload" href="lang/en.json" as="fetch"> <link rel="preload" href="lang/en.json" as="fetch">
<link rel="preload" href="fonts/OpenSans/static/OpenSans-Medium.ttf" as="font" type="font/ttf" crossorigin>
<link rel="stylesheet" type="text/css" href="styles/styles-main.css"> <link rel="stylesheet" type="text/css" href="styles/styles-main.css">
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
</head> </head>
@ -104,12 +105,12 @@
<!-- Center --> <!-- Center -->
<div id="center" class="opacity-0"> <div id="center" class="opacity-0">
<!-- Peers --> <!-- Peers -->
<x-peers class="center grow"></x-peers> <x-peers class="center grow-5"></x-peers>
<x-no-peers class="center grow fade-in no-animation-on-load" data-i18n-key="instructions.no-peers" data-i18n-attrs="data-drop-bg"> <x-no-peers class="center grow fade-in no-animation-on-load" data-i18n-key="instructions.no-peers" data-i18n-attrs="data-drop-bg">
<h2 data-i18n-key="instructions.no-peers-title" data-i18n-attrs="text"></h2> <h2 data-i18n-key="instructions.no-peers-title" data-i18n-attrs="text"></h2>
<div data-i18n-key="instructions.no-peers-subtitle" data-i18n-attrs="text"></div> <div data-i18n-key="instructions.no-peers-subtitle" data-i18n-attrs="text"></div>
</x-no-peers> </x-no-peers>
<x-instructions class="fade-in" data-i18n-key="instructions.x-instructions" data-i18n-attrs="desktop mobile data-drop-peer data-drop-bg"></x-instructions> <x-instructions class="grow fade-in" data-i18n-key="instructions.x-instructions" data-i18n-attrs="desktop mobile data-drop-peer data-drop-bg"></x-instructions>
<div class="shr-panel panel column" hidden> <div class="shr-panel panel column" hidden>
<div class="row"> <div class="row">
<div class="thumb center"> <div class="thumb center">
@ -128,7 +129,7 @@
</div> </div>
<div class="image-thumb" hidden></div> <div class="image-thumb" hidden></div>
</div> </div>
<div class="share-descriptor column p1"> <div class="share-descriptor column p-1">
<span class="descriptor-item"></span> <span class="descriptor-item"></span>
<span class="descriptor-other" hidden></span> <span class="descriptor-other" hidden></span>
</div> </div>
@ -179,7 +180,7 @@
<x-dialog id="language-select-dialog"> <x-dialog id="language-select-dialog">
<x-background class="full center"> <x-background class="full center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title" data-i18n-key="dialogs.language-selector-title" data-i18n-attrs="text"></h2> <h2 class="dialog-title" data-i18n-key="dialogs.language-selector-title" data-i18n-attrs="text"></h2>
</div> </div>
<div class="language-buttons p2"> <div class="language-buttons p2">
@ -276,10 +277,10 @@
<form action="#"> <form action="#">
<x-background class="full center text-center"> <x-background class="full center text-center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title" data-i18n-key="dialogs.pair-devices-title" data-i18n-attrs="text"></h2> <h2 class="dialog-title" data-i18n-key="dialogs.pair-devices-title" data-i18n-attrs="text"></h2>
</div> </div>
<div class="row center p2"> <div class="row center p-2">
<div class="column"> <div class="column">
<div class="center key-qr-code pointer" data-i18n-key="dialogs.pair-devices-qr-code" data-i18n-attrs="title"></div> <div class="center key-qr-code pointer" data-i18n-key="dialogs.pair-devices-qr-code" data-i18n-attrs="title"></div>
<h1 class="center key" dir="ltr">000 000</h1> <h1 class="center key" dir="ltr">000 000</h1>
@ -295,7 +296,7 @@
<span data-i18n-key="dialogs.hr-or" data-i18n-attrs="text"></span> <span data-i18n-key="dialogs.hr-or" data-i18n-attrs="text"></span>
</div> </div>
</div> </div>
<div class="row center p2"> <div class="row center p-2">
<div class="column fw"> <div class="column fw">
<div class="input-key-container six-chars" dir="ltr"> <div class="input-key-container six-chars" dir="ltr">
<input type="tel" class="textarea center" aria-label="pair-key-char-1" maxlength="1" autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" autofocus contenteditable placeholder disabled> <input type="tel" class="textarea center" aria-label="pair-key-char-1" maxlength="1" autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" autofocus contenteditable placeholder disabled>
@ -321,7 +322,7 @@
<form action="#"> <form action="#">
<x-background class="full center text-center"> <x-background class="full center text-center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title" data-i18n-key="dialogs.edit-paired-devices-title" data-i18n-attrs="text"></h2> <h2 class="dialog-title" data-i18n-key="dialogs.edit-paired-devices-title" data-i18n-attrs="text"></h2>
</div> </div>
<div class="paired-devices-wrapper" data-i18n-key="dialogs.paired-devices-wrapper" data-i18n-attrs="data-empty"></div> <div class="paired-devices-wrapper" data-i18n-key="dialogs.paired-devices-wrapper" data-i18n-attrs="data-empty"></div>
@ -344,10 +345,10 @@
<form action="#"> <form action="#">
<x-background class="full center text-center"> <x-background class="full center text-center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title" data-i18n-key="dialogs.temporary-public-room-title" data-i18n-attrs="text"></h2> <h2 class="dialog-title" data-i18n-key="dialogs.temporary-public-room-title" data-i18n-attrs="text"></h2>
</div> </div>
<div class="row center p2"> <div class="row center p-2">
<div class="column"> <div class="column">
<div class="center key-qr-code pointer" data-i18n-key="dialogs.public-room-qr-code" data-i18n-attrs="title"></div> <div class="center key-qr-code pointer" data-i18n-key="dialogs.public-room-qr-code" data-i18n-attrs="title"></div>
<h1 class="center key" dir="ltr"></h1> <h1 class="center key" dir="ltr"></h1>
@ -363,7 +364,7 @@
<span data-i18n-key="dialogs.hr-or" data-i18n-attrs="text"></span> <span data-i18n-key="dialogs.hr-or" data-i18n-attrs="text"></span>
</div> </div>
</div> </div>
<div class="row center p2"> <div class="row center p-2">
<div class="column fw"> <div class="column fw">
<div class="input-key-container" dir="ltr"> <div class="input-key-container" dir="ltr">
<input type="text" class="textarea center" aria-label="room-id-char-1" maxlength="1" autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" autofocus contenteditable placeholder disabled> <input type="text" class="textarea center" aria-label="room-id-char-1" maxlength="1" autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" autofocus contenteditable placeholder disabled>
@ -390,10 +391,10 @@
<x-dialog id="receive-request-dialog"> <x-dialog id="receive-request-dialog">
<x-background class="full center"> <x-background class="full center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title"></h2> <h2 class="dialog-title"></h2>
</div> </div>
<div class="row center p2"> <div class="row center p-2">
<div class="column center file-description"> <div class="column center file-description">
<div> <div>
<span class="display-name badge"></span> <span class="display-name badge"></span>
@ -420,10 +421,10 @@
<x-dialog id="receive-file-dialog"> <x-dialog id="receive-file-dialog">
<x-background class="full center"> <x-background class="full center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title"></h2> <h2 class="dialog-title"></h2>
</div> </div>
<div class="row center p2"> <div class="row center p-2">
<div class="column center file-description"> <div class="column center file-description">
<div> <div>
<span class="display-name badge"></span> <span class="display-name badge"></span>
@ -452,10 +453,10 @@
<form action="#"> <form action="#">
<x-background class="full center"> <x-background class="full center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title" data-i18n-key="dialogs.send-message-title" data-i18n-attrs="text"></h2> <h2 class="dialog-title" data-i18n-key="dialogs.send-message-title" data-i18n-attrs="text"></h2>
</div> </div>
<div class="row center p2 display-name-wrapper"> <div class="row center p-2 display-name-wrapper">
<div class="column"> <div class="column">
<div class="text-center"> <div class="text-center">
<span data-i18n-key="dialogs.send-message-to" data-i18n-attrs="text"></span> <span data-i18n-key="dialogs.send-message-to" data-i18n-attrs="text"></span>
@ -463,7 +464,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row p2"> <div class="row p-2">
<div class="column fw"> <div class="column fw">
<div class="fw textarea" role="textbox" data-i18n-key="dialogs.message" data-i18n-attrs="title placeholder" autofocus contenteditable></div> <div class="fw textarea" role="textbox" data-i18n-key="dialogs.message" data-i18n-attrs="title placeholder" autofocus contenteditable></div>
</div> </div>
@ -480,16 +481,16 @@
<x-dialog id="receive-text-dialog"> <x-dialog id="receive-text-dialog">
<x-background class="full center"> <x-background class="full center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title" class="text-center" data-i18n-key="dialogs.receive-text-title" data-i18n-attrs="text"></h2> <h2 class="dialog-title" class="text-center" data-i18n-key="dialogs.receive-text-title" data-i18n-attrs="text"></h2>
</div> </div>
<div class="row center p2 display-name-wrapper"> <div class="row center p-2 display-name-wrapper">
<div class="text-center"> <div class="text-center">
<span class="display-name badge"></span> <span class="display-name badge"></span>
<span data-i18n-key="dialogs.has-sent" data-i18n-attrs="text"></span> <span data-i18n-key="dialogs.has-sent" data-i18n-attrs="text"></span>
</div> </div>
</div> </div>
<div class="row center p2"> <div class="row center p-2">
<div class="column fw"> <div class="column fw">
<div id="text" class="textarea"></div> <div id="text" class="textarea"></div>
</div> </div>
@ -505,24 +506,24 @@
<x-dialog id="share-text-dialog"> <x-dialog id="share-text-dialog">
<x-background class="full center"> <x-background class="full center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title" data-i18n-key="dialogs.share-text-title" data-i18n-attrs="text"></h2> <h2 class="dialog-title" data-i18n-key="dialogs.share-text-title" data-i18n-attrs="text"></h2>
</div> </div>
<div class="row center p2 pb0"> <div class="row center p-2 pb-0">
<div class="column"> <div class="column">
<div class="text-center"> <div class="text-center">
<span data-i18n-key="dialogs.share-text-subtitle" data-i18n-attrs="text"></span> <span data-i18n-key="dialogs.share-text-subtitle" data-i18n-attrs="text"></span>
</div> </div>
</div> </div>
</div> </div>
<div class="row p2"> <div class="row p-2">
<div class="column fw"> <div class="column fw">
<div class="fw textarea" role="textbox" data-i18n-key="dialogs.message" data-i18n-attrs="title placeholder" contenteditable></div> <div class="fw textarea" role="textbox" data-i18n-key="dialogs.message" data-i18n-attrs="title placeholder" contenteditable></div>
</div> </div>
</div> </div>
<div class="row p2 center"> <div class="row p-2 center">
<span class="mx1" data-i18n-key="dialogs.share-text-checkbox" data-i18n-attrs="text"></span> <span class="mx-1" data-i18n-key="dialogs.share-text-checkbox" data-i18n-attrs="text"></span>
<label class="pointer switch mx1"> <label class="pointer switch mx-1">
<input type="checkbox"> <input type="checkbox">
<div class="slider round"></div> <div class="slider round"></div>
</label> </label>
@ -537,10 +538,10 @@
<x-dialog id="base64-paste-dialog"> <x-dialog id="base64-paste-dialog">
<x-background class="full center"> <x-background class="full center">
<x-paper shadow="2"> <x-paper shadow="2">
<div class="row center p2"> <div class="row center p-2">
<h2 class="dialog-title"></h2> <h2 class="dialog-title"></h2>
</div> </div>
<div class="row p2"> <div class="row p-2">
<button class="btn btn-rounded btn-grey center" id="base64-paste-btn" title="Paste"></button> <button class="btn btn-rounded btn-grey center" id="base64-paste-btn" title="Paste"></button>
<div class="textarea" title="CMD/⌘ + V" contenteditable hidden></div> <div class="textarea" title="CMD/⌘ + V" contenteditable hidden></div>
</div> </div>
@ -576,7 +577,7 @@
</svg> </svg>
<div class="title-wrapper" dir="ltr"> <div class="title-wrapper" dir="ltr">
<h1>PairDrop</h1> <h1>PairDrop</h1>
<div class="font-subheading">v1.9.4</div> <div class="font-subheading">v1.10.0</div>
</div> </div>
<div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text"></div> <div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text"></div>
<div class="row"> <div class="row">

View file

@ -7,7 +7,7 @@ class PairDrop {
this.$headerInstallBtn = $('install'); this.$headerInstallBtn = $('install');
this.deferredStyles = [ this.deferredStyles = [
"styles/deferred-styles.css" "styles/styles-deferred.css"
]; ];
this.deferredScripts = [ this.deferredScripts = [
"scripts/browser-tabs-connector.js", "scripts/browser-tabs-connector.js",

View file

@ -125,9 +125,12 @@ class HeaderUI {
} }
async evaluateOverflowing() { async evaluateOverflowing() {
// remove and reset bracket icon before evaluating // remove bracket icon before evaluating
this.$expandBtn.setAttribute('hidden', true); this.$expandBtn.setAttribute('hidden', true);
// reset bracket icon rotation and header overflow
this.$expandBtn.classList.add('flipped'); this.$expandBtn.classList.add('flipped');
this.$header.classList.remove('overflow-expanded');
const rtlLocale = Localization.isCurrentLocaleRtl(); const rtlLocale = Localization.isCurrentLocaleRtl();
let icon; let icon;
@ -152,7 +155,7 @@ class HeaderUI {
} }
else { else {
// no overflowing // no overflowing
// add overflowing-hidden class // remove overflowing-hidden class
this.$header.classList.remove('overflow-hidden'); this.$header.classList.remove('overflow-hidden');
} }
} }
@ -169,6 +172,7 @@ class HeaderUI {
this.$header.classList.remove('overflow-expanded'); this.$header.classList.remove('overflow-expanded');
this.$expandBtn.classList.add('flipped'); this.$expandBtn.classList.add('flipped');
} }
Events.fire('header-changed');
} }
} }

View file

@ -37,6 +37,7 @@ class PeersUI {
Events.on('dragleave', _ => this._onDragEnd()); Events.on('dragleave', _ => this._onDragEnd());
Events.on('dragend', _ => this._onDragEnd()); Events.on('dragend', _ => this._onDragEnd());
Events.on('resize', _ => this._evaluateOverflowingPeers()); Events.on('resize', _ => this._evaluateOverflowingPeers());
Events.on('header-changed', _ => this._evaluateOverflowingPeers());
Events.on('paste', e => this._onPaste(e)); Events.on('paste', e => this._onPaste(e));
Events.on('activate-share-mode', e => this._activateShareMode(e.detail.files, e.detail.text)); Events.on('activate-share-mode', e => this._activateShareMode(e.detail.files, e.detail.text));
@ -277,22 +278,10 @@ class PeersUI {
if (files[0].type.split('/')[0] === 'image') { if (files[0].type.split('/')[0] === 'image') {
try { try {
let image = files[0] let imageUrl = await getThumbnailAsDataUrl(files[0], 80, null, 0.9);
// Heic files can't be shown by browsers natively --> convert to jpeg
if (image.type === "image/heif" || image.type === "image/heic") {
let blob = await fileToBlob(image);
image = await heic2any({
blob,
toType: "image/jpeg",
quality: 0.9
});
}
let imageUrl = URL.createObjectURL(image);
this.$shareModeImageThumb.style.backgroundImage = `url(${imageUrl})`; this.$shareModeImageThumb.style.backgroundImage = `url(${imageUrl})`;
await waitUntilImageIsLoaded(imageUrl);
this.$shareModeImageThumb.removeAttribute('hidden'); this.$shareModeImageThumb.removeAttribute('hidden');
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -740,7 +729,7 @@ class Dialog {
hide() { hide() {
this.$el.removeAttribute('show'); this.$el.removeAttribute('show');
if (!window.isMobile && this.$autoFocus) { if (!window.isMobile) {
document.activeElement.blur(); document.activeElement.blur();
window.blur(); window.blur();
} }
@ -1586,7 +1575,7 @@ class EditPairedDevicesDialog extends Dialog {
<span class="center wrap"> <span class="center wrap">
${autoAcceptString} ${autoAcceptString}
</span> </span>
<label class="auto-accept switch pointer m1"> <label class="auto-accept switch pointer m-1">
<input type="checkbox" ${roomSecretsEntry.auto_accept ? "checked" : ""}> <input type="checkbox" ${roomSecretsEntry.auto_accept ? "checked" : ""}>
<div class="slider round"></div> <div class="slider round"></div>
</label> </label>
@ -2164,13 +2153,13 @@ class Base64Dialog extends Dialog {
// ?base64text=hash#BASE64ENCODED // ?base64text=hash#BASE64ENCODED
// base64 encoded text is url hash which cannot be seen by the server and is faster (recommended) // base64 encoded text is url hash which cannot be seen by the server and is faster (recommended)
this.show(); this.show();
await this.processBase64Text(hash) await this.processBase64Text(hash);
} }
else { else {
// ?base64text=BASE64ENCODED // ?base64text=BASE64ENCODED
// base64 encoded text is part of the url param. Seen by server and slow (not recommended) // base64 encoded text is part of the url param. Seen by server and slow (not recommended)
this.show(); this.show();
await this.processBase64Text(base64Text) await this.processBase64Text(base64Text);
} }
} }
@ -2185,7 +2174,7 @@ class Base64Dialog extends Dialog {
else if (base64Zip === 'hash') { else if (base64Zip === 'hash') {
// ?base64zip=hash#BASE64ENCODED // ?base64zip=hash#BASE64ENCODED
// base64 encoded zip file is url hash which cannot be seen by the server // base64 encoded zip file is url hash which cannot be seen by the server
await this.processBase64Zip(hash) await this.processBase64Zip(hash);
} }
} }
@ -2280,6 +2269,8 @@ class Base64Dialog extends Dialog {
hide() { hide() {
this.$pasteBtn.removeEventListener('click', _ => this._clickCallback()); this.$pasteBtn.removeEventListener('click', _ => this._clickCallback());
this.$fallbackTextarea.removeEventListener('input', _ => this._inputCallback()); this.$fallbackTextarea.removeEventListener('input', _ => this._inputCallback());
this.$fallbackTextarea.setAttribute('disabled', true);
this.$fallbackTextarea.blur();
super.hide(); super.hide();
} }
} }

View file

@ -1,4 +1,4 @@
const cacheVersion = 'v1.9.4'; const cacheVersion = 'v1.10.0';
const cacheTitle = `pairdrop-cache-${cacheVersion}`; const cacheTitle = `pairdrop-cache-${cacheVersion}`;
const forceFetch = false; // FOR DEVELOPMENT: Set to true to always update assets instead of using cached versions const forceFetch = false; // FOR DEVELOPMENT: Set to true to always update assets instead of using cached versions
const relativePathsToCache = [ const relativePathsToCache = [
@ -6,7 +6,7 @@ const relativePathsToCache = [
'index.html', 'index.html',
'manifest.json', 'manifest.json',
'styles/styles-main.css', 'styles/styles-main.css',
'styles/deferred-styles.css', 'styles/styles-deferred.css',
'scripts/localization.js', 'scripts/localization.js',
'scripts/main.js', 'scripts/main.js',
'scripts/network.js', 'scripts/network.js',

View file

@ -672,19 +672,18 @@ x-dialog .dialog-subheader {
margin-right: 6px; margin-right: 6px;
} }
.shr-panel .text-thumb svg { .shr-panel .thumb > .text-thumb > svg {
width: 18px; width: 18px;
height: 36px; height: 36px;
} }
.shr-panel .file-thumb svg { .shr-panel .thumb > .file-thumb > svg {
width: 36px; width: 36px;
height: 36px; height: 36px;
} }
.shr-panel .thumb .image-thumb { .shr-panel .thumb > .image-thumb {
background-size: cover; background-size: cover;
border-radius: 6px;
background-position: center; background-position: center;
} }

View file

@ -30,24 +30,24 @@ html {
width: 100%; width: 100%;
} }
.p1 { .p-1 {
padding: 5px; padding: 5px;
} }
.p2 { .p-2 {
padding: 10px; padding: 10px;
} }
.pb0 { .pb-0 {
padding-bottom: 0; padding-bottom: 0;
} }
.mx1 { .mx-1 {
margin-left: 5px; margin-left: 5px;
margin-right: 5px; margin-right: 5px;
} }
.m1 { .m-1 {
margin: 5px; margin: 5px;
} }
@ -75,6 +75,11 @@ html {
flex-grow: 2; flex-grow: 2;
} }
.grow-5 {
display: flex;
flex-grow: 5;
}
.shrink { .shrink {
display: flex; display: flex;
flex-shrink: 1; flex-shrink: 1;
@ -138,6 +143,7 @@ header {
z-index: 20; z-index: 20;
top: 0; top: 0;
right: 0; right: 0;
min-height: 56px;
} }
header.overflow-hidden { header.overflow-hidden {
@ -193,19 +199,26 @@ header * {
margin-bottom: 8px; margin-bottom: 8px;
} }
#theme-wrapper:hover .icon-button:not(.selected):hover:before { @media (hover: hover) and (pointer: fine) {
opacity: 0.3; #theme-wrapper:hover .icon-button:not(.selected):hover:before {
}
#theme-wrapper:hover .icon-button.selected::before {
opacity: 0.3;
}
@media (pointer: coarse) {
#theme-wrapper:hover .icon-button.selected:hover::before {
opacity: 0.3; opacity: 0.3;
} }
#theme-wrapper:hover .icon-button.selected::before {
opacity: 0.3;
}
}
@media (hover: none) and (pointer: coarse) {
#theme-wrapper:before {
opacity: 0.3 !important;
height: 40px !important;
}
#theme-wrapper .icon-button:before {
opacity: 0;
}
#theme-wrapper .icon-button:not(.selected) { #theme-wrapper .icon-button:not(.selected) {
height: 0; height: 0;
opacity: 0; opacity: 0;
@ -239,6 +252,7 @@ html[dir="rtl"] #expand.flipped > .icon {
@font-face { @font-face {
font-family: "Open Sans"; font-family: "Open Sans";
src: url('../fonts/OpenSans/static/OpenSans-Medium.ttf') format('truetype'); src: url('../fonts/OpenSans/static/OpenSans-Medium.ttf') format('truetype');
font-display: swap;
} }
body { body {
@ -830,9 +844,11 @@ x-instructions {
position: relative; position: relative;
opacity: 0.5; opacity: 0.5;
text-align: center; text-align: center;
margin: 50px 10px 0px; margin-right: 10px;
margin-left: 10px;
min-height: max(6vh, 40px);
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: end;
} }
x-instructions:not([drop-peer]):not([drop-bg]):before { x-instructions:not([drop-peer]):not([drop-bg]):before {