diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8805773 --- /dev/null +++ b/.editorconfig @@ -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}] diff --git a/.eslintrc.js b/.eslintrc.js index aabe8c1..24bbb04 100644 --- a/.eslintrc.js +++ b/.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" + } +}; diff --git a/.gitignore b/.gitignore index 19a9ac3..dd87e2d 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.storybook/main.js b/.storybook/main.js deleted file mode 100644 index 729cef1..0000000 --- a/.storybook/main.js +++ /dev/null @@ -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', - ], -}; - diff --git a/.storybook/preview.js b/.storybook/preview.js deleted file mode 100644 index 41d73ed..0000000 --- a/.storybook/preview.js +++ /dev/null @@ -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 => {storyFn()} -); - -addDecorator(withA11y); - -addDecorator(withKnobs); - -addDecorator(withDesign); - -addParameters({ - backgrounds: [ - {name: 'light', value: '#F4F4F4', default: true}, - {name: 'white', value: '#FFFFFF'}, - ], -}); - diff --git a/css/client.css b/css/client.css new file mode 100644 index 0000000..f4f63ff --- /dev/null +++ b/css/client.css @@ -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'); +} + diff --git a/css/create.css b/css/create.css new file mode 100644 index 0000000..c11e273 --- /dev/null +++ b/css/create.css @@ -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; +} diff --git a/css/main.css b/css/main.css new file mode 100644 index 0000000..70a7b16 --- /dev/null +++ b/css/main.css @@ -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; +} diff --git a/src/layouts/SingleColumn.scss b/css/open.css similarity index 52% rename from src/layouts/SingleColumn.scss rename to css/open.css index 3e589b8..560f7a3 100644 --- a/src/layouts/SingleColumn.scss +++ b/css/open.css @@ -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; +} diff --git a/css/preview.css b/css/preview.css new file mode 100644 index 0000000..8816178 --- /dev/null +++ b/css/preview.css @@ -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%; } +} diff --git a/css/spinner.css b/css/spinner.css new file mode 100644 index 0000000..4802dfc --- /dev/null +++ b/css/spinner.css @@ -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)); +} diff --git a/src/imgs/app-store-us-alt.svg b/images/app-store-us-alt.svg similarity index 100% rename from src/imgs/app-store-us-alt.svg rename to images/app-store-us-alt.svg diff --git a/src/imgs/background.svg b/images/background.svg similarity index 99% rename from src/imgs/background.svg rename to images/background.svg index bdca144..37c31f0 100644 --- a/src/imgs/background.svg +++ b/images/background.svg @@ -1,6 +1,6 @@ - + diff --git a/src/imgs/chat-icon.svg b/images/chat-icon.svg similarity index 100% rename from src/imgs/chat-icon.svg rename to images/chat-icon.svg diff --git a/images/client-icons/element.svg b/images/client-icons/element.svg new file mode 100644 index 0000000..5d1f7ba --- /dev/null +++ b/images/client-icons/element.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/imgs/fractal.png b/images/client-icons/fractal.png similarity index 100% rename from src/imgs/fractal.png rename to images/client-icons/fractal.png diff --git a/src/imgs/nheko.svg b/images/client-icons/nheko.svg similarity index 100% rename from src/imgs/nheko.svg rename to images/client-icons/nheko.svg diff --git a/images/client-icons/quaternion.svg b/images/client-icons/quaternion.svg new file mode 100644 index 0000000..e20f3bd --- /dev/null +++ b/images/client-icons/quaternion.svg @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/images/client-icons/tensor.png b/images/client-icons/tensor.png new file mode 100644 index 0000000..f4437c2 Binary files /dev/null and b/images/client-icons/tensor.png differ diff --git a/src/imgs/weechat.svg b/images/client-icons/weechat.svg similarity index 100% rename from src/imgs/weechat.svg rename to images/client-icons/weechat.svg diff --git a/src/imgs/copy.svg b/images/copy.svg similarity index 50% rename from src/imgs/copy.svg rename to images/copy.svg index 7906974..1d60511 100644 --- a/src/imgs/copy.svg +++ b/images/copy.svg @@ -1,4 +1,4 @@ - - + + diff --git a/src/imgs/fdroid-badge.png b/images/fdroid-badge.png similarity index 100% rename from src/imgs/fdroid-badge.png rename to images/fdroid-badge.png diff --git a/images/flathub-badge.svg b/images/flathub-badge.svg new file mode 100644 index 0000000..ad3b04a --- /dev/null +++ b/images/flathub-badge.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/imgs/google-play-us.svg b/images/google-play-us.svg similarity index 100% rename from src/imgs/google-play-us.svg rename to images/google-play-us.svg diff --git a/src/imgs/link.svg b/images/link.svg similarity index 100% rename from src/imgs/link.svg rename to images/link.svg diff --git a/src/imgs/matrix-logo.svg b/images/matrix-logo.svg similarity index 100% rename from src/imgs/matrix-logo.svg rename to images/matrix-logo.svg diff --git a/images/member-icon.svg b/images/member-icon.svg new file mode 100644 index 0000000..f969c17 --- /dev/null +++ b/images/member-icon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/images/platform-icon.svg b/images/platform-icon.svg new file mode 100644 index 0000000..125b671 --- /dev/null +++ b/images/platform-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/tick-dark.svg b/images/tick-dark.svg new file mode 100644 index 0000000..e19a7b1 --- /dev/null +++ b/images/tick-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/imgs/tick.svg b/images/tick.svg similarity index 100% rename from src/imgs/tick.svg rename to images/tick.svg diff --git a/index.html b/index.html new file mode 100644 index 0000000..c4caf02 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + You're invited to talk on Matrix + + + + + + + + diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 91a2d2c..0000000 --- a/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', -}; \ No newline at end of file diff --git a/package.json b/package.json index 66da327..6d5702e 100644 --- a/package.json +++ b/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" + } } diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 823d8d4..0000000 --- a/public/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - Matrix.to - - - -
- - diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..633c841 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,317 @@ +/* +Copyright 2020 Bruno Windels +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 = [ + ``, + ``, + `` + ]; + 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)); diff --git a/scripts/serve-local.js b/scripts/serve-local.js new file mode 100644 index 0000000..02581f9 --- /dev/null +++ b/scripts/serve-local.js @@ -0,0 +1,45 @@ +/* +Copyright 2020 Bruno Windels + +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); diff --git a/src/App.tsx b/src/App.tsx deleted file mode 100644 index fe11e17..0000000 --- a/src/App.tsx +++ /dev/null @@ -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 = ( - <> - - - ); - - 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 = ; - } else { - page = ( - - Links should be in the format {location.host}/#/{'<'} - matrix-resource-identifier{'>'} - - ); - } - } - - return ( - - -
- {page} - -
- - - ); -}; - -export default App; diff --git a/src/Link.js b/src/Link.js new file mode 100644 index 0000000..44d769e --- /dev/null +++ b/src/Link.js @@ -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}`; + } + } +} diff --git a/src/Platform.js b/src/Platform.js new file mode 100644 index 0000000..21de264 --- /dev/null +++ b/src/Platform.js @@ -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; +} diff --git a/src/Preferences.js b/src/Preferences.js new file mode 100644 index 0000000..53f5511 --- /dev/null +++ b/src/Preferences.js @@ -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; + } +} diff --git a/src/RootView.js b/src/RootView.js new file mode 100644 index 0000000..183724d --- /dev/null +++ b/src/RootView.js @@ -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); +} diff --git a/src/RootViewModel.js b/src/RootViewModel.js new file mode 100644 index 0000000..a77b82b --- /dev/null +++ b/src/RootViewModel.js @@ -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; + } +} diff --git a/src/_color-scheme.scss b/src/_color-scheme.scss deleted file mode 100644 index 1c32596..0000000 --- a/src/_color-scheme.scss +++ /dev/null @@ -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; diff --git a/src/_mixins.scss b/src/_mixins.scss deleted file mode 100644 index 5cff438..0000000 --- a/src/_mixins.scss +++ /dev/null @@ -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; - } -} diff --git a/src/clients/Element.ts b/src/clients/Element.ts deleted file mode 100644 index 37e3db0..0000000 --- a/src/clients/Element.ts +++ /dev/null @@ -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: [], -}; diff --git a/src/clients/Fractal.tsx b/src/clients/Fractal.tsx deleted file mode 100644 index f9ea9a2..0000000 --- a/src/clients/Fractal.tsx +++ /dev/null @@ -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 ( - - Click the '+' button in the top right and paste the - identifier - - ); - default: - return Fractal doesn't support this kind of link; - } - }, - 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; diff --git a/src/clients/Nheko.tsx b/src/clients/Nheko.tsx deleted file mode 100644 index f9201d3..0000000 --- a/src/clients/Nheko.tsx +++ /dev/null @@ -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 ( - - Type{' '} - - /join{' '} - - {link.identifier} - - - - ); - case LinkKind.UserId: - return ( - - Type{' '} - - /invite{' '} - - {link.identifier} - - - - ); - default: - return Nheko doesn't support this kind of link; - } - }, - 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; diff --git a/src/clients/Weechat.tsx b/src/clients/Weechat.tsx deleted file mode 100644 index 805a4b2..0000000 --- a/src/clients/Weechat.tsx +++ /dev/null @@ -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 ( - - Type{' '} - - /join{' '} - - {link.identifier} - - - - ); - case LinkKind.UserId: - return ( - - Type{' '} - - /invite{' '} - - {link.identifier} - - - - ); - default: - return Weechat doesn't support this kind of link; - } - }, - 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; diff --git a/src/clients/index.ts b/src/clients/index.ts deleted file mode 100644 index a00cd71..0000000 --- a/src/clients/index.ts +++ /dev/null @@ -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; diff --git a/src/clients/types.ts b/src/clients/types.ts deleted file mode 100644 index 9c4c266..0000000 --- a/src/clients/types.ts +++ /dev/null @@ -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; diff --git a/src/components/Avatar.stories.tsx b/src/components/Avatar.stories.tsx deleted file mode 100644 index 1032c18..0000000 --- a/src/components/Avatar.stories.tsx +++ /dev/null @@ -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<{}> = () => ( - -); diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx deleted file mode 100644 index adf99ac..0000000 --- a/src/components/Avatar.tsx +++ /dev/null @@ -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 = ({ className, avatarUrl, label }: IProps) => { - const [src, setSrc] = useState(avatarUrl); - useEffect(() => { - setSrc(avatarUrl ? avatarUrl : logo); - }, [avatarUrl]); - - const _className = classNames('avatar', className, { - avatarNoCrop: src === logo, - }); - return ( - setSrc(logo)} - alt={label} - className={_className} - /> - ); -}; - -interface IPropsUserAvatar { - user: User; - userId: string; -} - -export const UserAvatar: React.FC = ({ - user, - userId, -}: IPropsUserAvatar) => { - const [hs] = useHSs({ identifier: userId }); - return ( - - ); -}; - -interface IPropsRoomAvatar { - room: Room; -} - -export const RoomAvatar: React.FC = ({ - room, -}: IPropsRoomAvatar) => { - const [hs] = useHSs({ identifier: room.room_id }); - return ( - - ); -}; - -interface IPropsGroupAvatar { - group: Group; - groupId: string; -} - -export const GroupAvatar: React.FC = ({ - group, - groupId, -}: IPropsGroupAvatar) => { - const [hs] = useHSs({ identifier: groupId }); - return ( - - ); -}; - -export default Avatar; diff --git a/src/components/Button.scss b/src/components/Button.scss deleted file mode 100644 index 25997ab..0000000 --- a/src/components/Button.scss +++ /dev/null @@ -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; -} diff --git a/src/components/Button.stories.tsx b/src/components/Button.stories.tsx deleted file mode 100644 index 25cfee8..0000000 --- a/src/components/Button.stories.tsx +++ /dev/null @@ -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 = () => ( - -); - -export const Secondary: React.FC = () => ( - -); diff --git a/src/components/Button.tsx b/src/components/Button.tsx deleted file mode 100644 index fd031f2..0000000 --- a/src/components/Button.tsx +++ /dev/null @@ -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 { - // 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 -> = React.forwardRef( - ( - { - onClick, - children, - flashChildren, - className, - secondary, - icon, - flashIcon, - ...props - }: IProps, - ref: React.Ref - ) => { - 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 ? ( - - ) : null; - - return ( - - ); - } -); - -export default Button; diff --git a/src/components/ClientList.scss b/src/components/ClientList.scss deleted file mode 100644 index 24c8823..0000000 --- a/src/components/ClientList.scss +++ /dev/null @@ -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; -} diff --git a/src/components/ClientList.tsx b/src/components/ClientList.tsx deleted file mode 100644 index 64dbebc..0000000 --- a/src/components/ClientList.tsx +++ /dev/null @@ -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 = ({ 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 => ( -
  • - rememberSelection - ? clientDispatcher({ - action: ActionType.SetClient, - clientId: client.clientId, - }) - : undefined - } - > - -
  • - ); - - return ( -
      - {Clients.filter(showClient).map(clientLi)} -
    - ); -}; - -export default ClientList; diff --git a/src/components/ClientSelection.tsx b/src/components/ClientSelection.tsx deleted file mode 100644 index 6e5ed8d..0000000 --- a/src/components/ClientSelection.tsx +++ /dev/null @@ -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 = ({ link }: IProps) => { - const [clientState, clientStateDispatch] = useContext(ClientContext); - const [rememberSelection, setRememberSelection] = useState(false); - const options = ( -
    - { - setRememberSelection(!rememberSelection); - }} - checked={rememberSelection} - > - Remember for future invites in this browser - - { - clientStateDispatch({ - action: ActionType.ToggleShowOnlyDeviceClients, - }); - }} - checked={clientState.showOnlyDeviceClients} - > - Show only clients suggested for this device - - { - clientStateDispatch({ - action: ActionType.ToggleShowExperimentalClients, - }); - }} - checked={clientState.showExperimentalClients} - > - Show experimental clients - -
    - ); - - const clearSelection = - clientState.clientId !== null ? ( - - ) : null; - - return ( -
    - {options} - - {clearSelection} -
    - ); -}; - -export default ClientSelection; diff --git a/src/components/ClientTile.scss b/src/components/ClientTile.scss deleted file mode 100644 index a697aea..0000000 --- a/src/components/ClientTile.scss +++ /dev/null @@ -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%; -} diff --git a/src/components/ClientTile.tsx b/src/components/ClientTile.tsx deleted file mode 100644 index 9464e61..0000000 --- a/src/components/ClientTile.tsx +++ /dev/null @@ -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 = ({ client, link }: IProps) => { - const inviteLine = - client.kind === ClientKind.TEXT_CLIENT ? ( -

    {client.toInviteString(link)}

    - ) : 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 =

    {matchingInstallLinks.map((installLink) => { - return - {installLink.description} - ; - })}

    ; - } - - if (client.kind === ClientKind.LINKED_CLIENT) { - inviteButton = ; - } else { - const copyString = client.copyString(link); - if (copyString !== '') { - inviteButton = ( - - ); - } - } - - let clientTile = ( - - {client.name -
    -

    {client.name}

    -

    {client.description}

    - {installButtons} - {inviteLine} - {inviteButton} -
    -
    - ); - - if (client.kind === ClientKind.LINKED_CLIENT) { - if (!hasNativeClient) { - clientTile = ( - {clientTile} - ); - } - } - - return clientTile; -}; - -export default ClientTile; diff --git a/src/components/CreateLinkTile.scss b/src/components/CreateLinkTile.scss deleted file mode 100644 index e302aff..0000000 --- a/src/components/CreateLinkTile.scss +++ /dev/null @@ -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; - } - } - } -} diff --git a/src/components/CreateLinkTile.stories.tsx b/src/components/CreateLinkTile.stories.tsx deleted file mode 100644 index 48d7e5c..0000000 --- a/src/components/CreateLinkTile.stories.tsx +++ /dev/null @@ -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 = () => ; diff --git a/src/components/CreateLinkTile.tsx b/src/components/CreateLinkTile.tsx deleted file mode 100644 index 35950fd..0000000 --- a/src/components/CreateLinkTile.tsx +++ /dev/null @@ -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>; -} - -interface FormValues { - identifier: string; -} - -// Hacky use of types here -function validate(values: FormValues): Partial { - const errors: Partial = {}; - - 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 = ( - props: ILinkNotCreatedTileProps -) => { - return ( - -

    - Create shareable links to Matrix rooms, users or messages - without being tied to any app -

    - { - props.setLink( - document.location.protocol + - '//' + - document.location.host + - '/#/' + - values.identifier - ); - }} - > - {(formik): JSX.Element => ( -
    - - -
    - )} -
    -
    - ); -}; - -interface ILinkCreatedTileProps { - link: string; - setLink: React.Dispatch>; -} - -const LinkCreatedTile: React.FC = (props) => { - const buttonRef = useRef(null); - - // Focus button on render - useEffect((): void => { - if (buttonRef && buttonRef.current) { - buttonRef.current.focus(); - } - }); - - return ( - - - - {props.link} - - - - ); -}; - -const CreateLinkTile: React.FC = () => { - const [link, setLink] = React.useState(''); - if (!link) { - return ; - } else { - return ; - } -}; - -export default CreateLinkTile; diff --git a/src/components/DefaultPreview.tsx b/src/components/DefaultPreview.tsx deleted file mode 100644 index 00f4b91..0000000 --- a/src/components/DefaultPreview.tsx +++ /dev/null @@ -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 = ({ link }: IProps) => { - return ( -
    - -

    {link.identifier}

    -
    - ); -}; - -export default DefaultPreview; diff --git a/src/components/Details.scss b/src/components/Details.scss deleted file mode 100644 index 8fc8e6f..0000000 --- a/src/components/Details.scss +++ /dev/null @@ -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; - } -} diff --git a/src/components/Details.tsx b/src/components/Details.tsx deleted file mode 100644 index afa91d8..0000000 --- a/src/components/Details.tsx +++ /dev/null @@ -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 { - children?: React.ReactNode; -} - -const Details: React.FC = ({ children, ...props }: IProps) => ( - -); - -export default Details; diff --git a/src/components/EventPreview.tsx b/src/components/EventPreview.tsx deleted file mode 100644 index 00ac979..0000000 --- a/src/components/EventPreview.tsx +++ /dev/null @@ -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 = ({ room, event }: IProps) => ( - <> - -

    "{event.content}"

    -

    {event.sender}

    - -); - -export default EventPreview; diff --git a/src/components/FakeProgress.scss b/src/components/FakeProgress.scss deleted file mode 100644 index 32cd224..0000000 --- a/src/components/FakeProgress.scss +++ /dev/null @@ -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; - } -} diff --git a/src/components/FakeProgress.tsx b/src/components/FakeProgress.tsx deleted file mode 100644 index 587a7e3..0000000 --- a/src/components/FakeProgress.tsx +++ /dev/null @@ -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 = () => ( -
    -
    -
    -); - -export default FakeProgress; diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx deleted file mode 100644 index ca8dba5..0000000 --- a/src/components/Footer.tsx +++ /dev/null @@ -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 ? ( - <> - {' ยท '} - { - hsDispatch({ - action: HSACtionType.Clear, - }); - clientDispatch({ - action: ClientActionType.ClearClient, - }); - }} - > - Clear preferences - - - ) : null; - - return ( -
    - GitHub project - {' ยท '} - - Add your app - - {clear} -
    - ); -}; - -export default Footer; diff --git a/src/components/GroupPreview.scss b/src/components/GroupPreview.scss deleted file mode 100644 index aae3aba..0000000 --- a/src/components/GroupPreview.scss +++ /dev/null @@ -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; - } -} diff --git a/src/components/GroupPreview.tsx b/src/components/GroupPreview.tsx deleted file mode 100644 index 49a2c22..0000000 --- a/src/components/GroupPreview.tsx +++ /dev/null @@ -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 = ({ group, groupId }: IProps) => { - const description = group.long_description - ? group.long_description - : group.short_description - ? group.short_description - : null; - - return ( -
    - -

    {group.name}

    - {description ?

    {description}

    : null} -
    - ); -}; - -export default GroupPreview; diff --git a/src/components/HomeserverOptions.scss b/src/components/HomeserverOptions.scss deleted file mode 100644 index f0736c0..0000000 --- a/src/components/HomeserverOptions.scss +++ /dev/null @@ -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; - } -} diff --git a/src/components/HomeserverOptions.stories.tsx b/src/components/HomeserverOptions.stories.tsx deleted file mode 100644 index b6e112e..0000000 --- a/src/components/HomeserverOptions.stories.tsx +++ /dev/null @@ -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 = () => ( - -); diff --git a/src/components/HomeserverOptions.tsx b/src/components/HomeserverOptions.tsx deleted file mode 100644 index 750b1c0..0000000 --- a/src/components/HomeserverOptions.tsx +++ /dev/null @@ -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 { - const errors: Partial = {}; - 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 = ({ 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 = ( - - dispatcher({ action: ActionType.SetHS, HSURL: HSUrl }) - } - > - {({ values, errors }): JSX.Element => ( -
    - - {values.HSUrl && !errors.HSUrl ? ( - - ) : null} -
    - )} -
    - ); - - return ( - -
    -
    -

    - About  - - {link.identifier} - -

    -

    - 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. -

    -
    - Icon making it clear that connections may be made with external services -
    - setRemeberSelection(e.target.checked)} - > - Remember my choice - - - {hsInput} -
    - ); -}; - -export default HomeserverOptions; diff --git a/src/components/Input.scss b/src/components/Input.scss deleted file mode 100644 index 8163678..0000000 --- a/src/components/Input.scss +++ /dev/null @@ -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%); -} diff --git a/src/components/Input.stories.tsx b/src/components/Input.stories.tsx deleted file mode 100644 index f45e5ab..0000000 --- a/src/components/Input.stories.tsx +++ /dev/null @@ -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 = () => ( - {}}> -
    - -
    -
    -); diff --git a/src/components/Input.tsx b/src/components/Input.tsx deleted file mode 100644 index 21ce342..0000000 --- a/src/components/Input.tsx +++ /dev/null @@ -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 { - name: string; - type: string; - muted?: boolean; -} - -const Input: React.FC = ({ className, muted, ...props }) => { - const [field, meta] = useField(props); - - const errorBool = meta.touched && meta.value !== '' && meta.error; - const error = errorBool ? ( -
    {meta.error}
    - ) : null; - - const classNames = classnames('input', className, { - error: errorBool, - inputMuted: !!muted, - }); - - return ( - <> - - {error} - - ); -}; - -export default Input; diff --git a/src/components/InviteTile.stories.tsx b/src/components/InviteTile.stories.tsx deleted file mode 100644 index b92870c..0000000 --- a/src/components/InviteTile.stories.tsx +++ /dev/null @@ -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<{}> = () => ( - - This is an invite with a link - -); - -export const withInstruction: React.FC<{}> = () => ( - - This is an invite with an instruction - -); - -export const withUserPreview: React.FC<{}> = () => ( - - - -); - -export const withRoomPreviewAndRoomTopic: React.FC<{}> = () => ( - - - -); - -export const withRoomPreviewAndInviter: React.FC<{}> = () => ( - - - - -); diff --git a/src/components/InviteTile.tsx b/src/components/InviteTile.tsx deleted file mode 100644 index 76e8ef4..0000000 --- a/src/components/InviteTile.tsx +++ /dev/null @@ -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 = ({ children, client, link }: IProps) => { - const [showAdvanced, setShowAdvanced] = useState(false); - let invite: React.ReactNode; - let advanced: React.ReactNode; - - if (client === null) { - invite = showAdvanced ? null : ( - - ); - } else { - let inviteUseString: string; - - switch (client.kind) { - case ClientKind.LINKED_CLIENT: - invite = ( - - Accept invite - - ); - inviteUseString = `Accepting will open this link in ${client.name}.`; - break; - case ClientKind.TEXT_CLIENT: - // TODO: copy to clipboard - invite =

    {client.toInviteString(link)}

    ; - navigator.clipboard?.writeText(client.copyString(link)); - inviteUseString = `These are instructions for ${client.name}.`; - break; - } - - const advancedButton = ( -

    - {inviteUseString} - setShowAdvanced(!showAdvanced)} - > - Change client - -

    - ); - - invite = ( - <> - {invite} - {advancedButton} - - ); - } - - if (showAdvanced) { - if (client === null) { - advanced = ( - <> -
    -

    Almost done!

    -

    Great, pick a client below to confirm and continue

    - - - ); - } else { - advanced = ( - <> -
    -

    Change app

    - - - ); - } - } - - advanced = advanced ? ( -
    {advanced}
    - ) : null; - return ( - <> - - {children} - {invite} - {advanced} - - - ); -}; - -export default InviteTile; diff --git a/src/components/InvitingClientTile.stories.tsx b/src/components/InvitingClientTile.stories.tsx deleted file mode 100644 index 6cac6ee..0000000 --- a/src/components/InvitingClientTile.stories.tsx +++ /dev/null @@ -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 = ; diff --git a/src/components/InvitingClientTile.tsx b/src/components/InvitingClientTile.tsx deleted file mode 100644 index 2d22a6c..0000000 --- a/src/components/InvitingClientTile.tsx +++ /dev/null @@ -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 = ({ clientName }: IProps) => { - const client = clientMap[clientName]; - - if (!client) { - return ( - - {/* TODO: add gh link */} -

    - 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{' '} - - open a pr - - . -

    -
    - ); - } - - return ( - - {client.name} -

    - Invite created with {client.name} -

    -
    {client.description}
    -
    - ); -}; - -export default InvitingClientTile; diff --git a/src/components/LinkButton.tsx b/src/components/LinkButton.tsx deleted file mode 100644 index 375f926..0000000 --- a/src/components/LinkButton.tsx +++ /dev/null @@ -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 {} - -const LinkButton: React.FC = ({ - className, - children, - ...props -}: IProps) => ( - - {children} - -); - -export default LinkButton; diff --git a/src/components/LinkPreview.tsx b/src/components/LinkPreview.tsx deleted file mode 100644 index e5355ef..0000000 --- a/src/components/LinkPreview.tsx +++ /dev/null @@ -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 => { - // TODO: replace with client fetch - switch (link.kind) { - case LinkKind.Alias: - return ( - - ); - - case LinkKind.RoomId: - return ( - - ); - - case LinkKind.UserId: - return ( - - ); - - case LinkKind.Permalink: - return ( - - ); - - case LinkKind.GroupId: - return ( - - ); - - default: - // Todo Implement events - return <>; - } -}; - -interface PreviewProps extends IProps { - client: string; -} - -const Preview: React.FC = ({ link, client }: PreviewProps) => { - const [content, setContent] = useState(); - - // TODO: support multiple clients with vias - useEffect(() => { - (async (): Promise => - setContent( - await invite({ - clientAddress: client, - link, - }) - ))(); - }, [link, client]); - - return content; -}; - -const LinkPreview: React.FC = ({ link }: IProps) => { - let content: JSX.Element; - const [showHSOptions, setShowHSOPtions] = useState(false); - - const hses = useHSs({ link }); - - if (!hses.length) { - content = ( - <> - -
    setShowHSOPtions(!showHSOptions)} - > - - About  - - {link.identifier} - - -
    - - ); - if (showHSOptions) { - content = ( - <> - {content} - - - ); - } - } else { - content = ; - } - - 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 ? ( - - ) : ( -

    You're invited to join

    - ); - - return ( - - {sharer} - {content} - - ); -}; - -export default LinkPreview; diff --git a/src/components/MatrixTile.scss b/src/components/MatrixTile.scss deleted file mode 100644 index 6c8f17b..0000000 --- a/src/components/MatrixTile.scss +++ /dev/null @@ -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; -} diff --git a/src/components/MatrixTile.stories.tsx b/src/components/MatrixTile.stories.tsx deleted file mode 100644 index 9bc3233..0000000 --- a/src/components/MatrixTile.stories.tsx +++ /dev/null @@ -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 = () => ; diff --git a/src/components/MatrixTile.tsx b/src/components/MatrixTile.tsx deleted file mode 100644 index 9808a09..0000000 --- a/src/components/MatrixTile.tsx +++ /dev/null @@ -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 = ({ isLink }: IProps) => { - const copy = isLink ? ( -
    - This invite uses Matrix, an open - network for secure, decentralized communication. -
    - ) : ( -
    - Matrix.to is a stateless URL redirecting service for the{' '} - Matrix ecosystem. -
    - ); - - return ( -
    - - matrix-logo - {copy} -
    - -
    - ); -}; - -export default MatrixTile; diff --git a/src/components/RoomPreview.scss b/src/components/RoomPreview.scss deleted file mode 100644 index b7e7b36..0000000 --- a/src/components/RoomPreview.scss +++ /dev/null @@ -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; -} diff --git a/src/components/RoomPreview.tsx b/src/components/RoomPreview.tsx deleted file mode 100644 index 620874a..0000000 --- a/src/components/RoomPreview.tsx +++ /dev/null @@ -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 = ({ 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 ? ( -

    {room.num_joined_members.toLocaleString()} members

    - ) : null; - return ( -
    - -

    - {room.name ? room.name : roomAlias} -

    - {members} -

    {roomAlias}

    -
    - ); -}; - -export const RoomPreviewWithTopic: React.FC = ({ room }: IProps) => { - const topic = room.topic ?

    {room.topic}

    : null; - return ( - <> - - {topic} - - ); -}; - -export default RoomPreview; diff --git a/src/components/StyledCheckbox.scss b/src/components/StyledCheckbox.scss deleted file mode 100644 index 011e53f..0000000 --- a/src/components/StyledCheckbox.scss +++ /dev/null @@ -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; - } - } -} diff --git a/src/components/StyledCheckbox.tsx b/src/components/StyledCheckbox.tsx deleted file mode 100644 index 9450f4e..0000000 --- a/src/components/StyledCheckbox.tsx +++ /dev/null @@ -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 {} - -const StyledCheckbox: React.FC = ({ - children, - className, - ...otherProps -}: IProps) => ( - -); - -export default StyledCheckbox; diff --git a/src/components/TextButton.scss b/src/components/TextButton.scss deleted file mode 100644 index cdaed54..0000000 --- a/src/components/TextButton.scss +++ /dev/null @@ -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; - } -} diff --git a/src/components/TextButton.stories.tsx b/src/components/TextButton.stories.tsx deleted file mode 100644 index 2c95dc2..0000000 --- a/src/components/TextButton.stories.tsx +++ /dev/null @@ -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 = () => ( - This is a button? -); diff --git a/src/components/TextButton.tsx b/src/components/TextButton.tsx deleted file mode 100644 index 6c9cfc5..0000000 --- a/src/components/TextButton.tsx +++ /dev/null @@ -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> = ({ - className, - ...props -}) => { - return ( -