Merge branch 'next' into translate

This commit is contained in:
schlagmichdoch 2023-12-11 20:10:38 +01:00
commit da56a7b6bc
60 changed files with 2586 additions and 1677 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 269 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 271 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 271 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

View file

@ -40,7 +40,7 @@
</head>
<body translate="no">
<header class="row-reverse opacity-0">
<header class="row-reverse wrap opacity-0">
<a href="#about" class="icon-button" data-i18n-key="header.about" data-i18n-attrs="title aria-label">
<svg class="icon">
<use xlink:href="#info-outline"></use>
@ -95,20 +95,49 @@
<use xlink:href="#public-room-icon"></use>
</svg>
</div>
<div id="cancel-paste-mode" class="btn" data-i18n-key="header.cancel-paste-mode" data-i18n-attrs="text" hidden></div>
<div id="expand" class="icon-button" data-i18n-key="header.expand" data-i18n-attrs="title" hidden>
<svg class="icon">
<use xlink:href="#caret"></use>
</svg>
</div>
</header>
<!-- Center -->
<div id="center" class="opacity-0">
<!-- Peers -->
<div class="x-peers-filler"></div>
<x-peers class="center"></x-peers>
<x-no-peers class="no-animation-on-load" data-i18n-key="instructions.no-peers" data-i18n-attrs="data-drop-bg">
<x-peers class="center grow"></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">
<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>
</x-no-peers>
<x-instructions data-i18n-key="instructions.x-instructions" data-i18n-attrs="desktop mobile data-drop-peer data-drop-bg">
<p id="paste-filename"></p>
</x-instructions>
<x-instructions class="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="row">
<div class="thumb center">
<div class="text-thumb row" hidden>
<svg>
<use xlink:href="#font"></use>
</svg>
<svg>
<use xlink:href="#i-cursor"></use>
</svg>
</div>
<div class="file-thumb" hidden>
<svg>
<use xlink:href="#file"></use>
</svg>
</div>
<div class="image-thumb" hidden></div>
</div>
<div class="share-descriptor column p1">
<span class="descriptor-item"></span>
<span class="descriptor-other" hidden></span>
</div>
</div>
<div class="center btn-row wrap">
<div class="cancel-btn btn btn-small btn-rounded btn-dark text-white" data-i18n-key="header.cancel-share-mode" data-i18n-attrs="text"></div>
<div class="edit-btn btn btn-small btn-rounded btn-dark text-white" data-i18n-key="header.edit-share-mode" data-i18n-attrs="text" hidden></div>
</div>
</div>
<div id="websocket-fallback" hidden>
<span data-i18n-key="footer.traffic" data-i18n-attrs="text"></span>
<span data-i18n-key="footer.routed" data-i18n-attrs="text"></span>
@ -130,18 +159,18 @@
<div class="known-as-wrapper">
<span data-i18n-key="footer.known-as" data-i18n-attrs="text"></span>
<div id="display-name" class="badge" data-i18n-key="footer.display-name" data-i18n-attrs="data-placeholder title" placeholder="Loading..." autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" contenteditable></div>
<svg id="edit-pen" class="icon">
<svg class="icon edit-pen">
<use xlink:href="#edit-pen-icon"></use>
</svg>
</div>
<div class="discovery-wrapper row">
<div class="discovery-wrapper panel border row">
<div class="row center">
<span data-i18n-key="footer.discovery" data-i18n-attrs="text"></span>
</div>
<div class="row center">
<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 class="row center wrap">
<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>
</div>
</div>
</div>
@ -150,8 +179,8 @@
<x-dialog id="language-select-dialog">
<x-background class="full center">
<x-paper shadow="2">
<div class="row center">
<h2 class="center" data-i18n-key="dialogs.language-selector-title" data-i18n-attrs="text"></h2>
<div class="row center p2">
<h2 class="dialog-title" data-i18n-key="dialogs.language-selector-title" data-i18n-attrs="text"></h2>
</div>
<div class="language-buttons">
<button class="btn fw" data-i18n-key="dialogs.system-language" data-i18n-attrs="text"></button>
@ -229,7 +258,7 @@
<span>(Japanese)</span>
</button>
</div>
<div class="center row-reverse button-row">
<div class="center row-reverse btn-row wrap">
<button class="btn btn-rounded btn-grey" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
@ -240,12 +269,12 @@
<form action="#">
<x-background class="full center text-center">
<x-paper shadow="2">
<div class="row center">
<h2 class="center" data-i18n-key="dialogs.pair-devices-title" data-i18n-attrs="text"></h2>
<div class="row center p2">
<h2 class="dialog-title" data-i18n-key="dialogs.pair-devices-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center">
<div class="row center p2">
<div class="column">
<div class="center key-qr-code" 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>
<p class="center text-center key-instructions">
<span class="font-subheading" data-i18n-key="dialogs.input-key-on-this-device" data-i18n-attrs="text"></span>
@ -259,7 +288,7 @@
<span data-i18n-key="dialogs.hr-or" data-i18n-attrs="text"></span>
</div>
</div>
<div class="row center">
<div class="row center p2">
<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>
@ -272,7 +301,7 @@
<p class="font-subheading center text-center" data-i18n-key="dialogs.enter-key-from-another-device" data-i18n-attrs="text"></p>
</div>
</div>
<div class="button-row row-reverse">
<div class="btn-row row-reverse wrap">
<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>
@ -285,8 +314,8 @@
<form action="#">
<x-background class="full center text-center">
<x-paper shadow="2">
<div class="row center">
<h2 class="center" data-i18n-key="dialogs.edit-paired-devices-title" data-i18n-attrs="text"></h2>
<div class="row center p2">
<h2 class="dialog-title" data-i18n-key="dialogs.edit-paired-devices-title" data-i18n-attrs="text"></h2>
</div>
<div class="paired-devices-wrapper" data-i18n-key="dialogs.paired-devices-wrapper" data-i18n-attrs="data-empty"></div>
<div class="font-subheading center">
@ -296,7 +325,7 @@
<span data-i18n-key="dialogs.auto-accept-instructions-2" data-i18n-attrs="text"></span>
</p>
</div>
<div class="center row-reverse button-row">
<div class="center row-reverse btn-row wrap">
<button class="btn btn-rounded btn-grey" type="button" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
@ -308,14 +337,12 @@
<form action="#">
<x-background class="full center text-center">
<x-paper shadow="2">
<div class="row center">
<div class="column">
<h2 class="center" data-i18n-key="dialogs.temporary-public-room-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center p2">
<h2 class="dialog-title" data-i18n-key="dialogs.temporary-public-room-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center">
<div class="row center p2">
<div class="column">
<div class="center key-qr-code" 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>
<p class="center text-center key-instructions">
<span class="font-subheading" data-i18n-key="dialogs.input-room-id-on-another-device" data-i18n-attrs="text"></span>
@ -329,7 +356,7 @@
<span data-i18n-key="dialogs.hr-or" data-i18n-attrs="text"></span>
</div>
</div>
<div class="row center">
<div class="row center p2">
<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>
@ -341,10 +368,12 @@
<p class="font-subheading center text-center" data-i18n-key="dialogs.enter-room-id-from-another-device" data-i18n-attrs="text"></p>
</div>
</div>
<div class="center row-reverse button-row">
<button class="btn btn-rounded btn-grey" type="submit" data-i18n-key="dialogs.join" data-i18n-attrs="text" disabled></button>
<div class="center row-reverse btn-row wrap">
<div class="row-reverse wrap grow-2">
<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 leave-room" type="button" data-i18n-key="dialogs.leave" data-i18n-attrs="text"></button>
</div>
<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>
@ -354,15 +383,13 @@
<x-dialog id="receive-request-dialog">
<x-background class="full center">
<x-paper shadow="2">
<div class="row center">
<div class="column">
<h2 class="center"></h2>
</div>
<div class="row center p2">
<h2 class="dialog-title"></h2>
</div>
<div class="row center p1">
<div class="row center p2">
<div class="column center file-description">
<div>
<span class="display-name badge badge-gradient"></span>
<span class="display-name badge"></span>
<span data-i18n-key="dialogs.would-like-to-share" data-i18n-attrs="text"></span>
</div>
<div class="row file-name">
@ -375,8 +402,8 @@
</div>
</div>
<div class="center file-preview"></div>
<div class="row-reverse center button-row">
<button id="accept-request" class="btn btn-rounded btn-grey" title="ENTER" data-i18n-key="dialogs.accept" data-i18n-attrs="text" autofocus></button>
<div class="row-reverse center btn-row wrap">
<button id="accept-request" class="btn btn-rounded btn-grey" title="ENTER" data-i18n-key="dialogs.accept" data-i18n-attrs="text" autofocus disabled></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>
@ -386,15 +413,13 @@
<x-dialog id="receive-file-dialog">
<x-background class="full center">
<x-paper shadow="2">
<div class="row center">
<div class="column">
<h2 class="center"></h2>
</div>
<div class="row center p2">
<h2 class="dialog-title"></h2>
</div>
<div class="row center p1">
<div class="row center p2">
<div class="column center file-description">
<div>
<span class="display-name badge badge-gradient"></span>
<span class="display-name badge"></span>
<span data-i18n-key="dialogs.has-sent" data-i18n-attrs="text"></span>
</div>
<div class="row file-name">
@ -407,9 +432,9 @@
</div>
</div>
<div class="center file-preview"></div>
<div class="row-reverse center button-row">
<div class="row-reverse center btn-row wrap">
<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 id="download-btn" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.download" data-i18n-attrs="text" autofocus disabled></button>
<button class="btn btn-rounded btn-grey" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
@ -420,25 +445,23 @@
<form action="#">
<x-background class="full center">
<x-paper shadow="2">
<div class="row center">
<div class="column">
<h2 class="center" data-i18n-key="dialogs.send-message-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center p2">
<h2 class="dialog-title" data-i18n-key="dialogs.send-message-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center p1 display-name-wrapper">
<div class="row center p2 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 badge-gradient"></span>
<span class="display-name badge"></span>
</div>
</div>
</div>
<div class="row p1">
<div class="row p2">
<div class="column fw">
<div id="text-input" 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>
<div class="button-row row-reverse">
<div class="btn-row row-reverse wrap">
<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>
@ -450,34 +473,71 @@
<x-dialog id="receive-text-dialog">
<x-background class="full center">
<x-paper shadow="2">
<div class="row center">
<h2 class="text-center" data-i18n-key="dialogs.receive-text-title" data-i18n-attrs="text"></h2>
<div class="row center p2">
<h2 class="dialog-title" class="text-center" data-i18n-key="dialogs.receive-text-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center p1 display-name-wrapper">
<div class="row center p2 display-name-wrapper">
<div class="text-center">
<span class="display-name badge badge-gradient"></span>
<span class="display-name badge"></span>
<span data-i18n-key="dialogs.has-sent" data-i18n-attrs="text"></span>
</div>
</div>
<div class="row center p1">
<div class="row center p2">
<div class="column fw">
<div id="text" class="textarea"></div>
</div>
</div>
<div class="row-reverse center button-row">
<div class="row-reverse center btn-row wrap">
<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>
</x-dialog>
<!-- Share Text Dialog -->
<x-dialog id="share-text-dialog">
<x-background class="full center">
<x-paper shadow="2">
<div class="row center p2">
<h2 class="dialog-title" data-i18n-key="dialogs.share-text-title" data-i18n-attrs="text"></h2>
</div>
<div class="row center p2 pb0">
<div class="column">
<div class="text-center">
<span data-i18n-key="dialogs.share-text-subtitle" data-i18n-attrs="text"></span>
</div>
</div>
</div>
<div class="row p2">
<div class="column fw">
<div class="fw textarea" role="textbox" data-i18n-key="dialogs.message" data-i18n-attrs="title placeholder" contenteditable></div>
</div>
</div>
<div class="row p2 center">
<span class="mx1" data-i18n-key="dialogs.share-text-checkbox" data-i18n-attrs="text"></span>
<label class="pointer switch mx1">
<input type="checkbox">
<div class="slider round"></div>
</label>
</div>
<div class="btn-row row-reverse wrap">
<button class="btn btn-rounded btn-grey" type="submit" title="CTRL/⌘ + ENTER" data-i18n-key="dialogs.approve" data-i18n-attrs="text" autofocus disabled></button>
</div>
</x-paper>
</x-background>
</x-dialog>
<!-- base64 Paste Dialog -->
<x-dialog id="base64-paste-dialog">
<x-background class="full center">
<x-paper shadow="2">
<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">
<div class="row center p2">
<h2 class="dialog-title"></h2>
</div>
<div class="row p2">
<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>
<div class="row-reverse center btn-row wrap">
<button class="btn btn-rounded btn-grey" data-i18n-key="dialogs.close" data-i18n-attrs="text" close></button>
</div>
</x-paper>
@ -485,7 +545,14 @@
</x-dialog>
<!-- Toast -->
<div class="toast-container full center">
<x-toast id="toast" class="row center" shadow="1"></x-toast>
<x-toast id="toast" shadow="1">
<span class="center text-center"></span>
<div class="icon-button" data-i18n-key="dialogs.close-toast" data-i18n-attrs="title">
<svg class="icon">
<use xlink:href="#close-icon"></use>
</svg>
</div>
</x-toast>
</div>
<!-- About Page -->
<x-about id="about" class="full center column">
@ -560,9 +627,9 @@
<symbol id="github">
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"></path>
</symbol>
<g id="notifications">
<symbol id="notifications">
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"></path>
</g>
</symbol>
<symbol id="homescreen">
<path fill="none" d="M0 0h24v24H0V0z"></path>
<path d="M18 1.01L8 1c-1.1 0-2 .9-2 2v3h2V5h10v14H8v-1H6v3c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM10 15h2V8H5v2h3.59L3 15.59 4.41 17 10 11.41z"></path>
@ -572,11 +639,13 @@
<path d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1.41 16.09V20h-2.67v-1.93c-1.71-.36-3.16-1.46-3.27-3.4h1.96c.1 1.05.82 1.87 2.65 1.87 1.96 0 2.4-.98 2.4-1.59 0-.83-.44-1.61-2.67-2.14-2.48-.6-4.18-1.62-4.18-3.67 0-1.72 1.39-2.84 3.11-3.21V4h2.67v1.95c1.86.45 2.79 1.86 2.85 3.39H14.3c-.05-1.11-.64-1.87-2.22-1.87-1.5 0-2.4.68-2.4 1.64 0 .84.65 1.39 2.67 1.91s4.18 1.39 4.18 3.91c-.01 1.83-1.38 2.83-3.12 3.16z"></path>
</symbol>
<symbol id="icon-theme-auto" viewBox="0 0 24 24">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-54 -54 620 620"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M448 256c0-106-86-192-192-192V448c106 0 192-86 192-192zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256z"></path></svg>
<symbol id="icon-theme-auto" viewBox="-54 -54 620 620">
<!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path d="M448 256c0-106-86-192-192-192V448c106 0 192-86 192-192zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256z"></path>
</symbol>
<symbol id="icon-theme-light" viewBox="0 0 24 24">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-54 -54 620 620"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M361.5 1.2c5 2.1 8.6 6.6 9.6 11.9L391 121l107.9 19.8c5.3 1 9.8 4.6 11.9 9.6s1.5 10.7-1.6 15.2L446.9 256l62.3 90.3c3.1 4.5 3.7 10.2 1.6 15.2s-6.6 8.6-11.9 9.6L391 391 371.1 498.9c-1 5.3-4.6 9.8-9.6 11.9s-10.7 1.5-15.2-1.6L256 446.9l-90.3 62.3c-4.5 3.1-10.2 3.7-15.2 1.6s-8.6-6.6-9.6-11.9L121 391 13.1 371.1c-5.3-1-9.8-4.6-11.9-9.6s-1.5-10.7 1.6-15.2L65.1 256 2.8 165.7c-3.1-4.5-3.7-10.2-1.6-15.2s6.6-8.6 11.9-9.6L121 121 140.9 13.1c1-5.3 4.6-9.8 9.6-11.9s10.7-1.5 15.2 1.6L256 65.1 346.3 2.8c4.5-3.1 10.2-3.7 15.2-1.6zM160 256a96 96 0 1 1 192 0 96 96 0 1 1 -192 0zm224 0a128 128 0 1 0 -256 0 128 128 0 1 0 256 0z"></path></svg>
<symbol id="icon-theme-light" viewBox="-54 -54 620 620">
<!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path d="M361.5 1.2c5 2.1 8.6 6.6 9.6 11.9L391 121l107.9 19.8c5.3 1 9.8 4.6 11.9 9.6s1.5 10.7-1.6 15.2L446.9 256l62.3 90.3c3.1 4.5 3.7 10.2 1.6 15.2s-6.6 8.6-11.9 9.6L391 391 371.1 498.9c-1 5.3-4.6 9.8-9.6 11.9s-10.7 1.5-15.2-1.6L256 446.9l-90.3 62.3c-4.5 3.1-10.2 3.7-15.2 1.6s-8.6-6.6-9.6-11.9L121 391 13.1 371.1c-5.3-1-9.8-4.6-11.9-9.6s-1.5-10.7 1.6-15.2L65.1 256 2.8 165.7c-3.1-4.5-3.7-10.2-1.6-15.2s6.6-8.6 11.9-9.6L121 121 140.9 13.1c1-5.3 4.6-9.8 9.6-11.9s10.7-1.5 15.2 1.6L256 65.1 346.3 2.8c4.5-3.1 10.2-3.7 15.2-1.6zM160 256a96 96 0 1 1 192 0 96 96 0 1 1 -192 0zm224 0a128 128 0 1 0 -256 0 128 128 0 1 0 256 0z"></path>
</symbol>
<symbol id="icon-theme-dark" viewBox="0 0 24 24">
<rect fill="none" height="24" width="24"></rect><path d="M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36c-0.98,1.37-2.58,2.26-4.4,2.26 c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path>
@ -603,6 +672,21 @@
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path d="M0 128C0 92.7 28.7 64 64 64H256h48 16H576c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H320 304 256 64c-35.3 0-64-28.7-64-64V128zm320 0V384H576V128H320zM178.3 175.9c-3.2-7.2-10.4-11.9-18.3-11.9s-15.1 4.7-18.3 11.9l-64 144c-4.5 10.1 .1 21.9 10.2 26.4s21.9-.1 26.4-10.2l8.9-20.1h73.6l8.9 20.1c4.5 10.1 16.3 14.6 26.4 10.2s14.6-16.3 10.2-26.4l-64-144zM160 233.2L179 276H141l19-42.8zM448 164c11 0 20 9 20 20v4h44 16c11 0 20 9 20 20s-9 20-20 20h-2l-1.6 4.5c-8.9 24.4-22.4 46.6-39.6 65.4c.9 .6 1.8 1.1 2.7 1.6l18.9 11.3c9.5 5.7 12.5 18 6.9 27.4s-18 12.5-27.4 6.9l-18.9-11.3c-4.5-2.7-8.8-5.5-13.1-8.5c-10.6 7.5-21.9 14-34 19.4l-3.6 1.6c-10.1 4.5-21.9-.1-26.4-10.2s.1-21.9 10.2-26.4l3.6-1.6c6.4-2.9 12.6-6.1 18.5-9.8l-12.2-12.2c-7.8-7.8-7.8-20.5 0-28.3s20.5-7.8 28.3 0l14.6 14.6 .5 .5c12.4-13.1 22.5-28.3 29.8-45H448 376c-11 0-20-9-20-20s9-20 20-20h52v-4c0-11 9-20 20-20z"></path>
</symbol>
<symbol id="i-cursor" viewBox="-180 0 640 512">
<!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.-->
<path d="M.1 29.3C-1.4 47 11.7 62.4 29.3 63.9l8 .7C70.5 67.3 96 95 96 128.3V224H64c-17.7 0-32 14.3-32 32s14.3 32 32 32H96v95.7c0 33.3-25.5 61-58.7 63.8l-8 .7C11.7 449.6-1.4 465 .1 482.7s16.9 30.7 34.5 29.2l8-.7c34.1-2.8 64.2-18.9 85.4-42.9c21.2 24 51.2 40.1 85.4 42.9l8 .7c17.6 1.5 33.1-11.6 34.5-29.2s-11.6-33.1-29.2-34.5l-8-.7C185.5 444.7 160 417 160 383.7V288h32c17.7 0 32-14.3 32-32s-14.3-32-32-32H160V128.3c0-33.3 25.5-61 58.7-63.8l8-.7c17.6-1.5 30.7-16.9 29.2-34.5S239-1.4 221.3 .1l-8 .7C179.2 3.6 149.2 19.7 128 43.7c-21.2-24-51.2-40-85.4-42.9l-8-.7C17-1.4 1.6 11.7 .1 29.3z"></path>
</symbol>
<symbol id="font" viewBox="-100 0 640 512">
<!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.-->
<path d="M254 52.8C249.3 40.3 237.3 32 224 32s-25.3 8.3-30 20.8L57.8 416H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32h-1.8l18-48H303.8l18 48H320c-17.7 0-32 14.3-32 32s14.3 32 32 32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32H390.2L254 52.8zM279.8 304H168.2L224 155.1 279.8 304z"></path>
</symbol>
<symbol id="file" viewBox="-130 0 650 530">
<!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.-->
<path d="M320 464c8.8 0 16-7.2 16-16V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320zM0 64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64z"></path>
</symbol>
<symbol id="caret" viewBox="0 0 320 512">
<!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path d="M137.4 374.6c12.5 12.5 32.8 12.5 45.3 0l128-128c9.2-9.2 11.9-22.9 6.9-34.9s-16.6-19.8-29.6-19.8L32 192c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9l128 128z"></path>
</symbol>
</svg>
<!-- Scripts -->

