Merge pull request #2102 from maxberger/master
UI: More compact layour, auto-scroll to user in shares
This commit is contained in:
@@ -19,14 +19,17 @@ main {
|
|||||||
|
|
||||||
.container {
|
.container {
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 450px;
|
min-height: 500px;
|
||||||
width: 350px;
|
width: 95%;
|
||||||
|
max-width: 450px;
|
||||||
|
box-sizing: border-box;
|
||||||
transition: .2s;
|
transition: .2s;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 20px 40px;
|
padding: 1ex 1em 1ex 1em;
|
||||||
background: #fff;
|
background: rgb(250, 250, 250);
|
||||||
border: 1px solid #dadce0;
|
border: 1px solid #dadce0;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
box-shadow: 2px 2px 3px #0000001a;
|
||||||
display: block;
|
display: block;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@@ -39,12 +42,55 @@ main {
|
|||||||
color: #484848;
|
color: #484848;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container h2 {
|
table {
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 1ex 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #484848;
|
font-size: 0.8em;
|
||||||
font-size: 14pt;
|
padding: 0.2ex 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
border-bottom: 1px solid #dadce0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #666;
|
||||||
|
font-weight: normal;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.fill {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
details {
|
||||||
|
border: 1px solid #dadce0;
|
||||||
|
border-radius: 0.7ex;
|
||||||
|
padding: 0.5ex 0.7ex;
|
||||||
|
margin-bottom: 1ex;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.2ex 0;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary:hover {
|
||||||
|
color: #2494fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loginscene .infcloudlink {
|
#loginscene .infcloudlink {
|
||||||
@@ -394,6 +440,7 @@ select {
|
|||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.inline {
|
input.inline {
|
||||||
@@ -402,7 +449,7 @@ input.inline {
|
|||||||
|
|
||||||
input[type=text],
|
input[type=text],
|
||||||
input[type=password] {
|
input[type=password] {
|
||||||
width: calc(100% - 30px);
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:active,
|
input:active,
|
||||||
@@ -421,13 +468,22 @@ input:focus-visible {
|
|||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td .url-input-wrapper input {
|
||||||
|
min-height: 4ex;
|
||||||
|
}
|
||||||
|
|
||||||
.url-input-wrapper input {
|
.url-input-wrapper input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 40px;
|
||||||
padding-right: 45px !important;
|
min-height: 6ex;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
padding-top: 0.5ex;
|
||||||
|
padding-bottom: 0.5ex;
|
||||||
|
padding-right: 22px !important;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
|
height: 2ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#collectionsscene article .url-input-wrapper {
|
#collectionsscene article .url-input-wrapper {
|
||||||
@@ -436,7 +492,7 @@ input:focus-visible {
|
|||||||
|
|
||||||
.copy-btn {
|
.copy-btn {
|
||||||
flex: none;
|
flex: none;
|
||||||
margin-left: -38px;
|
margin-left: -30px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: #2494fe;
|
color: #2494fe;
|
||||||
@@ -539,6 +595,9 @@ button.inline {
|
|||||||
padding-right: 1px;
|
padding-right: 1px;
|
||||||
min-width: 2em;
|
min-width: 2em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
@@ -547,22 +606,10 @@ button.inline {
|
|||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#collectionsscene article {
|
|
||||||
height: auto;
|
|
||||||
min-height: 375px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: 280px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#collectionsscene ul {
|
#collectionsscene ul {
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#logoutview span {
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pill {
|
.pill {
|
||||||
@@ -573,12 +620,12 @@ button.inline {
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
vertical-align: baseline;
|
vertical-align: middle;
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.7ex;
|
||||||
background-color: #6c757d;
|
background-color: #6c757d;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
width: 1.4em;
|
min-width: 1.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
|
|||||||
@@ -158,10 +158,11 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr data-name="sharetokenrowtemplate" class="hidden">
|
<tr data-name="sharetokenrowtemplate" class="hidden">
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img src="css/icons/edit.svg"
|
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img
|
||||||
class="small_icon" alt="Edit"></button>
|
src="css/icons/edit.svg" class="small_icon" alt="Edit"></button>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span><span data-name="conversion">⟿</span></td>
|
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span><span
|
||||||
|
data-name="conversion">⟿</span></td>
|
||||||
<td>
|
<td>
|
||||||
<div class="url-input-wrapper">
|
<div class="url-input-wrapper">
|
||||||
<input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall">
|
<input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall">
|
||||||
@@ -169,14 +170,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img src="css/icons/delete.svg"
|
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img
|
||||||
class="small_icon" alt="Delete"></button>
|
src="css/icons/delete.svg" class="small_icon" alt="Delete"></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><button type="button" class="blue inline" data-name="sharebytoken" title="New Share by Token"><img src="css/icons/new.svg"
|
<td><button type="button" class="blue inline" data-name="sharebytoken" title="New Share by Token"><img
|
||||||
class="small_icon" alt="New Share by Token"></button>
|
src="css/icons/new.svg" class="small_icon" alt="New Share by Token"></button>
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="fill"></td>
|
||||||
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -189,10 +193,11 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr data-name="sharemaprowtemplate" class="hidden">
|
<tr data-name="sharemaprowtemplate" class="hidden">
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img src="css/icons/edit.svg"
|
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img
|
||||||
class="small_icon" alt="Edit"></button>
|
src="css/icons/edit.svg" class="small_icon" alt="Edit"></button>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span><span data-name="conversion">⟿</span></td>
|
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span><span
|
||||||
|
data-name="conversion">⟿</span></td>
|
||||||
<td>
|
<td>
|
||||||
<div class="url-input-wrapper">
|
<div class="url-input-wrapper">
|
||||||
<input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall">
|
<input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall">
|
||||||
@@ -200,8 +205,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img src="css/icons/delete.svg"
|
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img
|
||||||
class="small_icon" alt="Delete"></button>
|
src="css/icons/delete.svg" class="small_icon" alt="Delete"></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -210,6 +215,9 @@
|
|||||||
<img src="css/icons/new.svg" class="small_icon" alt="New Share by Map">
|
<img src="css/icons/new.svg" class="small_icon" alt="New Share by Map">
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="fill"></td>
|
||||||
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ import { SERVER } from "../constants.js";
|
|||||||
* Handles the display of URLs in input fields.
|
* Handles the display of URLs in input fields.
|
||||||
*/
|
*/
|
||||||
export class UrlTextHandler {
|
export class UrlTextHandler {
|
||||||
|
/** @type {?HTMLCanvasElement} */
|
||||||
|
static _canvas = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {HTMLInputElement} element The input element to handle.
|
* @param {HTMLInputElement} element The input element to handle.
|
||||||
* @param {HTMLButtonElement} copyButton The button element for copying.
|
* @param {HTMLButtonElement} copyButton The button element for copying.
|
||||||
@@ -32,9 +35,14 @@ export class UrlTextHandler {
|
|||||||
constructor(element, copyButton) {
|
constructor(element, copyButton) {
|
||||||
this._element = element;
|
this._element = element;
|
||||||
this._copyButton = copyButton;
|
this._copyButton = copyButton;
|
||||||
|
this._userIndex = -1;
|
||||||
|
|
||||||
this._element.addEventListener("focusin", () => {
|
this._element.addEventListener("focusin", () => {
|
||||||
this._element.setSelectionRange(0, 99999);
|
this._element.setSelectionRange(0, 99999);
|
||||||
|
this._updateScroll();
|
||||||
|
});
|
||||||
|
this._element.addEventListener("focusout", () => {
|
||||||
|
this._updateScroll();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this._copyButton) {
|
if (this._copyButton) {
|
||||||
@@ -42,6 +50,37 @@ export class UrlTextHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateScroll() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this._updateScroll_now();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the scroll position of the input field.
|
||||||
|
*/
|
||||||
|
_updateScroll_now() {
|
||||||
|
if (this._userIndex === -1) {
|
||||||
|
this._element.scrollLeft = this._element.scrollWidth;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let scrollPos = this._element.scrollWidth;
|
||||||
|
const value = this._element.value;
|
||||||
|
const style = window.getComputedStyle(this._element);
|
||||||
|
if (!UrlTextHandler._canvas) {
|
||||||
|
UrlTextHandler._canvas = document.createElement("canvas");
|
||||||
|
}
|
||||||
|
const context = UrlTextHandler._canvas.getContext("2d");
|
||||||
|
if (context) {
|
||||||
|
context.font = style.font;
|
||||||
|
const prefix = value.substring(0, this._userIndex);
|
||||||
|
scrollPos = context.measureText(prefix).width;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._element.scrollLeft = scrollPos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy the current value of the input to the clipboard.
|
* Copy the current value of the input to the clipboard.
|
||||||
*/
|
*/
|
||||||
@@ -76,10 +115,33 @@ export class UrlTextHandler {
|
|||||||
} else {
|
} else {
|
||||||
this._element.value = href;
|
this._element.value = href;
|
||||||
}
|
}
|
||||||
|
this._update_username_index();
|
||||||
|
this._updateScroll();
|
||||||
|
}
|
||||||
|
|
||||||
// Needs timeout to work correctly.
|
/**
|
||||||
setTimeout(() => {
|
* Update the username index.
|
||||||
this._element.scrollLeft = this._element.scrollWidth;
|
*/
|
||||||
}, 0);
|
_update_username_index() {
|
||||||
|
const value = this._element.value;
|
||||||
|
this._userIndex = -1;
|
||||||
|
try {
|
||||||
|
const url = new URL(value);
|
||||||
|
const path = url.pathname;
|
||||||
|
const parts = path.split("/").filter(p => p !== "");
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
const user = parts[parts.length - 2];
|
||||||
|
const search = "/" + user + "/";
|
||||||
|
const pathIndex = path.lastIndexOf(search);
|
||||||
|
if (pathIndex !== -1) {
|
||||||
|
const fullIndex = value.lastIndexOf(path);
|
||||||
|
if (fullIndex !== -1) {
|
||||||
|
this._userIndex = fullIndex + pathIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this._userIndex = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user