Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b286ef2a74 | ||
|
|
121937bcbe | ||
|
|
1274bd98df | ||
|
|
1942ffbdcd | ||
|
|
fdff541a2a | ||
|
|
b8a1c5386f | ||
|
|
3c71b8c8f8 | ||
|
|
27ba1bd931 | ||
|
|
2fad1225b0 | ||
|
|
3c968a2bb2 | ||
|
|
e30555c865 | ||
|
|
322df8d47e | ||
|
|
2c56ff2584 | ||
|
|
6d7254f2d2 | ||
|
|
4953fe79fe | ||
|
|
b15925815e | ||
|
|
51d61895a4 | ||
|
|
7f611bd199 | ||
|
|
1b05730c3d | ||
|
|
bf143681ff | ||
|
|
e9979fdad2 | ||
|
|
f1fa827d42 | ||
|
|
b7be3d762b | ||
|
|
7f21132f0c | ||
|
|
d48508b162 | ||
|
|
3ad28eaeb6 | ||
|
|
a87d6260d7 | ||
|
|
6286027559 | ||
|
|
6bf4d487f3 | ||
|
|
a3f9252b90 | ||
|
|
aeee77e9b8 | ||
|
|
8f1980eaa7 | ||
|
|
8cf67b1419 | ||
|
|
15c9640ae1 | ||
|
|
a0a107126b | ||
|
|
4e53b3e6ef | ||
|
|
006d57f7d1 | ||
|
|
273db4ed9a | ||
|
|
4452f0524f | ||
|
|
447cce7c92 | ||
|
|
1ce026c526 | ||
|
|
433558a131 | ||
|
|
7f215e15e9 | ||
|
|
edfdfd6dbc | ||
|
|
c8f551f66a | ||
|
|
3a5accf878 | ||
|
|
6523d5c548 | ||
|
|
a7ecd25465 | ||
|
|
10115f4d80 | ||
|
|
78ebe7df4a | ||
|
|
a023653cc6 | ||
|
|
b636dfcc84 | ||
|
|
25a03f7570 | ||
|
|
8540f8697f | ||
|
|
81059fc706 | ||
|
|
e50e48fd14 | ||
|
|
f399c230f3 | ||
|
|
1a17092555 | ||
|
|
4755eb8066 | ||
|
|
cd85b36da0 | ||
|
|
626080165e | ||
|
|
808c087792 | ||
|
|
ef5c31fff7 | ||
|
|
88030482df | ||
|
|
4106248634 | ||
|
|
a7008b5108 | ||
|
|
4de3e43dc8 | ||
|
|
8249e9f9e9 | ||
|
|
111e048e7b | ||
|
|
7093144ceb | ||
|
|
8afb049840 | ||
|
|
18504de67c | ||
|
|
13f7ed5415 | ||
|
|
2d9dbdd49e | ||
|
|
f9af5e0216 | ||
|
|
98741fb49c | ||
|
|
e863523510 | ||
|
|
4ff9d6ba5c | ||
|
|
7da654649d | ||
|
|
195e3f9a5a | ||
|
|
4e3f3bb644 | ||
|
|
6b4e6b1566 | ||
|
|
550774e291 | ||
|
|
9a495fd902 | ||
|
|
70de4ec769 | ||
|
|
02abf3417b | ||
|
|
148a953a7d | ||
|
|
c655c24007 | ||
|
|
22e727ee73 | ||
|
|
3dba75d8aa | ||
|
|
094369c63a | ||
|
|
ddb07d31aa | ||
|
|
9adaeb6fed | ||
|
|
3b1a686f99 | ||
|
|
fa4c451c8a | ||
|
|
b59b504d8b | ||
|
|
74a94d42c1 | ||
|
|
cc0c5c67f9 | ||
|
|
f9b9220c8b | ||
|
|
f6b7ca3a7e | ||
|
|
70cb660cd2 | ||
|
|
92ff3bd4dc | ||
|
|
edb4beefdd | ||
|
|
10f3aa030e | ||
|
|
51df6dbb4c | ||
|
|
23e727b97a | ||
|
|
b5393212e9 | ||
|
|
88b2697170 | ||
|
|
cbc0e06d4f | ||
|
|
cb8340e734 | ||
|
|
80b6f7afb5 | ||
|
|
0093a99312 | ||
|
|
3f75d6bcfc | ||
|
|
4f6aa69009 | ||
|
|
7afc447e69 | ||
|
|
8aa1347f7d | ||
|
|
9d66ba076b | ||
|
|
4b93ecb357 | ||
|
|
367145c9ff | ||
|
|
d43bd76631 | ||
|
|
d796765ef3 | ||
|
|
29b9734a56 | ||
|
|
1323989f83 | ||
|
|
45be34b103 | ||
|
|
75ef1c2d39 | ||
|
|
ed918fc4f9 | ||
|
|
aba5336bdb | ||
|
|
2ac9665f11 | ||
|
|
452f779295 | ||
|
|
a159ac946c | ||
|
|
47d5316480 | ||
|
|
b560d62194 | ||
|
|
19384e1027 | ||
|
|
a43b5a6a02 | ||
|
|
90ffafd4ad | ||
|
|
024c19f203 | ||
|
|
abac11dfb4 | ||
|
|
b22388770d | ||
|
|
e3538d66d9 | ||
|
|
7c96decfc9 | ||
|
|
5dc7997dc5 | ||
|
|
02ffce3ca5 | ||
|
|
09200d4632 | ||
|
|
762a698be2 | ||
|
|
6c24833a91 | ||
|
|
3cf4827e4d | ||
|
|
85e7b52493 | ||
|
|
ea32fe1c2d | ||
|
|
78451db766 | ||
|
|
15b146fab6 | ||
|
|
67a68469db | ||
|
|
f1715cede9 | ||
|
|
4d3dcc0977 | ||
|
|
ef5bf58108 | ||
|
|
b1dad60260 | ||
|
|
7e3627a7e1 | ||
|
|
c203e6f497 | ||
|
|
e3b78a860d | ||
|
|
e52b72f731 | ||
|
|
0d5a0fe21e | ||
|
|
39462bfc14 | ||
|
|
cadab15871 | ||
|
|
6dd97428c7 | ||
|
|
274fd1a299 | ||
|
|
823273bc26 | ||
|
|
21e2161bfd | ||
|
|
a7e9b1f9e3 | ||
|
|
08791fc13d | ||
|
|
7d0c405b8d | ||
|
|
291475afcc | ||
|
|
c53e5c50da | ||
|
|
181faba3a6 | ||
|
|
8a3cf6ce48 | ||
|
|
86ef94af34 | ||
|
|
b88f7e73da |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@status-im/js': patch
|
||||
---
|
||||
|
||||
get peer based on environment
|
||||
@@ -5,7 +5,7 @@
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"baseBranch": "origin/main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": []
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@status-im/js': patch
|
||||
---
|
||||
|
||||
use built-in crypto for pbkdf2
|
||||
@@ -1,8 +0,0 @@
|
||||
**/dist
|
||||
**/node_modules
|
||||
**/protos
|
||||
**/proto
|
||||
**/coverage
|
||||
**/storybook-static
|
||||
**/examples
|
||||
**/packages/status-react
|
||||
@@ -5,45 +5,52 @@ on:
|
||||
branches: ['main']
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
NEXT_PUBLIC_GHOST_API_URL: ''
|
||||
NEXT_PUBLIC_GHOST_API_KEY: ''
|
||||
INFURA_API_KEY: ''
|
||||
TAMAGUI_TARGET: 'web'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Test
|
||||
timeout-minutes: 15
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
# https://github.com/changesets/changesets/issues/1055
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'yarn'
|
||||
version: 9.12.3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.18.0
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Changeset
|
||||
# https://github.com/changesets/changesets/issues/1048
|
||||
run: pnpm dlx @changesets/cli status --since origin/main
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn --frozen-lockfile
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: yarn build
|
||||
run: pnpm build
|
||||
|
||||
- name: Typecheck
|
||||
run: yarn typecheck
|
||||
run: pnpm typecheck
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint && yarn format --check
|
||||
run: pnpm lint && pnpm format --check
|
||||
|
||||
- name: Test
|
||||
run: yarn test
|
||||
run: pnpm test
|
||||
|
||||
@@ -5,22 +5,37 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
env:
|
||||
NEXT_PUBLIC_GHOST_API_URL: ''
|
||||
NEXT_PUBLIC_GHOST_API_KEY: ''
|
||||
INFURA_API_KEY: ''
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
# https://docs.github.com/en/actions/using-workflows/reusing-workflows#calling-a-reusable-workflow
|
||||
uses: ./.github/workflows/ci.yml
|
||||
release:
|
||||
needs: ci
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn install --frozen-lockfile
|
||||
version: 9.12.3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.18.0
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm build
|
||||
- uses: changesets/action@v1
|
||||
id: changesets
|
||||
with:
|
||||
title: Release
|
||||
commit: Release
|
||||
version: yarn changeset version
|
||||
publish: yarn changeset publish
|
||||
version: pnpm changeset version
|
||||
publish: pnpm changeset publish
|
||||
createGithubReleases: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -80,9 +80,6 @@ node_modules/
|
||||
# Vercel
|
||||
.vercel
|
||||
|
||||
# Tamagui
|
||||
.tamagui
|
||||
|
||||
# Storybook
|
||||
storybook-static
|
||||
|
||||
@@ -104,3 +101,6 @@ web-build/
|
||||
|
||||
# Local
|
||||
**/.data
|
||||
|
||||
# Contentlayer
|
||||
.contentlayer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
pnpm lint-staged
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
20.18.0
|
||||
@@ -0,0 +1,2 @@
|
||||
!.npmrc
|
||||
#!pnpm-lock.yaml
|
||||
@@ -0,0 +1,11 @@
|
||||
; https://pnpm.io/cli/run#enable-pre-post-scripts
|
||||
enable-pre-post-scripts=true
|
||||
; https://pnpm.io/npmrc#node-linker
|
||||
; node-linker=hoisted
|
||||
; https://pnpm.io/npmrc#shamefully-hoist
|
||||
;shamefully-hoist=true
|
||||
;auto-install-peers=true
|
||||
; https://pnpm.io/npmrc#node-version
|
||||
node-version=20.18.0
|
||||
; https://pnpm.io/npmrc#engine-strict
|
||||
engine-strict=true
|
||||
@@ -0,0 +1 @@
|
||||
pnpm-lock.yaml
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"arrowParens": "avoid"
|
||||
"arrowParens": "avoid",
|
||||
"plugins": ["prettier-plugin-tailwindcss"],
|
||||
"tailwindFunctions": ["cx", "cva"]
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
"dbaeumer.vscode-eslint",
|
||||
"zxh404.vscode-proto3",
|
||||
"ms-vscode.hexeditor",
|
||||
"zixuanchen.vitest-explorer",
|
||||
"mikestead.dotenv",
|
||||
"bradlc.vscode-tailwindcss"
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"vitest.explorer",
|
||||
"github.vscode-github-actions"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -26,14 +26,15 @@
|
||||
"smartStep": true,
|
||||
"sourceMaps": true,
|
||||
"env": {
|
||||
"DEBUG": "*",
|
||||
// "DEBUG": "*,-vite*,-connect:*",
|
||||
"DEBUG_HIDE_DATE": "0",
|
||||
"DEBUG_COLORS": "1",
|
||||
"VITE_NODE": "true"
|
||||
},
|
||||
"runtimeArgs": ["--preserve-symlinks"],
|
||||
"outFiles": ["${workspaceFolder}/**/*.js"],
|
||||
"resolveSourceMapLocations": ["**/*"]
|
||||
"resolveSourceMapLocations": ["**/*"],
|
||||
"outputCapture": "std"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
@@ -59,48 +60,6 @@
|
||||
"smartStep": true,
|
||||
"console": "integratedTerminal",
|
||||
"sourceMaps": true
|
||||
},
|
||||
{
|
||||
"name": "Launch Website via Next.js (server-side)",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/apps/website",
|
||||
"command": "yarn dev"
|
||||
},
|
||||
{
|
||||
"name": "Attach to Website via Next.js (client-side)",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"webRoot": "${workspaceFolder}/apps/website",
|
||||
"url": "http://localhost:3000",
|
||||
"skipFiles": [
|
||||
".next/**",
|
||||
"${workspaceFolder}/node_modules/**",
|
||||
"<node_internals>/**",
|
||||
"**/webpack-internal://**"
|
||||
],
|
||||
"runtimeArgs": ["--auto-open-devtools-for-tabs"]
|
||||
},
|
||||
// todo: consider https://code.visualstudio.com/docs/editor/debugging#_compound-launch-configurations instead
|
||||
// todo: consider client+prelaunch as full stack
|
||||
// todo: consider workspaces https://code.visualstudio.com/docs/editor/multi-root-workspaces#_debugging
|
||||
{
|
||||
"name": "Launch Website via Next.js (full stack)",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/apps/website",
|
||||
"command": "yarn dev -p 3000",
|
||||
"serverReadyAction": {
|
||||
"pattern": "started server on .+, url: (https?://.+)",
|
||||
"action": "startDebugging",
|
||||
"name": "Attach to Website via Next.js (client-side)",
|
||||
"killOnServerStop": false
|
||||
},
|
||||
"skipFiles": [
|
||||
".next/**",
|
||||
"${workspaceFolder}/node_modules/**",
|
||||
"<node_internals>/**"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"eslint.packageManager": "yarn",
|
||||
"npm.packageManager": "yarn",
|
||||
"npm.packageManager": "pnpm",
|
||||
"eslint.useESLintClass": true,
|
||||
"eslint.workingDirectories": [
|
||||
"./packages/colors",
|
||||
"./packages/icons",
|
||||
"./packages/components",
|
||||
"./packages/status-js",
|
||||
"./apps/connector",
|
||||
{
|
||||
"mode": "auto",
|
||||
"#comment": "See https://github.com/microsoft/vscode-eslint/issues/1161 for reason (i.e. multiple .eslintrc config files)"
|
||||
}
|
||||
],
|
||||
"tailwindCSS.experimental.classRegex": [
|
||||
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
|
||||
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
|
||||
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
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 Status Research & Development GmbH
|
||||
|
||||
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.
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 Status Research & Development GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,346 @@
|
||||
# Mozilla Public License Version 2.0
|
||||
|
||||
### 1. Definitions
|
||||
|
||||
**1.1. “Contributor”**
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
**1.2. “Contributor Version”**
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
**1.3. “Contribution”**
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
**1.4. “Covered Software”**
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
**1.5. “Incompatible With Secondary Licenses”**
|
||||
means
|
||||
|
||||
- **(a)** that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
- **(b)** that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
**1.6. “Executable Form”**
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
**1.7. “Larger Work”**
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
**1.8. “License”**
|
||||
means this document.
|
||||
|
||||
**1.9. “Licensable”**
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
**1.10. “Modifications”**
|
||||
means any of the following:
|
||||
|
||||
- **(a)** any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
- **(b)** any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
**1.11. “Patent Claims” of a Contributor**
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
**1.12. “Secondary License”**
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
**1.13. “Source Code Form”**
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
**1.14. “You” (or “Your”)**
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, “You” includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, “control” means **(a)** the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or **(b)** ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
### 2. License Grants and Conditions
|
||||
|
||||
#### 2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
- **(a)** under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
- **(b)** under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
#### 2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
#### 2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
- **(a)** for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
- **(b)** for infringements caused by: **(i)** Your and any other third party's
|
||||
modifications of Covered Software, or **(ii)** the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
- **(c)** under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
#### 2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
#### 2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
#### 2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
#### 2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
### 3. Responsibilities
|
||||
|
||||
#### 3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
#### 3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
- **(a)** such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
- **(b)** You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
#### 3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
#### 3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
#### 3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
### 4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: **(a)** comply with
|
||||
the terms of this License to the maximum extent possible; and **(b)**
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
### 5. Termination
|
||||
|
||||
**5.1.** The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated **(a)** provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and **(b)** on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
**5.2.** If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
### 6. Disclaimer of Warranty
|
||||
|
||||
> Covered Software is provided under this License on an “as is”
|
||||
> basis, without warranty of any kind, either expressed, implied, or
|
||||
> statutory, including, without limitation, warranties that the
|
||||
> Covered Software is free of defects, merchantable, fit for a
|
||||
> particular purpose or non-infringing. The entire risk as to the
|
||||
> quality and performance of the Covered Software is with You.
|
||||
> Should any Covered Software prove defective in any respect, You
|
||||
> (not any Contributor) assume the cost of any necessary servicing,
|
||||
> repair, or correction. This disclaimer of warranty constitutes an
|
||||
> essential part of this License. No use of any Covered Software is
|
||||
> authorized under this License except under this disclaimer.
|
||||
|
||||
### 7. Limitation of Liability
|
||||
|
||||
> Under no circumstances and under no legal theory, whether tort
|
||||
> (including negligence), contract, or otherwise, shall any
|
||||
> Contributor, or anyone who distributes Covered Software as
|
||||
> permitted above, be liable to You for any direct, indirect,
|
||||
> special, incidental, or consequential damages of any character
|
||||
> including, without limitation, damages for lost profits, loss of
|
||||
> goodwill, work stoppage, computer failure or malfunction, or any
|
||||
> and all other commercial damages or losses, even if such party
|
||||
> shall have been informed of the possibility of such damages. This
|
||||
> limitation of liability shall not apply to liability for death or
|
||||
> personal injury resulting from such party's negligence to the
|
||||
> extent applicable law prohibits such limitation. Some
|
||||
> jurisdictions do not allow the exclusion or limitation of
|
||||
> incidental or consequential damages, so this exclusion and
|
||||
> limitation may not apply to You.
|
||||
|
||||
### 8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
### 9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
### 10. Versions of the License
|
||||
|
||||
#### 10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
#### 10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
#### 10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
## Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
## Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
@@ -1,127 +1,92 @@
|
||||
# Status Web 🌐
|
||||
# `status-web`
|
||||
|
||||
[](https://github.com/status-im/status-web/actions/workflows/ci.yml)
|
||||
|
||||
## About
|
||||
This monorepo contains packages for building web applications in the Status ecosystem. These packages can be used separately or combined to create consistent and beautiful user interfaces.
|
||||
|
||||
Embeddable, customizable and themable component for your Status Community.
|
||||
## Packages
|
||||
|
||||
### Who
|
||||
| Name | `npm` | Description |
|
||||
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`@status-im/components`](./packages/components) | [](https://www.npmjs.com/package/@status-im/components) | Component library built with Radix UI, React Aria, Tailwind CSS. |
|
||||
| [`@status-im/js`](./packages/status-js) | [](https://www.npmjs.com/package/@status-im/js) | Libary for Waku protocol integration and blockchain interactions. |
|
||||
| [`@status-im/icons`](./packages/icons) | [](https://www.npmjs.com/package/@status-im/icons) | Auto-generated icon library based on our [design system](https://www.figma.com/design/qLLuMLfpGxK9OfpIavwsmK/Iconset?node-id=3239-987&node-type=frame&t=0h8iIiZ3Sf0g4MRV-11). |
|
||||
| [`@status-im/colors`](./packages/colors) | [](https://www.npmjs.com/package/@status-im/colors) | Auto-generated color palette based on our [design system](https://www.figma.com/design/v98g9ZiaSHYUdKWrbFg9eM/Foundations?node-id=619-5995&node-type=canvas&m=dev). |
|
||||
| [`@status-im/eslint-config`](./packages/eslint-config) | [](https://www.npmjs.com/package/@status-im/eslint-config) | Shared ESLint configuration for consistent code style across projects. |
|
||||
|
||||
- For community leaders
|
||||
- online content creators
|
||||
- and their followers
|
||||
## Apps
|
||||
|
||||
### What
|
||||
| Name | Description |
|
||||
| -------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| [`./apps/connector`](./apps/connector) | Status Desktop Wallet extended to decentralised applications in your browser. |
|
||||
|
||||
- It is 100% open source
|
||||
- 100% decentralized
|
||||
- Peer-to-peer
|
||||
- Private
|
||||
- Pseudoanonymous
|
||||
- End-to-end encrypted
|
||||
- Free
|
||||
- Permissionless
|
||||
- Serverless
|
||||
- Group chat platform
|
||||
- And a virtual space outside the jurisdiction of any government
|
||||
## Prerequisites
|
||||
|
||||
### Why
|
||||
Required:
|
||||
|
||||
- To communicate and collaborate freely without worrying about
|
||||
- Censorship
|
||||
- Persecution
|
||||
- Chilling effects
|
||||
- Interference
|
||||
- Oppression
|
||||
- Being deplatformed, or shut down
|
||||
- Support
|
||||
- Autonomy
|
||||
- Free speech
|
||||
- Freedom of association
|
||||
- Freedom to transact
|
||||
- Right to privacy
|
||||
- Crypto native and frictionless integration
|
||||
- Monetization
|
||||
- Facilitation of sharing of common interests, needs, desires and values
|
||||
- Be trusted alternative to centralized group chat application
|
||||
- **[Node.js](https://nodejs.org/)** v20.x
|
||||
- **[pnpm](https://pnpm.io)** v9.12.x
|
||||
|
||||
## Usage
|
||||
Recommended:
|
||||
|
||||
### For Community owners 👥
|
||||
- **[Visual Studio Code](https://code.visualstudio.com/)**
|
||||
- install extensions listed in `.vscode/extensions.json` for optimal development experience
|
||||
|
||||
**Get public key to your pre-existing Community:**
|
||||
## Stack
|
||||
|
||||
1. Open Status Desktop
|
||||
2. Select Community
|
||||
3. Click on its overview in upper left corner
|
||||
4. Invite new people
|
||||
5. Share community
|
||||
6. Get only the public key from the URL (e.g. `0x033c88c950480493e2e759923bd38f9aad88e1b36295757a598679a569e6a96801`)
|
||||
- **Turborepo**: Manages our monorepo and speeds up builds
|
||||
- **TypeScript**: Adds type safety to our code
|
||||
- **React**: Our main library for building UIs
|
||||
- **Radix UI / React Aria**: Provides accessible UI primitives
|
||||
- **Tailwind CSS**: Used for styling
|
||||
- **Vite**: Our build tool and dev server
|
||||
- **Storybook**: For developing and showcasing components
|
||||
- **ESLint**: Keeps our code consistent and catches potential issues
|
||||
- **Prettier**: Formats our code
|
||||
- **Changesets**: Manages versioning and changelogs
|
||||
|
||||
**Or create new one first:**
|
||||
## Getting Started
|
||||
|
||||
1. Get Status Desktop at <https://status.im/get>
|
||||
2. Go to Chat
|
||||
3. Click on plus icon
|
||||
4. Click on Communities
|
||||
1. Clone the repository:
|
||||
|
||||
**Use the Community component:**
|
||||
```
|
||||
git clone https://github.com/status-im/status-web.git
|
||||
cd status-web
|
||||
```
|
||||
|
||||
In your project,
|
||||
2. Install dependencies:
|
||||
|
||||
Install package:
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
```sh
|
||||
npm install @status-im/react
|
||||
3. Build all packages:
|
||||
|
||||
```
|
||||
pnpm build
|
||||
```
|
||||
|
||||
4. Run tests:
|
||||
|
||||
```
|
||||
pnpm test
|
||||
```
|
||||
|
||||
5. Start development mode:
|
||||
```
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Storybook
|
||||
|
||||
To view and interact with the components, you can run Storybook:
|
||||
|
||||
```
|
||||
pnpm storybook
|
||||
```
|
||||
|
||||
Import component:
|
||||
This will start the Storybook server, allowing you to browse and test components in isolation.
|
||||
|
||||
```js
|
||||
import { Community } from '@status-im/react'
|
||||
```
|
||||
## Sponsors
|
||||
|
||||
Set component props:
|
||||
|
||||
```js
|
||||
<Community
|
||||
publicKey="0x033c88c950480493e2e759923bd38f9aad88e1b36295757a598679a569e6a96801"
|
||||
theme="light"
|
||||
/>
|
||||
```
|
||||
|
||||
For an example, see [examples/with-vite/src/app.tsx](./examples/with-vite/src/app.tsx).
|
||||
|
||||
### For User 👤
|
||||
|
||||
**Simply visit your Community's URL from the browser:**
|
||||
|
||||
If the Community doesn't require a joining request, that would be it. So look around and get the feel for the space.
|
||||
|
||||
**Once ready to chat, create a throwaway profile:**
|
||||
|
||||
Use Throwaway Profile > wait for your request to be approved and the chat input enabled > react to and write messages
|
||||
|
||||
**Optionally, you could even run the application locally yourself.**
|
||||
|
||||
Get the source ready:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/status-im/status-web.git
|
||||
cd ./status-web
|
||||
yarn install
|
||||
yarn run build
|
||||
```
|
||||
|
||||
Add your Community's public key to your environment:
|
||||
|
||||
```sh
|
||||
echo 'PUBLIC_KEY="0x033c88c950480493e2e759923bd38f9aad88e1b36295757a598679a569e6a96801"' >> examples/with-vite/.env
|
||||
```
|
||||
|
||||
And run it:
|
||||
|
||||
```sh
|
||||
yarn workspace with-vite run dev
|
||||
```
|
||||
This project is sponsored by Browserstack.
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
#cache
|
||||
.turbo
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
!.env.*
|
||||
.env*.local
|
||||
|
||||
out/
|
||||
build/
|
||||
dist/
|
||||
|
||||
# plasmo - https://www.plasmo.com
|
||||
.plasmo
|
||||
|
||||
# bpp - http://bpp.browser.market/
|
||||
keys.json
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
|
||||
apps/
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"arrowParens": "avoid",
|
||||
"tailwindConfig": "./tailwind.config.ts",
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @type {import('prettier').Options}
|
||||
*/
|
||||
export default {
|
||||
printWidth: 80,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: false,
|
||||
singleQuote: false,
|
||||
trailingComma: 'none',
|
||||
bracketSpacing: true,
|
||||
bracketSameLine: true,
|
||||
plugins: ['@ianvs/prettier-plugin-sort-imports'],
|
||||
importOrder: [
|
||||
'<BUILTIN_MODULES>', // Node.js built-in modules
|
||||
'<THIRD_PARTY_MODULES>', // Imports not matched by other special words or groups.
|
||||
'', // Empty line
|
||||
'^@plasmo/(.*)$',
|
||||
'',
|
||||
'^@plasmohq/(.*)$',
|
||||
'',
|
||||
'^~(.*)$',
|
||||
'',
|
||||
'^[./]',
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# connector
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 3c71b8c: update ESLint
|
||||
- Updated dependencies [3c71b8c]
|
||||
- @status-im/colors@1.0.2
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.11'
|
||||
|
||||
def changesDetected = false
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
options {
|
||||
timestamps()
|
||||
/* Prevent Jenkins jobs from running forever */
|
||||
timeout(time: 10, unit: 'MINUTES')
|
||||
/* manage how many builds we keep */
|
||||
buildDiscarder(logRotator(
|
||||
numToKeepStr: '20',
|
||||
daysToKeepStr: '30',
|
||||
))
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
|
||||
environment {
|
||||
PLATFORM = 'chrome'
|
||||
ZIP_NAME = utils.pkgFilename(
|
||||
type: 'Extension',
|
||||
version: 'none',
|
||||
arch: 'chrome',
|
||||
ext: 'zip',
|
||||
)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Check Changed Files') {
|
||||
when {
|
||||
changeset pattern: "apps/connector/**", comparator: "GLOB"
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
changesDetected = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Install') {
|
||||
when {
|
||||
expression { changesDetected }
|
||||
}
|
||||
steps {
|
||||
dir("${env.WORKSPACE}/apps/connector") {
|
||||
script {
|
||||
nix.shell(
|
||||
'pnpm install --frozen-lockfile',
|
||||
pure: false,
|
||||
entryPoint: "${env.WORKSPACE}/apps/connector/shell.nix"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
when {
|
||||
expression { changesDetected }
|
||||
}
|
||||
steps {
|
||||
dir("${env.WORKSPACE}") {
|
||||
script {
|
||||
nix.shell(
|
||||
'pnpm turbo run build --filter=connector',
|
||||
pure: false,
|
||||
entryPoint: "${env.WORKSPACE}/apps/connector/shell.nix"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Zip') {
|
||||
when {
|
||||
expression { changesDetected }
|
||||
}
|
||||
steps {
|
||||
dir("${env.WORKSPACE}/apps/connector") {
|
||||
zip(
|
||||
zipFile: env.ZIP_NAME,
|
||||
dir: 'build/chrome-mv3-prod',
|
||||
archive: false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Archive') {
|
||||
when {
|
||||
expression { changesDetected }
|
||||
}
|
||||
steps {
|
||||
dir("${env.WORKSPACE}/apps/connector") {
|
||||
archiveArtifacts(
|
||||
artifacts: env.ZIP_NAME,
|
||||
fingerprint: true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Upload') {
|
||||
when {
|
||||
expression { changesDetected }
|
||||
}
|
||||
steps {
|
||||
dir("${env.WORKSPACE}/apps/connector") {
|
||||
script {
|
||||
env.PKG_URL = s5cmd.upload(env.ZIP_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
script {
|
||||
if(changesDetected) {
|
||||
github.notifyPR(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
failure {
|
||||
script {
|
||||
if(changesDetected) {
|
||||
github.notifyPR(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanup { cleanWs() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
### 1. Definitions
|
||||
|
||||
**1.1. “Contributor”**
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
**1.2. “Contributor Version”**
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
**1.3. “Contribution”**
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
**1.4. “Covered Software”**
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
**1.5. “Incompatible With Secondary Licenses”**
|
||||
means
|
||||
|
||||
* **(a)** that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
* **(b)** that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
**1.6. “Executable Form”**
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
**1.7. “Larger Work”**
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
**1.8. “License”**
|
||||
means this document.
|
||||
|
||||
**1.9. “Licensable”**
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
**1.10. “Modifications”**
|
||||
means any of the following:
|
||||
|
||||
* **(a)** any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
* **(b)** any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
**1.11. “Patent Claims” of a Contributor**
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
**1.12. “Secondary License”**
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
**1.13. “Source Code Form”**
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
**1.14. “You” (or “Your”)**
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, “You” includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, “control” means **(a)** the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or **(b)** ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
|
||||
### 2. License Grants and Conditions
|
||||
|
||||
#### 2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
* **(a)** under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
* **(b)** under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
#### 2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
#### 2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
* **(a)** for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
* **(b)** for infringements caused by: **(i)** Your and any other third party's
|
||||
modifications of Covered Software, or **(ii)** the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
* **(c)** under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
#### 2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
#### 2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
#### 2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
#### 2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
|
||||
### 3. Responsibilities
|
||||
|
||||
#### 3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
#### 3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
* **(a)** such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
* **(b)** You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
#### 3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
#### 3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
#### 3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
|
||||
### 4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: **(a)** comply with
|
||||
the terms of this License to the maximum extent possible; and **(b)**
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
|
||||
### 5. Termination
|
||||
|
||||
**5.1.** The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated **(a)** provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and **(b)** on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
**5.2.** If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
|
||||
### 6. Disclaimer of Warranty
|
||||
|
||||
> Covered Software is provided under this License on an “as is”
|
||||
> basis, without warranty of any kind, either expressed, implied, or
|
||||
> statutory, including, without limitation, warranties that the
|
||||
> Covered Software is free of defects, merchantable, fit for a
|
||||
> particular purpose or non-infringing. The entire risk as to the
|
||||
> quality and performance of the Covered Software is with You.
|
||||
> Should any Covered Software prove defective in any respect, You
|
||||
> (not any Contributor) assume the cost of any necessary servicing,
|
||||
> repair, or correction. This disclaimer of warranty constitutes an
|
||||
> essential part of this License. No use of any Covered Software is
|
||||
> authorized under this License except under this disclaimer.
|
||||
|
||||
### 7. Limitation of Liability
|
||||
|
||||
> Under no circumstances and under no legal theory, whether tort
|
||||
> (including negligence), contract, or otherwise, shall any
|
||||
> Contributor, or anyone who distributes Covered Software as
|
||||
> permitted above, be liable to You for any direct, indirect,
|
||||
> special, incidental, or consequential damages of any character
|
||||
> including, without limitation, damages for lost profits, loss of
|
||||
> goodwill, work stoppage, computer failure or malfunction, or any
|
||||
> and all other commercial damages or losses, even if such party
|
||||
> shall have been informed of the possibility of such damages. This
|
||||
> limitation of liability shall not apply to liability for death or
|
||||
> personal injury resulting from such party's negligence to the
|
||||
> extent applicable law prohibits such limitation. Some
|
||||
> jurisdictions do not allow the exclusion or limitation of
|
||||
> incidental or consequential damages, so this exclusion and
|
||||
> limitation may not apply to You.
|
||||
|
||||
|
||||
### 8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
|
||||
### 9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
### 10. Versions of the License
|
||||
|
||||
#### 10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
#### 10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
#### 10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
## Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
## Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
@@ -0,0 +1,104 @@
|
||||
# A wallet connector by Status
|
||||
|
||||
Status Desktop Wallet extended to decentralized applications in your browser.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Depends on:
|
||||
|
||||
- **[Status Desktop](https://github.com/status-im/status-desktop/releases)** >=2.32.x
|
||||
|
||||
Tested with these browsers:
|
||||
|
||||
- Google Chrome
|
||||
- Arc
|
||||
|
||||
## Development
|
||||
|
||||
### Google Chrome
|
||||
|
||||
#### Develop
|
||||
|
||||
```bash
|
||||
pnpm dev:chrome
|
||||
```
|
||||
|
||||
#### Build
|
||||
|
||||
```bash
|
||||
pnpm build:chrome
|
||||
```
|
||||
|
||||
#### Load
|
||||
|
||||
Google Chrome > Window > Extensions > enable Developer mode
|
||||
|
||||
Google Chrome > Window > Extensions > Load unpacked > select build (build/chrome-mv3-dev)
|
||||
|
||||
> Note: Reloads automatically in development.
|
||||
|
||||
### Safari
|
||||
|
||||
#### Develop
|
||||
|
||||
```bash
|
||||
pnpm dev:safari
|
||||
```
|
||||
|
||||
#### Convert
|
||||
|
||||
```bash
|
||||
xcrun safari-web-extension-converter --no-open --macos-only --swift --project-location ./apps --app-name Status --bundle-identifier im.Status.Status ./build/safari-mv3-dev/
|
||||
```
|
||||
|
||||
#### Build
|
||||
|
||||
```bash
|
||||
xcodebuild -project apps/Status/Status.xcodeproj -scheme Status build
|
||||
```
|
||||
|
||||
#### Load
|
||||
|
||||
Safari > Settings... > Developer > Allow unsigned extensions
|
||||
|
||||
Safari > Settings... > Extensions > check Status
|
||||
|
||||
> Note: Does not reload automatically, requires build on change and converting as well if adding new files.
|
||||
|
||||
### Firefox Developer Edition
|
||||
|
||||
#### Develop
|
||||
|
||||
```bash
|
||||
pnpm dev:firefox
|
||||
```
|
||||
|
||||
#### Build
|
||||
|
||||
```bash
|
||||
pnpm build:firefox
|
||||
```
|
||||
|
||||
#### Load
|
||||
|
||||
https://support.mozilla.org/en-US/kb/add-on-signing-in-firefox#w_what-are-my-options-if-i-want-to-use-an-unsigned-add-on-advanced-users
|
||||
|
||||
Firefox Developer Edition > Tools > Add-ons and Themes > click on gear icon (Tools for all add-ons) > Install Add-on From File... > select build (build/firefox-mv3-prod.zip)
|
||||
|
||||
> Note: Does not reload automatically, requires build and load on change.
|
||||
|
||||
### Status Desktop
|
||||
|
||||
#### Run
|
||||
|
||||
##### macOS
|
||||
|
||||
```bash
|
||||
FLAG_CONNECTOR_ENABLED=1 '/Volumes/Status Desktop/Status.app/Contents/MacOS/nim_status_client'
|
||||
```
|
||||
|
||||
> Tip: Point to the installer package location without dropping and replacing current app.
|
||||
|
||||
## Testing
|
||||
|
||||
Download latest build from last merged PR or build from source. To use the extension see the load steps from [Development](#development) section.
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 91 KiB |
@@ -0,0 +1,41 @@
|
||||
import configs, { tailwindcssConfigs } from '@status-im/eslint-config'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
...configs,
|
||||
...tailwindcssConfigs,
|
||||
{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
rules: {
|
||||
'no-constant-binary-expression': 'error',
|
||||
'no-restricted-globals': ['error', 'process'],
|
||||
'jsx-a11y/alt-text': [
|
||||
1,
|
||||
{
|
||||
img: [],
|
||||
},
|
||||
],
|
||||
'no-empty': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.mjs'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.js'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ['.plasmo'],
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { Provider } from './src/contents/provider'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
ethereum: Provider
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"name": "connector",
|
||||
"version": "0.0.2",
|
||||
"license": "MPL-2.0",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/status-im/status-web.git",
|
||||
"directory": "apps/connector"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"dev:chrome": "plasmo dev --target=chrome-mv3",
|
||||
"dev:safari": "plasmo dev --target=safari-mv3",
|
||||
"dev:firefox": "plasmo dev --target=firefox-mv3",
|
||||
"build": "pnpm build:chrome",
|
||||
"build:chrome": "plasmo build --target=chrome-mv3",
|
||||
"build:firefox": "plasmo build --target=firefox-mv3 --zip",
|
||||
"lint": "eslint src",
|
||||
"format": "prettier --write .",
|
||||
"package": "plasmo package",
|
||||
"clean": "rimraf apps build .plasmo node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@plasmohq/messaging": "^0.6.2",
|
||||
"@plasmohq/storage": "^1.11.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-switch": "^1.1.0",
|
||||
"@status-im/colors": "workspace:*",
|
||||
"cva": "^1.0.0-beta.1",
|
||||
"ethers": "^6.13.0",
|
||||
"plasmo": "0.88.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"ts-pattern": "^5.2.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ianvs/prettier-plugin-sort-imports": "4.1.1",
|
||||
"@parcel/bundler-experimental": "^2.7.0",
|
||||
"@status-im/eslint-config": "workspace:*",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"@types/chrome": "0.0.258",
|
||||
"@types/node": "20.11.5",
|
||||
"@types/react": "18.2.48",
|
||||
"@types/react-dom": "18.2.18",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"husky": "^8.0.3",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "3.2.4",
|
||||
"prettier-plugin-tailwindcss": "^0.6.1",
|
||||
"rimraf": "^4.4.1",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-scrollbar-utilities": "^0.2.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"manifest": {
|
||||
"manifest_version": 3,
|
||||
"name": "A wallet connector by Status",
|
||||
"description": "Status Desktop Wallet extended to decentralised applications in your browser.",
|
||||
"externally_connectable": {
|
||||
"ids": [],
|
||||
"matches": []
|
||||
},
|
||||
"host_permissions": [
|
||||
"https://*/*"
|
||||
],
|
||||
"permissions": [
|
||||
"storage"
|
||||
],
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "no-reply@status.im"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx,js,jsx,mjs}": [
|
||||
"eslint",
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{yml,yaml,json}": [
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
source ? builtins.fetchTarball {
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/df27247e6f3e636c119e2610bf12d38b5e98cc79.tar.gz";
|
||||
sha256 = "sha256:0bbvimk7xb7akrx106mmsiwf9nzxnssisqmqffla03zz51d0kz2n";
|
||||
},
|
||||
pkgs ? import (source) {}
|
||||
}:
|
||||
|
||||
pkgs.mkShell {
|
||||
name = "browser-extension-shell";
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
nodejs_20
|
||||
pnpm
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Storage } from '@plasmohq/storage'
|
||||
import iconConnected from 'url:../assets/icon-connected.png' // eslint-disable-line import/no-unresolved
|
||||
import iconDisconnected from 'url:../assets/icon-disconnected.png' // eslint-disable-line import/no-unresolved
|
||||
|
||||
import { config } from '~config'
|
||||
|
||||
import type { ServiceWorkerMessage } from '~messages/service-worker-message'
|
||||
|
||||
/**
|
||||
* Check if the WebSocket server is reachable
|
||||
*/
|
||||
const storage = new Storage()
|
||||
|
||||
const DESKTOP_ENDPOINT_URL = config.desktop.rpc.url.replace('ws:', 'http:')
|
||||
const CHECK_INTERVAL_MS = 5000
|
||||
|
||||
const isWebSocketServerReachable = async (): Promise<boolean> => {
|
||||
try {
|
||||
await fetch(DESKTOP_ENDPOINT_URL, { method: 'HEAD' })
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function checkDesktopStatus() {
|
||||
const isServerReachable = await isWebSocketServerReachable()
|
||||
storage.set('status:desktop:running', isServerReachable)
|
||||
chrome.action.setIcon({
|
||||
path: isServerReachable ? iconConnected : iconDisconnected,
|
||||
})
|
||||
}
|
||||
|
||||
checkDesktopStatus()
|
||||
setInterval(checkDesktopStatus, CHECK_INTERVAL_MS)
|
||||
|
||||
/**
|
||||
* Handler for opening popup
|
||||
*/
|
||||
chrome.action.onClicked.addListener(async tab => {
|
||||
if (!tab.id || !tab.url) {
|
||||
return
|
||||
}
|
||||
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
type: 'status:icon:clicked',
|
||||
} satisfies ServiceWorkerMessage)
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
import { useLocalStorage } from '~hooks/use-local-storage'
|
||||
import { getFaviconUrl } from '~lib/get-favicon-url'
|
||||
|
||||
import { Network } from './network'
|
||||
import { Switch } from './switch'
|
||||
|
||||
const Connected = () => {
|
||||
const [defaultWallet, setDefaultWallet] = useLocalStorage(
|
||||
'status:default-wallet',
|
||||
true,
|
||||
)
|
||||
const [, setReopen] = useLocalStorage('status:popup:reopen', false)
|
||||
|
||||
const dappUrl = window.location.hostname
|
||||
const dappIcon = getFaviconUrl()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-5 flex flex-col gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{/* fixme: set default favicon `onerror` */}
|
||||
{dappIcon ? (
|
||||
<img src={dappIcon} alt="icon" className="size-8 rounded-full" />
|
||||
) : (
|
||||
<div className="size-8 rounded-full bg-neutral-5" />
|
||||
)}
|
||||
<div className="text-27 font-semibold">{dappUrl}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<Network />
|
||||
|
||||
<div className="flex items-center gap-2 rounded-2xl border border-neutral-20 bg-neutral-2.5 px-4 py-3">
|
||||
<div className="flex-1">
|
||||
<div className="text-15 font-medium text-neutral-100">
|
||||
Set as default wallet
|
||||
</div>
|
||||
<div className="text-13 font-regular text-neutral-50">
|
||||
Launch Status (Desktop) when connecting to dApps with MetaMask or
|
||||
other wallets
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={defaultWallet}
|
||||
onCheckedChange={checked => {
|
||||
setDefaultWallet(checked)
|
||||
setReopen(true)
|
||||
window.location.reload()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export { Connected }
|
||||
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
Root,
|
||||
Trigger,
|
||||
} from '@radix-ui/react-dropdown-menu'
|
||||
import { cx } from 'cva'
|
||||
|
||||
type Props = {
|
||||
children: [React.ReactElement, React.ReactElement]
|
||||
modal?: boolean
|
||||
onOpenChange?: (open: boolean) => void
|
||||
}
|
||||
|
||||
const DropdownMenu = (props: Props) => {
|
||||
const { children, onOpenChange, modal } = props
|
||||
|
||||
const [trigger, content] = children
|
||||
|
||||
return (
|
||||
<Root onOpenChange={onOpenChange} modal={modal}>
|
||||
<Trigger asChild>{trigger}</Trigger>
|
||||
{content}
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
type DropdownMenuItemProps = {
|
||||
label: string
|
||||
onSelect: () => void
|
||||
}
|
||||
|
||||
const MenuItem = (props: DropdownMenuItemProps) => {
|
||||
const { label, onSelect } = props
|
||||
|
||||
return (
|
||||
<ItemBase onSelect={onSelect}>
|
||||
<div className="flex items-center gap-8">
|
||||
<p className="text-15 font-medium text-neutral-100">{label}</p>
|
||||
</div>
|
||||
</ItemBase>
|
||||
)
|
||||
}
|
||||
|
||||
const Content = (props: React.ComponentProps<typeof DropdownMenuContent>) => {
|
||||
return (
|
||||
<DropdownMenuContent
|
||||
{...props}
|
||||
className={cx('w-64 p-1 rounded-xl bg-white-100', 'shadow-3 ')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const ItemBase = (props: React.ComponentProps<typeof DropdownMenuItem>) => {
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
{...props}
|
||||
className="flex h-8 cursor-pointer select-none items-center justify-between gap-2 rounded-[10px] px-2 transition-colors hover:bg-neutral-5"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const Separator = (
|
||||
props: React.ComponentProps<typeof DropdownMenuSeparator>,
|
||||
) => {
|
||||
return (
|
||||
<DropdownMenuSeparator
|
||||
{...props}
|
||||
className="mx-[-4px] my-1 h-px bg-neutral-10"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu.Content = Content
|
||||
DropdownMenu.Item = MenuItem
|
||||
DropdownMenu.Separator = Separator
|
||||
|
||||
export { DropdownMenu }
|
||||
export type DropdownMenuProps = Omit<Props, 'children'>
|
||||
@@ -0,0 +1,93 @@
|
||||
import { cx } from 'cva'
|
||||
|
||||
import { config } from '~config'
|
||||
|
||||
import { DropdownMenu } from './dropdown-menu'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
function downloadUrl(dataurl: string) {
|
||||
const link = document.createElement('a')
|
||||
link.href = dataurl
|
||||
link.target = '_blank'
|
||||
link.click()
|
||||
}
|
||||
|
||||
const MacOsPicker = (props: Props) => {
|
||||
const { children, className } = props
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<button
|
||||
className={cx(
|
||||
'group flex items-center justify-center gap-1 whitespace-nowrap rounded-xl border text-center text-15 font-medium leading-normal outline-none transition-all',
|
||||
'h-10 px-3',
|
||||
'border-neutral-30 bg-white-100 text-neutral-100 hover:border-neutral-40 active:border-neutral-50',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<span className="-mt-px">
|
||||
<svg
|
||||
color="rgba(9 16 28 / 100%)"
|
||||
width="20"
|
||||
height="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 20 20"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill="rgba(9 16 28 / 100%)"
|
||||
d="M14.357 10c.023 2.422 2.12 3.227 2.143 3.238-.018.056-.335 1.148-1.105 2.275-.665.975-1.356 1.946-2.444 1.966-1.069.02-1.413-.635-2.635-.635-1.222 0-1.604.615-2.616.655-1.05.04-1.85-1.054-2.52-2.025-1.371-1.987-2.42-5.613-1.012-8.062.699-1.215 1.948-1.985 3.303-2.005 1.031-.02 2.005.695 2.635.695.63 0 1.813-.86 3.056-.733.521.022 1.982.21 2.92 1.587-.075.047-1.743 1.02-1.725 3.044Zm-2.009-5.945c.558-.677.933-1.618.83-2.555-.803.032-1.775.537-2.351 1.213-.517.598-.97 1.556-.847 2.475.895.069 1.81-.457 2.368-1.133Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
{children}
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
className="-ml-1 transition-transform duration-200 group-aria-expanded:rotate-180"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z"
|
||||
fill="#E7EAEE"
|
||||
fillOpacity={1}
|
||||
/>
|
||||
<path
|
||||
d="M7 8.5L10 11.5L13 8.5"
|
||||
stroke={'#09101C'}
|
||||
strokeWidth="1.2"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<DropdownMenu.Content
|
||||
align="start"
|
||||
sideOffset={8}
|
||||
className="[&>div]:outline-none"
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
label="Apple Silicon"
|
||||
onSelect={() =>
|
||||
downloadUrl(config.desktop.downloadUrls.macos.silicon)
|
||||
}
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
label="Intel"
|
||||
onSelect={() => downloadUrl(config.desktop.downloadUrls.macos.intel)}
|
||||
/>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
export { MacOsPicker }
|
||||
@@ -0,0 +1,39 @@
|
||||
import arbitrumImage from 'url:../../assets/network/arbitrum.webp'
|
||||
import mainnetImage from 'url:../../assets/network/mainnet.webp'
|
||||
import optimismImage from 'url:../../assets/network/optimism.webp'
|
||||
|
||||
const Network = () => {
|
||||
return (
|
||||
<div className="flex h-[64px] items-center rounded-2xl border border-neutral-10 bg-white-100 px-4">
|
||||
<div className="flex w-full items-center">
|
||||
<div className="flex flex-1 flex-col">
|
||||
<div className="text-13 font-regular text-neutral-50">
|
||||
Supported networks
|
||||
</div>
|
||||
<div className="text-15 font-medium text-neutral-100">
|
||||
Mainnet, Optimism, Arbitrum
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<img
|
||||
className="box-content size-6 rounded-full border border-white-100"
|
||||
src={mainnetImage}
|
||||
alt="Mainnet"
|
||||
/>
|
||||
<img
|
||||
className="ml-[-5px] box-content size-6 rounded-full border border-white-100"
|
||||
src={optimismImage}
|
||||
alt="Optimism"
|
||||
/>
|
||||
<img
|
||||
className="ml-[-5px] box-content size-6 rounded-full border border-white-100"
|
||||
src={arbitrumImage}
|
||||
alt="Arbitrum"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { Network }
|
||||
@@ -0,0 +1,21 @@
|
||||
import unableToConnectImage from 'url:../../assets/unable-to-connect.png'
|
||||
|
||||
import { DownloadButton } from './download-button'
|
||||
|
||||
const NotConnected = () => {
|
||||
return (
|
||||
<div className="flex flex-col items-center">
|
||||
<img src={unableToConnectImage} alt="Not connected" className="w-full" />
|
||||
<div className="max-w-[304px] pb-5 pt-4 text-center">
|
||||
<p className="text-19 font-semibold">Unable to connect to Status</p>
|
||||
<p className="text-15">
|
||||
Make sure Status desktop app is running on your machine or download it
|
||||
below.
|
||||
</p>
|
||||
</div>
|
||||
<DownloadButton />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { NotConnected }
|
||||
@@ -0,0 +1,58 @@
|
||||
import { useStorage } from '@plasmohq/storage/hook'
|
||||
|
||||
const PinInstructions = () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [_showPinInstructions, setShowPinInstructions] = useStorage(
|
||||
'show-pin-instructions',
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="-mx-5 mt-8 flex items-center gap-2 border-t border-neutral-80/5 px-4 pt-3">
|
||||
<div className="flex-1">
|
||||
<div className="text-15 font-semibold text-neutral-100">
|
||||
Pin the extension
|
||||
</div>
|
||||
<div className="flex items-center gap-1 text-13 font-regular">
|
||||
Click <PuzzleIcon /> and then <PinIcon /> and voilà!
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="group inline-flex h-8 items-center justify-center gap-1 whitespace-nowrap rounded-xl border border-neutral-30 bg-white-100 px-3 text-center text-15 font-medium leading-normal text-neutral-100 outline-none transition-all hover:border-neutral-40 active:border-neutral-50"
|
||||
onClick={() => setShowPinInstructions(false)}
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { PinInstructions }
|
||||
|
||||
const PuzzleIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none">
|
||||
<path
|
||||
fill="#09101C"
|
||||
fillRule="evenodd"
|
||||
d="M7.5 2.6a.9.9 0 0 0-.9.9v.6H5V2.9h.487a2.1 2.1 0 0 1 4.026 0h.611c.4 0 .735 0 1.01.023.287.023.56.074.82.206a2.1 2.1 0 0 1 .917.918c.132.26.183.532.207.82.022.274.022.61.022 1.01v.61a2.1 2.1 0 0 1 0 4.026v.612c0 .4 0 .735-.022 1.01-.024.287-.075.56-.207.819a2.1 2.1 0 0 1-.918.918c-.259.132-.532.183-.819.206-.275.023-.61.023-1.01.023H4.876c-.4 0-.735 0-1.01-.023-.287-.023-.56-.074-.82-.206a2.1 2.1 0 0 1-.917-.918c-.132-.26-.183-.532-.207-.82-.022-.274-.022-.61-.022-1.01V9.4h.6a.9.9 0 1 0 0-1.8h-.6V5.876c0-.4 0-.735.022-1.01.024-.287.075-.56.207-.819a2.1 2.1 0 0 1 .918-.918c.259-.132.532-.183.819-.206.275-.022.61-.022 1.01-.022H5v1.2h-.1c-.43 0-.716 0-.936.018-.213.017-.31.048-.373.08a.9.9 0 0 0-.393.393c-.031.062-.062.16-.08.372-.018.22-.018.507-.018.937v.586a2.1 2.1 0 0 1 0 4.026v.588c0 .43 0 .716.018.936.018.213.049.31.08.372a.9.9 0 0 0 .393.393c.062.032.16.063.373.08.22.018.506.018.936.018h5.2c.43 0 .716 0 .936-.018.213-.017.31-.048.373-.08a.9.9 0 0 0 .393-.393c.031-.062.062-.16.08-.372.017-.22.018-.507.018-.937V9.4h.6a.9.9 0 1 0 0-1.8h-.6V5.9c0-.43 0-.716-.018-.936-.018-.213-.049-.31-.08-.372a.9.9 0 0 0-.393-.393c-.062-.032-.16-.063-.373-.08-.22-.018-.506-.018-.936-.018H8.4v-.6a.9.9 0 0 0-.9-.9Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const PinIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none">
|
||||
<g clipPath="url(#a)">
|
||||
<path
|
||||
fill="#09101C"
|
||||
fillRule="evenodd"
|
||||
d="M6.657 5.955c.497-.86.897-1.491 1.25-1.942.355-.454.625-.677.846-.78.377-.176.821-.097 1.932.545 1.111.641 1.402.986 1.439 1.4.02.243-.037.59-.253 1.124-.214.53-.56 1.193-1.057 2.053l-.073.126-.007.145-.173 3.53L3.58 8.123l2.896-1.973.113-.077.069-.119Zm4.628-3.217c-1.054-.608-2.033-1.062-3.04-.593-.47.22-.88.613-1.284 1.129-.387.495-.8 1.147-1.274 1.962L2.114 7.67l-.789.538.827.478 3.744 2.161-1.886 3.114h1.5l1.438-2.506 3.864 2.23.852.492.048-.981.214-4.367c.467-.815.823-1.497 1.058-2.078.245-.607.38-1.16.335-1.677-.097-1.105-.98-1.727-2.034-2.336Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="a">
|
||||
<path fill="#fff" d="M0 0h16v16H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
@@ -0,0 +1,66 @@
|
||||
import { cva } from 'cva'
|
||||
import { match } from 'ts-pattern'
|
||||
|
||||
type Props = {
|
||||
status: 'on' | 'off'
|
||||
}
|
||||
|
||||
const styles = cva({
|
||||
base: 'flex h-6 items-center gap-1 rounded-[20px] border px-2 text-13',
|
||||
variants: {
|
||||
status: {
|
||||
on: 'border-success-50/20 bg-success-50/10 text-success-60',
|
||||
off: 'border-danger-50/20 bg-danger-50/10 text-danger-60',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const StatusTag = (props: Props) => {
|
||||
const { status } = props
|
||||
|
||||
return (
|
||||
<div className={styles({ status })}>
|
||||
{match(status)
|
||||
.with('on', () => (
|
||||
<>
|
||||
<svg
|
||||
width={12}
|
||||
height={12}
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8 1.5l-1.5 3H10L4.5 10 5 7H2l2.5-5.5H8z"
|
||||
stroke="#1C8A80"
|
||||
strokeWidth={1.1}
|
||||
/>
|
||||
</svg>
|
||||
<span className="text-success-60">Status desktop running</span>
|
||||
</>
|
||||
))
|
||||
.with('off', () => (
|
||||
<>
|
||||
<svg
|
||||
width={12}
|
||||
height={12}
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5.45 1v4.5h1.1V1h-1.1zm2.525 1.58a3.95 3.95 0 11-3.95 0l-.55-.954a5.05 5.05 0 105.05 0l-.55.953z"
|
||||
fill="#BA434D"
|
||||
/>
|
||||
</svg>
|
||||
<span className="text-danger-60">Status desktop not running</span>
|
||||
</>
|
||||
))
|
||||
.exhaustive()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { StatusTag }
|
||||
@@ -0,0 +1,20 @@
|
||||
import * as BaseSwitch from '@radix-ui/react-switch'
|
||||
|
||||
type Props = {
|
||||
checked: boolean
|
||||
onCheckedChange: (checked: boolean) => void
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const Switch = (props: Props) => {
|
||||
return (
|
||||
<BaseSwitch.Root
|
||||
className="relative h-[20px] w-[30px] cursor-default rounded-full bg-neutral-30 outline-none data-[disabled]:cursor-not-allowed data-[state=checked]:bg-customisation-blue-50 data-[disabled]:opacity-30"
|
||||
{...props}
|
||||
>
|
||||
<BaseSwitch.Thumb className="block size-[16px] translate-x-0.5 rounded-full bg-white-100 transition-transform duration-100 will-change-transform data-[state=checked]:translate-x-[12px]" />
|
||||
</BaseSwitch.Root>
|
||||
)
|
||||
}
|
||||
|
||||
export { Switch }
|
||||
@@ -0,0 +1,17 @@
|
||||
export const config = {
|
||||
desktop: {
|
||||
rpc: {
|
||||
url: 'ws://localhost:8586',
|
||||
method: 'connector_callRPC',
|
||||
},
|
||||
downloadUrls: {
|
||||
macos: {
|
||||
silicon:
|
||||
'https://status.app/api/download/macos-silicon?source=connector',
|
||||
intel: 'https://status.app/api/download/macos-intel?source=connector',
|
||||
},
|
||||
windows: 'https://status.app/api/download/windows?source=connector',
|
||||
linux: 'https://status.app/api/download/linux?source=connector',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url(data-base64:../../assets/fonts/Inter.woff2) format('woff2');
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { useStorage } from '@plasmohq/storage/hook'
|
||||
import styleText from 'data-text:../style.css' // eslint-disable-line import/no-unresolved
|
||||
import logoSrc from 'url:../../assets/logo.png'
|
||||
|
||||
import { Connected } from '~components/connected'
|
||||
import { NotConnected } from '~components/not-connected'
|
||||
import { PinInstructions } from '~components/pin-instructions'
|
||||
import { StatusTag } from '~components/status-tag'
|
||||
import { useLocalStorage } from '~hooks/use-local-storage'
|
||||
import { useOutsideClick } from '~hooks/use-outside-click'
|
||||
import { ServiceWorkerMessage } from '~messages/service-worker-message'
|
||||
|
||||
import type { PlasmoGetStyle } from 'plasmo'
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => {
|
||||
const style = document.createElement('style')
|
||||
style.textContent = styleText
|
||||
return style
|
||||
}
|
||||
|
||||
type MessageHandler = Parameters<typeof chrome.runtime.onMessage.addListener>[0]
|
||||
|
||||
export default function Popup() {
|
||||
const [connected] = useStorage('status:desktop:running')
|
||||
const [showPinInstructions] = useStorage('show-pin-instructions', true)
|
||||
|
||||
const [reopen, setReopen] = useLocalStorage('status:popup:reopen', false)
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const handleOutsideClick = useCallback(() => setOpen(false), [])
|
||||
|
||||
useOutsideClick(containerRef, handleOutsideClick)
|
||||
|
||||
useEffect(() => {
|
||||
const handleMessage: MessageHandler = (message: ServiceWorkerMessage) => {
|
||||
try {
|
||||
message = ServiceWorkerMessage.parse(message)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
if (message.type === 'status:icon:clicked') {
|
||||
setOpen(open => !open)
|
||||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(handleMessage)
|
||||
|
||||
return () => {
|
||||
chrome.runtime.onMessage.removeListener(handleMessage)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (reopen) {
|
||||
setOpen(true)
|
||||
setReopen(false)
|
||||
}
|
||||
}, [reopen, setReopen])
|
||||
|
||||
if (!open) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="fixed right-2 top-2 max-w-[390px] overflow-hidden rounded-3xl"
|
||||
>
|
||||
<div className="grid w-full grid-rows-[auto,1fr] rounded-3xl bg-neutral-100">
|
||||
{/* Bar */}
|
||||
<div className="flex items-center justify-between px-5 py-3">
|
||||
<img src={logoSrc} alt="Status" className="size-8" />
|
||||
<StatusTag status={connected ? 'on' : 'off'} />
|
||||
</div>
|
||||
|
||||
<div className="mx-1 mb-1 overflow-hidden rounded-[20px] bg-white-100 p-5">
|
||||
{connected ? <Connected /> : <NotConnected />}
|
||||
{showPinInstructions && <PinInstructions />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
import { ProviderRpcError } from '~lib/provider-rpc-error'
|
||||
import { RequestArguments } from '~lib/request-arguments'
|
||||
import { ProxyMessage } from '~messages/proxy-message'
|
||||
|
||||
import type { ProviderMessage } from '~messages/provider-message'
|
||||
import type { PlasmoCSConfig } from 'plasmo'
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ['https://*/*'],
|
||||
world: 'MAIN',
|
||||
run_at: 'document_start',
|
||||
all_frames: false,
|
||||
}
|
||||
|
||||
type Event =
|
||||
| 'connect'
|
||||
| 'connected'
|
||||
| 'disconnect'
|
||||
| 'close'
|
||||
| 'error'
|
||||
| 'chainChanged'
|
||||
| 'accountsChanged'
|
||||
| 'networkChanged'
|
||||
|
||||
/**
|
||||
* @see https://eips.ethereum.org/EIPS/eip-1193 for spec
|
||||
*/
|
||||
export class Provider {
|
||||
#listeners: Map<Event, (...args: unknown[]) => void>
|
||||
|
||||
/**
|
||||
* @see https://github.com/snapshot-labs/lock/blob/503f4b07f1b631b1eed0dca993110dc561189261/src/utils.ts for other examples
|
||||
*/
|
||||
public isStatus: boolean
|
||||
|
||||
public isMetaMask: boolean
|
||||
public _metamask: {
|
||||
isUnlocked: () => Promise<true>
|
||||
} | null
|
||||
|
||||
// public isCoinbaseWallet: boolean
|
||||
public qrUrl: null
|
||||
|
||||
public autoRefreshOnNetworkChange: boolean
|
||||
|
||||
public provider: Record<string, unknown> | null
|
||||
|
||||
public __isProvider: boolean
|
||||
|
||||
public connected: boolean
|
||||
|
||||
constructor() {
|
||||
this.isStatus = true
|
||||
this.isMetaMask = false
|
||||
this._metamask = null
|
||||
// this.isCoinbaseWallet = false
|
||||
this.qrUrl = null
|
||||
this.autoRefreshOnNetworkChange = false
|
||||
this.provider = null
|
||||
this.__isProvider = false
|
||||
this.connected = false
|
||||
this.#listeners = new Map()
|
||||
}
|
||||
|
||||
public async request(args: RequestArguments) {
|
||||
try {
|
||||
args = RequestArguments.parse(args)
|
||||
} catch {
|
||||
throw new ProviderRpcError({
|
||||
code: -32602,
|
||||
message: 'Invalid request arguments',
|
||||
})
|
||||
}
|
||||
|
||||
await waitUntilComplete(document)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const { method, params } = args
|
||||
|
||||
const messageChannel = new MessageChannel()
|
||||
|
||||
messageChannel.port1.onmessage = ({ data }) => {
|
||||
try {
|
||||
const message = ProxyMessage.parse(data)
|
||||
|
||||
messageChannel.port1.close()
|
||||
|
||||
// note: method side-effects
|
||||
switch (message.type) {
|
||||
case 'status:proxy:success': {
|
||||
if (
|
||||
(method === 'eth_requestAccounts' ||
|
||||
method === 'eth_accounts') &&
|
||||
!this.connected
|
||||
) {
|
||||
this.#listeners.get('connect')?.({ chainId: '0x1' })
|
||||
this.#listeners.get('connected')?.({ chainId: '0x1' })
|
||||
this.connected = true
|
||||
}
|
||||
|
||||
if (method === 'wallet_switchEthereumChain') {
|
||||
this.#listeners.get('chainChanged')?.(message.data)
|
||||
this.#listeners.get('networkChanged')?.(message.data)
|
||||
}
|
||||
|
||||
resolve(message.data)
|
||||
|
||||
return
|
||||
}
|
||||
case 'status:proxy:error': {
|
||||
// note: for those dApps that make call after having permissions revoked
|
||||
if (
|
||||
message.error.message === 'dApp is not permitted by user' &&
|
||||
this.connected
|
||||
) {
|
||||
this.disconnect()
|
||||
}
|
||||
|
||||
reject(new ProviderRpcError(message.error))
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// we don't reject here because incoming message is not from the proxy
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const providerMessage: ProviderMessage = {
|
||||
type: 'status:provider',
|
||||
data: {
|
||||
method,
|
||||
params,
|
||||
},
|
||||
}
|
||||
|
||||
window.postMessage(providerMessage, window.origin, [messageChannel.port2])
|
||||
})
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public async send(...args: unknown[]): Promise<unknown> {
|
||||
return await this.request({
|
||||
method: args[0] as string,
|
||||
params: args[1] as Record<string, unknown>,
|
||||
})
|
||||
}
|
||||
|
||||
public on(event: Event, handler: (args: unknown) => void): void {
|
||||
this.#listeners.set(event, handler)
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public async close(): Promise<void> {
|
||||
this.disconnect()
|
||||
}
|
||||
|
||||
public removeListener(event: Event): void {
|
||||
// note: not all dapps remove these on disconnect
|
||||
if (event === 'close' || event === 'disconnect') {
|
||||
this.disconnect()
|
||||
}
|
||||
|
||||
this.#listeners.delete(event)
|
||||
}
|
||||
|
||||
public async enable() {
|
||||
return true
|
||||
}
|
||||
|
||||
private async disconnect() {
|
||||
if (!this.connected) {
|
||||
return
|
||||
}
|
||||
|
||||
this.connected = false
|
||||
|
||||
await this.request({
|
||||
method: 'wallet_revokePermissions',
|
||||
params: [
|
||||
{
|
||||
eth_accounts: {},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
window.postMessage(
|
||||
{
|
||||
type: 'status:provider:disconnect',
|
||||
} satisfies ProviderMessage,
|
||||
window.origin,
|
||||
)
|
||||
|
||||
this.#listeners.get('disconnect')?.()
|
||||
this.#listeners.get('close')?.()
|
||||
this.#listeners.clear()
|
||||
}
|
||||
}
|
||||
|
||||
const provider = new Provider()
|
||||
|
||||
/**
|
||||
* @see https://eips.ethereum.org/EIPS/eip-6963 for spec
|
||||
*/
|
||||
function announceProvider() {
|
||||
const info = {
|
||||
uuid: 'c14d6a7e-14c2-477d-bcb7-ffb732145eae',
|
||||
name: 'Status',
|
||||
icon: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzk1MF8xMjM5NikiPiA8bWFzayBpZD0ibWFzazBfOTUwXzEyMzk2IiBzdHlsZT0ibWFzay10eXBlOmFscGhhIiBtYXNrVW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4PSIwIiB5PSItMSIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMzIj4gPHBhdGggZD0iTTE2IC0wLjAwMDQ4ODI4MUM0IC0wLjAwMDQ4ODI4MSAwIDMuOTk5NTEgMCAxNS45OTk1QzAgMjcuOTk5NSA0IDMxLjk5OTUgMTYgMzEuOTk5NUMyOCAzMS45OTk1IDMyIDI3Ljk5OTUgMzIgMTUuOTk5NUMzMiAzLjk5OTUxIDI4IC0wLjAwMDQ4ODI4MSAxNiAtMC4wMDA0ODgyODFaIiBmaWxsPSJ3aGl0ZSIvPiA8L21hc2s+IDxnIG1hc2s9InVybCgjbWFzazBfOTUwXzEyMzk2KSI+IDxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2ZfOTUwXzEyMzk2KSI+IDxjaXJjbGUgY3g9IjIzIiBjeT0iOC45OTk1MSIgcj0iMTkiIGZpbGw9IiMxOTkyRDciLz4gPC9nPiA8ZyBmaWx0ZXI9InVybCgjZmlsdGVyMV9mXzk1MF8xMjM5NikiPiA8Y2lyY2xlIGN4PSIzMyIgY3k9IjE4Ljk5OTUiIHI9IjE5IiBmaWxsPSIjRjZCMDNDIi8+IDwvZz4gPGcgZmlsdGVyPSJ1cmwoI2ZpbHRlcjJfZl85NTBfMTIzOTYpIj4gPGNpcmNsZSBjeD0iNSIgY3k9IjMwLjk5OTUiIHI9IjE5IiBmaWxsPSIjRkY3RDQ2Ii8+IDwvZz4gPGcgZmlsdGVyPSJ1cmwoI2ZpbHRlcjNfZl85NTBfMTIzOTYpIj4gPGNpcmNsZSBjeD0iLTciIGN5PSI4Ljk5OTUxIiByPSIxOSIgZmlsbD0iIzcxNDBGRCIvPiA8L2c+IDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTguMTI4NCA4LjgwODQzQzE0Ljk1NTEgOC45ODk4NCAxMi42MTIxIDExLjg3NDMgMTIuMzUxNiAxNS4xMzc1QzEyLjM2NzYgMTUuMTMyNiAxMi4zODUzIDE1LjEyNzYgMTIuNDAzIDE1LjEyMjdDMTIuNDIwNyAxNS4xMTc4IDEyLjQzODQgMTUuMTEyOSAxMi40NTQ0IDE1LjEwOEMxMi44NTM1IDE1LjAwNjcgMTMuMjYxNyAxNC45NDUyIDEzLjY3MzEgMTQuOTI0M0MxNC41NjQxIDE0Ljg3NDUgMTUuMjg4NyAxNC45NTE2IDE2LjAxMzIgMTUuMDI4OEMxNi43Mzg3IDE1LjEwNiAxNy40NjQgMTUuMTgzMiAxOC4zNTYyIDE1LjEzMjlDMTguNzY1OCAxNS4xMTEzIDE5LjE3MjIgMTUuMDQ3OSAxOS41Njg4IDE0Ljk0NEMyMS4yNDc2IDE0LjUwODYgMjIuMjEzNSAxMy4zNzQgMjIuMTI4MiAxMS44MTkxQzIyLjAyMzEgOS44ODcwOCAyMC4wNzY5IDguNjk3MzIgMTguMTI4NCA4LjgwODQzWk0xMy44Nzk2IDIzLjE5MDlDMTcuMDUyOSAyMy4wMDk1IDE5LjM5NTkgMjAuMTI1IDE5LjY1NjQgMTYuODYxOEMxOS42MzYzIDE2Ljg2OCAxOS42MTM1IDE2Ljg3NDIgMTkuNTkxNSAxNi44ODAxQzE5LjU3ODQgMTYuODgzNyAxOS41NjU1IDE2Ljg4NzIgMTkuNTUzNiAxNi44OTA1QzE5LjE1NDUgMTYuOTkxOSAxOC43NDYyIDE3LjA1MzQgMTguMzM0OCAxNy4wNzQyQzE3LjQ0MjcgMTcuMTI0OSAxNi43MTczIDE3LjA0NzkgMTUuOTkxOSAxNi45NzA4QzE1LjI2NzQgMTYuODkzOCAxNC41NDI4IDE2LjgxNjkgMTMuNjUxOCAxNi44NjcxQzEzLjI0MjEgMTYuODg4OCAxMi44MzU4IDE2Ljk1MjEgMTIuNDM5MiAxNy4wNTYxQzEwLjc2MDMgMTcuNDkwNyA5Ljc5ODI5IDE4LjYyNTMgOS44Nzk3OSAyMC4xODAyQzkuOTg0OTEgMjIuMTEyMiAxMS45MzExIDIzLjMwMiAxMy44Nzk2IDIzLjE5MDlaIiBmaWxsPSJ3aGl0ZSIvPiA8L2c+IDwvZz4gPGRlZnM+IDxmaWx0ZXIgaWQ9ImZpbHRlcjBfZl85NTBfMTIzOTYiIHg9Ii01LjQzMDI2IiB5PSItMTkuNDMwNyIgd2lkdGg9IjU2Ljg2MDUiIGhlaWdodD0iNTYuODYwNSIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPiA8ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPiA8ZmVCbGVuZCBtb2RlPSJub3JtYWwiIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPiA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI0LjcxNTEzIiByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfOTUwXzEyMzk2Ii8+IDwvZmlsdGVyPiA8ZmlsdGVyIGlkPSJmaWx0ZXIxX2ZfOTUwXzEyMzk2IiB4PSI0LjU2OTc0IiB5PSItOS40MzA3NSIgd2lkdGg9IjU2Ljg2MDUiIGhlaWdodD0iNTYuODYwNSIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPiA8ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPiA8ZmVCbGVuZCBtb2RlPSJub3JtYWwiIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPiA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI0LjcxNTEzIiByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfOTUwXzEyMzk2Ii8+IDwvZmlsdGVyPiA8ZmlsdGVyIGlkPSJmaWx0ZXIyX2ZfOTUwXzEyMzk2IiB4PSItMjMuNDMwMyIgeT0iMi41NjkyNSIgd2lkdGg9IjU2Ljg2MDUiIGhlaWdodD0iNTYuODYwNSIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPiA8ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPiA8ZmVCbGVuZCBtb2RlPSJub3JtYWwiIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPiA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI0LjcxNTEzIiByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfOTUwXzEyMzk2Ii8+IDwvZmlsdGVyPiA8ZmlsdGVyIGlkPSJmaWx0ZXIzX2ZfOTUwXzEyMzk2IiB4PSItMzUuNDMwMyIgeT0iLTE5LjQzMDciIHdpZHRoPSI1Ni44NjA1IiBoZWlnaHQ9IjU2Ljg2MDUiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4gPGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz4gPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz4gPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iNC43MTUxMyIgcmVzdWx0PSJlZmZlY3QxX2ZvcmVncm91bmRCbHVyXzk1MF8xMjM5NiIvPiA8L2ZpbHRlcj4gPGNsaXBQYXRoIGlkPSJjbGlwMF85NTBfMTIzOTYiPiA8cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIGZpbGw9IndoaXRlIi8+IDwvY2xpcFBhdGg+IDwvZGVmcz4gPC9zdmc+',
|
||||
rdns: 'app.status',
|
||||
}
|
||||
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('eip6963:announceProvider', {
|
||||
detail: Object.freeze({ info, provider }),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
window.addEventListener('eip6963:requestProvider', () => {
|
||||
announceProvider()
|
||||
})
|
||||
|
||||
announceProvider()
|
||||
|
||||
function injectProvider() {
|
||||
Object.defineProperties(provider, {
|
||||
isStatus: {
|
||||
value: true,
|
||||
writable: false,
|
||||
},
|
||||
isMetaMask: {
|
||||
value: true,
|
||||
writable: false,
|
||||
},
|
||||
_metamask: {
|
||||
value: {
|
||||
isUnlocked: () => new Promise(resolve => resolve(true)),
|
||||
},
|
||||
writable: false,
|
||||
},
|
||||
// isCoinbaseWallet: {
|
||||
// value: true,
|
||||
// writable: false,
|
||||
// },
|
||||
qrUrl: {
|
||||
value: null,
|
||||
writable: false,
|
||||
},
|
||||
autoRefreshOnNetworkChange: {
|
||||
value: false,
|
||||
writable: true,
|
||||
},
|
||||
provider: {
|
||||
value: {},
|
||||
writable: true,
|
||||
},
|
||||
['__isProvider']: {
|
||||
value: true,
|
||||
writable: false,
|
||||
},
|
||||
connected: {
|
||||
value: true,
|
||||
writable: true,
|
||||
},
|
||||
})
|
||||
|
||||
Object.seal(provider)
|
||||
|
||||
Object.defineProperties(window, {
|
||||
ethereum: {
|
||||
get() {
|
||||
return provider
|
||||
},
|
||||
configurable: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// let redefinedProvider: any
|
||||
|
||||
if (window.localStorage.getItem('status:default-wallet') !== 'false') {
|
||||
// redefinedProvider = window.ethereum
|
||||
|
||||
injectProvider()
|
||||
}
|
||||
|
||||
// window.addEventListener('storage', () => {
|
||||
// if (window.localStorage.getItem('status:default-wallet') === 'false') {
|
||||
// window.ethereum = redefinedProvider
|
||||
// }
|
||||
// })
|
||||
|
||||
async function waitUntilComplete(document: Document): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (document.readyState === 'complete') {
|
||||
resolve()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
document.addEventListener('readystatechange', () => {
|
||||
if (document.readyState === 'complete') {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import { getFaviconUrl } from '~lib/get-favicon-url'
|
||||
import { ProviderMessage } from '~messages/provider-message'
|
||||
|
||||
import { DesktopClient } from '../lib/desktop-client'
|
||||
|
||||
import type { ProxyMessage } from '~messages/proxy-message'
|
||||
import type { EthersError } from 'ethers'
|
||||
import type { PlasmoCSConfig } from 'plasmo'
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
run_at: 'document_start',
|
||||
}
|
||||
|
||||
const desktopClient = new DesktopClient()
|
||||
|
||||
const handleMessage = async (event: MessageEvent) => {
|
||||
if (event.origin !== window.origin) {
|
||||
return
|
||||
}
|
||||
|
||||
let message: ProviderMessage
|
||||
try {
|
||||
message = ProviderMessage.parse(event.data)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
if (message.type === 'status:provider:disconnect') {
|
||||
desktopClient.stop()
|
||||
return
|
||||
}
|
||||
|
||||
if (message.type !== 'status:provider') {
|
||||
return
|
||||
}
|
||||
|
||||
if (!event.ports.length) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await desktopClient.send({
|
||||
...message.data,
|
||||
name: window.location.hostname,
|
||||
url: window.origin,
|
||||
iconUrl: getFaviconUrl() ?? '',
|
||||
})
|
||||
|
||||
event.ports[0].postMessage({
|
||||
type: 'status:proxy:success',
|
||||
data: response,
|
||||
} satisfies ProxyMessage)
|
||||
} catch (error) {
|
||||
let proxyError = {
|
||||
code: -32603,
|
||||
message: isError(error) ? error.message : 'Internal error',
|
||||
}
|
||||
|
||||
/**
|
||||
* ethers.js library has a custom error detection mechanism.
|
||||
* - Detected errors are stored in the `info` object:
|
||||
* @see https://github.com/ethers-io/ethers.js/blob/72c2182d01afa855d131e82635dca3da063cfb31/src.ts/providers/provider-jsonrpc.ts#L976-L1057
|
||||
* - Undetected errors are stored in the `error` field:
|
||||
* @see https://github.com/ethers-io/ethers.js/blob/72c2182d01afa855d131e82635dca3da063cfb31/src.ts/providers/provider-jsonrpc.ts#L1059
|
||||
*/
|
||||
if (isEthersError(error)) {
|
||||
if (isRpcError(error.error)) {
|
||||
proxyError = error.error
|
||||
} else if (isRpcError(error.info?.error)) {
|
||||
proxyError = error.info.error
|
||||
}
|
||||
}
|
||||
|
||||
const proxyMessage: ProxyMessage = {
|
||||
type: 'status:proxy:error',
|
||||
error: proxyError,
|
||||
}
|
||||
|
||||
event.ports[0].postMessage(proxyMessage)
|
||||
}
|
||||
}
|
||||
|
||||
function isError(error: unknown): error is Error {
|
||||
return !!error && typeof error === 'object' && 'message' in error
|
||||
}
|
||||
|
||||
function isEthersError(error: unknown): error is EthersError & {
|
||||
info?: { error?: { code: number; message: string } }
|
||||
} {
|
||||
return (
|
||||
!!error &&
|
||||
typeof error === 'object' &&
|
||||
'error' in error &&
|
||||
error.error !== null &&
|
||||
typeof error.error === 'object' &&
|
||||
'code' in error.error
|
||||
)
|
||||
}
|
||||
|
||||
function isRpcError(
|
||||
error: unknown,
|
||||
): error is { code: number; message: string } {
|
||||
return (
|
||||
!!error &&
|
||||
typeof error === 'object' &&
|
||||
'code' in error &&
|
||||
'message' in error
|
||||
)
|
||||
}
|
||||
|
||||
window.addEventListener('message', handleMessage)
|
||||
@@ -0,0 +1,35 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
declare global {
|
||||
interface Navigator {
|
||||
// @see https://github.com/lukewarlow/user-agent-data-types/blob/master/index.d.ts
|
||||
userAgentData?: {
|
||||
platform: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type Platform = 'macos' | 'windows' | 'linux'
|
||||
|
||||
export function detectDesktopOS(): Platform | null {
|
||||
const platform =
|
||||
window.navigator.userAgentData?.platform.toLowerCase() ??
|
||||
window.navigator.platform.toLowerCase()
|
||||
|
||||
if (platform.includes('mac')) return 'macos'
|
||||
if (platform.includes('win')) return 'windows'
|
||||
if (platform.includes('linux')) return 'linux'
|
||||
return null
|
||||
}
|
||||
|
||||
export const useDesktopOS = () => {
|
||||
const [desktopOS, setDesktopOS] = useState<Platform | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// note: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform#examples deprecated but use cases are still valid
|
||||
// note: https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-platform-dev (e.g. "MacIntel", "Win32", "Linux x86_64", "Linux armv81")
|
||||
setDesktopOS(detectDesktopOS())
|
||||
}, [])
|
||||
|
||||
return desktopOS
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export function useLocalStorage<T>(
|
||||
key: string,
|
||||
initialValue: T,
|
||||
): [T, (value: T | ((val: T) => T)) => void] {
|
||||
const [storedValue, setStoredValue] = useState<T>(initialValue)
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const item = window.localStorage.getItem(key)
|
||||
setStoredValue(item ? JSON.parse(item) : initialValue)
|
||||
} catch {
|
||||
setStoredValue(initialValue)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const handleStorageChange = (event: StorageEvent) => {
|
||||
if (event.key === key) {
|
||||
setStoredValue(
|
||||
event.newValue ? JSON.parse(event.newValue) : initialValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('storage', handleStorageChange)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', handleStorageChange)
|
||||
}
|
||||
}, [key, initialValue])
|
||||
|
||||
const setValue = (value: T | ((val: T) => T)) => {
|
||||
try {
|
||||
const valueToStore =
|
||||
value instanceof Function ? value(storedValue) : value
|
||||
|
||||
setStoredValue(valueToStore)
|
||||
window.localStorage.setItem(key, JSON.stringify(valueToStore))
|
||||
window.dispatchEvent(new Event('storage'))
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return [storedValue, setValue]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export const useOutsideClick = (
|
||||
ref: React.RefObject<HTMLDivElement>,
|
||||
callback: () => void,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
const path = event.composedPath()
|
||||
if (ref.current && !path.includes(ref.current)) {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', handleClick, true)
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', handleClick, true)
|
||||
}
|
||||
}, [ref, callback])
|
||||
|
||||
return ref
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { WebSocketProvider } from 'ethers'
|
||||
|
||||
import { config } from '~config'
|
||||
|
||||
import type { RequestArguments } from '~lib/request-arguments'
|
||||
import type { WebSocketLike } from 'ethers'
|
||||
|
||||
type DesktopRequestArguments = RequestArguments & {
|
||||
name: string
|
||||
url: string
|
||||
iconUrl: string
|
||||
}
|
||||
|
||||
export class DesktopClient {
|
||||
#rpcClient: WebSocketProvider | null = null
|
||||
|
||||
public stop() {
|
||||
if (!this.#rpcClient) {
|
||||
return
|
||||
}
|
||||
|
||||
this.#rpcClient?.destroy()
|
||||
this.#rpcClient = null
|
||||
|
||||
// todo: publish disconnect message/event after https://github.com/status-im/status-desktop/issues/16014
|
||||
}
|
||||
|
||||
public async send(args: DesktopRequestArguments) {
|
||||
if (!this.#rpcClient) {
|
||||
this.#rpcClient = new WebSocketProvider(
|
||||
config.desktop.rpc.url,
|
||||
'mainnet',
|
||||
{
|
||||
staticNetwork: true,
|
||||
},
|
||||
)
|
||||
;(this.#rpcClient.websocket as WebSocket).onclose = () => {
|
||||
this.stop()
|
||||
}
|
||||
}
|
||||
|
||||
await waitUntilOpen(this.#rpcClient.websocket)
|
||||
|
||||
return await this.#rpcClient.send(config.desktop.rpc.method, [
|
||||
JSON.stringify(args),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
async function waitUntilOpen(websocket: WebSocketLike) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (websocket.readyState === WebSocket.OPEN) {
|
||||
resolve()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (websocket.readyState === WebSocket.CLOSING) {
|
||||
reject(new Error('The RPC server is closing'))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (websocket.readyState === WebSocket.CLOSED) {
|
||||
reject(new Error('The RPC server is closed'))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
reject(new Error('Timed out to connect to the RPC server'))
|
||||
}, 30 * 1000)
|
||||
|
||||
const onopen = websocket.onopen?.bind(websocket)
|
||||
websocket.onopen = event => {
|
||||
onopen?.(event)
|
||||
websocket.onopen = onopen!
|
||||
clearTimeout(timeout)
|
||||
resolve()
|
||||
}
|
||||
|
||||
const onerror = websocket.onerror?.bind(websocket)
|
||||
websocket.onerror = event => {
|
||||
onerror?.(event)
|
||||
websocket.onerror = onerror!
|
||||
clearTimeout(timeout)
|
||||
reject(new Error('Failed to connect to the RPC server'))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export function getFaviconUrl() {
|
||||
const faviconElement =
|
||||
document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
||||
|
||||
if (faviconElement) {
|
||||
return faviconElement.href
|
||||
}
|
||||
|
||||
const iconElements =
|
||||
document.querySelectorAll<HTMLLinkElement>('link[rel*="icon"]')
|
||||
|
||||
if (iconElements.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return iconElements[0].href
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export class ProviderRpcError extends Error {
|
||||
public code: number
|
||||
public data: unknown
|
||||
|
||||
constructor(args: { code: number; message: string; data?: unknown }) {
|
||||
super(args.message)
|
||||
this.code = args.code
|
||||
this.data = args.data
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
/**
|
||||
* @see https://eips.ethereum.org/EIPS/eip-1193#request-1
|
||||
*/
|
||||
export const RequestArguments = z.object({
|
||||
method: z.string(),
|
||||
params: z
|
||||
.union([z.array(z.unknown()).readonly(), z.record(z.unknown()).optional()])
|
||||
.optional(),
|
||||
})
|
||||
|
||||
export type RequestArguments = z.infer<typeof RequestArguments>
|
||||
@@ -0,0 +1,18 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
import { RequestArguments } from '~lib/request-arguments'
|
||||
|
||||
export const ProviderMessage = z.discriminatedUnion('type', [
|
||||
z.object({
|
||||
type: z.literal('status:provider'),
|
||||
data: RequestArguments,
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('status:provider:disconnect'),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('status:provider:data'),
|
||||
}),
|
||||
])
|
||||
|
||||
export type ProviderMessage = z.infer<typeof ProviderMessage>
|
||||
@@ -0,0 +1,17 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
export const ProxyMessage = z.discriminatedUnion('type', [
|
||||
z.object({
|
||||
type: z.literal('status:proxy:success'),
|
||||
data: z.unknown(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('status:proxy:error'),
|
||||
error: z.object({
|
||||
code: z.number(),
|
||||
message: z.string(),
|
||||
}),
|
||||
}),
|
||||
])
|
||||
|
||||
export type ProxyMessage = z.infer<typeof ProxyMessage>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
export const ServiceWorkerMessage = z.discriminatedUnion('type', [
|
||||
z.object({
|
||||
type: z.literal('status:icon:clicked'),
|
||||
}),
|
||||
])
|
||||
|
||||
export type ServiceWorkerMessage = z.infer<typeof ServiceWorkerMessage>
|
||||
@@ -0,0 +1,15 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
font-family: theme(fontFamily.sans);
|
||||
color: theme(colors.neutral.100);
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: theme(fontFamily.sans) !important;
|
||||
font-size: initial !important;
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
import * as colors from '@status-im/colors'
|
||||
import { scrollbarWidth } from 'tailwind-scrollbar-utilities'
|
||||
import { fontFamily } from 'tailwindcss/defaultTheme'
|
||||
import plugin from 'tailwindcss/plugin'
|
||||
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
export const screens = {
|
||||
// We simulate the desktop first approach by using min-width 1px above the max-width of the previous breakpoint to match the design breakpoints
|
||||
// Otherwise, we would have to use max-width approach and change the entire codebase styles
|
||||
sm: '431px',
|
||||
md: '641px',
|
||||
'2md': '768px',
|
||||
lg: '869px',
|
||||
xl: '1024px',
|
||||
'2xl': '1281px',
|
||||
'3xl': '1441px',
|
||||
// TODO to be defined by design for pro-users
|
||||
'4xl': '1601px',
|
||||
}
|
||||
|
||||
export default {
|
||||
darkMode: 'media',
|
||||
future: {
|
||||
hoverOnlyWhenSupported: true,
|
||||
},
|
||||
content: [
|
||||
'./src/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
// './app/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
],
|
||||
theme: {
|
||||
fontFamily: {
|
||||
sans: ['Inter', ...fontFamily.sans],
|
||||
mono: fontFamily.mono,
|
||||
},
|
||||
|
||||
// use <Text /> from @status-im/components or arbitrary values
|
||||
// note: https://tailwindcss.com/docs/font-size#providing-a-default-line-height for `[fontSize, { lineHeight?, letterSpacing?, fontWeight? }]`
|
||||
fontSize: {
|
||||
// note: not in design system
|
||||
240: [
|
||||
'15rem',
|
||||
{
|
||||
lineHeight: '13.25rem',
|
||||
letterSpacing: '-0.6rem',
|
||||
},
|
||||
],
|
||||
// note: not in design system
|
||||
120: [
|
||||
'7.5rem',
|
||||
{
|
||||
lineHeight: '5.25rem',
|
||||
letterSpacing: '-0.1575rem',
|
||||
},
|
||||
],
|
||||
88: [
|
||||
'5.5rem',
|
||||
{
|
||||
lineHeight: '5.25rem',
|
||||
letterSpacing: '-0.1155rem',
|
||||
},
|
||||
],
|
||||
// note: not in design system
|
||||
76: [
|
||||
'4.75rem',
|
||||
{
|
||||
lineHeight: '4.25rem',
|
||||
letterSpacing: '-0.095rem',
|
||||
},
|
||||
],
|
||||
64: [
|
||||
'4rem',
|
||||
{
|
||||
lineHeight: '4.25rem',
|
||||
letterSpacing: '-0.08rem',
|
||||
},
|
||||
],
|
||||
// note: not in design system
|
||||
48: [
|
||||
'3rem',
|
||||
{
|
||||
lineHeight: '3.125rem',
|
||||
letterSpacing: '-0.06rem',
|
||||
},
|
||||
],
|
||||
40: [
|
||||
'2.5rem',
|
||||
{
|
||||
lineHeight: '2.75rem',
|
||||
letterSpacing: '-0.05rem',
|
||||
},
|
||||
],
|
||||
27: [
|
||||
'1.6875rem',
|
||||
{
|
||||
lineHeight: '2rem',
|
||||
letterSpacing: '-0.0354375rem',
|
||||
},
|
||||
],
|
||||
19: [
|
||||
'1.1875rem',
|
||||
{
|
||||
lineHeight: '1.75rem',
|
||||
letterSpacing: '-0.019rem',
|
||||
},
|
||||
],
|
||||
15: [
|
||||
'0.9375rem',
|
||||
{
|
||||
lineHeight: '1.359375rem',
|
||||
letterSpacing: '-0.0084375rem',
|
||||
},
|
||||
],
|
||||
13: [
|
||||
'0.8125rem',
|
||||
{
|
||||
lineHeight: '1.1375rem',
|
||||
letterSpacing: '-0.0024375rem',
|
||||
},
|
||||
],
|
||||
11: [
|
||||
'0.6875rem',
|
||||
{
|
||||
lineHeight: '0.97625rem',
|
||||
letterSpacing: '-0.0034375rem',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
colors: colors,
|
||||
|
||||
fontWeight: {
|
||||
regular: '400',
|
||||
400: '400',
|
||||
medium: '500',
|
||||
500: '500',
|
||||
semibold: '600',
|
||||
600: '600',
|
||||
bold: '700',
|
||||
700: '700',
|
||||
},
|
||||
|
||||
boxShadow: {
|
||||
1: '0px 2px 20px rgba(9, 16, 28, 0.04)',
|
||||
2: '0px 4px 20px rgba(9, 16, 28, 0.08)',
|
||||
3: '0px 8px 30px rgba(9, 16, 28, 0.12);',
|
||||
},
|
||||
|
||||
extend: {
|
||||
spacing: {
|
||||
30: '7.5rem',
|
||||
},
|
||||
|
||||
borderRadius: {
|
||||
'4xl': '2rem',
|
||||
},
|
||||
|
||||
maxWidth: {
|
||||
page: '1504',
|
||||
},
|
||||
|
||||
transitionProperty: {
|
||||
height: 'height',
|
||||
},
|
||||
|
||||
screens,
|
||||
|
||||
keyframes: {
|
||||
heightIn: {
|
||||
from: { height: '0' },
|
||||
// to: { height: 296 },
|
||||
to: { height: 'var(--radix-navigation-menu-viewport-height)' },
|
||||
},
|
||||
heightOut: {
|
||||
from: { height: 'var(--radix-navigation-menu-viewport-height)' },
|
||||
// from: { height: 296 },
|
||||
to: { height: '0' },
|
||||
},
|
||||
slide: {
|
||||
from: {
|
||||
transform: 'translateX(0)',
|
||||
},
|
||||
to: {
|
||||
transform: 'translateX(-100%)',
|
||||
},
|
||||
},
|
||||
slideInFromBottom: {
|
||||
from: {
|
||||
transform: 'translateY(200px)',
|
||||
},
|
||||
to: {
|
||||
transform: 'translateY(0)',
|
||||
},
|
||||
},
|
||||
marquee1: {
|
||||
'0%': { transform: 'translateX(0%)' },
|
||||
'100%': { transform: 'translateX(-100%)' },
|
||||
},
|
||||
explanationIn: {
|
||||
'0%': { opacity: '0', transform: 'scale(0.7)' },
|
||||
'80%': { opacity: '0.8', transform: 'scale(1.02)' },
|
||||
'100%': { opacity: '1', transform: 'scale(1)' },
|
||||
},
|
||||
explanationOut: {
|
||||
'0%': { opacity: '1', transform: 'scale(1)' },
|
||||
'100%': { opacity: '0', transform: 'scale(0.7)' },
|
||||
},
|
||||
explanationSlide: {
|
||||
'0%': {
|
||||
transform: 'translateY(100px)',
|
||||
opacity: '0',
|
||||
},
|
||||
'100%': {
|
||||
transform: 'translateY(0px)',
|
||||
opacity: '1',
|
||||
},
|
||||
},
|
||||
marquee2: {
|
||||
'0%': { transform: 'translateX(100%)' },
|
||||
'100%': { transform: 'translateX(0%)' },
|
||||
},
|
||||
|
||||
// dialog
|
||||
'overlay-enter': {
|
||||
from: { opacity: '0' },
|
||||
to: { opacity: '1' },
|
||||
},
|
||||
'overlay-exit': {
|
||||
'0%': { opacity: '1' },
|
||||
'100%': { opacity: '0' },
|
||||
},
|
||||
'drawer-enter': {
|
||||
from: { opacity: '0', transform: 'translateY(100%)' },
|
||||
to: { opacity: '1', transform: 'translateY(0)' },
|
||||
},
|
||||
'drawer-exit': {
|
||||
from: { opacity: '1', transform: 'translateY(0)' },
|
||||
to: { opacity: '0', transform: 'translateY(100%)' },
|
||||
},
|
||||
'dialog-enter': {
|
||||
from: {
|
||||
opacity: '0',
|
||||
transform: 'translate(-50%, -48%) scale(0.96)',
|
||||
},
|
||||
to: {
|
||||
opacity: '1',
|
||||
transform: 'translate(-50%, -50%) scale(1)',
|
||||
},
|
||||
},
|
||||
'dialog-exit': {
|
||||
from: { opacity: '1', transform: 'translate(-50%, -50%) scale(1)' },
|
||||
to: { opacity: '0', transform: 'translate(-50%, -48%) scale(0.96)' },
|
||||
},
|
||||
},
|
||||
|
||||
animation: {
|
||||
heightIn: 'heightIn 250ms ease',
|
||||
heightOut: 'heightOut 250ms ease',
|
||||
slide: '45s slide infinite linear',
|
||||
slideInFromBottom: 'slideInFromBottom 0.5s ease',
|
||||
marquee1: 'marquee1 180s linear infinite',
|
||||
marquee2: 'marquee2 180s linear infinite',
|
||||
explanationIn: 'explanationIn 150ms ease',
|
||||
explanationOut: 'explanationIn 150ms ease reverse',
|
||||
explanationSlideUp: 'explanationSlide 180ms ease',
|
||||
explanationSlideDown: 'explanationSlide 180ms ease reverse',
|
||||
},
|
||||
|
||||
backgroundImage: {
|
||||
'gradient-hatching':
|
||||
'repeating-linear-gradient(-75deg, #E7EAEE, #E7EAEE 4px, rgba(161, 171, 188, 0.2) 0px, rgba(161, 171, 188, 0.2) 6px)',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('tailwindcss-animate'),
|
||||
// add scrollbar utilities before lands in tailwindcss
|
||||
// @see https://github.com/tailwindlabs/tailwindcss/pull/5732
|
||||
scrollbarWidth(),
|
||||
// scrollbarColor(),
|
||||
// scrollbarGutter(),
|
||||
|
||||
plugin(({ matchUtilities }) => {
|
||||
matchUtilities({
|
||||
perspective: value => ({
|
||||
perspective: value,
|
||||
}),
|
||||
})
|
||||
}),
|
||||
],
|
||||
} satisfies Config
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "plasmo/templates/tsconfig.base",
|
||||
"exclude": ["node_modules"],
|
||||
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx", "global.d.ts"],
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"~*": ["./src/*"],
|
||||
},
|
||||
"baseUrl": ".",
|
||||
"lib": ["WebWorker", "dom", "WebWorker.ImportScripts"],
|
||||
"strictNullChecks": true,
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
},
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
# Tauri + React + Typescript
|
||||
|
||||
This template should help get you started developing with Tauri, React and Typescript in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
|
||||
@@ -1,27 +0,0 @@
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
// prevent vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
// tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true,
|
||||
},
|
||||
// to make use of `TAURI_DEBUG` and other env variables
|
||||
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
build: {
|
||||
// Tauri supports es2021
|
||||
target: process.env.TAURI_PLATFORM == 'windows' ? 'chrome105' : 'safari13',
|
||||
// don't minify for debug builds
|
||||
minify: !process.env.TAURI_DEBUG ? 'esbuild' : false,
|
||||
// produce sourcemaps for debug builds
|
||||
sourcemap: !!process.env.TAURI_DEBUG,
|
||||
},
|
||||
})
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"name": "desktop",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
"build": "vite build",
|
||||
"typecheck": "tsc",
|
||||
"preview": "vite preview",
|
||||
"clean": "rimraf node_modules .turbo"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.2.2",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/react": "^18.0.33",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@vitejs/plugin-react": "^3.1.0",
|
||||
"typescript": "^5.0.3",
|
||||
"vite": "^4.2.1"
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
[package]
|
||||
name = "desktop"
|
||||
version = "0.0.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
edition = "2021"
|
||||
rust-version = "1.57"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.2", features = ["api-all"] }
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
default = ["custom-protocol"]
|
||||
# this feature is used used for production builds where `devPath` points to the filesystem
|
||||
# DO NOT remove this
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 974 B |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 903 B |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,17 +0,0 @@
|
||||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![greet])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"devPath": "http://localhost:5173",
|
||||
"distDir": "../dist"
|
||||
},
|
||||
"package": {
|
||||
"productName": "desktop",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": true
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "com.tauri.dev",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
"height": 600,
|
||||
"resizable": true,
|
||||
"title": "desktop",
|
||||
"width": 800,
|
||||
"hiddenTitle": true,
|
||||
"titleBarStyle": "Overlay"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["_vite.config.ts"]
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": ["@status-im/eslint-config"]
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
// eslint-disable-next-line eslint-comments/disable-enable-pair
|
||||
/* eslint-disable import/namespace */
|
||||
import 'expo-dev-client'
|
||||
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import { useNavigation, useRoute } from '@react-navigation/native'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import { Heading, IconButton, Paragraph } from '@status-im/components'
|
||||
import { Avatar } from '@status-im/components/src/avatar'
|
||||
import { ArrowLeftIcon, MembersIcon } from '@status-im/icons'
|
||||
import { Stack as View, TamaguiProvider } from '@tamagui/core'
|
||||
import { useFonts } from 'expo-font'
|
||||
import { Platform } from 'react-native'
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context'
|
||||
import { AnimatePresence } from 'tamagui'
|
||||
|
||||
import { NavigationProvider } from './navigation/provider'
|
||||
import { ChannelScreen } from './screens/channel'
|
||||
import { HomeScreen } from './screens/home'
|
||||
import tamaguiConfig from './tamagui.config'
|
||||
|
||||
import type { RouteProp } from '@react-navigation/native'
|
||||
import type { HeaderBackButtonProps } from '@react-navigation/native-stack/lib/typescript/src/types'
|
||||
|
||||
export type RootStackParamList = {
|
||||
Home: undefined
|
||||
Channel: { channelId: string }
|
||||
}
|
||||
|
||||
const Stack = createNativeStackNavigator<RootStackParamList>()
|
||||
|
||||
const CustomHeaderLeft = (props: HeaderBackButtonProps) => {
|
||||
const navigation = useNavigation()
|
||||
const route = useRoute<RouteProp<RootStackParamList, 'Channel'>>()
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
icon={<ArrowLeftIcon size={20} />}
|
||||
onPress={() => {
|
||||
props.canGoBack && navigation.goBack()
|
||||
}}
|
||||
/>
|
||||
<Paragraph weight="semibold" marginLeft={12}>
|
||||
# {route.params.channelId || 'channel'}
|
||||
</Paragraph>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [position, setPosition] = useState(0)
|
||||
|
||||
const [loaded] = useFonts({
|
||||
Inter: require('@tamagui/font-inter/otf/Inter-Medium.otf'),
|
||||
InterBold: require('@tamagui/font-inter/otf/Inter-Bold.otf'),
|
||||
// Tamagui does this for you on web, but you need to do it manually on native. Only for the demo. We should seek a better solution.
|
||||
UbuntuMono: require('./assets/fonts/UbuntuMono.ttf'),
|
||||
})
|
||||
|
||||
const onScroll = event => {
|
||||
if (event.nativeEvent.contentOffset.y > 90) {
|
||||
setPosition(event.nativeEvent.contentOffset.y)
|
||||
} else {
|
||||
setPosition(0)
|
||||
}
|
||||
}
|
||||
|
||||
const showMinimizedHeader = useMemo(() => {
|
||||
return position > 90
|
||||
}, [position])
|
||||
|
||||
if (!loaded) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<TamaguiProvider config={tamaguiConfig} defaultTheme="light">
|
||||
<NavigationProvider>
|
||||
<SafeAreaProvider>
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
animation: 'slide_from_right',
|
||||
}}
|
||||
>
|
||||
<Stack.Screen
|
||||
name="Home"
|
||||
options={{
|
||||
headerTransparent: true,
|
||||
headerShadowVisible: false,
|
||||
header: () => (
|
||||
<View
|
||||
height={100}
|
||||
animation="fast"
|
||||
backgroundColor={
|
||||
showMinimizedHeader ? '$background' : 'transparent'
|
||||
}
|
||||
padding={16}
|
||||
paddingTop={48}
|
||||
flexDirection="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<AnimatePresence>
|
||||
{showMinimizedHeader && (
|
||||
<View
|
||||
key="header"
|
||||
animation={[
|
||||
'fast',
|
||||
{
|
||||
opacity: {
|
||||
overshootClamping: true,
|
||||
},
|
||||
},
|
||||
]}
|
||||
enterStyle={{ opacity: 0 }}
|
||||
exitStyle={{ opacity: 0 }}
|
||||
opacity={1}
|
||||
flexDirection="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
width="100%"
|
||||
>
|
||||
<Heading color="$textPrimary">Rarible</Heading>
|
||||
<Avatar
|
||||
src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.seadn.io%2Fgae%2FFG0QJ00fN3c_FWuPeUr9-T__iQl63j9hn5d6svW8UqOmia5zp3lKHPkJuHcvhZ0f_Pd6P2COo9tt9zVUvdPxG_9BBw%3Fw%3D500%26auto%3Dformat&f=1&nofb=1&ipt=c177cd71d8d0114080cfc6efd3f9e098ddaeb1b347919bd3089bf0aacb003b3e&ipo=images"
|
||||
size={48}
|
||||
outline
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</View>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{props => (
|
||||
<HomeScreen
|
||||
{...props}
|
||||
onScroll={onScroll}
|
||||
isMinimized={showMinimizedHeader}
|
||||
/>
|
||||
)}
|
||||
</Stack.Screen>
|
||||
<Stack.Screen
|
||||
name="Channel"
|
||||
component={ChannelScreen}
|
||||
options={{
|
||||
headerBlurEffect: 'systemUltraThinMaterialLight',
|
||||
headerStyle: {
|
||||
backgroundColor: Platform.select({
|
||||
ios: 'transparent',
|
||||
default: 'white',
|
||||
}),
|
||||
},
|
||||
headerTransparent: true,
|
||||
headerShadowVisible: false,
|
||||
headerTitle: '',
|
||||
headerLeft(props) {
|
||||
return <CustomHeaderLeft {...props} />
|
||||
},
|
||||
headerRight() {
|
||||
return (
|
||||
<IconButton
|
||||
icon={<MembersIcon size={20} />}
|
||||
onPress={() => {
|
||||
// noop
|
||||
}}
|
||||
/>
|
||||
)
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</SafeAreaProvider>
|
||||
</NavigationProvider>
|
||||
</TamaguiProvider>
|
||||
)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "mobile",
|
||||
"slug": "status-poc",
|
||||
"version": "1.0.3",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"updates": {
|
||||
"fallbackToCacheTimeout": 0
|
||||
},
|
||||
"assetBundlePatterns": ["**/*"],
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.marcelines.statuspoc"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#FFFFFF"
|
||||
},
|
||||
"package": "com.marcelines.statuspoc"
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
},
|
||||
"extra": {
|
||||
"eas": {
|
||||
"projectId": "e214cc8a-4e7e-4850-8a41-e280ca3a4469"
|
||||
}
|
||||
},
|
||||
"owner": "marcelines"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 27 KiB |