View file

@ -55,7 +55,7 @@
"click-to-show": "اضغط للعرض"
},
"header": {
"cancel-paste-mode": "تمّ",
"cancel-share-mode": "تمّ",
"theme-auto_title": "تكيٌف المظهر مع النظام",
"install_title": "تثبيت PairDrop",
"theme-dark_title": "إستخدام دائما المظهر المظلم",
@ -70,12 +70,12 @@
},
"instructions": {
"x-instructions_mobile": "انقر لإرسال الملفات أو انقر لفترة طويلة لإرسال رسالة",
"click-to-send": "انقر للإرسال",
"activate-paste-mode-and-other-files": "و{{count}} ملفات أخرى",
"tap-to-send": "انقر للإرسال",
"activate-paste-mode-base": "افتح PairDrop على الأجهزة الأخرى للإرسال",
"x-instructions-share-mode_desktop": "انقر للإرسال",
"activate-share-mode-and-other-files-plural": "و{{count}} ملفات أخرى",
"x-instructions-share-mode_mobile": "انقر للإرسال",
"activate-share-mode-base": "افتح PairDrop على الأجهزة الأخرى للإرسال",
"no-peers-subtitle": "قم بإقران الأجهزة أو ادخل إلى غرفة عامة لتتمكن من إكتشافها على الشبكات الأخرى",
"activate-paste-mode-shared-text": "النص المشترك",
"activate-share-mode-shared-text": "النص المشترك",
"x-instructions_desktop": "انقر لإرسال الملفات أو انقر بزر الماوس الأيمن لإرسال رسالة",
"no-peers-title": "افتح PairDrop على الأجهزة الأخرى لإرسال الملفات",
"x-instructions_data-drop-bg": "حرر لتحديد المستلم",
@ -84,7 +84,7 @@
},
"peer-ui": {
"processing": "مُعالجة …",
"click-to-send-paste-mode": "انقر للإرسال {{descriptor}}",
"click-to-send-share-mode": "انقر للإرسال {{descriptor}}",
"click-to-send": "انقر لإرسال الملفات أو انقر بزر الماوس الأيمن لإرسال رسالة",
"waiting": "يُرجى الإنتظار…",
"connection-hash": "للتحقق من أمان التشفير الشامل، قم بمقارنة رقم الأمان هذا على كلا الجهازين",

View file

@ -9,7 +9,7 @@
"theme-auto_title": "Systemstil verwenden",
"theme-dark_title": "Immer dunklen Stil verwenden",
"theme-light_title": "Immer hellen Stil verwenden",
"cancel-paste-mode": "Fertig",
"cancel-share-mode": "Fertig",
"language-selector_title": "Sprache Wählen",
"join-public-room_title": "Öffentlichen Raum temporär betreten"
},
@ -138,14 +138,14 @@
"no-peers-title": "Öffne PairDrop auf anderen Geräten, um Dateien zu senden",
"no-peers_data-drop-bg": "Hier ablegen, um Empfänger auszuwählen",
"no-peers-subtitle": "Kopple Geräte oder besuche einen öffentlichen Raum, damit du in anderen Netzwerken sichtbar bist",
"click-to-send": "Klicke zum Senden von",
"tap-to-send": "Tippe zum Senden von",
"x-instructions-share-mode_desktop": "Klicke zum Senden von",
"x-instructions-share-mode_mobile": "Tippe zum Senden von",
"x-instructions_data-drop-peer": "Hier ablegen, um an Peer zu senden",
"x-instructions_data-drop-bg": "Loslassen um Empfänger auszuwählen",
"x-instructions_mobile": "Tippe, um Dateien zu senden oder tippe lange, um Nachrichten zu senden",
"activate-paste-mode-base": "Öffne PairDrop auf anderen Geräten zum Senden von",
"activate-paste-mode-and-other-files": "und {{count}} anderen Dateien",
"activate-paste-mode-shared-text": "freigegebenem Text"
"activate-share-mode-base": "Öffne PairDrop auf anderen Geräten zum Senden von",
"activate-share-mode-and-other-files-plural": "und {{count}} anderen Dateien",
"activate-share-mode-shared-text": "freigegebenem Text"
},
"document-titles": {
"file-transfer-requested": "Dateiübertragung angefordert",
@ -159,7 +159,7 @@
"click-to-send": "Klicke, um Dateien zu senden oder benutze einen Rechtsklick, um eine Textnachricht zu senden",
"connection-hash": "Um die Ende-zu-Ende Verschlüsselung zu verifizieren, vergleiche die Sicherheitsnummer auf beiden Geräten",
"waiting": "Warte…",
"click-to-send-paste-mode": "Klicken um {{descriptor}} zu senden",
"click-to-send-share-mode": "Klicken um {{descriptor}} zu senden",
"transferring": "Übertragung läuft…",
"processing": "Bearbeitung läuft…",
"preparing": "Vorbereitung läuft…"

View file

@ -11,7 +11,8 @@
"pair-device_title": "Pair your devices permanently",
"edit-paired-devices_title": "Edit paired devices",
"join-public-room_title": "Join public room temporarily",
"cancel-paste-mode": "Done"
"cancel-share-mode": "Cancel",
"edit-share-mode": "Edit"
},
"instructions": {
"no-peers_data-drop-bg": "Release to select recipient",
@ -21,11 +22,14 @@
"x-instructions_mobile": "Tap to send files or long tap to send a message",
"x-instructions_data-drop-peer": "Release to send to peer",
"x-instructions_data-drop-bg": "Release to select recipient",
"click-to-send": "Click to send",
"tap-to-send": "Tap to send",
"activate-paste-mode-base": "Open PairDrop on other devices to send",
"activate-paste-mode-and-other-files": "and {{count}} other files",
"activate-paste-mode-shared-text": "shared text",
"x-instructions-share-mode_desktop": "Click to send {{descriptor}}",
"x-instructions-share-mode_mobile": "Tap to send {{descriptor}}",
"activate-share-mode-base": "Open PairDrop on other devices to send",
"activate-share-mode-and-other-file": "and 1 other file",
"activate-share-mode-and-other-files-plural": "and {{count}} other files",
"activate-share-mode-shared-text": "shared text",
"activate-share-mode-shared-file": "shared file",
"activate-share-mode-shared-files-plural": "{{count}} shared files",
"webrtc-requirement": "To use PairDrop on this instance, WebRTC must be enabled!"
},
"footer": {
@ -56,6 +60,7 @@
"cancel": "Cancel",
"edit-paired-devices-title": "Edit Paired Devices",
"unpair": "Unpair",
"paired-device-removed": "Paired device removed.",
"paired-devices-wrapper_data-empty": "No paired devices.",
"auto-accept-instructions-1": "Activate",
"auto-accept": "auto-accept",
@ -76,9 +81,11 @@
"send": "Send",
"receive-text-title": "Message Received",
"copy": "Copy",
"base64-title-files": "Share Files",
"base64-title-text": "Share Text",
"base64-processing": "Processing…",
"base64-tap-to-paste": "Tap here to paste {{type}}",
"base64-paste-to-send": "Paste here to send {{type}}",
"base64-tap-to-paste": "Tap here to share {{type}}",
"base64-paste-to-send": "Paste clipboard here to share {{type}}",
"base64-text": "text",
"base64-files": "files",
"file-other-description-image": "and 1 other image",
@ -94,7 +101,12 @@
"language-selector-title": "Set Language",
"system-language": "System Language",
"public-room-qr-code_title": "Click to copy link to public room",
"pair-devices-qr-code_title": "Click to copy link to pair this device"
"pair-devices-qr-code_title": "Click to copy link to pair this device",
"approve": "approve",
"share-text-title": "Share Text Message",
"share-text-subtitle": "Edit message before sending:",
"share-text-checkbox": "Always show this dialog when sharing text",
"close-toast_title": "Close notification"
},
"about": {
"close-about_aria-label": "Close About PairDrop",
@ -156,7 +168,7 @@
"message-received-plural": "{{count}} Messages Received"
},
"peer-ui": {
"click-to-send-paste-mode": "Click to send {{descriptor}}",
"click-to-send-share-mode": "Click to send {{descriptor}}",
"click-to-send": "Click to send files or right click to send a message",
"connection-hash": "To verify the security of the end-to-end encryption, compare this security number on both devices",
"preparing": "Preparing…",

View file

@ -4,7 +4,7 @@
"language-selector_title": "Configurar Idioma",
"about_title": "Sobre PairDrop",
"about_aria-label": "Abrir Sobre PairDrop",
"cancel-paste-mode": "Listo",
"cancel-share-mode": "Listo",
"install_title": "Instalar PairDrop",
"theme-dark_title": "Siempre usar tema oscuro",
"pair-device_title": "Empareja tus dispositivos permanentemente",
@ -73,12 +73,12 @@
},
"instructions": {
"x-instructions_mobile": "Toque para enviar archivos o toque prologádamente para enviar un mensaje",
"click-to-send": "Haga clic para enviar",
"activate-paste-mode-and-other-files": "y {{count}} archivos diferentes",
"tap-to-send": "Toca para enviar",
"activate-paste-mode-base": "Abra PairDrop en otros dispositivos para enviar",
"x-instructions-share-mode_desktop": "Haga clic para enviar",
"activate-share-mode-and-other-files-plural": "y {{count}} archivos diferentes",
"x-instructions-share-mode_mobile": "Toca para enviar",
"activate-share-mode-base": "Abra PairDrop en otros dispositivos para enviar",
"no-peers-subtitle": "Empareje dispositivos o ingrese a una sala pública para que lo puedan encontrar en otras redes",
"activate-paste-mode-shared-text": "texto compartido",
"activate-share-mode-shared-text": "texto compartido",
"x-instructions_desktop": "Haga clic para enviar archivos o haga clic derecho para enviar un mensaje",
"no-peers-title": "Abra PairDrop en otros dispositivos para enviar archivos",
"x-instructions_data-drop-peer": "Liberar para enviar a un par",
@ -87,7 +87,7 @@
},
"peer-ui": {
"processing": "Procesando…",
"click-to-send-paste-mode": "Haga clic para enviar {{descriptor}}",
"click-to-send-share-mode": "Haga clic para enviar {{descriptor}}",
"click-to-send": "Haga clic para enviar archivos o haga clic derecho para enviar un mensaje",
"waiting": "Esperando…",
"connection-hash": "Para verificar la seguridad del cifrado de extremo a extremo, compare este número de seguridad en ambos dispositivos",

View file

@ -11,7 +11,7 @@
"pair-device_title": "Associez vos appareils de manière permanente",
"edit-paired-devices_title": "Gérer les appareils couplés",
"join-public-room_title": "Rejoindre temporairement la salle publique",
"cancel-paste-mode": "Terminé"
"cancel-share-mode": "Terminé"
},
"instructions": {
"no-peers_data-drop-bg": "Déposer pour choisir le destinataire",
@ -21,11 +21,11 @@
"x-instructions_mobile": "Appuyez pour envoyer des fichiers ou appuyez longuement pour envoyer un message",
"x-instructions_data-drop-peer": "Déposer pour envoyer au destinataire",
"x-instructions_data-drop-bg": "Lâcher pour choisir le destinataire",
"click-to-send": "Cliquez pour envoyer",
"tap-to-send": "Appuyez pour envoyer",
"activate-paste-mode-base": "Ouvrez PairDrop sur d'autres appareils pour envoyer",
"activate-paste-mode-and-other-files": "et {{count}} autres fichiers",
"activate-paste-mode-shared-text": "texte partagé"
"x-instructions-share-mode_desktop": "Cliquez pour envoyer",
"x-instructions-share-mode_mobile": "Appuyez pour envoyer",
"activate-share-mode-base": "Ouvrez PairDrop sur d'autres appareils pour envoyer",
"activate-share-mode-and-other-files-plural": "et {{count}} autres fichiers",
"activate-share-mode-shared-text": "texte partagé"
},
"footer": {
"known-as": "Vous êtes connu comme :",
@ -149,7 +149,7 @@
"message-received-plural": "{{count}} Messages reçus"
},
"peer-ui": {
"click-to-send-paste-mode": "Cliquez pour envoyer {{descriptor}}",
"click-to-send-share-mode": "Cliquez pour envoyer {{descriptor}}",
"click-to-send": "Cliquez pour envoyer des fichiers ou faites un clic droit pour envoyer un message",
"connection-hash": "Pour vérifier la sécurité du chiffrement de bout en bout, comparez ce numéro de sécurité sur les deux appareils",
"preparing": "Préparation…",

View file

@ -58,7 +58,7 @@
"room-url-copied-to-clipboard": "Tautan ke ruang publik disalin ke papan klip"
},
"header": {
"cancel-paste-mode": "Selesai",
"cancel-share-mode": "Selesai",
"theme-auto_title": "Sesuaikan tema dengan sistem",
"install_title": "Instal PairDrop",
"theme-dark_title": "Selalu gunakan tema gelap",
@ -73,12 +73,12 @@
},
"instructions": {
"x-instructions_mobile": "Ketuk untuk mengirim file atau ketuk lama untuk mengirim pesan",
"click-to-send": "Klik untuk mengirim",
"activate-paste-mode-and-other-files": "dan {{count}} file lainnya",
"tap-to-send": "Ketuk untuk mengirim",
"activate-paste-mode-base": "Buka PairDrop di perangkat lain untuk berkirim",
"x-instructions-share-mode_desktop": "Klik untuk mengirim",
"activate-share-mode-and-other-files-plural": "dan {{count}} file lainnya",
"x-instructions-share-mode_mobile": "Ketuk untuk mengirim",
"activate-share-mode-base": "Buka PairDrop di perangkat lain untuk berkirim",
"no-peers-subtitle": "Pasangkan perangkat atau masuk ke ruang publik agar dapat terdeteksi di jaringan lain",
"activate-paste-mode-shared-text": "teks bersama",
"activate-share-mode-shared-text": "teks bersama",
"x-instructions_desktop": "Klik untuk mengirim file atau klik kanan untuk mengirim pesan",
"no-peers-title": "Buka PairDrop di perangkat lain untuk berkirim file",
"x-instructions_data-drop-peer": "Lepaskan untuk mengirim ke rekan",
@ -87,7 +87,7 @@
},
"peer-ui": {
"processing": "Memproses…",
"click-to-send-paste-mode": "Klik untuk mengirim {{descriptor}}",
"click-to-send-share-mode": "Klik untuk mengirim {{descriptor}}",
"click-to-send": "Klik untuk mengirim file atau klik kanan untuk mengirim pesan",
"waiting": "Menunggu…",
"connection-hash": "Untuk memverifikasi keamanan enkripsi end-to-end, bandingkan nomor keamanan ini pada kedua perangkat",

View file

@ -15,7 +15,7 @@
"known-as": "Sei visibile come:"
},
"header": {
"cancel-paste-mode": "Fatto",
"cancel-share-mode": "Fatto",
"theme-auto_title": "Adatta il tema al sistema automaticamente",
"install_title": "Installa PairDrop",
"theme-dark_title": "Usa sempre il tema scuro",
@ -30,12 +30,12 @@
},
"instructions": {
"x-instructions_mobile": "Tocca per inviare file o tocco prolungato per inviare un messaggio",
"click-to-send": "Clicca per inviare",
"activate-paste-mode-and-other-files": "e altri {{count}} files",
"tap-to-send": "Tocca per inviare",
"activate-paste-mode-base": "Apri PairDrop su altri dispositivi per inviare",
"x-instructions-share-mode_desktop": "Clicca per inviare",
"activate-share-mode-and-other-files-plural": "e altri {{count}} files",
"x-instructions-share-mode_mobile": "Tocca per inviare",
"activate-share-mode-base": "Apri PairDrop su altri dispositivi per inviare",
"no-peers-subtitle": "Abbina dispositivi o entra in una stanza pubblica per essere rilevabile su altre reti",
"activate-paste-mode-shared-text": "testo condiviso",
"activate-share-mode-shared-text": "testo condiviso",
"x-instructions_desktop": "Clicca per inviare files o usa il tasto destro per inviare un messaggio",
"no-peers-title": "Apri PairDrop su altri dispositivi per inviare files",
"x-instructions_data-drop-peer": "Rilascia per inviare al peer",
@ -139,7 +139,7 @@
},
"peer-ui": {
"processing": "Elaborazione…",
"click-to-send-paste-mode": "Clicca per inviare {{descriptor}}",
"click-to-send-share-mode": "Clicca per inviare {{descriptor}}",
"click-to-send": "Clicca per inviare files o tasto destro per inviare un messaggio",
"waiting": "In attesa…",
"connection-hash": "Per verificare la sicurezza della crittografia end-to-end, confronta questo numero di sicurezza su entrambi i dispositivi",

View file

@ -58,7 +58,7 @@
"room-url-copied-to-clipboard": "パブリックルームへのリンクをクリップボードにコピーしました"
},
"header": {
"cancel-paste-mode": "完了",
"cancel-share-mode": "完了",
"theme-auto_title": "テーマをシステムの設定に自動的に合わせる",
"install_title": "PairDropをインストール",
"theme-dark_title": "常にダークテーマを使用する",
@ -73,12 +73,12 @@
},
"instructions": {
"x-instructions_mobile": "タップしてファイルを送信または長押ししてメッセージを送信します",
"click-to-send": "クリックして送信",
"activate-paste-mode-and-other-files": "とその他{{count}}個のファイル",
"tap-to-send": "タップして送信",
"activate-paste-mode-base": "他のデバイスでPairDropを開いて送信します",
"x-instructions-share-mode_desktop": "クリックして送信",
"activate-share-mode-and-other-files-plural": "とその他{{count}}個のファイル",
"x-instructions-share-mode_mobile": "タップして送信",
"activate-share-mode-base": "他のデバイスでPairDropを開いて送信します",
"no-peers-subtitle": "デバイスをペア設定するかパブリックルームに参加すると、他のネットワーク上からも見つけられるようになります",
"activate-paste-mode-shared-text": "共有されたテキスト",
"activate-share-mode-shared-text": "共有されたテキスト",
"x-instructions_desktop": "左クリックしてファイルを送信または右クリックしてメッセージを送信します",
"no-peers-title": "他のデバイスでPairDropを開いてファイルを送信します",
"x-instructions_data-drop-peer": "離すとこの相手に送信します",
@ -87,7 +87,7 @@
},
"peer-ui": {
"processing": "処理中…",
"click-to-send-paste-mode": "クリックして{{descriptor}}を送信",
"click-to-send-share-mode": "クリックして{{descriptor}}を送信",
"click-to-send": "クリックしてファイルを送信または右クリックしてメッセージを送信します",
"waiting": "待機中…",
"connection-hash": "エンドツーエンド暗号化のセキュリティを確認するには、両方のデバイスのセキュリティナンバーを確認します",

View file

@ -7,7 +7,7 @@
"theme-light_title": "Alltid bruk lys drakt",
"theme-dark_title": "Alltid bruk mørk drakt",
"notification_title": "Skru på merknader",
"cancel-paste-mode": "Ferdig",
"cancel-share-mode": "Ferdig",
"install_title": "Installer PairDrop",
"pair-device_title": "Sammenkoble enhet"
},
@ -25,15 +25,15 @@
"x-instructions_desktop": "Klikk for å sende filer, eller høyreklikk for å sende en melding",
"x-instructions_mobile": "Trykk for å sende filer, eller lang-trykk for å sende en melding",
"x-instructions_data-drop-bg": "Slipp for å velge mottager",
"click-to-send": "Klikk for å sende",
"x-instructions-share-mode_desktop": "Klikk for å sende",
"no-peers_data-drop-bg": "Slipp for å velge mottager",
"no-peers-title": "Åpne PairDrop på andre enheter for å sende filer",
"no-peers-subtitle": "Sammenkoble enheter for å kunne oppdages på andre nettverk",
"x-instructions_data-drop-peer": "Slipp for å sende til likemann",
"tap-to-send": "Trykk for å sende",
"activate-paste-mode-base": "Åpne PairDrop på andre enheter for å sende",
"activate-paste-mode-and-other-files": "og {{count}} andre filer",
"activate-paste-mode-shared-text": "delt tekst"
"x-instructions-share-mode_mobile": "Trykk for å sende",
"activate-share-mode-base": "Åpne PairDrop på andre enheter for å sende",
"activate-share-mode-and-other-files-plural": "og {{count}} andre filer",
"activate-share-mode-shared-text": "delt tekst"
},
"dialogs": {
"input-key-on-this-device": "Skriv inn denne nøkkelen på en annen enhet",
@ -132,7 +132,7 @@
"processing": "Behandler …",
"transferring": "Overfører …",
"click-to-send": "Klikk for å sende filer, eller høyreklikk for å sende en melding",
"click-to-send-paste-mode": "Klikk for å sende {{descriptor}}",
"click-to-send-share-mode": "Klikk for å sende {{descriptor}}",
"connection-hash": "Sammenlign dette sikkerhetsnummeret på begge enhetene for å bekrefte ende-til-ende -krypteringen."
}
}

