diff --git a/css/client.css b/css/client.css index ec2f251..f045851 100644 --- a/css/client.css +++ b/css/client.css @@ -60,3 +60,24 @@ .ClientView .actions img { height: 100%; } + +.InstallClientView .instructions button { + background-repeat: no-repeat; + background-position: center; + background-color: var(--link); + padding: 4px; + border-radius: 4px; + border: none; + width: 24px; + height: 24px; + margin: 8px; + vertical-align: middle; +} + +.InstallClientView .instructions button.copy { + background-image: url('../images/copy.svg'); +} + +.InstallClientView .instructions button.tick { + background-image: url('../images/tick.svg'); +} diff --git a/src/open/ClientListViewModel.js b/src/open/ClientListViewModel.js index 2d34166..96d2737 100644 --- a/src/open/ClientListViewModel.js +++ b/src/open/ClientListViewModel.js @@ -55,7 +55,8 @@ export class ClientListViewModel extends ViewModel { _filterClients() { this.clientList = this._clients.filter(client => { - const isStable = this.platforms.map(p => client.getMaturity(p)).includes(Maturity.Stable); + const platformMaturities = this.platforms.map(p => client.getMaturity(p)); + const isStable = platformMaturities.includes(Maturity.Stable) || platformMaturities.includes(Maturity.Beta); const isSupported = client.platforms.some(p => this.platforms.includes(p)); if (!this._showExperimental && !isStable) { return false; diff --git a/src/open/ClientView.js b/src/open/ClientView.js index 696a011..dee2ec4 100644 --- a/src/open/ClientView.js +++ b/src/open/ClientView.js @@ -15,7 +15,7 @@ limitations under the License. */ import {TemplateView} from "../utils/TemplateView.js"; -import {copyButton} from "../utils/copy.js"; +import {copy} from "../utils/copy.js"; import {text} from "../utils/html.js"; function formatPlatforms(platforms) { @@ -66,10 +66,18 @@ class InstallClientView extends TemplateView { const children = []; if (vm.textInstructions) { - children.push(t.p({}, vm.textInstructions)); - if (vm.copyString) { - children.push(t.p(copyButton(t, () => vm.copyString, "Copy invite", "fullwidth primary"))); - } + const copyButton = t.button({ + className: "copy", + onClick: evt => { + if (copy(vm.copyString, copyButton.parentElement)) { + copyButton.className = "tick"; + setTimeout(() => { + copyButton.className = "copy"; + }, 2000); + } + } + }); + children.push(t.p({className: "instructions"}, [vm.textInstructions, copyButton])); } const actions = t.div({className: "actions"}, vm.actions.map(a => { @@ -78,6 +86,7 @@ class InstallClientView extends TemplateView { case "play-store": badgeUrl = "images/google-play-us.svg"; break; case "fdroid": badgeUrl = "images/fdroid-badge.png"; break; case "apple-app-store": badgeUrl = "images/app-store-us-alt.svg"; break; + case "flathub": badgeUrl = "images/flathub-badge.svg"; break; } return t.a({ href: a.url, diff --git a/src/open/ClientViewModel.js b/src/open/ClientViewModel.js index b47ce69..d75b45c 100644 --- a/src/open/ClientViewModel.js +++ b/src/open/ClientViewModel.js @@ -67,15 +67,13 @@ export class ClientViewModel extends ViewModel { }); } } - if (actions.length === 0) { - actions.push({ - label: `Visit app homepage`, - url: client.homepage, - primary: true, - kind: "homepage", - activated: () => {}, - }); - } + actions.push({ + label: `Visit app homepage`, + url: client.homepage, + primary: true, + kind: "homepage", + activated: () => {}, + }); return actions; } diff --git a/src/open/clients/Weechat.js b/src/open/clients/Weechat.js index 8e66559..2a018b7 100644 --- a/src/open/clients/Weechat.js +++ b/src/open/clients/Weechat.js @@ -20,7 +20,6 @@ import {Maturity, Platform, LinkKind, WebsiteLink} from "../types.js"; * Information on how to deep link to a given matrix client. */ export class Weechat { - /* should only contain alphanumerical and -_, no dots (needs to be usable as css class) */ get id() { return "weechat"; } getName(platform) { return "Weechat"; } get icon() { return "images/client-icons/weechat.svg"; } diff --git a/src/open/clients/index.js b/src/open/clients/index.js index a939543..657982e 100644 --- a/src/open/clients/index.js +++ b/src/open/clients/index.js @@ -16,10 +16,14 @@ limitations under the License. import {Element} from "./Element.js"; import {Weechat} from "./Weechat.js"; +import {Nheko} from "./Nheko.js"; +import {Fractal} from "./Fractal.js"; export function createClients() { return [ new Element(), new Weechat(), + new Nheko(), + new Fractal(), ]; -} \ No newline at end of file +} diff --git a/src/utils/copy.js b/src/utils/copy.js index 1a0773c..c417bfd 100644 --- a/src/utils/copy.js +++ b/src/utils/copy.js @@ -22,15 +22,20 @@ function selectNode(node) { selection.addRange(range); } +export function copy(text, parent) { + const span = document.createElement("span"); + span.innerText = text; + parent.appendChild(span); + selectNode(span); + const result = document.execCommand("copy"); + parent.removeChild(span); + return result; +} + export function copyButton(t, getCopyText, label, classNames) { return t.button({className: `${classNames} icon copy`, onClick: evt => { const button = evt.target; - const text = getCopyText(); - const span = document.createElement("span"); - span.innerText = text; - button.parentElement.appendChild(span); - selectNode(span); - if (document.execCommand("copy")) { + if (copy(getCopyText(), button)) { button.innerText = "Copied!"; button.classList.remove("copy"); button.classList.add("tick"); @@ -40,6 +45,5 @@ export function copyButton(t, getCopyText, label, classNames) { button.innerText = label; }, 2000); } - span.parentElement.removeChild(span); }}, label); }