Merge pull request #171 from matrix-org/bwindels/addnewversion
Merge new version
14
.editorconfig
Normal file
@ -0,0 +1,14 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
# [*.{js,py}]
|
19
.eslintrc.js
@ -1,7 +1,14 @@
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"matrix-org/ts",
|
||||
"matrix-org/react",
|
||||
],
|
||||
}
|
||||
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
};
|
||||
|
33
.gitignore
vendored
@ -1,31 +1,2 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# development
|
||||
bundle.js
|
||||
bundle.js.map
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
.vercel
|
||||
|
||||
storybook-static
|
||||
node_modules
|
||||
build
|
||||
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
stories: ['../src/**/*.stories.tsx'],
|
||||
addons: [
|
||||
'@storybook/preset-create-react-app',
|
||||
'@storybook/addon-actions',
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-storysource',
|
||||
'@storybook/addon-viewport/register',
|
||||
'@storybook/addon-a11y/register',
|
||||
'@storybook/addon-knobs/register',
|
||||
'@storybook/addon-actions/register',
|
||||
'storybook-addon-designs',
|
||||
'@storybook/addon-backgrounds/register',
|
||||
],
|
||||
};
|
||||
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { addDecorator } from '@storybook/react';
|
||||
import { withA11y } from '@storybook/addon-a11y';
|
||||
import { withKnobs } from '@storybook/addon-knobs';
|
||||
import { withDesign } from 'storybook-addon-designs'
|
||||
import { addParameters } from '@storybook/react';
|
||||
|
||||
import SingleColumn from '../src/layouts/SingleColumn';
|
||||
|
||||
// Default styles
|
||||
import "../src/index.scss";
|
||||
|
||||
addDecorator(
|
||||
storyFn => <SingleColumn>{storyFn()}</SingleColumn>
|
||||
);
|
||||
|
||||
addDecorator(withA11y);
|
||||
|
||||
addDecorator(withKnobs);
|
||||
|
||||
addDecorator(withDesign);
|
||||
|
||||
addParameters({
|
||||
backgrounds: [
|
||||
{name: 'light', value: '#F4F4F4', default: true},
|
||||
{name: 'white', value: '#FFFFFF'},
|
||||
],
|
||||
});
|
||||
|
82
css/client.css
Normal file
@ -0,0 +1,82 @@
|
||||
.ClientListView h2 {
|
||||
text-align: center;
|
||||
margin: 18px 0;
|
||||
}
|
||||
|
||||
.ClientListView .filterOption {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.ClientView {
|
||||
border: 1px solid #E6E6E6;
|
||||
border-radius: 8px;
|
||||
margin: 16px 0;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.ClientView .header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ClientView .description {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ClientView h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ClientView .clientIcon {
|
||||
border-radius: 8px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.ClientView .platforms {
|
||||
background-image: url('../images/platform-icon.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 center;
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.ClientView .actions a.badge {
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
margin: 8px 16px 8px 0;
|
||||
}
|
||||
|
||||
.ClientView .actions img {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ClientView .back {
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.InstallClientView .instructions button {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: transparent;
|
||||
padding: 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-dark.svg');
|
||||
}
|
||||
|
13
css/create.css
Normal file
@ -0,0 +1,13 @@
|
||||
.CreateLinkView h2 {
|
||||
padding: 0 40px;
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.CreateLinkView form {
|
||||
margin-top: 36px;
|
||||
}
|
||||
|
||||
.CreateLinkView form > *:not(:first-child) {
|
||||
margin-top: 24px;
|
||||
}
|
218
css/main.css
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import url('spinner.css');
|
||||
@import url('client.css');
|
||||
@import url('preview.css');
|
||||
@import url('create.css');
|
||||
@import url('open.css');
|
||||
|
||||
:root {
|
||||
--app-background: #f4f4f4;
|
||||
--background: #ffffff;
|
||||
--foreground: #000000;
|
||||
--font: #333333;
|
||||
--grey: #666666;
|
||||
--accent: #0098d4;
|
||||
--error: #d6001c;
|
||||
--link: #0098d4;
|
||||
--borders: #f4f4f4;
|
||||
--lightgrey: #E6E6E6;
|
||||
--spinner-stroke-size: 2px;
|
||||
}
|
||||
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--app-background);
|
||||
background-image: url('../images/background.svg');
|
||||
background-attachment: fixed;
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto;
|
||||
background-position: center -50px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
color: var(--font);
|
||||
padding: 120px 0 0 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p { line-height: 150%; }
|
||||
a { text-decoration: none; }
|
||||
|
||||
h1 { font-size: 24px; }
|
||||
h2 { font-size: 21px; }
|
||||
h3 { font-size: 16px; }
|
||||
|
||||
body,
|
||||
button,
|
||||
input,
|
||||
textarea {
|
||||
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
button, input[type=submit] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button, input {
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
input[type="checkbox"], input[type="radio"] {
|
||||
margin: 0 8px 0 0;
|
||||
}
|
||||
|
||||
.RootView {
|
||||
margin: 0 auto;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--background);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0px 18px 24px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.card, .footer {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
body {
|
||||
background-image: none;
|
||||
background-color: var(--background);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: unset;
|
||||
box-shadow: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.footer .links li:not(:first-child) {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.footer .links li:not(:first-child)::before {
|
||||
content: "·";
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.footer .links li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.footer .links {
|
||||
font-size: 12px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a, button.text {
|
||||
color: var(--link);
|
||||
}
|
||||
|
||||
button.text {
|
||||
background: none;
|
||||
border: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: inherit;
|
||||
padding: 8px 0;
|
||||
margin: -8px 0;
|
||||
}
|
||||
|
||||
button.text:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.primary, .secondary {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
padding: 12px 8px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background: var(--background);
|
||||
color: var(--link);
|
||||
border: 1px solid var(--link);
|
||||
border-radius: 32px;
|
||||
}
|
||||
|
||||
.primary {
|
||||
background: var(--link);
|
||||
color: var(--background);
|
||||
border-radius: 32px;
|
||||
}
|
||||
|
||||
.primary.icon, .secondary.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 {
|
||||
border: none;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
input[type='text'].large {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: var(--background);
|
||||
border: 1px solid var(--foreground);
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.fullwidth {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.LoadServerPolicyView {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.LoadServerPolicyView .spinner {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.LoadServerPolicyView h2 {
|
||||
margin-top: 0;
|
||||
}
|
@ -14,16 +14,39 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.singleColumnLayout {
|
||||
height: 100%;
|
||||
|
||||
padding: 0 1em;
|
||||
margin: 0 auto;
|
||||
|
||||
max-width: 480px;
|
||||
|
||||
display: grid;
|
||||
row-gap: 60px;
|
||||
.OpenLinkView .caption {
|
||||
color: var(--grey);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ServerConsentView .actions label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ServerConsentView .actions {
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ServerConsentView input[type=submit] {
|
||||
flex: 1;
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
.ServerOptions div {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.ServerOptions label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ServerOptions label > .line {
|
||||
flex: 1;
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--grey);
|
||||
padding: 4px 0;
|
||||
}
|
128
css/preview.css
Normal file
@ -0,0 +1,128 @@
|
||||
.PreviewView {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.PreviewView h1 {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.PreviewView .avatarContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.PreviewView .avatar {
|
||||
border-radius: 100%;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.PreviewView .defaultAvatar {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background-image: url('../images/chat-icon.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 85%;
|
||||
}
|
||||
|
||||
.PreviewView .spinner {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.PreviewView .avatar.loading {
|
||||
border: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.PreviewView .identifier {
|
||||
color: var(--grey);
|
||||
font-size: 12px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.PreviewView .identifier.placeholder {
|
||||
height: 1em;
|
||||
margin: 1em 30%;
|
||||
}
|
||||
|
||||
.PreviewView .memberCount {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.PreviewView .memberCount.loading {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.PreviewView .memberCount p {
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.PreviewView .memberCount p:not(.placeholder) {
|
||||
padding: 4px 8px 4px 24px;
|
||||
border-radius: 14px;
|
||||
background-image: url(../images/member-icon.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
background-color: var(--lightgrey);
|
||||
}
|
||||
|
||||
.PreviewView .memberCount p.placeholder {
|
||||
height: 1.5em;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.PreviewView .topic {
|
||||
font-size: 12px;
|
||||
color: var(--grey);
|
||||
margin: 32px 0;
|
||||
}
|
||||
|
||||
.PreviewView .topic.loading {
|
||||
display: block;
|
||||
margin: 24px 12px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.PreviewView .topic.loading .placeholder {
|
||||
height: 0.8em;
|
||||
display: block;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.PreviewView .topic.loading .placeholder:nth-child(2) {
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
border-radius: 1em;
|
||||
--flash-bg: #ddd;
|
||||
--flash-fg: #eee;
|
||||
background: linear-gradient(120deg,
|
||||
var(--flash-bg),
|
||||
var(--flash-bg) 10%,
|
||||
var(--flash-fg) calc(10% + 25px),
|
||||
var(--flash-bg) calc(10% + 50px)
|
||||
);
|
||||
animation: flash 2s linear infinite;
|
||||
background-size: 200%;
|
||||
}
|
||||
|
||||
@keyframes flash {
|
||||
0% { background-position-x: 0; }
|
||||
50% { background-position-x: -80%; }
|
||||
51% { background-position-x: 80%; }
|
||||
100% { background-position-x: 0%; }
|
||||
}
|
27
css/spinner.css
Normal file
@ -0,0 +1,27 @@
|
||||
@keyframes rotate {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 100%;
|
||||
border: var(--spinner-stroke-size) solid var(--app-background);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.spinner::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
border-radius: 100%;
|
||||
border-width: var(--spinner-stroke-size);
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
border-top-color: var(--grey);
|
||||
animation: rotate 0.8s linear infinite;
|
||||
box-sizing: border-box;
|
||||
margin: calc(-1 * var(--spinner-stroke-size));
|
||||
}
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -1,6 +1,6 @@
|
||||
<svg width="1440" height="1505" viewBox="0 0 1440 1505" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<g opacity="0.26">
|
||||
<g>
|
||||
<path opacity="0.26" d="M1027.99 602.979C1262.01 860.194 1465.48 1242.7 1528.69 1544.36C1592.2 1847.63 1503.31 2018.17 1310.8 1964.61C1117.48 1910.83 851.081 1638.68 658.35 1297.66C466.355 957.9 378.93 607.541 443.1 434.715C506.167 264.833 707.508 296.249 938.653 512.115C968.31 539.852 998.261 570.239 1027.99 602.979Z" stroke="url(#paint0_linear)" stroke-opacity="0.5" stroke-miterlimit="10"/>
|
||||
<path opacity="0.26" d="M1044.18 604.303C1277.61 867.698 1476.23 1255.51 1532.89 1558.78C1589.85 1863.67 1493.74 2031.71 1297.33 1973.07C1100.11 1914.14 833.789 1635 645.032 1288.91C457.01 944.068 376.871 591.501 447.59 420.442C517.133 252.325 723.184 289.112 954.844 511.085C984.648 539.632 1014.53 570.827 1044.18 604.303Z" stroke="url(#paint1_linear)" stroke-opacity="0.5" stroke-miterlimit="10"/>
|
||||
<path opacity="0.26" d="M1060.81 606.069C1293.5 875.644 1486.97 1268.6 1536.79 1573.27C1586.9 1879.56 1483.51 2045.03 1283.27 1981.09C1082.22 1916.94 816.124 1630.66 631.709 1279.64C447.955 930.015 375.249 575.389 452.665 406.316C528.757 240.112 739.517 282.417 971.546 510.496C1001.42 539.779 1031.3 571.784 1060.81 606.069Z" stroke="url(#paint2_linear)" stroke-opacity="0.5" stroke-miterlimit="10"/>
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
9
images/client-icons/element.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0" y="0" width="64" height="64" fill="#0dbd8b" stop-color="#000000" stroke="#000" stroke-dasharray="0.188976, 0.37795299999999998" stroke-width=".18898"/>
|
||||
<g clip-rule="evenodd" fill="#fff" fill-rule="evenodd">
|
||||
<path d="m25.28 10.88c0-1.5906 1.2894-2.88 2.88-2.88 10.604 0 19.2 8.5961 19.2 19.2 0 1.5906-1.2894 2.88-2.88 2.88s-2.88-1.2894-2.88-2.88c0-7.4227-6.0173-13.44-13.44-13.44-1.5906 0-2.88-1.2894-2.88-2.88z"/>
|
||||
<path d="m38.72 53.12c0 1.5906-1.2894 2.88-2.88 2.88-10.604 0-19.2-8.5961-19.2-19.2 0-1.5906 1.2894-2.88 2.88-2.88 1.5905 0 2.88 1.2894 2.88 2.88 0 7.4227 6.0173 13.44 13.44 13.44 1.5906 0 2.88 1.2894 2.88 2.88z"/>
|
||||
<path d="m10.88 38.72c-1.5906 0-2.88-1.2894-2.88-2.88 0-10.604 8.5961-19.2 19.2-19.2 1.5906 0 2.88 1.2894 2.88 2.88 0 1.5905-1.2894 2.88-2.88 2.88-7.4227 0-13.44 6.0173-13.44 13.44 0 1.5906-1.2894 2.88-2.88 2.88z"/>
|
||||
<path d="m53.12 25.28c1.5906 0 2.88 1.2894 2.88 2.88 0 10.604-8.5961 19.2-19.2 19.2-1.5906 0-2.88-1.2894-2.88-2.88 0-1.5905 1.2894-2.88 2.88-2.88 7.4227 0 13.44-6.0173 13.44-13.44 0-1.5906 1.2894-2.88 2.88-2.88z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
464
images/client-icons/quaternion.svg
Normal file
@ -0,0 +1,464 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48.000001"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="quaternion2.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="b"
|
||||
y1="23.774559"
|
||||
x1="22.540125"
|
||||
y2="44.054428"
|
||||
x2="42.645557"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(30,0)">
|
||||
<stop
|
||||
stop-color="#292c2f"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#292c2f"
|
||||
stop-opacity="0"
|
||||
id="stop14" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4416">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="0"
|
||||
id="stop4418" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4420" />
|
||||
</linearGradient>
|
||||
<style
|
||||
id="current-color-scheme"
|
||||
type="text/css">
|
||||
.ColorScheme-Text {
|
||||
color:#4d4d4d;
|
||||
}
|
||||
.ColorScheme-Highlight {
|
||||
color:#3daee9;
|
||||
}
|
||||
</style>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#b"
|
||||
id="linearGradient4384-2"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(18.78125,-16.0625)"
|
||||
x1="-21.260931"
|
||||
y1="13.89889"
|
||||
x2="10.555012"
|
||||
y2="48.902145" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4416"
|
||||
id="linearGradient4422-7"
|
||||
x1="-30.500504"
|
||||
y1="28.249998"
|
||||
x2="-10.500504"
|
||||
y2="7.8749971"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(4.0005053,-4.0000137)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#b"
|
||||
id="linearGradient5173"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.80454501,0,0,0.80454501,29.039903,1009.4479)"
|
||||
x1="-8.4545803"
|
||||
y1="4.9617052"
|
||||
x2="10.555012"
|
||||
y2="48.902145" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4416"
|
||||
id="linearGradient5175"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.89628968,0,0,0.89628968,2.535611,1907.0938)"
|
||||
x1="34.2505"
|
||||
y1="-976.61401"
|
||||
x2="8.5004978"
|
||||
y2="-1002.614" />
|
||||
<linearGradient
|
||||
gradientTransform="translate(-384.57,-499.8)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="0"
|
||||
y2="503.8"
|
||||
y1="543.8"
|
||||
id="a">
|
||||
<stop
|
||||
id="stop7"
|
||||
stop-color="#197cf1" />
|
||||
<stop
|
||||
id="stop9"
|
||||
stop-color="#20bcfa"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="432.5705"
|
||||
id="a-6"
|
||||
y1="547.79999"
|
||||
y2="500.04578"
|
||||
x2="432.5705"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-432.5705,-499.79999)">
|
||||
<stop
|
||||
style="stop-color:#1e2b35;stop-opacity:1"
|
||||
stop-color="#18222a"
|
||||
id="stop4216" />
|
||||
<stop
|
||||
style="stop-color:#525c64;stop-opacity:1"
|
||||
offset="1"
|
||||
stop-color="#566069"
|
||||
id="stop4218" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-344.5695,-499.79999)"
|
||||
id="b-7"
|
||||
y1="517.8"
|
||||
x1="399.57"
|
||||
y2="534.8"
|
||||
x2="416.57"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
id="stop4221" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-opacity="0"
|
||||
id="stop4223" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-344.5695,-499.79999)"
|
||||
id="c"
|
||||
y1="537.8"
|
||||
y2="508.8"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="0">
|
||||
<stop
|
||||
stop-color="#026ddc"
|
||||
id="stop4226" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#28b0fd"
|
||||
id="stop4228" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="d"
|
||||
y1="525.28"
|
||||
x1="408.65"
|
||||
y2="533.28"
|
||||
x2="416.65"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-.081-.48)">
|
||||
<stop
|
||||
stop-opacity=".065"
|
||||
id="stop4231" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-opacity="0"
|
||||
id="stop4233" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#d"
|
||||
id="e"
|
||||
y1="517.96"
|
||||
x1="417.79"
|
||||
y2="525.91"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="426.22"
|
||||
gradientTransform="matrix(-1,0,0,1,817.2,-0.48)" />
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="39.279999"
|
||||
y2="36.632999"
|
||||
x1="22.285"
|
||||
y1="18.709999"
|
||||
id="b-5"
|
||||
gradientTransform="translate(-13.182,-16.463)">
|
||||
<stop
|
||||
id="stop12-3"
|
||||
stop-color="#292c2f" />
|
||||
<stop
|
||||
id="stop14-5"
|
||||
stop-opacity="0"
|
||||
stop-color="#292c2f"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="463.30493"
|
||||
id="b-3"
|
||||
y1="791.61914"
|
||||
y2="721.56116"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="520.69641"
|
||||
gradientTransform="matrix(0.71874732,0,0,0.68157806,-378.12417,-491.55024)">
|
||||
<stop
|
||||
style="stop-color:#00945a;stop-opacity:1"
|
||||
stop-color="#26c281"
|
||||
id="stop4252" />
|
||||
<stop
|
||||
style="stop-color:#38fa95;stop-opacity:1"
|
||||
offset="1"
|
||||
stop-color="#3fc380"
|
||||
id="stop4254" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="a-67"
|
||||
y1="517.79999"
|
||||
y2="533.79999"
|
||||
x1="404.98001"
|
||||
x2="420.98001"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.98828127,0,0,0.98828127,-383.20097,-495.43517)">
|
||||
<stop
|
||||
stop-color="#383e51"
|
||||
id="stop4247" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#655c6f"
|
||||
stop-opacity="0"
|
||||
id="stop4249" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.98828127,0,0,0.98828127,-378.84265,-493.45861)"
|
||||
id="c-5"
|
||||
y1="531.79999"
|
||||
y2="515.79999"
|
||||
x2="0"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#70e4b3"
|
||||
id="stop4257" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#c8f0dc"
|
||||
id="stop4259" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="b-3-3"
|
||||
y1="785.71002"
|
||||
y2="727.71002"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="0"
|
||||
gradientTransform="matrix(0.71874732,0,0,0.68157806,-387.2511,-495.98773)">
|
||||
<stop
|
||||
stop-color="#26c281"
|
||||
id="stop4252-5" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#3fc380"
|
||||
id="stop4254-6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-13.130467,-10.269952)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="42.645557"
|
||||
y2="44.054428"
|
||||
x1="22.540125"
|
||||
y1="23.774559"
|
||||
id="b-1">
|
||||
<stop
|
||||
id="stop12-2"
|
||||
stop-color="#292c2f" />
|
||||
<stop
|
||||
id="stop14-7"
|
||||
stop-opacity="0"
|
||||
stop-color="#292c2f"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="39.179428"
|
||||
x2="3.3955555"
|
||||
y1="32.924278"
|
||||
x1="-2.8595951"
|
||||
gradientTransform="translate(7.947106,-34.03464)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4318-9"
|
||||
xlink:href="#b"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="39.179428"
|
||||
x2="3.3955555"
|
||||
y1="39.799278"
|
||||
x1="-13.672095"
|
||||
gradientTransform="translate(14.488281,-20.003906)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4345-7"
|
||||
xlink:href="#b"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="48.902145"
|
||||
x2="10.555012"
|
||||
y1="12.39889"
|
||||
x1="-22.510931"
|
||||
gradientTransform="translate(18.78125,-16.0625)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4384-2-2"
|
||||
xlink:href="#b"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="42.645557"
|
||||
y2="44.054428"
|
||||
x1="22.540125"
|
||||
y1="23.774559"
|
||||
id="b-36"
|
||||
gradientTransform="translate(-71.999501,32.001813)">
|
||||
<stop
|
||||
id="stop12-7"
|
||||
stop-color="#292c2f" />
|
||||
<stop
|
||||
id="stop14-53"
|
||||
stop-opacity="0"
|
||||
stop-color="#292c2f"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="389.3205"
|
||||
id="a-6-5"
|
||||
y1="547.67499"
|
||||
y2="499.92078"
|
||||
x2="426.6955"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-360.571,-467.79817)">
|
||||
<stop
|
||||
style="stop-color:#1e2b35;stop-opacity:1"
|
||||
stop-color="#18222a"
|
||||
id="stop4216-6" />
|
||||
<stop
|
||||
style="stop-color:#6d7983;stop-opacity:1"
|
||||
offset="1"
|
||||
stop-color="#566069"
|
||||
id="stop4218-2" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="32.789359"
|
||||
inkscape:cy="42.117635"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
showguides="false"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-global="false"
|
||||
showborder="false"
|
||||
borderlayer="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5026" />
|
||||
<sodipodi:guide
|
||||
position="13,11.25"
|
||||
orientation="0.70710678,0.70710678"
|
||||
id="guide5089" />
|
||||
<sodipodi:guide
|
||||
position="7.875,26.375001"
|
||||
orientation="0.70710678,0.70710678"
|
||||
id="guide5091" />
|
||||
<sodipodi:guide
|
||||
position="29.875,39.500001"
|
||||
orientation="0.70710678,0.70710678"
|
||||
id="guide5093" />
|
||||
<sodipodi:guide
|
||||
position="35,36.250001"
|
||||
orientation="0.70710678,0.70710678"
|
||||
id="guide5097" />
|
||||
<sodipodi:guide
|
||||
position="9.875,20.5"
|
||||
orientation="0.70710678,0.70710678"
|
||||
id="guide5126" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Livello 2">
|
||||
<path
|
||||
id="path5159"
|
||||
d="m 24.04876,6.1174361 c -9.930889,0 -17.925793,7.9949039 -17.925793,17.9257939 0,9.930889 7.994904,17.925793 17.925793,17.925793 0.02411,0 0.04771,-0.0017 0.07178,-0.0018 l 16.955978,4.3e-5 c 0.496545,0 0.89629,-0.399737 0.89629,-0.89629 l 0,-16.961232 c 8.1e-5,-0.02232 0.0018,-0.04418 0.0018,-0.06652 0,-9.930889 -7.994904,-17.9257934 -17.925795,-17.9257934 z"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#1d99f3;fill-opacity:1;fill-rule:nonzero;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:label="Livello 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1004.3622)">
|
||||
<path
|
||||
style="opacity:0.3;fill:#ffffff;fill-opacity:1;stroke-width:2.79999995;stroke-opacity:0.55"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 6.1310739,1028.8503 c -0.00358,-0.1498 -0.010755,-0.2976 -0.010755,-0.4483 0,-9.9308 7.994904,-17.9257 17.925794,-17.9257 9.93089,0 17.925795,7.9949 17.925795,17.9257 0,0.1507 -0.0072,0.2985 -0.01076,0.4483 -0.23662,-9.7221 -8.138312,-17.4777 -17.91504,-17.4777 -9.780313,0 -17.6784177,7.7556 -17.9150382,17.4777"
|
||||
id="path5163"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5165"
|
||||
d="m 11.232155,1026.802 14.222481,14.2935 -3.520064,-0.3911 -9.191278,-9.1912 2.684492,7.5202 6.204245,6.2684 2.49952,0.1156 17.241676,-0.023 0.640018,-1.0668 -0.05709,-14.8384 -0.0649,-1.7857 -8.756475,-8.7243 -0.64001,0.8532 -3.555621,-3.6266 -10.240187,0.64 -4.76453,4.1244 z"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.18800001;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient5173);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5167"
|
||||
d="m 6.1334706,1027.9574 c -0.00367,0.1495 -0.010504,0.2976 -0.010504,0.448 0,9.9309 7.9949037,17.9258 17.9257927,17.9258 0.02411,0 0.04771,0 0.07178,0 l 16.955981,0 c 0.496544,0 0.896289,-0.3996 0.896289,-0.8962 l 0,-0.8945 c 0,0.4965 -0.399745,0.8963 -0.896289,0.8963 l -16.955983,0 -0.07178,0 c -9.78071,0 -17.6785062,-7.7561 -17.9152898,-17.4777 z m 35.8393324,0.3763 0,0.1383 c 8.2e-5,-0.022 0.0018,-0.044 0.0018,-0.066 0,-0.024 -0.0018,-0.048 -0.0018,-0.072 z"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#161e25;fill-opacity:1;fill-rule:nonzero;stroke-width:2.79999995;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.55;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5169"
|
||||
d="m 24.850998,1015.3211 -2.3e-4,0 c -4.221957,-0.2137 -8.462616,1.6173 -11.185311,5.279 -1.410567,1.8989 -2.22395,4.0471 -2.493121,6.2301 l 1.696347,-0.2507 3.220344,-0.4718 2.68403,-2.0567 -5.463182,0.8056 c 0.374562,-1.1444 0.916754,-2.2533 1.67664,-3.2759 2.961145,-3.9843 7.972375,-5.4929 12.459008,-4.168 l 1.563639,-1.1933 c -1.347181,-0.5332 -2.750838,-0.8302 -4.158164,-0.9015 z m 6.710874,2.5126 -4.6e-4,0.01 -0.521308,1.6335 -0.859253,2.6992 0.499033,3.8383 1.715908,-5.384 c 0.863373,0.8389 1.619917,1.8132 2.204556,2.9452 2.442167,4.7279 1.298074,10.3196 -2.445266,13.7365 l 0.0072,0.053 c -0.02757,0.026 -0.05527,0.055 -0.0831,0.081 l 4.152714,4.8087 1.274973,-1.1026 -3.204232,-3.7103 c 3.427251,-3.9365 4.309935,-9.6879 1.761636,-14.6216 -1.086112,-2.1028 -2.658768,-3.7804 -4.502389,-4.9823 z m -20.627884,12.8598 c 0.795585,5.8959 5.518184,10.6684 11.708243,11.2806 2.355072,0.2329 4.622679,-0.1736 6.634024,-1.0664 l -1.086358,-1.3241 -0.0062,-5e-4 -2.138088,-2.6048 -3.22492,-1.339 3.657256,4.4524 c -1.173938,0.2676 -2.40585,0.375 -3.673603,0.2496 -5.070346,-0.501 -9.016389,-4.197 -10.072229,-8.8986 z"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.63318729;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.45;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient5175);fill-opacity:1;fill-rule:nonzero;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 24.04876,1010.4797 c -9.930889,0 -17.925793,7.9949 -17.925793,17.9257 0,9.9309 7.994904,17.9258 17.925793,17.9258 0.02411,0 0.04771,0 0.07178,0 l 16.955978,0 c 0.496545,0 0.89629,-0.3996 0.89629,-0.8962 l 0,-16.9612 c 8.1e-5,-0.022 0.0018,-0.044 0.0018,-0.066 0,-9.931 -7.994902,-17.9259 -17.925793,-17.9259 z"
|
||||
id="path5171"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 18 KiB |
BIN
images/client-icons/tensor.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
@ -1,4 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.5 15H6C4.89543 15 4 14.1046 4 13V6C4 4.89543 4.89543 4 6 4H13C14.1046 4 15 4.89543 15 6V9.5" stroke="white" stroke-width="1.5"/>
|
||||
<rect x="9" y="9" width="11" height="11" rx="2" stroke="white" stroke-width="1.5"/>
|
||||
<path d="M9.5 15H6C4.89543 15 4 14.1046 4 13V6C4 4.89543 4.89543 4 6 4H13C14.1046 4 15 4.89543 15 6V9.5" stroke="#0098d4" stroke-width="1.5"/>
|
||||
<rect x="9" y="9" width="11" height="11" rx="2" stroke="#0098d4" stroke-width="1.5"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 332 B |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
62
images/flathub-badge.svg
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="600" height="200" viewBox="0 0 600 200.00001" version="1.1" id="svg8129" inkscape:version="0.92.2 5c3e80d, 2017-08-06" sodipodi:docname="download-i.svg" inkscape:export-filename="/home/jimmac/SparkleShare/flathub-mockups/assets/download-button/download-i.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
|
||||
<defs id="defs8123"/>
|
||||
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.5" inkscape:cx="-1148.9932" inkscape:cy="140.4998" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" units="px" borderlayer="true" inkscape:showpageshadow="false" inkscape:snap-nodes="false" inkscape:snap-bbox="true" inkscape:bbox-nodes="true" inkscape:snap-bbox-midpoints="true" inkscape:window-width="3440" inkscape:window-height="1376" inkscape:window-x="0" inkscape:window-y="27" inkscape:window-maximized="1">
|
||||
<inkscape:grid type="xygrid" id="grid8722"/>
|
||||
</sodipodi:namedview>
|
||||
<metadata id="metadata8126">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(0,-922.51965)">
|
||||
<rect style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3.77952766;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" id="rect8720" width="596.22046" height="196.22047" x="1.8897638" y="924.40942" rx="32" ry="32"/>
|
||||
<g aria-label="FLATHUB" style="color:#000000;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:64.27679443px;line-height:125%;font-family:Overpass;-inkscape-font-specification:'Overpass, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#1d2020;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate" id="text7686">
|
||||
<path d="m 252.98791,1069.2683 h 7.71322 v -19.6044 h 13.62668 v -7.2633 h -13.62668 v -10.8628 h 21.33989 v -7.2632 h -29.05311 z" style="stroke-width:1" id="path51"/>
|
||||
<path d="m 289.39469,1069.2683 h 29.56732 v -7.3918 H 297.1079 v -37.6019 h -7.71321 z" style="stroke-width:1" id="path53"/>
|
||||
<path d="m 356.00553,1069.2683 h 8.09888 l -16.71197,-44.9937 h -7.64894 l -16.77624,44.9937 h 8.16315 l 3.53523,-9.8343 h 17.80467 z m -5.97774,-16.7762 h -12.91963 l 5.01359,-13.4982 c 0.44993,-1.2855 1.0927,-3.2138 1.47836,-4.5636 0.32139,1.3498 0.96415,3.2781 1.47837,4.5636 z" style="stroke-width:1" id="path55"/>
|
||||
<path d="m 383.46076,1031.6664 h 12.79108 v -7.3918 h -33.29538 v 7.3918 h 12.79109 v 37.6019 h 7.71321 z" style="stroke-width:1" id="path57"/>
|
||||
<path d="m 431.64627,1069.2683 h 7.64894 v -44.9937 h -7.64894 v 18.1903 h -19.6687 v -18.1903 h -7.71322 v 44.9937 h 7.71322 v -19.5401 h 19.6687 z" style="stroke-width:1" id="path59"/>
|
||||
<path d="m 467.4384,1070.0396 c 9.51296,0 17.54756,-4.6279 17.54756,-17.9332 v -27.8318 h -7.71321 v 27.8318 c 0,8.2274 -4.04944,10.5414 -9.83435,10.5414 -5.84919,0 -9.83435,-2.314 -9.83435,-10.5414 v -27.8318 h -7.71322 v 27.8318 c 0,13.4981 8.29171,17.9332 17.54757,17.9332 z" style="stroke-width:1" id="path61"/>
|
||||
<path d="m 495.53238,1024.2746 v 44.9937 h 19.34731 c 11.11989,0 15.04077,-7.0704 15.04077,-13.3053 0,-4.0494 -2.05686,-8.4845 -7.39183,-10.4128 3.98516,-1.9283 5.78491,-5.4636 5.78491,-9.2559 0,-6.1063 -3.53522,-12.0197 -14.398,-12.0197 z m 17.35473,18.126 h -9.64152 v -10.9913 h 10.86278 c 5.33497,0 6.42768,2.8282 6.42768,5.4635 0,3.2781 -2.5068,5.5278 -7.64894,5.5278 z m 2.44252,19.733 h -12.08404 v -12.5983 h 10.22001 c 7.00617,0 8.61309,3.2782 8.61309,6.6205 0,2.7639 -1.47836,5.9778 -6.74906,5.9778 z" style="stroke-width:1" id="path63"/>
|
||||
</g>
|
||||
<g transform="translate(-733.58433,141.64633)" id="g8587">
|
||||
<path sodipodi:nodetypes="ccccccccccc" inkscape:connector-curvature="0" id="rect7736" d="m 856.01397,830.22631 -66.76365,43.44891 v 34.93973 l 33.38182,21.72315 33.37926,-21.72315 v -0.005 l 0.003,0.003 33.38183,21.72574 33.37925,-21.72315 v -34.93979 z" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:12;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
|
||||
<g style="stroke-width:0.75573969" transform="matrix(0.50221552,0,0,0.50636711,429.63205,432.90461)" id="g7710">
|
||||
<rect style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.16674447;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="rect7688" width="79.110413" height="79.110413" x="1289.9076" y="279.42584" rx="0" ry="0" transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"/>
|
||||
<rect transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" ry="0" rx="0" y="215.8064" x="1226.2882" height="79.110413" width="79.110413" id="rect7690" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.16674447;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
|
||||
<path style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.02295876;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z" id="path7692" inkscape:connector-curvature="0"/>
|
||||
<path inkscape:connector-curvature="0" id="path7694" d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.02295876;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
|
||||
</g>
|
||||
<g style="stroke-width:0.75573969" transform="matrix(0.50221552,0,0,0.50636711,463.01368,454.62849)" id="g7722">
|
||||
<rect transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" ry="0" rx="0" y="279.42584" x="1289.9076" height="79.110413" width="79.110413" id="rect7714" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.16674447;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
|
||||
<rect style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.16674447;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="rect7716" width="79.110413" height="79.110413" x="1226.2882" y="215.8064" rx="0" ry="0" transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"/>
|
||||
<path inkscape:connector-curvature="0" id="path7718" d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.02295876;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
|
||||
<path style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.02295876;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z" id="path7720" inkscape:connector-curvature="0"/>
|
||||
</g>
|
||||
<g style="stroke-width:0.75573969" id="g7734" transform="matrix(0.50221552,0,0,0.50636711,396.25042,454.62849)">
|
||||
<rect style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.16674447;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" id="rect7726" width="79.110413" height="79.110413" x="1289.9076" y="279.42584" rx="0" ry="0" transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"/>
|
||||
<rect transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" ry="0" rx="0" y="215.8064" x="1226.2882" height="79.110413" width="79.110413" id="rect7728" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.16674447;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
|
||||
<path style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.02295876;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z" id="path7730" inkscape:connector-curvature="0"/>
|
||||
<path inkscape:connector-curvature="0" id="path7732" d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.02295876;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
|
||||
</g>
|
||||
</g>
|
||||
<g aria-label="Download On" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;line-height:1.25;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.99999988" id="text8718">
|
||||
<path d="m 253.10501,968.74764 v 25.33714 h 6.58766 c 9.12137,0 11.61889,-6.84103 11.61889,-12.66857 0,-6.26189 -2.89568,-12.66857 -11.47411,-12.66857 z m 6.76864,23.0568 h -4.23492 v -20.77646 h 4.63307 c 6.00853,0 8.39746,5.13982 8.39746,10.38823 0,4.92264 -1.99078,10.38823 -8.79561,10.38823 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path30"/>
|
||||
<path d="m 290.39326,994.51913 c 4.74166,0 7.9269,-3.61959 7.9269,-9.70051 0,-6.1533 -3.18524,-9.6643 -7.9269,-9.6643 -4.74166,0 -7.9269,3.61959 -7.9269,9.7005 0,6.15331 3.18524,9.66431 7.9269,9.66431 z m 0,-2.28034 c -3.43861,0 -5.2846,-2.78709 -5.2846,-7.38397 0,-4.81406 1.84599,-7.42016 5.2846,-7.42016 3.43861,0 5.2846,2.78708 5.2846,7.38396 0,4.63308 -1.91838,7.42017 -5.2846,7.42017 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path32"/>
|
||||
<path d="m 312.98936,994.08478 h 2.31653 l 3.6196,-11.22073 c 0.18098,-0.57914 0.47054,-1.48404 0.76011,-2.46133 0.28957,0.97729 0.61533,1.91839 0.79631,2.49752 l 3.69198,11.18454 h 2.28035 l 4.56068,-18.49611 h -2.53371 l -2.93187,13.32009 c -0.14479,0.72392 -0.32577,1.44784 -0.47055,2.20795 -0.21717,-0.76011 -0.39815,-1.48403 -0.61533,-2.20795 l -3.87296,-13.32009 h -1.73741 l -3.87296,13.32009 c -0.18098,0.68772 -0.36196,1.30306 -0.54294,2.02697 l -0.43435,-2.02697 -3.04045,-13.32009 h -2.53372 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path34"/>
|
||||
<path d="m 353.73035,994.08478 h 2.53371 v -10.24345 c 0,-6.1171 -2.09936,-8.68701 -6.62385,-8.68701 -1.95458,0 -3.61959,0.79631 -4.77786,2.46132 v -2.02697 h -2.53371 v 18.49611 h 2.53371 v -11.36552 c 0,-4.01774 1.95458,-5.2846 4.56069,-5.2846 2.46132,0 4.30731,1.44784 4.30731,5.35699 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path36"/>
|
||||
<path d="m 369.43905,994.08478 h 2.53371 v -26.13345 l -2.53371,1.23066 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path38"/>
|
||||
<path d="m 391.9605,994.51913 c 4.74166,0 7.9269,-3.61959 7.9269,-9.70051 0,-6.1533 -3.18524,-9.6643 -7.9269,-9.6643 -4.74167,0 -7.92691,3.61959 -7.92691,9.7005 0,6.15331 3.18524,9.66431 7.92691,9.66431 z m 0,-2.28034 c -3.43862,0 -5.28461,-2.78709 -5.28461,-7.38397 0,-4.81406 1.84599,-7.42016 5.28461,-7.42016 3.43861,0 5.2846,2.78708 5.2846,7.38396 0,4.63308 -1.91838,7.42017 -5.2846,7.42017 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path40"/>
|
||||
<path d="m 422.4473,994.08478 h 2.35273 v -12.52379 c 0,-5.2484 -3.511,-6.40667 -6.15331,-6.40667 -2.53371,0 -4.99503,1.08587 -6.47906,2.02697 l 0.72391,2.17175 c 1.37545,-0.94109 3.65579,-1.99077 5.50178,-1.99077 2.06317,0 4.05395,0.79631 4.05395,4.52449 v 1.55642 c -1.8098,-0.97729 -3.43862,-1.30305 -4.99504,-1.30305 -3.511,0 -6.73244,1.84599 -6.73244,6.11711 0,4.16253 2.56991,6.26189 6.29809,6.26189 1.99077,0 3.94535,-0.9049 5.42939,-2.24415 z m -5.17602,-1.7736 c -2.6785,0 -4.19873,-1.62882 -4.19873,-4.05394 0,-2.6785 2.13556,-3.90916 4.63308,-3.90916 1.59262,0 3.5472,0.72392 4.74167,1.52023 v 3.58339 c -1.12208,1.37545 -2.93187,2.85948 -5.17602,2.85948 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path42"/>
|
||||
<path d="m 443.62102,994.51913 c 2.31654,0 3.80057,-0.9049 4.92264,-2.02697 v 1.59262 h 2.53371 v -26.13345 l -2.53371,1.26686 v 7.67353 c -1.12207,-0.9049 -2.6423,-1.7374 -4.92264,-1.7374 -4.70547,0 -7.63734,3.58339 -7.63734,9.6643 0,5.89994 2.89567,9.70051 7.63734,9.70051 z m 0.28956,-2.28034 c -3.25763,0 -5.2846,-3.29383 -5.2846,-7.42017 0,-4.74166 1.88219,-7.38396 5.2846,-7.38396 2.35274,0 3.87297,1.44784 4.63308,2.6785 v 9.22995 c -1.01348,1.84599 -2.78708,2.89568 -4.63308,2.89568 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path44"/>
|
||||
<path d="m 489.0055,994.51913 c 7.81832,0 10.49682,-6.84103 10.49682,-13.10292 0,-6.26189 -2.6785,-13.10292 -10.49682,-13.10292 -7.81831,0 -10.49681,6.84103 -10.49681,13.10292 0,6.26189 2.6785,13.10292 10.49681,13.10292 z m 0,-2.28034 c -5.82754,0 -7.85451,-5.3208 -7.85451,-10.82258 0,-5.03123 2.02697,-10.82258 7.85451,-10.82258 5.82755,0 7.85452,5.3208 7.85452,10.82258 0,5.03123 -2.02697,10.82258 -7.85452,10.82258 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path46"/>
|
||||
<path d="m 523.36073,994.08478 h 2.53371 v -10.24345 c 0,-6.1171 -2.09936,-8.68701 -6.62385,-8.68701 -1.95458,0 -3.61959,0.79631 -4.77786,2.46132 v -2.02697 h -2.53371 v 18.49611 h 2.53371 v -11.36552 c 0,-4.01774 1.95458,-5.2846 4.56069,-5.2846 2.46132,0 4.30731,1.44784 4.30731,5.35699 z" style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:36.19591141px;font-family:Overpass;-inkscape-font-specification:'Overpass, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:6.63992262px;writing-mode:lr-tb;text-anchor:start;stroke-width:0.99999988" id="path48"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 549 B After Width: | Height: | Size: 549 B |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
7
images/member-icon.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.1332 16.3632C11.1709 16.7731 10.112 17 9 17C4.58172 17 1 13.4183 1 9C1 4.58172 4.58172 1 9 1C13.4183 1 17 4.58172 17 9C17 11.6173 15.7432 13.941 13.8001 15.4005V15.4005C13.4881 15.6349 13.1583 15.847 12.8133 16.0344C12.5926 16.1543 12.3657 16.2641 12.1332 16.3632ZM9.00004 9.39998C10.3255 9.39998 11.4 8.23592 11.4 6.79998C11.4 5.36404 10.3255 4.19998 9.00004 4.19998C7.67456 4.19998 6.60004 5.36404 6.60004 6.79998C6.60004 8.23592 7.67456 9.39998 9.00004 9.39998ZM8.99989 15.4001C10.7295 15.4001 12.2989 14.7139 13.4507 13.599C12.7384 11.8404 11.0141 10.6 9.00009 10.6C6.98597 10.6 5.26159 11.8406 4.54932 13.5992C5.7011 14.714 7.27038 15.4001 8.99989 15.4001Z"/>
|
||||
</mask>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.1332 16.3632C11.1709 16.7731 10.112 17 9 17C4.58172 17 1 13.4183 1 9C1 4.58172 4.58172 1 9 1C13.4183 1 17 4.58172 17 9C17 11.6173 15.7432 13.941 13.8001 15.4005V15.4005C13.4881 15.6349 13.1583 15.847 12.8133 16.0344C12.5926 16.1543 12.3657 16.2641 12.1332 16.3632ZM9.00004 9.39998C10.3255 9.39998 11.4 8.23592 11.4 6.79998C11.4 5.36404 10.3255 4.19998 9.00004 4.19998C7.67456 4.19998 6.60004 5.36404 6.60004 6.79998C6.60004 8.23592 7.67456 9.39998 9.00004 9.39998ZM8.99989 15.4001C10.7295 15.4001 12.2989 14.7139 13.4507 13.599C12.7384 11.8404 11.0141 10.6 9.00009 10.6C6.98597 10.6 5.26159 11.8406 4.54932 13.5992C5.7011 14.714 7.27038 15.4001 8.99989 15.4001Z" fill="#666666"/>
|
||||
<path d="M12.1332 16.3632L11.3492 14.5232L12.1332 16.3632ZM13.8001 15.4005H11.8001V19.4042L15.0013 16.9996L13.8001 15.4005ZM13.8001 15.4005H15.8001V11.3967L12.5989 13.8014L13.8001 15.4005ZM12.8133 16.0344L13.768 17.7919L13.768 17.7919L12.8133 16.0344ZM13.4507 13.599L14.8418 15.036L15.8107 14.098L15.3044 12.8481L13.4507 13.599ZM4.54932 13.5992L2.69558 12.8485L2.18935 14.0984L3.15837 15.0363L4.54932 13.5992ZM9 19C10.3863 19 11.7115 18.7168 12.9171 18.2031L11.3492 14.5232C10.6303 14.8295 9.83767 15 9 15V19ZM-1 9C-1 14.5228 3.47715 19 9 19V15C5.68629 15 3 12.3137 3 9H-1ZM9 -1C3.47715 -1 -1 3.47715 -1 9H3C3 5.68629 5.68629 3 9 3V-1ZM19 9C19 3.47715 14.5228 -1 9 -1V3C12.3137 3 15 5.68629 15 9H19ZM15.0013 16.9996C17.4256 15.1786 19 12.2729 19 9H15C15 10.9617 14.0607 12.7034 12.5989 13.8014L15.0013 16.9996ZM15.8001 15.4005V15.4005H11.8001V15.4005H15.8001ZM12.5989 13.8014C12.3645 13.9774 12.1171 14.1365 11.8586 14.277L13.768 17.7919C14.1995 17.5574 14.6116 17.2923 15.0013 16.9996L12.5989 13.8014ZM12.9171 18.2031C13.2082 18.0791 13.4921 17.9418 13.768 17.7919L11.8586 14.277C11.6932 14.3668 11.5233 14.449 11.3492 14.5232L12.9171 18.2031ZM9.40004 6.79998C9.40004 7.01655 9.31985 7.18185 9.22749 7.2819C9.13763 7.37925 9.05614 7.39998 9.00004 7.39998V11.4C11.5778 11.4 13.4 9.18675 13.4 6.79998H9.40004ZM9.00004 6.19998C9.05614 6.19998 9.13763 6.22071 9.22749 6.31806C9.31985 6.41811 9.40004 6.58341 9.40004 6.79998H13.4C13.4 4.41321 11.5778 2.19998 9.00004 2.19998V6.19998ZM8.60004 6.79998C8.60004 6.58341 8.68024 6.41811 8.77259 6.31806C8.86246 6.22071 8.94395 6.19998 9.00004 6.19998V2.19998C6.42228 2.19998 4.60004 4.41321 4.60004 6.79998H8.60004ZM9.00004 7.39998C8.94395 7.39998 8.86246 7.37925 8.77259 7.28189C8.68024 7.18184 8.60004 7.01655 8.60004 6.79998H4.60004C4.60004 9.18675 6.42228 11.4 9.00004 11.4V7.39998ZM12.0597 12.162C11.2659 12.9304 10.1898 13.4001 8.99989 13.4001V17.4001C11.2693 17.4001 13.332 16.4975 14.8418 15.036L12.0597 12.162ZM9.00009 12.6C10.1718 12.6 11.18 13.3204 11.597 14.3498L15.3044 12.8481C14.2968 10.3605 11.8564 8.60004 9.00009 8.60004V12.6ZM6.40306 14.35C6.82004 13.3204 7.82833 12.6 9.00009 12.6V8.60004C6.1436 8.60004 3.70313 10.3607 2.69558 12.8485L6.40306 14.35ZM8.99989 13.4001C7.81008 13.4001 6.73407 12.9304 5.94027 12.1621L3.15837 15.0363C4.66812 16.4976 6.73068 17.4001 8.99989 17.4001V13.4001Z" fill="#666666" mask="url(#path-1-inside-1)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
1
images/platform-icon.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="22" height="22" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.358 14.752H4.97a1.048 1.048 0 01-1.047-1.048V6.286c0-.579.469-1.048 1.047-1.048H17.08c.579 0 1.048.47 1.048 1.048v1.33M11.424 15.152v1.21M9.304 16.362h3.653" stroke="#666" stroke-width=".8" stroke-linecap="round" stroke-linejoin="round"/><rect x="14.543" y="8.955" width="3.914" height="7.371" rx=".648" stroke="#666" stroke-width=".8"/><path stroke="#666" stroke-width=".8" d="M16.028 15.174h1.048"/></svg>
|
After Width: | Height: | Size: 495 B |
3
images/tick-dark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.5 12.5L8.84497 15.845C9.71398 16.714 11.1538 16.601 11.8767 15.6071L18.5 6.5" stroke="#333" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 249 B |
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
16
index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>You're invited to talk on Matrix</title>
|
||||
<meta name="description" content="You're invited to talk on Matrix">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<link rel="stylesheet" type="text/css" href="css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<script id="main" type="module">
|
||||
import {main} from "./src/main.js";
|
||||
main(document.body);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
115
package.json
@ -1,82 +1,37 @@
|
||||
{
|
||||
"name": "matrix.to",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@quentin-sommer/react-useragent": "^3.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"formik": "^2.1.4",
|
||||
"promise.any": "^2.0.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "3.4.1",
|
||||
"what-input": "^5.2.10",
|
||||
"zod": "^1.10.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"lint:fix": "eslint src/**/*.ts src/**/*.tsx --fix",
|
||||
"storybook": "start-storybook -p 9009 -s public",
|
||||
"build-storybook": "build-storybook -s public"
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx,ts,tsx}": [
|
||||
"eslint --fix",
|
||||
"prettier --write --tab-width 4 --single-quote"
|
||||
],
|
||||
"src/**/*.{json,css,scss,md}": [
|
||||
"prettier --write --tab-width 4 --single-quote"
|
||||
]
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-a11y": "^5.3.19",
|
||||
"@storybook/addon-actions": "^5.3.19",
|
||||
"@storybook/addon-backgrounds": "^5.3.19",
|
||||
"@storybook/addon-knobs": "^5.3.19",
|
||||
"@storybook/addon-links": "^5.3.19",
|
||||
"@storybook/addon-storysource": "^5.3.19",
|
||||
"@storybook/addon-viewport": "^5.3.19",
|
||||
"@storybook/addons": "^5.3.19",
|
||||
"@storybook/preset-create-react-app": "^3.1.4",
|
||||
"@storybook/react": "^5.3.19",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@testing-library/user-event": "^7.1.2",
|
||||
"@types/classnames": "^2.2.10",
|
||||
"@types/jest": "^24.0.0",
|
||||
"@types/lodash": "^4.14.159",
|
||||
"@types/node": "^12.0.0",
|
||||
"@types/react": "^16.9.0",
|
||||
"@types/react-dom": "^16.9.0",
|
||||
"@types/yup": "^0.29.3",
|
||||
"eslint-config-matrix-org": "^0.1.0",
|
||||
"husky": "^4.2.5",
|
||||
"lint-staged": "^10.2.7",
|
||||
"node-sass": "^4.14.1",
|
||||
"prettier": "^2.0.5",
|
||||
"storybook-addon-designs": "^5.4.0",
|
||||
"ts-jest": "^26.1.4",
|
||||
"typescript": "~3.7.2"
|
||||
}
|
||||
"name": "matrix.to",
|
||||
"version": "1.1.3",
|
||||
"type": "module",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node scripts/serve-local.js",
|
||||
"build": "node scripts/build.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@rollup/plugin-babel": "^5.1.0",
|
||||
"@rollup/plugin-commonjs": "^15.0.0",
|
||||
"@rollup/plugin-multi-entry": "^4.0.0",
|
||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||
"@rollup/plugin-replace": "^2.3.4",
|
||||
"autoprefixer": "^10.0.1",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"core-js": "^3.6.5",
|
||||
"finalhandler": "^1.1.2",
|
||||
"mdn-polyfills": "^5.20.0",
|
||||
"postcss": "^8.1.1",
|
||||
"postcss-css-variables": "^0.17.0",
|
||||
"postcss-flexbugs-fixes": "^4.2.1",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-url": "^8.0.0",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"rollup": "^2.26.4",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"serve-static": "^1.14.1",
|
||||
"xxhashjs": "^0.2.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="A client-side matrix link redirection service"
|
||||
/>
|
||||
<title>Matrix.to</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
317
scripts/build.js
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import cheerio from "cheerio";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import xxhash from 'xxhashjs';
|
||||
import { rollup } from 'rollup';
|
||||
import postcss from "postcss";
|
||||
import postcssImport from "postcss-import";
|
||||
// needed for legacy bundle
|
||||
import babel from '@rollup/plugin-babel';
|
||||
// needed to find the polyfill modules in the main-legacy.js bundle
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
// needed because some of the polyfills are written as commonjs modules
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
// multi-entry plugin so we can add polyfill file to main
|
||||
import multi from '@rollup/plugin-multi-entry';
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
import replace from "@rollup/plugin-replace";
|
||||
// replace urls of asset names with content hashed version
|
||||
import postcssUrl from "postcss-url";
|
||||
import cssvariables from "postcss-css-variables";
|
||||
import autoprefixer from "autoprefixer";
|
||||
import flexbugsFixes from "postcss-flexbugs-fixes";
|
||||
|
||||
import {createClients} from "../src/open/clients/index.js";
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
const projectDir = path.join(dirname(fileURLToPath(import.meta.url)), "../");
|
||||
|
||||
async function build() {
|
||||
// get version number
|
||||
const version = JSON.parse(await fs.readFile(path.join(projectDir, "package.json"), "utf8")).version;
|
||||
// clear target dir
|
||||
const targetDir = path.join(projectDir, "build/");
|
||||
await removeDirIfExists(targetDir);
|
||||
await fs.mkdir(targetDir);
|
||||
await fs.mkdir(path.join(targetDir, "images"));
|
||||
await fs.mkdir(path.join(targetDir, ".well-known"));
|
||||
const assets = new AssetMap(targetDir);
|
||||
const imageAssets = await copyFolder(path.join(projectDir, "images"), path.join(targetDir, "images"));
|
||||
assets.addSubMap(imageAssets);
|
||||
await assets.write(`bundle-esm.js`, await buildJs("src/main.js", assets));
|
||||
await assets.write(`bundle-legacy.js`, await buildJsLegacy("src/main.js", assets, ["src/polyfill.js"]));
|
||||
await assets.write(`bundle.css`, await buildCss("css/main.css", targetDir, assets));
|
||||
await assets.writeUnhashed(".well-known/apple-app-site-association", buildAppleAssociatedAppsFile(createClients()));
|
||||
await assets.writeUnhashed("index.html", await buildHtml(assets));
|
||||
const globalHash = assets.hashForAll();
|
||||
console.log(`built matrix.to ${version} (${globalHash}) successfully with ${assets.size} files`);
|
||||
}
|
||||
|
||||
async function buildHtml(assets) {
|
||||
const devHtml = await fs.readFile(path.join(projectDir, "index.html"), "utf8");
|
||||
const doc = cheerio.load(devHtml);
|
||||
doc("link[rel=stylesheet]").attr("href", assets.resolve(`bundle.css`));
|
||||
const mainScripts = [
|
||||
`<script type="module">import {main} from "./${assets.resolve(`bundle-esm.js`)}"; main(document.body);</script>`,
|
||||
`<script type="text/javascript" nomodule src="${assets.resolve(`bundle-legacy.js`)}"></script>`,
|
||||
`<script type="text/javascript" nomodule>bundle.main(document.body);</script>`
|
||||
];
|
||||
doc("script#main").replaceWith(mainScripts.join(""));
|
||||
return doc.html();
|
||||
}
|
||||
|
||||
function createReplaceUrlPlugin(assets) {
|
||||
const replacements = {};
|
||||
for (const [key, value] of assets) {
|
||||
replacements[key] = value;
|
||||
}
|
||||
return replace(replacements);
|
||||
}
|
||||
|
||||
async function buildJs(mainFile, assets, extraFiles = []) {
|
||||
// create js bundle
|
||||
const bundle = await rollup({
|
||||
input: extraFiles.concat(mainFile),
|
||||
plugins: [multi(), terser(), createReplaceUrlPlugin(assets)],
|
||||
});
|
||||
const {output} = await bundle.generate({
|
||||
format: 'es',
|
||||
});
|
||||
const code = output[0].code;
|
||||
return code;
|
||||
}
|
||||
|
||||
async function buildJsLegacy(mainFile, assets, extraFiles = []) {
|
||||
// compile down to whatever IE 11 needs
|
||||
const babelPlugin = babel.babel({
|
||||
babelHelpers: 'bundled',
|
||||
exclude: 'node_modules/**',
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
useBuiltIns: "entry",
|
||||
corejs: "3",
|
||||
targets: "IE 11",
|
||||
}
|
||||
]
|
||||
]
|
||||
});
|
||||
// create js bundle
|
||||
const rollupConfig = {
|
||||
// important the extraFiles come first,
|
||||
// so polyfills are available in the global scope
|
||||
// if needed for the mainfile
|
||||
input: extraFiles.concat(mainFile),
|
||||
plugins: [multi(), commonjs(), nodeResolve(), createReplaceUrlPlugin(assets), babelPlugin, terser()]
|
||||
};
|
||||
const bundle = await rollup(rollupConfig);
|
||||
const {output} = await bundle.generate({
|
||||
format: 'iife',
|
||||
name: `bundle`
|
||||
});
|
||||
const code = output[0].code;
|
||||
return code;
|
||||
}
|
||||
|
||||
function buildAppleAssociatedAppsFile(clients) {
|
||||
const appIds = clients.map(c => c.appleAssociatedAppId).filter(id => !!id);
|
||||
return JSON.stringify({
|
||||
"applinks": {
|
||||
"apps": [],
|
||||
"details": {
|
||||
appIDs: appIds,
|
||||
components: [
|
||||
{
|
||||
"#": "/*", // only open urls with a fragment, so you can still create links
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
"webcredentials": {
|
||||
"apps": appIds
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function buildCss(entryPath, targetDir, assets) {
|
||||
entryPath = path.join(projectDir, entryPath);
|
||||
const assetUrlMapper = ({absolutePath}) => {
|
||||
const relPath = absolutePath.substr(projectDir.length);
|
||||
return assets.resolve(path.join(targetDir, relPath));
|
||||
};
|
||||
|
||||
const preCss = await fs.readFile(entryPath, "utf8");
|
||||
const options = [
|
||||
postcssImport,
|
||||
cssvariables(),
|
||||
autoprefixer({overrideBrowserslist: ["IE 11"], grid: "no-autoplace"}),
|
||||
flexbugsFixes(),
|
||||
postcssUrl({url: assetUrlMapper}),
|
||||
];
|
||||
const cssBundler = postcss(options);
|
||||
const result = await cssBundler.process(preCss, {from: entryPath});
|
||||
return result.css;
|
||||
}
|
||||
|
||||
async function removeDirIfExists(targetDir) {
|
||||
try {
|
||||
await fs.rmdir(targetDir, {recursive: true});
|
||||
} catch (err) {
|
||||
if (err.code !== "ENOENT") {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyFolder(srcRoot, dstRoot, filter = null, assets = null) {
|
||||
assets = assets || new AssetMap(dstRoot);
|
||||
const dirEnts = await fs.readdir(srcRoot, {withFileTypes: true});
|
||||
for (const dirEnt of dirEnts) {
|
||||
const dstPath = path.join(dstRoot, dirEnt.name);
|
||||
const srcPath = path.join(srcRoot, dirEnt.name);
|
||||
if (dirEnt.isDirectory()) {
|
||||
await fs.mkdir(dstPath);
|
||||
await copyFolder(srcPath, dstPath, filter, assets);
|
||||
} else if ((dirEnt.isFile() || dirEnt.isSymbolicLink()) && (!filter || filter(srcPath))) {
|
||||
const content = await fs.readFile(srcPath);
|
||||
await assets.write(dstPath, content);
|
||||
}
|
||||
}
|
||||
return assets;
|
||||
}
|
||||
|
||||
function contentHash(str) {
|
||||
var hasher = new xxhash.h32(0);
|
||||
hasher.update(str);
|
||||
return hasher.digest();
|
||||
}
|
||||
|
||||
class AssetMap {
|
||||
constructor(targetDir) {
|
||||
// remove last / if any, so substr in create works well
|
||||
this._targetDir = path.resolve(targetDir);
|
||||
this._assets = new Map();
|
||||
// hashes for unhashed resources so changes in these resources also contribute to the hashForAll
|
||||
this._unhashedHashes = [];
|
||||
}
|
||||
|
||||
_toRelPath(resourcePath) {
|
||||
let relPath = resourcePath;
|
||||
if (path.isAbsolute(resourcePath)) {
|
||||
if (!resourcePath.startsWith(this._targetDir)) {
|
||||
throw new Error(`absolute path ${resourcePath} that is not within target dir ${this._targetDir}`);
|
||||
}
|
||||
relPath = resourcePath.substr(this._targetDir.length + 1); // + 1 for the /
|
||||
}
|
||||
return relPath;
|
||||
}
|
||||
|
||||
_create(resourcePath, content) {
|
||||
const relPath = this._toRelPath(resourcePath);
|
||||
const hash = contentHash(Buffer.from(content));
|
||||
const dir = path.dirname(relPath);
|
||||
const extname = path.extname(relPath);
|
||||
const basename = path.basename(relPath, extname);
|
||||
const dstRelPath = path.join(dir, `${basename}-${hash}${extname}`);
|
||||
this._assets.set(relPath, dstRelPath);
|
||||
return dstRelPath;
|
||||
}
|
||||
|
||||
async write(resourcePath, content) {
|
||||
const relPath = this._create(resourcePath, content);
|
||||
const fullPath = path.join(this.directory, relPath);
|
||||
if (typeof content === "string") {
|
||||
await fs.writeFile(fullPath, content, "utf8");
|
||||
} else {
|
||||
await fs.writeFile(fullPath, content);
|
||||
}
|
||||
return relPath;
|
||||
}
|
||||
|
||||
async writeUnhashed(resourcePath, content) {
|
||||
const relPath = this._toRelPath(resourcePath);
|
||||
this._assets.set(relPath, relPath);
|
||||
const fullPath = path.join(this.directory, relPath);
|
||||
if (typeof content === "string") {
|
||||
await fs.writeFile(fullPath, content, "utf8");
|
||||
} else {
|
||||
await fs.writeFile(fullPath, content);
|
||||
}
|
||||
return relPath;
|
||||
}
|
||||
|
||||
get directory() {
|
||||
return this._targetDir;
|
||||
}
|
||||
|
||||
resolve(resourcePath) {
|
||||
const relPath = this._toRelPath(resourcePath);
|
||||
const result = this._assets.get(relPath);
|
||||
if (!result) {
|
||||
throw new Error(`unknown path: ${relPath}, only know ${Array.from(this._assets.keys()).join(", ")}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
addSubMap(assetMap) {
|
||||
if (!assetMap.directory.startsWith(this.directory)) {
|
||||
throw new Error(`map directory doesn't start with this directory: ${assetMap.directory} ${this.directory}`);
|
||||
}
|
||||
const relSubRoot = assetMap.directory.substr(this.directory.length + 1);
|
||||
for (const [key, value] of assetMap._assets.entries()) {
|
||||
this._assets.set(path.join(relSubRoot, key), path.join(relSubRoot, value));
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this._assets.entries();
|
||||
}
|
||||
|
||||
isUnhashed(relPath) {
|
||||
const resolvedPath = this._assets.get(relPath);
|
||||
if (!resolvedPath) {
|
||||
throw new Error("Unknown asset: " + relPath);
|
||||
}
|
||||
return relPath === resolvedPath;
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this._assets.size;
|
||||
}
|
||||
|
||||
has(relPath) {
|
||||
return this._assets.has(relPath);
|
||||
}
|
||||
|
||||
hashForAll() {
|
||||
const globalHashAssets = Array.from(this).map(([, resolved]) => resolved);
|
||||
globalHashAssets.push(...this._unhashedHashes);
|
||||
globalHashAssets.sort();
|
||||
return contentHash(globalHashAssets.join(","));
|
||||
}
|
||||
|
||||
addToHashForAll(resourcePath, content) {
|
||||
this._unhashedHashes.push(`${resourcePath}-${contentHash(Buffer.from(content))}`);
|
||||
}
|
||||
}
|
||||
|
||||
build().catch(err => console.error(err));
|
45
scripts/serve-local.js
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import finalhandler from "finalhandler"
|
||||
import http from "http"
|
||||
import serveStatic from "serve-static"
|
||||
import path from "path"
|
||||
import { fileURLToPath } from "url";
|
||||
const projectDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../");
|
||||
|
||||
// Serve up parent directory with cache disabled
|
||||
const serve = serveStatic(
|
||||
projectDir,
|
||||
{
|
||||
etag: false,
|
||||
setHeaders: res => {
|
||||
res.setHeader("Pragma", "no-cache");
|
||||
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
res.setHeader("Expires", "Wed, 21 Oct 2015 07:28:00 GMT");
|
||||
},
|
||||
index: ['index.html', 'index.htm']
|
||||
}
|
||||
);
|
||||
|
||||
// Create server
|
||||
const server = http.createServer(function onRequest (req, res) {
|
||||
console.log(req.method, req.url);
|
||||
serve(req, res, finalhandler(req, res))
|
||||
});
|
||||
|
||||
// Listen
|
||||
server.listen(5000);
|
76
src/App.tsx
@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import SingleColumn from './layouts/SingleColumn';
|
||||
import CreateLinkTile from './components/CreateLinkTile';
|
||||
import MatrixTile from './components/MatrixTile';
|
||||
import Tile from './components/Tile';
|
||||
import LinkRouter from './pages/LinkRouter';
|
||||
|
||||
import './App.scss';
|
||||
|
||||
import GlobalContext from './contexts/GlobalContext';
|
||||
|
||||
/* eslint-disable no-restricted-globals */
|
||||
|
||||
const App: React.FC = () => {
|
||||
let page = (
|
||||
<>
|
||||
<CreateLinkTile />
|
||||
</>
|
||||
);
|
||||
|
||||
const [hash, setHash] = useState(location.hash);
|
||||
|
||||
console.log(`Link for ${hash}`);
|
||||
|
||||
useEffect(() => {
|
||||
// Some hacky uri decoding
|
||||
if (location.href.split('/').length > 4) {
|
||||
location.href = decodeURIComponent(location.href);
|
||||
}
|
||||
|
||||
window.onhashchange = () => setHash(location.hash);
|
||||
}, []);
|
||||
|
||||
if (hash) {
|
||||
if (hash.startsWith('#/')) {
|
||||
page = <LinkRouter link={hash.slice(2)} />;
|
||||
} else {
|
||||
page = (
|
||||
<Tile>
|
||||
Links should be in the format {location.host}/#/{'<'}
|
||||
matrix-resource-identifier{'>'}
|
||||
</Tile>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<GlobalContext>
|
||||
<SingleColumn>
|
||||
<div className="topSpacer" />
|
||||
{page}
|
||||
<MatrixTile isLink={!!location.hash} />
|
||||
<div className="bottomSpacer" />
|
||||
</SingleColumn>
|
||||
</GlobalContext>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
163
src/Link.js
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {createEnum} from "./utils/enum.js";
|
||||
import {orderedUnique} from "./utils/unique.js";
|
||||
|
||||
const ROOMALIAS_PATTERN = /^#([^:]*):(.+)$/;
|
||||
const ROOMID_PATTERN = /^!([^:]*):(.+)$/;
|
||||
const USERID_PATTERN = /^@([^:]+):(.+)$/;
|
||||
const EVENTID_PATTERN = /^$([^:]+):(.+)$/;
|
||||
const GROUPID_PATTERN = /^\+([^:]+):(.+)$/;
|
||||
|
||||
export const IdentifierKind = createEnum(
|
||||
"RoomId",
|
||||
"RoomAlias",
|
||||
"UserId",
|
||||
"GroupId",
|
||||
);
|
||||
|
||||
function asPrefix(identifierKind) {
|
||||
switch (identifierKind) {
|
||||
case IdentifierKind.RoomId: return "!";
|
||||
case IdentifierKind.RoomAlias: return "#";
|
||||
case IdentifierKind.GroupId: return "+";
|
||||
case IdentifierKind.UserId: return "@";
|
||||
default: throw new Error("invalid id kind " + identifierKind);
|
||||
}
|
||||
}
|
||||
|
||||
export function getLabelForLinkKind(kind) {
|
||||
switch (kind) {
|
||||
case LinkKind.User: return "Start chat";
|
||||
case LinkKind.Room: return "View room";
|
||||
case LinkKind.Group: return "View community";
|
||||
case LinkKind.Event: return "View message";
|
||||
}
|
||||
}
|
||||
|
||||
export const LinkKind = createEnum(
|
||||
"Room",
|
||||
"User",
|
||||
"Group",
|
||||
"Event"
|
||||
)
|
||||
|
||||
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) {
|
||||
if (!fragment) {
|
||||
return null;
|
||||
}
|
||||
let [linkStr, queryParamsStr] = fragment.split("?");
|
||||
|
||||
let viaServers = [];
|
||||
let clientId = null;
|
||||
if (queryParamsStr) {
|
||||
const queryParams = queryParamsStr.split("&").map(pair => pair.split("="));
|
||||
viaServers = queryParams
|
||||
.filter(([key, value]) => key === "via")
|
||||
.map(([,value]) => value);
|
||||
const clientParam = queryParams.find(([key]) => key === "client");
|
||||
if (clientParam) {
|
||||
clientId = clientParam[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (linkStr.startsWith("#/")) {
|
||||
linkStr = linkStr.substr(2);
|
||||
}
|
||||
|
||||
const [identifier, eventId] = linkStr.split("/");
|
||||
|
||||
let matches;
|
||||
matches = USERID_PATTERN.exec(identifier);
|
||||
if (matches) {
|
||||
const server = matches[2];
|
||||
const localPart = matches[1];
|
||||
return new Link(clientId, viaServers, IdentifierKind.UserId, localPart, server);
|
||||
}
|
||||
matches = ROOMALIAS_PATTERN.exec(identifier);
|
||||
if (matches) {
|
||||
const server = matches[2];
|
||||
const localPart = matches[1];
|
||||
return new Link(clientId, viaServers, IdentifierKind.RoomAlias, localPart, server, eventId);
|
||||
}
|
||||
matches = ROOMID_PATTERN.exec(identifier);
|
||||
if (matches) {
|
||||
const server = matches[2];
|
||||
const localPart = matches[1];
|
||||
return new Link(clientId, viaServers, IdentifierKind.RoomId, localPart, server, eventId);
|
||||
}
|
||||
matches = GROUPID_PATTERN.exec(identifier);
|
||||
if (matches) {
|
||||
const server = matches[2];
|
||||
const localPart = matches[1];
|
||||
return new Link(clientId, viaServers, IdentifierKind.GroupId, localPart, server);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
constructor(clientId, viaServers, identifierKind, localPart, server, eventId) {
|
||||
const servers = [server];
|
||||
servers.push(...viaServers);
|
||||
this.servers = orderedUnique(servers);
|
||||
this.identifierKind = identifierKind;
|
||||
this.identifier = `${asPrefix(identifierKind)}${localPart}:${server}`;
|
||||
this.eventId = eventId;
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
get kind() {
|
||||
if (this.eventId) {
|
||||
return LinkKind.Event;
|
||||
}
|
||||
switch (this.identifierKind) {
|
||||
case IdentifierKind.RoomId:
|
||||
case IdentifierKind.RoomAlias:
|
||||
return LinkKind.Room;
|
||||
case IdentifierKind.UserId:
|
||||
return LinkKind.User;
|
||||
case IdentifierKind.GroupId:
|
||||
return LinkKind.Group;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
equals(link) {
|
||||
return link &&
|
||||
link.identifier === this.identifier &&
|
||||
this.servers.length === link.servers.length &&
|
||||
this.servers.every((s, i) => link.servers[i] === s);
|
||||
}
|
||||
|
||||
toFragment() {
|
||||
if (this.eventId) {
|
||||
return `/${this.identifier}/${this.eventId}`;
|
||||
} else {
|
||||
return `/${this.identifier}`;
|
||||
}
|
||||
}
|
||||
}
|
64
src/Platform.js
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {createEnum} from "./utils/enum.js";
|
||||
|
||||
export const Platform = createEnum(
|
||||
"DesktopWeb",
|
||||
"MobileWeb",
|
||||
"Android",
|
||||
"iOS",
|
||||
"Windows",
|
||||
"macOS",
|
||||
"Linux"
|
||||
);
|
||||
|
||||
export function guessApplicablePlatforms(userAgent, platform) {
|
||||
// return [Platform.DesktopWeb, Platform.Linux];
|
||||
let nativePlatform;
|
||||
let webPlatform;
|
||||
if (/android/i.test(userAgent)) {
|
||||
nativePlatform = Platform.Android;
|
||||
webPlatform = Platform.MobileWeb;
|
||||
} else if ( // https://stackoverflow.com/questions/9038625/detect-if-device-is-ios/9039885
|
||||
(
|
||||
/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
|
||||
) && !window.MSStream
|
||||
) {
|
||||
nativePlatform = Platform.iOS;
|
||||
webPlatform = Platform.MobileWeb;
|
||||
} else if (platform.toLowerCase().indexOf("linux") !== -1) {
|
||||
nativePlatform = Platform.Linux;
|
||||
webPlatform = Platform.DesktopWeb;
|
||||
} else if (platform.toLowerCase().indexOf("mac") !== -1) {
|
||||
nativePlatform = Platform.macOS;
|
||||
webPlatform = Platform.DesktopWeb;
|
||||
} else {
|
||||
nativePlatform = Platform.Windows;
|
||||
webPlatform = Platform.DesktopWeb;
|
||||
}
|
||||
return [nativePlatform, webPlatform];
|
||||
}
|
||||
|
||||
export function isWebPlatform(p) {
|
||||
return p === Platform.DesktopWeb || p === Platform.MobileWeb;
|
||||
}
|
||||
|
||||
|
||||
export function isDesktopPlatform(p) {
|
||||
return p === Platform.Linux || p === Platform.Windows || p === Platform.macOS;
|
||||
}
|
68
src/Preferences.js
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {Platform} from "./Platform.js";
|
||||
import {EventEmitter} from "./utils/ViewModel.js";
|
||||
|
||||
export class Preferences extends EventEmitter {
|
||||
constructor(localStorage) {
|
||||
super();
|
||||
this._localStorage = localStorage;
|
||||
this.clientId = null;
|
||||
// used to differentiate web from native if a client supports both
|
||||
this.platform = null;
|
||||
this.homeservers = null;
|
||||
|
||||
const prefsStr = localStorage.getItem("preferred_client");
|
||||
if (prefsStr) {
|
||||
const {id, platform} = JSON.parse(prefsStr);
|
||||
this.clientId = id;
|
||||
this.platform = Platform[platform];
|
||||
}
|
||||
const serversStr = localStorage.getItem("consented_servers");
|
||||
if (serversStr) {
|
||||
this.homeservers = JSON.parse(serversStr);
|
||||
}
|
||||
}
|
||||
|
||||
setClient(id, platform) {
|
||||
this.clientId = id;
|
||||
platform = Platform[platform];
|
||||
this.platform = platform;
|
||||
this._localStorage.setItem("preferred_client", JSON.stringify({id, platform}));
|
||||
this.emit("canClear")
|
||||
}
|
||||
|
||||
setHomeservers(homeservers, persist) {
|
||||
this.homeservers = homeservers;
|
||||
if (persist) {
|
||||
this._localStorage.setItem("consented_servers", JSON.stringify(homeservers));
|
||||
this.emit("canClear");
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._localStorage.removeItem("preferred_client");
|
||||
this._localStorage.removeItem("consented_servers");
|
||||
this.clientId = null;
|
||||
this.platform = null;
|
||||
this.homeservers = null;
|
||||
}
|
||||
|
||||
get canClear() {
|
||||
return !!this.clientId || !!this.platform || !!this.homeservers;
|
||||
}
|
||||
}
|
44
src/RootView.js
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {TemplateView} from "./utils/TemplateView.js";
|
||||
import {OpenLinkView} from "./open/OpenLinkView.js";
|
||||
import {CreateLinkView} from "./create/CreateLinkView.js";
|
||||
import {LoadServerPolicyView} from "./policy/LoadServerPolicyView.js";
|
||||
|
||||
export class RootView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.div({className: "RootView"}, [
|
||||
t.mapView(vm => vm.openLinkViewModel, vm => vm ? new OpenLinkView(vm) : null),
|
||||
t.mapView(vm => vm.createLinkViewModel, vm => vm ? new CreateLinkView(vm) : null),
|
||||
t.mapView(vm => vm.loadServerPolicyViewModel, vm => vm ? new LoadServerPolicyView(vm) : null),
|
||||
t.div({className: "footer"}, [
|
||||
t.p(t.img({src: "images/matrix-logo.svg"})),
|
||||
t.p(["This invite uses ", externalLink(t, "https://matrix.org", "Matrix"), ", an open network for secure, decentralized communication."]),
|
||||
t.ul({className: "links"}, [
|
||||
t.li(externalLink(t, "https://github.com/matrix-org/matrix.to", "GitHub project")),
|
||||
t.li(externalLink(t, "https://github.com/matrix-org/matrix.to/tree/main/src/clients", "Add your app")),
|
||||
t.li({className: {hidden: vm => !vm.hasPreferences}},
|
||||
t.button({className: "text", onClick: () => vm.clearPreferences()}, "Clear preferences")),
|
||||
])
|
||||
])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function externalLink(t, href, label) {
|
||||
return t.a({href, target: "_blank", rel: "noopener noreferrer"}, label);
|
||||
}
|
73
src/RootViewModel.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {Link} from "./Link.js";
|
||||
import {ViewModel} from "./utils/ViewModel.js";
|
||||
import {OpenLinkViewModel} from "./open/OpenLinkViewModel.js";
|
||||
import {createClients} from "./open/clients/index.js";
|
||||
import {CreateLinkViewModel} from "./create/CreateLinkViewModel.js";
|
||||
import {LoadServerPolicyViewModel} from "./policy/LoadServerPolicyViewModel.js";
|
||||
import {Platform} from "./Platform.js";
|
||||
|
||||
export class RootViewModel extends ViewModel {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.link = null;
|
||||
this.openLinkViewModel = null;
|
||||
this.createLinkViewModel = null;
|
||||
this.loadServerPolicyViewModel = null;
|
||||
this.preferences.on("canClear", () => {
|
||||
this.emitChange();
|
||||
});
|
||||
}
|
||||
|
||||
_updateChildVMs(oldLink) {
|
||||
if (this.link) {
|
||||
this.createLinkViewModel = null;
|
||||
if (!oldLink || !oldLink.equals(this.link)) {
|
||||
this.openLinkViewModel = new OpenLinkViewModel(this.childOptions({
|
||||
link: this.link,
|
||||
clients: createClients(),
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
this.openLinkViewModel = null;
|
||||
this.createLinkViewModel = new CreateLinkViewModel(this.childOptions());
|
||||
}
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
updateHash(hash) {
|
||||
if (hash.startsWith("#/policy/")) {
|
||||
const server = hash.substr(9);
|
||||
this.loadServerPolicyViewModel = new LoadServerPolicyViewModel(this.childOptions({server}));
|
||||
this.loadServerPolicyViewModel.load();
|
||||
} else {
|
||||
const oldLink = this.link;
|
||||
this.link = Link.parse(hash);
|
||||
this._updateChildVMs(oldLink);
|
||||
}
|
||||
}
|
||||
|
||||
clearPreferences() {
|
||||
this.preferences.clear();
|
||||
this._updateChildVMs();
|
||||
}
|
||||
|
||||
get hasPreferences() {
|
||||
return this.preferences.canClear;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
$app-background: #f4f4f4;
|
||||
$background: #ffffff;
|
||||
$foreground: #000000;
|
||||
$font: #333333;
|
||||
$grey: #666666;
|
||||
$accent: #0098d4;
|
||||
$error: #d6001c;
|
||||
$link: #0098d4;
|
||||
$borders: #f4f4f4;
|
@ -1,11 +0,0 @@
|
||||
@mixin unreal-focus {
|
||||
outline-width: 2px;
|
||||
outline-style: solid;
|
||||
outline-color: Highlight;
|
||||
|
||||
/* WebKit gets its native focus styles. */
|
||||
@media (-webkit-min-device-pixel-ratio: 0) {
|
||||
outline-color: -webkit-focus-ring-color;
|
||||
outline-style: auto;
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
LinkedClient,
|
||||
Maturity,
|
||||
ClientKind,
|
||||
ClientId,
|
||||
Platform,
|
||||
AppleStoreLink,
|
||||
PlayStoreLink,
|
||||
FDroidLink,
|
||||
} from './types';
|
||||
import { LinkKind } from '../parser/types';
|
||||
import logo from '../imgs/element.svg';
|
||||
|
||||
export const Element: LinkedClient = {
|
||||
kind: ClientKind.LINKED_CLIENT,
|
||||
name: 'Element',
|
||||
author: 'Element',
|
||||
logo: logo,
|
||||
homepage: 'https://element.io',
|
||||
maturity: Maturity.STABLE,
|
||||
description: 'Fully-featured Matrix client',
|
||||
platforms: [Platform.Desktop, Platform.Android, Platform.iOS],
|
||||
experimental: false,
|
||||
clientId: ClientId.Element,
|
||||
toUrl: (link) => {
|
||||
const params = link.arguments.originalParams.toString();
|
||||
const prefixedParams = params ? `?${params}` : '';
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
return new URL(
|
||||
`https://app.element.io/#/room/${link.identifier}${prefixedParams}`
|
||||
);
|
||||
case LinkKind.UserId:
|
||||
return new URL(
|
||||
`https://app.element.io/#/user/${link.identifier}${prefixedParams}`
|
||||
);
|
||||
case LinkKind.Permalink:
|
||||
return new URL(
|
||||
`https://app.element.io/#/room/${link.identifier}${prefixedParams}`
|
||||
);
|
||||
case LinkKind.GroupId:
|
||||
return new URL(
|
||||
`https://app.element.io/#/group/${link.identifier}${prefixedParams}`
|
||||
);
|
||||
}
|
||||
},
|
||||
linkSupport: () => true,
|
||||
installLinks: [
|
||||
new AppleStoreLink('vector', 'id1083446067'),
|
||||
new PlayStoreLink('im.vector.app'),
|
||||
new FDroidLink('im.vector.app'),
|
||||
],
|
||||
};
|
||||
|
||||
export const ElementDevelop: LinkedClient = {
|
||||
kind: ClientKind.LINKED_CLIENT,
|
||||
name: 'Element Develop',
|
||||
author: 'Element',
|
||||
logo: logo,
|
||||
homepage: 'https://element.io',
|
||||
maturity: Maturity.STABLE,
|
||||
description: 'Fully-featured Matrix client for the Web',
|
||||
platforms: [Platform.Desktop],
|
||||
experimental: true,
|
||||
clientId: ClientId.ElementDevelop,
|
||||
toUrl: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
return new URL(
|
||||
`https://develop.element.io/#/room/${link.identifier}`
|
||||
);
|
||||
case LinkKind.UserId:
|
||||
return new URL(
|
||||
`https://develop.element.io/#/user/${link.identifier}`
|
||||
);
|
||||
case LinkKind.Permalink:
|
||||
return new URL(
|
||||
`https://develop.element.io/#/room/${link.identifier}`
|
||||
);
|
||||
case LinkKind.GroupId:
|
||||
return new URL(
|
||||
`https://develop.element.io/#/group/${link.identifier}`
|
||||
);
|
||||
}
|
||||
},
|
||||
linkSupport: () => true,
|
||||
installLinks: [],
|
||||
};
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { TextClient, Maturity, ClientKind, ClientId, Platform } from './types';
|
||||
|
||||
import { LinkKind } from '../parser/types';
|
||||
|
||||
import logo from '../imgs/fractal.png';
|
||||
|
||||
const Fractal: TextClient = {
|
||||
kind: ClientKind.TEXT_CLIENT,
|
||||
name: 'Fractal',
|
||||
logo: logo,
|
||||
author: 'Daniel Garcia Moreno',
|
||||
homepage: 'https://github.com/poljar/weechat-matrix',
|
||||
maturity: Maturity.BETA,
|
||||
experimental: false,
|
||||
platforms: [Platform.Desktop],
|
||||
clientId: ClientId.Fractal,
|
||||
toInviteString: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
case LinkKind.UserId:
|
||||
return (
|
||||
<span>
|
||||
Click the '+' button in the top right and paste the
|
||||
identifier
|
||||
</span>
|
||||
);
|
||||
default:
|
||||
return <span>Fractal doesn't support this kind of link</span>;
|
||||
}
|
||||
},
|
||||
copyString: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
case LinkKind.UserId:
|
||||
return `${link.identifier}`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
linkSupport: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
case LinkKind.UserId:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
description: 'Fractal is a Matrix Client written in Rust',
|
||||
installLinks: [],
|
||||
};
|
||||
|
||||
export default Fractal;
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { TextClient, Maturity, ClientKind, ClientId, Platform } from './types';
|
||||
|
||||
import { LinkKind } from '../parser/types';
|
||||
|
||||
import logo from '../imgs/nheko.svg';
|
||||
|
||||
const Nheko: TextClient = {
|
||||
kind: ClientKind.TEXT_CLIENT,
|
||||
name: 'Nheko',
|
||||
logo: logo,
|
||||
author: 'mujx, red_sky, deepbluev7, Konstantinos Sideris',
|
||||
homepage: 'https://github.com/Nheko-Reborn/nheko',
|
||||
maturity: Maturity.BETA,
|
||||
experimental: false,
|
||||
platforms: [Platform.Desktop],
|
||||
clientId: ClientId.Nheko,
|
||||
toInviteString: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
return (
|
||||
<span>
|
||||
Type{' '}
|
||||
<code>
|
||||
/join{' '}
|
||||
<b className="matrixIdentifier">
|
||||
{link.identifier}
|
||||
</b>
|
||||
</code>
|
||||
</span>
|
||||
);
|
||||
case LinkKind.UserId:
|
||||
return (
|
||||
<span>
|
||||
Type{' '}
|
||||
<code>
|
||||
/invite{' '}
|
||||
<b className="matrixIdentifier">
|
||||
{link.identifier}
|
||||
</b>
|
||||
</code>
|
||||
</span>
|
||||
);
|
||||
default:
|
||||
return <span>Nheko doesn't support this kind of link</span>;
|
||||
}
|
||||
},
|
||||
copyString: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
return `/join ${link.identifier}`;
|
||||
case LinkKind.UserId:
|
||||
return `/invite ${link.identifier}`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
linkSupport: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
case LinkKind.UserId:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
description:
|
||||
'A native desktop app for Matrix that feels more like a mainstream chat app.',
|
||||
installLinks: [],
|
||||
};
|
||||
|
||||
export default Nheko;
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { TextClient, Maturity, ClientKind, ClientId, Platform } from './types';
|
||||
|
||||
import { LinkKind } from '../parser/types';
|
||||
|
||||
import logo from '../imgs/weechat.svg';
|
||||
|
||||
const Weechat: TextClient = {
|
||||
kind: ClientKind.TEXT_CLIENT,
|
||||
name: 'Weechat',
|
||||
logo: logo,
|
||||
author: 'Poljar',
|
||||
homepage: 'https://github.com/poljar/weechat-matrix',
|
||||
maturity: Maturity.LATE_BETA,
|
||||
experimental: false,
|
||||
platforms: [Platform.Desktop],
|
||||
clientId: ClientId.WeeChat,
|
||||
toInviteString: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
return (
|
||||
<span>
|
||||
Type{' '}
|
||||
<code>
|
||||
/join{' '}
|
||||
<b className="matrixIdentifier">
|
||||
{link.identifier}
|
||||
</b>
|
||||
</code>
|
||||
</span>
|
||||
);
|
||||
case LinkKind.UserId:
|
||||
return (
|
||||
<span>
|
||||
Type{' '}
|
||||
<code>
|
||||
/invite{' '}
|
||||
<b className="matrixIdentifier">
|
||||
{link.identifier}
|
||||
</b>
|
||||
</code>
|
||||
</span>
|
||||
);
|
||||
default:
|
||||
return <span>Weechat doesn't support this kind of link</span>;
|
||||
}
|
||||
},
|
||||
copyString: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
return `/join ${link.identifier}`;
|
||||
case LinkKind.UserId:
|
||||
return `/invite ${link.identifier}`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
linkSupport: (link) => {
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
case LinkKind.RoomId:
|
||||
case LinkKind.UserId:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
description: 'Command-line Matrix interface using Weechat',
|
||||
installLinks: [],
|
||||
};
|
||||
|
||||
export default Weechat;
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { Client } from './types';
|
||||
|
||||
import { Element, ElementDevelop } from './Element';
|
||||
import Weechat from './Weechat';
|
||||
import Nheko from './Nheko';
|
||||
import Fractal from './Fractal';
|
||||
|
||||
/*
|
||||
* All the supported clients of matrix.to
|
||||
*/
|
||||
const clients: Client[] = [Element, Weechat, Nheko, Fractal, ElementDevelop];
|
||||
|
||||
/*
|
||||
* A map from sharer string to client.
|
||||
* Configured by hand so we can change the mappings
|
||||
* easily later.
|
||||
*/
|
||||
export const clientMap: { [key: string]: Client } = {
|
||||
[Element.clientId]: Element,
|
||||
[Weechat.clientId]: Weechat,
|
||||
[ElementDevelop.clientId]: ElementDevelop,
|
||||
[Nheko.clientId]: Nheko,
|
||||
[Fractal.clientId]: Fractal,
|
||||
};
|
||||
|
||||
/*
|
||||
* All the supported clients of matrix.to
|
||||
*/
|
||||
export default clients;
|
@ -1,168 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { SafeLink } from '../parser/types';
|
||||
|
||||
/*
|
||||
* A collection of descriptive tags that can be added to
|
||||
* a clients description.
|
||||
*/
|
||||
export enum Platform {
|
||||
iOS = 'iOS',
|
||||
Android = 'ANDROID',
|
||||
Desktop = 'DESKTOP',
|
||||
}
|
||||
|
||||
/*
|
||||
* A collection of states used for describing a clients maturity.
|
||||
*/
|
||||
export enum Maturity {
|
||||
ALPHA = 'ALPHA',
|
||||
LATE_ALPHA = 'LATE ALPHA',
|
||||
BETA = 'BETA',
|
||||
LATE_BETA = 'LATE_BETA',
|
||||
STABLE = 'STABLE',
|
||||
}
|
||||
|
||||
/*
|
||||
* Used for constructing the discriminated union of all client types.
|
||||
*/
|
||||
export enum ClientKind {
|
||||
LINKED_CLIENT = 'LINKED_CLIENT',
|
||||
TEXT_CLIENT = 'TEXT_CLIENT',
|
||||
}
|
||||
|
||||
export enum ClientId {
|
||||
Element = 'element.io',
|
||||
ElementDevelop = 'develop.element.io',
|
||||
WeeChat = 'weechat',
|
||||
Nheko = 'nheko',
|
||||
Fractal = 'fractal',
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a native distribution channel for a client.
|
||||
* E.g App store for apple, PlayStore or F-Droid for Android
|
||||
*/
|
||||
export interface InstallLink {
|
||||
createInstallURL(deepLink: SafeLink) : string;
|
||||
// in AppleStoreLink, we can set the cookie here for deeplinking
|
||||
// onInstallChosen(deepLink: SafeLink);
|
||||
platform: Platform;
|
||||
channelId: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export class AppleStoreLink implements InstallLink {
|
||||
constructor(private org: string, private appId: string) {}
|
||||
|
||||
createInstallURL(deepLink: SafeLink) : string {
|
||||
return `https://apps.apple.com/app/${encodeURIComponent(this.org)}/${encodeURIComponent(this.appId)}`;
|
||||
}
|
||||
|
||||
get platform() : Platform {
|
||||
return Platform.iOS;
|
||||
}
|
||||
|
||||
get channelId(): string {
|
||||
return "apple-app-store";
|
||||
}
|
||||
|
||||
get description() {
|
||||
return "Download on the App Store";
|
||||
}
|
||||
}
|
||||
|
||||
export class PlayStoreLink implements InstallLink {
|
||||
constructor(private appId: string) {}
|
||||
|
||||
createInstallURL(deepLink: SafeLink) : string {
|
||||
return `https://play.google.com/store/apps/details?id=${encodeURIComponent(this.appId)}&referrer=${encodeURIComponent(deepLink.originalLink)}`;
|
||||
}
|
||||
|
||||
get platform() : Platform {
|
||||
return Platform.Android;
|
||||
}
|
||||
|
||||
get channelId(): string {
|
||||
return "play-store";
|
||||
}
|
||||
|
||||
get description() {
|
||||
return "Get it on Google Play";
|
||||
}
|
||||
}
|
||||
|
||||
export class FDroidLink implements InstallLink {
|
||||
constructor(private appId: string) {}
|
||||
|
||||
createInstallURL(deepLink: SafeLink) : string {
|
||||
return `https://f-droid.org/packages/${encodeURIComponent(this.appId)}`;
|
||||
}
|
||||
|
||||
get platform() : Platform {
|
||||
return Platform.Android;
|
||||
}
|
||||
|
||||
get channelId(): string {
|
||||
return "fdroid";
|
||||
}
|
||||
|
||||
get description() {
|
||||
return "Get it on F-Droid";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The descriptive details of a client
|
||||
*/
|
||||
export interface ClientDescription {
|
||||
name: string;
|
||||
author: string;
|
||||
homepage: string;
|
||||
logo: string;
|
||||
description: string;
|
||||
platforms: Platform[];
|
||||
maturity: Maturity;
|
||||
clientId: ClientId;
|
||||
experimental: boolean;
|
||||
linkSupport: (link: SafeLink) => boolean;
|
||||
installLinks: InstallLink[];
|
||||
}
|
||||
|
||||
/*
|
||||
* A client which can be opened using a link with the matrix resource.
|
||||
*/
|
||||
export interface LinkedClient extends ClientDescription {
|
||||
kind: ClientKind.LINKED_CLIENT;
|
||||
toUrl(parsedLink: SafeLink): URL;
|
||||
}
|
||||
|
||||
/*
|
||||
* A client which provides isntructions for how to access the descired
|
||||
* resource.
|
||||
*/
|
||||
export interface TextClient extends ClientDescription {
|
||||
kind: ClientKind.TEXT_CLIENT;
|
||||
toInviteString(parsedLink: SafeLink): JSX.Element;
|
||||
copyString(parsedLink: SafeLink): string;
|
||||
}
|
||||
|
||||
/*
|
||||
* A description for a client as well as a method for converting matrix.to
|
||||
* links to the client's specific representation.
|
||||
*/
|
||||
export type Client = LinkedClient | TextClient;
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// disable camelcase check because our object keys come
|
||||
// from the matrix spec
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { UserAvatar } from './Avatar';
|
||||
|
||||
export default {
|
||||
title: 'Avatar',
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url:
|
||||
'https://www.figma.com/file/WSXjCGc1k6FVI093qhlzOP/04-Recieving-share-link?node-id=143%3A5853',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: React.FC<{}> = () => (
|
||||
<UserAvatar
|
||||
user={{
|
||||
avatar_url: 'mxc://matrix.org/EqMZYbAYhREvHXvYFyfxOlkf',
|
||||
displayname: 'Jorik Schellekens',
|
||||
}}
|
||||
userId="@jorik:matrix.org"
|
||||
/>
|
||||
);
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Group, Room, User } from '../matrix-cypher';
|
||||
import useHSs from '../utils/getHS';
|
||||
import { getThumbnailURI } from '../utils/cypher-wrapper';
|
||||
import logo from '../imgs/chat-icon.svg';
|
||||
|
||||
import './Avatar.scss';
|
||||
|
||||
const AVATAR_SIZE = 96;
|
||||
|
||||
interface IProps {
|
||||
className?: string;
|
||||
avatarUrl: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const Avatar: React.FC<IProps> = ({ className, avatarUrl, label }: IProps) => {
|
||||
const [src, setSrc] = useState(avatarUrl);
|
||||
useEffect(() => {
|
||||
setSrc(avatarUrl ? avatarUrl : logo);
|
||||
}, [avatarUrl]);
|
||||
|
||||
const _className = classNames('avatar', className, {
|
||||
avatarNoCrop: src === logo,
|
||||
});
|
||||
return (
|
||||
<img
|
||||
src={src}
|
||||
onError={(): void => setSrc(logo)}
|
||||
alt={label}
|
||||
className={_className}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPropsUserAvatar {
|
||||
user: User;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export const UserAvatar: React.FC<IPropsUserAvatar> = ({
|
||||
user,
|
||||
userId,
|
||||
}: IPropsUserAvatar) => {
|
||||
const [hs] = useHSs({ identifier: userId });
|
||||
return (
|
||||
<Avatar
|
||||
avatarUrl={getThumbnailURI(
|
||||
hs,
|
||||
AVATAR_SIZE,
|
||||
AVATAR_SIZE,
|
||||
user.avatar_url
|
||||
)}
|
||||
label={user.displayname ? user.displayname : userId}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPropsRoomAvatar {
|
||||
room: Room;
|
||||
}
|
||||
|
||||
export const RoomAvatar: React.FC<IPropsRoomAvatar> = ({
|
||||
room,
|
||||
}: IPropsRoomAvatar) => {
|
||||
const [hs] = useHSs({ identifier: room.room_id });
|
||||
return (
|
||||
<Avatar
|
||||
avatarUrl={getThumbnailURI(
|
||||
hs,
|
||||
AVATAR_SIZE,
|
||||
AVATAR_SIZE,
|
||||
room.avatar_url
|
||||
)}
|
||||
label={room.name || room.room_id}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPropsGroupAvatar {
|
||||
group: Group;
|
||||
groupId: string;
|
||||
}
|
||||
|
||||
export const GroupAvatar: React.FC<IPropsGroupAvatar> = ({
|
||||
group,
|
||||
groupId,
|
||||
}: IPropsGroupAvatar) => {
|
||||
const [hs] = useHSs({ identifier: groupId });
|
||||
return (
|
||||
<Avatar
|
||||
avatarUrl={getThumbnailURI(
|
||||
hs,
|
||||
AVATAR_SIZE,
|
||||
AVATAR_SIZE,
|
||||
group.avatar_url
|
||||
)}
|
||||
label={group.name}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Avatar;
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
|
||||
height: 48px;
|
||||
|
||||
border-radius: 24px;
|
||||
border: 0;
|
||||
|
||||
background-color: $accent;
|
||||
color: $background;
|
||||
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
position: relative;
|
||||
|
||||
.buttonIcon {
|
||||
position: absolute;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
|
||||
left: 18px;
|
||||
top: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonSecondary {
|
||||
background-color: $background;
|
||||
color: $foreground;
|
||||
border: 1px solid $foreground;
|
||||
}
|
||||
|
||||
.errorButton:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.buttonHighlight {
|
||||
background-color: $accent;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { text } from '@storybook/addon-knobs';
|
||||
|
||||
import Button from './Button';
|
||||
|
||||
export default { title: 'Button' };
|
||||
|
||||
export const WithText: React.FC = () => (
|
||||
<Button onClick={action('clicked')}>
|
||||
{text('label', 'Hello Story Book')}
|
||||
</Button>
|
||||
);
|
||||
|
||||
export const Secondary: React.FC = () => (
|
||||
<Button secondary>Secondary button</Button>
|
||||
);
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import './Button.scss';
|
||||
|
||||
interface IProps extends React.ButtonHTMLAttributes<Element> {
|
||||
// Briefly display these instead of the children onClick
|
||||
flashChildren?: React.ReactNode;
|
||||
secondary?: boolean;
|
||||
icon?: string;
|
||||
flashIcon?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like a normal button except it will flash content when clicked.
|
||||
*/
|
||||
const Button: React.FC<
|
||||
IProps & React.RefAttributes<HTMLButtonElement>
|
||||
> = React.forwardRef(
|
||||
(
|
||||
{
|
||||
onClick,
|
||||
children,
|
||||
flashChildren,
|
||||
className,
|
||||
secondary,
|
||||
icon,
|
||||
flashIcon,
|
||||
...props
|
||||
}: IProps,
|
||||
ref: React.Ref<HTMLButtonElement>
|
||||
) => {
|
||||
const [wasClicked, setWasClicked] = React.useState(false);
|
||||
|
||||
const wrappedOnClick: React.MouseEventHandler = (e) => {
|
||||
if (onClick) {
|
||||
onClick(e);
|
||||
}
|
||||
|
||||
setWasClicked(true);
|
||||
window.setTimeout(() => {
|
||||
setWasClicked(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const content = wasClicked && flashChildren ? flashChildren : children;
|
||||
|
||||
const classNames = classnames('button', className, {
|
||||
buttonHighlight: wasClicked,
|
||||
buttonSecondary: secondary,
|
||||
});
|
||||
|
||||
const iconSrc = wasClicked && flashIcon ? flashIcon : icon;
|
||||
|
||||
const buttonIcon = icon ? (
|
||||
<img className="buttonIcon" src={iconSrc} alt="" />
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={classNames}
|
||||
onClick={wrappedOnClick}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
{buttonIcon}
|
||||
{content}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Button;
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.clientList {
|
||||
display: grid;
|
||||
row-gap: 20px;
|
||||
list-style-type: none;
|
||||
padding-inline-start: 0;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import { UAContext } from '@quentin-sommer/react-useragent';
|
||||
|
||||
import { SafeLink } from '../parser/types';
|
||||
import { ActionType, ClientContext } from '../contexts/ClientContext';
|
||||
import Clients from '../clients';
|
||||
import { Client, Platform } from '../clients/types';
|
||||
import ClientTile from './ClientTile';
|
||||
|
||||
import './ClientList.scss';
|
||||
|
||||
interface IProps {
|
||||
link: SafeLink;
|
||||
rememberSelection: boolean;
|
||||
}
|
||||
|
||||
const ClientList: React.FC<IProps> = ({ link, rememberSelection }: IProps) => {
|
||||
const [
|
||||
{ showOnlyDeviceClients, showExperimentalClients },
|
||||
clientDispatcher,
|
||||
] = useContext(ClientContext);
|
||||
const { uaResults } = useContext(UAContext);
|
||||
|
||||
/*
|
||||
* Function to decide whether a client is shown
|
||||
*/
|
||||
const showClient = (client: Client): boolean => {
|
||||
let showClient = false;
|
||||
|
||||
if (!showOnlyDeviceClients || uaResults === {}) {
|
||||
showClient = true;
|
||||
}
|
||||
|
||||
for (const platform of client.platforms) {
|
||||
switch (platform) {
|
||||
case Platform.Desktop:
|
||||
showClient = showClient || !(uaResults as any).mobile;
|
||||
break;
|
||||
case Platform.iOS:
|
||||
showClient = showClient || (uaResults as any).ios;
|
||||
break;
|
||||
case Platform.Android:
|
||||
showClient = showClient || (uaResults as any).android;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!showExperimentalClients && client.experimental) {
|
||||
showClient = false;
|
||||
}
|
||||
|
||||
if (!client.linkSupport(link)) {
|
||||
showClient = false;
|
||||
}
|
||||
|
||||
return showClient;
|
||||
};
|
||||
|
||||
const clientLi = (client: Client): JSX.Element => (
|
||||
<li
|
||||
key={client.clientId}
|
||||
onClick={(): void =>
|
||||
rememberSelection
|
||||
? clientDispatcher({
|
||||
action: ActionType.SetClient,
|
||||
clientId: client.clientId,
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<ClientTile client={client} link={link} />
|
||||
</li>
|
||||
);
|
||||
|
||||
return (
|
||||
<ul className="clientList">
|
||||
{Clients.filter(showClient).map(clientLi)}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClientList;
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext, useState } from 'react';
|
||||
|
||||
import './ClientSelection.scss';
|
||||
import { ActionType, ClientContext } from '../contexts/ClientContext';
|
||||
import ClientList from './ClientList';
|
||||
import { SafeLink } from '../parser/types';
|
||||
import Button from './Button';
|
||||
import StyledCheckbox from './StyledCheckbox';
|
||||
|
||||
interface IProps {
|
||||
link: SafeLink;
|
||||
}
|
||||
|
||||
const ClientSelection: React.FC<IProps> = ({ link }: IProps) => {
|
||||
const [clientState, clientStateDispatch] = useContext(ClientContext);
|
||||
const [rememberSelection, setRememberSelection] = useState(false);
|
||||
const options = (
|
||||
<div className="advancedOptions">
|
||||
<StyledCheckbox
|
||||
onChange={(): void => {
|
||||
setRememberSelection(!rememberSelection);
|
||||
}}
|
||||
checked={rememberSelection}
|
||||
>
|
||||
Remember for future invites in this browser
|
||||
</StyledCheckbox>
|
||||
<StyledCheckbox
|
||||
onChange={(): void => {
|
||||
clientStateDispatch({
|
||||
action: ActionType.ToggleShowOnlyDeviceClients,
|
||||
});
|
||||
}}
|
||||
checked={clientState.showOnlyDeviceClients}
|
||||
>
|
||||
Show only clients suggested for this device
|
||||
</StyledCheckbox>
|
||||
<StyledCheckbox
|
||||
onChange={(): void => {
|
||||
clientStateDispatch({
|
||||
action: ActionType.ToggleShowExperimentalClients,
|
||||
});
|
||||
}}
|
||||
checked={clientState.showExperimentalClients}
|
||||
>
|
||||
Show experimental clients
|
||||
</StyledCheckbox>
|
||||
</div>
|
||||
);
|
||||
|
||||
const clearSelection =
|
||||
clientState.clientId !== null ? (
|
||||
<Button
|
||||
onClick={(): void =>
|
||||
clientStateDispatch({
|
||||
action: ActionType.ClearClient,
|
||||
})
|
||||
}
|
||||
>
|
||||
Clear my default client
|
||||
</Button>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div className="advanced">
|
||||
{options}
|
||||
<ClientList link={link} rememberSelection={rememberSelection} />
|
||||
{clearSelection}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClientSelection;
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.clientTile {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
|
||||
color: $foreground;
|
||||
|
||||
> img {
|
||||
flex-shrink: 0;
|
||||
height: 116px;
|
||||
width: 116px;
|
||||
margin-right: 14px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
h1 {
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-right: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.button {
|
||||
height: 40px;
|
||||
min-width: 130px;
|
||||
max-width: 165px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
padding: 15px;
|
||||
|
||||
// For the chevron
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: $app-background;
|
||||
}
|
||||
|
||||
.installLink {
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
margin: 8px 16px 8px 0;
|
||||
img {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.clientTileLink {
|
||||
position: relative;
|
||||
|
||||
width: 100%;
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { UAContext } from '@quentin-sommer/react-useragent';
|
||||
|
||||
import { Client, ClientKind, Platform } from '../clients/types';
|
||||
import { SafeLink } from '../parser/types';
|
||||
import Tile from './Tile';
|
||||
import Button from './Button';
|
||||
|
||||
import appStoreBadge from '../imgs/app-store-us-alt.svg';
|
||||
import playStoreBadge from '../imgs/google-play-us.svg';
|
||||
import fdroidBadge from '../imgs/fdroid-badge.png';
|
||||
|
||||
import './ClientTile.scss';
|
||||
|
||||
interface IProps {
|
||||
client: Client;
|
||||
link: SafeLink;
|
||||
}
|
||||
|
||||
interface IInstallBadgeImages {
|
||||
[index: string]: string;
|
||||
}
|
||||
|
||||
const installBadgeImages : IInstallBadgeImages = {
|
||||
"fdroid": fdroidBadge,
|
||||
"apple-app-store": appStoreBadge,
|
||||
"play-store": playStoreBadge
|
||||
};
|
||||
|
||||
const ClientTile: React.FC<IProps> = ({ client, link }: IProps) => {
|
||||
const inviteLine =
|
||||
client.kind === ClientKind.TEXT_CLIENT ? (
|
||||
<p>{client.toInviteString(link)}</p>
|
||||
) : null;
|
||||
|
||||
const { uaResults } = useContext(UAContext);
|
||||
|
||||
const className = classNames('clientTile', {
|
||||
clientTileLink: client.kind === ClientKind.LINKED_CLIENT,
|
||||
});
|
||||
|
||||
let inviteButton: JSX.Element = <></>;
|
||||
const matchingInstallLinks = client.installLinks.filter((installLink) => {
|
||||
if ((uaResults as any).ios) {
|
||||
return installLink.platform === Platform.iOS;
|
||||
} else if ((uaResults as any).android) {
|
||||
return installLink.platform === Platform.Android;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
const hasNativeClient = matchingInstallLinks.length > 0;
|
||||
let installButtons = undefined;
|
||||
if (matchingInstallLinks.length) {
|
||||
installButtons = <p>{matchingInstallLinks.map((installLink) => {
|
||||
return <a
|
||||
rel="noopener noreferrer"
|
||||
aria-label={installLink.description}
|
||||
key={installLink.channelId}
|
||||
href={installLink.createInstallURL(link)}
|
||||
className="installLink"
|
||||
target="_blank">
|
||||
<img src={installBadgeImages[installLink.channelId]} alt={installLink.description} />
|
||||
</a>;
|
||||
})}</p>;
|
||||
}
|
||||
|
||||
if (client.kind === ClientKind.LINKED_CLIENT) {
|
||||
inviteButton = <Button>Accept invite</Button>;
|
||||
} else {
|
||||
const copyString = client.copyString(link);
|
||||
if (copyString !== '') {
|
||||
inviteButton = (
|
||||
<Button
|
||||
onClick={() => navigator.clipboard?.writeText(copyString)}
|
||||
flashChildren="Invite copied"
|
||||
>
|
||||
Copy invite
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let clientTile = (
|
||||
<Tile className={className}>
|
||||
<img src={client.logo} alt={client.name + ' logo'} />
|
||||
<div>
|
||||
<h1>{client.name}</h1>
|
||||
<p>{client.description}</p>
|
||||
{installButtons}
|
||||
{inviteLine}
|
||||
{inviteButton}
|
||||
</div>
|
||||
</Tile>
|
||||
);
|
||||
|
||||
if (client.kind === ClientKind.LINKED_CLIENT) {
|
||||
if (!hasNativeClient) {
|
||||
clientTile = (
|
||||
<a href={client.toUrl(link).toString()}>{clientTile}</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return clientTile;
|
||||
};
|
||||
|
||||
export default ClientTile;
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.createLinkTile {
|
||||
row-gap: 24px;
|
||||
|
||||
* {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> form {
|
||||
display: grid;
|
||||
row-gap: 24px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
> a {
|
||||
color: $foreground;
|
||||
font-weight: bold;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.createLinkReset {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
|
||||
border-radius: 100%;
|
||||
border: 1px solid lighten($grey, 50%);
|
||||
|
||||
background: $background;
|
||||
|
||||
padding: 6px;
|
||||
|
||||
position: relative;
|
||||
|
||||
> div {
|
||||
// This is a terrible case of faking it till
|
||||
// we make it. It will break. I'm so sorry
|
||||
position: absolute;
|
||||
display: none;
|
||||
|
||||
width: max-content;
|
||||
top: -35px;
|
||||
left: -17px;
|
||||
|
||||
border-radius: 30px;
|
||||
padding: 5px 15px;
|
||||
|
||||
background: $background;
|
||||
|
||||
word-wrap: none;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
|
||||
filter: invert(12%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 0;
|
||||
|
||||
background: $foreground;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
> div {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import CreateLinkTile from './CreateLinkTile';
|
||||
|
||||
export default {
|
||||
title: 'CreateLinkTile',
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url:
|
||||
'https://figma.com/file/WSXjCGc1k6FVI093qhlzOP/04-Recieving-share-link?node-id=59%3A1',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: React.FC = () => <CreateLinkTile />;
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Formik, Form } from 'formik';
|
||||
|
||||
import Tile from './Tile';
|
||||
import Button from './Button';
|
||||
import Input from './Input';
|
||||
import { parseHash } from '../parser/parser';
|
||||
import { LinkKind } from '../parser/types';
|
||||
import linkIcon from '../imgs/link.svg';
|
||||
import copyIcon from '../imgs/copy.svg';
|
||||
import tickIcon from '../imgs/tick.svg';
|
||||
import refreshIcon from '../imgs/refresh.svg';
|
||||
import './CreateLinkTile.scss';
|
||||
|
||||
interface ILinkNotCreatedTileProps {
|
||||
setLink: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
|
||||
interface FormValues {
|
||||
identifier: string;
|
||||
}
|
||||
|
||||
// Hacky use of types here
|
||||
function validate(values: FormValues): Partial<FormValues> {
|
||||
const errors: Partial<FormValues> = {};
|
||||
|
||||
if (values.identifier === '') {
|
||||
errors.identifier = '';
|
||||
return errors;
|
||||
}
|
||||
|
||||
const parse = parseHash(values.identifier);
|
||||
|
||||
if (parse.kind === LinkKind.ParseFailed) {
|
||||
errors.identifier =
|
||||
"That identifier doesn't look right. Double check the details.";
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
const LinkNotCreatedTile: React.FC<ILinkNotCreatedTileProps> = (
|
||||
props: ILinkNotCreatedTileProps
|
||||
) => {
|
||||
return (
|
||||
<Tile className="createLinkTile">
|
||||
<h1>
|
||||
Create shareable links to Matrix rooms, users or messages
|
||||
without being tied to any app
|
||||
</h1>
|
||||
<Formik
|
||||
initialValues={{
|
||||
identifier: '',
|
||||
}}
|
||||
validate={validate}
|
||||
onSubmit={(values): void => {
|
||||
props.setLink(
|
||||
document.location.protocol +
|
||||
'//' +
|
||||
document.location.host +
|
||||
'/#/' +
|
||||
values.identifier
|
||||
);
|
||||
}}
|
||||
>
|
||||
{(formik): JSX.Element => (
|
||||
<Form>
|
||||
<Input
|
||||
name={'identifier'}
|
||||
type={'text'}
|
||||
placeholder="#room:example.com, @user:example.com"
|
||||
autoFocus
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
icon={linkIcon}
|
||||
disabled={!!formik.errors.identifier}
|
||||
className={
|
||||
formik.errors.identifier ? 'errorButton' : ''
|
||||
}
|
||||
>
|
||||
Create Link
|
||||
</Button>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Tile>
|
||||
);
|
||||
};
|
||||
|
||||
interface ILinkCreatedTileProps {
|
||||
link: string;
|
||||
setLink: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
|
||||
const LinkCreatedTile: React.FC<ILinkCreatedTileProps> = (props) => {
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
// Focus button on render
|
||||
useEffect((): void => {
|
||||
if (buttonRef && buttonRef.current) {
|
||||
buttonRef.current.focus();
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Tile className="createLinkTile">
|
||||
<button
|
||||
className="createLinkReset"
|
||||
onClick={(): void => props.setLink('')}
|
||||
>
|
||||
<div>New link</div>
|
||||
<img src={refreshIcon} alt="Go back to matrix.to home page" />
|
||||
</button>
|
||||
<a className="matrixIdentifier" href={props.link}>
|
||||
{props.link}
|
||||
</a>
|
||||
<Button
|
||||
flashChildren={'Copied'}
|
||||
icon={copyIcon}
|
||||
flashIcon={tickIcon}
|
||||
onClick={(): void => {
|
||||
navigator.clipboard?.writeText(props.link);
|
||||
}}
|
||||
ref={buttonRef}
|
||||
>
|
||||
Copy Link
|
||||
</Button>
|
||||
</Tile>
|
||||
);
|
||||
};
|
||||
|
||||
const CreateLinkTile: React.FC = () => {
|
||||
const [link, setLink] = React.useState('');
|
||||
if (!link) {
|
||||
return <LinkNotCreatedTile setLink={setLink} />;
|
||||
} else {
|
||||
return <LinkCreatedTile link={link} setLink={setLink} />;
|
||||
}
|
||||
};
|
||||
|
||||
export default CreateLinkTile;
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { SafeLink } from '../parser/types';
|
||||
import Avatar from './Avatar';
|
||||
|
||||
import './DefaultPreview.scss';
|
||||
|
||||
import genericRoomPreview from '../imgs/chat-icon.svg';
|
||||
|
||||
interface IProps {
|
||||
link: SafeLink;
|
||||
}
|
||||
|
||||
const DefaultPreview: React.FC<IProps> = ({ link }: IProps) => {
|
||||
return (
|
||||
<div className="defaultPreview">
|
||||
<Avatar
|
||||
avatarUrl={genericRoomPreview}
|
||||
label={`Generic icon representing ${link.identifier}`}
|
||||
/>
|
||||
<h1 className="matrixIdentifier">{link.identifier}</h1>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DefaultPreview;
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../mixins';
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
|
||||
> :first-child {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
> input[type='checkbox'] {
|
||||
// Remove the OS's representation
|
||||
display: none;
|
||||
|
||||
&.focus-visible {
|
||||
& + img {
|
||||
@include unreal-focus;
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
& + img {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import chevron from '../imgs/chevron-down.svg';
|
||||
|
||||
import './Details.scss';
|
||||
|
||||
interface IProps extends React.InputHTMLAttributes<Element> {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const Details: React.FC<IProps> = ({ children, ...props }: IProps) => (
|
||||
<label className="details">
|
||||
{children}
|
||||
<input type="checkbox" {...props} />
|
||||
<img src={chevron} alt="" />
|
||||
</label>
|
||||
);
|
||||
|
||||
export default Details;
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Room, Event } from '../matrix-cypher';
|
||||
|
||||
import RoomPreview from './RoomPreview';
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
event: Event;
|
||||
}
|
||||
|
||||
const EventPreview: React.FC<IProps> = ({ room, event }: IProps) => (
|
||||
<>
|
||||
<RoomPreview room={room} />
|
||||
<p>"{event.content}"</p>
|
||||
<p>{event.sender}</p>
|
||||
</>
|
||||
);
|
||||
|
||||
export default EventPreview;
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.fakeProgress {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: lighten($grey, 50%);
|
||||
border-radius: 4px;
|
||||
|
||||
> div {
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
background-color: $foreground;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import './FakeProgress.scss';
|
||||
|
||||
const FakeProgress = () => (
|
||||
<div className="fakeProgress">
|
||||
<div />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default FakeProgress;
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
import HSContext, {
|
||||
HSOptions,
|
||||
ActionType as HSACtionType,
|
||||
} from '../contexts/HSContext';
|
||||
import ClientContext, {
|
||||
ActionType as ClientActionType,
|
||||
} from '../contexts/ClientContext';
|
||||
import TextButton from './TextButton';
|
||||
|
||||
import './Footer.scss';
|
||||
|
||||
const Footer: React.FC = () => {
|
||||
const [hsState, hsDispatch] = useContext(HSContext);
|
||||
const [clientState, clientDispatch] = useContext(ClientContext);
|
||||
|
||||
const clear =
|
||||
hsState.option !== HSOptions.Unset || clientState.clientId !== null ? (
|
||||
<>
|
||||
{' · '}
|
||||
<TextButton
|
||||
onClick={(): void => {
|
||||
hsDispatch({
|
||||
action: HSACtionType.Clear,
|
||||
});
|
||||
clientDispatch({
|
||||
action: ClientActionType.ClearClient,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Clear preferences
|
||||
</TextButton>
|
||||
</>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div className="footer">
|
||||
<a href="https://github.com/matrix-org/matrix.to">GitHub project</a>
|
||||
{' · '}
|
||||
<a href="https://github.com/matrix-org/matrix.to/tree/main/src/clients">
|
||||
Add your app
|
||||
</a>
|
||||
{clear}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.groupPreview {
|
||||
> .avatar {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Group } from '../matrix-cypher';
|
||||
|
||||
import { GroupAvatar } from './Avatar';
|
||||
|
||||
import './GroupPreview.scss';
|
||||
|
||||
interface IProps {
|
||||
group: Group;
|
||||
groupId: string;
|
||||
}
|
||||
|
||||
const GroupPreview: React.FC<IProps> = ({ group, groupId }: IProps) => {
|
||||
const description = group.long_description
|
||||
? group.long_description
|
||||
: group.short_description
|
||||
? group.short_description
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="groupPreview">
|
||||
<GroupAvatar group={group} groupId={groupId}/>
|
||||
<h1>{group.name}</h1>
|
||||
{description ? <p>{description}</p> : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GroupPreview;
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.homeserverOptions {
|
||||
display: grid;
|
||||
row-gap: 20px;
|
||||
|
||||
background: $app-background;
|
||||
text-align: left;
|
||||
|
||||
> * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.homeserverOptionsDescription {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
> p {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
> img {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
background-color: $background;
|
||||
height: 62px;
|
||||
width: 62px;
|
||||
padding: 11px;
|
||||
border-radius: 100%;
|
||||
margin-left: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
display: grid;
|
||||
row-gap: 25px;
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import HomeserverOptions from './HomeserverOptions';
|
||||
import { LinkKind } from '../parser/types';
|
||||
|
||||
export default {
|
||||
title: 'HomeserverOptions',
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url:
|
||||
'https://figma.com/file/WSXjCGc1k6FVI093qhlzOP/04-Recieving-share-link?node-id=143%3A5853',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: React.FC = () => (
|
||||
<HomeserverOptions
|
||||
link={{
|
||||
identifier: '#banter:matrix.org',
|
||||
arguments: { vias: [], originalParams: new URLSearchParams() },
|
||||
kind: LinkKind.Alias,
|
||||
originalLink: 'This is all made up',
|
||||
}}
|
||||
/>
|
||||
);
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { Formik, Form } from 'formik';
|
||||
import { string } from 'zod';
|
||||
|
||||
import Tile from './Tile';
|
||||
import HSContext, { TempHSContext, ActionType } from '../contexts/HSContext';
|
||||
import icon from '../imgs/telecom-mast.svg';
|
||||
import Button from './Button';
|
||||
import Input from './Input';
|
||||
import StyledCheckbox from './StyledCheckbox';
|
||||
import { SafeLink } from '../parser/types';
|
||||
|
||||
import './HomeserverOptions.scss';
|
||||
|
||||
interface IProps {
|
||||
link: SafeLink;
|
||||
}
|
||||
|
||||
interface FormValues {
|
||||
HSUrl: string;
|
||||
}
|
||||
|
||||
function validateURL(values: FormValues): Partial<FormValues> {
|
||||
const errors: Partial<FormValues> = {};
|
||||
try {
|
||||
string().url().parse(values.HSUrl);
|
||||
} catch {
|
||||
errors.HSUrl =
|
||||
'This must be a valid homeserver URL, starting with https://';
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
const HomeserverOptions: React.FC<IProps> = ({ link }: IProps) => {
|
||||
const HSStateDispatcher = useContext(HSContext)[1];
|
||||
const TempHSStateDispatcher = useContext(TempHSContext)[1];
|
||||
|
||||
const [rememberSelection, setRemeberSelection] = useState(false);
|
||||
|
||||
// Select which disaptcher to use based on whether we're writing
|
||||
// the choice to localstorage
|
||||
const dispatcher = rememberSelection
|
||||
? HSStateDispatcher
|
||||
: TempHSStateDispatcher;
|
||||
|
||||
const hsInput = (
|
||||
<Formik
|
||||
initialValues={{
|
||||
HSUrl: '',
|
||||
}}
|
||||
validate={validateURL}
|
||||
onSubmit={({ HSUrl }): void =>
|
||||
dispatcher({ action: ActionType.SetHS, HSURL: HSUrl })
|
||||
}
|
||||
>
|
||||
{({ values, errors }): JSX.Element => (
|
||||
<Form>
|
||||
<Input
|
||||
muted={!values.HSUrl}
|
||||
type="text"
|
||||
name="HSUrl"
|
||||
placeholder="Preferred homeserver URL"
|
||||
/>
|
||||
{values.HSUrl && !errors.HSUrl ? (
|
||||
<Button secondary type="submit">
|
||||
Use {values.HSUrl}
|
||||
</Button>
|
||||
) : null}
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
|
||||
return (
|
||||
<Tile className="homeserverOptions">
|
||||
<div className="homeserverOptionsDescription">
|
||||
<div>
|
||||
<h3>
|
||||
About
|
||||
<span className="matrixIdentifier">
|
||||
{link.identifier}
|
||||
</span>
|
||||
</h3>
|
||||
<p>
|
||||
A homeserver will show you metadata about the link, like
|
||||
a description. Homeservers will be able to relate your
|
||||
IP to things you've opened invites for in matrix.to.
|
||||
</p>
|
||||
</div>
|
||||
<img
|
||||
src={icon}
|
||||
alt="Icon making it clear that connections may be made with external services"
|
||||
/>
|
||||
</div>
|
||||
<StyledCheckbox
|
||||
checked={rememberSelection}
|
||||
onChange={(e): void => setRemeberSelection(e.target.checked)}
|
||||
>
|
||||
Remember my choice
|
||||
</StyledCheckbox>
|
||||
<Button
|
||||
secondary
|
||||
onClick={(): void => {
|
||||
dispatcher({ action: ActionType.SetAny });
|
||||
}}
|
||||
>
|
||||
Use any homeserver
|
||||
</Button>
|
||||
{hsInput}
|
||||
</Tile>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomeserverOptions;
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
@import '../error';
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
|
||||
background: $background;
|
||||
|
||||
border: 1px solid $foreground;
|
||||
border-radius: 16px;
|
||||
|
||||
font: lighten($grey, 60%);
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
|
||||
&.error {
|
||||
@include error;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: 1px solid $font;
|
||||
font: $font;
|
||||
}
|
||||
}
|
||||
|
||||
.inputError {
|
||||
@include error;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.inputMuted {
|
||||
border-color: lighten($grey, 60%);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { withDesign } from 'storybook-addon-designs';
|
||||
import { Formik, Form } from 'formik';
|
||||
|
||||
import Input from './Input';
|
||||
|
||||
export default {
|
||||
title: 'Input',
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url:
|
||||
'https://figma.com/file/WSXjCGc1k6FVI093qhlzOP/04-Recieving-share-link?node-id=59%3A1',
|
||||
},
|
||||
},
|
||||
decorators: [withDesign],
|
||||
};
|
||||
|
||||
export const Default: React.FC = () => (
|
||||
<Formik initialValues={{}} onSubmit={(): void => {}}>
|
||||
<Form>
|
||||
<Input
|
||||
name="Example input"
|
||||
type="text"
|
||||
placeholder="Write something"
|
||||
/>
|
||||
</Form>
|
||||
</Formik>
|
||||
);
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { useField } from 'formik';
|
||||
|
||||
import './Input.scss';
|
||||
|
||||
interface IProps extends React.InputHTMLAttributes<HTMLElement> {
|
||||
name: string;
|
||||
type: string;
|
||||
muted?: boolean;
|
||||
}
|
||||
|
||||
const Input: React.FC<IProps> = ({ className, muted, ...props }) => {
|
||||
const [field, meta] = useField(props);
|
||||
|
||||
const errorBool = meta.touched && meta.value !== '' && meta.error;
|
||||
const error = errorBool ? (
|
||||
<div className="inputError">{meta.error}</div>
|
||||
) : null;
|
||||
|
||||
const classNames = classnames('input', className, {
|
||||
error: errorBool,
|
||||
inputMuted: !!muted,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<input type="text" className={classNames} {...field} {...props} />
|
||||
{error}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Input;
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// disable camelcase check because our object keys come
|
||||
// from the matrix spec
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import InviteTile from './InviteTile';
|
||||
import UserPreview, { InviterPreview } from './UserPreview';
|
||||
import RoomPreview, { RoomPreviewWithTopic } from './RoomPreview';
|
||||
import Clients from '../clients';
|
||||
import { LinkKind, SafeLink } from '../parser/types';
|
||||
|
||||
export default {
|
||||
title: 'InviteTile',
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url:
|
||||
'https://figma.com/file/WSXjCGc1k6FVI093qhlzOP/04-Recieving-share-link?node-id=59%3A334',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const userLink: SafeLink = {
|
||||
kind: LinkKind.UserId,
|
||||
identifier: '@jorik:matrix.org',
|
||||
arguments: {
|
||||
vias: [],
|
||||
originalParams: new URLSearchParams(),
|
||||
},
|
||||
originalLink: 'asdfsadf',
|
||||
};
|
||||
|
||||
const roomLink: SafeLink = {
|
||||
kind: LinkKind.Alias,
|
||||
identifier: '#element-dev:matrix.org',
|
||||
arguments: {
|
||||
vias: [],
|
||||
originalParams: new URLSearchParams(),
|
||||
},
|
||||
originalLink: 'asdfsadf',
|
||||
};
|
||||
|
||||
export const withLink: React.FC<{}> = () => (
|
||||
<InviteTile client={Clients[0]} link={userLink}>
|
||||
This is an invite with a link
|
||||
</InviteTile>
|
||||
);
|
||||
|
||||
export const withInstruction: React.FC<{}> = () => (
|
||||
<InviteTile client={Clients[0]} link={userLink}>
|
||||
This is an invite with an instruction
|
||||
</InviteTile>
|
||||
);
|
||||
|
||||
export const withUserPreview: React.FC<{}> = () => (
|
||||
<InviteTile client={Clients[0]} link={userLink}>
|
||||
<UserPreview
|
||||
user={{
|
||||
avatar_url: 'mxc://matrix.org/EqMZYbAYhREvHXvYFyfxOlkf',
|
||||
displayname: 'Nicholas Briteli',
|
||||
}}
|
||||
userId="@nicholasbritelli:matrix.org"
|
||||
/>
|
||||
</InviteTile>
|
||||
);
|
||||
|
||||
export const withRoomPreviewAndRoomTopic: React.FC<{}> = () => (
|
||||
<InviteTile client={Clients[0]} link={roomLink}>
|
||||
<RoomPreviewWithTopic
|
||||
room={{
|
||||
aliases: ['#murrays:cheese.bar'],
|
||||
avatar_url: 'mxc://bleeker.street/CHEDDARandBRIE',
|
||||
guest_can_join: false,
|
||||
name: 'CHEESE',
|
||||
num_joined_members: 37,
|
||||
room_id: '!ol19s:bleecker.street',
|
||||
topic: 'Tasty tasty cheese',
|
||||
world_readable: true,
|
||||
}}
|
||||
/>
|
||||
</InviteTile>
|
||||
);
|
||||
|
||||
export const withRoomPreviewAndInviter: React.FC<{}> = () => (
|
||||
<InviteTile client={Clients[0]} link={roomLink}>
|
||||
<InviterPreview
|
||||
user={{
|
||||
avatar_url: 'mxc://matrix.org/EqMZYbAYhREvHXvYFyfxOlkf',
|
||||
displayname: 'Nicholas Briteli',
|
||||
}}
|
||||
userId="@nicholasbritelli:matrix.org"
|
||||
/>
|
||||
<RoomPreview
|
||||
room={{
|
||||
aliases: ['#murrays:cheese.bar'],
|
||||
avatar_url: 'mxc://bleeker.street/CHEDDARandBRIE',
|
||||
guest_can_join: false,
|
||||
name: 'CHEESE',
|
||||
num_joined_members: 37,
|
||||
room_id: '!ol19s:bleecker.street',
|
||||
topic: 'Tasty tasty cheese',
|
||||
world_readable: true,
|
||||
}}
|
||||
/>
|
||||
</InviteTile>
|
||||
);
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import './InviteTile.scss';
|
||||
|
||||
import Tile from './Tile';
|
||||
import LinkButton from './LinkButton';
|
||||
import Button from './Button';
|
||||
import ClientSelection from './ClientSelection';
|
||||
import { Client, ClientKind } from '../clients/types';
|
||||
import { SafeLink } from '../parser/types';
|
||||
import TextButton from './TextButton';
|
||||
|
||||
interface IProps {
|
||||
children?: React.ReactNode;
|
||||
client: Client | null;
|
||||
link: SafeLink;
|
||||
}
|
||||
|
||||
const InviteTile: React.FC<IProps> = ({ children, client, link }: IProps) => {
|
||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||
let invite: React.ReactNode;
|
||||
let advanced: React.ReactNode;
|
||||
|
||||
if (client === null) {
|
||||
invite = showAdvanced ? null : (
|
||||
<Button onClick={(): void => setShowAdvanced(!showAdvanced)}>
|
||||
Accept invite
|
||||
</Button>
|
||||
);
|
||||
} else {
|
||||
let inviteUseString: string;
|
||||
|
||||
switch (client.kind) {
|
||||
case ClientKind.LINKED_CLIENT:
|
||||
invite = (
|
||||
<LinkButton href={client.toUrl(link).toString()}>
|
||||
Accept invite
|
||||
</LinkButton>
|
||||
);
|
||||
inviteUseString = `Accepting will open this link in ${client.name}.`;
|
||||
break;
|
||||
case ClientKind.TEXT_CLIENT:
|
||||
// TODO: copy to clipboard
|
||||
invite = <p>{client.toInviteString(link)}</p>;
|
||||
navigator.clipboard?.writeText(client.copyString(link));
|
||||
inviteUseString = `These are instructions for ${client.name}.`;
|
||||
break;
|
||||
}
|
||||
|
||||
const advancedButton = (
|
||||
<p>
|
||||
{inviteUseString}
|
||||
<TextButton
|
||||
onClick={(): void => setShowAdvanced(!showAdvanced)}
|
||||
>
|
||||
Change client
|
||||
</TextButton>
|
||||
</p>
|
||||
);
|
||||
|
||||
invite = (
|
||||
<>
|
||||
{invite}
|
||||
{advancedButton}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (showAdvanced) {
|
||||
if (client === null) {
|
||||
advanced = (
|
||||
<>
|
||||
<hr />
|
||||
<h2>Almost done!</h2>
|
||||
<p>Great, pick a client below to confirm and continue</p>
|
||||
<ClientSelection link={link} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
advanced = (
|
||||
<>
|
||||
<hr />
|
||||
<h4>Change app</h4>
|
||||
<ClientSelection link={link} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
advanced = advanced ? (
|
||||
<div className="inviteTileClientSelection">{advanced}</div>
|
||||
) : null;
|
||||
return (
|
||||
<>
|
||||
<Tile className="inviteTile">
|
||||
{children}
|
||||
{invite}
|
||||
{advanced}
|
||||
</Tile>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InviteTile;
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import ClientTile from './InvitingClientTile';
|
||||
|
||||
export default { title: 'ClientTile' };
|
||||
|
||||
export const Element = <ClientTile clientName={'element.io'} />;
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Tile from './Tile';
|
||||
|
||||
import { clientMap } from '../clients';
|
||||
import './MatrixTile.scss';
|
||||
|
||||
interface IProps {
|
||||
clientName: string;
|
||||
}
|
||||
|
||||
const InvitingClientTile: React.FC<IProps> = ({ clientName }: IProps) => {
|
||||
const client = clientMap[clientName];
|
||||
|
||||
if (!client) {
|
||||
return (
|
||||
<Tile className="matrixTile">
|
||||
{/* TODO: add gh link */}
|
||||
<p>
|
||||
The client that created this link "{clientName}" is not a
|
||||
recognised client. If this is a mistake and you'd like a
|
||||
nice advertisement for it here please{' '}
|
||||
<a href="https://github.com/matrix-org/matrix.to">
|
||||
open a pr
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</Tile>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tile className="matrixTile">
|
||||
<img src={client.logo} alt={client.name} />
|
||||
<h2>
|
||||
Invite created with <a href={client.homepage}>{client.name}</a>
|
||||
</h2>
|
||||
<div>{client.description}</div>
|
||||
</Tile>
|
||||
);
|
||||
};
|
||||
|
||||
export default InvitingClientTile;
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import './Button.scss';
|
||||
|
||||
interface IProps extends React.LinkHTMLAttributes<HTMLElement> {}
|
||||
|
||||
const LinkButton: React.FC<IProps> = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: IProps) => (
|
||||
<a className={classnames('button', className)} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
||||
export default LinkButton;
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import { getEvent, client } from '../matrix-cypher';
|
||||
|
||||
import { RoomPreviewWithTopic } from './RoomPreview';
|
||||
import InviteTile from './InviteTile';
|
||||
import { SafeLink, LinkKind } from '../parser/types';
|
||||
import UserPreview, { WrappedInviterPreview } from './UserPreview';
|
||||
import EventPreview from './EventPreview';
|
||||
import GroupPreview from './GroupPreview';
|
||||
import HomeserverOptions from './HomeserverOptions';
|
||||
import DefaultPreview from './DefaultPreview';
|
||||
import Details from './Details';
|
||||
import { clientMap } from '../clients';
|
||||
import {
|
||||
getRoomFromId,
|
||||
getRoomFromAlias,
|
||||
getRoomFromPermalink,
|
||||
getUser,
|
||||
getGroup,
|
||||
} from '../utils/cypher-wrapper';
|
||||
import { ClientContext } from '../contexts/ClientContext';
|
||||
import useHSs from '../utils/getHS';
|
||||
|
||||
interface IProps {
|
||||
link: SafeLink;
|
||||
}
|
||||
|
||||
const invite = async ({
|
||||
clientAddress,
|
||||
link,
|
||||
}: {
|
||||
clientAddress: string;
|
||||
link: SafeLink;
|
||||
}): Promise<JSX.Element> => {
|
||||
// TODO: replace with client fetch
|
||||
switch (link.kind) {
|
||||
case LinkKind.Alias:
|
||||
return (
|
||||
<RoomPreviewWithTopic
|
||||
room={
|
||||
await getRoomFromAlias(clientAddress, link.identifier)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
case LinkKind.RoomId:
|
||||
return (
|
||||
<RoomPreviewWithTopic
|
||||
room={await getRoomFromId(clientAddress, link.identifier)}
|
||||
/>
|
||||
);
|
||||
|
||||
case LinkKind.UserId:
|
||||
return (
|
||||
<UserPreview
|
||||
user={await getUser(clientAddress, link.identifier)}
|
||||
userId={link.identifier}
|
||||
/>
|
||||
);
|
||||
|
||||
case LinkKind.Permalink:
|
||||
return (
|
||||
<EventPreview
|
||||
room={await getRoomFromPermalink(clientAddress, link)}
|
||||
event={
|
||||
await getEvent(
|
||||
await client(clientAddress),
|
||||
link.roomLink,
|
||||
link.eventId
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
case LinkKind.GroupId:
|
||||
return (
|
||||
<GroupPreview
|
||||
group={await getGroup(clientAddress, link.identifier)}
|
||||
groupId={link.identifier}
|
||||
/>
|
||||
);
|
||||
|
||||
default:
|
||||
// Todo Implement events
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
|
||||
interface PreviewProps extends IProps {
|
||||
client: string;
|
||||
}
|
||||
|
||||
const Preview: React.FC<PreviewProps> = ({ link, client }: PreviewProps) => {
|
||||
const [content, setContent] = useState(<DefaultPreview link={link} />);
|
||||
|
||||
// TODO: support multiple clients with vias
|
||||
useEffect(() => {
|
||||
(async (): Promise<void> =>
|
||||
setContent(
|
||||
await invite({
|
||||
clientAddress: client,
|
||||
link,
|
||||
})
|
||||
))();
|
||||
}, [link, client]);
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
const LinkPreview: React.FC<IProps> = ({ link }: IProps) => {
|
||||
let content: JSX.Element;
|
||||
const [showHSOptions, setShowHSOPtions] = useState(false);
|
||||
|
||||
const hses = useHSs({ link });
|
||||
|
||||
if (!hses.length) {
|
||||
content = (
|
||||
<>
|
||||
<DefaultPreview link={link} />
|
||||
<Details
|
||||
checked={showHSOptions}
|
||||
onChange={(): void => setShowHSOPtions(!showHSOptions)}
|
||||
>
|
||||
<span>
|
||||
About
|
||||
<span className="matrixIdentifier">
|
||||
{link.identifier}
|
||||
</span>
|
||||
</span>
|
||||
</Details>
|
||||
</>
|
||||
);
|
||||
if (showHSOptions) {
|
||||
content = (
|
||||
<>
|
||||
{content}
|
||||
<HomeserverOptions link={link} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
content = <Preview link={link} client={hses[0]} />;
|
||||
}
|
||||
|
||||
const [{ clientId }] = useContext(ClientContext);
|
||||
|
||||
// Select which client to link to
|
||||
const displayClientId = clientId
|
||||
? clientId
|
||||
: link.arguments.client
|
||||
? link.arguments.client
|
||||
: null;
|
||||
|
||||
const client = displayClientId ? clientMap[displayClientId] : null;
|
||||
|
||||
const sharer = link.arguments.sharer ? (
|
||||
<WrappedInviterPreview
|
||||
link={{
|
||||
kind: LinkKind.UserId,
|
||||
identifier: link.arguments.sharer,
|
||||
arguments: { vias: [], originalParams: new URLSearchParams() },
|
||||
originalLink: '',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<p style={{ margin: '0 0 10px 0' }}>You're invited to join</p>
|
||||
);
|
||||
|
||||
return (
|
||||
<InviteTile client={client} link={link}>
|
||||
{sharer}
|
||||
{content}
|
||||
</InviteTile>
|
||||
);
|
||||
};
|
||||
|
||||
export default LinkPreview;
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.matrixTile {
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
row-gap: 16px;
|
||||
padding: 0 40px;
|
||||
justify-items: left;
|
||||
text-align: left;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import MatrixTile from './MatrixTile';
|
||||
|
||||
export default { title: 'MatrixTile' };
|
||||
|
||||
export const Default: React.FC = () => <MatrixTile />;
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Tile from './Tile';
|
||||
import Footer from './Footer';
|
||||
|
||||
import logo from '../imgs/matrix-logo.svg';
|
||||
|
||||
import './MatrixTile.scss';
|
||||
|
||||
interface IProps {
|
||||
isLink?: boolean;
|
||||
}
|
||||
|
||||
const MatrixTile: React.FC<IProps> = ({ isLink }: IProps) => {
|
||||
const copy = isLink ? (
|
||||
<div>
|
||||
This invite uses <a href="https://matrix.org">Matrix</a>, an open
|
||||
network for secure, decentralized communication.
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
Matrix.to is a stateless URL redirecting service for the{' '}
|
||||
<a href="https://matrix.org">Matrix</a> ecosystem.
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Tile className="matrixTile">
|
||||
<img src={logo} alt="matrix-logo" />
|
||||
{copy}
|
||||
<Footer />
|
||||
</Tile>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MatrixTile;
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.roomPreview {
|
||||
> .avatar {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.roomTopic {
|
||||
padding-top: 8px;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Room } from '../matrix-cypher';
|
||||
|
||||
import { RoomAvatar } from './Avatar';
|
||||
|
||||
import './RoomPreview.scss';
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
}
|
||||
|
||||
const RoomPreview: React.FC<IProps> = ({ room }: IProps) => {
|
||||
const roomAlias = room.canonical_alias
|
||||
? room.canonical_alias
|
||||
: room.aliases
|
||||
? room.aliases[0]
|
||||
: room.room_id;
|
||||
const members =
|
||||
room.num_joined_members > 0 ? (
|
||||
<p>{room.num_joined_members.toLocaleString()} members</p>
|
||||
) : null;
|
||||
return (
|
||||
<div className="roomPreview">
|
||||
<RoomAvatar room={room} />
|
||||
<h1 className="matrixIdentifier">
|
||||
{room.name ? room.name : roomAlias}
|
||||
</h1>
|
||||
{members}
|
||||
<p className="matrixIdentifier">{roomAlias}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const RoomPreviewWithTopic: React.FC<IProps> = ({ room }: IProps) => {
|
||||
const topic = room.topic ? <p className="roomTopic">{room.topic}</p> : null;
|
||||
return (
|
||||
<>
|
||||
<RoomPreview room={room} />
|
||||
{topic}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RoomPreview;
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
@import '../mixins';
|
||||
|
||||
.styledCheckbox {
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
input[type='checkbox'] {
|
||||
display: none;
|
||||
|
||||
&:checked + div {
|
||||
background: $foreground;
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&.focus-visible {
|
||||
& + div {
|
||||
@include unreal-focus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.styledCheckboxWrapper {
|
||||
display: flex;
|
||||
|
||||
margin-right: 5px;
|
||||
border: 2px solid $foreground;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stolen from the matrix-react-sdk
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import tick from '../imgs/tick.svg';
|
||||
|
||||
import './StyledCheckbox.scss';
|
||||
|
||||
interface IProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const StyledCheckbox: React.FC<IProps> = ({
|
||||
children,
|
||||
className,
|
||||
...otherProps
|
||||
}: IProps) => (
|
||||
<label className="styledCheckbox">
|
||||
<input {...otherProps} type="checkbox" />
|
||||
{/* Using the div to center the image */}
|
||||
<div className="styledCheckboxWrapper">
|
||||
<img src={tick} alt="" />
|
||||
</div>
|
||||
{children}
|
||||
</label>
|
||||
);
|
||||
|
||||
export default StyledCheckbox;
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.textButton {
|
||||
background: none;
|
||||
border: none;
|
||||
color: $link;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import TextButton from './TextButton';
|
||||
|
||||
export default {
|
||||
title: 'TextButton',
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url:
|
||||
'https://figma.com/file/WSXjCGc1k6FVI093qhlzOP/04-Recieving-share-link?node-id=149%3A10756',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: React.FC = () => (
|
||||
<TextButton>This is a button?</TextButton>
|
||||
);
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import './TextButton.scss';
|
||||
|
||||
const TextButton: React.FC<React.ButtonHTMLAttributes<Element>> = ({
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button className={classnames('textButton', className)} {...props} />
|
||||
);
|
||||
};
|
||||
export default TextButton;
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.tile {
|
||||
background-color: $background;
|
||||
|
||||
border-radius: 16px;
|
||||
box-shadow: 0px 18px 24px rgba(0, 0, 0, 0.06);
|
||||
padding: 2rem;
|
||||
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
color: $grey;
|
||||
}
|
||||
transition: width 2s, height 2s, transform 2s;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Tile from './Tile';
|
||||
|
||||
export default {
|
||||
title: 'Tile',
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url:
|
||||
'https://figma.com/file/WSXjCGc1k6FVI093qhlzOP/04-Recieving-share-link?node-id=143%3A5853',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: React.FC = () => (
|
||||
<Tile>
|
||||
<h1>This is a tile</h1>
|
||||
<p>Some text</p>
|
||||
<p>Note the rounded corners</p>
|
||||
</Tile>
|
||||
);
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import './Tile.scss';
|
||||
|
||||
interface IProps {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const Tile: React.FC<IProps> = (props: IProps) => {
|
||||
return (
|
||||
<div className={classnames('tile', props.className)}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tile;
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
@import '../color-scheme';
|
||||
|
||||
.userPreview {
|
||||
width: 100%;
|
||||
|
||||
> .avatar {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
hr {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
.miniUserPreview {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
border: 1px solid $app-background;
|
||||
border-radius: 16px;
|
||||
padding: 6px 16px;
|
||||
|
||||
> div {
|
||||
flex-grow: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
&.centeredMiniUserPreview {
|
||||
h1 {
|
||||
width: unset;
|
||||
text-align: center;
|
||||
}
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { client, User, getUserDetails } from '../matrix-cypher';
|
||||
import classNames from 'classnames';
|
||||
import icon from '../imgs/chat-icon.svg';
|
||||
|
||||
import Avatar, { UserAvatar } from './Avatar';
|
||||
import useHSs from '../utils/getHS';
|
||||
import { UserId } from '../parser/types';
|
||||
|
||||
import './UserPreview.scss';
|
||||
|
||||
interface IProps {
|
||||
user: User;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
const UserPreview: React.FC<IProps> = ({ user, userId }: IProps) => (
|
||||
<div className="userPreview">
|
||||
<UserAvatar user={user} userId={userId} />
|
||||
<h1>{user.displayname} invites you to connect</h1>
|
||||
<p>{userId}</p>
|
||||
<hr />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default UserPreview;
|
||||
|
||||
interface InviterPreviewProps {
|
||||
user?: User;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export const InviterPreview: React.FC<InviterPreviewProps> = ({
|
||||
user,
|
||||
userId,
|
||||
}: InviterPreviewProps) => {
|
||||
const avatar = user ? (
|
||||
<UserAvatar user={user} userId={userId} />
|
||||
) : (
|
||||
<Avatar
|
||||
className="avatarNoCrop"
|
||||
label={`Placeholder icon for ${userId}`}
|
||||
avatarUrl={icon}
|
||||
/>
|
||||
);
|
||||
const className = classNames('miniUserPreview', {
|
||||
centeredMiniUserPreview: !user,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div>
|
||||
<h1>
|
||||
Invited by{' '}
|
||||
<b className="matrixIdentifier">
|
||||
{user ? user.displayname : userId}
|
||||
</b>
|
||||
</h1>
|
||||
{user ? <p className="matrixIdentifier">{userId}</p> : null}
|
||||
</div>
|
||||
{avatar}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface WrappedInviterProps {
|
||||
link: UserId;
|
||||
}
|
||||
|
||||
export const WrappedInviterPreview: React.FC<WrappedInviterProps> = ({
|
||||
link,
|
||||
}: WrappedInviterProps) => {
|
||||
const [user, setUser] = useState<User | undefined>(undefined);
|
||||
const hss = useHSs({ link });
|
||||
useEffect(() => {
|
||||
if (hss.length) {
|
||||
client(hss[0])
|
||||
.then((c) => getUserDetails(c, link.identifier))
|
||||
.then(setUser)
|
||||
.catch((x) => console.log("couldn't fetch user preview", x));
|
||||
}
|
||||
}, [hss, link]);
|
||||
return <InviterPreview user={user} userId={link.identifier} />;
|
||||
};
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { object, string, boolean, TypeOf } from 'zod';
|
||||
|
||||
import { ClientId } from '../clients/types';
|
||||
import { persistReducer } from '../utils/localStorage';
|
||||
|
||||
const STATE_SCHEMA = object({
|
||||
clientId: string().nullable(),
|
||||
showOnlyDeviceClients: boolean(),
|
||||
showExperimentalClients: boolean(),
|
||||
});
|
||||
|
||||
type State = TypeOf<typeof STATE_SCHEMA>;
|
||||
|
||||
// Actions are a discriminated union.
|
||||
export enum ActionType {
|
||||
SetClient = 'SET_CLIENT',
|
||||
ClearClient = 'CLEAR_CLIENT',
|
||||
ToggleShowOnlyDeviceClients = 'TOGGLE_SHOW_ONLY_DEVICE_CLIENTS',
|
||||
ToggleShowExperimentalClients = 'TOGGLE_SHOW_EXPERIMENTAL_CLIENTS',
|
||||
}
|
||||
|
||||
interface SetClient {
|
||||
action: ActionType.SetClient;
|
||||
clientId: ClientId;
|
||||
}
|
||||
|
||||
interface ClearClient {
|
||||
action: ActionType.ClearClient;
|
||||
}
|
||||
|
||||
interface ToggleShowOnlyDeviceClients {
|
||||
action: ActionType.ToggleShowOnlyDeviceClients;
|
||||
}
|
||||
|
||||
interface ToggleShowExperimentalClients {
|
||||
action: ActionType.ToggleShowExperimentalClients;
|
||||
}
|
||||
|
||||
export type Action =
|
||||
| SetClient
|
||||
| ClearClient
|
||||
| ToggleShowOnlyDeviceClients
|
||||
| ToggleShowExperimentalClients;
|
||||
|
||||
const INITIAL_STATE: State = {
|
||||
clientId: null,
|
||||
showOnlyDeviceClients: true,
|
||||
showExperimentalClients: false,
|
||||
};
|
||||
|
||||
export const [initialState, reducer] = persistReducer(
|
||||
'default-client',
|
||||
INITIAL_STATE,
|
||||
STATE_SCHEMA,
|
||||
(state: State, action: Action): State => {
|
||||
switch (action.action) {
|
||||
case ActionType.SetClient:
|
||||
return {
|
||||
...state,
|
||||
clientId: action.clientId,
|
||||
};
|
||||
case ActionType.ToggleShowOnlyDeviceClients:
|
||||
return {
|
||||
...state,
|
||||
showOnlyDeviceClients: !state.showOnlyDeviceClients,
|
||||
};
|
||||
case ActionType.ToggleShowExperimentalClients:
|
||||
return {
|
||||
...state,
|
||||
showExperimentalClients: !state.showExperimentalClients,
|
||||
};
|
||||
case ActionType.ClearClient:
|
||||
return {
|
||||
...state,
|
||||
clientId: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// The defualt reducer needs to be overwritten with the one above
|
||||
// after it's been put through react's useReducer
|
||||
export const ClientContext = React.createContext<
|
||||
[State, React.Dispatch<Action>]
|
||||
>([initialState, (): void => {}]);
|
||||
|
||||
export default ClientContext;
|
||||
|
||||
// Quick rename to make importing easier
|
||||
export const ClientProvider = ClientContext.Provider;
|
||||
export const ClientConsumer = ClientContext.Consumer;
|