View file

@ -55,7 +55,7 @@
"click-to-show": "Klik om te tonen"
},
"header": {
"cancel-paste-mode": "Klaar",
"cancel-share-mode": "Klaar",
"theme-auto_title": "Gebruik systeemstijl",
"install_title": "PairDrop installeren",
"theme-dark_title": "Altijd donkere modus gebruiken",
@ -70,12 +70,12 @@
},
"instructions": {
"x-instructions_mobile": "Tik om bestanden te versturen of houdt vast om een bericht te sturen",
"click-to-send": "Klik om te verzenden",
"activate-paste-mode-and-other-files": "en {{count}} andere bestanden",
"tap-to-send": "Tik om te verzenden",
"activate-paste-mode-base": "Open PairDrop op andere apparaten om te verzenden",
"x-instructions-share-mode_desktop": "Klik om te verzenden",
"activate-share-mode-and-other-files-plural": "en {{count}} andere bestanden",
"x-instructions-share-mode_mobile": "Tik om te verzenden",
"activate-share-mode-base": "Open PairDrop op andere apparaten om te verzenden",
"no-peers-subtitle": "Koppel apparaten of betreed een openbare ruimte om op andere netwerken zichtbaar te worden",
"activate-paste-mode-shared-text": "gedeelde tekst",
"activate-share-mode-shared-text": "gedeelde tekst",
"x-instructions_desktop": "Klik om bestanden te versturen of rechtsklik om een bericht te sturen",
"no-peers-title": "Open PairDrop op andere apparaten om bestanden te versturen",
"x-instructions_data-drop-peer": "Laat los om naar peer te versturen",
@ -84,7 +84,7 @@
},
"peer-ui": {
"processing": "Verwerken…",
"click-to-send-paste-mode": "Klik om {{descriptor}} te versturen",
"click-to-send-share-mode": "Klik om {{descriptor}} te versturen",
"click-to-send": "Klik om bestanden te versturen of rechtsklik om een bericht te versturen",
"waiting": "Wachten…",
"connection-hash": "Vergelijk dit veiligheidsnummer op beide apparaten, om de beveiliging van de eind-tot-eind versleuteling te verifiëren",

View file

@ -58,7 +58,7 @@
"room-url-copied-to-clipboard": "Link către sala publică copiat în clipboard"
},
"header": {
"cancel-paste-mode": "Gata",
"cancel-share-mode": "Gata",
"theme-auto_title": "Adaptează tema la sistem",
"install_title": "Instalează PairDrop",
"theme-dark_title": "Utilizați mereu tema întunecoasă",
@ -73,12 +73,12 @@
},
"instructions": {
"x-instructions_mobile": "Atingeți pentru a trimite fișiere sau atingeți lung pentru a trimite un mesaj",
"click-to-send": "Clic pentru a trimite",
"activate-paste-mode-and-other-files": "și {{count}} alte fișiere",
"tap-to-send": "Atinge pentru a trimite",
"activate-paste-mode-base": "Deschideți PairDrop pe alte dispozitive pentru a trimite",
"x-instructions-share-mode_desktop": "Clic pentru a trimite",
"activate-share-mode-and-other-files-plural": "și {{count}} alte fișiere",
"x-instructions-share-mode_mobile": "Atinge pentru a trimite",
"activate-share-mode-base": "Deschideți PairDrop pe alte dispozitive pentru a trimite",
"no-peers-subtitle": "Împerecheați dispozitive sau intrați într-o cameră publică pentru a fi descoperit în alte rețele",
"activate-paste-mode-shared-text": "text partajat",
"activate-share-mode-shared-text": "text partajat",
"x-instructions_desktop": "Dați clic pentru a trimite fișiere sau dați clic dreapta pentru a trimite un mesaj",
"no-peers-title": "Deschideți PairDrop pe alte dispozitive pentru a trimite fișiere",
"x-instructions_data-drop-peer": "Eliberare pentru a trimite la peer",
@ -87,7 +87,7 @@
},
"peer-ui": {
"processing": "Procesarea…",
"click-to-send-paste-mode": "Apasă pentru a trimite {{descriptor}}",
"click-to-send-share-mode": "Apasă pentru a trimite {{descriptor}}",
"click-to-send": "Apasă pentru a trimite fișiere sau apasă cu butonul din dreapta pentru a trimite un mesaj",
"waiting": "Așteptând…",
"connection-hash": "Pentru a verifica securitatea criptării end-to-end, comparați acest număr de securitate pe ambele dispozitive",

View file

@ -3,7 +3,7 @@
"about_aria-label": "Открыть страницу \"О сервисе\"",
"pair-device_title": "Связать ваши устройства навсегда",
"install_title": "Установить PairDrop",
"cancel-paste-mode": "Выполнено",
"cancel-share-mode": "Выполнено",
"edit-paired-devices_title": "Редактировать связанные устройства",
"notification_title": "Включить уведомления",
"about_title": "О сервисе",
@ -16,16 +16,16 @@
"instructions": {
"x-instructions_desktop": "Нажмите, чтобы отправить файлы, или щелкните правой кнопкой мыши, чтобы отправить сообщение",
"no-peers_data-drop-bg": "Отпустите, чтобы выбрать получателя",
"click-to-send": "Нажмите, чтобы отправить",
"x-instructions-share-mode_desktop": "Нажмите, чтобы отправить",
"x-instructions_data-drop-bg": "Отпустите, чтобы выбрать получателя",
"tap-to-send": "Прикоснитесь, чтобы отправить",
"x-instructions-share-mode_mobile": "Прикоснитесь, чтобы отправить",
"x-instructions_data-drop-peer": "Отпустите, чтобы послать узлу",
"x-instructions_mobile": "Прикоснитесь коротко, чтобы отправить файлы, или долго, чтобы отправить сообщение",
"no-peers-title": "Откройте PairDrop на других устройствах, чтобы отправить файлы",
"no-peers-subtitle": "Свяжите устройства или войдите в публичную комнату, чтобы вас могли обнаружить из других сетей",
"activate-paste-mode-and-other-files": "и {{count}} других файлов",
"activate-paste-mode-base": "Откройте PairDrop на других устройствах, чтобы отправить",
"activate-paste-mode-shared-text": "общий текст"
"activate-share-mode-and-other-files-plural": "и {{count}} других файлов",
"activate-share-mode-base": "Откройте PairDrop на других устройствах, чтобы отправить",
"activate-share-mode-shared-text": "общий текст"
},
"footer": {
"display-name_data-placeholder": "Загрузка…",
@ -148,7 +148,7 @@
"room-url-copied-to-clipboard": "Ссылка на публичную комнату была скопирована в буфер обмена"
},
"peer-ui": {
"click-to-send-paste-mode": "Нажмите, чтобы отправить {{descriptor}}",
"click-to-send-share-mode": "Нажмите, чтобы отправить {{descriptor}}",
"preparing": "Подготовка…",
"transferring": "Передача…",
"processing": "Обработка…",

View file

@ -9,19 +9,19 @@
"install_title": "PairDrop'u Yükle",
"pair-device_title": "Cihazı kalıcı olarak eşle",
"edit-paired-devices_title": "Eşleştirilmiş cihazları düzenle",
"cancel-paste-mode": "Bitti",
"cancel-share-mode": "Bitti",
"join-public-room_title": "Geçici olarak genel odaya katılın",
"language-selector_title": "Dili Seç"
},
"instructions": {
"no-peers_data-drop-bg": "Alıcıyı seçmek için bırakın",
"x-instructions_mobile": "Dosya göndermek için dokun veya mesaj göndermek için uzun dokun",
"click-to-send": "Göndermek için tıkla",
"activate-paste-mode-and-other-files": "ve {{count}} diğer dosya",
"tap-to-send": "Göndermek için dokun",
"activate-paste-mode-base": "Göndermek için diğer cihazlarda PairDrop'u açın",
"x-instructions-share-mode_desktop": "Göndermek için tıkla",
"activate-share-mode-and-other-files-plural": "ve {{count}} diğer dosya",
"x-instructions-share-mode_mobile": "Göndermek için dokun",
"activate-share-mode-base": "Göndermek için diğer cihazlarda PairDrop'u açın",
"no-peers-subtitle": "Diğer ağlarda keşfedilebilir olmak için cihazları eşleştirin veya ortak bir odaya girin",
"activate-paste-mode-shared-text": "paylaşılan metin",
"activate-share-mode-shared-text": "paylaşılan metin",
"x-instructions_desktop": "Dosya göndermek için tıkla ya da mesaj göndermek için sağ tıkla",
"no-peers-title": "Dosya göndermek için diğer cihazlarda PairDrop'u açın",
"x-instructions_data-drop-peer": "Göndermek için serbest bırak",
@ -139,7 +139,7 @@
},
"peer-ui": {
"processing": "İşleniyor…",
"click-to-send-paste-mode": "{{descriptor}} göndermek için tıkla",
"click-to-send-share-mode": "{{descriptor}} göndermek için tıkla",
"click-to-send": "Dosya göndermek için tıkla veya mesaj göndermek için sağ tıkla",
"waiting": "Bekleniyor…",
"connection-hash": "Uçtan uca şifrelemenin güvenliğini doğrulamak için her iki cihazda da bu güvenlik numarasını karşılaştırın",

View file

@ -9,7 +9,7 @@
"theme-dark_title": "总是使用暗黑主题",
"notification_title": "开启通知",
"edit-paired-devices_title": "管理已配对设备",
"cancel-paste-mode": "完成",
"cancel-share-mode": "完成",
"join-public-room_title": "暂时加入公共房间",
"language-selector_title": "设置语言"
},
@ -21,11 +21,11 @@
"x-instructions_desktop": "点击以发送文件 或 右键来发送信息",
"x-instructions_mobile": "轻触以发送文件 或 长按来发送信息",
"x-instructions_data-drop-bg": "释放来选择接收者",
"click-to-send": "点击发送",
"tap-to-send": "轻触发送",
"activate-paste-mode-base": "在其他设备上打开 PairDrop 来发送",
"activate-paste-mode-and-other-files": "和 {{count}} 个其他的文件",
"activate-paste-mode-shared-text": "分享文本"
"x-instructions-share-mode_desktop": "点击发送",
"x-instructions-share-mode_mobile": "轻触发送",
"activate-share-mode-base": "在其他设备上打开 PairDrop 来发送",
"activate-share-mode-and-other-files-plural": "和 {{count}} 个其他的文件",
"activate-share-mode-shared-text": "分享文本"
},
"footer": {
"routed": "途径服务器",
@ -155,7 +155,7 @@
"image-transfer-requested": "图片传输请求"
},
"peer-ui": {
"click-to-send-paste-mode": "点击发送 {{descriptor}}",
"click-to-send-share-mode": "点击发送 {{descriptor}}",
"click-to-send": "点击以发送文件 或 右键来发送信息",
"connection-hash": "若要验证端到端加密的安全性,请在两个设备上比较此安全编号",
"preparing": "准备中…",

View file

@ -65,6 +65,11 @@
"src": "images/pairdrop_screenshot_mobile_7.png",
"sizes": "1170x2532",
"type": "image/png"
},
{
"src": "images/pairdrop_screenshot_mobile_8.png",
"sizes": "1170x2532",
"type": "image/png"
}
],
"share_target": {
@ -81,201 +86,6 @@
}]
}
},
"file_handlers": [
{
"action": "/?file_handler",
"name": "All Files",
"accept": {
"application/cpl+xml": [".cpl"],
"application/gpx+xml": [".gpx"],
"application/gzip": [".gz"],
"application/java-archive": [".jar", ".war", ".ear"],
"application/java-vm": [".class"],
"application/javascript": [".js", ".mjs"],
"application/json": [".json", ".map"],
"application/manifest+json": [".webmanifest"],
"application/msword": [".doc", ".dot", ".wiz"],
"application/octet-stream": [".bin", ".dms", ".lrf", ".mar", ".so", ".dist", ".distz", ".pkg", ".bpk", ".dump", ".elc", ".deploy", ".exe", ".dll", ".deb", ".dmg", ".iso", ".img", ".msi", ".msp", ".msm", ".buffer"],
"application/oda": [".oda"],
"application/oxps": [".oxps"],
"application/pdf": [".pdf"],
"application/pgp-signature": [".asc", ".sig"],
"application/pics-rules": [".prf"],
"application/pkcs7-mime": [".p7c"],
"application/pkix-cert": [".cer"],
"application/postscript": [".ai", ".eps", ".ps"],
"application/rtf": [".rtf"],
"application/vnd.android.package-archive": [".apk"],
"application/vnd.apple.mpegurl": [".m3u", ".m3u8"],
"application/vnd.apple.pkpass": [".pkpass"],
"application/vnd.google-earth.kml+xml": [".kml"],
"application/vnd.google-earth.kmz": [".kmz"],
"application/vnd.ms-cab-compressed": [".cab"],
"application/vnd.ms-excel": [".xls", ".xlm", ".xla", ".xlc", ".xlt", ".xlw"],
"application/vnd.ms-outlook": [".msg"],
"application/vnd.ms-powerpoint": [".ppt", ".pot", ".ppa", ".pps", ".pwz"],
"application/vnd.ms-project": [".mpp", ".mpt"],
"application/vnd.ms-xpsdocument": [".xps"],
"application/vnd.oasis.opendocument.database": [".odb"],
"application/vnd.oasis.opendocument.spreadsheet": [".ods"],
"application/vnd.oasis.opendocument.text": [".odt"],
"application/vnd.openstreetmap.data+xml": [".osm"],
"application/vnd.openxmlformats-officedocument.presentationml.presentation": [".pptx"],
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [".xlsx"],
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": [".docx"],
"application/vnd.tcpdump.pcap": [".pcap", ".cap", ".dmp"],
"application/vnd.wordperfect": [".wpd"],
"application/wasm": [".wasm"],
"application/x-7z-compressed": [".7z"],
"application/x-apple-diskimage": [".dmg"],
"application/x-bcpio": [".bcpio"],
"application/x-bittorrent": [".torrent"],
"application/x-cbr": [".cbr", ".cba", ".cbt", ".cbz", ".cb7"],
"application/x-cdlink": [".vcd"],
"application/x-chrome-extension": [".crx"],
"application/x-cpio": [".cpio"],
"application/x-csh": [".csh"],
"application/x-debian-package": [".deb", ".udeb"],
"application/x-dvi": [".dvi"],
"application/x-freearc": [".arc"],
"application/x-gtar": [".gtar"],
"application/x-hdf": [".hdf"],
"application/x-hdf5": [".h5"],
"application/x-httpd-php": [".php"],
"application/x-iso9660-image": [".iso"],
"application/x-iwork-keynote-sffkey": [".key"],
"application/x-iwork-numbers-sffnumbers": [".numbers"],
"application/x-iwork-pages-sffpages": [".pages"],
"application/x-latex": [".latex"],
"application/x-makeself": [".run"],
"application/x-mif": [".mif"],
"application/x-ms-shortcut": [".lnk"],
"application/x-msaccess": [".mdb"],
"application/x-msdownload": [".exe", ".dll", ".com", ".bat", ".msi"],
"application/x-mspublisher": [".pub"],
"application/x-netcdf": [".cdf", ".nc"],
"application/x-perl": [".pl", ".pm"],
"application/x-pilot": [".prc", ".pdb"],
"application/x-pkcs12": [".p12", ".pfx"],
"application/x-pn-realaudio": [".ram"],
"application/x-python-code": [".pyc", ".pyo"],
"application/x-rar-compressed": [".rar"],
"application/x-redhat-package-manager": [".rpm"],
"application/x-sh": [".sh"],
"application/x-shar": [".shar"],
"application/x-shockwave-flash": [".swf"],
"application/x-sql": [".sql"],
"application/x-subrip": [".srt"],
"application/x-sv4cpio": [".sv4cpio"],
"application/x-sv4crc": [".sv4crc"],
"application/x-tads": [".gam"],
"application/x-tar": [".tar"],
"application/x-tcl": [".tcl"],
"application/x-tex": [".tex"],
"application/x-troff": [".roff", ".t", ".tr"],
"application/x-troff-man": [".man"],
"application/x-troff-me": [".me"],
"application/x-troff-ms": [".ms"],
"application/x-ustar": [".ustar"],
"application/x-wais-source": [".src"],
"application/x-xpinstall": [".xpi"],
"application/xhtml+xml": [".xhtml", ".xht"],
"application/xml": [".xsl", ".rdf", ".wsdl", ".xpdl"],
"application/zip": [".zip"],
"audio/3gpp": [".3gp", ".3gpp"],
"audio/3gpp2": [".3g2", ".3gpp2"],
"audio/aac": [".aac", ".adts", ".loas", ".ass"],
"audio/basic": [".au", ".snd"],
"audio/midi": [".mid", ".midi", ".kar", ".rmi"],
"audio/mpeg": [".mpga", ".mp2", ".mp2a", ".mp3", ".m2a", ".m3a"],
"audio/ogg": [".oga", ".ogg", ".spx", ".opus"],
"audio/opus": [".opus"],
"audio/x-aiff": [".aif", ".aifc", ".aiff"],
"audio/x-flac": [".flac"],
"audio/x-m4a": [".m4a"],
"audio/x-mpegurl": [".m3u"],
"audio/x-ms-wma": [".wma"],
"audio/x-pn-realaudio": [".ra"],
"audio/x-wav": [".wav"],
"font/otf": [".otf"],
"font/ttf": [".ttf"],
"font/woff": [".woff"],
"font/woff2": [".woff2"],
"image/emf": [".emf"],
"image/gif": [".gif"],
"image/heic": [".heic"],
"image/heif": [".heif"],
"image/ief": [".ief"],
"image/jpeg": [".jpeg", ".jpg"],
"image/jpg": [".jpg"],
"image/pict": [".pict", ".pct", ".pic"],
"image/png": [".png"],
"image/svg+xml": [".svg", ".svgz"],
"image/tiff": [".tif", ".tiff"],
"image/vnd.adobe.photoshop": [".psd"],
"image/vnd.djvu": [".djvu", ".djv"],
"image/vnd.dwg": [".dwg"],
"image/vnd.dxf": [".dxf"],
"image/vnd.microsoft.icon": [".ico"],
"image/vnd.ms-dds": [".dds"],
"image/x-3ds": [".3ds"],
"image/x-cmu-raster": [".ras"],
"image/x-icon": [".ico"],
"image/x-ms-bmp": [".bmp"],
"image/x-portable-anymap": [".pnm"],
"image/x-portable-bitmap": [".pbm"],
"image/x-portable-graymap": [".pgm"],
"image/x-portable-pixmap": [".ppm"],
"image/x-rgb": [".rgb"],
"image/x-tga": [".tga"],
"image/x-xbitmap": [".xbm"],
"image/x-xpixmap": [".xpm"],
"image/x-xwindowdump": [".xwd"],
"message/rfc822": [".eml", ".mht", ".mhtml", ".nws"],
"model/obj": [".obj"],
"model/stl": [".stl"],
"model/vnd.collada+xml": [".dae"],
"text/calendar": [".ics", ".ifb"],
"text/css": [".css"],
"text/csv": [".csv"],
"text/html": [".html", ".htm", ".shtml"],
"text/markdown": [".markdown", ".md"],
"text/plain": [".txt", ".text", ".conf", ".def", ".list", ".log", ".in", ".ini"],
"text/richtext": [".rtx"],
"text/rtf": [".rtf"],
"text/tab-separated-values": [".tsv"],
"text/x-c": [".c", ".cc", ".cxx", ".cpp", ".h", ".hh", ".dic"],
"text/x-java-source": [".java"],
"text/x-lua": [".lua"],
"text/x-python": [".py"],
"text/x-setext": [".etx"],
"text/x-sgml": [".sgm", ".sgml"],
"text/x-vcard": [".vcf"],
"text/xml": [".xml"],
"text/xul": [".xul"],
"text/yaml": [".yaml", ".yml"],
"video/3gpp": [".3gp", ".3gpp"],
"video/mp2t": [".ts"],
"video/mp4": [".mp4", ".mp4v", ".mpg4"],
"video/mpeg": [".mpeg", ".m1v", ".mpa", ".mpe", ".mpg"],
"video/quicktime": [".mov", ".qt"],
"video/webm": [".webm"],
"video/x-flv": [".flv"],
"video/x-m4v": [".m4v"],
"video/x-ms-asf": [".asf", ".asx"],
"video/x-ms-vob": [".vob"],
"video/x-ms-wmv": [".wmv"],
"video/x-msvideo": [".avi"],
"video/x-sgi-movie": [".*"]
},
"icons": [
{
"src": "/images/android-chrome-192x192.png",
"sizes": "192x192"
}
]
}
],
"launch_handler": {
"client_mode": "focus-existing"
}

