├── .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 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 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 | 3 | 4 | logo 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /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 |
43 | 52 |
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 | {`${shortName} 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 | {'background'} 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 | {'go 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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/bg-img.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/images/close-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/images/logo-wordmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 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 | 2 | 3 | 4 | 5 | 6 | 7 | 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 | } --------------------------------------------------------------------------------