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 {
|
||||
height: auto;
|
||||
min-height: 450px;
|
||||
width: 350px;
|
||||
min-height: 500px;
|
||||
width: 95%;
|
||||
max-width: 450px;
|
||||
box-sizing: border-box;
|
||||
transition: .2s;
|
||||
overflow: hidden;
|
||||
padding: 20px 40px;
|
||||
background: #fff;
|
||||
padding: 1ex 1em 1ex 1em;
|
||||
background: rgb(250, 250, 250);
|
||||
border: 1px solid #dadce0;
|
||||
border-radius: 8px;
|
||||
box-shadow: 2px 2px 3px #0000001a;
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
margin: 0 auto;
|
||||
@@ -39,12 +42,55 @@ main {
|
||||
color: #484848;
|
||||
}
|
||||
|
||||
.container h2 {
|
||||
margin: 0;
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1ex 0;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
text-align: left;
|
||||
color: #484848;
|
||||
font-size: 14pt;
|
||||
font-size: 0.8em;
|
||||
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 {
|
||||
@@ -394,6 +440,7 @@ select {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
outline: none !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input.inline {
|
||||
@@ -402,7 +449,7 @@ input.inline {
|
||||
|
||||
input[type=text],
|
||||
input[type=password] {
|
||||
width: calc(100% - 30px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input:active,
|
||||
@@ -421,13 +468,22 @@ input:focus-visible {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
td .url-input-wrapper input {
|
||||
min-height: 4ex;
|
||||
}
|
||||
|
||||
.url-input-wrapper input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-right: 45px !important;
|
||||
min-width: 40px;
|
||||
min-height: 6ex;
|
||||
padding-left: 0.5em;
|
||||
padding-top: 0.5ex;
|
||||
padding-bottom: 0.5ex;
|
||||
padding-right: 22px !important;
|
||||
box-sizing: border-box;
|
||||
width: 100% !important;
|
||||
margin-bottom: 0 !important;
|
||||
height: 2ex;
|
||||
}
|
||||
|
||||
#collectionsscene article .url-input-wrapper {
|
||||
@@ -436,7 +492,7 @@ input:focus-visible {
|
||||
|
||||
.copy-btn {
|
||||
flex: none;
|
||||
margin-left: -38px;
|
||||
margin-left: -30px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #2494fe;
|
||||
@@ -539,6 +595,9 @@ button.inline {
|
||||
padding-right: 1px;
|
||||
min-width: 2em;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
@@ -547,22 +606,10 @@ button.inline {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
#collectionsscene article {
|
||||
height: auto;
|
||||
min-height: 375px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 280px !important;
|
||||
}
|
||||
|
||||
#collectionsscene ul {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
#logoutview span {
|
||||
padding: 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.pill {
|
||||
@@ -573,12 +620,12 @@ button.inline {
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: 0.375rem;
|
||||
vertical-align: middle;
|
||||
border-radius: 0.7ex;
|
||||
background-color: #6c757d;
|
||||
color: #fff;
|
||||
margin: 0 2px;
|
||||
width: 1.4em;
|
||||
min-width: 1.3em;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
|
||||
@@ -158,10 +158,11 @@
|
||||
<tbody>
|
||||
<tr data-name="sharetokenrowtemplate" class="hidden">
|
||||
<td>
|
||||
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img src="css/icons/edit.svg"
|
||||
class="small_icon" alt="Edit"></button>
|
||||
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img
|
||||
src="css/icons/edit.svg" class="small_icon" alt="Edit"></button>
|
||||
</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>
|
||||
<div class="url-input-wrapper">
|
||||
<input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall">
|
||||
@@ -169,14 +170,17 @@
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img src="css/icons/delete.svg"
|
||||
class="small_icon" alt="Delete"></button>
|
||||
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img
|
||||
src="css/icons/delete.svg" class="small_icon" alt="Delete"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><button type="button" class="blue inline" data-name="sharebytoken" title="New Share by Token"><img src="css/icons/new.svg"
|
||||
class="small_icon" alt="New Share by Token"></button>
|
||||
<td><button type="button" class="blue inline" data-name="sharebytoken" title="New Share by Token"><img
|
||||
src="css/icons/new.svg" class="small_icon" alt="New Share by Token"></button>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="fill"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -189,10 +193,11 @@
|
||||
<tbody>
|
||||
<tr data-name="sharemaprowtemplate" class="hidden">
|
||||
<td>
|
||||
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img src="css/icons/edit.svg"
|
||||
class="small_icon" alt="Edit"></button>
|
||||
<button type="button" class="blue inline" data-name="edit" title="Edit Share"><img
|
||||
src="css/icons/edit.svg" class="small_icon" alt="Edit"></button>
|
||||
</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>
|
||||
<div class="url-input-wrapper">
|
||||
<input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall">
|
||||
@@ -200,8 +205,8 @@
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img src="css/icons/delete.svg"
|
||||
class="small_icon" alt="Delete"></button>
|
||||
<button type="button" class="red inline" data-name="delete" title="Delete Share"><img
|
||||
src="css/icons/delete.svg" class="small_icon" alt="Delete"></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -210,6 +215,9 @@
|
||||
<img src="css/icons/new.svg" class="small_icon" alt="New Share by Map">
|
||||
</button>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="fill"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -25,6 +25,9 @@ import { SERVER } from "../constants.js";
|
||||
* Handles the display of URLs in input fields.
|
||||
*/
|
||||
export class UrlTextHandler {
|
||||
/** @type {?HTMLCanvasElement} */
|
||||
static _canvas = null;
|
||||
|
||||
/**
|
||||
* @param {HTMLInputElement} element The input element to handle.
|
||||
* @param {HTMLButtonElement} copyButton The button element for copying.
|
||||
@@ -32,9 +35,14 @@ export class UrlTextHandler {
|
||||
constructor(element, copyButton) {
|
||||
this._element = element;
|
||||
this._copyButton = copyButton;
|
||||
this._userIndex = -1;
|
||||
|
||||
this._element.addEventListener("focusin", () => {
|
||||
this._element.setSelectionRange(0, 99999);
|
||||
this._updateScroll();
|
||||
});
|
||||
this._element.addEventListener("focusout", () => {
|
||||
this._updateScroll();
|
||||
});
|
||||
|
||||
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.
|
||||
*/
|
||||
@@ -76,10 +115,33 @@ export class UrlTextHandler {
|
||||
} else {
|
||||
this._element.value = href;
|
||||
}
|
||||
this._update_username_index();
|
||||
this._updateScroll();
|
||||
}
|
||||
|
||||
// Needs timeout to work correctly.
|
||||
setTimeout(() => {
|
||||
this._element.scrollLeft = this._element.scrollWidth;
|
||||
}, 0);
|
||||
/**
|
||||
* Update the username index.
|
||||
*/
|
||||
_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