View file

@ -19,42 +19,42 @@ class BrowserTabsConnector {
}
static peerIsSameBrowser(peerId) {
let peerIdsBrowser = JSON.parse(localStorage.getItem("peer_ids_browser"));
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");
const peerId = sessionStorage.getItem('peer_id');
if (!peerId) return false;
let peerIdsBrowser = [];
let peerIdsBrowserOld = JSON.parse(localStorage.getItem("peer_ids_browser"));
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));
localStorage.setItem('peer_ids_browser', JSON.stringify(peerIdsBrowser));
return peerIdsBrowser;
}
static async removePeerIdFromLocalStorage(peerId) {
let peerIdsBrowser = JSON.parse(localStorage.getItem("peer_ids_browser"));
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));
localStorage.setItem('peer_ids_browser', JSON.stringify(peerIdsBrowser));
return peerId;
}
static async removeOtherPeerIdsFromLocalStorage() {
const peerId = sessionStorage.getItem("peer_id");
const peerId = sessionStorage.getItem('peer_id');
if (!peerId) return false;
let peerIdsBrowser = [peerId];
localStorage.setItem("peer_ids_browser", JSON.stringify(peerIdsBrowser));
localStorage.setItem('peer_ids_browser', JSON.stringify(peerIdsBrowser));
return peerIdsBrowser;
}
}

