Compare commits

...

337 commits

Author SHA1 Message Date
sij
a72b9b0e05 Update README.md 2024-11-05 00:48:28 +01:00
sij
4ed6d78212 Add Dockerfile 2024-11-05 00:45:53 +01:00
sij
1679bae1c1 Add docker-compose.yaml 2024-11-05 00:45:29 +01:00
Half-Shot
3fe1016715 1.2.17 2024-09-02 17:57:02 +01:00
Will Hunt
cba383bc32
Merge pull request #333 from zecakeh/fractal-matrix-uri
Add support for deeplink for Fractal
2024-08-29 14:01:24 +01:00
Will Hunt
d2219ba4b6
Merge pull request #347 from ajbura/cinny-deep-liink
Cinny deep link
2024-08-29 14:01:06 +01:00
Will Hunt
ab5f922acf
Merge branch 'main' into fractal-matrix-uri 2024-08-29 10:25:40 +01:00
Josh Simmons
a51e28e3fd
Merge pull request #346 from matrix-org/update-dco
add DCO
2024-08-21 16:16:08 -07:00
Ajay Bura
e97ac79e05
fix typo in user path 2024-07-30 13:51:07 +05:30
Ajay Bura
0123ab4988
update user link path 2024-07-30 13:50:18 +05:30
Ajay Bura
9750d5e245
add cinny deep link 2024-07-28 09:08:07 +05:30
Josh Simmons
861d683af1 add DCO 2024-07-25 14:51:52 -07:00
Brage Fuglseth
fac2f9bf29
Update Flathub badge (#343)
See https://fosstodon.org/@bragefuglseth/112753049810610017
2024-07-09 16:56:36 +02:00
Doug
6928941868
Fix the apple-app-site-association file. (#339)
It now matches https://developer.apple.com/documentation/bundleresources/applinks
2024-05-09 15:46:25 +01:00
Doug
657fd9cc1a
Add Element X iOS entries in the apple-app-site-association. (#337)
* Add Element X to the apple-app-site-association file.

* Tidy up the generated apple-app-site-association file.
2024-05-07 11:39:56 +01:00
Kévin Commaille
d3458399c5
Update Fractal homepage URL
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2024-01-18 19:35:42 +01:00
Managing Director
00ccd16f19
Merge pull request #332 from matrix-org/matrix-foundation-md-patch-1
add LICENSE file
2024-01-11 11:33:58 -08:00
Managing Director
713ab3ee74
add LICENSE file
Adding LICENSE file to make the licensing more clear and easier to discover. (License already specified as ALv2 in package.json, but that's nonobvious.) This should resolve #302
2024-01-11 10:36:55 -08:00
Kévin Commaille
dbc054eda7
Add deeplink for Fractal
Uses the same code as Nheko.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2024-01-04 15:36:13 +01:00
Alexandre Franke
e04f48135f
Update Fractal (#327)
Co-authored-by: Alexandre Franke <afranke@gnome.org>
2023-11-27 17:40:02 +01:00
Michael Telatynski
356e7eb439
Merge pull request #321 from matrix-org/dependabot/npm_and_yarn/postcss-8.4.31 2023-11-09 09:53:45 +00:00
dependabot[bot]
6dd6732001
Bump postcss from 8.3.0 to 8.4.31
Bumps [postcss](https://github.com/postcss/postcss) from 8.3.0 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.3.0...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-09 09:52:50 +00:00
Michael Telatynski
cacaae6d15
Merge pull request #290 from matrix-org/dependabot/npm_and_yarn/minimatch-3.1.2 2023-11-09 09:51:37 +00:00
Michael Telatynski
7cf14ade52
Merge pull request #274 from matrix-org/dependabot/npm_and_yarn/nanoid-3.3.4 2023-11-09 09:51:20 +00:00
Michael Telatynski
7f34b74f88
Merge pull request #322 from matrix-org/dependabot/npm_and_yarn/babel/traverse-7.23.2 2023-10-17 08:37:00 +01:00
dependabot[bot]
890a7f7536
Bump @babel/traverse from 7.12.9 to 7.23.2
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.12.9 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-17 01:49:26 +00:00
Martin Giger
246cd5e941
Thunderbird officially has a flatpak now, update TB logo. (#319) 2023-09-15 22:02:33 +02:00
Michael Telatynski
95fa6d7245
Merge pull request #317 from matrix-org/dependabot/npm_and_yarn/semver-5.7.2 2023-07-11 12:33:58 +01:00
dependabot[bot]
0c19eceb0e
Bump semver from 5.7.1 to 5.7.2
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 11:30:38 +00:00
AJ Jordan
990bef4d17
Fix desktop Element download link (#313)
The previous link now leads to a page that says "Contact Sales".
2023-06-13 17:20:20 +02:00
Felix Stupp
6091a1af32
Add SchildiChat to clients (#301)
* Add SchildiChat to clients

mostly adapted version of element.js,
as SchildiChat is an fork of Element.

* SchildiChat: Change description to new official one

Reason: https://github.com/matrix-org/matrix.to/pull/301#issuecomment-1465739125
Source: https://raw.githubusercontent.com/SchildiChat/SchildiChat-android/5bbd462cdbecf64ceda7e65e8cd8a4e241bfca03/fastlane/metadata/android/en-US/short_description.txt

* SchildiChat: Add test instance to trusted web instances

Reason: https://github.com/matrix-org/matrix.to/pull/301#issuecomment-1465739125
2023-04-14 09:28:46 +02:00
3nt3
7b6233217c
Add the Cinny client (#286)
* Add the Cinny client

Signed-off-by: 3nt3 <gott@3nt3.de>

* Implement suggested edits by thibaultamartin

Signed-off-by: 3nt3 <gott@3nt3.de>

* fix instructions

Signed-off-by: 3nt3 <gott@3nt3.de>

* address things brought up in PR

Signed-off-by: 3nt3 <gott@3nt3.de>

---------

Signed-off-by: 3nt3 <gott@3nt3.de>
2023-02-20 09:44:15 +01:00
Travis Ralston
2cf8119800
Merge pull request #303 from matrix-org/madlittlemods/add-app-gitter-im
Add `app.gitter.im` as a trusted web instance
2023-02-17 13:18:47 -07:00
Eric Eastwood
68e81ddd79
Add trailing comma
Co-authored-by: Travis Ralston <travpc@gmail.com>
2023-02-17 14:08:24 -06:00
Eric Eastwood
97f77d141a Add app.gitter.im as trusted web instance 2023-02-16 14:01:38 -06:00
dependabot[bot]
e11e4e73e8
Bump minimatch from 3.0.4 to 3.1.2
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-11 10:58:36 +00:00
Michael Telatynski
7c4e0f3c23
Merge pull request #300 from matrix-org/dependabot/npm_and_yarn/minimist-1.2.7 2023-01-11 10:57:16 +00:00
dependabot[bot]
d7a132d88c
Bump minimist from 1.2.5 to 1.2.7
Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.7.
- [Release notes](https://github.com/minimistjs/minimist/releases)
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.7)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-11 10:49:54 +00:00
Michael Telatynski
636d899b65
Merge pull request #299 from matrix-org/dependabot/npm_and_yarn/json5-2.2.3 2023-01-11 10:49:22 +00:00
dependabot[bot]
23a0f4e876
Bump json5 from 2.1.3 to 2.2.3
Bumps [json5](https://github.com/json5/json5) from 2.1.3 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.1.3...v2.2.3)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-06 17:05:10 +00:00
Michael Telatynski
fde53099eb
Update README.md 2022-10-12 14:38:12 +01:00
Michael Telatynski
d487c936ab
Update README.md
Fixes https://github.com/matrix-org/matrix.to/issues/281
2022-10-12 14:34:03 +01:00
Thibault Martin
4932e49874
Merge pull request #282 from matrix-org/anoa/update_trusted_web_interfaces_doc
Update link to trusted web clients in the README and attempt to future-proof
2022-10-04 11:26:19 +02:00
Andrew Morgan
776e337d9b Update link to trusted web clients in README and attempt to future-proof 2022-10-04 10:20:52 +01:00
Thibault Martin
13d9145fbe
Merge pull request #246 from calebccff/twitter-embed
Add twitter embed meta tags
2022-09-19 13:57:02 +02:00
Thibault Martin
43a3fb9628
Merge branch 'main' into twitter-embed 2022-09-19 13:54:43 +02:00
Thibault Martin
b5fcd1dfd7
Explain what people can do with a matrix.to link
Avoid technical jargon
2022-09-19 13:54:23 +02:00
Thibault Martin
6280514a53
Use a less cryptic card name for newcomers 2022-09-19 13:53:48 +02:00
Thibault Martin
015b9db853
Merge pull request #280 from 0x1a8510f2/add-syphon
Add Syphon
2022-09-15 16:23:09 +02:00
Thibault Martin
3b3e99f937
Merge branch 'main' into add-syphon 2022-09-15 16:22:10 +02:00
Thibault Martin
b3fb015bcd
Merge pull request #277 from freaktechnik/thunderbird
Add Thunderbird
2022-09-15 16:18:48 +02:00
0x1a8510f2
56d523c804
Add Syphon 2022-09-15 14:41:32 +01:00
Michael Telatynski
a2b6e0bf5a
Merge pull request #279 from matrix-org/dependabot/npm_and_yarn/terser-5.14.2
Bump terser from 5.5.1 to 5.14.2
2022-07-26 09:02:08 +01:00
dependabot[bot]
a99e918c1f
Bump terser from 5.5.1 to 5.14.2
Bumps [terser](https://github.com/terser/terser) from 5.5.1 to 5.14.2.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-20 02:46:25 +00:00
Martin Giger
d2d69f4c06
Add Thunderbird 2022-07-08 15:57:57 +02:00
dependabot[bot]
626eda057f
Bump nanoid from 3.1.23 to 3.3.4
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.23 to 3.3.4.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.23...3.3.4)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 13:18:07 +00:00
Thib
44a7ce8821 Dont forget to commit package.json before tagging 2022-06-15 15:04:36 +02:00
Thibault Martin
f08c12066e
Merge pull request #272 from matrix-org/t3chguy-patch-1
Fix over-encoding issues in Element URIs
2022-06-09 16:36:31 +02:00
Michael Telatynski
c39e7e1f3a
Merge pull request #264 from CommanderRoot/rm-deprecated-substr
Replace deprecated String.prototype.substr()
2022-06-09 13:54:22 +01:00
Michael Telatynski
58f63c4afc
Fix over-encoding issues in Element URIs 2022-06-06 17:11:15 +01:00
Michael Telatynski
d7c108588e
Merge pull request #271 from deepbluev7/fix-element-deeplinks
Properly pass vias to Element clients
2022-06-06 17:07:39 +01:00
Nicolas Werner
0ca4d66a50
Properly pass vias to Element clients
Should fix joining rooms by roomid via matrix.to.

fixes #270

Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de>
2022-05-29 15:45:25 +02:00
Thibault Martin
0a15f14af0
Merge pull request #253 from CarlSchwan/feat/neochat
Add NeoChat
2022-05-20 17:54:11 +02:00
Carl Schwan
2c3e1daaa4
Update src/open/clients/NeoChat.js
Co-authored-by: Thibault Martin <thibaultamartin@users.noreply.github.com>
2022-05-20 17:52:12 +02:00
Thibault Martin
eefb744467
Merge pull request #239 from aaronraimist/install-links
Add new install links for Quaternion, Nheko, and FluffyChat
2022-05-19 09:43:34 +02:00
Thibault Martin
b7b1a33258
Merge pull request #252 from CarlSchwan/patch-1
Update metadata about Quatermion
2022-05-17 11:19:21 +02:00
Maze
783630b89b
Mention trusted web instances (#268)
Avoids confusion for people trying to make links lead to their own instance.
2022-05-04 11:14:26 -05:00
Tobias Speicher
d20d7734cd
Replace deprecated String.prototype.substr()
.substr() is deprecated so we replace it with .slice() which works similarily but isn't deprecated

Signed-off-by: Tobias Speicher <rootcommander@gmail.com>
2022-04-14 01:22:33 +02:00
Bruno Windels
3a8cc2d4d5
Merge pull request #260 from AndrewRyanChama/patch-1
Remove url encoding from android element:// links
2022-03-09 10:56:36 +01:00
Andrew Ryan
1839eaae3d
Remove url encoding from android element:// links
#248 introduced url encoding for the android element:// link but this caused a regression because the encoded url cannot be picked up by android's filters.  See #259 

This returns the android url to its previous form which still worked.
2022-03-04 14:15:26 -08:00
Carl Schwan
9f28514046
Add NeoChat 2022-01-06 10:44:37 +01:00
Carl Schwan
a1bb51ad2d
Update src/open/clients/Quaternion.js
Co-authored-by: Alexey Rusakov <Kitsune-Ral@users.sf.net>
2021-12-27 10:51:06 +01:00
Carl Schwan
95cc966e28
Update metadata about Quatermion 2021-12-25 22:45:21 +01:00
Aaron Raimist
5f4c9a7c07
Display both flathub and website download links for Linux
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-11-24 17:27:28 +00:00
Bruno Windels
a39c40539f bump version to 1.2.14 2021-11-24 09:53:24 +01:00
Bruno Windels
aa272ece4d bump version to 1.2.13 2021-11-24 09:50:36 +01:00
Bruno Windels
85678ea5cc
Merge pull request #236 from ptman/patch-1
Document optional URL params
2021-11-24 09:45:40 +01:00
Bruno Windels
4d779d5f52
Merge pull request #245 from krillefear/patch-1
Add deep link for FluffyChat Android and iOS
2021-11-24 09:43:08 +01:00
Bruno Windels
ded399d35d
Merge pull request #248 from matrix-org/url-escape-fragment
Apply URL encoding to the fragmentPath
2021-11-24 09:40:31 +01:00
James Salter
c378eb4b4a missed a spot 2021-11-24 19:15:46 +11:00
James Salter
b302bd6829 Apply URL encoding to the fragmentPath
According to RFC3986 section 3.5, only certain values are legal
in the fragment. # in particular isn't one of them, but this
is a character that appears in room names.

It shouldn't hurt to escape other, otherwise legal characters
in the fragment such as @ and :.
2021-11-24 17:14:26 +11:00
Caleb Connolly
72374d91b1
add twitter embed meta tags
Add embeds to make matrix invite links more obvious on twitter.
2021-11-23 14:23:51 +00:00
Krille Fear
d52e84ee23
Prefix with /chat/ to make it a valid Uri 2021-11-22 12:44:49 +01:00
Krille Fear
994ad17fc9
Add deep link for FluffyChat Android and iOS 2021-11-21 14:02:35 +01:00
Aaron Raimist
e71021e8aa
Add F-Droid button for FluffyChat
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-11-17 21:24:01 +00:00
Aaron Raimist
b5b8e9a743
Add macOS and Windows install links for Quaternion and Nheko
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2021-10-21 03:54:59 -05:00
Paul Tötterman
b0281fde72
Document optional URL params 2021-10-12 12:06:49 +03:00
Bruno Windels
7d22a57874 update version to 1.2.12 2021-09-17 16:58:08 +02:00
Bruno Windels
cb63e2d8d7
Merge pull request #233 from matrix-org/twily/trustFedoraEweb
Added chat.fedoraproject.org to list of trusted Elements
2021-09-17 16:54:42 +02:00
Twilight Sparkle
c22b2f942b Added chat.fedoraproject.org to list of trusted Elements 2021-09-17 10:11:07 +01:00
Bruno Windels
27c74448d6
Merge pull request #232 from matrix-org/bwindels/fix-parse-identifier
have a separate parse method for identifier so we don't validate the fragment hash
2021-09-14 10:51:39 +02:00
Bruno Windels
b32b4b8533 don't accept empty fragments 2021-09-14 10:49:24 +02:00
Bruno Windels
1b6d1de059 don't accept empty identifiers 2021-09-14 10:48:27 +02:00
Bruno Windels
41d7308ba8 have a separate parse method for identifier so we don't validate the fragment hash 2021-09-14 10:44:27 +02:00
Bruno Windels
a460b52e03
Merge pull request #228 from matrix-org/danilafe/invalid-url
Display an error when a junk URL is entered, and provide suggestions.
2021-09-06 13:28:43 +02:00
Danila Fedorin
3802829557 Differentiate between rooms and room aliases 2021-09-01 10:11:19 -07:00
Bruno Windels
874635e92a
Merge pull request #221 from matrix-org/dependabot/npm_and_yarn/path-parse-1.0.7
Bump path-parse from 1.0.6 to 1.0.7
2021-08-31 17:54:56 +02:00
Bruno Windels
385c8532eb
Merge pull request #212 from matrix-org/dependabot/npm_and_yarn/browserslist-4.16.6
Bump browserslist from 4.15.0 to 4.16.6
2021-08-31 17:45:24 +02:00
Danila Fedorin
5f5359ae65 Remove outdated comments 2021-08-30 14:48:22 -07:00
Danila Fedorin
e2fb5de595 Adjust fix suggestions 2021-08-30 14:42:28 -07:00
Danila Fedorin
b57fbd8b6d Add suggestions for invalid URLs 2021-08-30 14:14:31 -07:00
Danila Fedorin
0844279c58 Error on missing initial hash 2021-08-30 12:11:21 -07:00
Danila Fedorin
e4aeadecd7 Add a 'invalid URL' view 2021-08-30 12:05:42 -07:00
Danila Fedorin
628e99ba2d Cleanup view switching code a bit 2021-08-30 11:08:58 -07:00
Danila Fedorin
878663ca07 Start work on handling invalid URLs 2021-08-30 11:01:56 -07:00
Bruno Windels
88116bdfa6
Merge pull request #225 from matrix-org/danilafe/legal-disclaimer
Add a legal disclaimer view
2021-08-30 18:22:39 +02:00
Danila Fedorin
a773daa0cd Merge branch 'main' into danilafe/legal-disclaimer 2021-08-26 09:39:44 -07:00
Bruno Windels
55d60cb368 make it into a link 2021-08-26 10:46:04 +02:00
Bruno Windels
24f8987972
Merge pull request #226 from matrix-org/danilafe/policy-links
Hide links when opening policy, show policy when navigated after load
2021-08-26 09:51:24 +02:00
Danila Fedorin
725a7efb3c Add license header
I hope that 2021 is the correct year here.
2021-08-25 15:55:10 -07:00
Danila Fedorin
f862ed1403 Hide links when opening policy, show policy when navigated after load 2021-08-25 15:06:13 -07:00
Danila Fedorin
34b30de288 Add a legal disclaimer view 2021-08-25 14:47:42 -07:00
Michael Telatynski
c25a9dae4d
Merge pull request #219 from matrix-org/t3chguy/msc3266 2021-08-13 17:00:19 +01:00
dependabot[bot]
defc8b9cfd
Bump path-parse from 1.0.6 to 1.0.7
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 23:19:04 +00:00
Michael Telatynski
acd881385c Mass Tabs -> Spaces conversion 2021-07-23 12:25:21 +01:00
Michael Telatynski
9caf2ce268 Use alternative border radius when previewing a space 2021-07-15 15:36:30 +01:00
Michael Telatynski
7d2dd5cc68 Print port in serve-local script 2021-07-14 14:29:13 +01:00
Michael Telatynski
4bc70d99f4 gitignore .idea 2021-07-14 14:19:31 +01:00
Michael Telatynski
eb9ebaf28e Print port in serve-local script 2021-07-14 14:19:15 +01:00
Michael Telatynski
5c2f2b0684 Allow well-known to fail, it is optional after all 2021-07-14 14:19:05 +01:00
Bruno Windels
2acec4f124 1.2.10 2021-06-24 17:59:36 +02:00
Bruno Windels
128164aa23
Merge pull request #216 from matrix-org/bwindels-patch-1
add kde webchat as element trusted instance
2021-06-24 15:55:22 +00:00
Bruno Windels
57737a4655
add kde webchat 2021-06-14 11:44:24 +00:00
Bruno Windels
3738594fbc
Update README.md 2021-06-11 08:15:17 +00:00
Bruno Windels
bfffe55fcc
Merge pull request #215 from matrix-org/bwindels/bring-back-badge
Bring back badge
2021-06-11 08:04:11 +00:00
Bruno Windels
9b6a282e5f bring back badge added in PR #21 2021-06-11 10:01:42 +02:00
dependabot[bot]
cffba9252a
Bump browserslist from 4.15.0 to 4.16.6
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.15.0 to 4.16.6.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.15.0...4.16.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-26 22:41:46 +00:00
Bruno Windels
3c84eb81b3 release v1.2.9 2021-05-21 14:04:21 +02:00
Bruno Windels
b99e3d3099 Merge branch 'main' of github.com:matrix-org/matrix.to 2021-05-21 14:02:07 +02:00
Bruno Windels
b6585a6a52
Merge pull request #208 from matrix-org/dependabot/npm_and_yarn/lodash-4.17.21
Bump lodash from 4.17.20 to 4.17.21
2021-05-21 12:01:21 +00:00
Bruno Windels
42251a102b upgrade to postcss 8.2.10 2021-05-21 13:59:46 +02:00
dependabot[bot]
c9aec3bf56
Bump lodash from 4.17.20 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-11 23:38:47 +00:00
Bruno Windels
2931fdb548
Merge pull request #195 from ChristianPauly/main
Add FluffyChat
2021-04-13 09:53:51 +02:00
Bruno Windels
690fb3400c
Merge pull request #203 from matrix-org/bwindels/undo-fix-201
Undo fix for #201 as app.element.io uses mobile page & smart app banners
2021-04-13 09:53:30 +02:00
Bruno Windels
496c680cd2 undo fix for #201 as app.element.io uses mobile page & smart app banners
(but keep the other cleanups we did in there)
2021-04-13 09:47:21 +02:00
Bruno Windels
1f611122d1
Merge pull request #200 from deepbluev7/main
Allow deeplinking into Nheko via matrix: scheme
2021-04-12 15:33:54 +02:00
Bruno Windels
356ad93a2e
Merge pull request #202 from matrix-org/bwindels/fix-201
Show both open and install options when deeplink for native app is https link
2021-04-12 15:25:13 +02:00
Bruno Windels
fd208ee4dc basic wrapping for long identifiers, until we come up with something better 2021-04-12 15:21:27 +02:00
Bruno Windels
f02dc5aae9 also show install options for https deeplinks for native app 2021-04-12 15:15:21 +02:00
Bruno Windels
ef2acf81ef use map rather than mapView where it makes sense 2021-04-12 15:10:02 +02:00
Bruno Windels
d8f1371b60 update TemplateView to add if and map fns 2021-04-12 15:09:39 +02:00
Bruno Windels
0ee064fbe1 fix: this var does not exist and should be a member
became apparent during testing when no native platform is returned
2021-04-12 14:54:08 +02:00
Bruno Windels
fb03a3313a forgot to update version previously 2021-04-12 14:28:02 +02:00
Christian
a02bc8aa2c
Update Fluffychat.js 2021-04-09 20:49:44 +02:00
Nicolas Werner
98dd339fad
Allow deeplinking into Nheko via matrix: scheme
Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de>
2021-04-08 19:30:45 +02:00
Christian Pauly
5923b13fc1 Add FluffyChat 2021-02-13 17:28:25 +01:00
Bruno Windels
dc4ccaef09
Merge pull request #176 from matrix-org/anoa/weechat_punctuation
Fix punctuation of Weechat client description
2021-02-05 19:17:52 +00:00
Bruno Windels
3eb777983c
Merge pull request #183 from aaronraimist/build-instructions
Add some build instructions
2021-02-05 19:17:15 +00:00
Bruno Windels
a7519d3e1e
Merge pull request #186 from aaronraimist/fractal
Put back Fractal
2021-02-05 19:15:28 +00:00
Bruno Windels
260d2b61cd don't use trusted web instance for iOS
as it only intercepts the default app.element.io
2021-02-05 13:00:26 +01:00
Bruno Windels
163f405ae5 ensure the preferred platform is supported 2021-02-05 13:00:13 +01:00
Bruno Windels
533b13746d exit package script if anything fails
like running the wrong node version for the build
2021-02-04 17:15:36 +01:00
Bruno Windels
bbc4b44de5 1.2.7 2021-02-04 17:13:50 +01:00
Bruno Windels
8a3896eef5 fix clients that don't support deeplinking
...from showing a broken continue button
2021-02-04 17:11:10 +01:00
Bruno Windels
df9087ba17 styling for preferred client 2021-02-04 17:08:18 +01:00
Bruno Windels
cd559e14ea reload view when webInstances change in the link 2021-02-04 17:08:04 +01:00
Bruno Windels
daa6e21d75 put preferred clients first 2021-02-04 17:07:55 +01:00
Bruno Windels
8a23b9a49e add hosted by banner 2021-02-04 17:07:47 +01:00
Bruno Windels
573076c263 better naming 2021-02-04 17:07:31 +01:00
Bruno Windels
cd4f62d178 also render steps on open stage of client view as actions 2021-02-04 17:07:20 +01:00
Bruno Windels
28fb6dfe9d add method to get preferred web instance out of link
this is a preference that can be put in the link
2021-02-04 17:05:18 +01:00
Bruno Windels
82f16b9231 explain what value people will get from enabling javascript 2021-02-04 14:59:38 +01:00
Bruno Windels
09ba14e7fc 1.2.6 2021-02-04 11:59:43 +01:00
Bruno Windels
1cab51249e use same csp header for local dev as matrix.to 2021-02-04 11:31:42 +01:00
Bruno Windels
93081b9909 not legacy anymore, is it? 2021-02-04 11:31:29 +01:00
Bruno Windels
5aa2858f4b fix need for unsafe-eval in CSP header 2021-02-04 11:31:07 +01:00
Bruno Windels
034426ed45 1.2.5 2021-02-03 18:57:19 +01:00
Bruno Windels
a4642540b4 remove es6 module build, as we use some unsupported syntax in there
chrome 61 supports modules, but support for the coalesce operator
was only added in chrome 80. We don't transpile any syntax in the
es6 build, so things break in chrome 61 - 79. Let's just have everyone
use the legacy build which is only ~150kb instead of ~30kb and
not run the risk of running into more issues like this.

Alternatively, we can transpile some of the more recent syntax
features we use like coalescing operator, but don't feel like
making an exhaustive list of these atm.
2021-02-03 18:53:33 +01:00
Bruno Windels
dc23d9f584 update version 2021-02-02 18:22:23 +01:00
Bruno Windels
623512c2b5 add noscript 2021-02-02 18:19:45 +01:00
Bruno Windels
163c3a3f62 release 1.2.3 2021-02-01 16:03:04 +01:00
Bruno Windels
53d1018340 update client view when clicking "change client" link
it would just stay what it was before, so it was hard/impossible
to switch between web and native.
2021-02-01 16:00:46 +01:00
Bruno Windels
1c520a68a3 release v1.2.2 2021-02-01 11:20:04 +01:00
Bruno Windels
47d0db89c1 allow setting a web instance in the url from a whitelist
as web clients can be hosted on multiple domains, allow specifying
which hosted instance we want to use.

as this could be phishing vector, we work with a host whitelist for now
until a better solution comes to mind.
2021-02-01 11:12:25 +01:00
Bruno Windels
0aa9c2e766 iOS doesn't support intercepting matrix.to links yet
this makes the open in app button more prominent,
as we can't assume the app is installed
2021-02-01 11:11:20 +01:00
Aaron Raimist
87229630d7
Put back Fractal
Removed in 4aff6a96ea for some reason

Signed-off-by: Aaron Raimist <aaron@raim.ist>
2020-12-24 01:27:58 -06:00
Aaron Raimist
e13da505ed
Add some build instructions
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2020-12-22 00:27:34 -06:00
Bruno Windels
bf5e26dbb5 release 1.2.1 2020-12-16 10:59:39 +01:00
Bruno Windels
c3b2254b9d fix #172 2020-12-16 10:58:35 +01:00
Bruno Windels
46b6495e71 fix #175 2020-12-16 10:58:16 +01:00
Andrew Morgan
03db5be985
Fix punctuation of Weechat client description 2020-12-10 18:25:37 +00:00
Bruno Windels
66c51828b0 fix add your client link 2020-12-08 15:50:10 +01:00
Bruno Windels
75ff7e1b23 small tweak 2020-12-08 15:44:04 +01:00
Bruno Windels
9464bdb499 package script 2020-12-08 15:43:59 +01:00
Bruno Windels
70398ebb95 release 1.2.0 2020-12-08 12:27:48 +01:00
Bruno Windels
9455d49124
Update README.md 2020-12-08 11:23:59 +00:00
Bruno Windels
993e0ba403
Merge pull request #171 from matrix-org/bwindels/addnewversion
Merge new version
2020-12-08 11:23:20 +00:00
Bruno Windels
b18123d00a don't rely on browser defaults for font sizes 2020-12-08 10:43:18 +01:00
Bruno Windels
efdf0125c3 remove storybook 2020-12-08 10:29:55 +01:00
Bruno Windels
25be231beb new deps 2020-12-08 10:29:46 +01:00
Bruno Windels
c3256a8277 Merge remote-tracking branch 'origin/bwindels/rewrite' into bwindels/addnewversion 2020-12-07 19:12:17 +01:00
Bruno Windels
3180144c2e cleanup package manifest 2020-12-07 19:09:59 +01:00
Bruno Windels
1f43db2a5b remove most bits 2020-12-07 19:06:26 +01:00
Bruno Windels
685950ba43
Merge pull request #168 from matrix-org/bwindels/ux-refresh
UX refresh
2020-11-24 12:05:42 +00:00
Bruno Windels
92ba3546a2
Merge pull request #166 from matrix-org/valr/mobile_support
Add mobile store links
2020-11-24 11:32:05 +00:00
Bruno Windels
e9d14926e3 add a11y label to install buttons 2020-11-24 12:29:38 +01:00
Bruno Windels
89de7e671d remove obsolete ideas 2020-11-24 12:23:04 +01:00
Bruno Windels
f8c16f520e do copy change in other pr if needed 2020-11-24 12:21:39 +01:00
Bruno Windels
d484a9a423 add app store install badges 2020-11-23 18:23:23 +01:00
Valere
c78a91ea46 WIP 2020-11-17 15:15:11 +01:00
J. Ryan Stinnett
0e5a08a870 Revise buttons back to fully rounded 2020-10-30 17:43:27 +00:00
J. Ryan Stinnett
dd1c626dc5 Add missing license header 2020-10-30 17:41:22 +00:00
J. Ryan Stinnett
7c7d0250b4 Ensure button text is centred 2020-10-29 16:48:57 +00:00
J. Ryan Stinnett
74c45f93ad Rename Toggle component to Details
It's much more like a details / disclosure view you can expand than a typically
toggle switch.
2020-10-29 15:13:37 +00:00
J. Ryan Stinnett
0e75ad078d Avoid awkward breaks in toggle text 2020-10-28 18:02:46 +00:00
J. Ryan Stinnett
33b08da026 Make the created link actually a link 2020-10-28 16:44:39 +00:00
J. Ryan Stinnett
820d90ee86 Restyle link creation form 2020-10-23 18:03:20 +01:00
J. Ryan Stinnett
6d0acdafce
Merge pull request #162 from matrix-org/jryans/hide-focus-mouse
Hide focus ring for mouse users
2020-10-23 17:20:18 +01:00
J. Ryan Stinnett
b5f173efd9 Hide focus ring for mouse users
Fixes https://github.com/matrix-org/matrix.to/issues/120
2020-10-23 17:04:54 +01:00
Matthew Hodgson
f8d5ab2b69
Merge pull request #159 from ZJvandeWeg/zj-fix-footer
fix: Update footer URL path to existing branch
2020-10-10 12:24:13 +01:00
Zeger-Jan van de Weg
980efb9e00 fix: Update footer URL path to existing branch
In the footer there's a link to add clients to the tree of this
repository, which pointed to a branch that did not exist in the
repository anymore. As such GitHub rendered a 404. This change points to
the footer URL to the `main` branch, which should exist as it's the
default branch for this project.
2020-10-10 12:21:23 +02:00
J. Ryan Stinnett
a8e33b223a
Merge pull request #156 from matrix-org/jryans/tweaks
Quick fixes: round 1
2020-09-30 09:55:12 +01:00
J. Ryan Stinnett
1a6c741298 Shorten remember choice to avoid wrapping 2020-09-29 16:59:36 +01:00
J. Ryan Stinnett
03816c1224 Add multiple platforms to Element client 2020-09-29 16:57:08 +01:00
J. Ryan Stinnett
2eed84fc23 Rename Element client file 2020-09-29 16:41:28 +01:00
J. Ryan Stinnett
3f2fa42b93 Hide native inputs on Safari for iOS 2020-09-29 16:36:28 +01:00
J. Ryan Stinnett
e18ff8debb Avoid clipboard error on Safari for iOS 2020-09-29 16:26:38 +01:00
J. Ryan Stinnett
684a4cb19a Fix blank avatar on Safari 2020-09-29 16:10:44 +01:00
J. Ryan Stinnett
dcc43ff436 Tweak change client text 2020-09-29 13:50:33 +01:00
J. Ryan Stinnett
1ba8c656e7 Ignore development bundle 2020-09-29 13:50:33 +01:00
J. Ryan Stinnett
4466b725b2 Remove git add from tasks 2020-09-29 13:50:33 +01:00
J. Ryan Stinnett
0e770d81d6 Fix identifier wrapping
Fixes https://github.com/matrix-org/matrix.to/issues/153
2020-09-29 13:50:33 +01:00
Jorik Schellekens
11fd9e1c0f
Merge pull request #151 from matrix-org/vias
Pass args to clients
2020-09-25 11:45:31 +01:00
Jorik Schellekens
2216305dc2
Merge pull request #152 from matrix-org/existentialism
Remove the existentialist crisis
2020-09-24 17:00:20 +01:00
Jorik Schellekens
f6c4a372a9 Remove the existentialist crisis 2020-09-24 11:30:52 +01:00
Jorik Schellekens
fc052e6fae Pass args to client 2020-09-24 11:11:07 +01:00
Jorik Schellekens
32c6119243
Merge pull request #144 from matrix-org/thumbnails
Use thumbnails api instead of mxc download
2020-09-24 10:49:18 +01:00
Jorik Schellekens
09429d7b42
Use larger image size 2020-09-24 10:49:02 +01:00
Jorik Schellekens
ae788e16d5
Be explicit about the resize method
Co-authored-by: Travis Ralston <travpc@gmail.com>
2020-09-24 10:48:01 +01:00
Jorik Schellekens
3486a06df7
Merge pull request #146 from matrix-org/background
Fix background on large displays
2020-09-24 10:47:13 +01:00
Jorik Schellekens
4ff26aa9a6
Merge pull request #141 from matrix-org/invite-link
Remove link around generated invite
2020-09-24 10:46:51 +01:00
Jorik Schellekens
e8527df962
Merge branch 'main' into invite-link 2020-09-24 10:46:08 +01:00
Jorik Schellekens
ff62521614
Merge pull request #138 from matrix-org/leniant-identifiers
Make identifier regexes closer to the spec
2020-09-24 10:20:59 +01:00
Jorik Schellekens
50e25956c1
Merge pull request #137 from matrix-org/word-wrap
Stop weird text splitting
2020-09-23 17:03:37 +01:00
Jorik Schellekens
5d6e1e8b11
Merge pull request #139 from matrix-org/leniant-schemas
Future proof schemas by making them nonstrict
2020-09-23 17:03:16 +01:00
Jorik Schellekens
d69f9b0ab4
Merge pull request #140 from matrix-org/fractal-description
Update fractal description
2020-09-23 17:02:45 +01:00
Jorik Schellekens
129a3de6a8 Fix background on large displays 2020-09-23 16:57:31 +01:00
Jorik Schellekens
50f51d373f use a variable for the avatar size 2020-09-23 15:47:49 +01:00
Jorik Schellekens
ee8c860507 Use thumbnails instead of mxc download 2020-09-23 15:30:46 +01:00
Jorik Schellekens
ea3146ece6 Remove link from generated invite 2020-09-23 12:46:57 +01:00
Jorik Schellekens
2f48df9e9d update fractal description 2020-09-23 12:40:41 +01:00
Jorik Schellekens
dd372dbb50
Merge pull request #126 from matrix-org/matrixtwo/groups
Add rudimentary group support
2020-09-23 12:03:04 +01:00
Jorik Schellekens
645d0ab6fc inline small <p> ternary 2020-09-23 12:02:26 +01:00
Jorik Schellekens
b92996f1d5 Future proof schemas by making them nonstrict 2020-09-23 11:56:55 +01:00
Jorik Schellekens
78f8bfb45d Make identifier regexes closer to the spec 2020-09-23 11:32:41 +01:00
Jorik Schellekens
0a1d81528d Stop strange word wrap 2020-09-23 10:38:38 +01:00
Jorik Schellekens
75476bce86
Merge pull request #132 from matrix-org/fix-input-validation
Fix enter to submit behaviour
2020-09-23 10:36:46 +01:00
Jorik Schellekens
427a81f331
Merge pull request #133 from matrix-org/jryans/more-sans
Add more sans fonts
2020-09-21 18:34:03 +01:00
J. Ryan Stinnett
577c7006cd Add more sans fonts
Fixes https://github.com/matrix-org/matrix.to/issues/121
2020-09-21 18:27:37 +01:00
Jorik Schellekens
28405ee778 Fix enter to submit behaviour 2020-09-21 18:10:02 +01:00
Jorik Schellekens
79a0a1c7ba Fix eslint rule 2020-09-17 15:45:59 +01:00
Jorik Schellekens
cc175b34cb Add redimentary group support 2020-09-17 15:41:32 +01:00
Jorik Schellekens
122bb55535 Another dep: 2020-09-16 17:55:11 +01:00
Jorik Schellekens
14875d5a9b Add missing dep 2020-09-16 17:44:30 +01:00
Jorik Schellekens
47ffc841f7
Merge pull request #110 from matrix-org/matrixtwo/designreview
Implement design review changes
2020-09-16 14:58:50 +01:00
Jorik Schellekens
794d9d84ca hacky fix infinite loop 2020-09-16 14:57:48 +01:00
Jorik Schellekens
cf23f0a85e Move matrix-cypher into matrix.to 2020-09-16 14:57:16 +01:00
Jorik Schellekens
91cbb73ac8 add clients 2020-09-16 14:28:29 +01:00
Jorik Schellekens
1352feca21 design nitpicks 2020-09-16 13:58:27 +01:00
Jorik Schellekens
0a8685360f Update app on hashchange 2020-09-16 13:04:18 +01:00
Jorik Schellekens
c000c17a3b Nit picks 2020-09-16 12:46:16 +01:00
Jorik Schellekens
0bbf88430d Merge branch 'matrix-two' of github.com:matrix-org/matrix.to into matrixtwo/designreview 2020-09-16 00:23:23 +01:00
Jorik Schellekens
4d456c2799 Implement design review changes 2020-09-16 00:19:52 +01:00
Jorik Schellekens
8cac5fb9f1
Merge pull request #108 from matrix-org/matrixtwo/gdpr
Implement homeserver selection
2020-09-15 17:06:15 +01:00
Jorik Schellekens
145b835581
punctuation
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2020-09-15 17:04:24 +01:00
Jorik Schellekens
545f4f9ef4
typo
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2020-09-15 17:04:09 +01:00
Jorik Schellekens
471c9cd21d Fix empty array not falsy bug 2020-09-13 18:02:18 +01:00
Jorik Schellekens
5f5eb60c02 Cleanup, and ally stuff 2020-09-13 17:43:22 +01:00
Jorik Schellekens
74b790927e Show sharer preview for matrix.to links 2020-09-13 17:39:39 +01:00
Jorik Schellekens
f5f4eb7dae
Merge pull request #106 from matrix-org/matrixtwo/clients
Matrix.to client framework
2020-09-13 15:00:16 +01:00
Jorik Schellekens
40aa7769f8
Typo
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2020-09-13 15:00:04 +01:00
Jorik Schellekens
85fab36308 Add gdpr options 2020-09-13 14:58:37 +01:00
Jorik Schellekens
41b803fbe1
Update weechat description
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2020-09-10 12:54:02 +02:00
Jorik Schellekens
4921513e13 Automaitcally copy invite information 2020-09-10 11:52:13 +01:00
Jorik Schellekens
154f82f7d4 Stop background from wrapping 2020-09-10 11:31:01 +01:00
Jorik Schellekens
a82c318ecf Update client selection to match figma 2020-09-10 11:27:47 +01:00
Jorik Schellekens
18ad88f683 Make the remember client option work more intuitively. 2020-09-03 11:17:53 +02:00
Jorik Schellekens
3a7c778498 Actually fix the background 2020-09-01 12:16:29 +02:00
Jorik Schellekens
61666a1b81 Fix background 2020-09-01 11:56:20 +02:00
Jorik Schellekens
ecebec2da6 Fix line wraps and scrollbars 2020-09-01 11:53:16 +02:00
Jorik Schellekens
2ecc505e78 Fix generated links 2020-09-01 11:38:34 +02:00
Jorik Schellekens
d5fa741a05 fix wrap on h1 2020-09-01 11:09:48 +02:00
Jorik Schellekens
3372fccc0a lint, css polish, yarn lock, fix some warning 2020-09-01 10:44:26 +02:00
Jorik Schellekens
21e5435720 Configure background 2020-09-01 10:43:29 +02:00
Jorik Schellekens
e6b9325d05 Display correct client link by default 2020-09-01 10:43:01 +02:00
Jorik Schellekens
74d223e475 Add client options and styling for client tiles 2020-09-01 10:41:17 +02:00
Jorik Schellekens
6e7a119831 Add inviting client tile 2020-09-01 10:37:15 +02:00
Jorik Schellekens
dd8aa3d074 Create clients and configure them 2020-09-01 10:30:00 +02:00
Jorik Schellekens
47fe7860c3 Configure global storage 2020-09-01 10:29:58 +02:00
Jorik Schellekens
890669741c Remove Yup dependency and fix link validation 2020-09-01 09:57:49 +02:00
Jorik Schellekens
0d2caec456
Merge pull request #105 from matrix-org/matrixtwo/quotecrisis
Move to single quotes
2020-08-19 16:57:19 +01:00
Jorik Schellekens
c009300d09
Merge pull request #104 from matrix-org/matrixtwo/fallbackdata
Implement better fallbacks
2020-08-19 16:57:08 +01:00
Jorik Schellekens
53e1aa57d4
Merge pull request #103 from matrix-org/matrixtwo/mvp
Matrixtwo/mvp
2020-08-19 16:56:35 +01:00
Jorik Schellekens
67787062ba Remove debug statement 2020-08-19 16:55:56 +01:00
Jorik Schellekens
f7abaadef1 Move to single quotes 2020-08-18 11:16:31 +01:00
Jorik Schellekens
0ac4116b24 Implement better fallbacks 2020-08-18 11:07:26 +01:00
Jorik Schellekens
1ad11ed25f Implement minimum amount for a working matrix.to 2020-08-17 17:48:13 +01:00
Jorik Schellekens
f8fe32ffbc Remove accidental builds 2020-08-17 17:44:20 +01:00
Jorik Schellekens
9a85b82c04 Merge branch 'matrix-two' of github.com:matrix-org/matrix.to into matrixtwo/mvp 2020-08-17 16:54:52 +01:00
Jorik Schellekens
fbaf8a7acf
Merge pull request #101 from matrix-org/matrixtwo/previews
Add preview components
2020-08-10 14:59:32 +01:00
Jorik Schellekens
fc70e0c734 Merge branch 'matrix-two' of github.com:matrix-org/matrix.to into matrixtwo/mvp 2020-08-10 12:40:44 +01:00
Jorik Schellekens
9dd1008cb4
Merge pull request #89 from matrix-org/matrixtwo/linkparser
Create link parser and formatter
2020-08-10 12:35:48 +01:00
Jorik Schellekens
5b2c36833c Remove federtaed argument 2020-08-10 12:35:15 +01:00
Jorik Schellekens
14e22d41dc
Fix Typo
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2020-08-10 11:57:54 +01:00
Jorik Schellekens
2842e0cdde
Merge branch 'matrix-two' into matrixtwo/previews 2020-08-06 17:13:38 +01:00
Jorik Schellekens
ba90c5558d Add preview components 2020-08-06 16:38:26 +01:00
Jorik Schellekens
f1cc8eb1e3 Merge branch 'matrix-two' of github.com:matrix-org/matrix.to into matrixtwo/linkparser 2020-08-06 15:01:43 +01:00
Jorik Schellekens
0aa273a8bc Update parser to msc2644 and fix tests 2020-08-06 14:49:33 +01:00
Jorik Schellekens
1b68e23b76
Merge pull request #99 from matrix-org/matrixtwo/storybook
Add storybook
2020-08-03 18:43:00 +01:00
Jorik Schellekens
e6dcf6b3f5 Add copyright, remove whitespace 2020-08-03 18:40:09 +01:00
Jorik Schellekens
767eba53a8
Remove www
Co-authored-by: Travis Ralston <travpc@gmail.com>
2020-08-03 18:38:53 +01:00
Jorik Schellekens
eeb119ecb3 Cheeky lint 2020-07-30 13:34:29 +01:00
Jorik Schellekens
281f9ed766 Set up story book 2020-07-30 13:30:27 +01:00
Jorik Schellekens
d5f1b57b86
Merge pull request #88 from matrix-org/matrixtwo/basic-components
Add landing page
2020-07-23 17:01:42 +01:00
Jorik Schellekens
36899dad55 Fix review issues 2020-07-23 17:01:19 +01:00
Jorik Schellekens
7d9a9904f5 Add matrix logo 2020-06-25 02:01:53 +01:00
Jorik Schellekens
bb28571969 Remove redundent typings 2020-06-25 02:01:25 +01:00
Jorik Schellekens
c39cb0230d Add ref to hosted dev build 2020-06-25 00:43:45 +01:00
Jorik Schellekens
862f57043b Finish landing 2020-06-25 00:41:56 +01:00
Jorik Schellekens
4b35d635c9 Fix style 2020-06-24 16:30:00 +01:00
Jorik Schellekens
0cc791da64 Move eslint to dev dependency 2020-06-24 16:26:17 +01:00
Jorik Schellekens
6dab598f10 Fix scss indent 2020-06-24 16:23:36 +01:00
Jorik Schellekens
317d60b552 Fix prettier 2020-06-24 16:20:56 +01:00
Jorik Schellekens
7e380385b4 Missed a few 2020-06-24 16:17:08 +01:00
Jorik Schellekens
cece18abb2 Fix linting 2020-06-24 15:37:52 +01:00
Jorik Schellekens
d951d73de8 Add lodash dependency 2020-06-16 12:33:30 +01:00
Jorik Schellekens
a4aeefa53c
Doc lints 2020-06-11 02:10:56 +01:00
Jorik Schellekens
339ae06992 Force exhaustive checking on descriminator types 2020-06-11 01:58:44 +01:00
Jorik Schellekens
6325ea8328 Create link parser and formatter 2020-06-11 01:53:49 +01:00
Jorik Schellekens
4d782e59af Add basic components 2020-06-09 14:47:36 +01:00
Jorik Schellekens
8b07e64a9b
Merge pull request #87 from matrix-org/matrixtwo/color-scheme
Add basic styling
2020-06-09 14:42:46 +01:00
Jorik Schellekens
3ace67492a
Merge pull request #85 from matrix-org/matrixtwo/responsive-layout
Basic layout
2020-06-04 17:04:50 +01:00
Jorik Schellekens
af90eaa32d Add basic styling 2020-06-04 16:04:35 +01:00
Jorik Schellekens
170c75144d Basic layout 2020-06-04 14:35:07 +01:00
Jorik Schellekens
b9310c0a21
Merge pull request #83 from matrix-org/matrixtwo/initial-config
Initial config
2020-06-04 11:34:58 +01:00
Jorik Schellekens
b6f55c6011 Initial config 2020-06-01 14:42:30 +01:00
Jorik Schellekens
bfbb712fc2 Matrix.two is born 2020-05-27 15:52:09 +01:00
65 changed files with 7570 additions and 1048 deletions

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
node_modules node_modules
build build
*.tar.gz
/.idea
.DS_Store

59
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,59 @@
# Contributing to Matrix.to
Thank you for taking the time to contribute to Matrix!
This is the repository for Matrix.to, a simple url redirection service for the Matrix.org ecosystem which lets users share links to matrix entities without being tied to a specific app.
## Sign off
We ask that everybody who contributes to this project signs off their contributions, as explained below.
We follow a simple 'inbound=outbound' model for contributions: the act of submitting an 'inbound' contribution means that the contributor agrees to license their contribution under the same terms as the project's overall 'outbound' license - in our case, this is Apache Software License v2 (see [LICENSE](./LICENSE)).
In order to have a concrete record that your contribution is intentional and you agree to license it under the same terms as the project's license, we've adopted the same lightweight approach used by the [Linux Kernel](https://www.kernel.org/doc/html/latest/process/submitting-patches.html), [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), and many other projects: the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This is a simple declaration that you wrote the contribution or otherwise have the right to contribute it to Matrix:
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
If you agree to this for your contribution, then all that's needed is to include the line in your commit or pull request comment:
```
Signed-off-by: Your Name <your@email.example.org>
```
Git allows you to add this signoff automatically when using the `-s` flag to `git commit`, which uses the name and email set in your `user.name` and `user.email` git configs.

19
Dockerfile Normal file
View file

@ -0,0 +1,19 @@
FROM node:latest
# Set working directory
WORKDIR /app
# Copy package files first to leverage Docker cache
COPY package.json yarn.lock ./
# Install dependencies
RUN yarn install
# Copy the rest of the application
COPY . .
# Expose port 5000
EXPOSE 5000
# Start the application
CMD ["yarn", "start"]

177
LICENSE Normal file
View file

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

108
README.md Normal file
View file

@ -0,0 +1,108 @@
# dm.sij.law
This repo is cloned from the official Matrix.to repo on Github. I've added a Dockerfile and will make modifications in the future. The current version is live at [dm.sij.law](https://dm.sij.law)
## First clone the repo
```bash
git clone https://sij.ai/sij/env.esq.git
```
## Next build the image
```bash
docker build -t matrix-to .
```
## Then run it
```bash
docker run -d \
--name matrix-to \
-p 3636:5000 \
matrix-to
```
# EVERYTHING BELOW HERE IS ORIGINAL DOCUMENTATION
## Matrix.to
Matrix.to is a simple url redirection service for the Matrix.org ecosystem
which lets users share links to matrix entities without being tied to a
specific app.
Stylistically it serves as a landing page for rooms and communities.
## How can I put a badge on my website linking to my matrix room?
You can use the badge image we've put up at https://matrix.to/img/matrix-badge.svg, and use it in a link like this:
[![Chat on Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#matrix.to:matrix.org)
You can use this Markdown:
```md
[![Chat on Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#matrix.to:matrix.org)
```
Or this HTML:
```html
<a href="https://matrix.to/#/#matrix.to:matrix.org" rel="noopener" target="_blank"><img src="https://matrix.to/img/matrix-badge.svg" alt="Chat on Matrix"></a>
```
to show the badge.
## How does matrix.to work?
Matrix.to preserves user privacy by not sharing any information about the links
being followed with the Matrix.to server - the redirection is calculated
entirely clientside using JavaScript, and the link details is hidden behind a
fragment to avoid web clients leaking it to the server. However, acting as a
landing page it may leak your ip to any number of homeservers involved with the
entity linked to while fetching previews. There is an opt out under which no
previews will be loaded.
Anyone is welcome to host their own version of the Matrix.to app - Matrix.to is
**not** a single point of failure on the Matrix ecosystem; if the matrix.to
deployment ever failed, users could trivially copy the room/user/message
details out of the URLs and follow them manually, or change the hostname to
point at an alternative deployment of the service. The Matrix.to service could
also be hosted in an immutable/signed environment such as IPFS to further
increase its availability and avoid tampering.
## URL Scheme
The matrix.to URL scheme is
| Entity type: | Example URL |
|--------------|-------------------------------------------------------------------|
| Rooms: | https://matrix.to/#/#matrix:matrix.org |
| Rooms by ID: | https://matrix.to/#/!cURbafjkfsMDVwdRDQ:matrix.org |
| Users: | https://matrix.to/#/@matthew:matrix.org |
| Messages: | https://matrix.to/#/#matrix:matrix.org/$1448831580433WbpiJ:jki.re |
The #/ component is mandatory and exists to avoid leaking the target URL to the
server hosting matrix.to.
Note that linking to rooms by ID should only be used for rooms to which the
target user has been invited: these links cannot be assumed to work for all
visitors.
(Technically the # and @ in the URL fragment should probably be escaped, but in
practice for legibility we bend the rules and include it verbatim)
### Optional parameters
https://matrix.to/#/#matrix:matrix.org?web-instance[element.io]=chat.mozilla.org
- `client`, e.g. `client=im.fluffychat`, `client=element.io`
- `web-instance[]`, e.g. `web-instance[element.io]=chat.mozilla.org`.
- For [matrix.to](https://matrix.to/), we have a list of [trusted web instances configured](src/open/clients/Element.js) (see `trustedWebInstances`).
- `via`, e.g. `via=mozilla.org`
You can discuss matrix.to in
[`#matrix.to:matrix.org`](https://matrix.to/#/#matrix.to:matrix.org)
## Build Instructions
1. Install [yarn](https://classic.yarnpkg.com/en/docs/install)
1. `git clone https://github.com/matrix-org/matrix.to`
1. `cd matrix.to`
1. `yarn`
1. `yarn start`
1. Go to http://localhost:5000 in your browser

View file

@ -16,6 +16,22 @@
padding: 16px; padding: 16px;
} }
.ClientView.isPreferred {
border: 3px solid var(--link);
box-shadow: 0px 8px 4px rgba(0, 0, 0, 0.05);
}
.ClientView .hostedBanner {
text-align: center;
margin-bottom: 29px;
padding: 4px 0;
line-height: 20px;
border-radius: 8px;
font-weight: bold;
font-size: 16px;
background-color: var(--lightgrey);
}
.ClientView .header { .ClientView .header {
display: flex; display: flex;
} }
@ -36,7 +52,7 @@
height: 60px; height: 60px;
overflow: hidden; overflow: hidden;
display: block; display: block;
margin-left: 8px; margin-left: 16px;
} }
.ClientView .platforms { .ClientView .platforms {

View file

@ -21,31 +21,31 @@ limitations under the License.
@import url('open.css'); @import url('open.css');
:root { :root {
--app-background: #f4f4f4; --app-background: #f4f4f4;
--background: #ffffff; --background: #ffffff;
--foreground: #000000; --foreground: #000000;
--font: #333333; --font: #333333;
--grey: #666666; --grey: #666666;
--accent: #0098d4; --accent: #0098d4;
--error: #d6001c; --error: #d6001c;
--link: #0098d4; --link: #0098d4;
--borders: #f4f4f4; --borders: #f4f4f4;
--lightgrey: #E6E6E6; --lightgrey: #E6E6E6;
--spinner-stroke-size: 2px; --spinner-stroke-size: 2px;
} }
html { html {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
body { body {
background-color: var(--app-background); background-color: var(--app-background);
background-image: url('../images/background.svg'); background-image: url('../images/background.svg');
background-attachment: fixed; background-attachment: fixed;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: auto; background-size: auto;
background-position: center -50px; background-position: center -50px;
height: 100%; height: 100%;
width: 100%; width: 100%;
font-size: 14px; font-size: 14px;
@ -54,13 +54,17 @@ body {
margin: 0; margin: 0;
} }
p { noscript {
line-height: 150%; display: block;
padding: 20px;
} }
a { p { line-height: 150%; }
text-decoration: none; a { text-decoration: none; }
}
h1 { font-size: 24px; }
h2 { font-size: 21px; }
h3 { font-size: 16px; }
body, body,
button, button,
@ -85,12 +89,12 @@ input[type="checkbox"], input[type="radio"] {
.RootView { .RootView {
margin: 0 auto; margin: 0 auto;
max-width: 480px; max-width: 480px;
width: 100%; width: 100%;
} }
.card { .card {
background-color: var(--background); background-color: var(--background);
border-radius: 16px; border-radius: 16px;
box-shadow: 0px 18px 24px rgba(0, 0, 0, 0.06); box-shadow: 0px 18px 24px rgba(0, 0, 0, 0.06);
} }
@ -100,20 +104,20 @@ input[type="checkbox"], input[type="radio"] {
} }
.hidden { .hidden {
display: none !important; display: none !important;
} }
@media screen and (max-width: 480px) { @media screen and (max-width: 480px) {
body { body {
background-image: none; background-image: none;
background-color: var(--background); background-color: var(--background);
padding: 0; padding: 0;
} }
.card { .card {
border-radius: unset; border-radius: unset;
box-shadow: unset; box-shadow: unset;
} }
} }
@ -137,7 +141,7 @@ input[type="checkbox"], input[type="radio"] {
} }
a, button.text { a, button.text {
color: var(--link); color: var(--link);
} }
button.text { button.text {

View file

@ -7,6 +7,7 @@
font-size: 24px; font-size: 24px;
line-height: 32px; line-height: 32px;
margin-bottom: 8px; margin-bottom: 8px;
word-wrap: anywhere;
} }
.PreviewView .avatarContainer { .PreviewView .avatarContainer {
@ -21,6 +22,10 @@
height: 64px; height: 64px;
} }
.PreviewView .mxSpace .avatar {
border-radius: 12px;
}
.PreviewView .defaultAvatar { .PreviewView .defaultAvatar {
width: 64px; width: 64px;
height: 64px; height: 64px;

6
docker-compose.yaml Normal file
View file

@ -0,0 +1,6 @@
version: '3'
services:
matrix-to:
build: .
ports:
- "3636:5000"

13
docs/developers.md Normal file
View file

@ -0,0 +1,13 @@
# Developing
Clone the repo and
```
yarn start
```
## Storybook
Storybook lets you view components individually.
```
yarn storybook
```

View file

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="a">
<rect width="99" height="20" rx="3" fill="#fff"/>
</mask>
<g mask="url(#a)">
<path fill="#555" d="M0 0h42v20H0z"/>
<path fill="#46BC99" d="M42 0h59v20H42z"/>
<path fill="url(#b)" d="M0 0h99v20H0z"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="21" y="15" fill="#010101" fill-opacity=".3">matrix</text>
<text x="21" y="14">matrix</text>
<text x="68.5" y="15" fill="#010101" fill-opacity=".3">join chat</text>
<text x="68.5" y="14">join chat</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 781 B

View file

@ -0,0 +1,19 @@
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In -->
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<defs>
</defs>
<g>
<g>
<circle fill="#FFFFFF" cx="9" cy="9" r="8.5"/>
</g>
<g>
<path d="M9,0C4,0,0,4,0,9c0,5,4,9,9,9c5,0,9-4,9-9C18,4,14,0,9,0z M1.2,10.8l3.5-2.3c0-0.1,0-0.2,0-0.3c0-1.8,1.3-3.2,3.1-3.4
c0.1,0,0.2,0,0.4,0c1.2,0,2.3,0.6,2.9,1.6c0.3-0.1,0.6-0.1,0.9-0.1c0.4,0,0.8,0,1.2,0.1c0.7,0.2,1.4,0.5,2,0.9
C14.6,7.1,14,7,13.3,7c-1.2,0-2.2,0.4-2.9,1.4c-0.7,0.9-1.1,2-1.1,3.2c0,1.5-0.4,2.9-1.3,4.2c-0.3,0.4-0.5,0.7-0.8,1
C4.2,16.1,1.9,13.8,1.2,10.8z"/>
<circle cx="9.5" cy="6.4" r="0.5"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 871 B

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 181.4 181.9" style="enable-background:new 0 0 181.4 181.9;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:#F094BE;}
.st2{fill:#4D3F92;}
.st3{fill:#FFFFFF;}
</style>
<g id="Capa_1">
<rect x="0" y="0" style="color:#FFFFFF" width="181.4" height="181.9" class="st3"/>
</g>
<g id="Capa_2">
<g>
<path class="st2" d="M151.6,95.1c1.5-0.3,2.8-1,3.8-2c4-5.3,0.8-11.8-4.5-12.6c-0.8,0-1.5-0.8-1.5-1.5c0-0.3,0-0.5,0-0.5
c0.8-0.8,1.5-1.8,2.5-3.3c8.1-10.8,11.8-50.6,3.8-53.7c-9.8-3.3-29.7,6.3-38.3,17.4c-0.5-0.3-1-1-1-1.8c0.3-3-1.3-5.5-3.5-6.8
c-4.5-2.3-8.8,0-10.6,3.3c-0.5,0.8-1.3,1.3-2,1c-0.8,0-1.5-0.8-1.5-1.5c-0.5-2.5-2-4.5-4.3-5.5c-4.8-2-9.8,0.8-10.6,5.3
c-0.3,0.8-0.8,1.5-1.5,1.5c-0.8,0.3-1.5-0.3-2-1c-1.5-2.3-4-3.8-6.5-3.8c-4,0-7.6,3.3-7.8,7.3v0.3v0.3c0,0.8-0.5,1.5-1,1.8h-0.3
c-8.3-10.8-28.5-20.7-38.5-17.4c-8.1,2.8-4.3,42.6,4,53.4c1.5,2,2.8,3.5,3.8,4.5c-0.3,0.8-1,1.5-1.8,1.5c-1.3,0-2.5,0.5-3.5,1.3
c-5.3,5-2.3,12.1,3,13.4c0.8,0.3,1.5,1,1.5,1.8c0,0.8-0.5,1.8-1.3,2c-1,0.5-2,1-2.8,2c-4,5.8,0,12.3,5.5,12.3
c0.8,0,1.5,0.5,1.8,1.3c0.3,0.8,0.3,1.5-0.5,2c-1.5,1.5-2.3,3.5-2,5.5c0.3,2.8,2,5.3,4.8,6.5c1.5,0.8,3,0.8,4.5,0.5
c0.8-0.3,1.5,0,2,0.8c0.5,0.5,0.5,1.5,0.3,2c-0.8,1.5-1,3.3-0.5,5c0.8,2.8,2.8,4.8,5.5,5.5c2.5,0.5,4.3-0.3,5.5-0.8
c0.5-0.3-3.3,9.1-6,15.4c-0.8,2,1.3,4.3,3.5,3.3c8.3-3.8,22.2-10.3,22.2-9.8c0.5,5.3,6.5,9.1,12.3,5.3c1.3-0.8,2-2.3,2.3-3.5
c0.3-0.8,1-1.5,2-1.5c1,0,1.8,0.5,2,1.5c0.3,1.3,0.8,2.3,1.8,3c5.8,4.5,12.3,0.8,12.8-4.8c0-0.8,0.5-1.5,1.3-1.8
c0.8-0.3,1.5,0,2,0.5c1.5,1.5,3.3,2.5,5.3,2.5l0,0c2.5,0,5-1.3,6.5-3.8c1-1.5,1.3-3,1-5c0-0.8,0.3-1.5,0.8-2c0.5-0.5,1.5-0.5,2,0
c1.5,0.8,3.3,1.3,5,0.8c2.8-0.5,5-2.8,5.8-5.3c0.5-1.8,0.3-3.5-0.5-5.3c-0.3-0.8-0.3-1.5,0.3-2s1.3-0.8,2-0.8
c1.8,0.3,3.3,0.3,4.8-0.5c2.3-1,3.8-3,4.3-5.5c0.5-2.5-0.3-4.8-2-6.5c-0.5-0.5-0.8-1.3-0.5-2s1-1.3,1.8-1.3c1.8,0,3.8-0.5,5-2
c4.3-4.5,2.3-10.6-2.5-12.6c-0.8-0.3-1.3-1-1.3-2C150.1,95.8,150.8,95.1,151.6,95.1z"/>
<path class="st3" d="M131.4,42.2c0.5,1.5,0.5,3,0,4.5c-0.3,0.8,0,1.5,0.5,2s1.3,0.8,2,0.5c1-0.5,2-0.5,3-0.5c2.3,0,4.3,1,5.8,3
c1,1.3,1.8,3,1.5,4.8c0,1.5-0.5,2.8-1.3,4c-0.5,0.5-0.5,1.5,0,2c0.3,0.3,0.5,0.8,1,0.8c1-0.3,2-1,2.8-2c4.5-6.3,5.3-26.2,0.8-27.7
c-4.5-1.5-12.3,1.5-17.9,6C130.7,40.1,131.2,40.9,131.4,42.2z"/>
<path class="st3" d="M39,63.6c0.3-0.3,0.5-0.5,0.8-0.8c0.5-0.8,0.3-1.5,0-2C38.5,59,38.2,57,38.5,55c0.5-2.8,2.8-5,5.5-5.8
c1.5-0.5,3-0.3,4.5,0.3c0.8,0.3,1.5,0,2-0.5c0.5-0.5,0.8-1.3,0.5-2c-0.5-1.5-0.5-3,0-4.5c0.3-1,0.8-2,1.5-2.8
c-5.5-4.5-13.9-7.8-18.4-6.3S30.4,54.8,35,61.1C36,62.6,37.2,63.3,39,63.6z"/>
<g>
<circle class="st3" cx="60.9" cy="94.6" r="9.3"/>
<path class="st3" d="M100.7,94.6c0,5.3-4.3,9.3-9.3,9.3c-5.3,0-9.3-4.3-9.3-9.3S100.7,89.3,100.7,94.6z"/>
<circle class="st3" cx="121.6" cy="94.6" r="9.3"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="58" y1="69.999985" y2="69.999985">
<stop offset="0" stop-color="#4aaac9"/>
<stop offset="0.16" stop-color="#8bddf7"/>
<stop offset="0.32" stop-color="#4aaac9"/>
<stop offset="1" stop-color="#4aaac9"/>
</linearGradient>
<linearGradient id="b" gradientUnits="userSpaceOnUse" x1="31.462524" x2="39" y1="113.997253" y2="113.997253">
<stop offset="0" stop-color="#4aaac9"/>
<stop offset="0.469318" stop-color="#74d7f7"/>
<stop offset="1" stop-color="#4aaac9"/>
</linearGradient>
<linearGradient id="c" gradientUnits="userSpaceOnUse" x1="104" x2="120" y1="84" y2="84">
<stop offset="0" stop-color="#1a5fb4"/>
<stop offset="0.5" stop-color="#4296ff"/>
<stop offset="1" stop-color="#1a5fb4"/>
</linearGradient>
<clipPath id="d">
<path d="m 8 24 h 97 v 84 h -97 z m 0 0"/>
</clipPath>
<clipPath id="e">
<path d="m 24 24 h 80 c 8.835938 0 16 7.164062 16 16 v 52 c 0 8.835938 -7.164062 16 -16 16 h -80 c -8.835938 0 -16 -7.164062 -16 -16 v -52 c 0 -8.835938 7.164062 -16 16 -16 z m 0 0"/>
</clipPath>
<linearGradient id="f" gradientUnits="userSpaceOnUse" x1="55.608135" x2="71.783539" y1="100" y2="48.532928">
<stop offset="0" stop-color="#81dffe"/>
<stop offset="1" stop-color="#9bf8fe"/>
</linearGradient>
<filter id="g" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<mask id="h">
<g filter="url(#g)">
<rect fill-opacity="0.35" height="128" width="128"/>
</g>
</mask>
<clipPath id="i">
<rect height="152" width="192"/>
</clipPath>
<path d="m 24 28 h 72 c 8.835938 0 16 7.164062 16 16 v 52 c 0 8.835938 -7.164062 16 -16 16 h -72 c -8.835938 0 -16 -7.164062 -16 -16 v -52 c 0 -8.835938 7.164062 -16 16 -16 z m 0 0" fill="url(#a)"/>
<path d="m 24 28 h 80 c 8.835938 0 16 7.164062 16 16 v 48 c 0 8.835938 -7.164062 16 -16 16 h -80 c -8.835938 0 -16 -7.164062 -16 -16 v -48 c 0 -8.835938 7.164062 -16 16 -16 z m 0 0" fill="#53bde0"/>
<path d="m 24 100 v 12 h 4 c 2.210938 0 4 1.789062 4 4 v 7 c 0 1.992188 1.183594 3.792969 3.011719 4.585938 c 1.828125 0.789062 3.953125 0.417968 5.40625 -0.945313 l 13.523437 -12.707031 c 1.324219 -1.242188 3.070313 -1.933594 4.882813 -1.933594 h 9.175781 v -12 z m 0 0" fill="url(#b)" fill-rule="evenodd"/>
<path d="m 102 58.566406 h 2 c 8.835938 0 16 7.164063 16 16 v 21.433594 c 0 8.835938 -7.164062 16 -16 16 h -2 c -8.835938 0 -16 -7.164062 -16 -16 v -21.433594 c 0 -8.835937 7.164062 -16 16 -16 z m 0 0" fill="url(#c)"/>
<path d="m 86 87 h 18 v 25 h -18 z m 0 0" fill="#1a5fb4"/>
<path d="m 48 24 h 56 c 8.835938 0 16 7.164062 16 16 v 52 c 0 8.835938 -7.164062 16 -16 16 h -56 c -8.835938 0 -16 -7.164062 -16 -16 v -52 c 0 -8.835938 7.164062 -16 16 -16 z m 0 0" fill="#3584e4"/>
<g clip-path="url(#d)">
<g clip-path="url(#e)">
<path d="m 78.804688 16.023438 l 0.527343 2.460937 c -1.207031 -0.082031 -2.417969 4.964844 -3.621093 4.988281 c -19.335938 0.371094 -38.003907 14.230469 -39.148438 34.546875 c -0.835938 14.761719 9.570312 29.839844 25.15625 30.488281 c 10.371094 0.433594 20.96875 -6.957031 21.242188 -17.925781 c 0.179687 -7.078125 -4.953126 -14.3125 -12.488282 -14.355469 c -4.683594 -0.027343 -9.484375 3.425782 -9.398437 8.429688 c 0.074219 2.980469 2.300781 6.042969 5.511719 5.902344 c 1.8125 -0.082032 3.691406 -1.488282 3.539062 -3.453125 c -0.078125 -1.042969 -0.921875 -2.128907 -2.0625 -1.996094 c -0.5625 0.066406 -1.148438 0.539063 -1.046875 1.15625 c 0.070313 0.273437 0.285156 0.570313 0.597656 0.5 c 0.121094 -0.03125 0.25 -0.144531 0.214844 -0.28125 c 0 -0.042969 -0.070313 -0.09375 -0.113281 -0.074219 c 0 0.003906 -0.070313 0.023438 0 0.035156 v 0.007813 v -0.003906 v 0.035156 c 0 0.050781 -0.09375 0.050781 -0.136719 0.03125 c -0.121094 -0.066406 -0.113281 -0.242187 -0.070313 -0.347656 c 0.164063 -0.265625 0.542969 -0.230469 0.777344 -0.074219 c 0.519532 0.367188 0.429688 1.117188 0.070313 1.558594 c -0.710938 0.898437 -2.074219 0.726562 -2.867188 0.042968 c -1.5 -1.28125 -1.167969 -3.601562 0.070313 -4.941406 c 2.167968 -2.367187 5.929687 -1.792968 8.074218 0.28125 c 3.601563 3.476563 2.652344 9.308594 -0.675781 12.597656 c -5.359375 5.292969 -14.109375 3.800782 -18.992187 -1.324218 c -7.570313 -7.953125 -5.304688 -20.664063 2.335937 -27.6875 c 11.480469 -10.550782 29.507813 -7.242188 39.363281 3.785156 c 14.414063 16.121094 9.6875 41.066406 -5.855468 54.582031 c -11.121094 9.226563 -22.246094 15.429688 -32.949219 19.4375 c -13.058594 75.445313 -75.230469 6.835938 -81.039063 -4.195312 l 0.285157 -105.054688 z m 0 0" fill="url(#f)"/>
</g>
</g>
<path d="m 24 106 v 2 h 4 c 2.210938 0 4 1.789062 4 4 v 7 c 0 1.992188 1.183594 3.792969 3.011719 4.585938 c 1.828125 0.789062 3.953125 0.417968 5.40625 -0.945313 l 13.523437 -12.707031 c 1.324219 -1.242188 3.070313 -1.933594 4.882813 -1.933594 h 9.175781 v -2 z m 0 0" fill="#81dffe" fill-rule="evenodd"/>
<g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -8 -16)">
<path d="m 173 17 h 8 c 1.65625 0 3 1.34375 3 3 v 7 c 0 1.65625 -1.34375 3 -3 3 h -8 c -1.65625 0 -3 -1.34375 -3 -3 v -7 c 0 -1.65625 1.34375 -3 3 -3 z m 0 0" fill="#241f31"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -0,0 +1,34 @@
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M51 12C51 10.8954 50.1046 10 49 10H13C11.8954 10 11 10.8954 11 12V38C11 39.1046 11.8954 40 13 40H30.5858C30.851 40 31.1054 40.1054 31.2929 40.2929L39.2929 48.2929C39.9229 48.9229 41 48.4767 41 47.5858V41C41 40.4477 41.4477 40 42 40H49C50.1046 40 51 39.1046 51 38V12Z" fill="url(#paint0_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 37V38C11 39.1046 11.8954 40 13 40H30.5858C30.851 40 31.1054 40.1054 31.2929 40.2929L39.2929 48.2929C39.9229 48.9229 41 48.4767 41 47.5858V46.5858C41 47.4767 39.9229 47.9229 39.2929 47.2929L31.2929 39.2929C31.1054 39.1054 30.851 39 30.5858 39H13C11.8954 39 11 38.1046 11 37ZM41 41C41 40.4477 41.4477 40 42 40H49C50.1046 40 51 39.1046 51 38V37C51 38.1046 50.1046 39 49 39H42C41.4477 39 41 39.4477 41 40V41Z" fill="#000405" fill-opacity="0.1"/>
<path d="M8 10C8 8.89543 8.89543 8 10 8H46C47.1046 8 48 8.89543 48 10V36C48 37.1046 47.1046 38 46 38H28.4142C28.149 38 27.8946 38.1054 27.7071 38.2929L19.7071 46.2929C19.0771 46.9229 18 46.4767 18 45.5858V39C18 38.4477 17.5523 38 17 38H10C8.89543 38 8 37.1046 8 36V10Z" fill="url(#paint1_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 35V36C8 37.1046 8.89543 38 10 38H17C17.5523 38 18 38.4477 18 39V38C18 37.4477 17.5523 37 17 37H10C8.89543 37 8 36.1046 8 35ZM18 44.5858V45.5858C18 46.4767 19.0771 46.9229 19.7071 46.2929L27.7071 38.2929C27.8946 38.1054 28.149 38 28.4142 38H46C47.1046 38 48 37.1046 48 36V35C48 36.1046 47.1046 37 46 37H28.4142C28.149 37 27.8946 37.1054 27.7071 37.2929L19.7071 45.2929C19.0771 45.9229 18 45.4767 18 44.5858Z" fill="#031C5A" fill-opacity="0.1"/>
<rect x="13" y="14" width="30" height="4" rx="2" fill="url(#paint2_linear)"/>
<rect x="12.5" y="13.5" width="31" height="5" rx="2.5" stroke="#004E6E" stroke-opacity="0.1"/>
<rect x="13" y="21" width="25" height="4" rx="2" fill="url(#paint3_linear)"/>
<rect x="12.5" y="20.5" width="26" height="5" rx="2.5" stroke="#004E6E" stroke-opacity="0.1"/>
<rect x="13" y="28" width="20" height="4" rx="2" fill="url(#paint4_linear)"/>
<rect x="12.5" y="27.5" width="21" height="5" rx="2.5" stroke="#004E6E" stroke-opacity="0.1"/>
<defs>
<linearGradient id="paint0_linear" x1="51" y1="10" x2="11" y2="50" gradientUnits="userSpaceOnUse">
<stop stop-color="#6EB4D9"/>
<stop offset="1" stop-color="#004E6E"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="8" y1="8" x2="48" y2="48" gradientUnits="userSpaceOnUse">
<stop stop-color="#44F0D3"/>
<stop offset="1" stop-color="#3DAEE9"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="43" y1="18" x2="19.5854" y2="-11.2683" gradientUnits="userSpaceOnUse">
<stop stop-color="#D1D5D9"/>
<stop offset="1" stop-color="#FCFFFF"/>
</linearGradient>
<linearGradient id="paint3_linear" x1="38" y1="25" x2="14.02" y2="0.0208158" gradientUnits="userSpaceOnUse">
<stop stop-color="#D1D5D9"/>
<stop offset="1" stop-color="#FCFFFF"/>
</linearGradient>
<linearGradient id="paint4_linear" x1="33" y1="32" x2="9.39344" y2="12.3279" gradientUnits="userSpaceOnUse">
<stop stop-color="#D1D5D9"/>
<stop offset="1" stop-color="#FCFFFF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 43 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 118 KiB

View file

@ -0,0 +1,65 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M452.1 306.5H452.16C474.2 229.45 570.24 191.84 668.11 191.84C735.74 191.84 796.45 213.25 838.07 247.24C813.232 248.411 788.708 253.285 765.31 261.7C798.94 274.2 827.83 293.43 849.24 317.22C833.087 314.439 816.707 313.201 800.32 313.52C840.596 371.863 862.114 441.105 862 512C862 705.3 705.3 862 512 862C321.68 862 162 702.65 162 512C162 481.89 166 450.8 173.77 421.64C175.81 415.52 178.65 409.65 182.42 407.5C187.14 404.81 191.44 412.83 192.13 415.44C197.248 434.61 204.134 453.263 212.7 471.16C211.95 431.2 229.02 394.8 252.5 363.32C268.16 342.33 282.68 322.88 289.38 266.75C289.83 262.98 293.4 260.27 297.01 261.45C347.97 278.13 375.21 362.99 370.98 433.95C399.13 437.98 399 408.57 399 408.57C390 380.91 396 329.5 452 306.5H452.1Z" fill="url(#paint0_linear_1_4)"/>
<path opacity="0.9" d="M850.55 422.87C859.06 615.37 700.81 781.34 507.84 781.34C327.19 781.34 179.16 641.71 165.77 464.49C163.381 481.085 162.125 497.824 162.01 514.59C163.38 704.21 322.67 862 512.01 862C705.31 862 862.01 705.3 862.01 512C862.01 481.2 858.02 451.33 850.55 422.87Z" fill="url(#paint1_radial_1_4)"/>
<path style="mix-blend-mode:screen" d="M503.47 332.01C499.7 325.34 482.29 315.47 474.68 313.75C503.48 221.5 650.2 193.18 740 209.5C777.37 216.3 823.91 236.66 838.07 247.24C796.45 213.25 735.73 191.84 668.11 191.84C570.24 191.84 474.2 229.45 452.16 306.5H452C396 329.5 390 380.93 399 408.58C407.64 375.59 448.75 335.05 503.47 332.01Z" fill="url(#paint2_radial_1_4)"/>
<path d="M605.18 268.3C526.56 283.77 500.87 288.83 474.56 313.84C504.11 235.61 579.54 219.75 669.42 255.41C648.028 259.82 626.615 264.12 605.18 268.31V268.3Z" fill="url(#paint3_linear_1_4)"/>
<path d="M181 410.93C159.52 498.87 176.12 602.23 273.7 688.97C244.65 657.2 209.18 539.9 287.45 456.1C292.72 450.45 301.79 454.6 302.08 462.32C308.53 636.48 449.06 742.85 611.08 722.96C560.88 720.14 394.86 661.99 518.36 638.99C582.91 626.96 684.12 608.11 684.12 517.29C684.12 370.07 570.29 327.03 501.26 333.43C454.02 337.81 411.97 367.79 399.03 408.56C404 424.63 384.19 435.88 370.98 433.99C375.22 363.04 347.98 278.13 297.01 261.45C293.41 260.27 289.83 262.98 289.38 266.75C282.68 322.88 268.16 342.33 252.51 363.32C229.02 394.81 211.95 431.2 212.7 471.16C204.134 453.263 197.248 434.61 192.13 415.44C191.56 413.28 188.43 407.25 184.65 406.97C182.6 406.82 181.51 408.82 181 410.93Z" fill="url(#paint4_radial_1_4)"/>
<path style="mix-blend-mode:screen" d="M474.99 647.9C570.03 725.07 761.16 667.21 761.16 479.58C684 596.54 585.72 677.22 475 647.9H474.99Z" fill="url(#paint5_linear_1_4)"/>
<path style="mix-blend-mode:screen" d="M287.45 456.1C288.314 455.133 289.403 454.394 290.62 453.947C291.838 453.501 293.146 453.361 294.43 453.54C224.37 538.99 280.88 689.06 319.66 725.93C321.83 732.07 282.87 700.14 277.5 692.67C248 667.64 205.72 543.61 287.45 456.1Z" fill="url(#paint6_linear_1_4)"/>
<path d="M512 654.97C607.06 654.97 684.13 592.09 684.13 514.52C684.13 436.95 607.06 374.07 512 374.07C430.9 374.07 339.83 426.83 339.87 516.57C339.91 655.24 486.41 735.02 611.29 722.94C601.91 721.85 543.39 718.74 503.84 674C500.27 669.97 494.08 662.93 496.89 658.36C499.69 653.79 507.41 654.96 511.99 654.96L512 654.97Z" fill="url(#paint7_linear_1_4)"/>
<path opacity="0.6" d="M665.38 450.7L529.34 580.88C517.27 589.46 504.42 590.08 491.74 582.3L358.31 451.18C362.117 445.062 366.396 439.251 371.11 433.8L385.11 446.9C420.15 479.74 448.48 506.27 488.41 540.35C506.43 555.73 512.03 555.43 529.71 540.35C575.39 501.35 608.8 471.85 652.23 433.06C657.07 438.586 661.464 444.488 665.37 450.71L665.38 450.7Z" fill="white"/>
<mask id="mask0_1_4" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="339" y="448" width="346" height="277">
<path d="M684.13 514.52C684.13 592.09 607.06 654.97 512 654.97C507.41 654.97 499.7 653.79 496.89 658.37C494.08 662.93 500.27 669.97 503.84 674C541 716.04 594.91 721.33 609.06 722.72L611.29 722.94C486.41 735.02 339.91 655.24 339.87 516.57C339.74 493.482 346.165 470.831 358.4 451.25L492.48 573.03C502.02 581.69 518.09 581.69 527.63 573.03L664.25 448.94C676.95 468.52 684.13 490.84 684.13 514.52Z" fill="white"/>
</mask>
<g mask="url(#mask0_1_4)">
<path opacity="0.7" d="M300 352.53H735.07V747H300V352.53Z" fill="url(#paint8_linear_1_4)"/>
<g filter="url(#filter0_f_1_4)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M472.04 573.85C446.69 547.47 370.77 459.82 370.77 459.82L376.64 460.08L495.5 548.85C504.4 555.32 517.1 555.25 525.92 548.7L642.47 460.2L648.65 459.71C648.65 459.71 575.21 545.28 547.08 573.47C518.95 601.66 497.39 600.23 472.04 573.85Z" fill="#458FCD"/>
</g>
</g>
<path d="M536.15 303.81C554.57 298.01 552.95 279.78 552.95 279.78C552.95 279.78 543.74 268.93 525.49 274.94C508.41 280.57 505.76 292.74 505.76 292.74C505.76 292.74 515.09 310.44 536.15 303.81Z" fill="white"/>
<defs>
<filter id="filter0_f_1_4" x="338.77" y="427.71" width="341.88" height="198.416" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="16" result="effect1_foregroundBlur_1_4"/>
</filter>
<linearGradient id="paint0_linear_1_4" x1="283.48" y1="307.2" x2="776.88" y2="767.42" gradientUnits="userSpaceOnUse">
<stop stop-color="#1B91F3"/>
<stop offset="1" stop-color="#0B68CB"/>
</linearGradient>
<radialGradient id="paint1_radial_1_4" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(282.57 465.55) rotate(66.5177) scale(295.96 283.519)">
<stop offset="0.53" stop-color="#0B4186" stop-opacity="0"/>
<stop offset="1" stop-color="#0B4186" stop-opacity="0.45"/>
</radialGradient>
<radialGradient id="paint2_radial_1_4" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(521 344) rotate(-127.997) scale(63.2702 104.698)">
<stop stop-color="#EF3ACC" stop-opacity="0"/>
<stop offset="1" stop-color="#EF3ACC" stop-opacity="0.64"/>
</radialGradient>
<linearGradient id="paint3_linear_1_4" x1="420.77" y1="425.01" x2="598.31" y2="227.37" gradientUnits="userSpaceOnUse">
<stop stop-color="#0F5DB0"/>
<stop offset="1" stop-color="#0F5DB0" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint4_radial_1_4" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(380 702.7) rotate(-64.2624) scale(461.716 570.355)">
<stop offset="0.02" stop-color="#094188"/>
<stop offset="0.97" stop-color="#0B4186" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint5_linear_1_4" x1="731.92" y1="568.11" x2="649.37" y2="770.8" gradientUnits="userSpaceOnUse">
<stop stop-color="#E247C4" stop-opacity="0"/>
<stop offset="1" stop-color="#E247C4" stop-opacity="0.64"/>
</linearGradient>
<linearGradient id="paint6_linear_1_4" x1="220.01" y1="386.34" x2="292.74" y2="679.06" gradientUnits="userSpaceOnUse">
<stop offset="0.1" stop-color="#EF3ACC"/>
<stop offset="1" stop-color="#EF3ACC" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint7_linear_1_4" x1="512" y1="425.5" x2="512" y2="721.5" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="0.91" stop-color="#BEE1FE"/>
<stop offset="1" stop-color="#96CEFD"/>
</linearGradient>
<linearGradient id="paint8_linear_1_4" x1="517.54" y1="593" x2="517.54" y2="717" gradientUnits="userSpaceOnUse">
<stop stop-color="#BCE0FD"/>
<stop offset="1" stop-color="#88CCFC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

View file

@ -1,16 +1,26 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>You're invited to talk on Matrix</title> <title>You're invited to talk on Matrix</title>
<meta name="description" content="You're invited to talk on Matrix"> <meta name="description" content="You're invited to talk on Matrix">
<meta name="viewport" content="width=device-width, user-scalable=no"> <meta name="viewport" content="width=device-width, user-scalable=no">
<link rel="stylesheet" type="text/css" href="css/main.css"> <link rel="stylesheet" type="text/css" href="css/main.css">
<meta property="twitter:card" content="summary"/>
<meta property="twitter:image" content="https://matrix.org/blog/img/matrix-logo.png"/>
<meta property="twitter:site" content="@matrixdotorg"/>
<meta property="twitter:title" content="Matrix - Decentralised and secure communication"/>
<meta property="twitter:description" content="You're invited to talk on Matrix. If you don't already have a client this link will help you pick one, and join the conversation. If you already have one, this link will help you join the conversation"/>
</head> </head>
<body> <body>
<script id="main" type="module"> <script id="main" type="module">
import {main} from "./src/main.js"; import {main} from "./src/main.js";
main(document.body); main(document.body);
</script> </script>
<noscript>
<h1>Please enable javascript</h1>
<p>Matrix.to is a preview service from chat rooms, people and communities on <a href="https://matrix.org">Matrix</a>.</p>
<p>It preserves your privacy by only processing what you view on the client side. For this to work, it needs javascript.</p>
</noscript>
</body> </body>
</html> </html>

View file

@ -1,6 +1,6 @@
{ {
"name": "matrix.to", "name": "matrix.to",
"version": "0.0.1", "version": "1.2.17",
"type": "module", "type": "module",
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@ -23,7 +23,7 @@
"core-js": "^3.6.5", "core-js": "^3.6.5",
"finalhandler": "^1.1.2", "finalhandler": "^1.1.2",
"mdn-polyfills": "^5.20.0", "mdn-polyfills": "^5.20.0",
"postcss": "^8.1.1", "postcss": "^8.4.31",
"postcss-css-variables": "^0.17.0", "postcss-css-variables": "^0.17.0",
"postcss-flexbugs-fixes": "^4.2.1", "postcss-flexbugs-fixes": "^4.2.1",
"postcss-import": "^12.0.1", "postcss-import": "^12.0.1",

View file

@ -52,15 +52,16 @@ async function build() {
await removeDirIfExists(targetDir); await removeDirIfExists(targetDir);
await fs.mkdir(targetDir); await fs.mkdir(targetDir);
await fs.mkdir(path.join(targetDir, "images")); await fs.mkdir(path.join(targetDir, "images"));
await fs.mkdir(path.join(targetDir, "img")); // contains the badge image for historical reasons, unhashed
await fs.mkdir(path.join(targetDir, ".well-known")); await fs.mkdir(path.join(targetDir, ".well-known"));
const assets = new AssetMap(targetDir); const assets = new AssetMap(targetDir);
const imageAssets = await copyFolder(path.join(projectDir, "images"), path.join(targetDir, "images")); const imageAssets = await copyFolder(path.join(projectDir, "images"), path.join(targetDir, "images"));
assets.addSubMap(imageAssets); assets.addSubMap(imageAssets);
await assets.write(`bundle-esm.js`, await buildJs("src/main.js", assets)); await assets.write(`bundle.js`, await buildJs("src/main.js", assets, ["src/polyfill.js"]));
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.write(`bundle.css`, await buildCss("css/main.css", targetDir, assets));
await assets.writeUnhashed(".well-known/apple-app-site-association", buildAppleAssociatedAppsFile(createClients())); await assets.writeUnhashed(".well-known/apple-app-site-association", buildAppleAssociatedAppsFile(createClients()));
await assets.writeUnhashed("index.html", await buildHtml(assets)); await assets.writeUnhashed("index.html", await buildHtml(assets));
await assets.writeUnhashed("img/matrix-badge.svg", await fs.readFile(path.join(projectDir, "images-nohash/matrix-badge.svg")));
const globalHash = assets.hashForAll(); const globalHash = assets.hashForAll();
console.log(`built matrix.to ${version} (${globalHash}) successfully with ${assets.size} files`); console.log(`built matrix.to ${version} (${globalHash}) successfully with ${assets.size} files`);
} }
@ -70,9 +71,12 @@ async function buildHtml(assets) {
const doc = cheerio.load(devHtml); const doc = cheerio.load(devHtml);
doc("link[rel=stylesheet]").attr("href", assets.resolve(`bundle.css`)); doc("link[rel=stylesheet]").attr("href", assets.resolve(`bundle.css`));
const mainScripts = [ const mainScripts = [
`<script type="module">import {main} from "./${assets.resolve(`bundle-esm.js`)}"; main(document.body);</script>`, // this is needed to avoid hitting https://github.com/facebook/regenerator/issues/378
`<script type="text/javascript" nomodule src="${assets.resolve(`bundle-legacy.js`)}"></script>`, // which prevents the whole bundle to load, as our CSP headers don't allow unsafe-eval
`<script type="text/javascript" nomodule>bundle.main(document.body);</script>` // and I preferred this over disabling strict mode for the whole bundle
`<script type="text/javascript">window.regeneratorRuntime = undefined;</script>`,
`<script type="text/javascript" src="${assets.resolve(`bundle.js`)}"></script>`,
`<script type="text/javascript">bundle.main(document.body);</script>`
]; ];
doc("script#main").replaceWith(mainScripts.join("")); doc("script#main").replaceWith(mainScripts.join(""));
return doc.html(); return doc.html();
@ -87,19 +91,6 @@ function createReplaceUrlPlugin(assets) {
} }
async function buildJs(mainFile, assets, extraFiles = []) { 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 // compile down to whatever IE 11 needs
const babelPlugin = babel.babel({ const babelPlugin = babel.babel({
babelHelpers: 'bundled', babelHelpers: 'bundled',
@ -133,21 +124,20 @@ async function buildJsLegacy(mainFile, assets, extraFiles = []) {
} }
function buildAppleAssociatedAppsFile(clients) { function buildAppleAssociatedAppsFile(clients) {
const appIds = clients.map(c => c.appleAssociatedAppId).filter(id => !!id); const appIds = clients.map(c => c.appleAssociatedAppId).flat().filter(id => !!id);
return JSON.stringify({ return JSON.stringify({
"applinks": { "applinks": {
"apps": [], "details": [
"details": { {
appIDs: appIds, appIDs: appIds,
components: [ components: [
{ {
"#": "/*", // only open urls with a fragment, so you can still create links "#": "/*",
} "comment": "Only open urls with a fragment, so you can still create links"
] }
}, ]
}, }
"webcredentials": { ]
"apps": appIds
} }
}); });
} }
@ -155,7 +145,7 @@ function buildAppleAssociatedAppsFile(clients) {
async function buildCss(entryPath, targetDir, assets) { async function buildCss(entryPath, targetDir, assets) {
entryPath = path.join(projectDir, entryPath); entryPath = path.join(projectDir, entryPath);
const assetUrlMapper = ({absolutePath}) => { const assetUrlMapper = ({absolutePath}) => {
const relPath = absolutePath.substr(projectDir.length); const relPath = absolutePath.slice(projectDir.length);
return assets.resolve(path.join(targetDir, relPath)); return assets.resolve(path.join(targetDir, relPath));
}; };
@ -220,7 +210,7 @@ class AssetMap {
if (!resourcePath.startsWith(this._targetDir)) { if (!resourcePath.startsWith(this._targetDir)) {
throw new Error(`absolute path ${resourcePath} that is not within target dir ${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 / relPath = resourcePath.slice(this._targetDir.length + 1); // + 1 for the /
} }
return relPath; return relPath;
} }
@ -276,7 +266,7 @@ class AssetMap {
if (!assetMap.directory.startsWith(this.directory)) { if (!assetMap.directory.startsWith(this.directory)) {
throw new Error(`map directory doesn't start with this directory: ${assetMap.directory} ${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); const relSubRoot = assetMap.directory.slice(this.directory.length + 1);
for (const [key, value] of assetMap._assets.entries()) { for (const [key, value] of assetMap._assets.entries()) {
this._assets.set(path.join(relSubRoot, key), path.join(relSubRoot, value)); this._assets.set(path.join(relSubRoot, key), path.join(relSubRoot, value));
} }

8
scripts/package.sh Executable file
View file

@ -0,0 +1,8 @@
set -e
VERSION=$(jq -r ".version" package.json)
PACKAGE=matrixto-$VERSION.tar.gz
yarn build
pushd build
tar -czvf ../$PACKAGE ./
popd
echo $PACKAGE

View file

@ -23,23 +23,26 @@ const projectDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".
// Serve up parent directory with cache disabled // Serve up parent directory with cache disabled
const serve = serveStatic( const serve = serveStatic(
projectDir, projectDir,
{ {
etag: false, etag: false,
setHeaders: res => { setHeaders: res => {
res.setHeader("Pragma", "no-cache"); res.setHeader("Pragma", "no-cache");
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
res.setHeader("Expires", "Wed, 21 Oct 2015 07:28:00 GMT"); res.setHeader("Expires", "Wed, 21 Oct 2015 07:28:00 GMT");
}, // same CSP as matrix.to server is using, so local testing happens under similar environment
index: ['index.html', 'index.htm'] res.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src * data:; connect-src *; font-src 'self'; manifest-src 'self'; form-action 'self'; navigate-to *;");
} },
index: ['index.html', 'index.htm']
}
); );
// Create server // Create server
const server = http.createServer(function onRequest (req, res) { const server = http.createServer(function onRequest (req, res) {
console.log(req.method, req.url); console.log(req.method, req.url);
serve(req, res, finalhandler(req, res)) serve(req, res, finalhandler(req, res))
}); });
// Listen // Listen
server.listen(5000); server.listen(5000);
console.log("Listening on port 5000");

56
src/InvalidUrlView.js Normal file
View file

@ -0,0 +1,56 @@
/*
Copyright 2021 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 {LinkKind, IdentifierKind} from "./Link.js";
export class InvalidUrlView extends TemplateView {
render(t, vm) {
return t.div({ className: "DisclaimerView card" }, [
t.h1("Invalid URL"),
t.p([
'The link you have entered is not valid. If you like, you can ',
t.a({ href: "#/" }, 'return to the home page.')
]),
vm.validFixes.length ? this._renderValidFixes(t, vm.validFixes) : [],
]);
}
_describeRoom(identifierKind) {
return identifierKind === IdentifierKind.RoomAlias ? "room alias" : "room";
}
_describeLinkKind(linkKind, identifierKind) {
switch (linkKind) {
case LinkKind.Room: return `The ${this._describeRoom(identifierKind)} `;
case LinkKind.User: return "The user ";
case LinkKind.Group: return "The group ";
case LinkKind.Event: return `An event in ${this._describeRoom(identifierKind)} `;
}
}
_renderValidFixes(t, validFixes) {
return t.p([
'Did you mean any of the following?',
t.ul(validFixes.map(fix =>
t.li([
this._describeLinkKind(fix.link.kind, fix.link.identifierKind),
t.a({ href: fix.url }, fix.link.identifier)
])
))
]);
}
}

View file

@ -0,0 +1,25 @@
/*
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 {ViewModel} from "./utils/ViewModel.js";
import {tryFixUrl} from "./Link.js";
export class InvalidUrlViewModel extends ViewModel {
constructor(options) {
super(options);
this.validFixes = tryFixUrl(options.fragment);
}
}

View file

@ -24,38 +24,70 @@ const EVENTID_PATTERN = /^$([^:]+):(.+)$/;
const GROUPID_PATTERN = /^\+([^:]+):(.+)$/; const GROUPID_PATTERN = /^\+([^:]+):(.+)$/;
export const IdentifierKind = createEnum( export const IdentifierKind = createEnum(
"RoomId", "RoomId",
"RoomAlias", "RoomAlias",
"UserId", "UserId",
"GroupId", "GroupId",
); );
function asPrefix(identifierKind) { function asPrefix(identifierKind) {
switch (identifierKind) { switch (identifierKind) {
case IdentifierKind.RoomId: return "!"; case IdentifierKind.RoomId: return "!";
case IdentifierKind.RoomAlias: return "#"; case IdentifierKind.RoomAlias: return "#";
case IdentifierKind.GroupId: return "+"; case IdentifierKind.GroupId: return "+";
case IdentifierKind.UserId: return "@"; case IdentifierKind.UserId: return "@";
default: throw new Error("invalid id kind " + identifierKind); default: throw new Error("invalid id kind " + identifierKind);
} }
}
function getWebInstanceMap(queryParams) {
const prefix = "web-instance[";
const postfix = "]";
const webInstanceParams = queryParams.filter(([key]) => key.startsWith(prefix) && key.endsWith(postfix));
const webInstances = webInstanceParams.map(([key, value]) => {
const noPrefix = key.slice(prefix.length);
const clientId = noPrefix.slice(0, -postfix.length);
return [clientId, value];
});
return webInstances.reduce((map, [clientId, host]) => {
map[clientId] = host;
return map;
}, {});
} }
export function getLabelForLinkKind(kind) { export function getLabelForLinkKind(kind) {
switch (kind) { switch (kind) {
case LinkKind.User: return "Start chat"; case LinkKind.User: return "Start chat";
case LinkKind.Room: return "View room"; case LinkKind.Room: return "View room";
case LinkKind.Group: return "View community"; case LinkKind.Group: return "View community";
case LinkKind.Event: return "View message"; case LinkKind.Event: return "View message";
} }
} }
export const LinkKind = createEnum( export const LinkKind = createEnum(
"Room", "Room",
"User", "User",
"Group", "Group",
"Event" "Event"
) )
export function tryFixUrl(fragment) {
const attempts = [];
const afterHash = fragment.substring(fragment.startsWith("#/") ? 2 : 1);
attempts.push('#/@' + afterHash);
attempts.push('#/#' + afterHash);
attempts.push('#/!' + afterHash);
const validAttempts = [];
for (const attempt of [...new Set(attempts)]) {
const link = Link.parseFragment(attempt);
if (link) {
validAttempts.push({ url: attempt, link });
}
}
return validAttempts;
}
export class Link { export class Link {
static validateIdentifier(identifier) { static validateIdentifier(identifier) {
return !!( return !!(
@ -66,98 +98,115 @@ export class Link {
); );
} }
static parse(fragment) { static parseIdentifier(identifier) {
if (!fragment) { return Link._parse(identifier);
return null; }
}
let [linkStr, queryParamsStr] = fragment.split("?");
let viaServers = []; static parseFragment(fragment) {
if (!fragment) {
return null;
}
let [linkStr, queryParamsStr] = fragment.split("?");
if (!linkStr.startsWith("#/")) {
return null;
}
linkStr = linkStr.slice(2);
const [identifier, eventId] = linkStr.split("/");
let viaServers = [];
let clientId = null; let clientId = null;
if (queryParamsStr) { let webInstances = {};
const queryParams = queryParamsStr.split("&").map(pair => pair.split("=")); if (queryParamsStr) {
viaServers = queryParams const queryParams = queryParamsStr.split("&").map(pair => {
.filter(([key, value]) => key === "via") const [key, value] = pair.split("=");
.map(([,value]) => value); return [decodeURIComponent(key), decodeURIComponent(value)];
});
viaServers = queryParams
.filter(([key, value]) => key === "via")
.map(([,value]) => value);
const clientParam = queryParams.find(([key]) => key === "client"); const clientParam = queryParams.find(([key]) => key === "client");
if (clientParam) { if (clientParam) {
clientId = clientParam[1]; clientId = clientParam[1];
} }
} webInstances = getWebInstanceMap(queryParams);
}
return Link._parse(identifier, eventId, clientId, viaServers, webInstances);
}
if (linkStr.startsWith("#/")) { static _parse(identifier, eventId = undefined, clientId = null, viaServers = [], webInstances = {}) {
linkStr = linkStr.substr(2); if (!identifier) {
} return null;
}
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, webInstances);
}
matches = ROOMALIAS_PATTERN.exec(identifier);
if (matches) {
const server = matches[2];
const localPart = matches[1];
return new Link(clientId, viaServers, IdentifierKind.RoomAlias, localPart, server, webInstances, 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, webInstances, 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, webInstances);
}
return null;
}
const [identifier, eventId] = linkStr.split("/"); constructor(clientId, viaServers, identifierKind, localPart, server, webInstances, eventId) {
const servers = [server];
let matches; servers.push(...viaServers);
matches = USERID_PATTERN.exec(identifier); this.webInstances = webInstances;
if (matches) { this.servers = orderedUnique(servers);
const server = matches[2]; this.identifierKind = identifierKind;
const localPart = matches[1]; this.identifier = `${asPrefix(identifierKind)}${localPart}:${server}`;
return new Link(clientId, viaServers, IdentifierKind.UserId, localPart, server); this.eventId = eventId;
}
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; this.clientId = clientId;
} }
get kind() { get kind() {
if (this.eventId) { if (this.eventId) {
return LinkKind.Event; return LinkKind.Event;
} }
switch (this.identifierKind) { switch (this.identifierKind) {
case IdentifierKind.RoomId: case IdentifierKind.RoomId:
case IdentifierKind.RoomAlias: case IdentifierKind.RoomAlias:
return LinkKind.Room; return LinkKind.Room;
case IdentifierKind.UserId: case IdentifierKind.UserId:
return LinkKind.User; return LinkKind.User;
case IdentifierKind.GroupId: case IdentifierKind.GroupId:
return LinkKind.Group; return LinkKind.Group;
default: default:
return null; return null;
} }
} }
equals(link) { equals(link) {
return link && return link &&
link.identifier === this.identifier && link.identifier === this.identifier &&
this.servers.length === link.servers.length && this.servers.length === link.servers.length &&
this.servers.every((s, i) => link.servers[i] === s); this.servers.every((s, i) => link.servers[i] === s) &&
} Object.keys(this.webInstances).length === Object.keys(link.webInstances).length &&
Object.keys(this.webInstances).every(k => this.webInstances[k] === link.webInstances[k]);
}
toFragment() { toFragment() {
if (this.eventId) { if (this.eventId) {
return `/${this.identifier}/${this.eventId}`; return `/${this.identifier}/${this.eventId}`;
} else { } else {
return `/${this.identifier}`; return `/${this.identifier}`;
} }
} }
} }

View file

@ -17,17 +17,17 @@ limitations under the License.
import {createEnum} from "./utils/enum.js"; import {createEnum} from "./utils/enum.js";
export const Platform = createEnum( export const Platform = createEnum(
"DesktopWeb", "DesktopWeb",
"MobileWeb", "MobileWeb",
"Android", "Android",
"iOS", "iOS",
"Windows", "Windows",
"macOS", "macOS",
"Linux" "Linux"
); );
export function guessApplicablePlatforms(userAgent, platform) { export function guessApplicablePlatforms(userAgent, platform) {
// return [Platform.DesktopWeb, Platform.Linux]; // return [Platform.DesktopWeb, Platform.Linux];
let nativePlatform; let nativePlatform;
let webPlatform; let webPlatform;
if (/android/i.test(userAgent)) { if (/android/i.test(userAgent)) {
@ -55,10 +55,10 @@ export function guessApplicablePlatforms(userAgent, platform) {
} }
export function isWebPlatform(p) { export function isWebPlatform(p) {
return p === Platform.DesktopWeb || p === Platform.MobileWeb; return p === Platform.DesktopWeb || p === Platform.MobileWeb;
} }
export function isDesktopPlatform(p) { export function isDesktopPlatform(p) {
return p === Platform.Linux || p === Platform.Windows || p === Platform.macOS; return p === Platform.Linux || p === Platform.Windows || p === Platform.macOS;
} }

View file

@ -18,51 +18,51 @@ import {Platform} from "./Platform.js";
import {EventEmitter} from "./utils/ViewModel.js"; import {EventEmitter} from "./utils/ViewModel.js";
export class Preferences extends EventEmitter { export class Preferences extends EventEmitter {
constructor(localStorage) { constructor(localStorage) {
super(); super();
this._localStorage = localStorage; this._localStorage = localStorage;
this.clientId = null; this.clientId = null;
// used to differentiate web from native if a client supports both // used to differentiate web from native if a client supports both
this.platform = null; this.platform = null;
this.homeservers = null; this.homeservers = null;
const prefsStr = localStorage.getItem("preferred_client"); const prefsStr = localStorage.getItem("preferred_client");
if (prefsStr) { if (prefsStr) {
const {id, platform} = JSON.parse(prefsStr); const {id, platform} = JSON.parse(prefsStr);
this.clientId = id; this.clientId = id;
this.platform = Platform[platform]; this.platform = Platform[platform];
} }
const serversStr = localStorage.getItem("consented_servers"); const serversStr = localStorage.getItem("consented_servers");
if (serversStr) { if (serversStr) {
this.homeservers = JSON.parse(serversStr); this.homeservers = JSON.parse(serversStr);
} }
} }
setClient(id, platform) { setClient(id, platform) {
this.clientId = id; this.clientId = id;
platform = Platform[platform]; platform = Platform[platform];
this.platform = platform; this.platform = platform;
this._localStorage.setItem("preferred_client", JSON.stringify({id, platform})); this._localStorage.setItem("preferred_client", JSON.stringify({id, platform}));
this.emit("canClear") this.emit("canClear")
} }
setHomeservers(homeservers, persist) { setHomeservers(homeservers, persist) {
this.homeservers = homeservers; this.homeservers = homeservers;
if (persist) { if (persist) {
this._localStorage.setItem("consented_servers", JSON.stringify(homeservers)); this._localStorage.setItem("consented_servers", JSON.stringify(homeservers));
this.emit("canClear"); this.emit("canClear");
} }
} }
clear() { clear() {
this._localStorage.removeItem("preferred_client"); this._localStorage.removeItem("preferred_client");
this._localStorage.removeItem("consented_servers"); this._localStorage.removeItem("consented_servers");
this.clientId = null; this.clientId = null;
this.platform = null; this.platform = null;
this.homeservers = null; this.homeservers = null;
} }
get canClear() { get canClear() {
return !!this.clientId || !!this.platform || !!this.homeservers; return !!this.clientId || !!this.platform || !!this.homeservers;
} }
} }

View file

@ -18,27 +18,32 @@ import {TemplateView} from "./utils/TemplateView.js";
import {OpenLinkView} from "./open/OpenLinkView.js"; import {OpenLinkView} from "./open/OpenLinkView.js";
import {CreateLinkView} from "./create/CreateLinkView.js"; import {CreateLinkView} from "./create/CreateLinkView.js";
import {LoadServerPolicyView} from "./policy/LoadServerPolicyView.js"; import {LoadServerPolicyView} from "./policy/LoadServerPolicyView.js";
import {DisclaimerView} from "./disclaimer/DisclaimerView.js";
import {InvalidUrlView} from "./InvalidUrlView.js";
export class RootView extends TemplateView { export class RootView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({className: "RootView"}, [ return t.div({className: "RootView"}, [
t.mapView(vm => vm.openLinkViewModel, vm => vm ? new OpenLinkView(vm) : null), t.mapView(vm => vm.invalidUrlViewModel, invalidVM => invalidVM ? new InvalidUrlView(invalidVM) : null),
t.mapView(vm => vm.createLinkViewModel, vm => vm ? new CreateLinkView(vm) : null), t.mapView(vm => vm.showDisclaimer, disclaimer => disclaimer ? new DisclaimerView() : null),
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.mapView(vm => vm.loadServerPolicyViewModel, vm => vm ? new LoadServerPolicyView(vm) : null),
t.div({className: "footer"}, [ t.div({className: "footer"}, [
t.p(t.img({src: "images/matrix-logo.svg"})), 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.p(["This invite uses ", externalLink(t, "https://matrix.org", "Matrix"), ", an open network for secure, decentralized communication."]),
t.ul({className: "links"}, [ 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", "GitHub project")),
t.li(externalLink(t, "https://github.com/matrix-org/matrix.to/tree/main/src/clients", "Add your app")), t.li(externalLink(t, "https://github.com/matrix-org/matrix.to/tree/main/src/open/clients", "Add your app")),
t.li({className: {hidden: vm => !vm.hasPreferences}}, t.li({className: {hidden: vm => !vm.hasPreferences}},
t.button({className: "text", onClick: () => vm.clearPreferences()}, "Clear preferences")), t.button({className: "text", onClick: () => vm.clearPreferences()}, "Clear preferences")),
]) t.li(t.a({href: "#/disclaimer/"}, "Disclaimer")),
]) ])
]); ])
} ]);
}
} }
function externalLink(t, href, label) { function externalLink(t, href, label) {
return t.a({href, target: "_blank", rel: "noopener noreferrer"}, label); return t.a({href, target: "_blank", rel: "noopener noreferrer"}, label);
} }

View file

@ -20,54 +20,79 @@ import {OpenLinkViewModel} from "./open/OpenLinkViewModel.js";
import {createClients} from "./open/clients/index.js"; import {createClients} from "./open/clients/index.js";
import {CreateLinkViewModel} from "./create/CreateLinkViewModel.js"; import {CreateLinkViewModel} from "./create/CreateLinkViewModel.js";
import {LoadServerPolicyViewModel} from "./policy/LoadServerPolicyViewModel.js"; import {LoadServerPolicyViewModel} from "./policy/LoadServerPolicyViewModel.js";
import {InvalidUrlViewModel} from "./InvalidUrlViewModel.js";
import {Platform} from "./Platform.js"; import {Platform} from "./Platform.js";
export class RootViewModel extends ViewModel { export class RootViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
this.link = null; this.link = null;
this.openLinkViewModel = null; this.openLinkViewModel = null;
this.createLinkViewModel = null; this.createLinkViewModel = null;
this.loadServerPolicyViewModel = null; this.loadServerPolicyViewModel = null;
this.invalidUrlViewModel = null;
this.showDisclaimer = false;
this.preferences.on("canClear", () => { this.preferences.on("canClear", () => {
this.emitChange(); this.emitChange();
}); });
} }
_updateChildVMs(oldLink) { _updateChildVMs(newLink, oldLink) {
if (this.link) { this.link = newLink;
this.createLinkViewModel = null; if (!newLink) {
if (!oldLink || !oldLink.equals(this.link)) { this.openLinkViewModel = null;
this.openLinkViewModel = new OpenLinkViewModel(this.childOptions({ } else if (!oldLink || !oldLink.equals(newLink)) {
link: this.link, this.openLinkViewModel = new OpenLinkViewModel(this.childOptions({
clients: createClients(), link: newLink,
})); clients: createClients(),
} }));
} else { }
this.openLinkViewModel = null; }
this.createLinkViewModel = new CreateLinkViewModel(this.childOptions());
}
this.emitChange();
}
updateHash(hash) { _hideLinks() {
this.link = null;
this.openLinkViewModel = null;
this.createLinkViewModel = null;
}
updateHash(hash) {
// All view models except openLink are re-created anyway. Might as well
// clear them to avoid having to manually reset (n-1)/n view models in every case.
// That just doesn't scale well when we add new views.
const oldLink = this.link;
this.invalidUrlViewModel = null;
this.showDisclaimer = false;
this.loadServerPolicyViewModel = null;
this.createLinkViewModel = null;
let newLink;
if (hash.startsWith("#/policy/")) { if (hash.startsWith("#/policy/")) {
const server = hash.substr(9); const server = hash.slice(9);
this._updateChildVMs(null, oldLink);
this.loadServerPolicyViewModel = new LoadServerPolicyViewModel(this.childOptions({server})); this.loadServerPolicyViewModel = new LoadServerPolicyViewModel(this.childOptions({server}));
this.loadServerPolicyViewModel.load(); this.loadServerPolicyViewModel.load();
} else if (hash.startsWith("#/disclaimer/")) {
this._updateChildVMs(null, oldLink);
this.showDisclaimer = true;
} else if (hash === "" || hash === "#" || hash === "#/") {
this._updateChildVMs(null, oldLink);
this.createLinkViewModel = new CreateLinkViewModel(this.childOptions());
} else if (newLink = Link.parseFragment(hash)) {
this._updateChildVMs(newLink, oldLink);
} else { } else {
const oldLink = this.link; this._updateChildVMs(null, oldLink);
this.link = Link.parse(hash); this.invalidUrlViewModel = new InvalidUrlViewModel(this.childOptions({
this._updateChildVMs(oldLink); fragment: hash
}));
} }
} this.emitChange();
}
clearPreferences() { clearPreferences() {
this.preferences.clear(); this.preferences.clear();
this._updateChildVMs(); this._updateChildVMs();
} }
get hasPreferences() { get hasPreferences() {
return this.preferences.canClear; return this.preferences.canClear;
} }
} }

View file

@ -19,31 +19,31 @@ import {PreviewView} from "../preview/PreviewView.js";
import {copyButton} from "../utils/copy.js"; import {copyButton} from "../utils/copy.js";
export class CreateLinkView extends TemplateView { export class CreateLinkView extends TemplateView {
render(t, vm) { render(t, vm) {
const link = t.a({href: vm => vm.linkUrl}, vm => vm.linkUrl); const link = t.a({href: vm => vm.linkUrl}, vm => vm.linkUrl);
return t.div({className: "CreateLinkView card"}, [ return t.div({className: "CreateLinkView card"}, [
t.h1("Create shareable links to Matrix rooms, users or messages without being tied to any app"), t.h1("Create shareable links to Matrix rooms, users or messages without being tied to any app"),
t.form({action: "#", onSubmit: evt => this._onSubmit(evt)}, [ t.form({action: "#", onSubmit: evt => this._onSubmit(evt)}, [
t.div(t.input({ t.div(t.input({
className: "fullwidth large", className: "fullwidth large",
type: "text", type: "text",
name: "identifier", name: "identifier",
required: true, required: true,
placeholder: "#room:example.com, @user:example.com", placeholder: "#room:example.com, @user:example.com",
onChange: evt => this._onIdentifierChange(evt) onChange: evt => this._onIdentifierChange(evt)
})), })),
t.div(t.input({className: "primary fullwidth icon link", type: "submit", value: "Create link"})) t.div(t.input({className: "primary fullwidth icon link", type: "submit", value: "Create link"}))
]), ]),
]); ]);
} }
_onSubmit(evt) { _onSubmit(evt) {
evt.preventDefault(); evt.preventDefault();
const form = evt.target; const form = evt.target;
const {identifier} = form.elements; const {identifier} = form.elements;
this.value.createLink(identifier.value); this.value.createLink(identifier.value);
identifier.value = ""; identifier.value = "";
} }
_onIdentifierChange(evt) { _onIdentifierChange(evt) {
const inputField = evt.target; const inputField = evt.target;

View file

@ -19,18 +19,18 @@ import {PreviewViewModel} from "../preview/PreviewViewModel.js";
import {Link} from "../Link.js"; import {Link} from "../Link.js";
export class CreateLinkViewModel extends ViewModel { export class CreateLinkViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
this._link = null; this._link = null;
this.previewViewModel = null; this.previewViewModel = null;
} }
validateIdentifier(identifier) { validateIdentifier(identifier) {
return Link.validateIdentifier(identifier); return Link.validateIdentifier(identifier);
} }
async createLink(identifier) { async createLink(identifier) {
this._link = Link.parse(identifier); this._link = Link.parseIdentifier(identifier);
if (this._link) { if (this._link) {
this.openLink("#" + this._link.toFragment()); this.openLink("#" + this._link.toFragment());
} }

View file

@ -0,0 +1,33 @@
/*
Copyright 2021 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";
export class DisclaimerView extends TemplateView {
render(t) {
return t.div({ className: "DisclaimerView card" }, [
t.h1("Disclaimer"),
t.p(
'Matrix.to is a service provided by the Matrix.org Foundation ' +
'which allows you to easily create invites to Matrix rooms and accounts, ' +
'regardless of your Matrix homeserver. The service is provided "as is" without ' +
'warranty of any kind, either express, implied, statutory or otherwise. ' +
'The Matrix.org Foundation shall not be responsible or liable for the room ' +
'and account contents shared via this service.'
),
]);
}
}

View file

@ -21,18 +21,18 @@ import {Preferences} from "./Preferences.js";
import {guessApplicablePlatforms} from "./Platform.js"; import {guessApplicablePlatforms} from "./Platform.js";
export async function main(container) { export async function main(container) {
const vm = new RootViewModel({ const vm = new RootViewModel({
request: xhrRequest, request: xhrRequest,
openLink: url => location.href = url, openLink: url => location.href = url,
platforms: guessApplicablePlatforms(navigator.userAgent, navigator.platform), platforms: guessApplicablePlatforms(navigator.userAgent, navigator.platform),
preferences: new Preferences(window.localStorage), preferences: new Preferences(window.localStorage),
origin: location.origin, origin: location.origin,
}); });
vm.updateHash(location.hash); vm.updateHash(decodeURIComponent(location.hash));
window.__rootvm = vm; window.__rootvm = vm;
const view = new RootView(vm); const view = new RootView(vm);
container.appendChild(view.mount()); container.appendChild(view.mount());
window.addEventListener('hashchange', () => { window.addEventListener('hashchange', () => {
vm.updateHash(location.hash); vm.updateHash(decodeURIComponent(location.hash));
}); });
} }

View file

@ -18,52 +18,50 @@ import {TemplateView} from "../utils/TemplateView.js";
import {ClientView} from "./ClientView.js"; import {ClientView} from "./ClientView.js";
export class ClientListView extends TemplateView { export class ClientListView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.mapView(vm => vm.clientViewModel, () => { return t.mapView(vm => vm.clientViewModel, () => {
if (vm.clientViewModel) { if (vm.clientViewModel) {
return new ContinueWithClientView(vm); return new ContinueWithClientView(vm);
} else { } else {
return new AllClientsView(vm); return new AllClientsView(vm);
} }
}); });
} }
} }
class AllClientsView extends TemplateView { class AllClientsView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({className: "ClientListView"}, [ return t.div({className: "ClientListView"}, [
t.h2("Choose an app to continue"), t.h2("Choose an app to continue"),
t.mapView(vm => vm.clientList, () => { t.map(vm => vm.clientList, (clientList, t) => {
return new TemplateView(vm, t => { return t.div({className: "list"}, clientList.map(clientViewModel => {
return t.div({className: "list"}, vm.clientList.map(clientViewModel => { return t.view(new ClientView(clientViewModel));
return t.view(new ClientView(clientViewModel)); }));
})); }),
}); t.div(t.label([
}), t.input({
t.div(t.label([ type: "checkbox",
t.input({ checked: vm.showUnsupportedPlatforms,
type: "checkbox", onChange: evt => vm.showUnsupportedPlatforms = evt.target.checked,
checked: vm.showUnsupportedPlatforms, }),
onChange: evt => vm.showUnsupportedPlatforms = evt.target.checked, "Show apps not available on my platform"
}), ])),
"Show apps not available on my platform" t.div(t.label({className: "filterOption"}, [
])), t.input({
t.div(t.label({className: "filterOption"}, [ type: "checkbox",
t.input({ checked: vm.showExperimental,
type: "checkbox", onChange: evt => vm.showExperimental = evt.target.checked,
checked: vm.showExperimental, }),
onChange: evt => vm.showExperimental = evt.target.checked, "Show experimental apps"
}), ])),
"Show experimental apps" ]);
])), }
]);
}
} }
class ContinueWithClientView extends TemplateView { class ContinueWithClientView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({className: "ClientListView"}, [ return t.div({className: "ClientListView"}, [
t.div({className: "list"}, t.view(new ClientView(vm.clientViewModel))) t.div({className: "list"}, t.view(new ClientView(vm.clientViewModel)))
]); ]);
} }
} }

View file

@ -20,67 +20,70 @@ import {ClientViewModel} from "./ClientViewModel.js";
import {ViewModel} from "../utils/ViewModel.js"; import {ViewModel} from "../utils/ViewModel.js";
export class ClientListViewModel extends ViewModel { export class ClientListViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
const {clients, client, link} = options; const {clients, client, link} = options;
this._clients = clients; this._clients = clients;
this._link = link; this._link = link;
this.clientList = null; this.clientList = null;
this._showExperimental = false; this._showExperimental = false;
this._showUnsupportedPlatforms = false; this._showUnsupportedPlatforms = false;
this._filterClients(); this._filterClients();
this.clientViewModel = null; this.clientViewModel = null;
if (client) { if (client) {
this._pickClient(client); this._pickClient(client);
} }
} }
get showUnsupportedPlatforms() { get showUnsupportedPlatforms() {
return this._showUnsupportedPlatforms; return this._showUnsupportedPlatforms;
} }
get showExperimental() { get showExperimental() {
return this._showExperimental; return this._showExperimental;
} }
set showUnsupportedPlatforms(enabled) { set showUnsupportedPlatforms(enabled) {
this._showUnsupportedPlatforms = enabled; this._showUnsupportedPlatforms = enabled;
this._filterClients(); this._filterClients();
} }
set showExperimental(enabled) { set showExperimental(enabled) {
this._showExperimental = enabled; this._showExperimental = enabled;
this._filterClients(); this._filterClients();
} }
_filterClients() { _filterClients() {
this.clientList = this._clients.filter(client => { const clientVMs = this._clients.filter(client => {
const platformMaturities = this.platforms.map(p => client.getMaturity(p)); const platformMaturities = this.platforms.map(p => client.getMaturity(p));
const isStable = platformMaturities.includes(Maturity.Stable) || platformMaturities.includes(Maturity.Beta); const isStable = platformMaturities.includes(Maturity.Stable) || platformMaturities.includes(Maturity.Beta);
const isSupported = client.platforms.some(p => this.platforms.includes(p)); const isSupported = client.platforms.some(p => this.platforms.includes(p));
if (!this._showExperimental && !isStable) { if (!this._showExperimental && !isStable) {
return false; return false;
} }
if (!this._showUnsupportedPlatforms && !isSupported) { if (!this._showUnsupportedPlatforms && !isSupported) {
return false; return false;
} }
return true; return true;
}).map(client => new ClientViewModel(this.childOptions({ }).map(client => new ClientViewModel(this.childOptions({
client, client,
link: this._link, link: this._link,
pickClient: client => this._pickClient(client) pickClient: client => this._pickClient(client)
}))); })));
this.emitChange(); const preferredClientVMs = clientVMs.filter(c => c.hasPreferredWebInstance);
} const otherClientVMs = clientVMs.filter(c => !c.hasPreferredWebInstance);
this.clientList = preferredClientVMs.concat(otherClientVMs);
this.emitChange();
}
_pickClient(client) { _pickClient(client) {
this.clientViewModel = this.clientList.find(vm => vm.clientId === client.id); this.clientViewModel = this.clientList.find(vm => vm.clientId === client.id);
this.clientViewModel.pick(this); this.clientViewModel.pick(this);
this.emitChange(); this.emitChange();
} }
showAll() { showAll() {
this.clientViewModel = null; this.clientViewModel = null;
this.emitChange(); this.emitChange();
} }
} }

View file

@ -19,11 +19,11 @@ import {copy} from "../utils/copy.js";
import {text, tag} from "../utils/html.js"; import {text, tag} from "../utils/html.js";
function formatPlatforms(platforms) { function formatPlatforms(platforms) {
return platforms.reduce((str, p, i, all) => { return platforms.reduce((str, p, i, all) => {
const first = i === 0; const first = i === 0;
const last = i === all.length - 1; const last = i === all.length - 1;
return str + (first ? "" : last ? " & " : ", ") + p; return str + (first ? "" : last ? " & " : ", ") + p;
}, ""); }, "");
} }
function renderInstructions(parts) { function renderInstructions(parts) {
@ -38,50 +38,46 @@ function renderInstructions(parts) {
export class ClientView extends TemplateView { export class ClientView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({className: "ClientView"}, [ return t.div({className: {"ClientView": true, "isPreferred": vm => vm.hasPreferredWebInstance}}, [
t.div({className: "header"}, [ ... vm.hasPreferredWebInstance ? [t.div({className: "hostedBanner"}, vm.hostedByBannerLabel)] : [],
t.div({className: "description"}, [ t.div({className: "header"}, [
t.h3(vm.name), t.div({className: "description"}, [
t.p([vm.description, " ", t.a({ t.h3(vm.name),
t.p([vm.description, " ", t.a({
href: vm.homepage, href: vm.homepage,
target: "_blank", target: "_blank",
rel: "noopener noreferrer" rel: "noopener noreferrer"
}, "Learn more")]), }, "Learn more")]),
t.p({className: "platforms"}, formatPlatforms(vm.availableOnPlatformNames)), t.p({className: "platforms"}, formatPlatforms(vm.availableOnPlatformNames)),
]), ]),
t.img({className: "clientIcon", src: vm.iconUrl}) t.img({className: "clientIcon", src: vm.iconUrl})
]), ]),
t.mapView(vm => vm.stage, stage => { t.mapView(vm => vm.stage, stage => {
switch (stage) { switch (stage) {
case "open": return new OpenClientView(vm); case "open": return new OpenClientView(vm);
case "install": return new InstallClientView(vm); case "install": return new InstallClientView(vm);
} }
}), }),
]); ]);
} }
} }
class OpenClientView extends TemplateView { class OpenClientView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({className: "OpenClientView"}, [ return t.div({className: "OpenClientView"}, [
t.a({ ...vm.openActions.map(a => renderAction(t, a)),
className: "primary fullwidth",
href: vm.deepLink,
rel: "noopener noreferrer",
onClick: () => vm.deepLinkActivated(),
}, "Continue"),
showBack(t, vm), showBack(t, vm),
]); ]);
} }
} }
class InstallClientView extends TemplateView { class InstallClientView extends TemplateView {
render(t, vm) { render(t, vm) {
const children = []; const children = [];
const textInstructions = vm.textInstructions; const textInstructions = vm.textInstructions;
if (textInstructions) { if (textInstructions) {
const copyButton = t.button({ const copyButton = t.button({
className: "copy", className: "copy",
title: "Copy instructions", title: "Copy instructions",
@ -95,45 +91,25 @@ class InstallClientView extends TemplateView {
} }
} }
}); });
children.push(t.p({className: "instructions"}, renderInstructions(textInstructions).concat(copyButton))); children.push(t.p({className: "instructions"}, renderInstructions(textInstructions).concat(copyButton)));
} }
const actions = t.div({className: "actions"}, vm.actions.map(a => { const actions = t.div({className: "actions"}, vm.installActions.map(a => renderAction(t, a)));
let badgeUrl; children.push(actions);
switch (a.kind) {
case "play-store": badgeUrl = "images/google-play-us.svg"; break;
case "fdroid": badgeUrl = "images/fdroid-badge.png"; break;
case "apple-app-store": badgeUrl = "images/app-store-us-alt.svg"; break;
case "flathub": badgeUrl = "images/flathub-badge.svg"; break;
}
return t.a({
href: a.url,
className: {
fullwidth: !badgeUrl,
primary: a.primary && !badgeUrl,
secondary: !a.primary && !badgeUrl,
badge: !!badgeUrl,
},
rel: "noopener noreferrer",
["aria-label"]: a.label,
onClick: () => a.activated()
}, badgeUrl ? t.img({src: badgeUrl}) : a.label);
}));
children.push(actions);
if (vm.showDeepLinkInInstall) { if (vm.showDeepLinkInInstall) {
const deepLink = t.a({ const openItHere = t.a({
rel: "noopener noreferrer", rel: "noopener noreferrer",
href: vm.deepLink, href: vm.openActions[0].url,
onClick: () => vm.deepLinkActivated(), onClick: () => vm.openActions[0].activated(),
}, "open it here"); }, "open it here");
children.push(t.p([`If you already have ${vm.name} installed, you can `, deepLink, "."])) children.push(t.p([`If you already have ${vm.name} installed, you can `, openItHere, "."]))
} }
children.push(showBack(t, vm)); children.push(showBack(t, vm));
return t.div({className: "InstallClientView"}, children); return t.div({className: "InstallClientView"}, children);
} }
} }
function showBack(t, vm) { function showBack(t, vm) {
@ -142,3 +118,25 @@ function showBack(t, vm) {
t.button({className: "text", onClick: () => vm.back()}, "Change"), t.button({className: "text", onClick: () => vm.back()}, "Change"),
]); ]);
} }
function renderAction(t, a) {
let badgeUrl;
switch (a.kind) {
case "play-store": badgeUrl = "images/google-play-us.svg"; break;
case "fdroid": badgeUrl = "images/fdroid-badge.png"; break;
case "apple-app-store": badgeUrl = "images/app-store-us-alt.svg"; break;
case "flathub": badgeUrl = "images/flathub-badge.svg"; break;
}
return t.a({
href: a.url,
className: {
fullwidth: !badgeUrl,
primary: a.primary && !badgeUrl,
secondary: !a.primary && !badgeUrl,
badge: !!badgeUrl,
},
rel: "noopener noreferrer",
["aria-label"]: a.label,
onClick: () => a.activated()
}, badgeUrl ? t.img({src: badgeUrl}) : a.label);
}

View file

@ -27,70 +27,140 @@ function getMatchingPlatforms(client, supportedPlatforms) {
} }
export class ClientViewModel extends ViewModel { export class ClientViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
const {client, link, pickClient} = options; const {client, link, pickClient} = options;
this._client = client; this._client = client;
this._link = link; this._link = link;
this._pickClient = pickClient; this._pickClient = pickClient;
// to provide "choose other client" button after calling pick() // to provide "choose other client" button after calling pick()
this._clientListViewModel = null; this._clientListViewModel = null;
this._update();
}
const matchingPlatforms = getMatchingPlatforms(client, this.platforms); _update() {
const nativePlatform = matchingPlatforms.find(p => !isWebPlatform(p)); const matchingPlatforms = getMatchingPlatforms(this._client, this.platforms);
const webPlatform = matchingPlatforms.find(p => isWebPlatform(p)); this._webPlatform = matchingPlatforms.find(p => isWebPlatform(p));
this._nativePlatform = matchingPlatforms.find(p => !isWebPlatform(p));
const preferredPlatform = matchingPlatforms.find(p => p === this.preferences.platform);
this._proposedPlatform = preferredPlatform || this._nativePlatform || this._webPlatform;
this._proposedPlatform = this.preferences.platform || nativePlatform || webPlatform; this.openActions = this._createOpenActions();
this._nativePlatform = nativePlatform || this._proposedPlatform; this.installActions = this._createInstallActions();
this._clientCanIntercept = !!(this._nativePlatform && this._client.canInterceptMatrixToLinks(this._nativePlatform));
this._showOpen = this.openActions.length && !this._clientCanIntercept;
}
this.actions = this._createActions(client, link, nativePlatform, webPlatform); // these are only shown in the open stage
this._clientCanIntercept = !!(nativePlatform && client.canInterceptMatrixToLinks(nativePlatform)); _createOpenActions() {
this._showOpen = this.deepLink && !this._clientCanIntercept; const hasPreferredWebInstance = this.hasPreferredWebInstance;
} let deepLinkLabel = "Continue";
if (hasPreferredWebInstance) {
if (this._proposedPlatform === this._nativePlatform) {
deepLinkLabel = "Open in app";
} else {
deepLinkLabel = `Open on ${this._client.getPreferredWebInstance(this._link)}`;
}
}
const actions = [];
const proposedDeepLink = this._client.getDeepLink(this._proposedPlatform, this._link);
if (proposedDeepLink) {
actions.push({
label: deepLinkLabel,
url: proposedDeepLink,
primary: true,
activated: () => {
this._pickClient(this._client);
this.preferences.setClient(this._client.id, this._proposedPlatform);
// only show install screen if we tried to open a native deeplink
if (this._showOpen && this._proposedPlatform === this._nativePlatform) {
this._showOpen = false;
this.emitChange();
}
},
});
}
// show only if there is a preferred instance, and if we don't already link to it in the first button
if (hasPreferredWebInstance && this._webPlatform && this._proposedPlatform !== this._webPlatform) {
actions.push({
label: `Open on ${this._client.getPreferredWebInstance(this._link)}`,
url: this._client.getDeepLink(this._webPlatform, this._link),
kind: "open-in-web",
activated: () => {} // don't persist this choice as we don't persist the preferred web instance, it's in the url
});
}
return actions;
}
_createActions(client, link, nativePlatform, webPlatform) { // these are only shown in the install stage
let actions = []; _createInstallActions() {
if (nativePlatform) { let actions = [];
const nativeActions = (client.getInstallLinks(nativePlatform) || []).map(installLink => { if (this._nativePlatform) {
return { const nativeActions = (this._client.getInstallLinks(this._nativePlatform) || []).map(installLink => {
label: installLink.getDescription(nativePlatform), return {
url: installLink.createInstallURL(link), label: installLink.getDescription(this._nativePlatform),
kind: installLink.channelId, url: installLink.createInstallURL(this._link),
primary: true, kind: installLink.channelId,
activated: () => this.preferences.setClient(client.id, nativePlatform), primary: true,
}; activated: () => this.preferences.setClient(this._client.id, this._nativePlatform),
}); };
actions.push(...nativeActions); });
} actions.push(...nativeActions);
if (webPlatform) { }
const webDeepLink = client.getDeepLink(webPlatform, link); if (this._webPlatform) {
if (webDeepLink) { const webDeepLink = this._client.getDeepLink(this._webPlatform, this._link);
actions.push({ if (webDeepLink) {
label: `Continue in your browser`, const webLabel = this.hasPreferredWebInstance ?
url: webDeepLink, `Open on ${this._client.getPreferredWebInstance(this._link)}` :
kind: "open-in-web", `Continue in your browser`;
activated: () => this.preferences.setClient(client.id, webPlatform), actions.push({
}); label: webLabel,
} url: webDeepLink,
} kind: "open-in-web",
return actions; activated: () => {
} if (!this.hasPreferredWebInstance) {
this.preferences.setClient(this._client.id, this._webPlatform);
}
},
});
}
}
return actions;
}
get hasPreferredWebInstance() {
// also check there is a web platform that matches the platforms the user is on (mobile or desktop web)
return this._webPlatform && typeof this._client.getPreferredWebInstance(this._link) === "string";
}
get hostedByBannerLabel() {
const preferredWebInstance = this._client.getPreferredWebInstance(this._link);
if (this._webPlatform && preferredWebInstance) {
let label = preferredWebInstance;
const subDomainIdx = preferredWebInstance.lastIndexOf(".", preferredWebInstance.lastIndexOf("."));
if (subDomainIdx !== -1) {
label = preferredWebInstance.slice(preferredWebInstance.length - subDomainIdx + 1);
}
return `Hosted by ${label}`;
}
return;
}
get homepage() { get homepage() {
return this._client.homepage; return this._client.homepage;
} }
get identifier() { get identifier() {
return this._link.identifier; return this._link.identifier;
} }
get description() { get description() {
return this._client.description; return this._client.description;
} }
get clientId() { get clientId() {
return this._client.id; return this._client.id;
} }
get name() { get name() {
return this._client.name; return this._client.name;
@ -100,69 +170,56 @@ export class ClientViewModel extends ViewModel {
return this._client.icon; return this._client.icon;
} }
get stage() { get stage() {
return this._showOpen ? "open" : "install"; return this._showOpen ? "open" : "install";
} }
get textInstructions() { get textInstructions() {
let instructions = this._client.getLinkInstructions(this._proposedPlatform, this._link); let instructions = this._client.getLinkInstructions(this._proposedPlatform, this._link);
if (instructions && !Array.isArray(instructions)) { if (instructions && !Array.isArray(instructions)) {
instructions = [instructions]; instructions = [instructions];
} }
return instructions; return instructions;
} }
get copyString() { get copyString() {
return this._client.getCopyString(this._proposedPlatform, this._link); return this._client.getCopyString(this._proposedPlatform, this._link);
} }
get showDeepLinkInInstall() { get showDeepLinkInInstall() {
return this._clientCanIntercept && this.deepLink; // we can assume this._nativePlatform as this._clientCanIntercept already checks it
} return this._clientCanIntercept && !!this._client.getDeepLink(this._nativePlatform, this._link);
get availableOnPlatformNames() {
const platforms = this._client.platforms;
const textPlatforms = [];
const hasWebPlatform = platforms.some(p => isWebPlatform(p));
if (hasWebPlatform) {
textPlatforms.push("Web");
}
const desktopPlatforms = platforms.filter(p => isDesktopPlatform(p));
if (desktopPlatforms.length === 1) {
textPlatforms.push(desktopPlatforms[0]);
} else {
textPlatforms.push("Desktop");
}
if (platforms.includes(Platform.Android)) {
textPlatforms.push("Android");
}
if (platforms.includes(Platform.iOS)) {
textPlatforms.push("iOS");
}
return textPlatforms;
}
get deepLink() {
const platform = this.showBack ? this._proposedPlatform : this._nativePlatform;
return this._client.getDeepLink(platform, this._link);
} }
deepLinkActivated() { get availableOnPlatformNames() {
this._pickClient(this._client); const platforms = this._client.platforms;
this.preferences.setClient(this._client.id, this._proposedPlatform); const textPlatforms = [];
if (this._showOpen) { const hasWebPlatform = platforms.some(p => isWebPlatform(p));
this._showOpen = false; if (hasWebPlatform) {
this.emitChange(); textPlatforms.push("Web");
} }
} const desktopPlatforms = platforms.filter(p => isDesktopPlatform(p));
if (desktopPlatforms.length === 1) {
textPlatforms.push(desktopPlatforms[0]);
} else {
textPlatforms.push("Desktop");
}
if (platforms.includes(Platform.Android)) {
textPlatforms.push("Android");
}
if (platforms.includes(Platform.iOS)) {
textPlatforms.push("iOS");
}
return textPlatforms;
}
pick(clientListViewModel) { pick(clientListViewModel) {
this._clientListViewModel = clientListViewModel; this._clientListViewModel = clientListViewModel;
this.emitChange(); this.emitChange();
} }
// whether or not we are only showing this client (in open or install stage)
get showBack() { get showBack() {
// if we're not only showing this client, don't show back (see pick())
return !!this._clientListViewModel; return !!this._clientListViewModel;
} }
@ -170,6 +227,11 @@ export class ClientViewModel extends ViewModel {
if (this._clientListViewModel) { if (this._clientListViewModel) {
const vm = this._clientListViewModel; const vm = this._clientListViewModel;
this._clientListViewModel = null; this._clientListViewModel = null;
// clear the client preference so we default back to to native link if any
// in the list with all clients, and also if we refresh, we get the list with
// all clients rather than having our "change client" click reverted.
this.preferences.setClient(undefined, undefined);
this._update();
this.emitChange(); this.emitChange();
vm.showAll(); vm.showAll();
} }

View file

@ -20,14 +20,14 @@ import {PreviewView} from "../preview/PreviewView.js";
import {ServerConsentView} from "./ServerConsentView.js"; import {ServerConsentView} from "./ServerConsentView.js";
export class OpenLinkView extends TemplateView { export class OpenLinkView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({className: "OpenLinkView card"}, [ return t.div({className: "OpenLinkView card"}, [
t.mapView(vm => vm.previewViewModel, previewVM => previewVM ? t.mapView(vm => vm.previewViewModel, previewVM => previewVM ?
new ShowLinkView(vm) : new ShowLinkView(vm) :
new ServerConsentView(vm.serverConsentViewModel) new ServerConsentView(vm.serverConsentViewModel)
), ),
]); ]);
} }
} }
class ShowLinkView extends TemplateView { class ShowLinkView extends TemplateView {

View file

@ -23,21 +23,21 @@ import {getLabelForLinkKind} from "../Link.js";
import {orderedUnique} from "../utils/unique.js"; import {orderedUnique} from "../utils/unique.js";
export class OpenLinkViewModel extends ViewModel { export class OpenLinkViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
const {clients, link} = options; const {clients, link} = options;
this._link = link; this._link = link;
this._clients = clients; this._clients = clients;
this.serverConsentViewModel = null; this.serverConsentViewModel = null;
this.previewViewModel = null; this.previewViewModel = null;
this.clientsViewModel = null; this.clientsViewModel = null;
this.previewLoading = false; this.previewLoading = false;
if (this.preferences.homeservers === null) { if (this.preferences.homeservers === null) {
this._showServerConsent(); this._showServerConsent();
} else { } else {
this._showLink(); this._showLink();
} }
} }
_showServerConsent() { _showServerConsent() {
let servers = []; let servers = [];
@ -67,24 +67,24 @@ export class OpenLinkViewModel extends ViewModel {
link: this._link, link: this._link,
consentedServers: this.preferences.homeservers consentedServers: this.preferences.homeservers
})); }));
this.previewLoading = true; this.previewLoading = true;
this.emitChange(); this.emitChange();
await this.previewViewModel.load(); await this.previewViewModel.load();
this.previewLoading = false; this.previewLoading = false;
this.emitChange(); this.emitChange();
} }
get previewDomain() { get previewDomain() {
return this.previewViewModel?.domain; return this.previewViewModel?.domain;
} }
get previewFailed() { get previewFailed() {
return this.previewViewModel?.failed; return this.previewViewModel?.failed;
} }
get showClientsLabel() { get showClientsLabel() {
return getLabelForLinkKind(this._link.kind); return getLabelForLinkKind(this._link.kind);
} }
changeServer() { changeServer() {
this.previewViewModel = null; this.previewViewModel = null;

View file

@ -27,7 +27,7 @@ export class ServerConsentView extends TemplateView {
className: "text", className: "text",
onClick: () => vm.continueWithoutConsent(this._askEveryTimeChecked) onClick: () => vm.continueWithoutConsent(this._askEveryTimeChecked)
}, "continue without a preview"); }, "continue without a preview");
return t.div({className: "ServerConsentView"}, [ return t.div({className: "ServerConsentView"}, [
t.p([ t.p([
"Preview this link using the ", "Preview this link using the ",
t.strong(vm => vm.selectedServer || "…"), t.strong(vm => vm.selectedServer || "…"),
@ -56,7 +56,7 @@ export class ServerConsentView extends TemplateView {
]) ])
]) ])
]); ]);
} }
_onSubmit(evt) { _onSubmit(evt) {
evt.preventDefault(); evt.preventDefault();

View file

@ -22,13 +22,13 @@ import {getLabelForLinkKind} from "../Link.js";
import {orderedUnique} from "../utils/unique.js"; import {orderedUnique} from "../utils/unique.js";
export class ServerConsentViewModel extends ViewModel { export class ServerConsentViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
this.servers = options.servers; this.servers = options.servers;
this.done = options.done; this.done = options.done;
this.selectedServer = this.servers[0]; this.selectedServer = this.servers[0];
this.showSelectServer = false; this.showSelectServer = false;
} }
setShowServers() { setShowServers() {
this.showSelectServer = true; this.showSelectServer = true;

84
src/open/clients/Cinny.js Normal file
View file

@ -0,0 +1,84 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2022 3nt3 <gott@3nt3.de>
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 { Maturity, Platform, LinkKind, FlathubLink, style } from "../types.js";
export class Cinny {
get id() {
return "cinny";
}
get name() {
return "Cinny";
}
get icon() {
return "images/client-icons/cinny.svg";
}
get author() {
return "Copyright (c) 2021-present Ajay Bura (ajbura) and contributors";
}
get homepage() {
return "https://cinny.in";
}
get platforms() {
return [
Platform.DesktopWeb,
Platform.Linux,
Platform.macOS,
Platform.Windows,
];
}
get description() {
return "A Matrix client focusing primarily on simple, elegant and secure interface. The main goal is to have an instant messaging application that is easy on people and has a modern touch.";
}
getMaturity(platform) {
return Maturity.Stable;
}
getDeepLink(platform, link) {
let fragmentPath;
switch (link.kind) {
case LinkKind.User:
fragmentPath = `direct/create?userId=${encodeURIComponent(link.identifier)}`;
break;
case LinkKind.Room:
fragmentPath = `home/${encodeURIComponent(link.identifier)}`;
break;
case LinkKind.Event:
fragmentPath = `home/${encodeURIComponent(link.identifier)}/${encodeURIComponent(link.eventId)}`;
break;
}
if ((link.kind === LinkKind.Event || link.kind === LinkKind.Room) && link.servers.length > 0) {
fragmentPath += `?via=${link.servers.map(server => encodeURIComponent(server)).join(',')}`;
}
return `https://app.cinny.in/${fragmentPath}`
}
canInterceptMatrixToLinks(platform) {
return false;
}
getLinkInstructions(platform, link) {}
getCopyString(platform, link) {}
getInstallLinks(platform) {}
getPreferredWebInstance(link) {}
}

View file

@ -15,66 +15,100 @@ limitations under the License.
*/ */
import {Maturity, Platform, LinkKind, import {Maturity, Platform, LinkKind,
FDroidLink, AppleStoreLink, PlayStoreLink, WebsiteLink} from "../types.js"; FDroidLink, AppleStoreLink, PlayStoreLink, WebsiteLink} from "../types.js";
const trustedWebInstances = [
"app.element.io", // first one is the default one
"develop.element.io",
"chat.fedoraproject.org",
"chat.fosdem.org",
"chat.mozilla.org",
"webchat.kde.org",
"app.gitter.im",
];
/** /**
* Information on how to deep link to a given matrix client. * Information on how to deep link to a given matrix client.
*/ */
export class Element { export class Element {
get id() { return "element.io"; } get id() { return "element.io"; }
get platforms() { get platforms() {
return [ return [
Platform.Android, Platform.iOS, Platform.Android, Platform.iOS,
Platform.Windows, Platform.macOS, Platform.Linux, Platform.Windows, Platform.macOS, Platform.Linux,
Platform.DesktopWeb Platform.DesktopWeb
]; ];
} }
get icon() { return "images/client-icons/element.svg"; } get icon() { return "images/client-icons/element.svg"; }
get appleAssociatedAppId() { return "7J4U792NQT.im.vector.app"; } get appleAssociatedAppId() {
get name() {return "Element"; } return [
get description() { return 'Fully-featured Matrix client, used by millions.'; } "7J4U792NQT.im.vector.app",
get homepage() { return "https://element.io"; } "7J4U792NQT.io.element.elementx",
get author() { return "Element"; } "7J4U792NQT.io.element.elementx.nightly",
getMaturity(platform) { return Maturity.Stable; } "7J4U792NQT.io.element.elementx.pr"
];
}
get name() {return "Element"; }
get description() { return 'Fully-featured Matrix client, used by millions.'; }
get homepage() { return "https://element.io"; }
get author() { return "Element"; }
getMaturity(platform) { return Maturity.Stable; }
getDeepLink(platform, link) { getDeepLink(platform, link) {
let fragmentPath; let fragmentPath;
switch (link.kind) { switch (link.kind) {
case LinkKind.User: case LinkKind.User:
fragmentPath = `user/${link.identifier}`; fragmentPath = `user/${encodeURIComponent(link.identifier)}`;
break; break;
case LinkKind.Room: case LinkKind.Room:
fragmentPath = `room/${link.identifier}`; fragmentPath = `room/${encodeURIComponent(link.identifier)}`;
break; break;
case LinkKind.Group: case LinkKind.Group:
fragmentPath = `group/${link.identifier}`; fragmentPath = `group/${encodeURIComponent(link.identifier)}`;
break; break;
case LinkKind.Event: case LinkKind.Event:
fragmentPath = `room/${link.identifier}/${link.eventId}`; fragmentPath = `room/${encodeURIComponent(link.identifier)}/${encodeURIComponent(link.eventId)}`;
break; break;
} }
if (platform === Platform.DesktopWeb || platform === Platform.MobileWeb || platform === Platform.iOS) {
return `https://app.element.io/#/${fragmentPath}`; if ((link.kind === LinkKind.Event || link.kind === LinkKind.Room) && link.servers.length > 0) {
} else if (platform === Platform.Linux || platform === Platform.Windows || platform === Platform.macOS) { fragmentPath += '?' + link.servers.map(server => `via=${encodeURIComponent(server)}`).join('&');
return `element://vector/webapp/#/${fragmentPath}`; }
} else {
const isWebPlatform = platform === Platform.DesktopWeb || platform === Platform.MobileWeb;
if (isWebPlatform || platform === Platform.iOS) {
let instanceHost = trustedWebInstances[0];
// we use app.element.io which iOS will intercept, but it likely won't intercept any other trusted instances
// so only use a preferred web instance for true web links.
if (isWebPlatform && trustedWebInstances.includes(link.webInstances[this.id])) {
instanceHost = link.webInstances[this.id];
}
return `https://${instanceHost}/#/${fragmentPath}`;
} else if (platform === Platform.Linux || platform === Platform.Windows || platform === Platform.macOS) {
return `element://vector/webapp/#/${fragmentPath}`;
} else {
return `element://${fragmentPath}`; return `element://${fragmentPath}`;
} }
} }
getLinkInstructions(platform, link) {} getLinkInstructions(platform, link) {}
getCopyString(platform, link) {} getCopyString(platform, link) {}
getInstallLinks(platform) { getInstallLinks(platform) {
switch (platform) { switch (platform) {
case Platform.iOS: return [new AppleStoreLink('vector', 'id1083446067')]; case Platform.iOS: return [new AppleStoreLink('vector', 'id1083446067')];
case Platform.Android: return [new PlayStoreLink('im.vector.app'), new FDroidLink('im.vector.app')]; case Platform.Android: return [new PlayStoreLink('im.vector.app'), new FDroidLink('im.vector.app')];
default: return [new WebsiteLink("https://element.io/get-started")]; default: return [new WebsiteLink("https://element.io/download")];
} }
} }
canInterceptMatrixToLinks(platform) { canInterceptMatrixToLinks(platform) {
return platform === Platform.iOS || platform === Platform.Android; return platform === Platform.Android;
} }
getPreferredWebInstance(link) {
const idx = trustedWebInstances.indexOf(link.webInstances[this.id])
return idx === -1 ? undefined : trustedWebInstances[idx];
}
} }

View file

@ -0,0 +1,94 @@
/*
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 { Maturity, Platform, LinkKind, FlathubLink, AppleStoreLink, PlayStoreLink, FDroidLink, WebsiteLink } from "../types.js";
/**
* Information on how to deep link to a given matrix client.
*/
export class Fluffychat {
get id() { return "im.fluffychat"; }
get name() { return "FluffyChat"; }
get icon() { return "images/client-icons/fluffychat.svg"; }
get author() { return "Krille Fear"; }
get homepage() { return "https://fluffychat.im"; }
get platforms() {
return [
Platform.Android, Platform.iOS,
Platform.Windows, Platform.macOS, Platform.Linux,
Platform.DesktopWeb,
];
}
get description() { return "Chat with your friends using the cutest messenger in the Matrix network"; }
getMaturity(platform) {
switch (platform) {
case Platform.Android: return Maturity.Stable;
case Platform.iOS: return Maturity.Stable;
case Platform.DesktopWeb: return Maturity.Stable;
case Platform.Linux: return Maturity.Stable;
case Platform.macOS: return Maturity.Beta;
case Platform.Windows: return Maturity.Beta;
}
}
getInstallLinks(platform) {
switch (platform) {
case Platform.iOS: return [new AppleStoreLink("fluffychat", "id1551469600")];
case Platform.Android: return [
new PlayStoreLink("chat.fluffy.fluffychat"),
new FDroidLink('chat.fluffy.fluffychat'),
];
case Platform.Linux: return [
new FlathubLink("im.fluffychat.Fluffychat"),
new WebsiteLink("https://fluffychat.im"),
];
default: return [new WebsiteLink("https://fluffychat.im")];
}
}
getLinkInstructions(platform, link) {
if (link.kind === LinkKind.User) {
switch (platform) {
case Platform.Android: return;
case Platform.DesktopWeb: return "Open the web app at https://fluffychat.im/web/ and log in to your account. Click on '+' and paste the username.";
default: return "Open the app and click on '+' and paste the username.";
}
}
if (link.kind === LinkKind.Room) {
switch (platform) {
case Platform.Android: return;
case Platform.DesktopWeb: return "Open the web app at https://fluffychat.im/web/ and log in to your account. Click on 'Discover' and paste the identifier.";
default: return "Open the app on your device. Click on 'Discover' and paste the identifier.";
}
}
}
getCopyString(platform, link) {
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) {
return link.identifier;
}
}
getDeepLink(platform, link) {
switch (platform) {
case Platform.Android: return `im.fluffychat://chat/${link.identifier}`;
case Platform.iOS: return `im.fluffychat://chat/${link.identifier}`;
default: break;
}
}
canInterceptMatrixToLinks(platform) {
return platform === Platform.Android;
}
getPreferredWebInstance(link) {}
}

View file

@ -20,22 +20,50 @@ import {Maturity, Platform, LinkKind, FlathubLink} from "../types.js";
* Information on how to deep link to a given matrix client. * Information on how to deep link to a given matrix client.
*/ */
export class Fractal { export class Fractal {
get id() { return "fractal"; } get id() { return "fractal"; }
get name() { return "Fractal"; } get name() { return "Fractal"; }
get icon() { return "images/client-icons/fractal.png"; } get icon() { return "images/client-icons/fractal.svg"; }
get author() { return "Daniel Garcia Moreno"; } get author() { return "Daniel Garcia Moreno"; }
get homepage() { return "https://gitlab.gnome.org/GNOME/fractal"; } get homepage() { return "https://gitlab.gnome.org/World/fractal"; }
get platforms() { return [Platform.Linux]; } get platforms() { return [Platform.Linux]; }
get description() { return 'Fractal is a Matrix Client written in Rust.'; } get description() { return 'GNOME client, suitable for desktop and mobile. Written in Rust.'; }
getMaturity(platform) { return Maturity.Beta; } getMaturity(platform) { return Maturity.Beta; }
getDeepLink(platform, link) {}
canInterceptMatrixToLinks(platform) { return false; }
getLinkInstructions(platform, link) { getDeepLink(platform, link) {
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) { if (platform === Platform.Linux) {
return "Click the '+' button in the top right and paste the identifier"; let identifier = encodeURIComponent(link.identifier.substring(1));
let isRoomid = link.identifier.substring(0, 1) === '!';
let fragmentPath;
switch (link.kind) {
case LinkKind.User:
fragmentPath = `u/${identifier}?action=chat`;
break;
case LinkKind.Room:
case LinkKind.Event:
if (isRoomid)
fragmentPath = `roomid/${identifier}`;
else
fragmentPath = `r/${identifier}`;
if (link.kind === LinkKind.Event)
fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`;
fragmentPath += '?action=join';
fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join('');
break;
case LinkKind.Group:
return;
}
return `matrix:${fragmentPath}`;
} }
} }
canInterceptMatrixToLinks(platform) { return false; }
getLinkInstructions(platform, link) {
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) {
return "Click the menu button above the list of rooms, select the Join Room entry, and paste the identifier";
}
}
getCopyString(platform, link) { getCopyString(platform, link) {
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) { if (link.kind === LinkKind.User || link.kind === LinkKind.Room) {
@ -43,9 +71,11 @@ export class Fractal {
} }
} }
getInstallLinks(platform) { getInstallLinks(platform) {
if (platform === Platform.Linux) { if (platform === Platform.Linux) {
return [new FlathubLink("org.gnome.Fractal")]; return [new FlathubLink("org.gnome.Fractal")];
} }
} }
getPreferredWebInstance(link) {}
} }

View file

@ -0,0 +1,79 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2021 Carl Schwan <carl@carlschwan.eu>
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 {Maturity, Platform, LinkKind, FlathubLink, style} from "../types.js";
export class NeoChat {
get id() { return "neochat"; }
get name() { return "NeoChat"; }
get icon() { return "images/client-icons/org.kde.neochat.svg"; }
get author() { return "Tobias Fella and Carl Schwan"; }
get homepage() { return "https://apps.kde.org/neochat/"; }
get platforms() { return [Platform.Linux]; }
get description() { return 'NeoChat is a convergent, cross-platform Matrix client.'; }
getMaturity(platform) { return Maturity.Beta; }
getDeepLink(platform, link) {
if (platform === Platform.Linux || platform === Platform.Windows) {
let identifier = encodeURIComponent(link.identifier.substring(1));
let isRoomid = link.identifier.substring(0, 1) === '!';
let fragmentPath;
switch (link.kind) {
case LinkKind.User:
fragmentPath = `u/${identifier}?action=chat`;
break;
case LinkKind.Room:
case LinkKind.Event:
if (isRoomid)
fragmentPath = `roomid/${identifier}`;
else
fragmentPath = `r/${identifier}`;
if (link.kind === LinkKind.Event)
fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`;
fragmentPath += '?action=join';
fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join('');
break;
case LinkKind.Group:
return;
}
return `matrix:${fragmentPath}`;
}
}
canInterceptMatrixToLinks(platform) { return false; }
getLinkInstructions(platform, link) {
switch (link.kind) {
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)];
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)];
}
}
getCopyString(platform, link) {
switch (link.kind) {
case LinkKind.User: return `/invite ${link.identifier}`;
case LinkKind.Room: return `/join ${link.identifier}`;
}
}
getInstallLinks(platform) {
if (platform === Platform.Linux) {
return [new FlathubLink("org.kde.neochat")];
}
}
getPreferredWebInstance(link) {}
}

View file

@ -14,29 +14,55 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {Maturity, Platform, LinkKind, FlathubLink, style} from "../types.js"; import {Maturity, Platform, LinkKind, FlathubLink, WebsiteLink, style} from "../types.js";
/** /**
* Information on how to deep link to a given matrix client. * Information on how to deep link to a given matrix client.
*/ */
export class Nheko { export class Nheko {
get id() { return "nheko"; } get id() { return "nheko"; }
get name() { return "Nheko"; } get name() { return "Nheko"; }
get icon() { return "images/client-icons/nheko.svg"; } get icon() { return "images/client-icons/nheko.svg"; }
get author() { return "mujx, red_sky, deepbluev7, Konstantinos Sideris"; } get author() { return "mujx, red_sky, deepbluev7, Konstantinos Sideris"; }
get homepage() { return "https://github.com/Nheko-Reborn/nheko"; } get homepage() { return "https://github.com/Nheko-Reborn/nheko"; }
get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; } get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; }
get description() { return 'A native desktop app for Matrix that feels more like a mainstream chat app.'; } get description() { return 'A native desktop app for Matrix that feels more like a mainstream chat app.'; }
getMaturity(platform) { return Maturity.Beta; } getMaturity(platform) { return Maturity.Beta; }
getDeepLink(platform, link) {} getDeepLink(platform, link) {
canInterceptMatrixToLinks(platform) { return false; } if (platform === Platform.Linux || platform === Platform.Windows) {
let identifier = encodeURIComponent(link.identifier.substring(1));
let isRoomid = link.identifier.substring(0, 1) === '!';
let fragmentPath;
switch (link.kind) {
case LinkKind.User:
fragmentPath = `u/${identifier}?action=chat`;
break;
case LinkKind.Room:
case LinkKind.Event:
if (isRoomid)
fragmentPath = `roomid/${identifier}`;
else
fragmentPath = `r/${identifier}`;
getLinkInstructions(platform, link) { if (link.kind === LinkKind.Event)
switch (link.kind) { fragmentPath += `/e/${encodeURIComponent(link.eventId.substring(1))}`;
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)]; fragmentPath += '?action=join';
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)]; fragmentPath += link.servers.map(server => `&via=${encodeURIComponent(server)}`).join('');
} break;
} case LinkKind.Group:
return;
}
return `matrix:${fragmentPath}`;
}
}
canInterceptMatrixToLinks(platform) { return false; }
getLinkInstructions(platform, link) {
switch (link.kind) {
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)];
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)];
}
}
getCopyString(platform, link) { getCopyString(platform, link) {
switch (link.kind) { switch (link.kind) {
@ -45,9 +71,15 @@ export class Nheko {
} }
} }
getInstallLinks(platform) { getInstallLinks(platform) {
if (platform === Platform.Linux) { switch (platform) {
return [new FlathubLink("io.github.NhekoReborn.Nheko")]; case Platform.Linux: return [
new FlathubLink("io.github.NhekoReborn.Nheko"),
new WebsiteLink("https://github.com/Nheko-Reborn/nheko/releases/latest"),
];
default: return [new WebsiteLink("https://github.com/Nheko-Reborn/nheko/releases/latest")];
} }
} }
getPreferredWebInstance(link) {}
} }

View file

@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {Maturity, Platform, LinkKind, FlathubLink, style} from "../types.js"; import {Maturity, Platform, LinkKind, FlathubLink, WebsiteLink, style} from "../types.js";
export class Quaternion { export class Quaternion {
get id() { return "quaternion"; } get id() { return "quaternion"; }
get name() { return "Quaternion"; } get name() { return "Quaternion"; }
get icon() { return "images/client-icons/quaternion.svg"; } get icon() { return "images/client-icons/quaternion.svg"; }
get author() { return "Felix Rohrbach"; } get author() { return "The Quotient project"; }
get homepage() { return "https://github.com/Fxrh/Quaternion"; } get homepage() { return "https://github.com/quotient-im/Quaternion"; }
get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; } get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; }
get description() { return 'Qt5 and C++ cross-platform desktop Matrix client.'; } get description() { return 'Qt5 and C++ cross-platform desktop Matrix client.'; }
getMaturity(platform) { return Maturity.Beta; } getMaturity(platform) { return Maturity.Beta; }
@ -43,8 +43,14 @@ export class Quaternion {
} }
getInstallLinks(platform) { getInstallLinks(platform) {
if (platform === Platform.Linux) { switch (platform) {
return [new FlathubLink("com.github.quaternion")]; case Platform.Linux: return [
new FlathubLink("com.github.quaternion"),
new WebsiteLink("https://github.com/quotient-im/Quaternion/releases/latest"),
];
default: return [new WebsiteLink("https://github.com/quotient-im/Quaternion/releases/latest")];
} }
} }
getPreferredWebInstance(link) {}
} }

View file

@ -0,0 +1,112 @@
/*
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 {
Maturity, Platform, LinkKind,
FDroidLink, FlathubLink, PlayStoreLink, WebsiteLink
} from "../types.js";
const trustedWebInstances = [
"app.schildi.chat", // first one is the default one
"test.schildi.chat",
];
/**
* Information on how to deep link to a given matrix client.
*/
export class SchildiChat {
get id() { return "schildi.chat"; }
get platforms() {
return [
Platform.Android,
Platform.Windows, Platform.macOS, Platform.Linux,
Platform.DesktopWeb
];
}
get icon() { return "images/client-icons/schildichat.svg"; }
get name() { return "SchildiChat"; }
get description() { return 'Feature-rich messenger for Matrix based on Element with some extras and tweaks.'; }
get homepage() { return "https://schildi.chat"; }
get author() { return "SchildiChat team"; }
getMaturity(platform) { return Maturity.Stable; }
getDeepLink(platform, link) {
let fragmentPath;
switch (link.kind) {
case LinkKind.User:
fragmentPath = `user/${encodeURIComponent(link.identifier)}`;
break;
case LinkKind.Room:
fragmentPath = `room/${encodeURIComponent(link.identifier)}`;
break;
case LinkKind.Group:
fragmentPath = `group/${encodeURIComponent(link.identifier)}`;
break;
case LinkKind.Event:
fragmentPath = `room/${encodeURIComponent(link.identifier)}/${encodeURIComponent(link.eventId)}`;
break;
}
if ((link.kind === LinkKind.Event || link.kind === LinkKind.Room) && link.servers.length > 0) {
fragmentPath += '?' + link.servers.map(server => `via=${encodeURIComponent(server)}`).join('&');
}
const isWebPlatform = platform === Platform.DesktopWeb || platform === Platform.MobileWeb;
if (isWebPlatform) {
let instanceHost = trustedWebInstances[0];
if (isWebPlatform && trustedWebInstances.includes(link.webInstances[this.id])) {
instanceHost = link.webInstances[this.id];
}
return `https://${instanceHost}/#/${fragmentPath}`;
} else if (platform === Platform.Linux || platform === Platform.Windows || platform === Platform.macOS) {
return `schildichat://vector/webapp/#/${fragmentPath}`;
} else {
return `schildichat://${fragmentPath}`;
}
}
getLinkInstructions(platform, link) { }
getCopyString(platform, link) { }
getInstallLinks(platform) {
switch (platform) {
case Platform.Linux:
return [
new FlathubLink("chat.schildi.desktop"),
new WebsiteLink("https://schildi.chat/desktop/"),
]
case Platform.Windows || Platform.macOS:
return [new WebsiteLink("https://schildi.chat/desktop/")];
case Platform.Android:
return [
new PlayStoreLink('de.spiritcroc.riotx'),
new FDroidLink('de.spiritcroc.riotx'),
new WebsiteLink("https://schildi.chat/android/"),
];
default: return [new WebsiteLink("https://schildi.chat")];
}
}
canInterceptMatrixToLinks(platform) {
return platform === Platform.Android;
}
getPreferredWebInstance(link) {
const idx = trustedWebInstances.indexOf(link.webInstances[this.id])
return idx === -1 ? undefined : trustedWebInstances[idx];
}
}

View file

@ -0,0 +1,91 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2022 0x1a8510f2 <admin@0x1a8510f2.space>
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 { Maturity, Platform, LinkKind, FlathubLink, AppleStoreLink, PlayStoreLink, FDroidLink, WebsiteLink } from "../types.js";
export class Syphon {
get id() { return "org.syphon.syphon"; }
get name() { return "Syphon"; }
get icon() { return "images/client-icons/syphon.svg"; }
get author() { return "Taylor Ereio"; }
get homepage() { return "https://syphon.org"; }
get platforms() {
return [
Platform.Android,
Platform.iOS,
Platform.Linux,
Platform.Windows,
Platform.macOS,
//Platform.DesktopWeb, // Supported by flutter but no builds yet
];
}
get description() {
return "chat with your privacy and freedom intact";
}
getMaturity(platform) {
return Maturity.Alpha;
}
getInstallLinks(platform) {
switch (platform) {
case Platform.Android: return [
new PlayStoreLink("org.tether.tether"),
new FDroidLink("org.tether.tether"),
];
case Platform.iOS: return [
new AppleStoreLink("syphon", "id1496285352")
];
case Platform.Linux: return [
new FlathubLink("org.syphon.Syphon"),
new WebsiteLink("https://syphon.org"),
];
default: return [new WebsiteLink("https://syphon.org")];
}
}
getLinkInstructions(platform, link) {
if (link.kind === LinkKind.User) {
return "Open the app, click on the direct message button (inside the floating button \
at the bottom), then paste the identifier.";
}
if (link.kind === LinkKind.Room) {
return "Open the app, click on the search public rooms button (inside the floating button \
at the bottom), then paste the identifier.";
}
}
getCopyString(platform, link) {
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) {
return link.identifier;
}
}
getDeepLink(platform, link) {
/*switch (platform) {
case Platform.Android: return `org.tether.tether://chat/${link.identifier}`;
case Platform.iOS: return `org.tether.tether://chat/${link.identifier}`;
default: break;
}*/
}
canInterceptMatrixToLinks(platform) {
return platform === Platform.Android;
}
getPreferredWebInstance(link) {}
}

View file

@ -47,4 +47,6 @@ export class Tensor {
return [new FDroidLink("io.davidar.tensor")]; return [new FDroidLink("io.davidar.tensor")];
} }
} }
getPreferredWebInstance(link) {}
} }

View file

@ -0,0 +1,70 @@
/*
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 { Maturity, Platform, LinkKind, FlathubLink, WebsiteLink, style} from "../types.js";
/**
* Information on how to deep link to a given matrix client.
*/
export class Thunderbird {
get id() { return "thunderbird"; }
get name() { return "Thunderbird"; }
get icon() { return "images/client-icons/thunderbird.svg"; }
get author() { return "MZLA Technologies Corporation"; }
get homepage() { return "https://www.thunderbird.net"; }
get platforms() {
return [
Platform.Windows, Platform.macOS, Platform.Linux,
];
}
get description() { return "Thunderbird is a free open-source email, calendar & chat app."; }
getMaturity(platform) {
return Maturity.Beta;
}
getInstallLinks(platform) {
const links = [];
if (platform === Platform.Linux) {
links.push(new FlathubLink("org.mozilla.Thunderbird"));
}
links.push(new WebsiteLink(this.homepage));
return links;
}
getLinkInstructions(platform, link) {
if (link.kind === LinkKind.User) {
return "Open the Chat tab, click on 'Add Contact' and paste the username.";
}
if (link.kind === LinkKind.Room) {
return [
"Open the Chat tab, click on 'Join Chat' and paste the identifier or type ",
style.code(`/join ${link.identifier}`),
" in an existing Matrix conversation."
];
}
}
getCopyString(platform, link) {
if (link.kind === LinkKind.User || link.kind === LinkKind.Room) {
return link.identifier;
}
}
getDeepLink(platform, link) {}
canInterceptMatrixToLinks(platform) {
return false;
}
getPreferredWebInstance(link) {}
}

View file

@ -20,23 +20,23 @@ import {Maturity, Platform, LinkKind, WebsiteLink, style} from "../types.js";
* Information on how to deep link to a given matrix client. * Information on how to deep link to a given matrix client.
*/ */
export class Weechat { export class Weechat {
get id() { return "weechat"; } get id() { return "weechat"; }
get name() { return "Weechat"; } get name() { return "Weechat"; }
get icon() { return "images/client-icons/weechat.svg"; } get icon() { return "images/client-icons/weechat.svg"; }
get author() { return "Poljar"; } get author() { return "Poljar"; }
get homepage() { return "https://github.com/poljar/weechat-matrix"; } get homepage() { return "https://github.com/poljar/weechat-matrix"; }
get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; } get platforms() { return [Platform.Windows, Platform.macOS, Platform.Linux]; }
get description() { return 'Command-line Matrix interface using Weechat'; } get description() { return 'Command-line Matrix interface using Weechat.'; }
getMaturity(platform) { return Maturity.Beta; } getMaturity(platform) { return Maturity.Beta; }
getDeepLink(platform, link) {} getDeepLink(platform, link) {}
canInterceptMatrixToLinks(platform) { return false; } canInterceptMatrixToLinks(platform) { return false; }
getLinkInstructions(platform, link) { getLinkInstructions(platform, link) {
switch (link.kind) { switch (link.kind) {
case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)]; case LinkKind.User: return [`Type `, style.code(`/invite ${link.identifier}`)];
case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)]; case LinkKind.Room: return [`Type `, style.code(`/join ${link.identifier}`)];
} }
} }
getCopyString(platform, link) { getCopyString(platform, link) {
switch (link.kind) { switch (link.kind) {
@ -45,5 +45,7 @@ export class Weechat {
} }
} }
getInstallLinks(platform) {} getInstallLinks(platform) {}
getPreferredWebInstance(link) {}
} }

View file

@ -15,18 +15,31 @@ limitations under the License.
*/ */
import {Element} from "./Element.js"; import {Element} from "./Element.js";
import {SchildiChat} from "./SchildiChat.js";
import {Weechat} from "./Weechat.js"; import {Weechat} from "./Weechat.js";
import {Nheko} from "./Nheko.js"; import {Nheko} from "./Nheko.js";
import {Fractal} from "./Fractal.js"; import {Fractal} from "./Fractal.js";
import {Quaternion} from "./Quaternion.js"; import {Quaternion} from "./Quaternion.js";
import {Tensor} from "./Tensor.js"; import {Tensor} from "./Tensor.js";
import {Fluffychat} from "./Fluffychat.js";
import {NeoChat} from "./NeoChat.js";
import {Syphon} from "./Syphon.js";
import {Thunderbird} from "./Thunderbird.js";
import {Cinny} from "./Cinny.js"
export function createClients() { export function createClients() {
return [ return [
new Element(), new Element(),
new Weechat(), new SchildiChat(),
new Weechat(),
new Nheko(), new Nheko(),
new Fractal(),
new Quaternion(), new Quaternion(),
new Tensor(), new Tensor(),
]; new Fluffychat(),
new NeoChat(),
new Syphon(),
new Thunderbird(),
new Cinny(),
];
} }

View file

@ -21,8 +21,8 @@ export {Platform} from "../Platform.js";
export class AppleStoreLink { export class AppleStoreLink {
constructor(org, appId) { constructor(org, appId) {
this._org = org; this._org = org;
this._appId = appId; this._appId = appId;
} }
createInstallURL(link) { createInstallURL(link) {
@ -40,7 +40,7 @@ export class AppleStoreLink {
export class PlayStoreLink { export class PlayStoreLink {
constructor(appId) { constructor(appId) {
this._appId = appId; this._appId = appId;
} }
createInstallURL(link) { createInstallURL(link) {
@ -58,7 +58,7 @@ export class PlayStoreLink {
export class FDroidLink { export class FDroidLink {
constructor(appId) { constructor(appId) {
this._appId = appId; this._appId = appId;
} }
createInstallURL(link) { createInstallURL(link) {
@ -94,7 +94,7 @@ export class FlathubLink {
export class WebsiteLink { export class WebsiteLink {
constructor(url) { constructor(url) {
this._url = url; this._url = url;
} }
createInstallURL(link) { createInstallURL(link) {

View file

@ -17,10 +17,10 @@ limitations under the License.
import {TemplateView} from "../utils/TemplateView.js"; import {TemplateView} from "../utils/TemplateView.js";
export class LoadServerPolicyView extends TemplateView { export class LoadServerPolicyView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({className: "LoadServerPolicyView card"}, [ return t.div({className: "LoadServerPolicyView card"}, [
t.div({className: {spinner: true, hidden: vm => !vm.loading}}), t.div({className: {spinner: true, hidden: vm => !vm.loading}}),
t.h2(vm => vm.message) t.h2(vm => vm.message)
]); ]);
} }
} }

View file

@ -18,12 +18,12 @@ import {ViewModel} from "../utils/ViewModel.js";
import {resolveServer} from "../preview/HomeServer.js"; import {resolveServer} from "../preview/HomeServer.js";
export class LoadServerPolicyViewModel extends ViewModel { export class LoadServerPolicyViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
this.server = options.server; this.server = options.server;
this.message = `Looking up ${this.server} privacy policy…`; this.message = `Looking up ${this.server} privacy policy…`;
this.loading = false; this.loading = false;
} }
async load() { async load() {
this.loading = true; this.loading = true;

View file

@ -14,62 +14,82 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
function noTrailingSlash(url) {
return url.endsWith("/") ? url.slice(0, -1) : url;
}
export async function resolveServer(request, baseURL) { export async function resolveServer(request, baseURL) {
if (!baseURL.startsWith("http://") && !baseURL.startsWith("https://")) { baseURL = noTrailingSlash(baseURL);
baseURL = `https://${baseURL}`; if (!baseURL.startsWith("http://") && !baseURL.startsWith("https://")) {
} baseURL = `https://${baseURL}`;
{ }
const {status, body} = await request(`${baseURL}/.well-known/matrix/client`, {method: "GET"}).response(); {
if (status === 200) { try {
const proposedBaseURL = body?.['m.homeserver']?.base_url; const {status, body} = await request(`${baseURL}/.well-known/matrix/client`, {method: "GET"}).response();
if (typeof proposedBaseURL === "string") { if (status === 200) {
baseURL = proposedBaseURL; const proposedBaseURL = body?.['m.homeserver']?.base_url;
} if (typeof proposedBaseURL === "string") {
} baseURL = noTrailingSlash(proposedBaseURL);
} }
{ }
const {status} = await request(`${baseURL}/_matrix/client/versions`, {method: "GET"}).response(); } catch (e) {
if (status !== 200) { console.warn("Failed to fetch ${baseURL}/.well-known/matrix/client", e);
throw new Error(`Invalid versions response from ${baseURL}`); }
} }
} {
return new HomeServer(request, baseURL); const {status} = await request(`${baseURL}/_matrix/client/versions`, {method: "GET"}).response();
if (status !== 200) {
throw new Error(`Invalid versions response from ${baseURL}`);
}
}
return new HomeServer(request, baseURL);
} }
export class HomeServer { export class HomeServer {
constructor(request, baseURL) { constructor(request, baseURL) {
this._request = request; this._request = request;
this.baseURL = baseURL; this.baseURL = baseURL;
} }
async getUserProfile(userId) { async getUserProfile(userId) {
const {body} = await this._request(`${this.baseURL}/_matrix/client/r0/profile/${encodeURIComponent(userId)}`).response(); const {body} = await this._request(`${this.baseURL}/_matrix/client/r0/profile/${encodeURIComponent(userId)}`).response();
return body; return body;
} }
async findPublicRoomById(roomId) { // MSC3266 implementation
const {body, status} = await this._request(`${this.baseURL}/_matrix/client/r0/directory/list/room/${encodeURIComponent(roomId)}`).response(); async getRoomSummary(roomIdOrAlias, viaServers) {
if (status !== 200 || body.visibility !== "public") { let query;
return; if (viaServers.length > 0) {
} query = "?" + viaServers.map(server => `via=${encodeURIComponent(server)}`).join('&');
let nextBatch; }
do { const {body, status} = await this._request(`${this.baseURL}/_matrix/client/unstable/im.nheko.summary/rooms/${encodeURIComponent(roomIdOrAlias)}/summary${query}`).response();
const queryParams = encodeQueryParams({limit: 10000, since: nextBatch}); if (status !== 200) return;
const {body, status} = await this._request(`${this.baseURL}/_matrix/client/r0/publicRooms?${queryParams}`).response(); return body;
nextBatch = body.next_batch; }
const publicRoom = body.chunk.find(c => c.room_id === roomId);
if (publicRoom) {
return publicRoom;
}
} while (nextBatch);
}
async getRoomIdFromAlias(alias) { async findPublicRoomById(roomId) {
const {status, body} = await this._request(`${this.baseURL}/_matrix/client/r0/directory/room/${encodeURIComponent(alias)}`).response(); const {body, status} = await this._request(`${this.baseURL}/_matrix/client/r0/directory/list/room/${encodeURIComponent(roomId)}`).response();
if (status === 200) { if (status !== 200 || body.visibility !== "public") {
return body.room_id; return;
} }
} let nextBatch;
do {
const queryParams = encodeQueryParams({limit: 10000, since: nextBatch});
const {body, status} = await this._request(`${this.baseURL}/_matrix/client/r0/publicRooms?${queryParams}`).response();
nextBatch = body.next_batch;
const publicRoom = body.chunk.find(c => c.room_id === roomId);
if (publicRoom) {
return publicRoom;
}
} while (nextBatch);
}
async getRoomIdFromAlias(alias) {
const {status, body} = await this._request(`${this.baseURL}/_matrix/client/r0/directory/room/${encodeURIComponent(alias)}`).response();
if (status === 200) {
return body.room_id;
}
}
async getPrivacyPolicyUrl(lang = "en") { async getPrivacyPolicyUrl(lang = "en") {
const headers = new Map(); const headers = new Map();
@ -89,7 +109,7 @@ export class HomeServer {
} }
} }
mxcUrlThumbnail(url, width, height, method) { mxcUrlThumbnail(url, width, height, method) {
const parts = parseMxcUrl(url); const parts = parseMxcUrl(url);
if (parts) { if (parts) {
const [serverName, mediaId] = parts; const [serverName, mediaId] = parts;
@ -103,7 +123,7 @@ export class HomeServer {
function parseMxcUrl(url) { function parseMxcUrl(url) {
const prefix = "mxc://"; const prefix = "mxc://";
if (url.startsWith(prefix)) { if (url.startsWith(prefix)) {
return url.substr(prefix.length).split("/", 2); return url.slice(prefix.length).split("/", 2);
} else { } else {
return null; return null;
} }

View file

@ -43,20 +43,20 @@ class LoadingPreviewView extends TemplateView {
} }
class LoadedPreviewView extends TemplateView { class LoadedPreviewView extends TemplateView {
render(t, vm) { render(t, vm) {
const avatar = t.mapView(vm => vm.avatarUrl, avatarUrl => { const avatar = t.map(vm => vm.avatarUrl, (avatarUrl, t) => {
if (avatarUrl) { if (avatarUrl) {
return new TemplateView(avatarUrl, (t, src) => t.img({className: "avatar", src})); return t.img({className: "avatar", src: avatarUrl});
} else { } else {
return new TemplateView(null, t => t.div({className: "defaultAvatar"})); return t.div({className: "defaultAvatar"});
} }
}); });
return t.div([ return t.div({className: vm.isSpaceRoom ? "mxSpace" : undefined}, [
t.div({className: "avatarContainer"}, avatar), t.div({className: "avatarContainer"}, avatar),
t.h1(vm => vm.name), t.h1(vm => vm.name),
t.p({className: {identifier: true, hidden: vm => !vm.identifier}}, vm => vm.identifier), t.p({className: {identifier: true, hidden: vm => !vm.identifier}}, vm => vm.identifier),
t.div({className: {memberCount: true, hidden: vm => !vm.memberCount}}, t.p([vm => vm.memberCount, " members"])), t.div({className: {memberCount: true, hidden: vm => !vm.memberCount}}, t.p([vm => vm.memberCount, " members"])),
t.p({className: {topic: true, hidden: vm => !vm.topic}}, [vm => vm.topic]), t.p({className: {topic: true, hidden: vm => !vm.topic}}, [vm => vm.topic]),
]); ]);
} }
} }

View file

@ -21,92 +21,101 @@ import {ClientListViewModel} from "../open/ClientListViewModel.js";
import {ClientViewModel} from "../open/ClientViewModel.js"; import {ClientViewModel} from "../open/ClientViewModel.js";
export class PreviewViewModel extends ViewModel { export class PreviewViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
const { link, consentedServers } = options; const { link, consentedServers } = options;
this._link = link; this._link = link;
this._consentedServers = consentedServers; this._consentedServers = consentedServers;
this.loading = false; this.loading = false;
this.name = this._link.identifier; this.name = this._link.identifier;
this.avatarUrl = null; this.avatarUrl = null;
this.identifier = null; this.identifier = null;
this.memberCount = null; this.memberCount = null;
this.topic = null; this.topic = null;
this.domain = null; this.domain = null;
this.failed = false; this.failed = false;
} this.isSpaceRoom = false;
}
async load() { async load() {
const {kind} = this._link; const {kind} = this._link;
const supportsPreview = kind === LinkKind.User || kind === LinkKind.Room || kind === LinkKind.Event; const supportsPreview = kind === LinkKind.User || kind === LinkKind.Room || kind === LinkKind.Event;
if (supportsPreview) { if (supportsPreview) {
this.loading = true; this.loading = true;
this.emitChange(); this.emitChange();
for (const server of this._consentedServers) { for (const server of this._consentedServers) {
try { try {
const homeserver = await resolveServer(this.request, server); const homeserver = await resolveServer(this.request, server);
switch (this._link.kind) { switch (this._link.kind) {
case LinkKind.User: case LinkKind.User:
await this._loadUserPreview(homeserver, this._link.identifier); await this._loadUserPreview(homeserver, this._link.identifier);
break; break;
case LinkKind.Room: case LinkKind.Room:
case LinkKind.Event: case LinkKind.Event:
await this._loadRoomPreview(homeserver, this._link); await this._loadRoomPreview(homeserver, this._link);
break; break;
} }
// assume we're done if nothing threw // assume we're done if nothing threw
this.domain = server; this.domain = server;
this.loading = false; this.loading = false;
this.emitChange(); this.emitChange();
return; return;
} catch (err) { } catch (err) {
continue; continue;
} }
} }
} }
this.loading = false; this.loading = false;
this._setNoPreview(this._link); this._setNoPreview(this._link);
if (this._consentedServers.length && supportsPreview) { if (this._consentedServers.length && supportsPreview) {
this.domain = this._consentedServers[this._consentedServers.length - 1]; this.domain = this._consentedServers[this._consentedServers.length - 1];
this.failed = true; this.failed = true;
} }
this.emitChange(); this.emitChange();
} }
get hasTopic() { return this._link.kind === LinkKind.Room; } get hasTopic() { return this._link.kind === LinkKind.Room; }
get hasMemberCount() { return this.hasTopic; } get hasMemberCount() { return this.hasTopic; }
async _loadUserPreview(homeserver, userId) { async _loadUserPreview(homeserver, userId) {
const profile = await homeserver.getUserProfile(userId); const profile = await homeserver.getUserProfile(userId);
this.name = profile.displayname || userId; this.name = profile.displayname || userId;
this.avatarUrl = profile.avatar_url ? this.avatarUrl = profile.avatar_url ?
homeserver.mxcUrlThumbnail(profile.avatar_url, 64, 64, "crop") : homeserver.mxcUrlThumbnail(profile.avatar_url, 64, 64, "crop") :
null; null;
this.identifier = userId; this.identifier = userId;
} }
async _loadRoomPreview(homeserver, link) { async _loadRoomPreview(homeserver, link) {
let publicRoom; let publicRoom;
if (link.identifierKind === IdentifierKind.RoomId) { if (link.identifierKind === IdentifierKind.RoomId || link.identifierKind === IdentifierKind.RoomAlias) {
publicRoom = await homeserver.findPublicRoomById(link.identifier); publicRoom = await homeserver.getRoomSummary(link.identifier, link.servers);
} else if (link.identifierKind === IdentifierKind.RoomAlias) { }
const roomId = await homeserver.getRoomIdFromAlias(link.identifier);
if (roomId) { if (!publicRoom) {
publicRoom = await homeserver.findPublicRoomById(roomId); if (link.identifierKind === IdentifierKind.RoomId) {
} publicRoom = await homeserver.findPublicRoomById(link.identifier);
} } else if (link.identifierKind === IdentifierKind.RoomAlias) {
this.name = publicRoom?.name || publicRoom?.canonical_alias || link.identifier; const roomId = await homeserver.getRoomIdFromAlias(link.identifier);
this.avatarUrl = publicRoom?.avatar_url ? if (roomId) {
homeserver.mxcUrlThumbnail(publicRoom.avatar_url, 64, 64, "crop") : publicRoom = await homeserver.findPublicRoomById(roomId);
null; }
this.memberCount = publicRoom?.num_joined_members; }
this.topic = publicRoom?.topic; }
this.identifier = publicRoom?.canonical_alias || link.identifier;
this.name = publicRoom?.name || publicRoom?.canonical_alias || link.identifier;
this.avatarUrl = publicRoom?.avatar_url ?
homeserver.mxcUrlThumbnail(publicRoom.avatar_url, 64, 64, "crop") :
null;
this.memberCount = publicRoom?.num_joined_members;
this.topic = publicRoom?.topic;
this.identifier = publicRoom?.canonical_alias || link.identifier;
this.isSpaceRoom = publicRoom?.room_type === "m.space";
if (this.identifier === this.name) { if (this.identifier === this.name) {
this.identifier = null; this.identifier = null;
} }
} }
_setNoPreview(link) { _setNoPreview(link) {
this.name = link.identifier; this.name = link.identifier;

View file

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { setAttribute, text, isChildren, classNames, TAG_NAMES, HTML_NS, tag } from "./html.js"; import { setAttribute, text, isChildren, classNames, TAG_NAMES, HTML_NS } from "./html.js";
/** /**
Bindable template. Renders once, and allows bindings for given nodes. If you need Bindable template. Renders once, and allows bindings for given nodes. If you need
@ -33,11 +33,13 @@ import { setAttribute, text, isChildren, classNames, TAG_NAMES, HTML_NS, tag } f
export class TemplateView { export class TemplateView {
constructor(value, render = undefined) { constructor(value, render = undefined) {
this._value = value; this._value = value;
// TODO: can avoid this if we have a separate class for inline templates vs class template views
this._render = render; this._render = render;
this._eventListeners = null; this._eventListeners = null;
this._bindings = null; this._bindings = null;
this._subViews = null; this._subViews = null;
this._root = null; this._root = null;
// TODO: can avoid this if we adopt the handleEvent pattern in our EventListener
this._boundUpdateFromValue = null; this._boundUpdateFromValue = null;
} }
@ -108,6 +110,10 @@ export class TemplateView {
return this._root; return this._root;
} }
_updateFromValue(changedProps) {
this.update(this._value, changedProps);
}
update(value) { update(value) {
this._value = value; this._value = value;
if (this._bindings) { if (this._bindings) {
@ -117,10 +123,6 @@ export class TemplateView {
} }
} }
_updateFromValue(changedProps) {
this.update(this._value, changedProps);
}
_addEventListener(node, name, fn, useCapture = false) { _addEventListener(node, name, fn, useCapture = false) {
if (!this._eventListeners) { if (!this._eventListeners) {
this._eventListeners = []; this._eventListeners = [];
@ -135,12 +137,19 @@ export class TemplateView {
this._bindings.push(bindingFn); this._bindings.push(bindingFn);
} }
_addSubView(view) { addSubView(view) {
if (!this._subViews) { if (!this._subViews) {
this._subViews = []; this._subViews = [];
} }
this._subViews.push(view); this._subViews.push(view);
} }
removeSubView(view) {
const idx = this._subViews.indexOf(view);
if (idx !== -1) {
this._subViews.splice(idx, 1);
}
}
} }
// what is passed to render // what is passed to render
@ -201,7 +210,7 @@ class TemplateBuilder {
setAttribute(node, key, classNames(value)); setAttribute(node, key, classNames(value));
} }
} else if (key.startsWith("on") && key.length > 2 && isFn) { } else if (key.startsWith("on") && key.length > 2 && isFn) {
const eventName = key.substr(2, 1).toLowerCase() + key.substr(3); const eventName = key.slice(2, 3).toLowerCase() + key.slice(3);
const handler = value; const handler = value;
this._templateView._addEventListener(node, eventName, handler); this._templateView._addEventListener(node, eventName, handler);
} else if (isFn) { } else if (isFn) {
@ -238,8 +247,6 @@ class TemplateBuilder {
const newNode = renderNode(node); const newNode = renderNode(node);
if (node.parentNode) { if (node.parentNode) {
node.parentNode.replaceChild(newNode, node); node.parentNode.replaceChild(newNode, node);
} else {
console.warn("Could not update parent of node binding");
} }
node = newNode; node = newNode;
} }
@ -279,15 +286,10 @@ class TemplateBuilder {
} catch (err) { } catch (err) {
return errorToDOM(err); return errorToDOM(err);
} }
this._templateView._addSubView(view); this._templateView.addSubView(view);
return root; return root;
} }
// sugar
createTemplate(render) {
return vm => new TemplateView(vm, render);
}
// map a value to a view, every time the value changes // map a value to a view, every time the value changes
mapView(mapFn, viewCreator) { mapView(mapFn, viewCreator) {
return this._addReplaceNodeBinding(mapFn, (prevNode) => { return this._addReplaceNodeBinding(mapFn, (prevNode) => {
@ -308,15 +310,36 @@ class TemplateBuilder {
}); });
} }
// creates a conditional subtemplate // Special case of mapView for a TemplateView.
if(fn, viewCreator) { // Always creates a TemplateView, if this is optional depending
// on mappedValue, use `if` or `mapView`
map(mapFn, renderFn) {
return this.mapView(mapFn, mappedValue => {
return new TemplateView(this._value, (t, vm) => {
const rootNode = renderFn(mappedValue, t, vm);
if (!rootNode) {
// TODO: this will confuse mapView which assumes that
// a comment node means there is no view to clean up
return document.createComment("map placeholder");
}
return rootNode;
});
});
}
ifView(predicate, viewCreator) {
return this.mapView( return this.mapView(
value => !!fn(value), value => !!predicate(value),
enabled => enabled ? viewCreator(this._value) : null enabled => enabled ? viewCreator(this._value) : null
); );
} }
}
// creates a conditional subtemplate
// use mapView if you need to map to a different view class
if(predicate, renderFn) {
return this.ifView(predicate, vm => new TemplateView(vm, renderFn));
}
}
function errorToDOM(error) { function errorToDOM(error) {
const stack = new Error().stack; const stack = new Error().stack;

386
yarn.lock
View file

@ -9,6 +9,14 @@
dependencies: dependencies:
"@babel/highlight" "^7.10.4" "@babel/highlight" "^7.10.4"
"@babel/code-frame@^7.22.13":
version "7.22.13"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
dependencies:
"@babel/highlight" "^7.22.13"
chalk "^2.4.2"
"@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7": "@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7":
version "7.12.7" version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41"
@ -45,6 +53,16 @@
jsesc "^2.5.1" jsesc "^2.5.1"
source-map "^0.5.0" source-map "^0.5.0"
"@babel/generator@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
dependencies:
"@babel/types" "^7.23.0"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.10.4": "@babel/helper-annotate-as-pure@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3"
@ -98,6 +116,11 @@
"@babel/types" "^7.10.5" "@babel/types" "^7.10.5"
lodash "^4.17.19" lodash "^4.17.19"
"@babel/helper-environment-visitor@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
"@babel/helper-explode-assignable-expression@^7.10.4": "@babel/helper-explode-assignable-expression@^7.10.4":
version "7.12.1" version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz#8006a466695c4ad86a2a5f2fb15b5f2c31ad5633" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz#8006a466695c4ad86a2a5f2fb15b5f2c31ad5633"
@ -114,6 +137,14 @@
"@babel/template" "^7.10.4" "@babel/template" "^7.10.4"
"@babel/types" "^7.10.4" "@babel/types" "^7.10.4"
"@babel/helper-function-name@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
"@babel/template" "^7.22.15"
"@babel/types" "^7.23.0"
"@babel/helper-get-function-arity@^7.10.4": "@babel/helper-get-function-arity@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
@ -128,6 +159,13 @@
dependencies: dependencies:
"@babel/types" "^7.10.4" "@babel/types" "^7.10.4"
"@babel/helper-hoist-variables@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-member-expression-to-functions@^7.12.1": "@babel/helper-member-expression-to-functions@^7.12.1":
version "7.12.7" version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855"
@ -209,11 +247,28 @@
dependencies: dependencies:
"@babel/types" "^7.11.0" "@babel/types" "^7.11.0"
"@babel/helper-split-export-declaration@^7.22.6":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-string-parser@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
"@babel/helper-validator-identifier@^7.10.4": "@babel/helper-validator-identifier@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
"@babel/helper-validator-identifier@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
"@babel/helper-validator-option@^7.12.1": "@babel/helper-validator-option@^7.12.1":
version "7.12.1" version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz#175567380c3e77d60ff98a54bb015fe78f2178d9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz#175567380c3e77d60ff98a54bb015fe78f2178d9"
@ -247,11 +302,25 @@
chalk "^2.0.0" chalk "^2.0.0"
js-tokens "^4.0.0" js-tokens "^4.0.0"
"@babel/highlight@^7.22.13":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
dependencies:
"@babel/helper-validator-identifier" "^7.22.20"
chalk "^2.4.2"
js-tokens "^4.0.0"
"@babel/parser@^7.12.7": "@babel/parser@^7.12.7":
version "7.12.7" version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056"
integrity sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg== integrity sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
"@babel/plugin-proposal-async-generator-functions@^7.12.1": "@babel/plugin-proposal-async-generator-functions@^7.12.1":
version "7.12.1" version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz#dc6c1170e27d8aca99ff65f4925bd06b1c90550e" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz#dc6c1170e27d8aca99ff65f4925bd06b1c90550e"
@ -791,20 +860,30 @@
"@babel/parser" "^7.12.7" "@babel/parser" "^7.12.7"
"@babel/types" "^7.12.7" "@babel/types" "^7.12.7"
"@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9": "@babel/template@^7.22.15":
version "7.12.9" version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.9.tgz#fad26c972eabbc11350e0b695978de6cc8e8596f" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
integrity sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw== integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
dependencies: dependencies:
"@babel/code-frame" "^7.10.4" "@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.12.5" "@babel/parser" "^7.22.15"
"@babel/helper-function-name" "^7.10.4" "@babel/types" "^7.22.15"
"@babel/helper-split-export-declaration" "^7.11.0"
"@babel/parser" "^7.12.7" "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9":
"@babel/types" "^7.12.7" version "7.23.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
dependencies:
"@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.23.0"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/parser" "^7.23.0"
"@babel/types" "^7.23.0"
debug "^4.1.0" debug "^4.1.0"
globals "^11.1.0" globals "^11.1.0"
lodash "^4.17.19"
"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.4.4": "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.4.4":
version "7.12.7" version "7.12.7"
@ -815,6 +894,82 @@
lodash "^4.17.19" lodash "^4.17.19"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@jridgewell/gen-mapping@^0.3.0":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/gen-mapping@^0.3.2":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/resolve-uri@^3.1.0":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
"@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/source-map@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/sourcemap-codec@^1.4.14":
version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@^0.3.17":
version "0.3.19"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811"
integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==
dependencies:
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.14"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@rollup/plugin-babel@^5.1.0": "@rollup/plugin-babel@^5.1.0":
version "5.2.2" version "5.2.2"
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.2.2.tgz#e5623a01dd8e37e004ba87f2de218c611727d9b2" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.2.2.tgz#e5623a01dd8e37e004ba87f2de218c611727d9b2"
@ -900,6 +1055,11 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
acorn@^8.5.0:
version "8.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
ansi-styles@^3.2.1: ansi-styles@^3.2.1:
version "3.2.1" version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@ -908,15 +1068,15 @@ ansi-styles@^3.2.1:
color-convert "^1.9.0" color-convert "^1.9.0"
autoprefixer@^10.0.1: autoprefixer@^10.0.1:
version "10.0.4" version "10.1.0"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.0.4.tgz#f87ac6105d7861e31af794b8ebb1c6d4390d3d55" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.1.0.tgz#b19fd8524edef8c85c9db3bdb0c998de84e172fb"
integrity sha512-hmjYejN/WTyPP9cdNmiwtwqM8/ACVJPD5ExtwoOceQohNbgnFNiwpL2+U4bXS8aXozBL00WvH6WhqbuHf0Fgfg== integrity sha512-0/lBNwN+ZUnb5su18NZo5MBIjDaq6boQKZcxwy86Gip/CmXA2zZqUoFQLCNAGI5P25ZWSP2RWdhDJ8osfKEjoQ==
dependencies: dependencies:
browserslist "^4.14.7" browserslist "^4.15.0"
caniuse-lite "^1.0.30001161" caniuse-lite "^1.0.30001165"
colorette "^1.2.1" colorette "^1.2.1"
fraction.js "^4.0.12"
normalize-range "^0.1.2" normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss-value-parser "^4.1.0" postcss-value-parser "^4.1.0"
babel-plugin-dynamic-import-node@^2.3.3: babel-plugin-dynamic-import-node@^2.3.3:
@ -927,9 +1087,9 @@ babel-plugin-dynamic-import-node@^2.3.3:
object.assign "^4.1.0" object.assign "^4.1.0"
balanced-match@^1.0.0: balanced-match@^1.0.0:
version "1.0.0" version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
boolbase@~1.0.0: boolbase@~1.0.0:
version "1.0.0" version "1.0.0"
@ -944,21 +1104,21 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0" balanced-match "^1.0.0"
concat-map "0.0.1" concat-map "0.0.1"
browserslist@^4.14.5, browserslist@^4.14.7: browserslist@^4.14.5, browserslist@^4.15.0:
version "4.15.0" version "4.16.6"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.15.0.tgz#3d48bbca6a3f378e86102ffd017d9a03f122bdb0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
integrity sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ== integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==
dependencies: dependencies:
caniuse-lite "^1.0.30001164" caniuse-lite "^1.0.30001219"
colorette "^1.2.1" colorette "^1.2.2"
electron-to-chromium "^1.3.612" electron-to-chromium "^1.3.723"
escalade "^3.1.1" escalade "^3.1.1"
node-releases "^1.1.67" node-releases "^1.1.71"
buffer-from@^1.0.0: buffer-from@^1.0.0:
version "1.1.1" version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
builtin-modules@^3.1.0: builtin-modules@^3.1.0:
version "3.1.0" version "3.1.0"
@ -973,10 +1133,10 @@ call-bind@^1.0.0:
function-bind "^1.1.1" function-bind "^1.1.1"
get-intrinsic "^1.0.0" get-intrinsic "^1.0.0"
caniuse-lite@^1.0.30001161, caniuse-lite@^1.0.30001164: caniuse-lite@^1.0.30001165, caniuse-lite@^1.0.30001219:
version "1.0.30001164" version "1.0.30001230"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001164.tgz#5bbfd64ca605d43132f13cc7fdabb17c3036bfdc" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz#8135c57459854b2240b57a4a6786044bdc5a9f71"
integrity sha512-G+A/tkf4bu0dSp9+duNiXc7bGds35DioCyC6vgK2m/rjA4Krpy5WeZgZyfH2f0wj2kI6yAWWucyap6oOwmY1mg== integrity sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2" version "2.4.2"
@ -1011,10 +1171,10 @@ color-name@1.1.3:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
colorette@^1.2.1: colorette@^1.2.1, colorette@^1.2.2:
version "1.2.1" version "1.2.2"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
commander@^2.20.0: commander@^2.20.0:
version "2.20.3" version "2.20.3"
@ -1029,7 +1189,7 @@ commondir@^1.0.1:
concat-map@0.0.1: concat-map@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
convert-source-map@^1.7.0: convert-source-map@^1.7.0:
version "1.7.0" version "1.7.0"
@ -1039,17 +1199,17 @@ convert-source-map@^1.7.0:
safe-buffer "~5.1.1" safe-buffer "~5.1.1"
core-js-compat@^3.7.0: core-js-compat@^3.7.0:
version "3.8.0" version "3.8.1"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.0.tgz#3248c6826f4006793bd637db608bca6e4cd688b1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.1.tgz#8d1ddd341d660ba6194cbe0ce60f4c794c87a36e"
integrity sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ== integrity sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==
dependencies: dependencies:
browserslist "^4.14.7" browserslist "^4.15.0"
semver "7.0.0" semver "7.0.0"
core-js@^3.6.5: core-js@^3.6.5:
version "3.8.0" version "3.8.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.0.tgz#0fc2d4941cadf80538b030648bb64d230b4da0ce" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.1.tgz#f51523668ac8a294d1285c3b9db44025fda66d47"
integrity sha512-W2VYNB0nwQQE7tKS7HzXd7r2y/y2SVJl4ga6oH/dnaLFzM0o2lB2P3zCkWj5Wc/zyMYjtgd5Hmhk0ObkQFZOIA== integrity sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==
css-select@~1.2.0: css-select@~1.2.0:
version "1.2.0" version "1.2.0"
@ -1161,10 +1321,10 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.612: electron-to-chromium@^1.3.723:
version "1.3.613" version "1.3.739"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.613.tgz#5ad7ec1e19d28c81edb6d61b9d4990d1c9716182" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.739.tgz#f07756aa92cabd5a6eec6f491525a64fe62f98b9"
integrity sha512-c3gkahddiUalk7HLhTC7PsKzPZmovYFtgh+g3rZJ+dGokk4n4dzEoOBnoV8VU8ptvnGJMhrjM/lyXKSltqf2hQ== integrity sha512-+LPJVRsN7hGZ9EIUUiWCpO7l4E3qBYHNadazlucBfsXBbccDFNKUBAgzE68FnkWGJPwD/AfKhSzL+G+Iqb8A4A==
encodeurl@~1.0.2: encodeurl@~1.0.2:
version "1.0.2" version "1.0.2"
@ -1234,6 +1394,11 @@ finalhandler@^1.1.2:
statuses "~1.5.0" statuses "~1.5.0"
unpipe "~1.0.0" unpipe "~1.0.0"
fraction.js@^4.0.12:
version "4.0.12"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.12.tgz#0526d47c65a5fb4854df78bc77f7bec708d7b8c3"
integrity sha512-8Z1K0VTG4hzYY7kA/1sj4/r1/RWLBD3xwReT/RCrUCbzPszjNQCCsy3ktkU/eaEqX3MYa4pY37a52eiBlPMlhA==
fresh@0.5.2: fresh@0.5.2:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@ -1387,16 +1552,14 @@ jsesc@~0.5.0:
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
json5@^2.1.2: json5@^2.1.2:
version "2.1.3" version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
dependencies:
minimist "^1.2.5"
lodash@^4.15.0, lodash@^4.17.19: lodash@^4.15.0, lodash@^4.17.19:
version "4.17.20" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
magic-string@^0.25.7: magic-string@^0.25.7:
version "0.25.7" version "0.25.7"
@ -1434,16 +1597,16 @@ mime@^2.3.1:
integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==
minimatch@^3.0.4: minimatch@^3.0.4:
version "3.0.4" version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimist@^1.2.5: minimist@^1.2.5:
version "1.2.5" version "1.2.7"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
mkdirp@^0.5.0: mkdirp@^0.5.0:
version "0.5.5" version "0.5.5"
@ -1467,15 +1630,15 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
nanoid@^3.1.18: nanoid@^3.3.6:
version "3.1.20" version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
node-releases@^1.1.67: node-releases@^1.1.71:
version "1.1.67" version "1.1.72"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe"
integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg== integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==
normalize-range@^0.1.2: normalize-range@^0.1.2:
version "0.1.2" version "0.1.2"
@ -1489,11 +1652,6 @@ nth-check@~1.0.1:
dependencies: dependencies:
boolbase "~1.0.0" boolbase "~1.0.0"
num2fraction@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=
object-keys@^1.0.12, object-keys@^1.1.1: object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@ -1541,9 +1699,14 @@ path-is-absolute@^1.0.0:
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-parse@^1.0.6: path-parse@^1.0.6:
version "1.0.6" version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picomatch@^2.2.1, picomatch@^2.2.2: picomatch@^2.2.1, picomatch@^2.2.2:
version "2.2.2" version "2.2.2"
@ -1621,15 +1784,14 @@ postcss@^7.0.1, postcss@^7.0.2, postcss@^7.0.26:
source-map "^0.6.1" source-map "^0.6.1"
supports-color "^6.1.0" supports-color "^6.1.0"
postcss@^8.1.1: postcss@^8.4.31:
version "8.1.10" version "8.4.31"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.1.10.tgz#129834f94c720554d2cfdaeb27d5542ac4a026ea" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
integrity sha512-iBXEV5VTTYaRRdxiFYzTtuv2lGMQBExqkZKSzkJe+Fl6rvQrA/49UVGKqB+LG54hpW/TtDBMGds8j33GFNW7pg== integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
dependencies: dependencies:
colorette "^1.2.1" nanoid "^3.3.6"
nanoid "^3.1.18" picocolors "^1.0.0"
source-map "^0.6.1" source-map-js "^1.0.2"
vfile-location "^3.2.0"
randombytes@^2.1.0: randombytes@^2.1.0:
version "2.1.0" version "2.1.0"
@ -1726,9 +1888,9 @@ rollup-plugin-terser@^7.0.2:
terser "^5.0.0" terser "^5.0.0"
rollup@^2.26.4: rollup@^2.26.4:
version "2.34.0" version "2.34.2"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.34.0.tgz#ecc7f1d4ce2cb88bb51bec2f56b984f3c35b8271" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.34.2.tgz#fa73e05c64df587e9ed4dc80d7d4e7d4a43f8908"
integrity sha512-dW5iLvttZzdVehjEuNJ1bWvuMEJjOWGmnuFS82WeKHTGXDkRHQeq/ExdifkSyJv9dLcR86ysKRmrIDyR6O0X8g== integrity sha512-mvtQLqu3cNeoctS+kZ09iOPxrc1P1/Bt1z15enuQ5feyKOdM3MJAVFjjsygurDpSWn530xB4AlA83TWIzRstXA==
optionalDependencies: optionalDependencies:
fsevents "~2.1.2" fsevents "~2.1.2"
@ -1748,9 +1910,9 @@ semver@7.0.0:
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^5.4.1, semver@^5.5.0: semver@^5.4.1, semver@^5.5.0:
version "5.7.1" version "5.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
send@0.17.1: send@0.17.1:
version "0.17.1" version "0.17.1"
@ -1793,10 +1955,15 @@ setprototypeof@1.1.1:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
source-map-support@~0.5.19: source-map-js@^1.0.2:
version "0.5.19" version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies: dependencies:
buffer-from "^1.0.0" buffer-from "^1.0.0"
source-map "^0.6.0" source-map "^0.6.0"
@ -1811,11 +1978,6 @@ source-map@^0.6.0, source-map@^0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@~0.7.2:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
sourcemap-codec@^1.4.4: sourcemap-codec@^1.4.4:
version "1.4.8" version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
@ -1855,13 +2017,14 @@ supports-color@^7.0.0:
has-flag "^4.0.0" has-flag "^4.0.0"
terser@^5.0.0: terser@^5.0.0:
version "5.5.1" version "5.14.2"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
integrity sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ== integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
dependencies: dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
commander "^2.20.0" commander "^2.20.0"
source-map "~0.7.2" source-map-support "~0.5.20"
source-map-support "~0.5.19"
to-fast-properties@^2.0.0: to-fast-properties@^2.0.0:
version "2.0.0" version "2.0.0"
@ -1906,11 +2069,6 @@ util-deprecate@^1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
vfile-location@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c"
integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==
wrappy@1: wrappy@1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"