Merge pull request #206 from schlagmichdoch/fix-send-text-dialog-cut-off

Make style more airy; Dark mode real black; Recreate Icons
This commit is contained in:
schlagmichdoch 2023-11-23 19:36:15 +01:00 committed by GitHub
commit 021c67bd77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 732 additions and 415 deletions

View file

@ -85,7 +85,8 @@ Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
* 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)
* When hosting PairDrop yourself you can [set your own STUN/TURN servers](/docs/host-your-own.md#specify-stunturn-servers)
* Built-in translations
* Built-in translations via [Weblate](https://hosted.weblate.org/engage/pairdrop/)
* Airy design (Thanks [@Avieshek](https://linktr.ee/avieshek/))
</details>

View file

@ -0,0 +1,93 @@
Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View file

@ -0,0 +1,100 @@
Open Sans Variable Font
=======================
This download contains Open Sans as both variable fonts and static fonts.
Open Sans is a variable font with these axes:
wdth
wght
This means all the styles are contained in these files:
OpenSans-VariableFont_wdth,wght.ttf
OpenSans-Italic-VariableFont_wdth,wght.ttf
If your app fully supports variable fonts, you can now pick intermediate styles
that arent available as static fonts. Not all apps support variable fonts, and
in those cases you can use the static font files for Open Sans:
static/OpenSans_Condensed-Light.ttf
static/OpenSans_Condensed-Regular.ttf
static/OpenSans_Condensed-Medium.ttf
static/OpenSans_Condensed-SemiBold.ttf
static/OpenSans_Condensed-Bold.ttf
static/OpenSans_Condensed-ExtraBold.ttf
static/OpenSans_SemiCondensed-Light.ttf
static/OpenSans_SemiCondensed-Regular.ttf
static/OpenSans_SemiCondensed-Medium.ttf
static/OpenSans_SemiCondensed-SemiBold.ttf
static/OpenSans_SemiCondensed-Bold.ttf
static/OpenSans_SemiCondensed-ExtraBold.ttf
static/OpenSans-Light.ttf
static/OpenSans-Regular.ttf
static/OpenSans-Medium.ttf
static/OpenSans-SemiBold.ttf
static/OpenSans-Bold.ttf
static/OpenSans-ExtraBold.ttf
static/OpenSans_Condensed-LightItalic.ttf
static/OpenSans_Condensed-Italic.ttf
static/OpenSans_Condensed-MediumItalic.ttf
static/OpenSans_Condensed-SemiBoldItalic.ttf
static/OpenSans_Condensed-BoldItalic.ttf
static/OpenSans_Condensed-ExtraBoldItalic.ttf
static/OpenSans_SemiCondensed-LightItalic.ttf
static/OpenSans_SemiCondensed-Italic.ttf
static/OpenSans_SemiCondensed-MediumItalic.ttf
static/OpenSans_SemiCondensed-SemiBoldItalic.ttf
static/OpenSans_SemiCondensed-BoldItalic.ttf
static/OpenSans_SemiCondensed-ExtraBoldItalic.ttf
static/OpenSans-LightItalic.ttf
static/OpenSans-Italic.ttf
static/OpenSans-MediumItalic.ttf
static/OpenSans-SemiBoldItalic.ttf
static/OpenSans-BoldItalic.ttf
static/OpenSans-ExtraBoldItalic.ttf
Get started
-----------
1. Install the font files you want to use
2. Use your app's font picker to view the font family and all the
available styles
Learn more about variable fonts
-------------------------------
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
https://variablefonts.typenetwork.com
https://medium.com/variable-fonts
In desktop apps
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
Online
https://developers.google.com/fonts/docs/getting_started
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
Installing fonts
MacOS: https://support.apple.com/en-us/HT201749
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
Android Apps
https://developers.google.com/fonts/docs/android
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
License
-------
Please read the full license text (OFL.txt) to understand the permissions,
restrictions and requirements for usage, redistribution, and modification.
You can use them in your products & projects print or digital,
commercial or otherwise.
This isn't legal advice, please consider consulting a lawyer and see the full
license for all details.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View file

@ -5,7 +5,7 @@
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!-- Web App Config -->
<title>PairDrop</title>
<title>PairDrop | Transfer Files Cross-Platform. No Setup, No Signup.</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#3367d6">
<meta name="color-scheme" content="dark light">
@ -95,7 +95,7 @@
<use xlink:href="#public-room-icon"></use>
</svg>
</div>
<div id="cancel-paste-mode" class="button" data-i18n-key="header.cancel-paste-mode" data-i18n-attrs="text" hidden></div>
<div id="cancel-paste-mode" class="btn" data-i18n-key="header.cancel-paste-mode" data-i18n-attrs="text" hidden></div>
</header>
<!-- Center -->
<div id="center" class="opacity-0">
@ -118,7 +118,13 @@
<!-- Footer -->
<footer class="column opacity-0">
<svg class="icon logo">
<use xlink:href="#wifi-tethering"></use>
<defs>
<linearGradient id="primaryGradient" gradientTransform="rotate(90)">
<stop offset="0%" class="start-color" />
<stop offset="100%" class="stop-color" />
</linearGradient>
</defs>
<use xlink:href="#wifi-tethering" style="fill: url(#primaryGradient);"></use>
</svg>
<div class="column">
<div class="known-as-wrapper">
@ -133,9 +139,9 @@
<span data-i18n-key="footer.discovery" data-i18n-attrs="text"></span>
</div>
<div class="row center">
<span class="badge badge-room-ip" data-i18n-key="footer.on-this-network" data-i18n-attrs="text title"></span>
<span class="badge badge-room-secret pointer" data-i18n-key="footer.paired-devices" data-i18n-attrs="text title" hidden></span>
<span class="badge badge-room-public-id pointer" data-i18n-key="footer.public-room-devices" data-i18n-attrs="title" hidden>in room IAIAI</span>
<span class="badge badge-gradient badge-room-ip" data-i18n-key="footer.on-this-network" data-i18n-attrs="text title"></span>
<span class="badge badge-gradient badge-room-secret pointer" data-i18n-key="footer.paired-devices" data-i18n-attrs="text title" hidden></span>
<span class="badge badge-gradient badge-room-public-id pointer" data-i18n-key="footer.public-room-devices" data-i18n-attrs="title" hidden>in room IAIAI</span>
</div>
</div>
</div>
@ -148,78 +154,78 @@
<h2 class="center" data-i18n-key="dialogs.language-selector-title" data-i18n-attrs="text"></h2>
</div>
<div class="language-buttons">
<button class="button fw" data-i18n-key="dialogs.system-language" data-i18n-attrs="text"></button>
<button class="button fw" value="ar">
<button class="btn fw" data-i18n-key="dialogs.system-language" data-i18n-attrs="text"></button>
<button class="btn fw" value="ar">
<span>العربية</span>
<span>-</span>
<span>(Arabic)</span>
</button>
<button class="button fw" value="de">
<button class="btn fw" value="de">
<span>Deutsch</span>
<span>-</span>
<span>(German)</span>
</button>
<button class="button fw" value="en">
<button class="btn fw" value="en">
<span>English</span>
</button>
<button class="button fw" value="es">
<button class="btn fw" value="es">
<span>Español</span>
<span>-</span>
<span>(Spanish)</span>
</button>
<button class="button fw" value="fr">
<button class="btn fw" value="fr">
<span>Français</span>
<span>-</span>
<span>(French)</span>
</button>
<button class="button fw" value="id">
<button class="btn fw" value="id">
<span>Bahasa Indonesia</span>
<span>-</span>
<span>(Indonesian)</span>
</button>
<button class="button fw" value="it">
<button class="btn fw" value="it">
<span>Italiano</span>
<span>-</span>
<span>(Italian)</span>
</button>
<button class="button fw" value="nl">
<button class="btn fw" value="nl">
<span>Nederlands</span>
<span>-</span>
<span>(Dutch)</span>
</button>
<button class="button fw" value="nb">
<button class="btn fw" value="nb">
<span>Norsk</span>
<span>-</span>
<span>(Norwegian)</span>
</button>
<button class="button fw" value="ro">
<button class="btn fw" value="ro">
<span>Română</span>
<span>-</span>
<span>(Romanian)</span>
</button>
<button class="button fw" value="ru">
<button class="btn fw" value="ru">
<span>Русский язык</span>
<span>-</span>
<span>(Russian)</span>
</button>
<button class="button fw" value="tr">
<button class="btn fw" value="tr">
<span>Türkçe</span>
<span>-</span>
<span>(Turkish)</span>
</button>
<button class="button fw" value="zh-CN">
<button class="btn fw" value="zh-CN">
<span>中文</span>
<span>-</span>
<span>(Chinese)</span>
</button>
<button class="button fw" value="ja">
<button class="btn fw" value="ja">
<span>日本語</span>
<span>-</span>
<span>(Japanese)</span>
</button>
</div>
<div class="center row-reverse button-row">
<button class="button" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
<button class="btn btn-rounded btn-grey" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
</x-background>
@ -249,7 +255,7 @@
</div>
</div>
<div class="row center">
<div class="column">
<div class="column fw">
<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-2" maxlength="1" autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" contenteditable placeholder disabled>
@ -262,8 +268,8 @@
</div>
</div>
<div class="button-row row-reverse">
<button class="button" type="submit" data-i18n-key="dialogs.pair" data-i18n-attrs="text" disabled></button>
<button class="button" type="button" data-i18n-key="dialogs.cancel" data-i18n-attrs="text" close></button>
<button class="btn btn-rounded btn-grey" type="submit" data-i18n-key="dialogs.pair" data-i18n-attrs="text" disabled></button>
<button class="btn btn-rounded btn-grey" type="button" data-i18n-key="dialogs.cancel" data-i18n-attrs="text" close></button>
</div>
</x-paper>
</x-background>
@ -286,7 +292,7 @@
</p>
</div>
<div class="center row-reverse button-row">
<button class="button" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
<button class="btn btn-rounded btn-grey" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
</x-background>
@ -319,7 +325,7 @@
</div>
</div>
<div class="row center">
<div class="column">
<div class="column fw">
<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-2" maxlength="1" autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" contenteditable placeholder disabled>
@ -331,9 +337,9 @@
</div>
</div>
<div class="center row-reverse button-row">
<button class="button" type="submit" data-i18n-key="dialogs.join" data-i18n-attrs="text" disabled></button>
<button class="button" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
<button class="button leave-room" type="button" data-i18n-key="dialogs.leave" data-i18n-attrs="text"></button>
<button class="btn btn-rounded btn-grey" type="submit" data-i18n-key="dialogs.join" data-i18n-attrs="text" disabled></button>
<button class="btn btn-rounded btn-grey" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
<button class="btn btn-rounded btn-grey leave-room" type="button" data-i18n-key="dialogs.leave" data-i18n-attrs="text"></button>
</div>
</x-paper>
</x-background>
@ -348,10 +354,10 @@
<h2 class="center"></h2>
</div>
</div>
<div class="row center">
<div class="row center p1">
<div class="column center file-description">
<div>
<span class="display-name badge"></span>
<span class="display-name badge badge-gradient"></span>
<span data-i18n-key="dialogs.would-like-to-share" data-i18n-attrs="text"></span>
</div>
<div class="row file-name">
@ -365,8 +371,8 @@
</div>
<div class="center file-preview"></div>
<div class="row-reverse center button-row">
<button id="accept-request" class="button" title="ENTER" data-i18n-key="dialogs.accept" data-i18n-attrs="text" autofocus></button>
<button id="decline-request" class="button" title="ESCAPE" data-i18n-key="dialogs.decline" data-i18n-attrs="text"></button>
<button id="accept-request" class="btn btn-rounded btn-grey" title="ENTER" data-i18n-key="dialogs.accept" data-i18n-attrs="text" autofocus></button>
<button id="decline-request" class="btn btn-rounded btn-grey" title="ESCAPE" data-i18n-key="dialogs.decline" data-i18n-attrs="text"></button>
</div>
</x-paper>
</x-background>
@ -380,10 +386,10 @@
<h2 class="center"></h2>
</div>
</div>
<div class="row center">
<div class="row center p1">
<div class="column center file-description">
<div>
<span class="display-name badge"></span>
<span class="display-name badge badge-gradient"></span>
<span data-i18n-key="dialogs.has-sent" data-i18n-attrs="text"></span>
</div>
<div class="row file-name">
@ -397,9 +403,9 @@
</div>
<div class="center file-preview"></div>
<div class="row-reverse center button-row">
<button id="share-btn" class="button" data-i18n-key="dialogs.share" data-i18n-attrs="text" hidden></button>
<button id="download-btn" class="button" data-i18n-key="dialogs.download" data-i18n-attrs="text" autofocus></button>
<button class="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
<button id="share-btn" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.share" data-i18n-attrs="text" hidden></button>
<button id="download-btn" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.download" data-i18n-attrs="text" autofocus></button>
<button class="btn btn-rounded btn-grey" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
</x-background>
@ -414,22 +420,22 @@
<h2 class="center" data-i18n-key="dialogs.send-message-title" data-i18n-attrs="text"></h2>
</div>
</div>
<div class="row center display-name-wrapper">
<div class="row center p1 display-name-wrapper">
<div class="column">
<div class="text-center">
<span data-i18n-key="dialogs.send-message-to" data-i18n-attrs="text"></span>
<span class="display-name badge"></span>
<span class="display-name badge badge-gradient"></span>
</div>
</div>
</div>
<div class="row">
<div class="row p1">
<div class="column fw">
<div id="text-input" class="textarea" role="textbox" data-i18n-key="dialogs.message" data-i18n-attrs="title" autocapitalize="none" spellcheck="false" autofocus contenteditable></div>
<div id="text-input" class="fw textarea" role="textbox" data-i18n-key="dialogs.message" data-i18n-attrs="title placeholder" autofocus contenteditable></div>
</div>
</div>
<div class="button-row row-reverse">
<button class="button" type="submit" title="CTRL/⌘ + ENTER" data-i18n-key="dialogs.send" data-i18n-attrs="text" disabled></button>
<button class="button" type="button" title="ESCAPE" data-i18n-key="dialogs.cancel" data-i18n-attrs="text" close></button>
<button class="btn btn-rounded btn-grey" type="submit" title="CTRL/⌘ + ENTER" data-i18n-key="dialogs.send" data-i18n-attrs="text" disabled></button>
<button class="btn btn-rounded btn-grey" type="button" title="ESCAPE" data-i18n-key="dialogs.cancel" data-i18n-attrs="text" close></button>
</div>
</x-paper>
</x-background>
@ -442,20 +448,20 @@
<div class="row center">
<h2 class="text-center" data-i18n-key="dialogs.receive-text-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center">
<div class="row center p1 display-name-wrapper">
<div class="text-center">
<span class="display-name badge"></span>
<span class="display-name badge badge-gradient"></span>
<span data-i18n-key="dialogs.has-sent" data-i18n-attrs="text"></span>
</div>
</div>
<div class="row center">
<div class="row center p1">
<div class="column fw">
<div id="text" class="textarea fw"></div>
<div id="text" class="textarea"></div>
</div>
</div>
<div class="row-reverse center button-row">
<button id="copy" class="button" title="CTRL/⌘ + C" data-i18n-key="dialogs.copy" data-i18n-attrs="text"></button>
<button id="close" class="button" title="ESCAPE" data-i18n-key="dialogs.close" data-i18n-attrs="text"></button>
<button id="copy" class="btn btn-rounded btn-grey" title="CTRL/⌘ + C" data-i18n-key="dialogs.copy" data-i18n-attrs="text"></button>
<button id="close" class="btn btn-rounded btn-grey" title="ESCAPE" data-i18n-key="dialogs.close" data-i18n-attrs="text"></button>
</div>
</x-paper>
</x-background>
@ -464,10 +470,10 @@
<x-dialog id="base64-paste-dialog">
<x-background class="full center">
<x-paper shadow="2">
<button class="button 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" placeholder="Paste here to send files" title="CMD/⌘ + V" contenteditable hidden></div>
<div class="row-reverse center button-row">
<button class="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
<button class="btn btn-rounded btn-grey" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
</x-background>

View file

@ -70,8 +70,9 @@
"share": "Share",
"download": "Download",
"send-message-title": "Send Message",
"send-message-to": "Send a Message to",
"send-message-to": "To:",
"message_title": "Insert message to send",
"message_placeholder": "Text",
"send": "Send",
"receive-text-title": "Message Received",
"copy": "Copy",

View file

@ -1,29 +1,30 @@
{
"name": "PairDrop",
"short_name": "PairDrop",
"icons": [{
"icons": [
{
"src": "images/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},{
},
{
"src": "images/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
},{
},
{
"src": "images/android-chrome-192x192-maskable.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},{
},
{
"src": "images/android-chrome-512x512-maskable.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
},{
"src": "images/favicon-96x96.png",
"sizes": "96x96",
"type": "image/png"
}],
}
],
"background_color": "#efefef",
"start_url": "/",
"scope": "/",

View file

@ -0,0 +1,60 @@
class BrowserTabsConnector {
constructor() {
this.bc = new BroadcastChannel('pairdrop');
this.bc.addEventListener('message', e => this._onMessage(e));
Events.on('broadcast-send', e => this._broadcastSend(e.detail));
}
_broadcastSend(message) {
this.bc.postMessage(message);
}
_onMessage(e) {
console.log('Broadcast:', e.data)
switch (e.data.type) {
case 'self-display-name-changed':
Events.fire('self-display-name-changed', e.data.detail);
break;
}
}
static peerIsSameBrowser(peerId) {
let peerIdsBrowser = JSON.parse(localStorage.getItem("peer_ids_browser"));
return peerIdsBrowser
? peerIdsBrowser.indexOf(peerId) !== -1
: false;
}
static async addPeerIdToLocalStorage() {
const peerId = sessionStorage.getItem("peer_id");
if (!peerId) return false;
let peerIdsBrowser = [];
let peerIdsBrowserOld = JSON.parse(localStorage.getItem("peer_ids_browser"));
if (peerIdsBrowserOld) peerIdsBrowser.push(...peerIdsBrowserOld);
peerIdsBrowser.push(peerId);
peerIdsBrowser = peerIdsBrowser.filter(onlyUnique);
localStorage.setItem("peer_ids_browser", JSON.stringify(peerIdsBrowser));
return peerIdsBrowser;
}
static async removePeerIdFromLocalStorage(peerId) {
let peerIdsBrowser = JSON.parse(localStorage.getItem("peer_ids_browser"));
const index = peerIdsBrowser.indexOf(peerId);
peerIdsBrowser.splice(index, 1);
localStorage.setItem("peer_ids_browser", JSON.stringify(peerIdsBrowser));
return peerId;
}
static async removeOtherPeerIdsFromLocalStorage() {
const peerId = sessionStorage.getItem("peer_id");
if (!peerId) return false;
let peerIdsBrowser = [peerId];
localStorage.setItem("peer_ids_browser", JSON.stringify(peerIdsBrowser));
return peerIdsBrowser;
}
}

View file

@ -39,7 +39,7 @@ class PairDrop {
registerServiceWorker() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/service-worker.js')
.register('service-worker.js')
.then(serviceWorker => {
console.log('Service Worker registered');
window.serviceWorker = serviceWorker
@ -99,6 +99,7 @@ class PairDrop {
"styles/deferred-styles.css"
];
this.deferredScripts = [
"scripts/browser-tabs-connector.js",
"scripts/util.js",
"scripts/network.js",
"scripts/ui.js",

View file

@ -271,8 +271,8 @@ class BackgroundCanvas {
drawCircle(ctx, radius) {
ctx.beginPath();
ctx.lineWidth = 2;
let opacity = Math.max(0, 0.3 * (1 - 1 * radius / Math.max(this.w, this.h)));
ctx.strokeStyle = `rgba(128, 128, 128, ${opacity})`;
let opacity = Math.max(0, 0.3 * (1 - 1.2 * radius / Math.max(this.w, this.h)));
ctx.strokeStyle = `rgba(165, 165, 165, ${opacity})`;
ctx.arc(this.x0, this.y0, radius, 0, 2 * Math.PI);
ctx.stroke();
}

View file

@ -280,6 +280,8 @@ class PeersUI {
class PeerUI {
static _badgeClassNames = ["badge-room-ip", "badge-room-secret", "badge-room-public-id"];
constructor(peer, connectionHash) {
this.$xInstructions = $$('x-instructions');
this.$xPeers = $$('x-peers');
@ -330,14 +332,12 @@ class PeerUI {
<div class="name font-subheading"></div>
<div class="device-name font-body2"></div>
<div class="status font-body2"></div>
<span class="connection-hash font-body2" dir="ltr" title="${ Localization.getTranslation("peer-ui.connection-hash") }"></span>
</div>
</label>`;
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.$el.querySelector('.connection-hash').textContent = this._connectionHash;
}
addTypesToClassList() {
@ -569,7 +569,7 @@ class Dialog {
document.activeElement.blur();
window.blur();
}
document.title = 'PairDrop';
document.title = 'PairDrop | Transfer Files Cross-Platform. No Setup, No Signup.';
changeFavicon("images/favicon-96x96.png");
this.correspondingPeerId = undefined;
}
@ -1187,8 +1187,8 @@ class PairDeviceDialog extends Dialog {
// Display the QR code for the url
const qr = new QRCode({
content: this._getPairUrl(),
width: 150,
height: 150,
width: 130,
height: 130,
padding: 1,
background: 'rgb(250,250,250)',
color: 'rgb(18, 18, 18)',
@ -1392,7 +1392,7 @@ class EditPairedDevicesDialog extends Dialog {
<label class="auto-accept pointer">${autoAcceptString}
<input type="checkbox" ${roomSecretsEntry.auto_accept ? "checked" : ""}>
</label>
<button class="button" type="button">${unpairString}</button>
<button class="btn" type="button">${unpairString}</button>
</div>`
$pairedDevice
@ -1433,7 +1433,19 @@ class EditPairedDevicesDialog extends Dialog {
}
_onEditPairedDevices() {
this._initDOM().then(_ => this.show());
this._initDOM()
.then(_ => {
this._evaluateOverflowing();
this.show();
});
}
_evaluateOverflowing() {
if (this.$pairedDevicesWrapper.clientHeight < this.$pairedDevicesWrapper.scrollHeight) {
this.$pairedDevicesWrapper.classList.add('overflowing');
} else {
this.$pairedDevicesWrapper.classList.remove('overflowing');
}
}
_clearRoomSecrets() {
@ -1556,8 +1568,8 @@ class PublicRoomDialog extends Dialog {
// Display the QR code for the url
const qr = new QRCode({
content: this._getShareRoomUrl(),
width: 150,
height: 150,
width: 130,
height: 130,
padding: 1,
background: 'rgb(250,250,250)',
color: 'rgb(18, 18, 18)',
@ -1736,16 +1748,27 @@ class SendTextDialog extends Dialog {
_onChange() {
if (this._textInputEmpty()) {
this.$submit.setAttribute('disabled', true);
// remove remaining whitespace on Firefox on text deletion
this.$text.innerText = "";
}
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');
}
}
_onRecipient(peerId, deviceName) {
this.correspondingPeerId = peerId;
this.$peerDisplayName.innerText = deviceName;
this.$peerDisplayName.classList.remove("badge-room-ip", "badge-room-secret", "badge-room-public-id");
this.$peerDisplayName.classList.remove(...PeerUI._badgeClassNames);
this.$peerDisplayName.classList.add($(peerId).ui._badgeClassName());
this.show();
@ -1768,8 +1791,8 @@ class SendTextDialog extends Dialog {
to: this.correspondingPeerId,
text: this.$text.innerText
});
this.$text.innerText = "";
this.hide();
setTimeout(() => this.$text.innerText = "", 300);
}
}
@ -1818,7 +1841,7 @@ class ReceiveTextDialog extends Dialog {
_showReceiveTextDialog(text, peerId) {
this.$displayName.innerText = $(peerId).ui._displayName();
this.$displayName.classList.remove("badge-room-ip", "badge-room-secret", "badge-room-public-id");
this.$displayName.classList.remove(...PeerUI._badgeClassNames);
this.$displayName.classList.add($(peerId).ui._badgeClassName());
this.$text.innerText = text;
@ -1832,12 +1855,22 @@ class ReceiveTextDialog extends Dialog {
});
}
this._evaluateOverflowing();
this._setDocumentTitleMessages();
changeFavicon("images/favicon-96x96-notification.png");
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`
@ -2326,64 +2359,3 @@ class NoSleepUI {
}
}
}
class BrowserTabsConnector {
constructor() {
this.bc = new BroadcastChannel('pairdrop');
this.bc.addEventListener('message', e => this._onMessage(e));
Events.on('broadcast-send', e => this._broadcastSend(e.detail));
}
_broadcastSend(message) {
this.bc.postMessage(message);
}
_onMessage(e) {
console.log('Broadcast:', e.data)
switch (e.data.type) {
case 'self-display-name-changed':
Events.fire('self-display-name-changed', e.data.detail);
break;
}
}
static peerIsSameBrowser(peerId) {
let peerIdsBrowser = JSON.parse(localStorage.getItem("peer_ids_browser"));
return peerIdsBrowser
? peerIdsBrowser.indexOf(peerId) !== -1
: false;
}
static async addPeerIdToLocalStorage() {
const peerId = sessionStorage.getItem("peer_id");
if (!peerId) return false;
let peerIdsBrowser = [];
let peerIdsBrowserOld = JSON.parse(localStorage.getItem("peer_ids_browser"));
if (peerIdsBrowserOld) peerIdsBrowser.push(...peerIdsBrowserOld);
peerIdsBrowser.push(peerId);
peerIdsBrowser = peerIdsBrowser.filter(onlyUnique);
localStorage.setItem("peer_ids_browser", JSON.stringify(peerIdsBrowser));
return peerIdsBrowser;
}
static async removePeerIdFromLocalStorage(peerId) {
let peerIdsBrowser = JSON.parse(localStorage.getItem("peer_ids_browser"));
const index = peerIdsBrowser.indexOf(peerId);
peerIdsBrowser.splice(index, 1);
localStorage.setItem("peer_ids_browser", JSON.stringify(peerIdsBrowser));
return peerId;
}
static async removeOtherPeerIdsFromLocalStorage() {
const peerId = sessionStorage.getItem("peer_id");
if (!peerId) return false;
let peerIdsBrowser = [peerId];
localStorage.setItem("peer_ids_browser", JSON.stringify(peerIdsBrowser));
return peerIdsBrowser;
}
}

View file

@ -1,27 +1,46 @@
/* All styles in this sheet are not needed on page load and deferred */
/* Peers */
x-peers.overflowing {
background: /* Shadow covers */ linear-gradient(rgb(var(--bg-color)) 30%, rgba(var(--bg-color), 0)),
linear-gradient(rgba(var(--bg-color), 0), rgb(var(--bg-color)) 70%) 0 100%,
/* Shadows */ radial-gradient(farthest-side at 50% 0, rgba(var(--text-color), .2), rgba(var(--text-color), 0)),
radial-gradient(farthest-side at 50% 100%, rgba(var(--text-color), .2), rgba(var(--text-color), 0)) 0 100%;
background-repeat: no-repeat;
background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
/* Opera doesn't support this in the shorthand */
background-attachment: local, local, scroll, scroll;
/* 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;
border: none;
outline: none;
padding: 16px 24px;
border-radius: 12px;
font-size: inherit;
font-family: inherit;
display: block;
overflow: auto;
resize: none;
line-height: 16px;
max-height: 300px;
word-break: break-word;
word-wrap: anywhere;
}
/* Peers */
x-peers:has(> x-peer) {
--peers-per-row: 10;
}
/* peers-per-row if height is too small for 2 rows */
@media screen and (min-height: 538px) and (max-height: 683px) and (max-width: 402px),
screen and (min-height: 517px) and (max-height: 664px) and (min-width: 426px) {
@media screen and (min-height: 505px) and (max-height: 649px) and (max-width: 426px),
screen and (min-height: 486px) and (max-height: 631px) and (min-width: 426px) {
x-peers:has(> x-peer) {
--peers-per-row: 3;
}
@ -55,9 +74,8 @@ screen and (min-height: 517px) and (max-height: 664px) and (min-width: 426px) {
}
}
/* peers-per-row if height is too small for 3 rows */
@media screen and (min-height: 683px) and (max-width: 402px),
screen and (min-height: 664px) and (min-width: 426px) {
@media screen and (min-height: 649px) and (max-width: 425px),
screen and (min-height: 631px) and (min-width: 426px) {
x-peers:has(> x-peer) {
--peers-per-row: 3;
}
@ -99,6 +117,11 @@ x-peer {
flex-wrap: wrap;
}
x-peer input[type="file"] {
visibility: hidden;
position: absolute;
}
x-peer label {
width: var(--peer-width);
touch-action: manipulation;
@ -119,48 +142,60 @@ x-peer .icon-wrapper {
width: var(--icon-size);
padding: 12px;
border-radius: 50%;
background: var(--primary-color);
background: var(--accent-color);
background-image: linear-gradient(45deg, var(--accent-color) 40%, color-mix(in srgb, var(--accent-color) 70%, white) 100%);
color: white;
display: flex;
}
x-peer.type-secret .icon-wrapper {
background: var(--paired-device-color);
--accent-color: var(--paired-device-color);
}
x-peer:not(.type-ip):not(.type-secret).type-public-id .icon-wrapper {
background: var(--public-room-color);
--accent-color: var(--public-room-color);
}
x-peer x-icon > .highlight-wrapper {
.highlight-wrapper {
align-self: center;
align-items: center;
margin: 7px auto 0;
height: 6px;
}
x-peer x-icon > .highlight-wrapper > .highlight {
.highlight {
width: 15px;
height: 6px;
border-radius: 4px;
margin-left: 1px;
margin-right: 1px;
--highlight-color: var(--badge-color);
background-color: var(--highlight-color);
background-image: linear-gradient(180deg, var(--highlight-color) 0%, color-mix(in srgb, var(--highlight-color) 90%, black));
}
.highlight-room-ip {
--highlight-color: var(--primary-color);
}
.highlight-room-secret {
--highlight-color: var(--paired-device-color);
}
.highlight-room-public-id {
--highlight-color: var(--public-room-color);
}
x-peer:not(.type-ip) .highlight-room-ip {
display: none;
}
x-peer.type-ip x-icon > .highlight-wrapper > .highlight.highlight-room-ip {
background-color: var(--primary-color);
display: inline;
x-peer:not(.type-secret) .highlight-room-secret {
display: none;
}
x-peer.type-secret x-icon > .highlight-wrapper > .highlight.highlight-room-secret {
background-color: var(--paired-device-color);
display: inline;
}
x-peer.type-public-id x-icon > .highlight-wrapper > .highlight.highlight-room-public-id {
background-color: var(--public-room-color);
display: inline;
x-peer:not(.type-public-id) .highlight-room-public-id {
display: none;
}
x-peer:not([status]):hover x-icon,
@ -174,7 +209,6 @@ x-peer[status] x-icon {
transform: scale(1);
}
x-peer.ws-peer {
margin-top: -1.5px;
}
@ -213,18 +247,8 @@ x-peer.ws-peer .highlight-wrapper {
}
.status,
.device-name,
.connection-hash {
opacity: 0.7;
}
.device-name {
font-size: 14px;
white-space: nowrap;
}
.connection-hash {
font-size: 12px;
opacity: 0.7;
white-space: nowrap;
}
@ -256,14 +280,13 @@ x-peer[drop] x-icon {
}
Dialog
/* Dialog */
x-dialog x-background {
background: rgba(0, 0, 0, 0.61);
z-index: 10;
background: rgba(0, 0, 0, 0.8);
z-index: 30;
transition: opacity 300ms;
will-change: opacity;
padding: 15px;
overflow: overlay;
}
@ -272,8 +295,7 @@ x-dialog x-paper {
flex-direction: column;
width: calc(100vw - 10px);
z-index: 3;
background: white;
border-radius: 8px;
border-radius: 30px;
max-width: 400px;
overflow: hidden;
box-sizing: border-box;
@ -292,8 +314,8 @@ x-dialog x-paper {
x-paper > .row:first-of-type {
background-color: var(--accent-color);
border-bottom: solid 4px var(--border-color);
margin-bottom: 10px;
padding: 10px;
margin-bottom: 5px;
}
x-paper > .row:first-of-type h2 {
@ -339,7 +361,6 @@ x-dialog a {
width: 100%;
display: flex;
justify-content: center;
margin-top: 10px;
}
.input-key-container > input {
@ -372,20 +393,22 @@ x-dialog a {
-moz-user-select: text;
user-select: text;
display: inline-block;
font-size: 50px;
font-size: 45px;
letter-spacing: min(calc((100vw - 80px - 99px) / 100 * 7), 20px);
text-indent: calc(0.5 * (11px + min(calc((100vw - 80px - 99px) / 100 * 6), 28px)));
margin: 25px 0;
margin: 10px 0;
}
.key-qr-code {
margin: 16px;
width: fit-content;
align-self: center;
margin-top: 15px;
margin-bottom: 10px;
}
.key-instructions {
flex-direction: column;
margin: 0;
}
x-dialog h2 {
@ -394,19 +417,19 @@ x-dialog h2 {
}
x-dialog hr {
height: 3px;
height: 1px;
border: none;
width: 100%;
background-color: var(--border-color);
}
.hr-note {
margin-top: 10px;
margin-bottom: 20px;
margin-top: 23px;
margin-bottom: 31px;
}
.hr-note hr {
margin-bottom: -2px;
margin-bottom: -1px;
}
.hr-note > div {
@ -417,9 +440,9 @@ x-dialog hr {
.hr-note > div > span {
padding: 3px 10px;
border-radius: 10px;
border-radius: 20px;
color: rgb(var(--text-color));
background-color: rgb(var(--bg-color));
background-color: var(--dialog-bg-color);
border: var(--border-color) solid 3px;
text-transform: uppercase;
}
@ -438,20 +461,10 @@ x-dialog hr {
}
.paired-devices-wrapper {
border-top: solid 4px var(--paired-device-color);
margin-top: -5px;
border-bottom: solid 4px var(--paired-device-color);
max-height: 65vh;
overflow: scroll;
background: /* Shadow covers */ linear-gradient(rgb(var(--bg-color)) 30%, rgba(var(--bg-color), 0)),
linear-gradient(rgba(var(--bg-color), 0), rgb(var(--bg-color)) 70%) 0 100%,
/* Shadows */ radial-gradient(farthest-side at 50% 0, rgba(var(--text-color), .3), rgba(var(--text-color), 0)),
radial-gradient(farthest-side at 50% 100%, rgba(var(--text-color), .3), rgba(var(--text-color), 0)) 0 100%;
background-repeat: no-repeat;
background-size: 100% 80px, 100% 80px, 100% 24px, 100% 24px;
/* Opera doesn't support this in the shorthand */
background-attachment: local, local, scroll, scroll;
}
.paired-device {
@ -515,44 +528,41 @@ x-dialog hr {
text-overflow: ellipsis;
}
/* Receive Dialog */
x-paper > .row {
padding: 10px;
}
/* button row*/
x-paper > .button-row {
border-top: solid 3px var(--border-color);
height: 50px;
margin-top: 10px;
margin: 5px 10px 10px;
}
x-paper > .button-row > .button {
x-paper > .button-row > .btn {
height: 100%;
width: 100%;
}
html:not([dir="rtl"]) x-paper > .button-row > .button:not(:first-child) {
border-right: solid 1.5px var(--border-color);
html:not([dir="rtl"]) x-paper > .button-row > .btn:not(:first-child) {
margin-right: 5px;
}
html:not([dir="rtl"]) x-paper > .button-row > .button:not(:last-child) {
border-left: solid 1.5px var(--border-color);
html:not([dir="rtl"]) x-paper > .button-row > .btn:not(:last-child) {
margin-left: 5px;
}
html[dir="rtl"] x-paper > .button-row > .button:not(:first-child) {
border-left: solid 1.5px var(--border-color);
html[dir="rtl"] x-paper > .button-row > .btn:not(:first-child) {
margin-right: 5px;
}
html[dir="rtl"] x-paper > .button-row > .button:not(:last-child) {
border-right: solid 1.5px var(--border-color);
html[dir="rtl"] x-paper > .button-row > .btn:not(:last-child) {
margin-left: 5px;
}
.language-buttons > button > span {
margin: 0 0.3em;
}
.language-buttons > button {
min-height: 36px;
}
.file-description {
max-width: 100%;
}
@ -581,31 +591,37 @@ x-dialog .dialog-subheader {
padding-bottom: 16px;
}
#send-text-dialog .display-name-wrapper {
.display-name-wrapper {
padding-bottom: 0;
}
#text-input {
min-height: 200px;
width: 100%;
#send-text-dialog,
#receive-text-dialog {
font-size: 16px; /* prevents auto-zoom on edit */
--shadow-color-rgb: var(--shadow-color-secondary-rgb);
--shadow-color-cover-rgb: var(--shadow-color-secondary-cover-rgb);
}
#edit-paired-devices-dialog {
--shadow-color-rgb: var(--shadow-color-dialog-rgb);
--shadow-color-cover-rgb: var(--shadow-color-dialog-cover-rgb);
}
#text-input:before {
opacity: 0.5;
}
/* Receive Text Dialog */
#receive-text-dialog #text {
width: 100%;
word-break: break-all;
max-height: calc(100vh - 393px);
max-height: 400px;
padding: 10px;
overflow-x: hidden;
overflow-y: auto;
overflow-y: scroll;
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
white-space: pre-wrap;
}
#receive-text-dialog #text a {
cursor: pointer;
}
#receive-text-dialog #text a:hover {
@ -618,17 +634,11 @@ x-dialog .dialog-subheader {
pointer-events: none;
}
.row-separator {
border-bottom: solid 2.5px var(--border-color);
margin: auto -24px;
}
#base64-paste-btn,
#base64-paste-dialog .textarea {
width: 100%;
height: 40vh;
border: solid 12px #438cff;
border-radius: 8px;
}
#base64-paste-dialog .textarea {
@ -639,7 +649,7 @@ x-dialog .dialog-subheader {
}
#base64-paste-dialog .textarea::before {
font-size: 15px;
font-size: 14px;
letter-spacing: 0.12em;
color: var(--primary-color);
font-weight: 700;
@ -647,7 +657,6 @@ x-dialog .dialog-subheader {
white-space: pre-wrap;
}
/* Peer loading Indicator */
.progress {
@ -679,7 +688,6 @@ x-dialog .dialog-subheader {
transform: rotate(180deg);
}
/*
Color Themes
*/
@ -687,7 +695,7 @@ x-dialog .dialog-subheader {
/* Colored Elements */
x-dialog x-paper {
background-color: rgb(var(--bg-color));
background-color: var(--dialog-bg-color);
}
.textarea {

View file

@ -1,18 +1,5 @@
/* All styles in this sheet are needed on page load */
/* Constants */
:root {
--icon-size: 24px;
--primary-color: #4285f4;
--paired-device-color: #00a69c;
--public-room-color: #db8500;
--accent-color: var(--primary-color);
--peer-width: 120px;
--ws-peer-color: #ff6b6b;
color-scheme: light dark;
}
/* Layout */
html,
@ -43,6 +30,10 @@ html {
width: 100%;
}
.p1 {
padding: 10px;
}
.row-reverse {
display: flex;
flex-direction: row-reverse;
@ -90,7 +81,7 @@ header {
padding: 8px 12px;
box-sizing: border-box;
width: 100vw;
z-index: 2;
z-index: 20;
top: 0;
right: 0;
}
@ -163,10 +154,18 @@ header > div:hover .icon-button.selected::before {
/* Typography */
@font-face {
font-family: "Open Sans";
src: url('../fonts/OpenSans/static/OpenSans-Medium.ttf') format('truetype');
}
body {
font-family: -apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-family: "Open Sans", -apple-system, BlinkMacSystemFont, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
font-variant-ligatures: common-ligatures;
font-kerning: normal;
}
h1 {
@ -174,7 +173,7 @@ h1 {
font-weight: 400;
letter-spacing: -.01em;
line-height: 40px;
margin: 8px 0 0;
margin: 0 0 4px;
}
h2 {
@ -260,7 +259,19 @@ x-noscript {
0 2px 4px -1px rgba(0, 0, 0, 0.4);
}
.overflowing {
background:
/* Shadow covers */
linear-gradient(rgb(var(--shadow-color-cover-rgb)) 30%, rgba(var(--shadow-color-cover-rgb), 0)),
linear-gradient(rgba(var(--shadow-color-cover-rgb), 0), rgb(var(--shadow-color-cover-rgb)) 70%) 0 100%,
/* Shadows */
radial-gradient(farthest-side at 50% 0, rgba(var(--shadow-color-rgb), .2), rgba(var(--shadow-color-rgb), 0)),
radial-gradient(farthest-side at 50% 100%, rgba(var(--shadow-color-rgb), .2), rgba(var(--shadow-color-rgb), 0))
0 100%;
background-repeat: no-repeat;
background-size: 100% 60px, 100% 60px, 100% 24px, 100% 24px;
background-attachment: local, local, scroll, scroll;
}
/* Animations */
@ -295,6 +306,28 @@ x-noscript {
flex-grow: 1;
}
x-peers {
position: relative;
display: flex;
flex-flow: row wrap;
flex-grow: 1;
align-items: start !important;
justify-content: center;
z-index: 2;
transition: background-color 0.5s ease;
overflow-y: scroll;
overflow-x: hidden;
overscroll-behavior-x: none;
scrollbar-width: none;
--peers-per-row: 6; /* default if browser does not support :has selector */
--x-peers-width: min(100vw, calc(var(--peers-per-row) * (var(--peer-width) + 25px) - 16px));
width: var(--x-peers-width);
margin-right: 20px;
margin-left: 20px;
}
/* Empty Peers List */
x-no-peers {
@ -331,34 +364,6 @@ x-no-peers[drop-bg] * {
display: none;
}
input[type="file"] {
visibility: hidden;
position: absolute;
}
x-peers {
position: relative;
display: flex;
flex-flow: row wrap;
flex-grow: 1;
align-items: start !important;
justify-content: center;
z-index: 2;
transition: --bg-color 0.5s ease;
overflow-y: scroll;
overflow-x: hidden;
overscroll-behavior-x: none;
scrollbar-width: none;
--peers-per-row: 6; /* default if browser does not support :has selector */
--x-peers-width: min(100vw, calc(var(--peers-per-row) * (var(--peer-width) + 25px) - 16px));
width: var(--x-peers-width);
margin-right: 20px;
margin-left: 20px;
}
/* Footer */
footer {
@ -378,16 +383,23 @@ footer .logo {
}
.discovery-wrapper {
font-size: 12px;
margin: 10px auto auto;
border: 3px solid var(--border-color);
border-radius: 0.5rem;
font-size: 14px;
margin: 15px auto auto;
border: 2px solid var(--border-color);
padding: 2px;
background-color: rgb(var(--bg-color));
transition: background-color 0.5s ease;
min-height: 24px;
}
.discovery-wrapper.column {
border-radius: 16px;
}
.discovery-wrapper.row {
border-radius: 12px;
}
/*You can be discovered wrapper*/
.discovery-wrapper > div:first-of-type {
padding-left: 4px;
@ -401,28 +413,32 @@ footer .logo {
}
.badge {
border-radius: 0.3rem/0.3rem;
border-radius: 0.4rem;
padding-right: 0.3rem;
padding-left: 0.3em;
background-color: var(--badge-color);
color: white;
transition: background-color 0.5s ease;
white-space: nowrap;
}
.badge-gradient {
background-image: linear-gradient(180deg, color-mix(in srgb, var(--badge-color) 80%, white) 0%, var(--badge-color) 50%);
}
.badge-room-ip {
background-color: var(--primary-color);
border-color: var(--primary-color);
--badge-color: var(--primary-color);
}
.badge-room-secret {
background-color: var(--paired-device-color);
border-color: var(--paired-device-color);
--badge-color: var(--paired-device-color);
}
.badge-room-public-id {
background-color: var(--public-room-color);
border-color: var(--public-room-color);
--badge-color: var(--public-room-color);
}
.known-as-wrapper {
font-size: 16px; /* prevents auto-zoom on edit */
}
#display-name {
@ -470,13 +486,12 @@ x-dialog:not([show]) x-background {
opacity: 0;
}
/* Button */
.button {
.btn {
font-family: "Open Sans", -apple-system, BlinkMacSystemFont, sans-serif;
padding: 2px 16px 0;
box-sizing: border-box;
min-height: 36px;
font-size: 14px;
line-height: 24px;
font-weight: 700;
@ -490,13 +505,13 @@ x-dialog:not([show]) x-background {
overflow: hidden;
}
.button[disabled] {
color: #5B5B66;
.btn[disabled] {
color: var(--btn-disabled-color);
cursor: not-allowed;
}
.button,
.btn,
.icon-button {
position: relative;
display: flex;
@ -508,7 +523,7 @@ x-dialog:not([show]) x-background {
outline: none;
}
.button:before,
.btn:before,
.icon-button:before {
content: '';
position: absolute;
@ -516,41 +531,33 @@ x-dialog:not([show]) x-background {
left: 0;
right: 0;
bottom: 0;
background: currentColor;
opacity: 0;
background-color: var(--accent-color);
transition: opacity 300ms;
}
.button:not([disabled]):hover:before,
.btn:not([disabled]):hover:before,
.icon-button:hover:before {
opacity: 0.1;
}
.button[selected],
.btn[selected],
.icon-button[selected] {
opacity: 0.1;
}
#cancel-paste-mode {
z-index: 2;
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);
}
.button:focus:before,
.btn:focus:before,
.icon-button:focus:before {
opacity: 0.2;
}
.btn-rounded {
border-radius: 12px;
}
.btn-grey {
background-color: var(--bg-color-secondary);
}
button::-moz-focus-inner {
border: 0;
@ -567,30 +574,12 @@ button::-moz-focus-inner {
border-radius: 50%;
}
/* Text Input */
.textarea {
box-sizing: border-box;
border: none;
outline: none;
padding: 16px 24px;
border-radius: 8px;
font-size: 14px;
font-family: inherit;
background: #f1f3f4;
display: block;
overflow: auto;
resize: none;
line-height: 16px;
max-height: calc(100vh - 254px);
white-space: pre;
}
/* Info Animation */
#about {
color: white;
z-index: 11;
z-index: 32;
overflow: hidden;
pointer-events: none;
text-align: center;
@ -631,7 +620,7 @@ button::-moz-focus-inner {
}
#about .title-wrapper > div {
margin-left: 0.5em;
margin-left: 0.4em;
}
#about x-background {
@ -641,10 +630,11 @@ button::-moz-focus-inner {
top: calc(28px - var(--size-half));
width: var(--size);
height: var(--size);
border-radius: 50%;
background: var(--primary-color);
transform: scale(0);
z-index: -1;
background: var(--primary-color);
background-image: radial-gradient(circle at calc(50% - 36px), var(--accent-color) 0%, color-mix(in srgb, var(--accent-color) 40%, black) 80%);
--crop-size: 0px;
clip-path: circle(var(--crop-size));
}
html:not([dir="rtl"]) #about x-background {
@ -658,12 +648,12 @@ html[dir="rtl"] #about x-background {
/* Hack such that initial scale(0) isn't animated */
#about x-background {
will-change: transform;
transition: transform 800ms cubic-bezier(0.77, 0, 0.175, 1);
will-change: clip-path;
transition: clip-path 800ms cubic-bezier(0.77, 0, 0.175, 1);
}
#about:target x-background {
transform: scale(1);
--crop-size: var(--size);
}
#about .row a {
@ -687,6 +677,38 @@ canvas.circles {
content: attr(placeholder);
}
/* Toast */
.toast-container {
padding: 0 8px 24px;
overflow: hidden;
pointer-events: none;
}
x-toast {
position: absolute;
min-height: 48px;
top: 50px;
width: 100%;
max-width: 344px;
background-color: rgb(var(--text-color));
color: var(--dialog-bg-color);
align-items: center;
box-sizing: border-box;
padding: 8px 24px;
z-index: 40;
transition: opacity 200ms, transform 300ms ease-out;
cursor: default;
line-height: 24px;
border-radius: 12px;
pointer-events: all;
}
x-toast:not([show]):not(:hover) {
opacity: 0;
transform: translateY(-100px);
}
/* Instructions */
x-instructions {
@ -757,36 +779,12 @@ x-peers:empty~x-instructions {
}
}
/* Toast */
/* Constants */
.toast-container {
padding: 0 8px 24px;
overflow: hidden;
pointer-events: none;
}
x-toast {
position: absolute;
min-height: 48px;
top: 50px;
width: 100%;
max-width: 344px;
background-color: rgb(var(--text-color));
color: rgb(var(--bg-color));
align-items: center;
box-sizing: border-box;
padding: 8px 24px;
z-index: 20;
transition: opacity 200ms, transform 300ms ease-out;
cursor: default;
line-height: 24px;
border-radius: 8px;
pointer-events: all;
}
x-toast:not([show]):not(:hover) {
opacity: 0;
transform: translateY(-100px);
:root {
--icon-size: 24px;
--peer-width: 120px;
color-scheme: light dark;
}
/*
@ -794,22 +792,82 @@ x-toast:not([show]):not(:hover) {
*/
/* Default colors */
body {
/* Constant colors */
--primary-color: #4285f4;
--paired-device-color: #00a69c;
--public-room-color: #db8500;
--accent-color: var(--primary-color);
--ws-peer-color: #ff6b6b;
--btn-disabled-color: #5B5B66;
/* shadows */
--shadow-color-rgb: var(--text-color);
--shadow-color-cover-rgb: var(--bg-color);
}
/* Light theme colors */
body {
--text-color: 51,51,51;
--bg-color: 250,250,250; /*rgb code*/
--bg-color-test: 18,18,18;
--bg-color-secondary: #e4e4e4;
--dialog-bg-color: #fff;
--bg-color: 255,255,255;
--bg-color-secondary: #f2f2f2;
--border-color: rgb(169, 169, 169);
--badge-color: #a5a5a5;
--shadow-color-secondary-rgb: 0,0,0;
--shadow-color-secondary-cover-rgb: 242,242,242;
--shadow-color-dialog-rgb: 0,0,0;
--shadow-color-dialog-cover-rgb: 242,242,242;
}
/* Dark theme colors */
body.dark-theme {
--text-color: 238,238,238;
--bg-color: 18,18,18; /*rgb code*/
--bg-color-secondary: #333;
--border-color: rgb(238,238,238);
--dialog-bg-color: #121212;
--bg-color: 0,0,0;
--bg-color-secondary: #262628;
--border-color: rgb(91, 91, 91);
--badge-color: #717171;
--shadow-color-secondary-rgb: 255,255,255;
--shadow-color-secondary-cover-rgb: 38,38,38;
--shadow-color-dialog-rgb: 255,255,255;
--shadow-color-dialog-cover-rgb: 38,38,38;
}
/* Styles for users who prefer dark mode at the OS level */
@media (prefers-color-scheme: dark) {
/* defaults to dark theme */
body {
--text-color: 238,238,238;
--dialog-bg-color: #121212;
--bg-color-secondary: #262628;
--bg-color: 0,0,0;
--border-color: rgb(91, 91, 91);
--badge-color: #717171;
--shadow-color-secondary-rgb: 255,255,255;
--shadow-color-secondary-cover-rgb: 38,38,38;
--shadow-color-dialog-rgb: 255,255,255;
--shadow-color-dialog-cover-rgb: 38,38,38;
}
/* Override dark mode with light mode styles if the user decides to swap */
body.light-theme {
--text-color: 51,51,51;
--dialog-bg-color: #fff;
--bg-color: 255,255,255;
--bg-color-secondary: #f2f2f2;
--border-color: rgb(169, 169, 169);
--badge-color: #a5a5a5;
--shadow-color-secondary-rgb: 0,0,0;
--shadow-color-secondary-cover-rgb: 242,242,242;
--shadow-color-dialog-rgb: 0,0,0;
--shadow-color-dialog-cover-rgb: 242,242,242;
}
}
/* Colored Elements */
@ -819,26 +877,41 @@ body {
transition: background-color 0.5s ease;
}
/* Styles for users who prefer dark mode at the OS level */
@media (prefers-color-scheme: dark) {
x-dialog x-paper {
background-color: var(--dialog-bg-color);
}
/* defaults to dark theme */
body {
--text-color: 238,238,238;
--bg-color: 18,18,18; /*rgb code*/
--bg-color-secondary: #333;
--border-color: rgb(238,238,238);
--badge-color: #717171;
.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);
}
@supports (stop-color: color-mix(in srgb, blue 50%, black)) {
#primaryGradient .start-color {
stop-color: color-mix(in srgb, var(--primary-color) 80%, white);
}
}
/* Override dark mode with light mode styles if the user decides to swap */
body.light-theme {
--text-color: 51,51,51;
--bg-color: 250,250,250; /*rgb code*/
--bg-color-secondary: #e4e4e4;
--border-color: rgb(169, 169, 169);
--badge-color: #a5a5a5;
}
#primaryGradient .stop-color {
stop-color: var(--primary-color);
}
@ -894,3 +967,4 @@ See note here: https://developer.mozilla.org/en-US/docs/Web/CSS/user-select */
-webkit-user-select: text;
user-select: text;
}