1
public/scripts/heic2any.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -2,33 +2,30 @@ class Localization {
constructor() {
Localization.defaultLocale = "en";
Localization.supportedLocales = ["ar", "de", "en", "es", "fr", "id", "it", "ja", "nb", "nl", "ro", "ru", "tr", "zh-CN","pt-BR"];
Localization.supportedLocalesRTL = ["ar"];
Localization.supportedLocalesRtl = ["ar"];
Localization.translations = {};
Localization.defaultTranslations = {};
Localization.systemLocale = Localization.getSupportedOrDefault(navigator.languages);
let storedLanguageCode = localStorage.getItem("language-code");
let storedLanguageCode = localStorage.getItem('language_code');
Localization.initialLocale = storedLanguageCode && Localization.isSupported(storedLanguageCode)
? storedLanguageCode
: Localization.systemLocale;
Localization
.setTranslation(Localization.initialLocale)
.then(_ => {
console.log("Initial translation successful.");
Events.fire("initial-translation-loaded");
});
}
static isSupported(locale) {
return Localization.supportedLocales.indexOf(locale) > -1;
}
static isRTLLanguage(locale) {
return Localization.supportedLocalesRTL.indexOf(locale) > -1;
static isRtlLanguage(locale) {
return Localization.supportedLocalesRtl.indexOf(locale) > -1;
}
static isCurrentLocaleRtl() {
return Localization.isRtlLanguage(Localization.locale);
}
static getSupportedOrDefault(locales) {
@ -41,6 +38,10 @@ class Localization {
|| Localization.defaultLocale;
}
async setInitialTranslation() {
await Localization.setTranslation(Localization.initialLocale)
}
static async setTranslation(locale) {
if (!locale) locale = Localization.systemLocale;
@ -49,7 +50,7 @@ class Localization {
const htmlRootNode = document.querySelector('html');
if (Localization.isRTLLanguage(locale)) {
if (Localization.isRtlLanguage(locale)) {
htmlRootNode.setAttribute('dir', 'rtl');
}
else {
@ -85,7 +86,7 @@ class Localization {
}
static isSystemLocale() {
return !localStorage.getItem('language-code');
return !localStorage.getItem('language_code');
}
static async fetchTranslationsFor(newLocale) {
@ -121,7 +122,7 @@ class Localization {
}
}
static getTranslation(key, attr=null, data={}, useDefault=false) {
static getTranslation(key, attr = null, data = {}, useDefault = false) {
const keys = key.split(".");
let translationCandidates = useDefault
@ -142,27 +143,45 @@ class Localization {
translation = translationCandidates[lastKey];
for (let j in data) {
translation = translation.replace(`{{${j}}}`, data[j]);
if (translation.includes(`{{${j}}}`)) {
translation = translation.replace(`{{${j}}}`, data[j]);
} else {
console.warn(`Translation for your language ${Localization.locale.toUpperCase()} misses at least one data placeholder:`, key, attr, data);
Localization.logHelpCallKey(key);
Localization.logHelpCall();
translation = "";
break;
}
}
} catch (e) {
console.error(e);
translation = "";
}
if (!translation) {
if (!useDefault) {
translation = this.getTranslation(key, attr, data, true);
console.warn(`Missing translation entry for your language ${Localization.locale.toUpperCase()}. Using ${Localization.defaultLocale.toUpperCase()} instead.`, key, attr);
console.warn(`Translate this string here: https://hosted.weblate.org/browse/pairdrop/pairdrop-spa/${Localization.locale.toLowerCase()}/?q=${key}`)
console.log("Help translating PairDrop: https://hosted.weblate.org/engage/pairdrop/");
Localization.logHelpCallKey(key);
Localization.logHelpCall();
translation = this.getTranslation(key, attr, data, true);
}
else {
console.warn("Missing translation in default language:", key, attr);
Localization.logHelpCall();
}
}
return Localization.escapeHTML(translation);
}
static logHelpCall() {
console.log("Help translating PairDrop: https://hosted.weblate.org/engage/pairdrop/");
}
static logHelpCallKey(key) {
console.warn(`Translate this string here: https://hosted.weblate.org/browse/pairdrop/pairdrop-spa/${Localization.locale.toLowerCase()}/?q=${key}`);
}
static escapeHTML(unsafeText) {
let div = document.createElement('div');
div.innerText = unsafeText;

View file

@ -1,39 +1,69 @@
class PairDrop {
constructor() {
this.$header = $$('header.opacity-0');
this.$center = $$('#center');
this.$footer = $$('footer');
this.$xNoPeers = $$('x-no-peers');
this.$headerNotificationButton = $('notification');
this.$editPairedDevicesHeaderBtn = $('edit-paired-devices');
this.$footerInstructionsPairedDevices = $$('.discovery-wrapper .badge-room-secret');
this.$head = $$('head');
this.$installBtn = $('install');
this.$headerNotificationBtn = $('notification');
this.$headerEditPairedDevicesBtn = $('edit-paired-devices');
this.$footerPairedDevicesBadge = $$('.discovery-wrapper .badge-room-secret');
this.$headerInstallBtn = $('install');
this.deferredStyles = [
"styles/deferred-styles.css"
];
this.deferredScripts = [
"scripts/browser-tabs-connector.js",
"scripts/util.js",
"scripts/network.js",
"scripts/ui.js",
"scripts/qr-code.min.js",
"scripts/zip.min.js",
"scripts/no-sleep.min.js",
"scripts/heic2any.min.js"
];
this.registerServiceWorker();
Events.on('beforeinstallprompt', e => this.onPwaInstallable(e));
const persistentStorage = new PersistentStorage();
const themeUI = new ThemeUI();
const backgroundCanvas = new BackgroundCanvas();
this.persistentStorage = new PersistentStorage();
this.localization = new Localization();
this.themeUI = new ThemeUI();
this.backgroundCanvas = new BackgroundCanvas();
this.headerUI = new HeaderUI();
this.centerUI = new CenterUI();
this.footerUI = new FooterUI();
Events.on('initial-translation-loaded', _ => {
// FooterUI needs translations
const footerUI = new FooterUI();
this.initialize()
.then(_ => {
console.log("Initialization completed.");
});
}
Events.on('fade-in-ui', _ => this.fadeInUI())
Events.on('fade-in-header', _ => this.fadeInHeader())
async initialize() {
// Translate page before fading in
await this.localization.setInitialTranslation()
console.log("Initial translation successful.");
// Evaluate UI elements and fade in UI
this.evaluateUI();
// Show "Loading..." until connected to WsServer
await this.footerUI.showLoading();
// Load deferred assets
this.loadDeferredAssets();
});
// Evaluate css shifting UI elements and fade in UI elements
await this.evaluatePermissionsAndRoomSecrets();
await this.headerUI.evaluateOverflowing();
await this.headerUI.fadeIn();
await this.footerUI._evaluateFooterBadges();
await this.footerUI.fadeIn();
await this.centerUI.fadeIn();
await this.backgroundCanvas.fadeIn();
// Translate page -> fires 'initial-translation-loaded' on finish
const localization = new Localization();
// Load deferred assets
await this.loadDeferredAssets();
console.log("Loading of deferred assets completed.");
await this.hydrate();
console.log("UI hydrated.");
// Evaluate url params as soon as ws is connected
Events.on('ws-connected', _ => this.evaluateUrlParams(), {once: true});
}
registerServiceWorker() {
@ -50,130 +80,148 @@ class PairDrop {
onPwaInstallable(e) {
if (!window.matchMedia('(display-mode: minimal-ui)').matches) {
// only display install btn when not installed
this.$installBtn.removeAttribute('hidden');
this.$installBtn.addEventListener('click', () => {
this.$installBtn.setAttribute('hidden', true);
this.$headerInstallBtn.removeAttribute('hidden');
this.$headerInstallBtn.addEventListener('click', () => {
this.$headerInstallBtn.setAttribute('hidden', true);
e.prompt();
});
}
return e.preventDefault();
}
evaluateUI() {
async evaluatePermissionsAndRoomSecrets() {
// Check whether notification permissions have already been granted
if ('Notification' in window && Notification.permission !== 'granted') {
this.$headerNotificationButton.removeAttribute('hidden');
this.$headerNotificationBtn.removeAttribute('hidden');
}
PersistentStorage
.getAllRoomSecrets()
.then(roomSecrets => {
if (roomSecrets.length > 0) {
this.$editPairedDevicesHeaderBtn.removeAttribute('hidden');
this.$footerInstructionsPairedDevices.removeAttribute('hidden');
}
})
.finally(() => {
Events.fire('evaluate-footer-badges');
Events.fire('fade-in-header');
});
let roomSecrets = await PersistentStorage.getAllRoomSecrets();
if (roomSecrets.length > 0) {
this.$headerEditPairedDevicesBtn.removeAttribute('hidden');
this.$footerPairedDevicesBadge.removeAttribute('hidden');
}
}
fadeInUI() {
this.$center.classList.remove('opacity-0');
this.$footer.classList.remove('opacity-0');
// Prevent flickering on load
setTimeout(() => {
this.$xNoPeers.classList.remove('no-animation-on-load');
}, 600);
}
fadeInHeader() {
this.$header.classList.remove('opacity-0');
}
loadDeferredAssets() {
async loadDeferredAssets() {
console.log("Load deferred assets");
this.deferredStyles = [
"styles/deferred-styles.css"
];
this.deferredScripts = [
"scripts/browser-tabs-connector.js",
"scripts/util.js",
"scripts/network.js",
"scripts/ui.js",
"scripts/qr-code.min.js",
"scripts/zip.min.js",
"scripts/no-sleep.min.js"
];
this.deferredStyles.forEach(url => this.loadStyleSheet(url, _ => this.onStyleLoaded(url)))
this.deferredScripts.forEach(url => this.loadScript(url, _ => this.onScriptLoaded(url)))
}
loadStyleSheet(url, callback) {
let stylesheet = document.createElement('link');
stylesheet.rel = 'stylesheet';
stylesheet.href = url;
stylesheet.type = 'text/css';
stylesheet.onload = callback;
this.$head.appendChild(stylesheet);
}
loadScript(url, callback) {
let script = document.createElement("script");
script.src = url;
script.onload = callback;
document.body.appendChild(script);
}
onStyleLoaded(url) {
// remove entry from array
const index = this.deferredStyles.indexOf(url);
if (index !== -1) {
this.deferredStyles.splice(index, 1);
for (const url of this.deferredStyles) {
await this.loadAndApplyStylesheet(url);
}
this.onAssetLoaded();
}
onScriptLoaded(url) {
// remove entry from array
const index = this.deferredScripts.indexOf(url);
if (index !== -1) {
this.deferredScripts.splice(index, 1);
for (const url of this.deferredScripts) {
await this.loadAndApplyScript(url);
}
this.onAssetLoaded();
}
onAssetLoaded() {
if (this.deferredScripts.length || this.deferredStyles.length) return;
loadStyleSheet(url) {
return new Promise((resolve, reject) => {
let stylesheet = document.createElement('link');
stylesheet.rel = 'stylesheet';
stylesheet.href = url;
stylesheet.type = 'text/css';
stylesheet.onload = resolve;
stylesheet.onerror = reject;
console.log("Loading of deferred assets completed. Start UI hydration.");
this.hydrate();
document.head.appendChild(stylesheet);
});
}
hydrate() {
const peersUI = new PeersUI();
const languageSelectDialog = new LanguageSelectDialog();
const receiveFileDialog = new ReceiveFileDialog();
const receiveRequestDialog = new ReceiveRequestDialog();
const sendTextDialog = new SendTextDialog();
const receiveTextDialog = new ReceiveTextDialog();
const pairDeviceDialog = new PairDeviceDialog();
const clearDevicesDialog = new EditPairedDevicesDialog();
const publicRoomDialog = new PublicRoomDialog();
const base64ZipDialog = new Base64ZipDialog();
const toast = new Toast();
const notifications = new Notifications();
const networkStatusUI = new NetworkStatusUI();
const webShareTargetUI = new WebShareTargetUI();
const webFileHandlersUI = new WebFileHandlersUI();
const noSleepUI = new NoSleepUI();
const broadCast = new BrowserTabsConnector();
const server = new ServerConnection();
const peers = new PeersManager(server);
console.log("UI hydrated.")
async loadAndApplyStylesheet(url) {
try {
await this.loadStyleSheet(url);
console.log(`Stylesheet loaded successfully: ${url}`);
} catch (error) {
console.error('Error loading stylesheet:', error);
}
}
loadScript(url) {
return new Promise((resolve, reject) => {
let script = document.createElement("script");
script.src = url;
script.onload = resolve;
script.onerror = reject;
document.body.appendChild(script);
});
}
async loadAndApplyScript(url) {
try {
await this.loadScript(url);
console.log(`Script loaded successfully: ${url}`);
} catch (error) {
console.error('Error loading script:', error);
}
}
async hydrate() {
this.peersUI = new PeersUI();
this.languageSelectDialog = new LanguageSelectDialog();
this.receiveFileDialog = new ReceiveFileDialog();
this.receiveRequestDialog = new ReceiveRequestDialog();
this.sendTextDialog = new SendTextDialog();
this.receiveTextDialog = new ReceiveTextDialog();
this.pairDeviceDialog = new PairDeviceDialog();
this.clearDevicesDialog = new EditPairedDevicesDialog();
this.publicRoomDialog = new PublicRoomDialog();
this.base64Dialog = new Base64Dialog();
this.shareTextDialog = new ShareTextDialog();
this.toast = new Toast();
this.notifications = new Notifications();
this.networkStatusUI = new NetworkStatusUI();
this.webShareTargetUI = new WebShareTargetUI();
this.webFileHandlersUI = new WebFileHandlersUI();
this.noSleepUI = new NoSleepUI();
this.broadCast = new BrowserTabsConnector();
this.server = new ServerConnection();
this.peers = new PeersManager(this.server);
}
async evaluateUrlParams() {
// get url params
const urlParams = new URLSearchParams(window.location.search);
const hash = window.location.hash.substring(1);
// evaluate url params
if (urlParams.has('pair_key')) {
const pairKey = urlParams.get('pair_key');
this.pairDeviceDialog._pairDeviceJoin(pairKey);
}
else if (urlParams.has('room_id')) {
const roomId = urlParams.get('room_id');
this.publicRoomDialog._joinPublicRoom(roomId);
}
else if (urlParams.has('base64text')) {
const base64Text = urlParams.get('base64text');
await this.base64Dialog.evaluateBase64Text(base64Text, hash);
}
else if (urlParams.has('base64zip')) {
const base64Zip = urlParams.get('base64zip');
await this.base64Dialog.evaluateBase64Zip(base64Zip, hash);
}
else if (urlParams.has("share_target")) {
const shareTargetType = urlParams.get("share_target");
const title = urlParams.get('title') || '';
const text = urlParams.get('text') || '';
const url = urlParams.get('url') || '';
await this.webShareTargetUI.evaluateShareTarget(shareTargetType, title, text, url);
}
else if (urlParams.has("file_handler")) {
await this.webFileHandlersUI.evaluateLaunchQueue();
}
else if (urlParams.has("init")) {
const init = urlParams.get("init");
if (init === "pair") {
this.pairDeviceDialog._pairDeviceInitiate();
}
else if (init === "public_room") {
this.publicRoomDialog._createPublicRoom();
}
}
// remove url params from url
const urlWithoutParams = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", urlWithoutParams);
}
}

View file

@ -433,47 +433,6 @@ class Peer {
: false;
}
getResizedImageDataUrl(file, width = undefined, height = undefined, quality = 0.7) {
return new Promise((resolve, reject) => {
let image = new Image();
image.src = URL.createObjectURL(file);
image.onload = _ => {
let imageWidth = image.width;
let imageHeight = image.height;
let canvas = document.createElement('canvas');
// resize the canvas and draw the image data into it
if (width && height) {
canvas.width = width;
canvas.height = height;
}
else if (width) {
canvas.width = width;
canvas.height = Math.floor(imageHeight * width / imageWidth)
}
else if (height) {
canvas.width = Math.floor(imageWidth * height / imageHeight);
canvas.height = height;
}
else {
canvas.width = imageWidth;
canvas.height = imageHeight
}
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
let dataUrl = canvas.toDataURL("image/jpeg", quality);
resolve(dataUrl);
}
image.onerror = _ => reject(`Could not create an image thumbnail from type ${file.type}`);
})
.then(dataUrl => {
return dataUrl;
})
.catch(e => console.error(e));
}
async requestFileTransfer(files) {
let header = [];
let totalSize = 0;
@ -493,7 +452,11 @@ class Peer {
let dataUrl = '';
if (files[0].type.split('/')[0] === 'image') {
dataUrl = await this.getResizedImageDataUrl(files[0], 400, null, 0.9);
try {
dataUrl = await getThumbnailAsDataUrl(files[0], 400, null, 0.9);
} catch (e) {
console.error(e);
}
}
Events.fire('set-progress', {peerId: this._peerId, progress: 1, status: 'prepare'})
@ -1118,20 +1081,9 @@ class PeersManager {
this.peers[detail.to]._respondToFileTransferRequest(detail.accepted);
}
_onFilesSelected(message) {
let inputFiles = Array.from(message.files);
delete message.files;
let files = [];
const l = inputFiles.length;
for (let i=0; i<l; i++) {
// when filetype is empty guess via suffix
const inputFile = inputFiles.shift();
const file = inputFile.type
? inputFile
: new File([inputFile], inputFile.name, {type: mime.getMimeByFilename(inputFile.name)});
files.push(file)
}
this.peers[message.to].requestFileTransfer(files);
async _onFilesSelected(message) {
let files = await mime.addMissingMimeTypesToFiles(message.files);
await this.peers[message.to].requestFileTransfer(files);
}
_onSendText(message) {

View file

@ -4,7 +4,7 @@ class PersistentStorage {
PersistentStorage.logBrowserNotCapable();
return;
}
const DBOpenRequest = window.indexedDB.open('pairdrop_store', 4);
const DBOpenRequest = window.indexedDB.open('pairdrop_store', 5);
DBOpenRequest.onerror = e => {
PersistentStorage.logBrowserNotCapable();
console.log('Error initializing database: ');
@ -13,7 +13,7 @@ class PersistentStorage {
DBOpenRequest.onsuccess = _ => {
console.log('Database initialised.');
};
DBOpenRequest.onupgradeneeded = e => {
DBOpenRequest.onupgradeneeded = async e => {
const db = e.target.result;
const txn = e.target.transaction;
@ -42,6 +42,14 @@ class PersistentStorage {
roomSecretsObjectStore4.createIndex('display_name', 'display_name');
roomSecretsObjectStore4.createIndex('auto_accept', 'auto_accept');
}
if (e.oldVersion <= 4) {
// migrate to v5
const editedDisplayNameOld = await PersistentStorage.get('editedDisplayName');
if (editedDisplayNameOld) {
await PersistentStorage.set('edited_display_name', editedDisplayNameOld);
await PersistentStorage.delete('editedDisplayName');
}
}
}
}
@ -141,7 +149,7 @@ class PersistentStorage {
return(secrets);
} catch (e) {
this.logBrowserNotCapable();
return 0;
return [];
}
}

View file

@ -111,15 +111,91 @@ class ThemeUI {
}
}
class HeaderUI {
constructor() {
this.$header = $$('header');
this.$expandBtn = $('expand');
Events.on("resize", _ => this.evaluateOverflowing());
this.$expandBtn.addEventListener('click', _ => this.onExpandBtnClick());
}
async fadeIn() {
this.$header.classList.remove('opacity-0');
}
async evaluateOverflowing() {
// remove and reset bracket icon before evaluating
this.$expandBtn.setAttribute('hidden', true);
this.$expandBtn.classList.add('flipped');
const rtlLocale = Localization.isCurrentLocaleRtl();
let icon;
const $headerIconsShown = document.querySelectorAll('body > header:first-of-type > *:not([hidden])');
for (let i= 1; i < $headerIconsShown.length; i++) {
let isFurtherLeftThanLastIcon = $headerIconsShown[i].offsetLeft >= $headerIconsShown[i-1].offsetLeft;
let isFurtherRightThanLastIcon = $headerIconsShown[i].offsetLeft <= $headerIconsShown[i-1].offsetLeft;
if ((!rtlLocale && isFurtherLeftThanLastIcon) || (rtlLocale && isFurtherRightThanLastIcon)) {
// we have found the first icon on second row. Use previous icon.
icon = $headerIconsShown[i-1];
break;
}
}
if (icon) {
// overflowing
// add overflowing-hidden class
this.$header.classList.add('overflow-hidden');
// add expand btn 2 before icon
this.$expandBtn.removeAttribute('hidden');
icon.before(this.$expandBtn);
}
else {
// no overflowing
// add overflowing-hidden class
this.$header.classList.remove('overflow-hidden');
}
}
onExpandBtnClick() {
// toggle overflowing-hidden class and flip expand btn icon
if (this.$header.classList.contains('overflow-hidden')) {
this.$header.classList.remove('overflow-hidden');
this.$header.classList.add('overflow-expanded');
this.$expandBtn.classList.remove('flipped');
}
else {
this.$header.classList.add('overflow-hidden');
this.$header.classList.remove('overflow-expanded');
this.$expandBtn.classList.add('flipped');
}
}
}
class CenterUI {
constructor() {
this.$center = $$('#center');
this.$xNoPeers = $$('x-no-peers');
}
async fadeIn() {
this.$center.classList.remove('opacity-0');
// Prevent flickering on load
setTimeout(() => {
this.$xNoPeers.classList.remove('no-animation-on-load');
}, 600);
}
}
class FooterUI {
constructor() {
this.$footer = $$('footer');
this.$displayName = $('display-name');
this.$discoveryWrapper = $$('footer .discovery-wrapper');
// Show "Loading…"
this.$displayName.setAttribute('placeholder', this.$displayName.dataset.placeholder);
this.$displayName.addEventListener('keydown', e => this._onKeyDownDisplayName(e));
this.$displayName.addEventListener('keyup', e => this._onKeyUpDisplayName(e));
this.$displayName.addEventListener('blur', e => this._saveDisplayName(e.target.innerText));
@ -133,7 +209,15 @@ class FooterUI {
Events.on('evaluate-footer-badges', _ => this._evaluateFooterBadges());
}
_evaluateFooterBadges() {
async showLoading() {
this.$displayName.setAttribute('placeholder', this.$displayName.dataset.placeholder);
}
async fadeIn() {
this.$footer.classList.remove('opacity-0');
}
async _evaluateFooterBadges() {
if (this.$discoveryWrapper.querySelectorAll('div:last-of-type > span[hidden]').length < 2) {
this.$discoveryWrapper.classList.remove('row');
this.$discoveryWrapper.classList.add('column');
@ -143,17 +227,15 @@ class FooterUI {
this.$discoveryWrapper.classList.add('row');
}
Events.fire('redraw-canvas');
Events.fire('fade-in-ui');
}
_loadSavedDisplayName() {
this._getSavedDisplayName()
.then(displayName => {
console.log("Retrieved edited display name:", displayName)
if (displayName) {
Events.fire('self-display-name-changed', displayName);
}
});
async _loadSavedDisplayName() {
const displayName = await this._getSavedDisplayName()
if (!displayName) return;
console.log("Retrieved edited display name:", displayName)
Events.fire('self-display-name-changed', displayName);
}
_onDisplayName(displayName){
@ -184,13 +266,13 @@ class FooterUI {
if (newDisplayName === savedDisplayName) return;
if (newDisplayName) {
PersistentStorage.set('editedDisplayName', newDisplayName)
PersistentStorage.set('edited_display_name', newDisplayName)
.then(_ => {
Events.fire('notify-user', Localization.getTranslation("notifications.display-name-changed-permanently"));
})
.catch(_ => {
console.log("This browser does not support IndexedDB. Use localStorage instead.");
localStorage.setItem('editedDisplayName', newDisplayName);
localStorage.setItem('edited_display_name', newDisplayName);
Events.fire('notify-user', Localization.getTranslation("notifications.display-name-changed-temporarily"));
})
.finally(() => {
@ -199,10 +281,10 @@ class FooterUI {
});
}
else {
PersistentStorage.delete('editedDisplayName')
PersistentStorage.delete('edited_display_name')
.catch(_ => {
console.log("This browser does not support IndexedDB. Use localStorage instead.")
localStorage.removeItem('editedDisplayName');
localStorage.removeItem('edited_display_name');
})
.finally(() => {
Events.fire('notify-user', Localization.getTranslation("notifications.display-name-random-again"));
@ -214,13 +296,13 @@ class FooterUI {
_getSavedDisplayName() {
return new Promise((resolve) => {
PersistentStorage.get('editedDisplayName')
PersistentStorage.get('edited_display_name')
.then(displayName => {
if (!displayName) displayName = "";
resolve(displayName);
})
.catch(_ => {
let displayName = localStorage.getItem('editedDisplayName');
let displayName = localStorage.getItem('edited_display_name');
if (!displayName) displayName = "";
resolve(displayName);
})
@ -234,16 +316,16 @@ class BackgroundCanvas {
this.cCtx = this.c.getContext('2d');
this.$footer = $$('footer');
// fade-in on load
Events.on('fade-in-ui', _ => this._fadeIn());
// redraw canvas
Events.on('resize', _ => this.init());
Events.on('redraw-canvas', _ => this.init());
Events.on('translation-loaded', _ => this.init());
// ShareMode
Events.on('share-mode-changed', e => this.onShareModeChanged(e.detail.active));
}
_fadeIn() {
async fadeIn() {
this.c.classList.remove('opacity-0');
}
@ -263,16 +345,24 @@ class BackgroundCanvas {
this.x0 = this.w / 2;
this.y0 = this.h - this.offset;
this.dw = Math.round(Math.max(this.w, this.h, 1000) / 13);
this.baseColor = '165, 165, 165';
this.baseOpacity = 0.3;
this.drawCircles(this.cCtx);
}
onShareModeChanged(active) {
this.baseColor = active ? '165, 165, 255' : '165, 165, 165';
this.baseOpacity = active ? 0.5 : 0.3;
this.drawCircles(this.cCtx);
}
drawCircle(ctx, radius) {
ctx.beginPath();
ctx.lineWidth = 2;
let opacity = Math.max(0, 0.3 * (1 - 1.2 * radius / Math.max(this.w, this.h)));
ctx.strokeStyle = `rgba(165, 165, 165, ${opacity})`;
let opacity = Math.max(0, this.baseOpacity * (1 - 1.2 * radius / Math.max(this.w, this.h)));
ctx.strokeStyle = `rgba(${this.baseColor}, ${opacity})`;
ctx.arc(this.x0, this.y0, radius, 0, 2 * Math.PI);
ctx.stroke();
}

File diff suppressed because it is too large Load diff

View file

@ -104,305 +104,315 @@ const zipper = (() => {
const mime = (() => {
const suffixToMimeMap = {
"cpl": "application/cpl+xml",
"gpx": "application/gpx+xml",
"gz": "application/gzip",
"jar": "application/java-archive",
"war": "application/java-archive",
"ear": "application/java-archive",
"class": "application/java-vm",
"js": "application/javascript",
"mjs": "application/javascript",
"json": "application/json",
"map": "application/json",
"webmanifest": "application/manifest+json",
"doc": "application/msword",
"dot": "application/msword",
"wiz": "application/msword",
"bin": "application/octet-stream",
"dms": "application/octet-stream",
"lrf": "application/octet-stream",
"mar": "application/octet-stream",
"so": "application/octet-stream",
"dist": "application/octet-stream",
"distz": "application/octet-stream",
"pkg": "application/octet-stream",
"bpk": "application/octet-stream",
"dump": "application/octet-stream",
"elc": "application/octet-stream",
"deploy": "application/octet-stream",
"img": "application/octet-stream",
"msp": "application/octet-stream",
"msm": "application/octet-stream",
"buffer": "application/octet-stream",
"oda": "application/oda",
"oxps": "application/oxps",
"pdf": "application/pdf",
"asc": "application/pgp-signature",
"sig": "application/pgp-signature",
"prf": "application/pics-rules",
"p7c": "application/pkcs7-mime",
"cer": "application/pkix-cert",
"ai": "application/postscript",
"eps": "application/postscript",
"ps": "application/postscript",
"apk": "application/vnd.android.package-archive",
"m3u8": "application/vnd.apple.mpegurl",
"pkpass": "application/vnd.apple.pkpass",
"kml": "application/vnd.google-earth.kml+xml",
"kmz": "application/vnd.google-earth.kmz",
"cab": "application/vnd.ms-cab-compressed",
"xls": "application/vnd.ms-excel",
"xlm": "application/vnd.ms-excel",
"xla": "application/vnd.ms-excel",
"xlc": "application/vnd.ms-excel",
"xlt": "application/vnd.ms-excel",
"xlw": "application/vnd.ms-excel",
"msg": "application/vnd.ms-outlook",
"ppt": "application/vnd.ms-powerpoint",
"pot": "application/vnd.ms-powerpoint",
"ppa": "application/vnd.ms-powerpoint",
"pps": "application/vnd.ms-powerpoint",
"pwz": "application/vnd.ms-powerpoint",
"mpp": "application/vnd.ms-project",
"mpt": "application/vnd.ms-project",
"xps": "application/vnd.ms-xpsdocument",
"odb": "application/vnd.oasis.opendocument.database",
"ods": "application/vnd.oasis.opendocument.spreadsheet",
"odt": "application/vnd.oasis.opendocument.text",
"osm": "application/vnd.openstreetmap.data+xml",
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"pcap": "application/vnd.tcpdump.pcap",
"cap": "application/vnd.tcpdump.pcap",
"dmp": "application/vnd.tcpdump.pcap",
"wpd": "application/vnd.wordperfect",
"wasm": "application/wasm",
"7z": "application/x-7z-compressed",
"dmg": "application/x-apple-diskimage",
"bcpio": "application/x-bcpio",
"torrent": "application/x-bittorrent",
"cbr": "application/x-cbr",
"cba": "application/x-cbr",
"cbt": "application/x-cbr",
"cbz": "application/x-cbr",
"cb7": "application/x-cbr",
"vcd": "application/x-cdlink",
"crx": "application/x-chrome-extension",
"cpio": "application/x-cpio",
"csh": "application/x-csh",
"deb": "application/x-debian-package",
"udeb": "application/x-debian-package",
"dvi": "application/x-dvi",
"arc": "application/x-freearc",
"gtar": "application/x-gtar",
"hdf": "application/x-hdf",
"h5": "application/x-hdf5",
"php": "application/x-httpd-php",
"iso": "application/x-iso9660-image",
"key": "application/x-iwork-keynote-sffkey",
"numbers": "application/x-iwork-numbers-sffnumbers",
"pages": "application/x-iwork-pages-sffpages",
"latex": "application/x-latex",
"run": "application/x-makeself",
"mif": "application/x-mif",
"lnk": "application/x-ms-shortcut",
"mdb": "application/x-msaccess",
"exe": "application/x-msdownload",
"dll": "application/x-msdownload",
"com": "application/x-msdownload",
"bat": "application/x-msdownload",
"msi": "application/x-msdownload",
"pub": "application/x-mspublisher",
"cdf": "application/x-netcdf",
"nc": "application/x-netcdf",
"pl": "application/x-perl",
"pm": "application/x-perl",
"prc": "application/x-pilot",
"pdb": "application/x-pilot",
"p12": "application/x-pkcs12",
"pfx": "application/x-pkcs12",
"ram": "application/x-pn-realaudio",
"pyc": "application/x-python-code",
"pyo": "application/x-python-code",
"rar": "application/x-rar-compressed",
"rpm": "application/x-redhat-package-manager",
"sh": "application/x-sh",
"shar": "application/x-shar",
"swf": "application/x-shockwave-flash",
"sql": "application/x-sql",
"srt": "application/x-subrip",
"sv4cpio": "application/x-sv4cpio",
"sv4crc": "application/x-sv4crc",
"gam": "application/x-tads",
"tar": "application/x-tar",
"tcl": "application/x-tcl",
"tex": "application/x-tex",
"roff": "application/x-troff",
"t": "application/x-troff",
"tr": "application/x-troff",
"man": "application/x-troff-man",
"me": "application/x-troff-me",
"ms": "application/x-troff-ms",
"ustar": "application/x-ustar",
"src": "application/x-wais-source",
"xpi": "application/x-xpinstall",
"xhtml": "application/xhtml+xml",
"xht": "application/xhtml+xml",
"xsl": "application/xml",
"rdf": "application/xml",
"wsdl": "application/xml",
"xpdl": "application/xml",
"zip": "application/zip",
"3gp": "audio/3gp",
"3gpp": "audio/3gpp",
"3g2": "audio/3gpp2",
"3gpp2": "audio/3gpp2",
"aac": "audio/aac",
"adts": "audio/aac",
"loas": "audio/aac",
"ass": "audio/aac",
"au": "audio/basic",
"snd": "audio/basic",
"mid": "audio/midi",
"midi": "audio/midi",
"kar": "audio/midi",
"rmi": "audio/midi",
"mpga": "audio/mpeg",
"mp2": "audio/mpeg",
"mp2a": "audio/mpeg",
"mp3": "audio/mpeg",
"m2a": "audio/mpeg",
"m3a": "audio/mpeg",
"oga": "audio/ogg",
"ogg": "audio/ogg",
"spx": "audio/ogg",
"opus": "audio/opus",
"aif": "audio/x-aiff",
"aifc": "audio/x-aiff",
"aiff": "audio/x-aiff",
"flac": "audio/x-flac",
"m4a": "audio/x-m4a",
"m3u": "audio/x-mpegurl",
"wma": "audio/x-ms-wma",
"ra": "audio/x-pn-realaudio",
"wav": "audio/x-wav",
"otf": "font/otf",
"ttf": "font/ttf",
"woff": "font/woff",
"woff2": "font/woff2",
"emf": "image/emf",
"gif": "image/gif",
"heic": "image/heic",
"heif": "image/heif",
"ief": "image/ief",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"pict": "image/pict",
"pct": "image/pict",
"pic": "image/pict",
"png": "image/png",
"svg": "image/svg+xml",
"svgz": "image/svg+xml",
"tif": "image/tiff",
"tiff": "image/tiff",
"psd": "image/vnd.adobe.photoshop",
"djvu": "image/vnd.djvu",
"djv": "image/vnd.djvu",
"dwg": "image/vnd.dwg",
"dxf": "image/vnd.dxf",
"dds": "image/vnd.ms-dds",
"webp": "image/webp",
"3ds": "image/x-3ds",
"ras": "image/x-cmu-raster",
"ico": "image/x-icon",
"bmp": "image/x-ms-bmp",
"pnm": "image/x-portable-anymap",
"pbm": "image/x-portable-bitmap",
"pgm": "image/x-portable-graymap",
"ppm": "image/x-portable-pixmap",
"rgb": "image/x-rgb",
"tga": "image/x-tga",
"xbm": "image/x-xbitmap",
"xpm": "image/x-xpixmap",
"xwd": "image/x-xwindowdump",
"eml": "message/rfc822",
"mht": "message/rfc822",
"mhtml": "message/rfc822",
"nws": "message/rfc822",
"obj": "model/obj",
"stl": "model/stl",
"dae": "model/vnd.collada+xml",
"ics": "text/calendar",
"ifb": "text/calendar",
"css": "text/css",
"csv": "text/csv",
"html": "text/html",
"htm": "text/html",
"shtml": "text/html",
"markdown": "text/markdown",
"md": "text/markdown",
"txt": "text/plain",
"text": "text/plain",
"conf": "text/plain",
"def": "text/plain",
"list": "text/plain",
"log": "text/plain",
"in": "text/plain",
"ini": "text/plain",
"rtx": "text/richtext",
"rtf": "text/rtf",
"tsv": "text/tab-separated-values",
"c": "text/x-c",
"cc": "text/x-c",
"cxx": "text/x-c",
"cpp": "text/x-c",
"h": "text/x-c",
"hh": "text/x-c",
"dic": "text/x-c",
"java": "text/x-java-source",
"lua": "text/x-lua",
"py": "text/x-python",
"etx": "text/x-setext",
"sgm": "text/x-sgml",
"sgml": "text/x-sgml",
"vcf": "text/x-vcard",
"xml": "text/xml",
"xul": "text/xul",
"yaml": "text/yaml",
"yml": "text/yaml",
"ts": "video/mp2t",
"mp4": "video/mp4",
"mp4v": "video/mp4",
"mpg4": "video/mp4",
"mpeg": "video/mpeg",
"m1v": "video/mpeg",
"mpa": "video/mpeg",
"mpe": "video/mpeg",
"mpg": "video/mpeg",
"mov": "video/quicktime",
"qt": "video/quicktime",
"webm": "video/webm",
"flv": "video/x-flv",
"m4v": "video/x-m4v",
"asf": "video/x-ms-asf",
"asx": "video/x-ms-asf",
"vob": "video/x-ms-vob",
"wmv": "video/x-ms-wmv",
"avi": "video/x-msvideo",
"*": "video/x-sgi-movie"
}
return {
getMimeByFilename(filename) {
try {
const arr = filename.split('.');
const suffix = arr[arr.length - 1].toLowerCase();
return {
"cpl": "application/cpl+xml",
"gpx": "application/gpx+xml",
"gz": "application/gzip",
"jar": "application/java-archive",
"war": "application/java-archive",
"ear": "application/java-archive",
"class": "application/java-vm",
"js": "application/javascript",
"mjs": "application/javascript",
"json": "application/json",
"map": "application/json",
"webmanifest": "application/manifest+json",
"doc": "application/msword",
"dot": "application/msword",
"wiz": "application/msword",
"bin": "application/octet-stream",
"dms": "application/octet-stream",
"lrf": "application/octet-stream",
"mar": "application/octet-stream",
"so": "application/octet-stream",
"dist": "application/octet-stream",
"distz": "application/octet-stream",
"pkg": "application/octet-stream",
"bpk": "application/octet-stream",
"dump": "application/octet-stream",
"elc": "application/octet-stream",
"deploy": "application/octet-stream",
"img": "application/octet-stream",
"msp": "application/octet-stream",
"msm": "application/octet-stream",
"buffer": "application/octet-stream",
"oda": "application/oda",
"oxps": "application/oxps",
"pdf": "application/pdf",
"asc": "application/pgp-signature",
"sig": "application/pgp-signature",
"prf": "application/pics-rules",
"p7c": "application/pkcs7-mime",
"cer": "application/pkix-cert",
"ai": "application/postscript",
"eps": "application/postscript",
"ps": "application/postscript",
"apk": "application/vnd.android.package-archive",
"m3u8": "application/vnd.apple.mpegurl",
"pkpass": "application/vnd.apple.pkpass",
"kml": "application/vnd.google-earth.kml+xml",
"kmz": "application/vnd.google-earth.kmz",
"cab": "application/vnd.ms-cab-compressed",
"xls": "application/vnd.ms-excel",
"xlm": "application/vnd.ms-excel",
"xla": "application/vnd.ms-excel",
"xlc": "application/vnd.ms-excel",
"xlt": "application/vnd.ms-excel",
"xlw": "application/vnd.ms-excel",
"msg": "application/vnd.ms-outlook",
"ppt": "application/vnd.ms-powerpoint",
"pot": "application/vnd.ms-powerpoint",
"ppa": "application/vnd.ms-powerpoint",
"pps": "application/vnd.ms-powerpoint",
"pwz": "application/vnd.ms-powerpoint",
"mpp": "application/vnd.ms-project",
"mpt": "application/vnd.ms-project",
"xps": "application/vnd.ms-xpsdocument",
"odb": "application/vnd.oasis.opendocument.database",
"ods": "application/vnd.oasis.opendocument.spreadsheet",
"odt": "application/vnd.oasis.opendocument.text",
"osm": "application/vnd.openstreetmap.data+xml",
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"pcap": "application/vnd.tcpdump.pcap",
"cap": "application/vnd.tcpdump.pcap",
"dmp": "application/vnd.tcpdump.pcap",
"wpd": "application/vnd.wordperfect",
"wasm": "application/wasm",
"7z": "application/x-7z-compressed",
"dmg": "application/x-apple-diskimage",
"bcpio": "application/x-bcpio",
"torrent": "application/x-bittorrent",
"cbr": "application/x-cbr",
"cba": "application/x-cbr",
"cbt": "application/x-cbr",
"cbz": "application/x-cbr",
"cb7": "application/x-cbr",
"vcd": "application/x-cdlink",
"crx": "application/x-chrome-extension",
"cpio": "application/x-cpio",
"csh": "application/x-csh",
"deb": "application/x-debian-package",
"udeb": "application/x-debian-package",
"dvi": "application/x-dvi",
"arc": "application/x-freearc",
"gtar": "application/x-gtar",
"hdf": "application/x-hdf",
"h5": "application/x-hdf5",
"php": "application/x-httpd-php",
"iso": "application/x-iso9660-image",
"key": "application/x-iwork-keynote-sffkey",
"numbers": "application/x-iwork-numbers-sffnumbers",
"pages": "application/x-iwork-pages-sffpages",
"latex": "application/x-latex",
"run": "application/x-makeself",
"mif": "application/x-mif",
"lnk": "application/x-ms-shortcut",
"mdb": "application/x-msaccess",
"exe": "application/x-msdownload",
"dll": "application/x-msdownload",
"com": "application/x-msdownload",
"bat": "application/x-msdownload",
"msi": "application/x-msdownload",
"pub": "application/x-mspublisher",
"cdf": "application/x-netcdf",
"nc": "application/x-netcdf",
"pl": "application/x-perl",
"pm": "application/x-perl",
"prc": "application/x-pilot",
"pdb": "application/x-pilot",
"p12": "application/x-pkcs12",
"pfx": "application/x-pkcs12",
"ram": "application/x-pn-realaudio",
"pyc": "application/x-python-code",
"pyo": "application/x-python-code",
"rar": "application/x-rar-compressed",
"rpm": "application/x-redhat-package-manager",
"sh": "application/x-sh",
"shar": "application/x-shar",
"swf": "application/x-shockwave-flash",
"sql": "application/x-sql",
"srt": "application/x-subrip",
"sv4cpio": "application/x-sv4cpio",
"sv4crc": "application/x-sv4crc",
"gam": "application/x-tads",
"tar": "application/x-tar",
"tcl": "application/x-tcl",
"tex": "application/x-tex",
"roff": "application/x-troff",
"t": "application/x-troff",
"tr": "application/x-troff",
"man": "application/x-troff-man",
"me": "application/x-troff-me",
"ms": "application/x-troff-ms",
"ustar": "application/x-ustar",
"src": "application/x-wais-source",
"xpi": "application/x-xpinstall",
"xhtml": "application/xhtml+xml",
"xht": "application/xhtml+xml",
"xsl": "application/xml",
"rdf": "application/xml",
"wsdl": "application/xml",
"xpdl": "application/xml",
"zip": "application/zip",
"3gp": "audio/3gp",
"3gpp": "audio/3gpp",
"3g2": "audio/3gpp2",
"3gpp2": "audio/3gpp2",
"aac": "audio/aac",
"adts": "audio/aac",
"loas": "audio/aac",
"ass": "audio/aac",
"au": "audio/basic",
"snd": "audio/basic",
"mid": "audio/midi",
"midi": "audio/midi",
"kar": "audio/midi",
"rmi": "audio/midi",
"mpga": "audio/mpeg",
"mp2": "audio/mpeg",
"mp2a": "audio/mpeg",
"mp3": "audio/mpeg",
"m2a": "audio/mpeg",
"m3a": "audio/mpeg",
"oga": "audio/ogg",
"ogg": "audio/ogg",
"spx": "audio/ogg",
"opus": "audio/opus",
"aif": "audio/x-aiff",
"aifc": "audio/x-aiff",
"aiff": "audio/x-aiff",
"flac": "audio/x-flac",
"m4a": "audio/x-m4a",
"m3u": "audio/x-mpegurl",
"wma": "audio/x-ms-wma",
"ra": "audio/x-pn-realaudio",
"wav": "audio/x-wav",
"otf": "font/otf",
"ttf": "font/ttf",
"woff": "font/woff",
"woff2": "font/woff2",
"emf": "image/emf",
"gif": "image/gif",
"heic": "image/heic",
"heif": "image/heif",
"ief": "image/ief",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"pict": "image/pict",
"pct": "image/pict",
"pic": "image/pict",
"png": "image/png",
"svg": "image/svg+xml",
"svgz": "image/svg+xml",
"tif": "image/tiff",
"tiff": "image/tiff",
"psd": "image/vnd.adobe.photoshop",
"djvu": "image/vnd.djvu",
"djv": "image/vnd.djvu",
"dwg": "image/vnd.dwg",
"dxf": "image/vnd.dxf",
"dds": "image/vnd.ms-dds",
"webp": "image/webp",
"3ds": "image/x-3ds",
"ras": "image/x-cmu-raster",
"ico": "image/x-icon",
"bmp": "image/x-ms-bmp",
"pnm": "image/x-portable-anymap",
"pbm": "image/x-portable-bitmap",
"pgm": "image/x-portable-graymap",
"ppm": "image/x-portable-pixmap",
"rgb": "image/x-rgb",
"tga": "image/x-tga",
"xbm": "image/x-xbitmap",
"xpm": "image/x-xpixmap",
"xwd": "image/x-xwindowdump",
"eml": "message/rfc822",
"mht": "message/rfc822",
"mhtml": "message/rfc822",
"nws": "message/rfc822",
"obj": "model/obj",
"stl": "model/stl",
"dae": "model/vnd.collada+xml",
"ics": "text/calendar",
"ifb": "text/calendar",
"css": "text/css",
"csv": "text/csv",
"html": "text/html",
"htm": "text/html",
"shtml": "text/html",
"markdown": "text/markdown",
"md": "text/markdown",
"txt": "text/plain",
"text": "text/plain",
"conf": "text/plain",
"def": "text/plain",
"list": "text/plain",
"log": "text/plain",
"in": "text/plain",
"ini": "text/plain",
"rtx": "text/richtext",
"rtf": "text/rtf",
"tsv": "text/tab-separated-values",
"c": "text/x-c",
"cc": "text/x-c",
"cxx": "text/x-c",
"cpp": "text/x-c",
"h": "text/x-c",
"hh": "text/x-c",
"dic": "text/x-c",
"java": "text/x-java-source",
"lua": "text/x-lua",
"py": "text/x-python",
"etx": "text/x-setext",
"sgm": "text/x-sgml",
"sgml": "text/x-sgml",
"vcf": "text/x-vcard",
"xml": "text/xml",
"xul": "text/xul",
"yaml": "text/yaml",
"yml": "text/yaml",
"ts": "video/mp2t",
"mp4": "video/mp4",
"mp4v": "video/mp4",
"mpg4": "video/mp4",
"mpeg": "video/mpeg",
"m1v": "video/mpeg",
"mpa": "video/mpeg",
"mpe": "video/mpeg",
"mpg": "video/mpeg",
"mov": "video/quicktime",
"qt": "video/quicktime",
"webm": "video/webm",
"flv": "video/x-flv",
"m4v": "video/x-m4v",
"asf": "video/x-ms-asf",
"asx": "video/x-ms-asf",
"vob": "video/x-ms-vob",
"wmv": "video/x-ms-wmv",
"avi": "video/x-msvideo",
"*": "video/x-sgi-movie",
}[suffix] || '';
} catch (e) {
console.error(e);
return '';
async guessMimeByFilename(filename) {
const split = filename.split('.');
if (split.length === 1) {
// Filename does not include suffix
return "";
}
const suffix = split[split.length - 1].toLowerCase();
return suffixToMimeMap[suffix] || "";
},
async addMissingMimeTypesToFiles(files) {
// if filetype is empty guess via suffix otherwise leave unchanged
for (let i = 0; i < files.length; i++) {
if (!files[i].type) {
files[i] = new File([files[i]], files[i].name, {type: await mime.guessMimeByFilename(files[i].name) || ""});
}
}
return files;
}
};
@ -457,4 +467,120 @@ function base64ToArrayBuffer(base64) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
async function fileToBlob (file) {
return new Blob([new Uint8Array(await file.arrayBuffer())], {type: file.type});
}
function getThumbnailAsDataUrl(file, width = undefined, height = undefined, quality = 0.7) {
return new Promise(async (resolve, reject) => {
try {
if (file.type === "image/heif" || file.type === "image/heic") {
// browsers can't show heic files --> convert to jpeg before creating thumbnail
let blob = await fileToBlob(file);
file = await heic2any({
blob,
toType: "image/jpeg",
quality: quality
});
}
let imageUrl = URL.createObjectURL(file);
let image = new Image();
image.src = imageUrl;
await waitUntilImageIsLoaded(imageUrl);
let imageWidth = image.width;
let imageHeight = image.height;
let canvas = document.createElement('canvas');
// resize the canvas and draw the image data into it
if (width && height) {
canvas.width = width;
canvas.height = height;
}
else if (width) {
canvas.width = width;
canvas.height = Math.floor(imageHeight * width / imageWidth)
}
else if (height) {
canvas.width = Math.floor(imageWidth * height / imageHeight);
canvas.height = height;
}
else {
canvas.width = imageWidth;
canvas.height = imageHeight
}
let ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
let dataUrl = canvas.toDataURL("image/jpeg", quality);
resolve(dataUrl);
} catch (e) {
console.error(e);
reject(new Error(`Could not create an image thumbnail from type ${file.type}`));
}
})
}
// Resolves returned promise when image is loaded and throws error if image cannot be shown
function waitUntilImageIsLoaded(imageUrl, timeout = 10000) {
return new Promise((resolve, reject) => {
let image = new Image();
image.src = imageUrl;
const onLoad = () => {
cleanup();
resolve();
};
const onError = () => {
cleanup();
reject(new Error('Image failed to load.'));
};
const cleanup = () => {
clearTimeout(timeoutId);
image.onload = null;
image.onerror = null;
URL.revokeObjectURL(imageUrl);
};
const timeoutId = setTimeout(() => {
cleanup();
reject(new Error('Image loading timed out.'));
}, timeout);
image.onload = onLoad;
image.onerror = onError;
});
}
async function decodeBase64Files(base64) {
if (!base64) throw new Error('Base64 is empty');
let bstr = atob(base64), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
const zipBlob = new File([u8arr], 'archive.zip');
let files = [];
const zipEntries = await zipper.getEntries(zipBlob);
for (let i = 0; i < zipEntries.length; i++) {
let fileBlob = await zipper.getData(zipEntries[i]);
files.push(new File([fileBlob], zipEntries[i].filename));
}
return files
}
async function decodeBase64Text(base64) {
if (!base64) throw new Error('Base64 is empty');
return decodeURIComponent(escape(window.atob(base64)))
}

View file

@ -1,20 +1,5 @@
/* All styles in this sheet are not needed on page load and deferred */
/* Paste mode */
#cancel-paste-mode {
z-index: 21;
margin: 0;
padding: 0;
position: absolute;
top: 0;
right: 0;
left: 0;
width: 100vw;
height: 56px;
background-color: var(--primary-color);
color: rgb(238, 238, 238);
}
/* Text Input */
.textarea {
box-sizing: border-box;
@ -22,17 +7,21 @@
outline: none;
padding: 16px 24px;
border-radius: 12px;
font-size: inherit;
font-size: 16px;
font-family: inherit;
display: block;
overflow: auto;
resize: none;
line-height: 16px;
max-height: 300px;
max-height: 350px;
word-break: break-word;
word-wrap: anywhere;
}
.textarea:before {
opacity: 0.5;
}
/* Peers */
x-peers:has(> x-peer) {
@ -279,6 +268,56 @@ x-peer[drop] x-icon {
transform: scale(1.1);
}
/* Checkboxes as slider */
.switch {
display: inline-block;
height: 20px;
position: relative;
width: 30px;
}
.switch input {
display:none;
}
.slider {
background-color: rgba(128, 128, 128, 0.5);
cursor: pointer;
top: 0;
bottom: 0;
right: 0;
left: 0;
position: absolute;
transition: .4s;
}
.slider:before {
background-color: #fff;
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 16px;
height: 16px;
transition: .4s;
}
input:checked + .slider {
background-color: var(--primary-color);
}
input:checked + .slider:before {
transform: translateX(10px);
}
.slider.round {
border-radius: 20px;
}
.slider.round:before {
border-radius: 50%;
}
/* Dialog */
@ -287,38 +326,30 @@ x-dialog x-background {
z-index: 30;
transition: opacity 300ms;
will-change: opacity;
overflow: overlay;
padding: 10px 5px 20px;
overflow: scroll
}
x-dialog x-paper {
position: relative;
display: flex;
margin: auto;
flex-direction: column;
width: calc(100vw - 10px);
width: 400px;
z-index: 3;
border-radius: 30px;
max-width: 400px;
overflow: hidden;
box-sizing: border-box;
transition: transform 300ms;
will-change: transform;
}
#pair-device-dialog x-paper,
#edit-paired-devices-dialog x-paper,
#public-room-dialog x-paper,
#language-select-dialog x-paper {
position: absolute;
top: max(50%, 350px);
margin-top: -328.5px;
}
x-paper > .row:first-of-type {
background-color: var(--accent-color);
padding: 10px;
margin-bottom: 5px;
}
x-paper > .row:first-of-type h2 {
x-paper .dialog-title {
color: white;
}
@ -357,6 +388,10 @@ x-dialog a {
/* Pair Devices Dialog & Public Room Dialog */
#public-room-dialog x-paper {
width: 450px;
}
.input-key-container {
width: 100%;
display: flex;
@ -394,15 +429,15 @@ x-dialog a {
user-select: text;
display: inline-block;
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)));
letter-spacing: 18px;
text-indent: 15px;
margin: 10px 0;
}
.key-qr-code {
width: fit-content;
align-self: center;
margin-top: 15px;
margin-top: 5px;
margin-bottom: 10px;
}
@ -424,8 +459,8 @@ x-dialog hr {
}
.hr-note {
margin-top: 23px;
margin-bottom: 31px;
margin-top: 13px;
margin-bottom: 21px;
}
.hr-note hr {
@ -447,10 +482,6 @@ x-dialog hr {
text-transform: uppercase;
}
#pair-device-dialog x-background {
padding: 16px!important;
}
/* Edit Paired Devices Dialog */
.paired-devices-wrapper:empty:before {
content: attr(data-empty);
@ -474,6 +505,10 @@ x-dialog hr {
align-items: center;
}
.paired-device:empty {
padding: 47px;
}
.paired-device:not(:last-child) {
border-bottom: solid 4px var(--paired-device-color);
}
@ -489,30 +524,11 @@ x-dialog hr {
border-bottom: solid 2px rgba(128, 128, 128, 0.5);
opacity: 1;
}
.paired-device span {
width: 100%;
}
.paired-device > .button-wrapper {
display: flex;
height: 36px;
justify-content: space-between;
flex-direction: row;
align-items: center;
width: 100%;
}
.paired-device > .button-wrapper > label,
.paired-device > .button-wrapper > button {
display: flex;
align-items: center;
text-align: center;
white-space: nowrap;
justify-content: center;
width: 50%;
padding-left: 6px;
padding-right: 6px;
height: 36px;
.paired-device > .button-wrapper > * {
min-height: 38px;
padding-left: 5px;
padding-right: 5px;
}
.paired-device > .button-wrapper > :not(:last-child) {
@ -529,32 +545,17 @@ x-dialog hr {
}
/* button row*/
x-paper > .button-row {
.btn-row .btn {
margin: 3px;
flex-grow: 1;
height: 50px;
width: 120px; /* fixed width needed to ensure same width for all buttons */
}
x-paper > .btn-row {
margin: 5px 10px 10px;
}
x-paper > .button-row > .btn {
height: 100%;
width: 100%;
}
html:not([dir="rtl"]) x-paper > .button-row > .btn:not(:first-child) {
margin-right: 5px;
}
html:not([dir="rtl"]) x-paper > .button-row > .btn:not(:last-child) {
margin-left: 5px;
}
html[dir="rtl"] x-paper > .button-row > .btn:not(:first-child) {
margin-right: 5px;
}
html[dir="rtl"] x-paper > .button-row > .btn:not(:last-child) {
margin-left: 5px;
}
.language-buttons > button > span {
margin: 0 0.3em;
}
@ -597,7 +598,10 @@ x-dialog .dialog-subheader {
#send-text-dialog,
#receive-text-dialog {
font-size: 16px; /* prevents auto-zoom on edit */
font-size: 16px; /* prevents auto-zoom on edit */
}
.textarea.overflowing {
--shadow-color-rgb: var(--shadow-color-secondary-rgb);
--shadow-color-cover-rgb: var(--shadow-color-secondary-cover-rgb);
}
@ -607,10 +611,6 @@ x-dialog .dialog-subheader {
--shadow-color-cover-rgb: var(--shadow-color-dialog-cover-rgb);
}
#text-input:before {
opacity: 0.5;
}
/* Receive Text Dialog */
#receive-text-dialog #text {
@ -634,11 +634,82 @@ x-dialog .dialog-subheader {
pointer-events: none;
}
/* Do not call it 'share-panel', 'share-pannel' or 'sharepanel' as iOS Safari does not show any element with these classnames... */
.shr-panel {
min-width: 250px;
max-width: calc(100vw - 20px);
overflow: hidden;
color: white;
background-color: var(--primary-color);
background-image: linear-gradient(225deg, var(--accent-color) 0%, color-mix(in srgb, var(--accent-color) 60%, black) 100%);
}
.shr-panel > div {
margin: 4px 2px;
}
.shr-panel > div:not(:first-child) {
margin-top: 2px;
}
.shr-panel .thumb > div {
width: 36px;
height: 36px;
background: white;
border-radius: 6px;
margin-right: 6px;
}
.shr-panel .text-thumb svg {
width: 18px;
height: 36px;
}
.shr-panel .file-thumb svg {
width: 36px;
height: 36px;
}
.shr-panel .thumb .image-thumb {
background-size: cover;
border-radius: 6px;
background-position: center;
}
.shr-panel .btn {
height: 36px;
}
.share-descriptor {
justify-content: center;
}
.share-descriptor > span {
display: inline;
margin-bottom: 0;
margin-top: 0;
height: 20px;
max-width: 15rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.share-descriptor > span:first-child {
font-weight: bold;
}
.share-descriptor > span:not(:first-child) {
font-size: small;
}
#base64-paste-btn,
#base64-paste-dialog .textarea {
width: 100%;
height: 40vh;
border: solid 12px #438cff;
margin: 6px;
}
#base64-paste-dialog .textarea {

View file

@ -31,12 +31,65 @@ html {
}
.p1 {
padding: 5px;
}
.p2 {
padding: 10px;
}
.row-reverse {
.pb0 {
padding-bottom: 0;
}
.mx1 {
margin-left: 5px;
margin-right: 5px;
}
.m1 {
margin: 5px;
}
.cursive {
font-style: italic;
}
.wrap {
display: flex;
flex-direction: row-reverse;
flex-wrap: wrap;
}
.wrap-reverse {
display: flex;
flex-wrap: wrap-reverse;
}
.grow {
display: flex;
flex-grow: 1;
}
.grow-2 {
display: flex;
flex-grow: 2;
}
.shrink {
display: flex;
flex-shrink: 1;
}
.flex {
display: flex;
}
.align-center {
align-items: center;
}
.space-evenly {
justify-content: space-evenly;
}
.space-between {
@ -48,6 +101,11 @@ html {
flex-direction: row;
}
.row-reverse {
display: flex;
flex-direction: row-reverse;
}
.column {
display: flex;
flex-direction: column;
@ -59,10 +117,6 @@ html {
justify-content: center;
}
.grow {
flex-grow: 1;
}
.full {
position: absolute;
top: 0;
@ -76,7 +130,7 @@ html {
}
header {
position: absolute;
position: relative;
align-items: baseline;
padding: 8px 12px;
box-sizing: border-box;
@ -86,67 +140,95 @@ header {
right: 0;
}
header.overflow-hidden {
overflow: hidden;
}
header:not(.overflow-expanded) {
height: 56px;
}
header > * {
margin-left: 4px;
margin-right: 4px;
}
header > div {
header > * {
display: flex;
flex-direction: column;
align-self: flex-start;
touch-action: manipulation;
}
header > div .icon-button {
header > .icon-button {
height: 40px;
}
header * {
transition: all 300ms;
}
header > div > div {
#theme-wrapper > div {
display: flex;
flex-direction: column;
}
header > div:not(:hover) .icon-button:not(.selected) {
/* expand theme buttons */
#theme-wrapper:not(:hover) .icon-button:not(.selected) {
height: 0;
opacity: 0;
}
#theme-wrapper:hover::before {
border-radius: 20px;
background: currentColor;
opacity: 0.1;
background: var(--primary-color);
opacity: 0.2;
transition: opacity 300ms;
content: '';
position: absolute;
width: 40px;
height: 120px;
top: 0;
bottom: 0;
margin-top: 8px;
margin-bottom: 8px;
}
header > div:hover .icon-button.selected::before {
opacity: 0.1;
#theme-wrapper:hover .icon-button:not(.selected):hover:before {
opacity: 0.3;
}
#theme-wrapper:hover .icon-button.selected::before {
opacity: 0.3;
}
@media (pointer: coarse) {
header > div:hover .icon-button.selected:hover::before {
opacity: 0.2;
#theme-wrapper:hover .icon-button.selected:hover::before {
opacity: 0.3;
}
header > div .icon-button:not(.selected) {
#theme-wrapper .icon-button:not(.selected) {
height: 0;
opacity: 0;
pointer-events: none;
}
header > div > div {
#theme-wrapper > div {
flex-direction: column-reverse;
}
}
#expand > .icon {
transition: transform 150ms ease-out
}
html:not([dir="rtl"]) #expand.flipped > .icon {
transform: rotate(-90deg);
}
html[dir="rtl"] #expand.flipped > .icon {
transform: rotate(90deg);
}
[hidden] {
display: none !important;
}
@ -177,7 +259,7 @@ h1 {
}
h2 {
font-size: 24px;
font-size: 22px;
font-weight: 400;
letter-spacing: -.012em;
line-height: 32px;
@ -201,6 +283,10 @@ h3 {
text-align: center;
}
.text-white {
color: white !important;
}
.font-body1,
body {
font-size: 14px;
@ -276,19 +362,16 @@ x-noscript {
/* Animations */
/* Opacity for elements at keyframe 100% is set on element (default 1) */
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#center {
position: relative;
display: flex;
margin-top: 56px;
flex-direction: column-reverse;
flex-grow: 1;
justify-content: space-around;
@ -301,18 +384,10 @@ x-noscript {
/* Peers */
#x-peers-filler {
display: flex;
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;
@ -324,8 +399,6 @@ x-peers {
--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 */
@ -382,30 +455,35 @@ footer .logo {
margin-top: -10px;
}
.discovery-wrapper {
font-size: 14px;
margin: 15px auto auto;
.border {
border: 2px solid var(--border-color);
}
.panel {
font-size: 14px;
padding: 2px;
background-color: rgb(var(--bg-color));
transition: background-color 0.5s ease;
min-height: 24px;
}
.discovery-wrapper.column {
.panel.column {
border-radius: 16px;
}
.discovery-wrapper.row {
.panel.row {
border-radius: 12px;
}
/*You can be discovered wrapper*/
.discovery-wrapper > div:first-of-type {
.panel > div:first-of-type {
padding-left: 4px;
padding-right: 4px;
}
/* You can be discovered wrapper */
.discovery-wrapper {
margin: 15px auto auto;
}
.discovery-wrapper .badge {
word-break: keep-all;
@ -421,10 +499,6 @@ footer .logo {
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 {
--badge-color: var(--primary-color);
}
@ -447,8 +521,11 @@ footer .logo {
text-align: left;
border: none;
outline: none;
height: 20px;
max-width: 15em;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
cursor: text;
margin-bottom: -6px;
padding-bottom: 0.1rem;
@ -456,11 +533,10 @@ footer .logo {
border-right: solid 1rem transparent;
border-left: solid 1rem transparent;
background-clip: padding-box;
overflow: hidden;
z-index: 1;
}
#edit-pen {
.edit-pen {
width: 1rem;
height: 1rem;
margin-bottom: -2px;
@ -468,16 +544,16 @@ footer .logo {
}
html:not([dir="rtl"]) #display-name,
html:not([dir="rtl"]) #edit-pen {
html:not([dir="rtl"]) .edit-pen {
margin-left: -1rem;
}
html[dir="rtl"] #display-name,
html[dir="rtl"] #edit-pen {
html[dir="rtl"] .edit-pen {
margin-right: -1rem;
}
html[dir="rtl"] #edit-pen {
html[dir="rtl"] .edit-pen {
transform: rotateY(180deg);
}
@ -505,6 +581,11 @@ x-dialog:not([show]) x-background {
overflow: hidden;
}
.btn-small {
font-size: 12px;
line-height: 22px;
}
.btn[disabled] {
color: var(--btn-disabled-color);
cursor: not-allowed;
@ -531,6 +612,7 @@ x-dialog:not([show]) x-background {
left: 0;
right: 0;
bottom: 0;
z-index: -1;
opacity: 0;
background-color: var(--accent-color);
transition: opacity 300ms;
@ -538,27 +620,44 @@ x-dialog:not([show]) x-background {
.btn:not([disabled]):hover:before,
.icon-button:hover:before {
opacity: 0.1;
opacity: 0.3;
}
.btn[selected],
.icon-button[selected] {
opacity: 0.1;
opacity: 0.3;
}
.btn:focus:before,
.icon-button:focus:before {
opacity: 0.2;
opacity: 0.4;
}
.btn-round {
border-radius: 50%;
}
.btn-rounded {
border-radius: 12px;
}
.btn-small.btn-rounded {
border-radius: 6px;
}
.btn-grey {
background-color: var(--bg-color-secondary);
}
.btn-dark {
background-color: #262628;
}
.btn-primary {
background: var(--primary-color);
color: rgb(var(--bg-color));
}
button::-moz-focus-inner {
border: 0;
}
@ -686,16 +785,17 @@ canvas.circles {
}
x-toast {
display: flex;
justify-content: space-between;
position: absolute;
min-height: 48px;
top: 50px;
width: 100%;
max-width: 344px;
max-width: 400px;
background-color: rgb(var(--text-color));
color: var(--dialog-bg-color);
align-items: center;
box-sizing: border-box;
padding: 8px 24px;
padding: 8px;
z-index: 40;
transition: opacity 200ms, transform 300ms ease-out;
cursor: default;
@ -704,22 +804,34 @@ x-toast {
pointer-events: all;
}
x-toast:not([show]):not(:hover) {
x-toast.top-row {
top: 3px;
}
x-toast:not([show]) {
opacity: 0;
transform: translateY(-100px);
transform: translateY(calc(-100% + -55px));
}
x-toast span {
flex-grow: 1;
margin: auto 4px auto 10px
}
x-dialog[show] ~ div x-toast {
background-color: var(--lt-dialog-bg-color);
color: rgb(var(--lt-text-color));
}
/* Instructions */
x-instructions {
display: flex;
position: relative;
opacity: 0.5;
text-align: center;
margin-left: 10px;
margin-right: 10px;
display: flex;
margin: 50px 10px 0px;
flex-direction: column;
flex-grow: 1;
justify-content: center;
}
@ -735,12 +847,10 @@ x-instructions[drop-bg]:not([drop-peer]):before {
content: attr(data-drop-bg);
}
x-instructions p {
display: none;
}
x-peers:empty,
x-peers:empty~x-instructions {
opacity: 0 !important;
display: none;
}
@media (hover: none) and (pointer: coarse) {
@ -796,43 +906,70 @@ body {
/* Constant colors */
--primary-color: #4285f4;
--paired-device-color: #00a69c;
--public-room-color: #db8500;
--public-room-color: #ed9d01;
--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 */
--lt-text-color: 51,51,51;
--lt-dialog-bg-color: #fff;
--lt-bg-color: 255,255,255;
--lt-bg-color-secondary: #f2f2f2;
--lt-border-color: #a9a9a9;
--lt-badge-color: #a5a5a5;
--lt-shadow-color-secondary-rgb: 0,0,0;
--lt-shadow-color-secondary-cover-rgb: 242,242,242;
--lt-shadow-color-dialog-rgb: 0,0,0;
--lt-shadow-color-dialog-cover-rgb: 242,242,242;
/* Dark theme colors */
--dt-text-color: 238,238,238;
--dt-dialog-bg-color: #141414;
--dt-bg-color: 0,0,0;
--dt-bg-color-secondary: #262628;
--dt-border-color: #919191;
--dt-badge-color: #717171;
--dt-shadow-color-secondary-rgb: 255,255,255;
--dt-shadow-color-secondary-cover-rgb: 38,38,38;
--dt-shadow-color-dialog-rgb: 255,255,255;
--dt-shadow-color-dialog-cover-rgb: 38,38,38;
}
/* Light theme colors */
body {
--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;
--text-color: var(--lt-text-color);
--dialog-bg-color: var(--lt-dialog-bg-color);
--bg-color: var(--lt-bg-color);
--bg-color-secondary: var(--lt-bg-color-secondary);
--border-color: var(--lt-border-color);
--badge-color: var(--lt-badge-color);
--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;
--shadow-color-secondary-rgb: var(--lt-shadow-color-secondary-rgb);
--shadow-color-secondary-cover-rgb: var(--lt-shadow-color-secondary-cover-rgb);
--shadow-color-dialog-rgb: var(--lt-shadow-color-dialog-rgb);
--shadow-color-dialog-cover-rgb: var(--lt-shadow-color-dialog-cover-rgb);
}
/* Dark theme colors */
body.dark-theme {
--text-color: 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;
--text-color: var(--dt-text-color);
--dialog-bg-color: var(--dt-dialog-bg-color);
--bg-color: var(--dt-bg-color);
--bg-color-secondary: var(--dt-bg-color-secondary);
--border-color: var(--dt-border-color);
--badge-color: var(--dt-badge-color);
--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;
--shadow-color-secondary-rgb: var(--dt-shadow-color-secondary-rgb);
--shadow-color-secondary-cover-rgb: var(--dt-shadow-color-secondary-cover-rgb);
--shadow-color-dialog-rgb: var(--dt-shadow-color-dialog-rgb);
--shadow-color-dialog-cover-rgb: var(--dt-shadow-color-dialog-cover-rgb);
}
/* Styles for users who prefer dark mode at the OS level */
@ -840,33 +977,33 @@ body.dark-theme {
/* 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;
--text-color: var(--dt-text-color);
--dialog-bg-color: var(--dt-dialog-bg-color);
--bg-color: var(--dt-bg-color);
--bg-color-secondary: var(--dt-bg-color-secondary);
--border-color: var(--dt-border-color);
--badge-color: var(--dt-badge-color);
--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;
--shadow-color-secondary-rgb: var(--dt-shadow-color-secondary-rgb);
--shadow-color-secondary-cover-rgb: var(--dt-shadow-color-secondary-cover-rgb);
--shadow-color-dialog-rgb: var(--dt-shadow-color-dialog-rgb);
--shadow-color-dialog-cover-rgb: var(--dt-shadow-color-dialog-cover-rgb);
}
/* 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;
--text-color: var(--lt-text-color);
--dialog-bg-color: var(--lt-dialog-bg-color);
--bg-color: var(--lt-bg-color);
--bg-color-secondary: var(--lt-bg-color-secondary);
--border-color: var(--lt-border-color);
--badge-color: var(--lt-badge-color);
--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;
--shadow-color-secondary-rgb: var(--lt-shadow-color-secondary-rgb);
--shadow-color-secondary-cover-rgb: var(--lt-shadow-color-secondary-cover-rgb);
--shadow-color-dialog-rgb: var(--lt-shadow-color-dialog-rgb);
--shadow-color-dialog-cover-rgb: var(--lt-shadow-color-dialog-cover-rgb);
}
}
@ -877,28 +1014,6 @@ body {
transition: background-color 0.5s ease;
}
x-dialog x-paper {
background-color: var(--dialog-bg-color);
}
.textarea {
color: rgb(var(--text-color)) !important;
background-color: var(--bg-color-secondary) !important;
}
.textarea * {
margin: 0 !important;
padding: 0 !important;
color: unset !important;
background: unset !important;
border: unset !important;
opacity: unset !important;
font-family: inherit !important;
font-size: inherit !important;
font-style: unset !important;
font-weight: unset !important;
}
/* Gradient for wifi-tether icon */
#primaryGradient .start-color {
stop-color: var(--primary-color);
@ -946,8 +1061,8 @@ html {
/* webkit scrollbar style*/
::-webkit-scrollbar{
width: 4px;
height: 4px;
width: 0;
height: 0;
}
::-webkit-scrollbar-thumb{