polish create page

This commit is contained in:
Bruno Windels 2020-12-04 15:31:03 +01:00
parent e69b92418f
commit 2ecdf32356
5 changed files with 84 additions and 9 deletions

View file

@ -3,3 +3,11 @@
word-break: break-all; word-break: break-all;
text-align: center; text-align: center;
} }
.CreateLinkView form {
margin-top: 36px;
}
.CreateLinkView form > *:not(:first-child) {
margin-top: 24px;
}

View file

@ -47,7 +47,6 @@ body {
height: 100%; height: 100%;
width: 100%; width: 100%;
font-size: 14px; font-size: 14px;
line-height: 24px;
color: var(--font); color: var(--font);
padding: 120px 0 0 0; padding: 120px 0 0 0;
margin: 0; margin: 0;
@ -142,9 +141,8 @@ button.text:hover {
text-decoration: none; text-decoration: none;
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
padding: 8px; padding: 12px 8px;
margin: 8px 0; margin: 8px 0;
line-height: 24px;
} }
.secondary { .secondary {
@ -158,6 +156,23 @@ button.text:hover {
border-radius: 32px; border-radius: 32px;
} }
.primary.icon {
background-repeat: no-repeat;
background-position: 12px center;
}
.icon.link {
background-image: url('../images/link.svg');
}
.icon.tick {
background-image: url('../images/tick.svg');
}
.icon.copy {
background-image: url('../images/copy.svg');
}
button.primary, input[type='submit'].primary, button.secondary, input[type='submit'].secondary { button.primary, input[type='submit'].primary, button.secondary, input[type='submit'].secondary {
border: none; border: none;
font-size: inherit; font-size: inherit;

View file

@ -58,6 +58,15 @@ export const LinkKind = createEnum(
) )
export class Link { export class Link {
static validateIdentifier(identifier) {
return !!(
USERID_PATTERN.exec(identifier) ||
ROOMALIAS_PATTERN.exec(identifier) ||
ROOMID_PATTERN.exec(identifier) ||
GROUPID_PATTERN.exec(identifier)
);
}
static parse(fragment) { static parse(fragment) {
if (!fragment) { if (!fragment) {
return null; return null;

View file

@ -17,23 +17,53 @@ limitations under the License.
import {TemplateView} from "../utils/TemplateView.js"; import {TemplateView} from "../utils/TemplateView.js";
import {PreviewView} from "../preview/PreviewView.js"; import {PreviewView} from "../preview/PreviewView.js";
function selectNode(node) {
let selection = window.getSelection();
selection.removeAllRanges();
let range = document.createRange();
range.selectNode(copyNode);
selection.addRange(range);
}
function copyButton(t, copyNode, label, classNames) {
return t.button({className: `${classNames} icon copy`, onClick: evt => {
const button = evt.target;
selectNode(copyNode);
if (document.execCommand("copy")) {
button.innerText = "Copied!";
button.classList.remove("copy");
button.classList.add("tick");
setTimeout(() => {
button.classList.remove("tick");
button.classList.add("copy");
button.innerText = label;
}, 2000);
}
}}, label);
}
export class CreateLinkView extends TemplateView { export class CreateLinkView extends TemplateView {
render(t, vm) { render(t, vm) {
const link = t.a({href: vm => vm.linkUrl}, vm => vm.linkUrl);
return t.div({className: "CreateLinkView card"}, [ return t.div({className: "CreateLinkView card"}, [
t.h1( t.h1(
{className: {hidden: vm => vm.previewViewModel}}, {className: {hidden: vm => vm.previewViewModel}},
"Create shareable links to Matrix rooms, users or messages without being tied to any app" "Create shareable links to Matrix rooms, users or messages without being tied to any app"
), ),
t.mapView(vm => vm.previewViewModel, childVM => childVM ? new PreviewView(childVM) : null), t.mapView(vm => vm.previewViewModel, childVM => childVM ? new PreviewView(childVM) : null),
t.h2({className: {hidden: vm => !vm.linkUrl}}, t.a({href: vm => vm.linkUrl}, vm => vm.linkUrl)), t.div({className: {hidden: vm => !vm.linkUrl}}, [
t.form({action: "#", onSubmit: evt => this._onSubmit(evt)}, [ t.h2(link),
t.div(copyButton(t, link, "Copy link", "fullwidth primary")),
]),
t.form({action: "#", onSubmit: evt => this._onSubmit(evt), className: {hidden: vm => vm.linkUrl}}, [
t.div(t.input({ t.div(t.input({
className: "fullwidth large", className: "fullwidth large",
type: "text", type: "text",
name: "identifier", name: "identifier",
placeholder: "#room:example.com, @user:example.com" placeholder: "#room:example.com, @user:example.com",
onChange: evt => this._onIdentifierChange(evt)
})), })),
t.div(t.input({className: "primary fullwidth", type: "submit", value: "Create link"})) t.div(t.input({className: "primary fullwidth icon link", type: "submit", value: "Create link"}))
]), ]),
]); ]);
} }
@ -44,4 +74,13 @@ export class CreateLinkView extends TemplateView {
const identifier = form.elements.identifier.value; const identifier = form.elements.identifier.value;
this.value.createLink(identifier); this.value.createLink(identifier);
} }
}
_onIdentifierChange(evt) {
const inputField = evt.target;
if (!this.value.validateIdentifier(inputField.value)) {
inputField.setCustomValidity("That doesn't seem valid. Try #room:example.com, @user:example.com or +group:example.com.");
} else {
inputField.setCustomValidity("");
}
}
}

View file

@ -24,6 +24,10 @@ export class CreateLinkViewModel extends ViewModel {
this.previewViewModel = null; this.previewViewModel = null;
} }
validateIdentifier(identifier) {
return Link.validateIdentifier(identifier);
}
async createLink(identifier) { async createLink(identifier) {
this._link = Link.parse(identifier); this._link = Link.parse(identifier);
if (this._link) { if (this._link) {
@ -45,4 +49,4 @@ export class CreateLinkViewModel extends ViewModel {
return `${this.origin}/#${this._link.toFragment()}`; return `${this.origin}/#${this._link.toFragment()}`;
} }
} }
} }