├── .github
├── CODEOWNERS
├── dependabot.yml
└── workflows
│ ├── security-code-scanner.yml
│ └── sonar.yml
├── .gitignore
├── .netlify
└── state.json
├── .nvmrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package.json
├── public
├── _redirects
├── fox.ico
├── images
│ └── dapps
│ │ ├── 1inch.svg
│ │ ├── 3box.io.png
│ │ ├── Mintable.png
│ │ ├── aave.svg
│ │ ├── aragon.org.png
│ │ ├── axieinfinity.com.png
│ │ ├── balancer.exchange.png
│ │ ├── bancor.network.png
│ │ ├── blockchaincuties.com.png
│ │ ├── brave_frontier_heroes.png
│ │ ├── cdp.makerdao.com.png
│ │ ├── cent.co.png
│ │ ├── chanlist.png
│ │ ├── clovers.png
│ │ ├── coindesk.com.png
│ │ ├── coingecko.com.png
│ │ ├── compound.finance.png
│ │ ├── cryptodozer.io.png
│ │ ├── cryptokitties.co.png
│ │ ├── curve.fi.png
│ │ ├── decrypt.co.jpg
│ │ ├── defi_saver.png
│ │ ├── defipulse.com.png
│ │ ├── dydx.png
│ │ ├── ens.jpg
│ │ ├── f1deltatime.com.png
│ │ ├── foam.space.png
│ │ ├── forkdelta.app.png
│ │ ├── gitcoin.co.png
│ │ ├── gnosis_safe.png
│ │ ├── idex.market.png
│ │ ├── instant.airswap.io.png
│ │ ├── kauri.io.png
│ │ ├── known_origin.png
│ │ ├── kyber.network.png
│ │ ├── localethereum.com.png
│ │ ├── makersplace.com.jpg
│ │ ├── matcha.png
│ │ ├── megacryptopolis.png
│ │ ├── microsponsors.png
│ │ ├── miime.png
│ │ ├── mintbase.png
│ │ ├── mirror.png
│ │ ├── my_crypto_heroes.jpg
│ │ ├── mythx.png
│ │ ├── nexusmutual.io.png
│ │ ├── opensea.io.png
│ │ ├── pTokens.png
│ │ ├── pickle.finance.jpeg
│ │ ├── pooltogether.us.png
│ │ ├── popula.com.png
│ │ ├── radar_relay.png
│ │ ├── rarible.com.jpg
│ │ ├── sorare.jpg
│ │ ├── superrare.co.jpg
│ │ ├── tokenlon.png
│ │ ├── tokensets.com.png
│ │ ├── totle.jpeg
│ │ ├── uniswap.exchange.png
│ │ ├── yearn.finance.png
│ │ ├── zapper.svg
│ │ └── zerion.io.png
├── index.html
├── logo-192.png
├── logo-512.png
└── manifest.json
├── scripts
└── auto-changelog.sh
├── sonar-project.properties
├── src
├── App.css
├── App.js
├── App.test.js
├── components
│ ├── Autocomplete
│ │ ├── index.css
│ │ └── index.js
│ ├── Dapp
│ │ ├── index.css
│ │ └── index.js
│ ├── ExploreDapps
│ │ ├── DappCategory.css
│ │ ├── DappCategory.js
│ │ ├── index.css
│ │ └── index.js
│ ├── Favorites
│ │ ├── index.css
│ │ └── index.js
│ ├── FeaturedDappsCarousel
│ │ ├── FeaturedDapp.css
│ │ ├── FeaturedDapp.js
│ │ ├── index.css
│ │ └── index.js
│ ├── Header
│ │ ├── index.css
│ │ └── index.js
│ ├── Navbar
│ │ ├── index.css
│ │ └── index.js
│ ├── ScrollToTop
│ │ └── index.js
│ ├── Tabs
│ │ ├── Tab.css
│ │ ├── Tab.js
│ │ ├── index.css
│ │ └── index.js
│ └── TakeATour
│ │ ├── index.css
│ │ └── index.js
├── data
│ ├── all-dapps.js
│ └── featured-dapps.js
├── images
│ ├── back-icon.svg
│ ├── bg-img.svg
│ ├── close-icon.svg
│ ├── logo-wordmark.svg
│ └── logo.svg
├── index.css
├── index.js
├── logo.svg
├── pages
│ ├── Category.js
│ └── Home.js
├── serviceWorker.js
└── util
│ ├── analytics.js
│ └── browser.js
└── yarn.lock
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Lines starting with '#' are comments.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | * @MetaMask/website-team
5 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "npm"
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/.github/workflows/security-code-scanner.yml:
--------------------------------------------------------------------------------
1 | name: 'MetaMask Security Code Scanner'
2 |
3 | on:
4 | push:
5 | branches: ['master']
6 | pull_request:
7 | branches: ['master']
8 |
9 | jobs:
10 | run-security-scan:
11 | runs-on: ubuntu-latest
12 | permissions:
13 | actions: read
14 | contents: read
15 | security-events: write
16 | steps:
17 | - name: MetaMask Security Code Scanner
18 | uses: MetaMask/Security-Code-Scanner@main
19 | with:
20 | repo: ${{ github.repository }}
21 | paths_ignored: |
22 | .storybook/
23 | '**/__snapshots__/'
24 | '**/*.snap'
25 | '**/*.stories.js'
26 | '**/*.stories.tsx'
27 | '**/*.test.browser.ts*'
28 | '**/*.test.js*'
29 | '**/*.test.ts*'
30 | '**/fixtures/'
31 | '**/jest.config.js'
32 | '**/jest.environment.js'
33 | '**/mocks/'
34 | '**/test*/'
35 | docs/
36 | e2e/
37 | merged-packages/
38 | node_modules
39 | storybook/
40 | test*/
41 | rules_excluded: example
42 | project_metrics_token: ${{ secrets.SECURITY_SCAN_METRICS_TOKEN }}
43 | slack_webhook: ${{ secrets.APPSEC_BOT_SLACK_WEBHOOK }}
44 |
--------------------------------------------------------------------------------
/.github/workflows/sonar.yml:
--------------------------------------------------------------------------------
1 | name: Sonar
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | build:
8 | name: Sonar
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | with:
13 | fetch-depth: 0
14 | - uses: sonarsource/sonarqube-scan-action@master
15 | env:
16 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
17 | SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 | .vscode/
--------------------------------------------------------------------------------
/.netlify/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "siteId": "376e0098-7ce1-47ce-8711-bc430a137f41"
3 | }
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v12
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## Current Main Branch
4 |
5 | ## 1.1.0 - Aug 15, 2022
6 | - [#136](https://github.com/MetaMask/metamask-mobile/pull/136): [UPDATE] Disable iOS links
7 |
8 | ## 1.0.1 - Jul 22, 2022
9 | - [#134](https://github.com/MetaMask/dapps/pull/134): [FIX] - remove categories filter for iOS
10 |
11 | ## 1.0.0 - Jul 12, 2022
12 | - [#132](https://github.com/MetaMask/dapps/pull/132): Show explore sites on iOS
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2020 MetaMask
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # home.metamask.io
2 |
3 | ## Contributing
4 |
5 | ### Managing featured dapps
6 |
7 | You need to submit a pull request to this repo with your changes to the file:
8 | https://github.com/MetaMask/dapps/blob/master/src/data/featured-dapps.js
9 |
10 | ### Managing dapps inside categories
11 |
12 | You need to submit a pull request to this repo with your changes to the file:
13 | https://github.com/MetaMask/dapps/blob/master/src/data/all-dapps.js
14 |
15 | ### Dapp icons
16 |
17 | If you're adding a new dapp to the list, make sure you add its icon under ./public/images/dapps/
18 |
19 | If you're deleting a dapp from the list, make sure that you're deleting its icon (but check it's not in use in another category!)
20 |
21 | ## Development
22 |
23 | Available commands:
24 |
25 | ### `npm start`
26 |
27 | Runs the app in the development mode.
28 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
29 |
30 | The page will reload if you make edits.
31 | You will also see any lint errors in the console.
32 |
33 | ### `npm test`
34 |
35 | Launches the test runner in the interactive watch mode.
36 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
37 |
38 | ### `npm run build`
39 |
40 | Builds the app for production to the `build` folder.
41 | It correctly bundles React in production mode and optimizes the build for the best performance.
42 |
43 | The build is minified and the filenames include the hashes.
44 | Your app is ready to be deployed!
45 |
46 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
47 |
48 | ### Release
49 |
50 | The project follows the same release process as the other projects in the MetaMask organization.
51 |
52 | 1. Choose a release version.
53 |
54 | - The release version should be chosen according to SemVer. Analyze the changes to see whether they include any breaking changes, new features, or deprecations, then choose the appropriate SemVer version. See [the SemVer specification](https://semver.org/) for more information.
55 |
56 | 2. If this release is backporting changes onto a previous release, then ensure there is a major version branch for that version (e.g. `1.x` for a `v1` backport release).
57 |
58 | - The major version branch should be set to the most recent release with that major version. For example, when backporting a `v1.0.2` release, you'd want to ensure there was a `1.x` branch that was set to the `v1.0.1` tag.
59 |
60 | 4. Create a release PR branch using the following syntax `release/x.x.x`.
61 |
62 | 4. Run `yarn auto-changelog` on the release branch and check that the changelog is correctly formatted.
63 |
64 | - Generally any changes that don't affect consumers of the package (e.g. lockfile changes or development environment changes) are omitted. Exceptions may be made for changes that might be of interest despite not having an effect upon the published package (e.g. major test improvements, security improvements, improved documentation, etc.).
65 | - Try to explain each change in terms that users of the package would understand (e.g. avoid referencing internal variables/concepts).
66 | - Consolidate related changes into one change entry if it makes it easier to explain.
67 |
68 | 5. Dev review and QA the release.
69 |
70 | - If changes are made to the base branch, the release branch will need to be updated with these changes and review/QA will need to restart again. As such, it's probably best to avoid merging other PRs into the base branch while review is underway.
71 |
72 | ### Deployments
73 |
74 | - Make sure you have the netlify client configured with your credentials and you have access to the project.
75 |
76 | #### Staging
77 |
78 | - `npm run deploy`
79 |
80 | #### Production
81 |
82 | - `npm run deploy:prod`
83 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@metamask/dapps",
3 | "license": "ISC",
4 | "version": "1.1.0",
5 | "private": true,
6 | "resolutions": {
7 | "**/optimist/minimist": "^1.2.5",
8 | "**/loader-fs-cache/mkdirp": "^0.5.1"
9 | },
10 | "dependencies": {
11 | "@fortawesome/fontawesome-svg-core": "^1.2.19",
12 | "@fortawesome/free-solid-svg-icons": "^5.9.0",
13 | "@fortawesome/react-fontawesome": "^0.1.4",
14 | "react": "^16.8.6",
15 | "react-device-detect": "^1.17.0",
16 | "react-dom": "^16.8.6",
17 | "react-router-dom": "^5.0.1",
18 | "react-router-transition": "^1.3.0",
19 | "react-scripts": "5.0.1",
20 | "url-parse": "^1.5.9"
21 | },
22 | "scripts": {
23 | "start": "react-scripts start",
24 | "build": "react-scripts build",
25 | "deploy": "react-scripts build && netlify deploy --dir \"build\"",
26 | "deploy:prod": "react-scripts build && netlify deploy --dir \"build\" --prod",
27 | "test": "react-scripts test",
28 | "eject": "react-scripts eject",
29 | "update-changelog": "./scripts/auto-changelog.sh"
30 | },
31 | "homepage": "https://metamask.github.io/dapps/",
32 | "eslintConfig": {
33 | "extends": "react-app"
34 | },
35 | "browserslist": {
36 | "production": [
37 | ">0.2%",
38 | "not dead",
39 | "not op_mini all"
40 | ],
41 | "development": [
42 | "last 1 chrome version",
43 | "last 1 firefox version",
44 | "last 1 safari version"
45 | ]
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
2 |
--------------------------------------------------------------------------------
/public/fox.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/fox.ico
--------------------------------------------------------------------------------
/public/images/dapps/1inch.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/public/images/dapps/3box.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/3box.io.png
--------------------------------------------------------------------------------
/public/images/dapps/Mintable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/Mintable.png
--------------------------------------------------------------------------------
/public/images/dapps/aave.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/images/dapps/aragon.org.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/aragon.org.png
--------------------------------------------------------------------------------
/public/images/dapps/axieinfinity.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/axieinfinity.com.png
--------------------------------------------------------------------------------
/public/images/dapps/balancer.exchange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/balancer.exchange.png
--------------------------------------------------------------------------------
/public/images/dapps/bancor.network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/bancor.network.png
--------------------------------------------------------------------------------
/public/images/dapps/blockchaincuties.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/blockchaincuties.com.png
--------------------------------------------------------------------------------
/public/images/dapps/brave_frontier_heroes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/brave_frontier_heroes.png
--------------------------------------------------------------------------------
/public/images/dapps/cdp.makerdao.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/cdp.makerdao.com.png
--------------------------------------------------------------------------------
/public/images/dapps/cent.co.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/cent.co.png
--------------------------------------------------------------------------------
/public/images/dapps/chanlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/chanlist.png
--------------------------------------------------------------------------------
/public/images/dapps/clovers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/clovers.png
--------------------------------------------------------------------------------
/public/images/dapps/coindesk.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/coindesk.com.png
--------------------------------------------------------------------------------
/public/images/dapps/coingecko.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/coingecko.com.png
--------------------------------------------------------------------------------
/public/images/dapps/compound.finance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/compound.finance.png
--------------------------------------------------------------------------------
/public/images/dapps/cryptodozer.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/cryptodozer.io.png
--------------------------------------------------------------------------------
/public/images/dapps/cryptokitties.co.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/cryptokitties.co.png
--------------------------------------------------------------------------------
/public/images/dapps/curve.fi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/curve.fi.png
--------------------------------------------------------------------------------
/public/images/dapps/decrypt.co.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/decrypt.co.jpg
--------------------------------------------------------------------------------
/public/images/dapps/defi_saver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/defi_saver.png
--------------------------------------------------------------------------------
/public/images/dapps/defipulse.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/defipulse.com.png
--------------------------------------------------------------------------------
/public/images/dapps/dydx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/dydx.png
--------------------------------------------------------------------------------
/public/images/dapps/ens.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/ens.jpg
--------------------------------------------------------------------------------
/public/images/dapps/f1deltatime.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/f1deltatime.com.png
--------------------------------------------------------------------------------
/public/images/dapps/foam.space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/foam.space.png
--------------------------------------------------------------------------------
/public/images/dapps/forkdelta.app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/forkdelta.app.png
--------------------------------------------------------------------------------
/public/images/dapps/gitcoin.co.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/gitcoin.co.png
--------------------------------------------------------------------------------
/public/images/dapps/gnosis_safe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/gnosis_safe.png
--------------------------------------------------------------------------------
/public/images/dapps/idex.market.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/idex.market.png
--------------------------------------------------------------------------------
/public/images/dapps/instant.airswap.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/instant.airswap.io.png
--------------------------------------------------------------------------------
/public/images/dapps/kauri.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/kauri.io.png
--------------------------------------------------------------------------------
/public/images/dapps/known_origin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/known_origin.png
--------------------------------------------------------------------------------
/public/images/dapps/kyber.network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/kyber.network.png
--------------------------------------------------------------------------------
/public/images/dapps/localethereum.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/localethereum.com.png
--------------------------------------------------------------------------------
/public/images/dapps/makersplace.com.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/makersplace.com.jpg
--------------------------------------------------------------------------------
/public/images/dapps/matcha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/matcha.png
--------------------------------------------------------------------------------
/public/images/dapps/megacryptopolis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/megacryptopolis.png
--------------------------------------------------------------------------------
/public/images/dapps/microsponsors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/microsponsors.png
--------------------------------------------------------------------------------
/public/images/dapps/miime.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/miime.png
--------------------------------------------------------------------------------
/public/images/dapps/mintbase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/mintbase.png
--------------------------------------------------------------------------------
/public/images/dapps/mirror.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/mirror.png
--------------------------------------------------------------------------------
/public/images/dapps/my_crypto_heroes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/my_crypto_heroes.jpg
--------------------------------------------------------------------------------
/public/images/dapps/mythx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/mythx.png
--------------------------------------------------------------------------------
/public/images/dapps/nexusmutual.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/nexusmutual.io.png
--------------------------------------------------------------------------------
/public/images/dapps/opensea.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/opensea.io.png
--------------------------------------------------------------------------------
/public/images/dapps/pTokens.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/pTokens.png
--------------------------------------------------------------------------------
/public/images/dapps/pickle.finance.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/pickle.finance.jpeg
--------------------------------------------------------------------------------
/public/images/dapps/pooltogether.us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/pooltogether.us.png
--------------------------------------------------------------------------------
/public/images/dapps/popula.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/popula.com.png
--------------------------------------------------------------------------------
/public/images/dapps/radar_relay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/radar_relay.png
--------------------------------------------------------------------------------
/public/images/dapps/rarible.com.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/rarible.com.jpg
--------------------------------------------------------------------------------
/public/images/dapps/sorare.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/sorare.jpg
--------------------------------------------------------------------------------
/public/images/dapps/superrare.co.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/superrare.co.jpg
--------------------------------------------------------------------------------
/public/images/dapps/tokenlon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/tokenlon.png
--------------------------------------------------------------------------------
/public/images/dapps/tokensets.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/tokensets.com.png
--------------------------------------------------------------------------------
/public/images/dapps/totle.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/totle.jpeg
--------------------------------------------------------------------------------
/public/images/dapps/uniswap.exchange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/uniswap.exchange.png
--------------------------------------------------------------------------------
/public/images/dapps/yearn.finance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/yearn.finance.png
--------------------------------------------------------------------------------
/public/images/dapps/zapper.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/images/dapps/zerion.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/images/dapps/zerion.io.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | MetaMask Home
23 |
24 |
25 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/public/logo-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/logo-192.png
--------------------------------------------------------------------------------
/public/logo-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MetaMask/dapps/a8adba12ce14934c8a1f452a4cb33dcd1139b6fb/public/logo-512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "fox.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/scripts/auto-changelog.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 | set -u
5 | set -o pipefail
6 |
7 | readonly URL='https://github.com/MetaMask/metamask-mobile'
8 |
9 | git fetch --tags
10 |
11 | most_recent_tag="$(git describe --tags "$(git rev-list --tags --max-count=1)")"
12 |
13 | git rev-list "${most_recent_tag}"..HEAD --reverse | while read commit
14 |
15 | do
16 | subject="$(git show -s --format="%s" "$commit")"
17 |
18 | # Squash & Merge: the commit subject is parsed as ` (#)`
19 | if grep -E -q '\(#[[:digit:]]+\)' <<< "$subject"
20 | then
21 | pr="$(awk '{print $NF}' <<< "$subject" | tr -d '()')"
22 | prefix="[$pr]($URL/pull/${pr###}): "
23 | description="$(awk '{NF--; print $0}' <<< "$subject")"
24 |
25 | # Merge: the PR ID is parsed from the git subject (which is of the form `Merge pull request
26 | # # from `, and the description is assumed to be the first line of the body.
27 | # If no body is found, the description is set to the commit subject
28 | elif grep -E -q '#[[:digit:]]+\sfrom' <<< "$subject"
29 | then
30 | pr="$(awk '{print $4}' <<< "$subject")"
31 | prefix="[$pr]($URL/pull/${pr###}): "
32 |
33 | first_line_of_body="$(git show -s --format="%b" "$commit" | head -n 1 | tr -d '\r')"
34 | if [[ -z "$first_line_of_body" ]]
35 | then
36 | description="$subject"
37 | else
38 | description="$first_line_of_body"
39 | fi
40 |
41 | # Normal commits: The commit subject is the description, and the PR ID is omitted.
42 | else
43 | pr=''
44 | prefix=''
45 | description="$subject"
46 | fi
47 |
48 | # add entry to CHANGELOG
49 | if [[ "$OSTYPE" == "linux-gnu" ]]
50 | then
51 | # shellcheck disable=SC1004
52 | sed -i'' '/## Current Main Branch/a\
53 | - '"$prefix$description"''$'\n' CHANGELOG.md
54 | else
55 | # shellcheck disable=SC1004
56 | sed -i '' '/## Current Main Branch/a\
57 | - '"$prefix$description"''$'\n' CHANGELOG.md
58 | fi
59 | done
60 | echo 'CHANGELOG updated'
61 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.projectKey=metamask-dapps
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #f5f7f8;
3 | -webkit-tap-highlight-color: rgba(0,0,0,0);
4 | -webkit-touch-callout: none;
5 | -webkit-user-select: none;
6 | -khtml-user-select: none;
7 | -moz-user-select: none;
8 | -ms-user-select: none;
9 | user-select: none;
10 | }
11 |
12 | .App {
13 | font-family: 'Roboto', sans-serif;
14 | padding-bottom: 0px;
15 | max-width: 768px;
16 | margin: auto;
17 | position: relative;
18 | }
19 |
20 | a {
21 | text-decoration: none;
22 | }
23 |
24 | a:active {
25 | opacity: 0.5;
26 | }
27 |
28 | button:focus {
29 | outline:0;
30 | }
31 |
32 | button:active {
33 | opacity: 0.5;
34 | }
35 |
36 | .animated-wrapper-rule {
37 | position: absolute;
38 | top: 0;
39 | bottom: 0;
40 | width: 100%;
41 | height: 0;
42 | z-index: 99999999;
43 | }
44 |
45 | .category-wrapper {
46 | margin-left: 15px;
47 | margin-right: 15px;
48 | padding-bottom: 15px;
49 | }
50 |
51 | @media only screen and (max-width: 321px) {
52 | body {
53 | overflow-x: hidden;
54 | }
55 |
56 | .dapp-category {
57 | width: 136px;
58 | min-width: 0%;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { BrowserRouter as Router, Route } from "react-router-dom";
3 | import { AnimatedRoute } from 'react-router-transition';
4 | import Home from './pages/Home';
5 | import Category from './pages/Category';
6 | import ScrollToTop from './components/ScrollToTop/';
7 | import './App.css';
8 |
9 | function App() {
10 | const [isLoading, setIsLoading] = useState(true);
11 |
12 | useEffect(() => {
13 | const run = async () => {
14 | try {
15 | await window.ethereum.send('metamask_injectHomepageScripts');
16 | } catch (e) {
17 | /**
18 | * To render the app in the desktop browser we need to set loading to false
19 | * as it throws by not finding the metamask_injectHomepageScripts event which is only
20 | * available in MM webview.
21 | * */
22 | setIsLoading(false);
23 | console.error(e);
24 | }
25 | }
26 |
27 | window.addEventListener('metamask_onHomepageScriptsInjected', () => {
28 | setIsLoading(false)
29 | })
30 |
31 | run()
32 | // eslint-disable-next-line react-hooks/exhaustive-deps
33 | }, [])
34 |
35 | if (isLoading) return null
36 |
37 | return (
38 |
39 |
40 |
41 |
42 |
43 |
({
50 | transform: `translateX(${styles.offset}%)`,
51 | })}
52 | />
53 |
54 |
55 |
56 |
57 | );
58 | }
59 |
60 | export default App;
61 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/components/Autocomplete/index.css:
--------------------------------------------------------------------------------
1 | .autocomplete {
2 | position: absolute;
3 | top: 163px;
4 | z-index: 999999;
5 | height: 42px;
6 | left: 16px;
7 | right: 16px;
8 | background: #FFFFFF;
9 | box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.25);
10 | border-radius: 20px;
11 | padding-left: 16px;
12 | padding-right: 16px;
13 | display: flex;
14 | }
15 |
16 | .autocomplete-input {
17 | width: 100%;
18 | font-size: 16px;
19 | outline-width: 0;
20 | border: 0px;
21 | -webkit-appearance: none;
22 | }
--------------------------------------------------------------------------------
/src/components/Autocomplete/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import onUrlSubmit from '../../util/browser';
3 | import{trackEvent, ANALYTICS_EVENT_OPTS} from '../../util/analytics';
4 | import './index.css';
5 |
6 | export default class Autocomplete extends Component {
7 | state = {
8 | value: ''
9 | }
10 |
11 | trackEventSearchUsed = () => {
12 | trackEvent(ANALYTICS_EVENT_OPTS.SEARCH_USED, {
13 | option_chosen: 'Search bar on dapp listing',
14 | number_of_tabs: undefined,
15 | });
16 | }
17 |
18 | handleChange = (event) => {
19 | this.setState({value: event.target.value});
20 | }
21 |
22 | onFocus = (event) => {
23 | event.preventDefault();
24 | window.ethereum.send('metamask_showAutocomplete');
25 | // needs to be blurred or else it will still be focused when the metamask mobile modal closes triggering an infinite loop
26 | event.target.blur()
27 | };
28 |
29 | handleSubmit = (event) => {
30 | event.preventDefault();
31 | this.trackEventSearchUsed();
32 | const searchEngine = window.__mmSearchEngine;
33 | const sanitizedInput = onUrlSubmit(this.state.value, searchEngine);
34 | window.location.href = sanitizedInput;
35 | }
36 |
37 | render(){
38 | return (
39 |
53 | );
54 | }
55 | }
--------------------------------------------------------------------------------
/src/components/Dapp/index.css:
--------------------------------------------------------------------------------
1 | .dapp {
2 | position: relative;
3 | }
4 |
5 | .dapp-container {
6 | display: flex;
7 | margin-bottom: 15px;
8 | padding-left: 16px;
9 | padding-right: 16px;
10 | padding-top: 10px;
11 | padding-bottom: 10px;
12 | background: #FFFFFF;
13 | box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
14 | border-radius: 8px;
15 | flex-direction: row;
16 | }
17 |
18 | .dapp:active {
19 | opacity: 0.5
20 | }
21 |
22 | .dapp-logo {
23 | margin-top: 2px;
24 | width: auto;
25 | min-width: 48px;
26 | height: 48px;
27 | border-radius: 9px;
28 | margin-right: 16px;
29 | }
30 |
31 | .dapp-logo-small {
32 | min-width: 32px;
33 | height: 32px;
34 | }
35 |
36 | .dapp-name {
37 | font-style: normal;
38 | font-weight: normal;
39 | font-size: 18px;
40 | line-height: 25px;
41 | align-items: center;
42 | color: #24292E;
43 | text-align: left;
44 | margin-bottom: 3px;
45 | margin-top: 0px;
46 | overflow: hidden;
47 | white-space: nowrap;
48 | text-overflow: ellipsis;
49 | }
50 |
51 | .dapp-name-small {
52 | font-size: 16px;
53 | line-height: 22px;
54 | }
55 |
56 | .dapp-desc {
57 | margin-top: 0px;
58 | margin-bottom: 0px;
59 | font-style: normal;
60 | font-weight: normal;
61 | font-size: 12px;
62 | line-height: 17px;
63 | text-align: left;
64 | color: #6A737D;
65 | }
66 |
67 | .dapp-content {
68 | width: 80%;
69 | }
70 |
71 | .dapp-url {
72 | font-family: Roboto;
73 | font-style: normal;
74 | font-weight: normal;
75 | font-size: 12px;
76 | line-height: 17px;
77 | text-align: left;
78 | color: #037DD6;
79 | overflow: hidden;
80 | white-space: nowrap;
81 | text-overflow: ellipsis;
82 | display: block;
83 | }
84 |
85 |
86 | .dapp-close {
87 | z-index: 1;
88 | width: 16px;
89 | height: 16px;
90 | padding: 5px;
91 | position: absolute;
92 | top: 5px;
93 | right: 0;
94 | text-align: center;
95 | background-color: transparent;
96 | display: block;
97 | box-sizing: content-box;
98 | border: 0px;
99 | }
--------------------------------------------------------------------------------
/src/components/Dapp/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import closeIcon from '../../images/close-icon.svg';
3 | import{trackEvent, ANALYTICS_EVENT_OPTS} from '../../util/analytics';
4 | import './index.css';
5 |
6 | export default class Dapp extends Component {
7 |
8 | trackEventOpenListedDapp = (e) => {
9 | e.preventDefault();
10 | trackEvent(ANALYTICS_EVENT_OPTS.OPEN_LISTED_DAPP, {
11 | 'dapp_name' : this.props.data.name,
12 | 'dapp_url': this.props.data.url,
13 | 'position': this.props.position + 1
14 | });
15 | window.location.href = this.props.data.url;
16 | }
17 |
18 | renderDescription = (description) => {
19 | return description && ({description}
)
20 | }
21 |
22 | onClose = (e) => {
23 | e.preventDefault();
24 | this.props.onClose(this.props.data.url);
25 | }
26 |
27 |
28 | render(){
29 | const { size, closable, data: { name, description, url, icon }} = this.props;
30 | return (
31 |
56 | );
57 | }
58 | }
--------------------------------------------------------------------------------
/src/components/ExploreDapps/DappCategory.css:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | .dapp-category-container{
5 | display: flex;
6 | flex: 1;
7 | min-width: 50%;
8 | }
9 |
10 | .dapp-category{
11 | display: flex;
12 | flex: 1;
13 | height: 64px;
14 | background: #FFFFFF;
15 | box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
16 | border-radius: 8px;
17 | text-align: center;
18 | align-items: center;
19 | min-width: 150px;
20 | margin: 7px;
21 | padding-left: 15px;
22 | padding-right: 8px;
23 | }
24 |
25 | .dapp-category:nth-child(even) {
26 | margin-right: 0px;
27 | }
28 |
29 | .dapp-category-icon {
30 | font-size: 32px;
31 | font-size: 32px;
32 | line-height: 32px;
33 | width: 32px;
34 | height: 32px;
35 | }
36 |
37 | .dapp-category-name {
38 | display: flex;
39 | font-style: normal;
40 | font-weight: normal;
41 | font-size: 14px;
42 | color: #24292E;
43 | padding: 8px;
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/src/components/ExploreDapps/DappCategory.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Link } from "react-router-dom";
3 |
4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
5 | import{trackEvent, ANALYTICS_EVENT_OPTS} from '../../util/analytics';
6 |
7 | import './DappCategory.css';
8 |
9 | export default class DappCategory extends Component {
10 | trackEventOpenDappCategory = () => {
11 | trackEvent(ANALYTICS_EVENT_OPTS.OPEN_DAPP_CATEGORY, {
12 | 'dapp_category_name' : this.props.data.name,
13 | });
14 | }
15 |
16 | render() {
17 | const { name, icon, color } = this.props.data;
18 | const url = `/${name.toLowerCase().replace(" ", "-")}`;
19 | return (
20 | // eslint-disable-next-line jsx-a11y/anchor-is-valid
21 |
26 |
27 |
32 | {name}
33 |
34 |
35 | );
36 | }
37 | }
--------------------------------------------------------------------------------
/src/components/ExploreDapps/index.css:
--------------------------------------------------------------------------------
1 | .explore-dapps {
2 | display: flex;
3 | flex: 1;
4 | flex-direction: row;
5 | padding-bottom: 18px;
6 | flex-wrap: wrap;
7 | }
--------------------------------------------------------------------------------
/src/components/ExploreDapps/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import DappCategory from './DappCategory';
3 | import allDapps from '../../data/all-dapps';
4 | import './index.css';
5 |
6 | export default class ExploreDapps extends Component {
7 | render() {
8 | return (
9 |
10 | {
11 | allDapps.map( (dapp) => (
12 |
16 | ))
17 | }
18 |
19 | );
20 | }
21 | }
--------------------------------------------------------------------------------
/src/components/Favorites/index.css:
--------------------------------------------------------------------------------
1 | .favorites-empty {
2 | min-height: 255px;
3 | display: flex;
4 | flex: 1;
5 | align-items: center;
6 | justify-content: center;
7 | }
8 |
9 | .favorites {
10 | width: 100%
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/Favorites/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { getHost } from '../../util/browser';
3 | import Dapp from '../Dapp';
4 | import './index.css';
5 |
6 | export default class Favorites extends Component {
7 | state = {
8 | favorites: [],
9 | }
10 |
11 | componentDidMount() {
12 | if (window.__mmFavorites) {
13 | this.setState({ favorites: window.__mmFavorites });
14 | }
15 |
16 | window.addEventListener('metamask_onHomepageScriptsInjected', () => {
17 | if (window.__mmFavorites && JSON.stringify(this.state.favorites) !== JSON.stringify(window.__mmFavorites)) {
18 | this.setState({ favorites: window.__mmFavorites });
19 | }
20 | });
21 |
22 | }
23 |
24 | onClose = async (url) => {
25 | const { favorites } = await window.ethereum.send('metamask_removeFavorite', [url]);
26 | this.setState({ favorites: favorites.reverse() });
27 | }
28 |
29 | renderFavorites() {
30 | return (
31 |
32 | {
33 | this.state.favorites.map((dapp, i) => (
34 |
46 | ))
47 | }
48 |
49 | );
50 | }
51 |
52 | renderEmpty() {
53 | return (
54 |
55 |
You have no favorites yet
56 |
57 | );
58 | }
59 |
60 | render() {
61 | if (!this.state.favorites || !this.state.favorites.length) {
62 | return this.renderEmpty();
63 | }
64 |
65 | return this.renderFavorites()
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/components/FeaturedDappsCarousel/FeaturedDapp.css:
--------------------------------------------------------------------------------
1 |
2 | .featured-dapp {
3 | /* White */
4 | display: flex;
5 | flex:1;
6 | align-items: center;
7 | flex-direction: column;
8 | padding-right: 20px;
9 | box-sizing: content-box;
10 | text-decoration: none;
11 | }
12 |
13 | .featured-dapp:active{
14 | opacity: 0.5
15 | }
16 |
17 | .featured-dapp-box{
18 | height: 65px;
19 | width: 65px;
20 | background: #FFFFFF;
21 | box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
22 | border-radius: 8px;
23 | text-align: center;
24 | align-items: center;
25 | justify-content: center;
26 | }
27 |
28 | .featured-dapp-logo {
29 | height: 38px;
30 | width: 38px;
31 | margin-top: 13px;
32 | }
33 |
34 | .featured-dapp-name {
35 | margin-top: 12px;
36 | width: 65px;
37 | font-style: normal;
38 | font-weight: normal;
39 | font-size: 12px;
40 | line-height: 17px;
41 | text-align: center;
42 | color: #000000;
43 | padding-bottom: 0px;
44 | margin-bottom: 0px;
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/components/FeaturedDappsCarousel/FeaturedDapp.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import './FeaturedDapp.css';
3 | import{trackEvent, ANALYTICS_EVENT_OPTS} from '../../util/analytics';
4 |
5 | export default class FeaturedDapp extends Component {
6 |
7 | track = (e) => {
8 | trackEvent(ANALYTICS_EVENT_OPTS.CLICKS_FEATURED_DAPP, {
9 | 'Dapp' : this.props.data.shortName,
10 | 'Url' : this.props.data.url,
11 | 'Position': this.props.position + 1
12 | });
13 | window.location.href = this.props.data.url;
14 | }
15 |
16 | render(){
17 | const { shortName, url, icon } = this.props.data;
18 | return (
19 |
24 |
25 |
30 |
31 | {shortName}
32 |
33 |
34 | );
35 | }
36 | }
--------------------------------------------------------------------------------
/src/components/FeaturedDappsCarousel/index.css:
--------------------------------------------------------------------------------
1 | .featured-dapps{
2 | margin-bottom: 30px;
3 | }
4 | .featured-dapps-title{
5 | padding-left: 16px;
6 | padding-right: 16px;
7 | font-size: 0.9rem;
8 | text-align: left;
9 | color: #6A737D;
10 | margin-bottom: 5px;
11 | font-weight: 500;
12 | }
13 |
14 | .featured-dapps-carousel-wrapper {
15 | overflow-y: hidden;
16 | overflow-x: scroll;
17 | height: 102px;
18 | width: 100%;
19 | }
20 |
21 | .featured-dapps-carousel {
22 | display: flex;
23 | flex: 1;
24 | flex-direction: row;
25 | overflow-x: scroll;
26 | padding-top: 10px;
27 | padding-left: 16px;
28 | padding-right: 16px;
29 | padding-bottom: 20px;
30 | -webkit-overflow-scrolling: touch;
31 | box-sizing: content-box;
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/FeaturedDappsCarousel/index.js:
--------------------------------------------------------------------------------
1 | // import React, { Component } from 'react'
2 | // import FeaturedDapp from './FeaturedDapp';
3 | // import featuredDapps from '../../data/featured-dapps';
4 |
5 | // import './index.css';
6 |
7 |
8 | // export default class FeaturedDappsCarousel extends Component {
9 | // render(){
10 | // return (
11 | //
12 | //
Featured Projects
13 | //
14 | //
15 | // {
16 | // featuredDapps.map( (dapp, position) => (
17 | //
22 | // ))
23 | // }
24 | //
25 | //
26 | //
27 | // );
28 | // }
29 | // }
--------------------------------------------------------------------------------
/src/components/Header/index.css:
--------------------------------------------------------------------------------
1 | .header {
2 | z-index: 0;
3 | height: 170px;
4 | display: flex;
5 | flex: 1;
6 | background: #190066;
7 | margin-bottom: 55px;
8 | position: relative;
9 | align-items: center;
10 | justify-content: center;
11 | text-align: center;
12 |
13 | }
14 |
15 | .header .bg-img{
16 | height: 170px;
17 | width: 100%;
18 | margin-top: 85px;
19 | }
20 |
21 | .header .logo-img{
22 | background-color: transparent;
23 | position: absolute;
24 | height: 66px;
25 | width: 102px;
26 | z-index: 999999999;
27 | align-self: center;
28 | justify-content: center;
29 | margin-top: 10px;
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/src/components/Header/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import BgImage from '../../images/bg-img.svg';
3 | import './index.css';
4 |
5 | export default class Header extends Component {
6 | render(){
7 | return (
8 |
9 |

10 |
11 | );
12 | }
13 | }
--------------------------------------------------------------------------------
/src/components/Navbar/index.css:
--------------------------------------------------------------------------------
1 | .navbar {
2 | background-color: #ffffff;
3 | display: flex;
4 | flex: 1;
5 | flex-direction: row;
6 | margin-bottom: 15px;
7 | }
8 | .navbar-back {
9 | position: absolute;
10 | margin: 16px;
11 | border: 0px;
12 | background-color: transparent;
13 | padding-top: 5px;
14 | padding-bottom: 5px;
15 | }
16 |
17 | .navbar h1{
18 | margin-top: 18px;
19 | display: flex;
20 | flex: 1;
21 | font-style: normal;
22 | font-weight: normal;
23 | font-size: 18px;
24 | line-height: 25px;
25 | align-items: center;
26 | justify-content: center;
27 | text-align: center;
28 | color: #000000;
29 | }
--------------------------------------------------------------------------------
/src/components/Navbar/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Link } from 'react-router-dom';
3 |
4 | import backIcon from '../../images/back-icon.svg';
5 |
6 | import './index.css';
7 |
8 | export default class Navbar extends Component {
9 | render(){
10 | const { title } = this.props;
11 | return (
12 |
13 |
17 |

18 |
19 |
{title}
20 |
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/ScrollToTop/index.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react'
2 | import { withRouter } from 'react-router-dom';
3 |
4 | class ScrollToTop extends Component {
5 | componentDidUpdate(prevProps) {
6 | if (this.props.location.pathname !== prevProps.location.pathname) {
7 | window.scrollTo(0, 0);
8 | }
9 | }
10 |
11 | render() {
12 | return this.props.children;
13 | }
14 | }
15 |
16 | export default withRouter(ScrollToTop);
17 |
--------------------------------------------------------------------------------
/src/components/Tabs/Tab.css:
--------------------------------------------------------------------------------
1 | .tab-list-item {
2 | list-style: none;
3 | margin-bottom: -1px;
4 | padding: 0.5rem 0.75rem;
5 | color: #6A737D;
6 | font-size: 14px;
7 | display: flex;
8 | flex: 1;
9 | justify-content: center;
10 | }
11 |
12 | .tab-list-active {
13 | border-bottom: 2px solid #037DD6;
14 | color: #037DD6;
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/Tabs/Tab.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import './Tab.css';
4 |
5 | export default class Tab extends Component {
6 | static propTypes = {
7 | activeTab: PropTypes.string.isRequired,
8 | label: PropTypes.string.isRequired,
9 | onClick: PropTypes.func.isRequired,
10 | };
11 |
12 | onClick = () => {
13 | const { label, onClick } = this.props;
14 | onClick(label);
15 | }
16 |
17 | render() {
18 | const {
19 | onClick,
20 | props: {
21 | activeTab,
22 | label,
23 | },
24 | } = this;
25 |
26 | let className = 'tab-list-item';
27 |
28 | if (activeTab === label) {
29 | className += ' tab-list-active';
30 | }
31 |
32 | return (
33 |
37 | {label}
38 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Tabs/index.css:
--------------------------------------------------------------------------------
1 | .tab-list {
2 | border-bottom: 1px solid #D6D9DC;
3 | padding-left: 0;
4 | display: flex;
5 | flex: 1;
6 | flex-direction: row;
7 | }
8 |
9 | .tab-content {
10 | display: flex;
11 | flex: 1;
12 | padding-left: 8px;
13 | padding-right: 8px;
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/Tabs/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { trackEvent, ANALYTICS_EVENT_OPTS } from '../../util/analytics';
4 | import Tab from './Tab';
5 |
6 | import './index.css';
7 |
8 | export default class Tabs extends Component {
9 | static propTypes = {
10 | children: PropTypes.instanceOf(Array).isRequired,
11 | }
12 |
13 | constructor(props) {
14 | super(props);
15 |
16 | const firstTab = props.children.find((child)=> !child.props.hide)
17 |
18 | this.state = {
19 | activeTab: firstTab.props.label,
20 | };
21 | }
22 |
23 | onTabSelected = (tab) => {
24 | this.setState({ activeTab: tab });
25 | trackEvent(ANALYTICS_EVENT_OPTS.CLICKS_HOMEPAGE_TAB, { 'Tab' : tab});
26 | if (tab === 'Favorites') {
27 | trackEvent(ANALYTICS_EVENT_OPTS.CLICKS_FAVORITES_TAB);
28 | }
29 | }
30 |
31 | render() {
32 | const {
33 | onTabSelected,
34 | props: {
35 | children,
36 | },
37 | state: {
38 | activeTab,
39 | }
40 | } = this;
41 |
42 | return (
43 |
44 |
45 | {children.map((child) => {
46 | const { label, hide } = child.props;
47 | if(hide) return null
48 |
49 | return (
50 |
56 | );
57 | })}
58 |
59 |
60 | {children.map((child) => {
61 | if(child.props.hide) return null
62 | if (child.props.label !== activeTab) return undefined;
63 | return child.props.children;
64 | })}
65 |
66 |
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/components/TakeATour/index.css:
--------------------------------------------------------------------------------
1 | .take-a-tour-wrapper {
2 | position: relative;
3 | margin-left: 8px;
4 | margin-right: 8px;
5 | }
6 |
7 | .take-a-tour {
8 | display: flex;
9 | flex: 1;
10 | height: 48px;
11 | background: #FFFFFF;
12 | box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.25);
13 | border-radius: 8px;
14 | text-align: center;
15 | align-items: center;
16 | justify-content: center;
17 | flex-direction: row;
18 | padding: 16px;
19 | }
20 |
21 | .take-a-tour-logo {
22 | margin-right: 16px;
23 | width: 38px;
24 | height: 38px;
25 | padding: 5px;
26 | box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
27 | border-radius: 8px;
28 | }
29 |
30 | .take-a-tour-content {
31 | display: flex;
32 | flex: 1;
33 | flex-direction: column;
34 | }
35 |
36 |
37 | .take-a-tour-content h3{
38 | display: flex;
39 | flex: 1;
40 | color: #24292E;
41 | font-family: Roboto;
42 | font-style: normal;
43 | font-weight: 500;
44 | font-size: 16px;
45 | line-height: 23px;
46 | margin-bottom: 5px;
47 | }
48 |
49 | .take-a-tour-content p{
50 | display: flex;
51 | flex: 1;
52 | font-family: Roboto;
53 | font-style: normal;
54 | font-weight: normal;
55 | font-size: 10px;
56 | line-height: 14px;
57 | color: #24292E;
58 | text-align: left;
59 | margin-top: 0px;
60 | }
61 |
62 | .take-a-tour-close {
63 | width: 16px;
64 | height: 16px;
65 | padding: 5px;
66 | position: absolute;
67 | top: 5px;
68 | right: 0;
69 | text-align: center;
70 | background-color: transparent;
71 | display: block;
72 | box-sizing: content-box;
73 | border: 0px;
74 | }
--------------------------------------------------------------------------------
/src/components/TakeATour/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import logo from '../../images/logo.svg';
3 | import closeIcon from '../../images/close-icon.svg';
4 | import './index.css';
5 |
6 | export default class TakeATour extends Component {
7 | state = {
8 | hideTutorialBanner: localStorage.getItem('hideTutorialBanner')
9 | }
10 |
11 | hideBanner = () => {
12 | localStorage.setItem('hideTutorialBanner', 'true');
13 | this.setState({hideTutorialBanner: true});
14 | }
15 |
16 | showTutorial = (e) => {
17 | e.preventDefault();
18 | window.ethereum.send('metamask_showTutorial');
19 | }
20 |
21 | render(){
22 | if (this.state.hideTutorialBanner) return null;
23 |
24 | return (
25 |
45 |
46 | );
47 | }
48 | }
--------------------------------------------------------------------------------
/src/data/all-dapps.js:
--------------------------------------------------------------------------------
1 | import { library } from '@fortawesome/fontawesome-svg-core'
2 | import { isIOS } from 'react-device-detect';
3 | import { faCreditCard,faDice, faCommentAlt, faMoneyBillWave, faNewspaper, faWrench, faExchangeAlt, faStore } from '@fortawesome/free-solid-svg-icons'
4 | library.add(faCreditCard, faDice, faCommentAlt, faMoneyBillWave, faNewspaper, faWrench, faExchangeAlt, faStore)
5 |
6 | const categories = [
7 | {
8 | name: 'Decentralized finance',
9 | displayIos: false,
10 | icon: 'money-bill-wave',
11 | color: '#5cd879',
12 | dapps: [
13 | {
14 | name: 'Compound',
15 | url: 'https://app.compound.finance/',
16 | description: 'Earn interest on your ETH',
17 | icon: './images/dapps/compound.finance.png'
18 | },
19 | {
20 | name: 'MakerDAO CDP',
21 | url: 'https://oasis.app/',
22 | description: 'Trade, borrow, and save using Dai',
23 | icon: './images/dapps/cdp.makerdao.com.png'
24 | },
25 | {
26 | name: 'PoolTogether',
27 | url: 'https://app.pooltogether.com/',
28 | description: 'A prize-linked savings account. By saving money you have a chance to win prizes',
29 | icon: './images/dapps/pooltogether.us.png'
30 | },
31 | {
32 | name: 'DeFi Saver',
33 | url: 'https://defisaver.com/',
34 | description: 'One-stop management solution for DeFi protocols',
35 | icon: './images/dapps/defi_saver.png'
36 | },
37 | {
38 | name: 'pTokens',
39 | url: 'https://dapp.ptokens.io/',
40 | description: 'Make your crypto compatible with any blockchain!',
41 | icon: './images/dapps/pTokens.png'
42 | },
43 | {
44 | name: 'Zapper',
45 | url: 'https://zapper.fi',
46 | description: 'Manage your DeFi assets and liabilities in one simple interface',
47 | icon: './images/dapps/zapper.svg'
48 | },
49 | {
50 | name: 'Yearn',
51 | url: 'https://yearn.finance/',
52 | description: 'An ecosystem of aggregators that utilize lending services to optimize your token lending',
53 | icon: './images/dapps/yearn.finance.png'
54 | },
55 | {
56 | name: 'Aave',
57 | url: 'https://aave.com/',
58 | description: 'An open-source, non-custodial protocol enabling the creation of money markets',
59 | icon: './images/dapps/aave.svg'
60 | },
61 | {
62 | name: 'Zerion',
63 | url: 'https://zerion.io/',
64 | description: 'Zerion is the easiest way to build and manage your entire DeFi portfolio from one place',
65 | icon: './images/dapps/zerion.io.png'
66 | },
67 | {
68 | name: 'Token Sets',
69 | url: 'https://www.tokensets.com/',
70 | description: 'Manage your crypto porfolio',
71 | icon: './images/dapps/tokensets.com.png'
72 | },
73 | {
74 | name: 'Pickle Finance',
75 | url: 'https://pickle.finance',
76 | description: 'Stabilize stablecoins',
77 | icon: './images/dapps/pickle.finance.jpeg'
78 | },
79 | {
80 | name: 'Nexus Mutual',
81 | url: 'https://nexusmutual.io/',
82 | description: 'A people-powered alternative to insurance',
83 | icon: './images/dapps/nexusmutual.io.png'
84 | },
85 | {
86 | name: 'Curve',
87 | url: 'https://www.curve.fi/',
88 | description: 'Creating deep on-chain liquidity using advanced bonding curves',
89 | icon: './images/dapps/curve.fi.png'
90 | },
91 | ],
92 | },
93 | {
94 | name: 'Decentralized exchanges',
95 | displayIos: false,
96 | icon: 'exchange-alt',
97 | color: '#bbb9f3',
98 | dapps: [
99 | {
100 | name: 'Uniswap',
101 | url: 'https://uniswap.exchange/',
102 | description: 'Swap and trade tokens',
103 | icon: './images/dapps/uniswap.exchange.png'
104 | },
105 | {
106 | name: 'dYdX',
107 | url: 'https://trade.dydx.exchange/',
108 | description: 'A decentralized and non-custodial trading platform offering perpetual margin, and spot trading',
109 | icon: './images/dapps/dydx.png'
110 | },
111 | {
112 | name: 'Kyber Swap',
113 | url: 'https://kyberswap.com/',
114 | description: 'A simple way to exchange tokens',
115 | icon: './images/dapps/kyber.network.png'
116 | },
117 | {
118 | name: 'Tokenlon',
119 | url: 'https://tokenlon.im/',
120 | description: 'Tokenlon DEX, powered by 0x protocol',
121 | icon: './images/dapps/tokenlon.png'
122 | },
123 | {
124 | name: '1inch',
125 | url: 'https://1inch.exchange',
126 | description: '1inch is a DEX aggregator with the best DEX prices and single point of entry for DeFi',
127 | icon: './images/dapps/1inch.svg'
128 | },
129 | {
130 | name: 'Totle Swap',
131 | url: 'https://totle.exchange',
132 | description: 'Swap any ERC-20 token at the best price',
133 | icon: './images/dapps/totle.jpeg'
134 | },
135 | {
136 | name: 'Radar Relay',
137 | url: 'https://relay.radar.tech/',
138 | description: 'Simple and secure wallet to wallet trading with the best prices in DeFi',
139 | icon: './images/dapps/radar_relay.png'
140 | },
141 | {
142 | name: 'AirSwap',
143 | url: 'https://instant.airswap.io/',
144 | description: 'Trade Tokens Easily, Securely, & Without Trading Fees',
145 | icon: './images/dapps/instant.airswap.io.png'
146 | },
147 | {
148 | name: 'Balancer',
149 | url: 'https://balancer.exchange/#/swap',
150 | description: 'Swap ERC20 tokens trustlessly across all Balancer liquidity pools.balancer.exchange',
151 | icon: './images/dapps/balancer.exchange.png'
152 | },
153 | {
154 | name: 'Matcha',
155 | url: 'https://matcha.xyz/',
156 | description: 'Simple crypto trading for everyone',
157 | icon: './images/dapps/matcha.png'
158 | },
159 | ]
160 | },
161 | {
162 | name: 'Art & collectibles',
163 | displayIos: false,
164 | icon: 'store',
165 | color: '#F29D62',
166 | dapps: [
167 | {
168 | name: 'miime',
169 | url: 'https://miime.io/',
170 | description: 'miime is an NFT marketplace catering to blockchain gamers in Japan and across the world',
171 | icon: './images/dapps/miime.png'
172 | },
173 | {
174 | name: 'Mintable',
175 | url: 'https://mintable.app',
176 | description: 'Mintable is a next generation NFT marketplace, the easiest place to trade NFTs and create your own.',
177 | icon: './images/dapps/mintable.png'
178 | },
179 | {
180 | name: 'OpenSea',
181 | url: 'https://opensea.io/',
182 | description: 'Buy, sell, and discover rare digital items',
183 | icon: './images/dapps/opensea.io.png'
184 | },
185 | {
186 | name: 'KnownOrigin',
187 | url: 'https://knownorigin.io/',
188 | description: 'Discover and collect rare digital artwork',
189 | icon: './images/dapps/known_origin.png'
190 | },
191 | {
192 | name: 'Mintbase',
193 | url: 'https://mintbase.io',
194 | description: 'Leading non-fungible token creation tool and marketplace',
195 | icon: './images/dapps/mintbase.png'
196 | },
197 | {
198 | name: 'Axie Infinity',
199 | url: 'https://axieinfinity.com/#',
200 | description: 'Collect and raise fantasy creatures called Axie',
201 | icon: './images/dapps/axieinfinity.com.png'
202 | },
203 | {
204 | name: 'Sorare',
205 | url: 'https://sorare.com/',
206 | description: 'Global Fantasy Football. Collect limited edition digital collectibles',
207 | icon: './images/dapps/sorare.jpg'
208 | },
209 | {
210 | name: 'Clovers Network',
211 | url: 'https://clovers.network',
212 | description: 'Discover, collect & trade cryptographic icons',
213 | icon: './images/dapps/clovers.png'
214 | },
215 | {
216 | name: 'CryptoKitties',
217 | url: 'https://www.cryptokitties.co/',
218 | description: 'Collect, breed and trade unique CryptoKitties',
219 | icon: './images/dapps/cryptokitties.co.png'
220 | },
221 | {
222 | name: 'Super Rare',
223 | url: 'https://superrare.co/',
224 | description: 'Discover and collect digital artworks',
225 | icon: './images/dapps/superrare.co.jpg'
226 | },
227 | {
228 | name: 'Rarible',
229 | url: 'https://rarible.com/',
230 | description: 'Create and sell digital collectibles',
231 | icon: './images/dapps/rarible.com.jpg'
232 | },
233 | {
234 | name: 'Makersplace',
235 | url: 'https://makersplace.com/',
236 | description: 'Collect truly rare digital artworks',
237 | icon: './images/dapps/makersplace.com.jpg'
238 | },
239 | {
240 | name: 'My Crypto Heroes',
241 | url: 'https://www.mycryptoheroes.net/home',
242 | description: 'Collect and battle heroes',
243 | icon: './images/dapps/my_crypto_heroes.jpg'
244 | },
245 | {
246 | name: 'CryptoDozer Marketplace',
247 | url: 'https://market.playdapp.io',
248 | description: 'From sales to purchases, marketplace is reliable and fast',
249 | icon: './images/dapps/cryptodozer.io.png'
250 | },
251 | {
252 | name: 'Brave Frontier Heroes',
253 | url: 'https://bravefrontierheroes.com',
254 | description: 'Use heroes in turn-based quests and battles.',
255 | icon: './images/dapps/brave_frontier_heroes.png'
256 | },
257 | {
258 | name: 'Blockchain Cuties',
259 | url: 'https://blockchaincuties.com/',
260 | description: 'Cuties are cats, dogs, and bears that go on adventures.',
261 | icon: './images/dapps/blockchaincuties.com.png'
262 | },
263 | {
264 | name: 'F1 Delta Time',
265 | url: 'https://www.f1deltatime.com/',
266 | description: 'Own F1 Delta collectibles & stake to earn',
267 | icon: './images/dapps/f1deltatime.com.png'
268 | },
269 | {
270 | name: 'MegaCryptoPolis',
271 | url: 'https://mcp3d.com',
272 | description: 'Collect land and build a blockchain city.',
273 | icon: './images/dapps/megacryptopolis.png'
274 | },
275 | ]
276 | },
277 | {
278 | name: 'Earn crypto',
279 | displayIos: false,
280 | icon: 'credit-card',
281 | color: '#1098FC',
282 | dapps: [
283 | {
284 | name: 'Gitcoin',
285 | url: 'https://gitcoin.co/',
286 | description: 'Get paid in crypto for working on open source projects',
287 | icon: './images/dapps/gitcoin.co.png'
288 | },
289 | {
290 | name: 'Local Ethereum',
291 | url: 'https://localethereum.com/',
292 | description: 'Get ETH peer-to-peer in over 130 countries',
293 | icon: './images/dapps/localethereum.com.png'
294 | },
295 | {
296 | name: 'Cent',
297 | url: 'https://beta.cent.co/',
298 | description: 'Earn ETH by creating content',
299 | icon: './images/dapps/cent.co.png'
300 | },
301 | {
302 | name: 'Mirror',
303 | url: 'https://mirror.xyz',
304 | description: 'Mirror—a crypto native creative suite, with crowdfunding & publishing tools for creators. ',
305 | icon: './images/dapps/mirror.png'
306 | },
307 | ],
308 | },
309 | {
310 | name: 'Developer tools',
311 | displayIos: false,
312 | icon: 'wrench',
313 | color: '#838c96',
314 | dapps: [
315 | {
316 | name: 'Chainlist',
317 | url: 'https://chainlist.org/',
318 | description: 'A site for adding additional blockchains to your wallet',
319 | icon: './images/dapps/chainlist.png'
320 | },
321 | {
322 | name: 'Ethereum Name Service',
323 | url: 'https://app.ens.domains/',
324 | description: 'Have one name for all your cryptocurrency wallets, a decentralised website, & more',
325 | icon: './images/dapps/ens.jpg'
326 | },
327 | {
328 | name: 'Gnosis Safe Multisig',
329 | url: 'https://gnosis-safe.io/app/#/',
330 | description: 'Manage digital assets collectively',
331 | icon: './images/dapps/gnosis_safe.png'
332 | },
333 | {
334 | name: 'Microsponsors',
335 | url: 'https://microsponsors.io',
336 | description: 'Microsponsors is an auction house for tokenized Time',
337 | icon: './images/dapps/microsponsors.png'
338 | },
339 | {
340 | name: 'MythX',
341 | url: 'https://mythx.io/',
342 | description: 'Smart contract security service for Ethereum',
343 | icon: './images/dapps/mythx.png'
344 | },
345 | ]
346 | },
347 | {
348 | name: 'Social',
349 | displayIos: false,
350 | icon: 'comment-alt',
351 | color: '#F8CD45',
352 | dapps: [
353 | {
354 | name: '3Box',
355 | url: 'https://3box.io/hub',
356 | description: 'Social profiles for Ethereum',
357 | icon: './images/dapps/3box.io.png'
358 | },
359 | {
360 | name: 'Kauri',
361 | url: 'https://kauri.io/',
362 | description: 'Ethereum dev content in a decentralized knowledge base',
363 | icon: './images/dapps/kauri.io.png'
364 | },
365 | {
366 | name: 'FOAM',
367 | url: 'https://map.foam.space',
368 | description: 'Create, curate, and search a consensus-driven map',
369 | icon: './images/dapps/foam.space.png'
370 | },
371 | {
372 | name: 'Aragon',
373 | url: 'https://aragon.org/discover/',
374 | description: 'Create and manage communities, companies, organizations',
375 | icon: './images/dapps/aragon.org.png'
376 | },
377 | ],
378 | },
379 | {
380 | name: 'Markets',
381 | displayIos: false,
382 | icon: 'newspaper',
383 | color: '#FF849A',
384 | dapps: [
385 | {
386 | name: 'Popula',
387 | url: 'https://popula.com/',
388 | description: 'News powered by Civil and Ethereum',
389 | icon: './images/dapps/popula.com.png'
390 | },
391 | {
392 | name: 'CoinDesk',
393 | url: 'https://www.coindesk.com/',
394 | description: 'Blockchain news',
395 | icon: './images/dapps/coindesk.com.png'
396 | },
397 | {
398 | name: 'CoinGecko',
399 | url: 'https://www.coingecko.com/en',
400 | description: 'Cryptocurrency Prices & Market Capitalization',
401 | icon: './images/dapps/coingecko.com.png'
402 | },
403 | {
404 | name: 'DeCrypt',
405 | url: 'https://decrypt.co/',
406 | description: 'News about Ethereum, Bitcoin and Web3',
407 | icon: './images/dapps/decrypt.co.jpg'
408 | },
409 | {
410 | name: 'Defipulse',
411 | url: 'https://defipulse.com/',
412 | description: 'The analytics + rankings hub for DeFi',
413 | icon: './images/dapps/defipulse.com.png'
414 | },
415 | ],
416 | }
417 | ];
418 |
419 | // hide any of the above on iOS when displayIos is false
420 | const filtered = categories.filter(({ displayIos = true }) => !(isIOS && !displayIos));
421 |
422 | export default filtered;
423 |
--------------------------------------------------------------------------------
/src/data/featured-dapps.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | url: 'https://uniswap.exchange/',
4 | name: 'Uniswap Exchange',
5 | shortName: 'Uniswap',
6 | description: 'Uniswap is a protocol for automated token exchange on Ethereum.',
7 | icon: './images/dapps/uniswap.exchange.png'
8 | },
9 | {
10 | url: 'https://opensea.io/',
11 | name: 'OpenSea',
12 | shortName: 'OpenSea',
13 | description: 'The largest marketplace for crypto collectibles. Buy, sell, and discover rare digital items',
14 | icon: './images/dapps/opensea.io.png'
15 | },
16 | {
17 | url: 'https://compound.finance/',
18 | name: 'Compound',
19 | shortName: 'Compound',
20 | description: 'Supply assets to the Compound protocol and earn interest.',
21 | icon: './images/dapps/compound.finance.png'
22 | },
23 | {
24 | url: 'https://oasis.app/',
25 | name: 'MakerDAO CDP',
26 | shortName: 'MakerDAO',
27 | description: 'This is the place to generate DAI! Manage depositing of collateral and generation of DAI.',
28 | icon: './images/dapps/cdp.makerdao.com.png'
29 | },
30 | {
31 | url: 'https://3box.io/',
32 | name: '3Box',
33 | shortName: '3Box',
34 | description:
35 | 'Create a social profile for your Ethereum account to start building trust, connection, and community.',
36 | icon: './images/dapps/3box.io.png'
37 | },
38 | {
39 | url: 'https://mainnet.aragon.org/',
40 | name: 'Aragon',
41 | shortName: 'Aragon',
42 | description: 'Aragon lets you freely organize and collaborate without borders or intermediaries.',
43 | icon: './images/dapps/aragon.org.png'
44 | }
45 | ];
46 |
--------------------------------------------------------------------------------
/src/images/back-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/images/bg-img.svg:
--------------------------------------------------------------------------------
1 |
26 |
--------------------------------------------------------------------------------
/src/images/close-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/images/logo-wordmark.svg:
--------------------------------------------------------------------------------
1 |
40 |
--------------------------------------------------------------------------------
/src/images/logo.svg:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 | document.addEventListener("touchstart", function(){}, true);
9 |
10 | // If you want your app to work offline and load faster, you can change
11 | // unregister() to register() below. Note this comes with some pitfalls.
12 | // Learn more about service workers: https://bit.ly/CRA-PWA
13 | serviceWorker.unregister();
14 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/pages/Category.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Navbar from '../components/Navbar/';
3 | import Dapp from '../components/Dapp/';
4 | import allDapps from '../data/all-dapps';
5 |
6 | export default class Category extends Component {
7 |
8 | state = {
9 | category: null
10 | };
11 |
12 | componentDidMount(){
13 | const category = allDapps.find((cat) => (
14 | cat.name.toLowerCase().replace(" ", "-") === this.props.match.params.category
15 | ));
16 |
17 | if(category){
18 | this.setState({category});
19 | }
20 |
21 | }
22 |
23 |
24 | render(){
25 | const { category } = this.state || {};
26 | if(!category){
27 | return null;
28 | }
29 | return (
30 |
31 |
32 |
33 | { category.dapps.sort((a, b) => a.name.charCodeAt(0) - b.name.charCodeAt(0)).map( (dapp, i) => (
34 |
35 | ))
36 | }
37 |
38 |
39 | );
40 | }
41 | }
--------------------------------------------------------------------------------
/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Header from '../components/Header/';
3 | import Tabs from '../components/Tabs/';
4 | import Autocomplete from '../components/Autocomplete/';
5 | // import FeaturedDappsCarousel from '../components/FeaturedDappsCarousel/';
6 | import ExploreDapps from '../components/ExploreDapps/';
7 | import Favorites from '../components/Favorites/';
8 | import TakeATour from '../components/TakeATour/';
9 | import{trackEvent, ANALYTICS_EVENT_OPTS} from '../util/analytics';
10 | import { isIOS } from 'react-device-detect';
11 |
12 | const isMobile = {
13 | Android: function () {
14 | return navigator.userAgent.match(/Android/i);
15 | },
16 | BlackBerry: function () {
17 | return navigator.userAgent.match(/BlackBerry/i);
18 | },
19 | iOS: function () {
20 | return navigator.userAgent.match(/iPhone|iPad|iPod/i);
21 | },
22 | Opera: function () {
23 | return navigator.userAgent.match(/Opera Mini/i);
24 | },
25 | Windows: function () {
26 | return navigator.userAgent.match(/IEMobile/i);
27 | },
28 | any: function () {
29 | return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
30 | }
31 | };
32 |
33 | export default class Home extends Component {
34 | componentDidMount() {
35 | trackEvent(ANALYTICS_EVENT_OPTS.IMPRESSION);
36 | }
37 |
38 | render() {
39 | return (
40 |
41 |
42 |
43 | {/*
*/}
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | {isMobile.any() ?
: ''}
53 |
54 | );
55 | }
56 | }
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/util/analytics.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | export function trackEvent(action, data){
3 | if(mixpanel && window.__mmMetametrics && mixpanel.track){
4 | const category = action.category
5 | delete action.category
6 | mixpanel.track(
7 | category,
8 | {...action, ...data},
9 | );
10 | }
11 | }
12 |
13 | const generateOpt = (category, action, name) => ({ category, action, name });
14 |
15 | const NAMES = {
16 | DAPP: 'Dapp',
17 | FEATURED_DAPP: 'Featured Dapp',
18 | DAPP_CATEGORY: 'Dapp Category',
19 | HOMEPAGE_TAB: 'Homepage Tab',
20 | OPEN_FAVORITE: 'Opened Favorites',
21 | SEARCH_USED: 'Search Used',
22 | OPEN_DAPP_CATEGORY: 'Opened Dapp Category',
23 | OPEN_LISTED_DAPP: 'Opened Listed Dapp',
24 | };
25 |
26 | const ACTIONS = {
27 | CLICK: 'Click',
28 | IMPRESSION: 'Impression',
29 | };
30 |
31 | const CATEGORIES = {
32 | BROWSER_HOME: 'Browser Home',
33 | };
34 |
35 | export const ANALYTICS_EVENT_OPTS = {
36 | CLICKS_DAPP: generateOpt(
37 | CATEGORIES.BROWSER_HOME,
38 | ACTIONS.CLICK,
39 | NAMES.DAPP
40 | ),
41 | CLICKS_FEATURED_DAPP: generateOpt(
42 | CATEGORIES.BROWSER_HOME,
43 | ACTIONS.CLICK,
44 | NAMES.FEATURED_DAPP
45 | ),
46 | CLICKS_DAPP_CATEGORY: generateOpt(
47 | CATEGORIES.BROWSER_HOME,
48 | ACTIONS.CLICK,
49 | NAMES.DAPP_CATEGORY
50 | ),
51 | CLICKS_HOMEPAGE_TAB: generateOpt(
52 | CATEGORIES.BROWSER_HOME,
53 | ACTIONS.CLICK,
54 | NAMES.HOMEPAGE_TAB
55 | ),
56 | IMPRESSION: generateOpt(
57 | CATEGORIES.BROWSER_HOME,
58 | ACTIONS.IMPRESSION,
59 | ),
60 | CLICKS_FAVORITES_TAB: generateOpt(
61 | NAMES.OPEN_FAVORITE
62 | ),
63 | SEARCH_USED: generateOpt(
64 | NAMES.SEARCH_USED
65 | ),
66 | OPEN_DAPP_CATEGORY: generateOpt(
67 | NAMES.OPEN_DAPP_CATEGORY
68 | ),
69 | OPEN_LISTED_DAPP: generateOpt(
70 | NAMES.OPEN_LISTED_DAPP
71 | )
72 | };
73 |
74 | export default {trackEvent,ANALYTICS_EVENT_OPTS }
75 |
--------------------------------------------------------------------------------
/src/util/browser.js:
--------------------------------------------------------------------------------
1 |
2 | import URL from 'url-parse';
3 |
4 | /**
5 | * Returns a sanitized url, which could be a search engine url if
6 | * a keyword is detected instead of a url
7 | *
8 | * @param {string} input - String corresponding to url input
9 | * @param {string} searchEngine - Protocol string to append to URLs that have none
10 | * @param {string} defaultProtocol - Protocol string to append to URLs that have none
11 | * @returns {string} - String corresponding to sanitized input depending if it's a search or url
12 | */
13 | export default function onUrlSubmit(input, searchEngine, defaultProtocol = 'https://') {
14 | //Check if it's a url or a keyword
15 | const res = input.match(/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!&',;=.+]+$/g);
16 | if (res === null) {
17 | // In case of keywords we default to google search
18 | let searchUrl = 'https://www.google.com/search?q=' + escape(input);
19 | if (searchEngine === 'DuckDuckGo') {
20 | searchUrl = 'https://duckduckgo.com/?q=' + escape(input);
21 | }
22 | return searchUrl;
23 | }
24 | const hasProtocol = input.match(/^[a-z]*:\/\//);
25 | const sanitizedURL = hasProtocol ? input : `${defaultProtocol}${input}`;
26 | return sanitizedURL;
27 | }
28 |
29 | export function getHost(url) {
30 | const urlObj = new URL(url);
31 | const { hostname } = urlObj;
32 | return hostname;
33 | }
--------------------------------------------------------------------------------