diff --git a/.circleci/config.yml b/.circleci/config.yml index ded74216385..19fefbc0a49 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -328,6 +328,46 @@ jobs: - run: name: Compare test signatures for consensus, nonconsensus code command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'eval `opam config env` && export PATH="$HOME/.cargo/bin:$PATH" && ./scripts/compare_test_signatures.sh' + client-sdk-unit-tests: + docker: + - image: codaprotocol/coda:toolchain-9924f4c56a40d65d36440e8f70b93720f29ba171 + steps: + + - run: + name: Disable LFS checkout + command: | + git config --global filter.lfs.smudge "git-lfs smudge --skip %f" + git config --global lfs.fetchexclude "*" + - checkout + + + - run: + name: Update Submodules + command: git submodule sync && git submodule update --init --recursive + - run: + name: Create opam cache signature file including a year/date stamp to ensure occasional rebuilds + command: | + cat scripts/setup-opam.sh > opam_ci_cache.sig + cat src/opam.export >> opam_ci_cache.sig + date +%Y-%m >> opam_ci_cache.sig + - restore_cache: + name: Restore cache - opam + keys: + - opam-linux-v1-{{ checksum "opam_ci_cache.sig" }} + - run: + name: Install opam dependencies - opam -- make setup-opam + command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'make setup-opam' + + - run: + name: Build client SDK, run unit tests + command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'eval `opam config env` && export PATH="$HOME/.cargo/bin:$PATH" && ./scripts/client-sdk-unit-tests.sh' + - run: + name: Yarn deps + command: cd frontend/client_sdk && yarn install + - run: + name: Prepublish client SDK packages + command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'set -o pipefail; eval `opam config env` && cd frontend/client_sdk && yarn prepublishOnly' + update-branch-protection: docker: - image: python:3 @@ -511,54 +551,6 @@ jobs: command: ./scripts/skip_if_only_frontend_or_rfcs.sh scripts/artifacts.sh - store_artifacts: path: package - - build-client-sdk: - resource_class: large - docker: - - image: codaprotocol/coda:toolchain-9924f4c56a40d65d36440e8f70b93720f29ba171 - steps: - - - run: - name: Disable LFS checkout - command: | - git config --global filter.lfs.smudge "git-lfs smudge --skip %f" - git config --global lfs.fetchexclude "*" - - checkout - - - run: - name: Artifacts Path - command: | - mkdir -p /tmp/artifacts - - - run: - name: Update Submodules - command: git submodule sync && git submodule update --init --recursive - - run: - name: Create opam cache signature file including a year/date stamp to ensure occasional rebuilds - command: | - cat scripts/setup-opam.sh > opam_ci_cache.sig - cat src/opam.export >> opam_ci_cache.sig - date +%Y-%m >> opam_ci_cache.sig - - restore_cache: - name: Restore cache - opam - keys: - - opam-linux-v1-{{ checksum "opam_ci_cache.sig" }} - - run: - name: Install opam dependencies - opam -- make setup-opam - command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'make setup-opam' - - - run: - name: Build client SDK for Javascript - command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'set -o pipefail; eval `opam config env` && make client_sdk 2>&1 | tee /tmp/artifacts/buildclientsdk.log' - environment: - DUNE_PROFILE: nonconsensus_medium_curves - no_output_timeout: 10m - - run: - name: Yarn deps - command: cd frontend/client_sdk && yarn install - - run: - name: Build And Test Client SDK - command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'set -o pipefail; eval `opam config env` && cd frontend/client_sdk && yarn prepublishOnly' build-artifacts--testnet_postake_medium_curves: resource_class: xlarge docker: @@ -1467,6 +1459,7 @@ workflows: - lint - lint-opt - compare-test-signatures + - client-sdk-unit-tests - update-branch-protection: filters: branches: @@ -1476,7 +1469,6 @@ workflows: - test-archive - build-archive - build-macos - - build-client-sdk - build-artifacts--testnet_postake_medium_curves - build-artifacts-docker--testnet_postake_medium_curves--coda-daemon: requires: diff --git a/.circleci/config.yml.jinja b/.circleci/config.yml.jinja index 7c19fc62ac1..86f8481650f 100644 --- a/.circleci/config.yml.jinja +++ b/.circleci/config.yml.jinja @@ -225,6 +225,22 @@ jobs: - run: name: Compare test signatures for consensus, nonconsensus code command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'eval `opam config env` && export PATH="$HOME/.cargo/bin:$PATH" && ./scripts/compare_test_signatures.sh' + client-sdk-unit-tests: + docker: + - image: codaprotocol/coda:toolchain-9924f4c56a40d65d36440e8f70b93720f29ba171 + steps: + {{ checkout_no_lfs }} + {{ opam_init_linux }} + - run: + name: Build client SDK, run unit tests + command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'eval `opam config env` && export PATH="$HOME/.cargo/bin:$PATH" && ./scripts/client-sdk-unit-tests.sh' + - run: + name: Yarn deps + command: cd frontend/client_sdk && yarn install + - run: + name: Prepublish client SDK packages + command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'set -o pipefail; eval `opam config env` && cd frontend/client_sdk && yarn prepublishOnly' + update-branch-protection: docker: - image: python:3 @@ -388,30 +404,6 @@ jobs: - store_artifacts: path: package - build-client-sdk: - resource_class: large - docker: - - image: codaprotocol/coda:toolchain-9924f4c56a40d65d36440e8f70b93720f29ba171 - steps: - {{ checkout_no_lfs }} - - run: - name: Artifacts Path - command: | - mkdir -p /tmp/artifacts - {{ opam_init_linux }} - - run: - name: Build client SDK for Javascript - command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'set -o pipefail; eval `opam config env` && make client_sdk 2>&1 | tee /tmp/artifacts/buildclientsdk.log' - environment: - DUNE_PROFILE: nonconsensus_medium_curves - no_output_timeout: 10m - - run: - name: Yarn deps - command: cd frontend/client_sdk && yarn install - - run: - name: Build And Test Client SDK - command: ./scripts/skip_if_only_frontend_or_rfcs.sh bash -c 'set -o pipefail; eval `opam config env` && cd frontend/client_sdk && yarn prepublishOnly' - {%- for profile in build_artifact_profiles %} build-artifacts--{{profile}}: resource_class: xlarge @@ -704,6 +696,7 @@ workflows: - lint - lint-opt - compare-test-signatures + - client-sdk-unit-tests - update-branch-protection: filters: branches: @@ -713,7 +706,6 @@ workflows: - test-archive - build-archive - build-macos - - build-client-sdk {%- for profile in build_artifact_profiles %} - build-artifacts--{{profile}} {%- endfor %} diff --git a/.mergify.yml b/.mergify.yml index 606ab2dcbf1..16a1713f321 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -2,8 +2,8 @@ pull_request_rules: - name: automatically merge approved PRs with the ready-to-merge label conditions: - "status-success=ci/circleci: build-artifacts--testnet_postake_medium_curves" - - "status-success=ci/circleci: build-client-sdk" - "status-success=ci/circleci: build-wallet" + - "status-success=ci/circleci: client-sdk-unit-tests" - "status-success=ci/circleci: compare-test-signatures" - "status-success=ci/circleci: lint" - "status-success=ci/circleci: test--dev--coda-batch-payment-test" @@ -26,8 +26,8 @@ pull_request_rules: - name: automatically merge approved PRs into develop with the ready-to-merge-into-develop label conditions: - "status-success=ci/circleci: build-artifacts--testnet_postake_medium_curves" - - "status-success=ci/circleci: build-client-sdk" - "status-success=ci/circleci: build-wallet" + - "status-success=ci/circleci: client-sdk-unit-tests" - "status-success=ci/circleci: compare-test-signatures" - "status-success=ci/circleci: lint" - "status-success=ci/circleci: test--dev--coda-batch-payment-test" diff --git a/Makefile b/Makefile index 2d1f031dbd1..3edfe448b02 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,16 @@ client_sdk_test_sigs_nonconsensus : ulimit -s 65532 && (ulimit -n 10240 || true) && dune build src/app/client_sdk/tests/test_signatures_nonconsensus.exe --profile=nonconsensus_medium_curves $(info Build complete) +rosetta_lib_encodings : + $(info Starting Build) + ulimit -s 65532 && (ulimit -n 10240 || true) && dune build src/lib/rosetta_lib/test/test_encodings.exe --profile=testnet_postake_medium_curves + $(info Build complete) + +rosetta_lib_encodings_nonconsensus : + $(info Starting Build) + ulimit -s 65532 && (ulimit -n 10240 || true) && dune build src/nonconsensus/rosetta_lib/test/test_encodings.exe --profile=nonconsensus_medium_curves + $(info Build complete) + dhall_types : $(info Starting Build) ulimit -s 65532 && (ulimit -n 10240 || true) && dune build src/app/dhall_types/dump_dhall_types.exe --profile=dev diff --git a/buildkite/scripts/build-client-sdk.sh b/buildkite/scripts/build-client-sdk.sh deleted file mode 100755 index 3a663ff1eb9..00000000000 --- a/buildkite/scripts/build-client-sdk.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -o pipefail - -echo "--- Make client sdk" -mkdir -p /tmp/artifacts -make client_sdk 2>&1 | tee /tmp/artifacts/buildclientsdk.log - -echo "--- Yarn deps" -pushd frontend/client_sdk && yarn install && popd - -echo "--- Build and test Client SDK" -eval `opam config env` && \ - pushd frontend/client_sdk && \ - yarn prepublishOnly && \ - popd - diff --git a/buildkite/scripts/client-sdk-tool.sh b/buildkite/scripts/client-sdk-tool.sh new file mode 100755 index 00000000000..2fedaebc6e0 --- /dev/null +++ b/buildkite/scripts/client-sdk-tool.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -eo pipefail + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 ''" + exit 1 +fi + +yarn_args="${1}" + +echo "--- Client SDK execute: ${yarn_args}" +eval `opam config env` && \ + pushd frontend/client_sdk && \ + yarn install && \ + yarn ${yarn_args} && \ + popd diff --git a/buildkite/scripts/setup-database-for-archive-node.sh b/buildkite/scripts/setup-database-for-archive-node.sh index 90a49d8cd14..eaf39c2242f 100755 --- a/buildkite/scripts/setup-database-for-archive-node.sh +++ b/buildkite/scripts/setup-database-for-archive-node.sh @@ -6,7 +6,7 @@ user=$1 password=$2 db=$3 -sudo apt-get install -y postgresql +sudo apt-get update -y && sudo apt-get install -y postgresql sudo service postgresql start sudo -u postgres psql -c "CREATE USER ${user} WITH SUPERUSER PASSWORD '${password}';" -sudo -u postgres createdb -O $user $db \ No newline at end of file +sudo -u postgres createdb -O $user $db diff --git a/buildkite/src/Jobs/ClientSdk.dhall b/buildkite/src/Jobs/ClientSdk.dhall index 931f0c97f09..3eb919c1d44 100644 --- a/buildkite/src/Jobs/ClientSdk.dhall +++ b/buildkite/src/Jobs/ClientSdk.dhall @@ -1,14 +1,15 @@ let Prelude = ../External/Prelude.dhall -let S = ../Lib/SelectFiles.dhall +let S = ../Lib/SelectFiles.dhall let Cmd = ../Lib/Cmds.dhall let Pipeline = ../Pipeline/Dsl.dhall +let JobSpec = ../Pipeline/JobSpec.dhall + let Command = ../Command/Base.dhall let OpamInit = ../Command/OpamInit.dhall let Docker = ../Command/Docker/Type.dhall let Size = ../Command/Size.dhall -let JobSpec = ../Pipeline/JobSpec.dhall in @@ -23,14 +24,35 @@ Pipeline.build name = "ClientSdk" }, steps = [ - Command.build - Command.Config::{ - commands = OpamInit.andThenRunInDocker ([] : List Text) "./buildkite/scripts/build-client-sdk.sh", - label = "Build client-sdk", - key = "build-client-sdk", - target = Size.Medium, - docker = None Docker.Type - } + Command.build + Command.Config::{ + commands = [ + Cmd.run "chmod -R 777 frontend/client_sdk", + Cmd.runInDocker + Cmd.Docker::{image = (../Constants/ContainerImages.dhall).codaToolchain} + "cd frontend/client_sdk && yarn install" + ] + , label = "Install Yarn dependencies" + , key = "install-yarn-deps" + , target = Size.Small + , docker = None Docker.Type + }, + Command.build + Command.Config::{ + commands = OpamInit.andThenRunInDocker ([] : List Text) "./scripts/client-sdk-unit-tests.sh" + , label = "Build client SDK, run unit tests" + , key = "client-sdk-build-unittests" + , target = Size.Medium + , docker = None Docker.Type + }, + Command.build + Command.Config::{ + commands = OpamInit.andThenRunInDocker ([] : List Text) "./buildkite/scripts/client-sdk-tool.sh 'prepublishOnly'" + , label = "Prepublish client SDK packages" + , key = "prepublish-client-sdk" + , target = Size.Medium + , docker = None Docker.Type + } ] } diff --git a/frontend/website-redesign/pages/developers.js b/frontend/website-redesign/pages/developers.js deleted file mode 100644 index 602522a4e1a..00000000000 --- a/frontend/website-redesign/pages/developers.js +++ /dev/null @@ -1 +0,0 @@ -export { make as default } from '@reason/pages/Developers' diff --git a/frontend/website-redesign/pages/genesis.js b/frontend/website-redesign/pages/genesis.js deleted file mode 100644 index 8cb7eb86c28..00000000000 --- a/frontend/website-redesign/pages/genesis.js +++ /dev/null @@ -1 +0,0 @@ -export { make as default } from '@reason/pages/Genesis' diff --git a/frontend/website-redesign/pages/leaderboard.js b/frontend/website-redesign/pages/leaderboard.js deleted file mode 100644 index 824ecd5c85a..00000000000 --- a/frontend/website-redesign/pages/leaderboard.js +++ /dev/null @@ -1 +0,0 @@ -export { make as default } from '@reason/pages/LeaderboardPage' diff --git a/frontend/website-redesign/pages/memberProfile.js b/frontend/website-redesign/pages/memberProfile.js deleted file mode 100644 index 67ce377c6d0..00000000000 --- a/frontend/website-redesign/pages/memberProfile.js +++ /dev/null @@ -1 +0,0 @@ -export { make as default } from '@reason/pages/MemberProfilePage' diff --git a/frontend/website-redesign/pages/privacy.mdx b/frontend/website-redesign/pages/privacy.mdx deleted file mode 100644 index 23ed1b44711..00000000000 --- a/frontend/website-redesign/pages/privacy.mdx +++ /dev/null @@ -1,78 +0,0 @@ -import Page from '@reason/pages/MarkdownPage'; -export default Page({title: "Privacy Policy"}); - -**O(1) LABS OPERATING CORPORATION** - -**PRIVACY POLICY** - -**Last Updated: May 9th, 2018** - -This privacy policy ("**Policy**") describes how O(1) Labs Operating Corporation and its related companies ("**Company**") collect, use and share personal information of consumer users of this website, codaprotocol.com (the "**Site**"). This Policy also applies to any of our other websites that post this Policy. This Policy does not apply to websites that post different statements. - -**WHAT WE COLLECT** - -We get information about you in a range of ways. - -> **Information You Give Us.** We collect your email address as well as other information you directly give us on our Site. -> -> **Information We Get From Others.** We may get information about you from other sources. We may add this to information we get from this Site. -> -> **Information Automatically Collected.** We automatically log information about you and your computer. For example, when visiting our Site, we log your computer operating system type, browser type, browser language, the website you visited before browsing to our Site, pages you viewed, how long you spent on a page, access times and information about your use of and actions on our Site. -> -> **Cookies.** We may log information using "cookies." Cookies are small data files stored on your hard drive by a website. We may use both session Cookies (which expire once you close your web browser) and persistent Cookies (which stay on your computer until you delete them) to provide you with a more personal and interactive experience on our Site. This type of information is collected to make the Site more useful to you and to tailor the experience with us to meet your special interests and needs. - -**USE OF PERSONAL INFORMATION** - -We use your personal information as follows: - -* We use your personal information to operate, maintain, and improve our sites, products, and services. - -* We use your personal information to respond to comments and questions and provide customer service. - -* We use your personal information to send information including confirmations, invoices, technical notices, updates, security alerts, and support and administrative messages. - -* We use your personal information to communicate about promotions, upcoming events, and other news about products and services offered by us and our selected partners. - -* We use your personal information to provide and deliver products and services customers request. - - -**SHARING OF PERSONAL INFORMATION** - -We may share personal information as follows: - -* We may share personal information with your consent. For example, you may let us share personal information with others for their own marketing uses. Those uses will be subject to their privacy policies. - -* We may share personal information when we do a business deal, or negotiate a business deal, involving the sale or transfer of all or a part of our business or assets. These deals can include any merger, financing, acquisition, or bankruptcy transaction or proceeding. - -* We may share personal information for legal, protection, and safety purposes. - - * We may share information to comply with laws. - - * We may share information to respond to lawful requests and legal processes. - - * We may share information to protect the rights and property of O(1) Labs Operating Corporation, our agents, customers, and others. This includes enforcing our agreements, policies, and terms of use. - - * We may share information in an emergency. This includes protecting the safety of our employees and agents, our customers, or any person. - -* We may share information with those who need it to do work for us. - - -We may also share aggregated and/or anonymized data with others for their own uses. - -**INFORMATION CHOICES AND CHANGES** - -Our marketing emails tell you how to "opt-out." If you opt out, we may still send you non-marketing emails. Non-marketing emails include emails about your accounts and our business dealings with you. - -You may send requests about personal information to our Contact Information below. You can request to change contact choices, opt-out of our sharing with others, and update your personal information. - -You can typically remove and reject cookies from our Site with your browser settings. Many browsers are set to accept cookies until you change your settings. If you remove or reject our cookies, it could affect how our Site works for you. - -**CONTACT INFORMATION.** We welcome your comments or questions about this privacy policy. You may also contact us at our address: - -O(1) Labs Operating Corporation - -111 New Montgomery St Suite 400 - -San Francisco, California 94103 - -**CHANGES TO THIS PRIVACY POLICY.** We may change this privacy policy. If we make any changes, we will change the Last Updated date above. diff --git a/frontend/website-redesign/pages/tcGenesis.mdx b/frontend/website-redesign/pages/tcGenesis.mdx deleted file mode 100644 index 327c72d476d..00000000000 --- a/frontend/website-redesign/pages/tcGenesis.mdx +++ /dev/null @@ -1,119 +0,0 @@ -import Page from '@reason/pages/MarkdownPage'; -export default Page({title: "Coda Genesis Program Terms and Conditions"}); - -**Coda Genesis Program** - -**Program Details** - -1. The Coda Genesis Program prepares participants to become the network’s first block producers upon mainnet launch. Up to 1,000 members will be selected from the Coda testnet community to receive a distribution of 66,000 tokens as founding members of the Genesis Program. -2. Members will be able to participate in the Coda testnet by completing challenges, learning how to operate the protocol, strengthening and hardening the protocol through feedback, creating tooling and documentation and building the community. -3. At mainnet launch, up to 6.67% of coda tokens will be distributed amongst Genesis founding members. All Genesis founding members who qualify will receive the same amount of coda tokens. **No token distributions will be confirmed or guaranteed at any time before mainnet launch**. -4. Genesis founding members will be required to participate as block producers on mainnet by staking or delegating their tokens. All tokens distributed under the Genesis program (from Cohort 2 onwards*) will be subject to a 4 year vesting period starting at mainnet launch. During the vesting period, Genesis members must participate by staking or delegating all of their unvested tokens. **Members who do not stake or delegate for the entire vesting period will forfeit all of their unvested tokens.** *Note: Cohort 1 has a 1-year staking period -5. 25% of tokens will vest on the one year anniversary of mainnet launch, with the remaining tokens vesting in equal monthly tranches over the following three years. Additional tokens earned as a reward for staking or delegating are not subject to any restrictions. Refer to the Vesting Schedule below for more information. -6. To become a Genesis founding member, you must complete the application, pass KYC checks and provide all required documentation, and agree to the Terms and Conditions. - -**Vesting Schedule** - -**(**Based on a grant of 66,000 tokens) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- New tokens - Cumulative tokens vested -
Year 1 - 0 - 0 -
End of year 1 - 16,500 - 16,500 -
Each month after year 1 - 1,375 - - -
End of year 2 - - - 33,000 -
End of year 3 - - - 49,500 -
End of year 4 - - - - 66,000 -
- -**Terms and Conditions** - -1. These terms and conditions (“Terms”) govern the Coda Genesis Program (the “Program”) and form a binding agreement between you and O(1) Labs Operating Corporation (“O1 Labs”). By applying to participate in the Program, you agree to be bound by these Terms and the O1 Labs Privacy Policy, which can be found at https://codaprotocol.com/privacy.html -2. The Program prepares participants to become the first block producers upon Coda Protocol’s mainnet launch. It is designed to enable a wide range of independent participants to become significant block producers. In order to have a sufficiently large set of block producers, there needs to be a large number of independent participants who hold coda tokens immediately after mainnet launch and have the technical knowledge and competence to stake tokens. Participants who hold coda tokens may also be incentivized to make other valuable contributions to Coda Protocol and its community of users. -3. APPLYING TO PARTICIPATE IN THE PROGRAM OR BECOMING A MEMBER DOES NOT GRANT YOU ANY RIGHTS OR ENTITLEMENTS AND SPECIFICALLY DOES NOT GUARANTEE THAT YOU WILL RECEIVE ANY PAYMENT, COMPENSATION, REWARD OR OTHER VALUE, INCLUDING CODA TOKENS. -4. To become a Member you must: - a. be at least 18 years of age and not be prohibited from participating in the Program by any applicable law or regulation, - b. not be a citizen or resident of any jurisdiction subject to sanctions as enforced by the Office of Foreign Assets Control, including without limitation Burma, Crimea and Sevastopol, Cote d’Ivoire, Cuba, Democratic Republic of Congo, Iran, Iraq, Libya, North Korea, Sudan, Syria, Zimbabwe, and you must not be named by OFAC as a Specially Designated National or Blocked Person; - c. not be an employee, contractor, shareholder, investor or other related party of O(1) Labs, - d. not be an employee, contractor, shareholder, investor or other related party of any company, organization or entity that operates a business as a miner, staker or other validator on a public blockchain, if another Member shares the same affiliation(s) - i.e. only one person per company can be a Member; - e. confirm your intent and ability, if you were to receive coda tokens in the future, to participate as a block producer by staking or delegating the tokens, - f. pass KYC checks by proving your identity, or if you represent an entity, by also providing the required corporate documents and proving the identity of the ultimate beneficial owner(s) of the entity. -5. If you have met the requirements above, then you may be registered as a Member. Meeting the requirements does not guarantee that you will become a Member. Becoming a Member does not guarantee that you will receive coda tokens or any other benefits. -6. When identifying participants who may qualify as Members, the following contributions may be taken into account: being a testnet participant, creating documentation, including explanatory documents and blog posts, stress-testing the protocol, creating tooling for the protocol or applications that use the protocol, translating documentation into different languages, providing help and support to users and other participants, including creating and moderating chats, forums, social media channels and meetups, and reporting bugs and issues in the protocol. -7. Coda Protocol Testnet points may be taken into consideration when determining whether you qualify as a Member. However, testnet points do not guarantee eligibility for the Program or receipt of any benefits, and are not redeemable for cash or other value. Testnet points are an indication of the participant’s technical competence and commitment to support the protocol. For example, a participant with more testnet points is more likely to have the know-how to be a Block Producer on Coda Protocol mainnet, or to detect and report bugs effectively. However, O(1) Labs will not make any discretionary judgment about the value of any participant’s contributions. -8. No distributions will be made before the mainnet launch of Coda Protocol. You are not guaranteed to receive a distribution until the time that you actually receive coda tokens and fully satisfy the vesting requirements. -9. All Members who receive a distribution will receive the same amount of coda tokens. O(1) Labs will not have discretion to allocate more or fewer tokens to any participant. -10. All tokens distributed under the Genesis program, for Cohort 2 and all following Cohorts, will be subject to a 4 year vesting period commencing on the day of Coda Protocol’s mainnet genesis block (“Vesting Period”). -11. **IF YOU DO NOT STAKE OR DELEGATE ALL UNVESTED TOKENS FOR THE DURATION OF THE VESTING PERIOD THEN YOU RISK FORFEITING ANY UNVESTED TOKENS.** -12. During the Vesting Period, forfeiture will be enforced automatically at the protocol level. This means that if you fail to meet the staking requirement, Coda Protocol will automatically enforce the forfeiture of your tokens, which will be irreversible and not subject to dispute. O(1) Labs will not be able to prevent forfeiture from being enforced by Coda Protocol and will not compensate you in the event that your tokens are forfeited. -13. At the end of the one year anniversary of the genesis block, one-quarter of your coda tokens will vest and be fully released. Those tokens will be immediately available to you, with no further restrictions on transfer or sale. The remaining three quarters of the tokens will vest in equal tranches at the end of each month over the following three years. -14. Vested tokens will be immediately available to you, with no further restrictions on transfer or sale. Additional tokens earned as a reward for staking or delegating are not subject to any restrictions on transfer or sale. -15. During the Vesting Period: - a. your full entitlement of tokens will be available for staking or delegating; and - b. all unvested tokens will be unable to be sold or transferred to any other address - this will be enforced automatically at the protocol level. -16. YOU ACCEPT AND ACKNOWLEDGE THAT THERE ARE RISKS ASSOCIATED WITH USING ANY CRYPTOCURRENCY NETWORK, INCLUDING, BUT NOT LIMITED TO, THE RISK OF UNKNOWN VULNERABILITIES IN OR UNANTICIPATED CHANGES TO THE NETWORK PROTOCOL. YOU ACKNOWLEDGE AND ACCEPT THE RISKS OF FUTURE CHANGES TO CODA PROTOCOL AND AGREE THAT O(1) LABS IS NOT RESPONSIBLE FOR SUCH OPERATING CHANGES AND IS NOT LIABLE FOR ANY LOSS OF VALUE YOU MAY EXPERIENCE AS A RESULT OF SUCH CHANGES IN OPERATING RULES. YOU ACCEPT AND ACKNOWLEDGE THAT O(1) LABS WILL NOT BE RESPONSIBLE FOR ANY LOSSES, FAILURES, DISRUPTIONS, ERRORS, DISTORTIONS OR DELAYS YOU MAY EXPERIENCE WHEN PARTICIPATING IN THE PROGRAM, HOWEVER CAUSED. YOU ACKNOWLEDGE AND ACCEPT THAT O(1) LABS HAS NO CONTROL OVER ANY CRYPTOCURRENCY NETWORK AND WILL NOT BE RESPONSIBLE FOR ANY HARM OCCURRING AS A RESULT OF SUCH RISKS. -17. O(1) LABS WILL NOT BE RESPONSIBLE OR LIABLE TO YOU FOR ANY LOSS AND TAKES NO RESPONSIBILITY FOR AND WILL NOT BE LIABLE TO YOU FOR YOUR PARTICIPATION IN THE PROGRAM, INCLUDING BUT NOT LIMITED TO ANY LOSSES, DAMAGES OR CLAIMS ARISING FROM: (I) USER ERROR SUCH AS FORGOTTEN PASSWORDS, LOST OR MISSING PRIVATE KEYS, INCORRECTLY CONSTRUCTED TRANSACTIONS, OR MISTYPED ADDRESSES; (II) SERVER FAILURE; (III) CORRUPTED WALLET FILES; (IV) UNAUTHORIZED ACCESS TO APPLICATIONS; OR (V) ANY UNAUTHORIZED THIRD PARTY ACTIVITIES, INCLUDING WITHOUT LIMITATION THE USE OF VIRUSES, PHISHING, BRUTE FORCING OR OTHER MEANS OF ATTACK. -18. O(1) LABS MAKES NO WARRANTY THAT ANY CODA TESTNET OR CODA MAINNET INCLUDING WALLETS, NODES OR ANY OTHER SOFTWARE RELEASED BY O(1) LABS, ARE FREE OF VIRUSES OR ERRORS, WILL BE UNINTERRUPTED, OR THAT DEFECTS WILL BE CORRECTED. O(1) LABS WILL NOT BE RESPONSIBLE OR LIABLE TO YOU FOR ANY LOSS OF ANY KIND, FROM ACTION TAKEN, OR TAKEN IN RELIANCE ON MATERIAL, OR INFORMATION, CONTAINED OR MADE AVAILABLE THROUGH THE PROGRAM. -19. ALL PROGRAMS, APPLICATIONS, SOFTWARE, DOCUMENTATION AND OTHER MATERIALS RELATED TO CODA PROTOCOL ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS WITHOUT ANY REPRESENTATION OR WARRANTY, WHETHER EXPRESS, IMPLIED OR STATUTORY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, O(1) LABS SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND/OR NON-INFRINGEMENT. O(1) LABS DOES NOT MAKE ANY REPRESENTATIONS OR WARRANTIES THAT ACCESS TO AND PART OF CODA PROTOCOL OR ANY OF THE MATERIALS CONTAINED THEREIN, WILL BE CONTINUOUS, UNINTERRUPTED, TIMELY, OR ERROR-FREE. EXCEPT FOR THE EXPRESS STATEMENTS SET FORTH IN THIS AGREEMENT, YOU HEREBY ACKNOWLEDGE AND AGREE THAT YOU HAVE NOT RELIED UPON ANY OTHER STATEMENT OR UNDERSTANDING, WHETHER WRITTEN OR ORAL, WITH RESPECT TO YOUR APPLICATION TO OR PARTICIPATION IN THE PROGRAM. -20. It is your sole responsibility to determine whether, and to what extent, any taxes apply as a result of your participation in the Program, including as a result of acquiring or staking coda tokens, and to withhold, collect, report and remit the correct amounts of taxes to the appropriate tax authorities. For the avoidance of doubt, O(1) Labs does not provide investment, tax, or legal advice. You should consult with a professional tax adviser regarding your specific situation. -21. You will indemnify and hold harmless O(1) Labs, its affiliates, and their respective officers, directors, employees and agents (together, the “Released Parties”), from and against any claims, disputes, demands, liabilities, damages, losses, and costs and expenses, including, without limitation, reasonable legal and accounting fees arising out of or in any way connected with your participation in the Program. -22. NEITHER THE RELEASED PARTIES NOR ANY OTHER PARTY INVOLVED IN THE PROGRAM WILL BE LIABLE FOR ANY INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOST PROFITS, LOST REVENUES, LOST SAVINGS, LOST BUSINESS OPPORTUNITY, LOSS OF DATA OR GOODWILL, SERVICE INTERRUPTION, COMPUTER DAMAGE OR SYSTEM FAILURE OR THE COST OF SUBSTITUTE ACTIVITIES OF ANY KIND ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR YOUR PARTICIPATION IN, OR INABILITY TO PARTICIPATE IN, THE PROGRAM, WHETHER BASED ON WARRANTY, CONTRACT, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR ANY OTHER LEGAL THEORY, AND WHETHER OR NOT O(1) LABS OR ANY OTHER PARTY HAS BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGE, EVEN IF A LIMITED REMEDY SET FORTH HEREIN IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, SO THE ABOVE LIMITATION MAY NOT APPLY TO YOU. -23. THE EXCLUSIONS AND LIMITATIONS OF DAMAGES SET FORTH ABOVE ARE FUNDAMENTAL ELEMENTS OF THE BASIS OF THE BARGAIN BETWEEN O(1) LABS AND YOU. -24. These Terms and any action related thereto will be governed by the laws of the state of California in the United States of America without regard to its conflict of laws provisions. The exclusive jurisdiction for all disputes will be in San Francisco, California, and you and O(1) Labs each waive any objection to such jurisdiction and venue. -25. You and we agree that any dispute arising out of or relating to the Program or these Terms, including, without limitation, federal and state statutory claims, common law claims, and those based in contract, tort, fraud, misrepresentation, or any other legal theory, shall be resolved through binding arbitration, on an individual basis. Subject to applicable jurisdictional requirements, you may elect to pursue your claim in your local small claims court rather than through arbitration so long as your matter remains in small claims court and proceeds only on an individual (non-class and non-representative) basis. Arbitration shall be conducted in accordance with the American Arbitration Association's rules for arbitration of consumer-related disputes. This agreement to arbitrate includes, without limitation, disputes arising out of or related to the interpretation or application of the Arbitration Agreement, including the enforceability, revocability, scope, or validity of the Arbitration Agreement or any portion of the Arbitration Agreement. All such matters shall be decided by an arbitrator and not by a court or judge. -26. The place of arbitration shall be in San Francisco, California. The language of arbitration shall be English. The arbitral award shall be final and binding upon both parties. TO THE EXTENT PERMISSIBLE BY LAW, ALL CLAIMS MUST BE BROUGHT IN A PARTY’S INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS, COLLECTIVE ACTION, OR REPRESENTATIVE PROCEEDING. THE ARBITRATOR MAY NOT CONSOLIDATE MORE THAN ONE PERSON'S CLAIMS OR ENGAGE IN ANY CLASS ARBITRATION. YOU ACKNOWLEDGE THAT, BY AGREEING TO THESE TERMS, YOU ARE WAIVING THE RIGHT TO A TRIAL BY JURY AND THE RIGHT TO PARTICIPATE IN A CLASS ACTION -27. These Terms constitute the entire and exclusive understanding and agreement between O(1) Labs and you regarding the Program, and the Terms supersede and replace any and all prior oral or written understandings or agreements between O(1) Labs and you. To the extent of any conflict or inconsistency between these Terms and any other documents or materials provided by O(1) Labs, these Terms prevail. If any provision of the Terms is held invalid or unenforceable by an arbitrator or a court of competent jurisdiction, that provision will be enforced to the maximum extent permissible and the other provisions of the Terms will remain in full force and effect. You may not assign or transfer the Terms, by operation of law or otherwise, without O(1) Labs’s prior written consent. Any attempt by you to assign or transfer the Terms, without such consent, will be null and void. O(1) Labs may freely assign or transfer these Terms without restriction. Subject to the foregoing, these Terms will bind and inure to the benefit of the parties, their successors and permitted assigns. -28. O(1) Labs’s failure to enforce any right or provision of these Terms will not be considered a waiver of such right or provision. The waiver of any such right or provision will be effective only if in writing and signed by a duly authorized representative of O(1) Labs. Except as expressly set forth in these Terms, the exercise by either party of any of its remedies under these Terms will be without prejudice to its other remedies under these Terms or otherwise. -29. O(1) Labs may, with or without prior notice and at any time, modify or terminate, temporarily or permanently, any part or all of the Program, except for distributions of coda that have been confirmed in the genesis block. Once distributions have been confirmed at the protocol level, neither O(1) Labs nor any other party has the ability to cancel or change them. Any notices or other communications provided by O(1) Labs under the Terms, including those regarding modifications to the Terms, will be posted on this page. - -_Last updated July 8, 2020._ diff --git a/frontend/website-redesign/pages/testnet.js b/frontend/website-redesign/pages/testnet.js deleted file mode 100644 index 8fe27529075..00000000000 --- a/frontend/website-redesign/pages/testnet.js +++ /dev/null @@ -1 +0,0 @@ -export { make as default } from '@reason/pages/Testnet' diff --git a/frontend/website-redesign/pages/tos.mdx b/frontend/website-redesign/pages/tos.mdx deleted file mode 100644 index 6f1cd39e37e..00000000000 --- a/frontend/website-redesign/pages/tos.mdx +++ /dev/null @@ -1,160 +0,0 @@ -import Page from '@reason/pages/MarkdownPage'; -export default Page({title: "Terms and Services"}); - -**Website Terms of Use** - -**Version 1.0** - -**Last revised on: May 9th, 2018** - -The website located at codaprotocol.com (the "**Site**") is a copyrighted work belonging to O(1) Labs Operating Corporation ("**Company**", "**us**", "**our**", and "**we**"). Certain features of the Site may be subject to additional guidelines, terms, or rules, which will be posted on the Site in connection with such features. All such additional terms, guidelines, and rules are incorporated by reference into these Terms. - -These Terms of Use (these "**Terms**") set forth the legally binding terms and conditions that govern your use of the Site. By accessing or using the Site, you are accepting these Terms (on behalf of yourself or the entity that you represent), and you represent and warrant that you have the right, authority, and capacity to enter into these Terms (on behalf of yourself or the entity that you represent). you may not access or use the Site or accept the Terms if you are not at least 18 years old. If you do not agree with all of the provisions of these Terms, do not access and/or use the Site. - -These terms require the use of arbitration (Section 10.2) on an individual basis to resolve disputes, rather than jury trials or class actions, and also limit the remedies available to you in the event of a dispute. - -1. **Accounts** - -2. **Account Creation.** In order to use certain features of the Site, you must register for an account ("**Account**") and provide certain information about yourself as prompted by the account registration form. You represent and warrant that: (a) all required registration information you submit is truthful and accurate; (b) you will maintain the accuracy of such information. You may delete your Account at any time, for any reason, by following the instructions on the Site. Company may suspend or terminate your Account in accordance with Section 8. - -3. **Account Responsibilities.** You are responsible for maintaining the confidentiality of your Account login information and are fully responsible for all activities that occur under your Account. You agree to immediately notify Company of any unauthorized use, or suspected unauthorized use of your Account or any other breach of security. Company cannot and will not be liable for any loss or damage arising from your failure to comply with the above requirements. - -4. **Access to the Site** - -5. **License.** Subject to these Terms, Company grants you a non-transferable, non-exclusive, revocable, limited license to use and access the Site solely for your own personal, noncommercial use. - -6. **Certain Restrictions.** The rights granted to you in these Terms are subject to the following restrictions: (a) you shall not license, sell, rent, lease, transfer, assign, distribute, host, or otherwise commercially exploit the Site, whether in whole or in part, or any content displayed on the Site; (b) you shall not modify, make derivative works of, disassemble, reverse compile or reverse engineer any part of the Site; (c) you shall not access the Site in order to build a similar or competitive website, product, or service; and (d) except as expressly stated herein, no part of the Site may be copied, reproduced, distributed, republished, downloaded, displayed, posted or transmitted in any form or by any means. Unless otherwise indicated, any future release, update, or other addition to functionality of the Site shall be subject to these Terms. All copyright and other proprietary notices on the Site (or on any content displayed on the Site) must be retained on all copies thereof. - -7. **Modification.** Company reserves the right, at any time, to modify, suspend, or discontinue the Site (in whole or in part) with or without notice to you. You agree that Company will not be liable to you or to any third party for any modification, suspension, or discontinuation of the Site or any part thereof. - -8. **No Support or Maintenance.** You acknowledge and agree that Company will have no obligation to provide you with any support or maintenance in connection with the Site. - -9. **Ownership.** Excluding any User Content that you may provide (defined below), you acknowledge that all the intellectual property rights, including copyrights, patents, trade marks, and trade secrets, in the Site and its content are owned by Company or Company’s suppliers. Neither these Terms (nor your access to the Site) transfers to you or any third party any rights, title or interest in or to such intellectual property rights, except for the limited access rights expressly set forth in Section 2.1. Company and its suppliers reserve all rights not granted in these Terms. There are no implied licenses granted under these Terms. - -10. **User Content** - -11. **User Content.** "**User Content**" means any and all information and content that a user submits to, or uses with, the Site (e.g., content in the user’s profile or postings). You are solely responsible for your User Content. You assume all risks associated with use of your User Content, including any reliance on its accuracy, completeness or usefulness by others, or any disclosure of your User Content that personally identifies you or any third party. You hereby represent and warrant that your User Content does not violate our Acceptable Use Policy (defined in Section 3.3). You may not represent or imply to others that your User Content is in any way provided, sponsored or endorsed by Company. Because you alone are responsible for your User Content, you may expose yourself to liability if, for example, your User Content violates the Acceptable Use Policy. Company is not obligated to backup any User Content, and your User Content may be deleted at any time without prior notice. You are solely responsible for creating and maintaining your own backup copies of your User Content if you desire. - -12. **License.** You hereby grant (and you represent and warrant that you have the right to grant) to Company an irrevocable, nonexclusive, royalty-free and fully paid, worldwide license to reproduce, distribute, publicly display and perform, prepare derivative works of, incorporate into other works, and otherwise use and exploit your User Content, and to grant sublicenses of the foregoing rights, solely for the purposes of including your User Content in the Site. You hereby irrevocably waive (and agree to cause to be waived) any claims and assertions of moral rights or attribution with respect to your User Content. - -13. **Acceptable Use Policy.** The following terms constitute our "**Acceptable Use Policy**": - -14. You agree not to use the Site to collect, upload, transmit, display, or distribute any User Content (i) that violates any third-party right, including any copyright, trademark, patent, trade secret, moral right, privacy right, right of publicity, or any other intellectual property or proprietary right; (ii) that is unlawful, harassing, abusive, tortious, threatening, harmful, invasive of another’s privacy, vulgar, defamatory, false, intentionally misleading, trade libelous, pornographic, obscene, patently offensive, promotes racism, bigotry, hatred, or physical harm of any kind against any group or individual or is otherwise objectionable; (iii) that is harmful to minors in any way; or (iv) that is in violation of any law, regulation, or obligations or restrictions imposed by any third party. - -15. In addition, you agree not to: (i) upload, transmit, or distribute to or through the Site any computer viruses, worms, or any software intended to damage or alter a computer system or data; (ii) send through the Site unsolicited or unauthorized advertising, promotional materials, junk mail, spam, chain letters, pyramid schemes, or any other form of duplicative or unsolicited messages, whether commercial or otherwise; (iii) use the Site to harvest, collect, gather or assemble information or data regarding other users, including e-mail addresses, without their consent; (iv) interfere with, disrupt, or create an undue burden on servers or networks connected to the Site, or violate the regulations, policies or procedures of such networks; (v) attempt to gain unauthorized access to the Site (or to other computer systems or networks connected to or used together with the Site), whether through password mining or any other means; (vi) harass or interfere with any other user’s use and enjoyment of the Site; or (vi) use software or automated agents or scripts to produce multiple accounts on the Site, or to generate automated searches, requests, or queries to (or to strip, scrape, or mine data from) the Site (provided, however, that we conditionally grant to the operators of public search engines revocable permission to use spiders to copy materials from the Site for the sole purpose of and solely to the extent necessary for creating publicly available searchable indices of the materials, but not caches or archives of such materials, subject to the parameters set forth in our robots.txt file). - -16. **Enforcement.** We reserve the right (but have no obligation) to review any User Content, and to investigate and/or take appropriate action against you in our sole discretion if you violate the Acceptable Use Policy or any other provision of these Terms or otherwise create liability for us or any other person. Such action may include removing or modifying your User Content, terminating your Account in accordance with Section 8, and/or reporting you to law enforcement authorities. - -17. **Feedback.** If you provide Company with any feedback or suggestions regarding the Site ("**Feedback**"), you hereby assign to Company all rights in such Feedback and agree that Company shall have the right to use and fully exploit such Feedback and related information in any manner it deems appropriate. Company will treat any Feedback you provide to Company as non-confidential and non-proprietary. You agree that you will not submit to Company any information or ideas that you consider to be confidential or proprietary. - -18. **Indemnification.** You agree to indemnify and hold Company (and its officers, employees, and agents) harmless, including costs and attorneys’ fees, from any claim or demand made by any third party due to or arising out of (a) your use of the Site, (b) your violation of these Terms, (c) your violation of applicable laws or regulations or (d) your User Content. Company reserves the right, at your expense, to assume the exclusive defense and control of any matter for which you are required to indemnify us, and you agree to cooperate with our defense of these claims. You agree not to settle any matter without the prior written consent of Company. Company will use reasonable efforts to notify you of any such claim, action or proceeding upon becoming aware of it. - -19. **Third-Party Links & Ads; Other Users** - -20. **Third-Party Links & Ads.** The Site may contain links to third-party websites and services, and/or display advertisements for third parties (collectively, "**Third-Party Links & Ads**"). Such Third-Party Links & Ads are not under the control of Company, and Company is not responsible for any Third-Party Links & Ads. Company provides access to these Third-Party Links & Ads only as a convenience to you, and does not review, approve, monitor, endorse, warrant, or make any representations with respect to Third-Party Links & Ads. You use all Third-Party Links & Ads at your own risk, and should apply a suitable level of caution and discretion in doing so. When you click on any of the Third-Party Links & Ads, the applicable third party’s terms and policies apply, including the third party’s privacy and data gathering practices. You should make whatever investigation you feel necessary or appropriate before proceeding with any transaction in connection with such Third-Party Links & Ads. - -21. **Other Users.** Each Site user is solely responsible for any and all of its own User Content. Because we do not control User Content, you acknowledge and agree that we are not responsible for any User Content, whether provided by you or by others. We make no guarantees regarding the accuracy, currency, suitability, or quality of any User Content. Your interactions with other Site users are solely between you and such users. You agree that Company will not be responsible for any loss or damage incurred as the result of any such interactions. If there is a dispute between you and any Site user, we are under no obligation to become involved. - -22. **Release.** You hereby release and forever discharge the Company (and our officers, employees, agents, successors, and assigns) from, and hereby waive and relinquish, each and every past, present and future dispute, claim, controversy, demand, right, obligation, liability, action and cause of action of every kind and nature (including personal injuries, death, and property damage), that has arisen or arises directly or indirectly out of, or that relates directly or indirectly to, the Site (including any interactions with, or act or omission of, other Site users or any Third-Party Links & Ads). IF YOU ARE A CALIFORNIA RESIDENT, YOU HEREBY WAIVE CALIFORNIA CIVIL CODE SECTION 1542 IN CONNECTION WITH THE FOREGOING, WHICH STATES: “A GENERAL RELEASE DOES NOT EXTEND TO CLAIMS WHICH THE CREDITOR DOES NOT KNOW OR SUSPECT TO EXIST IN HIS OR HER FAVOR AT THE TIME OF EXECUTING THE RELEASE, WHICH IF KNOWN BY HIM OR HER MUST HAVE MATERIALLY AFFECTED HIS OR HER SETTLEMENT WITH THE DEBTOR.” - -23. **Disclaimers** - - -THE SITE IS PROVIDED ON AN "AS-IS" AND "AS AVAILABLE" BASIS, AND COMPANY (AND OUR SUPPLIERS) EXPRESSLY DISCLAIM ANY AND ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING ALL WARRANTIES OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, QUIET ENJOYMENT, ACCURACY, OR NON-INFRINGEMENT. WE (AND OUR SUPPLIERS) MAKE NO WARRANTY THAT THE SITE WILL MEET YOUR REQUIREMENTS, WILL BE AVAILABLE ON AN UNINTERRUPTED, TIMELY, SECURE, OR ERROR-FREE BASIS, OR WILL BE ACCURATE, RELIABLE, FREE OF VIRUSES OR OTHER HARMFUL CODE, COMPLETE, LEGAL, OR SAFE. IF APPLICABLE LAW REQUIRES ANY WARRANTIES WITH RESPECT TO THE SITE, ALL SUCH WARRANTIES ARE LIMITED IN DURATION TO NINETY (90) DAYS FROM THE DATE OF FIRST USE. - -SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO YOU. SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY LASTS, SO THE ABOVE LIMITATION MAY NOT APPLY TO YOU. - -24. **Limitation on Liability** - - TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL COMPANY (OR OUR SUPPLIERS) BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY LOST PROFITS, LOST DATA, COSTS OF PROCUREMENT OF SUBSTITUTE PRODUCTS, OR ANY INDIRECT, CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL OR PUNITIVE DAMAGES ARISING FROM OR RELATING TO THESE TERMS OR YOUR USE OF, OR INABILITY TO USE, THE SITE, EVEN IF COMPANY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ACCESS TO, AND USE OF, THE SITE IS AT YOUR OWN DISCRETION AND RISK, AND YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR DEVICE OR COMPUTER SYSTEM, OR LOSS OF DATA RESULTING THEREFROM. - - TO THE MAXIMUM EXTENT PERMITTED BY LAW, NOTWITHSTANDING ANYTHING TO THE CONTRARY CONTAINED HEREIN, OUR LIABILITY TO YOU FOR ANY DAMAGES ARISING FROM OR RELATED TO THIS AGREEMENT (FOR ANY CAUSE WHATSOEVER AND REGARDLESS OF THE FORM OF THE ACTION), WILL AT ALL TIMES BE LIMITED TO A MAXIMUM OF FIFTY US DOLLARS (U.S. $50). THE EXISTENCE OF MORE THAN ONE CLAIM WILL NOT ENLARGE THIS LIMIT. YOU AGREE THAT OUR SUPPLIERS WILL HAVE NO LIABILITY OF ANY KIND ARISING FROM OR RELATING TO THIS AGREEMENT. - - SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATION OR EXCLUSION MAY NOT APPLY TO YOU. - -25. **Term and Termination.** Subject to this Section, these Terms will remain in full force and effect while you use the Site. We may suspend or terminate your rights to use the Site (including your Account) at any time for any reason at our sole discretion, including for any use of the Site in violation of these Terms. Upon termination of your rights under these Terms, your Account and right to access and use the Site will terminate immediately. You understand that any termination of your Account may involve deletion of your User Content associated with your Account from our live databases. Company will not have any liability whatsoever to you for any termination of your rights under these Terms, including for termination of your Account or deletion of your User Content. Even after your rights under these Terms are terminated, the following provisions of these Terms will remain in effect: Sections 2.2 through 2.5, Section 3 and Sections 4 through 10. - -26. **Copyright Policy.** - - Company respects the intellectual property of others and asks that users of our Site do the same. In connection with our Site, we have adopted and implemented a policy respecting copyright law that provides for the removal of any infringing materials and for the termination, in appropriate circumstances, of users of our online Site who are repeat infringers of intellectual property rights, including copyrights. If you believe that one of our users is, through the use of our Site, unlawfully infringing the copyright(s) in a work, and wish to have the allegedly infringing material removed, the following information in the form of a written notification (pursuant to 17 U.S.C. § 512(c)) must be provided to our designated Copyright Agent: - - -1. your physical or electronic signature; - -2. identification of the copyrighted work(s) that you claim to have been infringed; - -3. identification of the material on our services that you claim is infringing and that you request us to remove; - -4. sufficient information to permit us to locate such material; - -5. your address, telephone number, and e-mail address; - -6. a statement that you have a good faith belief that use of the objectionable material is not authorized by the copyright owner, its agent, or under the law; and - -7. a statement that the information in the notification is accurate, and under penalty of perjury, that you are either the owner of the copyright that has allegedly been infringed or that you are authorized to act on behalf of the copyright owner. - - -Please note that, pursuant to 17 U.S.C. § 512(f), any misrepresentation of material fact (falsities) in a written notification automatically subjects the complaining party to liability for any damages, costs and attorney’s fees incurred by us in connection with the written notification and allegation of copyright infringement. - -27. **General** - -28. **Changes.** These Terms are subject to occasional revision, and if we make any substantial changes, we may notify you by sending you an e-mail to the last e-mail address you provided to us (if any), and/or by prominently posting notice of the changes on our Site. You are responsible for providing us with your most current e-mail address. In the event that the last e-mail address that you have provided us is not valid, or for any reason is not capable of delivering to you the notice described above, our dispatch of the e-mail containing such notice will nonetheless constitute effective notice of the changes described in the notice. Any changes to these Terms will be effective upon the earlier of thirty (30) calendar days following our dispatch of an e-mail notice to you (if applicable) or thirty (30) calendar days following our posting of notice of the changes on our Site. These changes will be effective immediately for new users of our Site. Continued use of our Site following notice of such changes shall indicate your acknowledgement of such changes and agreement to be bound by the terms and conditions of such changes. - -29. **Dispute Resolution. _Please read this Arbitration Agreement carefully. It is part of your contract with Company and affects your rights. It contains procedures for MANDATORY BINDING ARBITRATION AND A CLASS ACTION WAIVER._** - -30. _Applicability of Arbitration Agreement._ All claims and disputes (excluding claims for injunctive or other equitable relief as set forth below) in connection with the Terms or the use of any product or service provided by the Company that cannot be resolved informally or in small claims court shall be resolved by binding arbitration on an individual basis under the terms of this Arbitration Agreement. Unless otherwise agreed to, all arbitration proceedings shall be held in English. This Arbitration Agreement applies to you and the Company, and to any subsidiaries, affiliates, agents, employees, predecessors in interest, successors, and assigns, as well as all authorized or unauthorized users or beneficiaries of services or goods provided under the Terms. - -31. _Notice Requirement and Informal Dispute Resolution_. Before either party may seek arbitration, the party must first send to the other party a written Notice of Dispute (**“Notice”**) describing the nature and basis of the claim or dispute, and the requested relief. A Notice to the Company should be sent to: 362 Pierce St Apt D, San Francisco, California 94117. After the Notice is received, you and the Company may attempt to resolve the claim or dispute informally. If you and the Company do not resolve the claim or dispute within thirty (30) days after the Notice is received, either party may begin an arbitration proceeding. The amount of any settlement offer made by any party may not be disclosed to the arbitrator until after the arbitrator has determined the amount of the award, if any, to which either party is entitled. - -32. Arbitration Rules. Arbitration shall be initiated through the American Arbitration Association (**"AAA"**), an established alternative dispute resolution provider (**"ADR Provider"**) that offers arbitration as set forth in this section. If AAA is not available to arbitrate, the parties shall agree to select an alternative ADR Provider. The rules of the ADR Provider shall govern all aspects of the arbitration, including but not limited to the method of initiating and/or demanding arbitration, except to the extent such rules are in conflict with the Terms. The AAA Consumer Arbitration Rules (**"Arbitration Rules"**) governing the arbitration are available online at www.adr.org or by calling the AAA at 1-800-778-7879. The arbitration shall be conducted by a single, neutral arbitrator. Any claims or disputes where the total amount of the award sought is less than Ten Thousand U.S. Dollars (US $10,000.00) may be resolved through binding non-appearance-based arbitration, at the option of the party seeking relief. For claims or disputes where the total amount of the award sought is Ten Thousand U.S. Dollars (US $10,000.00) or more, the right to a hearing will be determined by the Arbitration Rules. Any hearing will be held in a location within 100 miles of your residence, unless you reside outside of the United States, and unless the parties agree otherwise. If you reside outside of the U.S., the arbitrator shall give the parties reasonable notice of the date, time and place of any oral hearings. Any judgment on the award rendered by the arbitrator may be entered in any court of competent jurisdiction. If the arbitrator grants you an award that is greater than the last settlement offer that the Company made to you prior to the initiation of arbitration, the Company will pay you the greater of the award or $2,500.00. Each party shall bear its own costs (including attorney’s fees) and disbursements arising out of the arbitration and shall pay an equal share of the fees and costs of the ADR Provider. - -33. _Additional Rules for Non-Appearance Based Arbitration_. If non-appearance based arbitration is elected, the arbitration shall be conducted by telephone, online and/or based solely on written submissions; the specific manner shall be chosen by the party initiating the arbitration. The arbitration shall not involve any personal appearance by the parties or witnesses unless otherwise agreed by the parties. - -34. _Time Limits._ If you or the Company pursue arbitration, the arbitration action must be initiated and/or demanded within the statute of limitations (i.e., the legal deadline for filing a claim) and within any deadline imposed under the AAA Rules for the pertinent claim. - -35. _Authority of Arbitrator_. If arbitration is initiated, the arbitrator will decide the rights and liabilities, if any, of you and the Company, and the dispute will not be consolidated with any other matters or joined with any other cases or parties. The arbitrator shall have the authority to grant motions dispositive of all or part of any claim. The arbitrator shall have the authority to award monetary damages, and to grant any non-monetary remedy or relief available to an individual under applicable law, the AAA Rules, and the Terms. The arbitrator shall issue a written award and statement of decision describing the essential findings and conclusions on which the award is based, including the calculation of any damages awarded. The arbitrator has the same authority to award relief on an individual basis that a judge in a court of law would have. The award of the arbitrator is final and binding upon you and the Company. - -36. _Waiver of Jury Trial._ THE PARTIES HEREBY WAIVE THEIR CONSTITUTIONAL AND STATUTORY RIGHTS TO GO TO COURT AND HAVE A TRIAL IN FRONT OF A JUDGE OR A JURY, instead electing that all claims and disputes shall be resolved by arbitration under this Arbitration Agreement. Arbitration procedures are typically more limited, more efficient and less costly than rules applicable in a court and are subject to very limited review by a court. In the event any litigation should arise between you and the Company in any state or federal court in a suit to vacate or enforce an arbitration award or otherwise, YOU AND THE COMPANY WAIVE ALL RIGHTS TO A JURY TRIAL, instead electing that the dispute be resolved by a judge. - -37. _Waiver of Class or Consolidated Actions_. ALL CLAIMS AND DISPUTES WITHIN THE SCOPE OF THIS ARBITRATION AGREEMENT MUST BE ARBITRATED OR LITIGATED ON AN INDIVIDUAL BASIS AND NOT ON A CLASS BASIS, AND CLAIMS OF MORE THAN ONE CUSTOMER OR USER CANNOT BE ARBITRATED OR LITIGATED JOINTLY OR CONSOLIDATED WITH THOSE OF ANY OTHER CUSTOMER OR USER. - -38. _Confidentiality_. All aspects of the arbitration proceeding, including but not limited to the award of the arbitrator and compliance therewith, shall be strictly confidential. The parties agree to maintain confidentiality unless otherwise required by law. This paragraph shall not prevent a party from submitting to a court of law any information necessary to enforce this Agreement, to enforce an arbitration award, or to seek injunctive or equitable relief. - -39. _Severability_. If any part or parts of this Arbitration Agreement are found under the law to be invalid or unenforceable by a court of competent jurisdiction, then such specific part or parts shall be of no force and effect and shall be severed and the remainder of the Agreement shall continue in full force and effect. - -40. _Right to Waive._ Any or all of the rights and limitations set forth in this Arbitration Agreement may be waived by the party against whom the claim is asserted. Such waiver shall not waive or affect any other portion of this Arbitration Agreement. - -41. _Survival of Agreement_. This Arbitration Agreement will survive the termination of your relationship with Company. - -42. _Small Claims Court._ Notwithstanding the foregoing, either you or the Company may bring an individual action in small claims court. - -43. _Emergency Equitable Relief_. Notwithstanding the foregoing, either party may seek emergency equitable relief before a state or federal court in order to maintain the status quo pending arbitration. A request for interim measures shall not be deemed a waiver of any other rights or obligations under this Arbitration Agreement. - -44. _Claims Not Subject to Arbitration._ Notwithstanding the foregoing, claims of defamation, violation of the Computer Fraud and Abuse Act, and infringement or misappropriation of the other party’s patent, copyright, trademark or trade secrets shall not be subject to this Arbitration Agreement. - -45. _Courts._ In any circumstances where the foregoing Arbitration Agreement permits the parties to litigate in court, the parties hereby agree to submit to the personal jurisdiction of the courts located within San Francisco County, California, for such purpose - -46. **Export.** The Site may be subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree not to export, reexport, or transfer, directly or indirectly, any U.S. technical data acquired from Company, or any products utilizing such data, in violation of the United States export laws or regulations. - -47. **Disclosures.** Company is located at the address in Section 10.8. If you are a California resident, you may report complaints to the Complaint Assistance Unit of the Division of Consumer Product of the California Department of Consumer Affairs by contacting them in writing at 400 R Street, Sacramento, CA 95814, or by telephone at (800) 952-5210. - -48. **Electronic Communications.** The communications between you and Company use electronic means, whether you use the Site or send us emails, or whether Company posts notices on the Site or communicates with you via email. For contractual purposes, you (a) consent to receive communications from Company in an electronic form; and (b) agree that all terms and conditions, agreements, notices, disclosures, and other communications that Company provides to you electronically satisfy any legal requirement that such communications would satisfy if it were be in a hardcopy writing. The foregoing does not affect your non-waivable rights. - -49. **Entire Terms.** These Terms constitute the entire agreement between you and us regarding the use of the Site. Our failure to exercise or enforce any right or provision of these Terms shall not operate as a waiver of such right or provision. The section titles in these Terms are for convenience only and have no legal or contractual effect. The word "including" means "including without limitation". If any provision of these Terms is, for any reason, held to be invalid or unenforceable, the other provisions of these Terms will be unimpaired and the invalid or unenforceable provision will be deemed modified so that it is valid and enforceable to the maximum extent permitted by law. Your relationship to Company is that of an independent contractor, and neither party is an agent or partner of the other. These Terms, and your rights and obligations herein, may not be assigned, subcontracted, delegated, or otherwise transferred by you without Company’s prior written consent, and any attempted assignment, subcontract, delegation, or transfer in violation of the foregoing will be null and void. Company may freely assign these Terms. The terms and conditions set forth in these Terms shall be binding upon assignees. - -50. **Copyright/Trademark Information**. Copyright © 2018 O(1) Labs Operating Corporation. All rights reserved. All trademarks, logos and service marks ("**Marks**") displayed on the Site are our property or the property of other third parties. You are not permitted to use these Marks without our prior written consent or the consent of such third party which may own the Marks. - -51. **Contact Information:** - - -> Evan Shapiro -> -> Address: -> -> 111 New Montgomery St Suite 400 -> -> San Francisco, California 94103 -> -> Telephone: +1 (415) 985-7715 -> -> Email: contact@o1labs.org diff --git a/frontend/website-redesign/src/Theme.re b/frontend/website-redesign/src/Theme.re index 836ee81518e..81ec98459b7 100644 --- a/frontend/website-redesign/src/Theme.re +++ b/frontend/website-redesign/src/Theme.re @@ -1,461 +1,309 @@ -module Colors = { - let string = - fun - | `rgb(r, g, b) => Printf.sprintf("rgb(%d,%d,%d)", r, g, b) - | `rgba(r, g, b, a) => Printf.sprintf("rgba(%d,%d,%d,%f)", r, g, b, a) - | `hsl(h, s, l) => Printf.sprintf("hsl(%d,%d%%,%d%%)", h, s, l) - | `hsla(`deg(h), `percent(s), `percent(l), `num(a)) => - Printf.sprintf("hsla(%f,%f%%,%f%%,%f)", h, s, l, a); - - let fadedBlue = `rgb((111, 167, 197)); - let babyBlue = `hex("F4F8FB"); +open Css; +module Colors = { + let orange = `hex("ff603b"); + let mint = `hex("9fe4c9"); + let gray = `hex("d9d9d9"); let white = Css.white; - let whiteAlpha = a => `rgba((255, 255, 255, a)); - let hyperlinkAlpha = a => - `hsla((`deg(201.), `percent(71.), `percent(52.), `num(a))); - let hyperlink = hyperlinkAlpha(1.0); - - let blackAlpha = a => `rgba((0, 0, 0, a)); - - let hyperlinkHover = `hex("0AA9FF"); - let hyperlinkLight = `hsl((`deg(201.), `percent(71.), `percent(70.))); - - let metallicBlue = `rgb((70, 99, 131)); - let denimTwo = `rgb((61, 88, 120)); - let greyBlue = `rgb((118, 147, 190)); - let darkGreyBlue = `rgb((61, 88, 120)); - let greyishBrown = `rgb((74, 74, 74)); - - let bluishGreen = `rgb((22, 168, 85)); - let offWhite = `rgb((243, 243, 243)); - let grey = `rgb((129, 146, 168)); - - let azureAlpha = a => `rgba((45, 158, 219, a)); - let gandalf = `rgb((243, 243, 243)); - let veryLightGrey = `rgb((235, 235, 235)); - - let slateAlpha = a => - `hsla((`deg(209.), `percent(20.), `percent(40.), `num(a))); - let slate = slateAlpha(1.0); - - let navy = `rgb((0, 49, 90)); - let navyBlue = `rgb((0, 23, 74)); - let navyBlueAlpha = a => `rgba((0, 23, 74, a)); - let greyishAlpha = a => `rgba((170, 170, 170, a)); - let saville = `hsl((`deg(212.), `percent(33.), `percent(35.))); - - let clover = `rgb((22, 168, 85)); - let lightClover = `rgba((118, 205, 135, 0.12)); - - let kernelAlpha = a => `rgba((0, 212, 0, a)); - let kernel = kernelAlpha(1.); - - let tealAlpha = a => `rgba((71, 130, 160, a)); - let teal = tealAlpha(1.); - let tealBlueAlpha = a => `rgba((0, 170, 170, a)); - let tealBlue = tealBlueAlpha(1.); - - let rosebud = `rgb((163, 83, 111)); - let rosebudAlpha = a => `rgba((163, 83, 111, a)); - - let blueBlue = `rgb((42, 81, 224)); - let midnight = `rgb((31, 45, 61)); - let leaderboardMidnight = `rgb((52, 75, 101)); - - let india = `rgb((242, 183, 5)); - let indiaAlpha = a => `rgba((242, 183, 5, a)); - - let amber = `rgb((242, 149, 68)); - let amberAlpha = a => `rgba((242, 149, 68, a)); - - let marine = `rgb((51, 104, 151)); - let marineAlpha = a => `rgba((51, 104, 151, a)); - - let jungleAlpha = a => `rgba((47, 172, 70, a)); - let jungle = jungleAlpha(1.); - - let tan = `hex("F1EFEA"); + let black = Css.black; }; module Typeface = { - open Css; - - let ibmplexserif = fontFamily("IBM Plex Serif, serif"); - + let monumentGrotesk = fontFamily("Monument Grotesk, serif"); + let monumentGroteskMono = fontFamily("Monument Grotesk mono, serif"); let ibmplexsans = fontFamily("IBM Plex Sans, Helvetica Neue, Arial, sans-serif"); - let ibmplexmono = fontFamily("IBM Plex Mono, Menlo, monospace"); - - let aktivgrotesk = fontFamily("aktiv-grotesk-extended, sans-serif"); - - let rubik = fontFamily("Rubik, sans-serif"); - - let pragmataPro = fontFamily("PragmataPro, monospace"); - - let ddinexp = fontFamily("D-Din-Exp,Helvetica Neue, Arial, sans-serif"); }; module MediaQuery = { - let veryVeryLarge = "(min-width: 77rem)"; - let veryLarge = "(min-width: 70.8125rem)"; - let somewhatLarge = "(min-width: 65.5rem)"; - let tablet = "(min-width:60rem)"; - let desktop = "(min-width:105rem)"; - let full = "(min-width: 54rem)"; - let notMobile = "(min-width: 32rem)"; - let notSmallMobile = "(min-width: 25rem)"; - let statusLiftAlways = "(min-width: 38rem)"; - let statusLift = keepAnnouncementBar => - keepAnnouncementBar ? statusLiftAlways : "(min-width: 0rem)"; + let tablet = "(min-width:48rem)"; + let desktop = "(min-width:90rem)"; - // to adjust root font size (therefore pixels) - let iphoneSEorSmaller = "(max-width: 374px)"; -}; - -/** sets both paddingLeft and paddingRight, as one should */ -let paddingX = m => Css.[paddingLeft(m), paddingRight(m)]; - -/** sets both paddingTop and paddingBottom, as one should */ -let paddingY = m => Css.[paddingTop(m), paddingBottom(m)]; - -let generateStyles = rules => (Css.style(rules), rules); + /** to add a style to tablet and desktop, but not mobile */ + let notMobile = "(min-width:23.5rem)"; -module Link = { - open Css; - - let (init, basicStylesNoHover) = - generateStyles([ - Typeface.ibmplexsans, - color(Colors.hyperlink), - textDecoration(`none), - fontWeight(`medium), - fontSize(`rem(1.125)), - letterSpacing(`rem(-0.0125)), - lineHeight(`rem(1.5)), - media(MediaQuery.notMobile, [fontSize(`rem(1.0))]), - ]); - - module No_hover = { - let basic = init; - }; - - let (basic, basicStyles) = - generateStyles([ - hover([color(Colors.hyperlinkHover)]), - ...basicStylesNoHover, - ]); + /** to add a style just to mobile */ + let mobile = "(max-width:48rem)"; }; -module H1 = { - open Css; +/** this function is needed to include the font files with the font styles */ +let generateStyles = rules => (Css.style(rules), rules); - let (hero, heroStyles) = - generateStyles([ - Typeface.ibmplexsans, - fontWeight(`num(200)), - fontSize(`rem(2.25)), - letterSpacing(`rem(-0.02375)), - lineHeight(`rem(3.0)), - color(Colors.saville), +module Type = { + let h1jumbo = + style([ + Typeface.monumentGrotesk, + fontWeight(`normal), + fontSize(`rem(3.5)), + lineHeight(`rem(4.1875)), + color(black), media( - MediaQuery.full, - [ - fontSize(`rem(3.0)), - letterSpacing(`rem(-0.03125)), - lineHeight(`rem(4.0)), - ], + MediaQuery.tablet, + [fontSize(`rem(4.5)), lineHeight(`rem(5.4))], ), ]); - let basic = merge([hero, style([fontWeight(`semiBold)])]); -}; - -module H2 = { - open Css; - let (basic, basicStyles) = - generateStyles([ - Typeface.ibmplexsans, + let h1 = + style([ + Typeface.monumentGrotesk, fontWeight(`normal), fontSize(`rem(2.25)), - letterSpacing(`rem(-0.03125)), - lineHeight(`rem(3.0)), + lineHeight(`rem(2.7)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(3.0)), lineHeight(`rem(3.6))], + ), ]); -}; - -module Technical = { - open Css; - let border = f => style([f(`px(3), `dashed, Colors.greyishAlpha(0.5))]); - let basic = + let h2 = style([ - Typeface.pragmataPro, - fontWeight(`normal), - color(Css.white), - fontSize(`rem(0.9375)), - textTransform(`uppercase), + Typeface.monumentGrotesk, + fontSize(`rem(1.875)), + lineHeight(`rem(2.25)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(2.5)), lineHeight(`rem(3.))], + ), ]); -}; -module H3 = { - open Css; - - let (basic, basicStyles) = - generateStyles([ - Typeface.ibmplexsans, - fontSize(`rem(1.25)), - textAlign(`center), - lineHeight(`rem(1.5)), + let h3 = + style([ + Typeface.monumentGrotesk, + fontSize(`rem(1.6)), + lineHeight(`rem(2.1)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(2.0)), lineHeight(`rem(2.375))], + ), ]); - let wideNoColor = + /** initially named "h4MonoAllCaps", + * but cut to h4 for brevity since we currently don't have another h4 style + */ + let h4 = style([ - whiteSpace(`nowrap), - fontSize(`rem(1.0)), - letterSpacing(`em(0.25)), - Typeface.aktivgrotesk, - fontWeight(`medium), - fontStyle(`normal), - textAlign(`center), + Typeface.monumentGrotesk, + fontSize(`rem(1.125)), + lineHeight(`rem(1.7)), textTransform(`uppercase), + letterSpacing(`em(0.02)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(1.25)), lineHeight(`rem(1.9))], + ), ]); - let wide = merge([wideNoColor, style([color(Colors.fadedBlue)])]); - - let wings = { - let wing = [ - contentRule(""), - fontSize(`px(5)), - verticalAlign(`top), - lineHeight(`rem(1.3)), - borderTop(`pt(1), `solid, `rgba((155, 155, 155, 0.3))), - borderBottom(`pt(1), `solid, `rgba((155, 155, 155, 0.3))), - ...paddingX(`rem(1.5)), - ]; - - merge([ - wide, - style([ - before([marginRight(`rem(1.0)), ...wing]), - after([marginLeft(`rem(1.0)), ...wing]), - ]), + let h5 = + style([ + Typeface.monumentGrotesk, + fontSize(`rem(1.3)), + lineHeight(`rem(1.56)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(1.5)), lineHeight(`rem(1.8))], + ), ]); - }; - - module Technical = { - let basic = - style([ - Typeface.pragmataPro, - fontSize(`rem(0.9375)), - fontWeight(`bold), - letterSpacing(`px(1)), - textTransform(`uppercase), - ]); - let title = merge([basic, style([color(Css.black)])]); - - let boxed = - merge([ - basic, - Technical.border(Css.border), - style([ - color(Colors.white), - lineHeight(`rem(1.5)), - display(`inlineFlex), - justifyContent(`center), - alignItems(`center), - minWidth(`rem(9.0625)), - height(`rem(3.)), - margin(`auto), - whiteSpace(`nowrap), - padding2(~v=`zero, ~h=`rem(1.)), - ]), - ]); - }; -}; - -module H4 = { - open Css; + let h6 = + style([ + Typeface.monumentGrotesk, + fontSize(`rem(1.125)), + lineHeight(`rem(1.375)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(1.125)), lineHeight(`rem(1.4))], + ), + ]); - let (basic, basicStyles) = - generateStyles([ - Typeface.ibmplexsans, - textAlign(`center), - fontSize(`rem(1.0625)), - lineHeight(`rem(1.5)), - letterSpacing(`rem(0.25)), - opacity(50.0), + /** the following are specific component names, but use some styles already defined */ + let pageLabel = + style([ + Typeface.monumentGrotesk, + fontSize(`rem(0.9)), + lineHeight(`rem(1.37)), textTransform(`uppercase), - fontWeight(`normal), - color(Colors.greyishBrown), + letterSpacing(`em(0.02)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(1.25)), lineHeight(`rem(1.875))], + ), ]); - let semiBold = merge([basic, style([fontWeight(`semiBold)])]); - let header = + let label = style([ - Typeface.ibmplexsans, - textAlign(`center), - fontSize(`rem(1.5)), - lineHeight(`rem(2.0)), - fontWeight(`semiBold), - color(Colors.saville), + Typeface.monumentGrotesk, + fontSize(`rem(0.75)), + lineHeight(`rem(1.)), + color(black), + textTransform(`uppercase), + letterSpacing(`em(0.03)), + media( + MediaQuery.tablet, + [fontSize(`rem(0.88)), lineHeight(`rem(1.))], + ), ]); - let (wide, wideStyles) = - generateStyles([ + let buttonLabel = + style([ + Typeface.monumentGrotesk, fontSize(`rem(0.75)), - letterSpacing(`rem(0.125)), - Typeface.aktivgrotesk, - fontWeight(`medium), - fontStyle(`normal), - textAlign(`center), + fontWeight(`num(500)), + lineHeight(`rem(1.)), + color(black), textTransform(`uppercase), - media(MediaQuery.notMobile, [whiteSpace(`nowrap)]), + letterSpacing(`px(1)), ]); -}; - -module H5 = { - open Css; - let init = + let link = style([ - Typeface.ibmplexsans, - fontSize(`rem(0.9345)), - letterSpacing(`rem(0.125)), - fontWeight(`normal), - color(Colors.slateAlpha(0.5)), - textTransform(`uppercase), + Typeface.monumentGrotesk, + fontSize(`rem(1.125)), + lineHeight(`rem(1.7)), + color(Colors.orange), + hover([textDecoration(`underline)]), ]); - let basic = merge([init, style([lineHeight(`rem(1.5))])]); + let navLink = + style([ + Typeface.monumentGrotesk, + fontSize(`rem(1.1)), + lineHeight(`rem(1.1)), + color(black), + ]); - let tight = merge([init, style([lineHeight(`rem(1.25))])]); + let sidebarLink = + style([ + Typeface.monumentGrotesk, + fontSize(`rem(1.)), + lineHeight(`rem(1.5)), + color(black), + ]); - let semiBold = - merge([ - style([ - Typeface.ibmplexsans, - fontStyle(`normal), - fontWeight(`semiBold), - fontSize(`rem(1.25)), - lineHeight(`rem(1.5)), - color(Colors.saville), - ]), + let tooltip = + style([ + Typeface.monumentGrotesk, + fontSize(`px(13)), + lineHeight(`rem(1.)), + color(black), ]); -}; -module H6 = { - open Css; - let init = - style([Typeface.ibmplexsans, fontStyle(`normal), textAlign(`center)]); + let creditName = + style([ + Typeface.monumentGrotesk, + fontSize(`px(10)), + lineHeight(`rem(1.)), + letterSpacing(`em(-0.01)), + ]); - let extraSmall = - merge([ - init, - style([ - fontSize(`rem(0.75)), - letterSpacing(`rem(0.0875)), - fontWeight(`num(500)), - lineHeight(`rem(1.0)), - ]), + let metadata = + style([ + Typeface.monumentGrotesk, + fontSize(`px(12)), + lineHeight(`rem(1.)), + letterSpacing(`em(0.05)), + textTransform(`uppercase), ]); -}; -module Body = { - open Css; + let announcement = + style([ + Typeface.monumentGrotesk, + fontWeight(`num(500)), + fontSize(`px(14)), + lineHeight(`rem(1.5)), + ]); - module Technical = { - let (basic, basicStyles) = - generateStyles([ - Typeface.pragmataPro, - color(Css.white), - fontSize(`rem(1.)), - lineHeight(`rem(1.25)), - letterSpacing(`rem(0.00625)), - ]); - }; + let errorMessage = + style([ + Typeface.monumentGrotesk, + fontSize(`px(13)), + lineHeight(`rem(1.)), + color(`hex("e93939")), + ]); - let (basic, basicStyles) = - generateStyles([ - Typeface.ibmplexsans, - color(Colors.saville), + let pageSubhead = + style([ + Typeface.monumentGrotesk, fontSize(`rem(1.125)), - lineHeight(`rem(1.625)), - fontWeight(`normal), - letterSpacing(`rem(0.016)), + lineHeight(`rem(1.68)), + color(black), media( - MediaQuery.notMobile, - [ - fontSize(`rem(1.0)), - lineHeight(`rem(1.5)), - letterSpacing(`rem(0.01)), - ], + MediaQuery.tablet, + [fontSize(`rem(1.31)), lineHeight(`rem(1.93))], ), ]); - let basic_semibold = merge([basic, style([fontWeight(`semiBold)])]); - - let big = + let sectionSubhead = style([ - Typeface.ibmplexsans, - color(Colors.darkGreyBlue), - fontSize(`rem(1.125)), - lineHeight(`rem(1.875)), + Typeface.monumentGrotesk, + fontSize(`rem(1.)), + lineHeight(`rem(1.5)), + letterSpacing(`px(-1)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(1.25)), lineHeight(`rem(1.875))], + ), ]); - let big_semibold = merge([big, style([fontWeight(`semiBold)])]); + let paragraph = + style([ + Typeface.monumentGrotesk, + fontSize(`rem(1.)), + lineHeight(`rem(1.5)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(1.125)), lineHeight(`rem(1.69))], + ), + ]); - let small = + let paragraphSmall = style([ - Typeface.ibmplexsans, - fontSize(`rem(0.8125)), - opacity(0.5), - lineHeight(`rem(1.25)), + Typeface.monumentGrotesk, + fontSize(`rem(0.875)), + lineHeight(`rem(1.31)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(1.)), lineHeight(`rem(1.5))], + ), ]); - let basic_small = + let paragraphMono = style([ - Typeface.ibmplexsans, - fontSize(`rem(0.8125)), - color(Colors.saville), + Typeface.monumentGrotesk, + fontSize(`rem(1.)), + lineHeight(`rem(1.5)), + letterSpacing(`rem(0.03125)), + color(black), + media( + MediaQuery.tablet, + [ + fontSize(`rem(1.)), + lineHeight(`rem(1.5)), + letterSpacing(`px(-1)), + ], + ), ]); - let medium = + let quote = style([ - Typeface.ibmplexsans, - fontStyle(`normal), - fontSize(`px(16)), - lineHeight(`px(24)), - color(Colors.teal), + Typeface.monumentGrotesk, + fontSize(`rem(1.31)), + lineHeight(`rem(1.875)), + letterSpacing(`em(-0.03)), + color(black), + media( + MediaQuery.tablet, + [fontSize(`rem(2.5)), lineHeight(`rem(3.125))], + ), ]); }; - -// Match Tachyons setting pretty much everything to border-box -Css.global( - "a,article,aside,blockquote,body,code,dd,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,html,input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],legend,li,main,nav,ol,p,pre,section,table,td,textarea,th,tr,ul", - [Css.boxSizing(`borderBox)], -); - -// Reset padding that appears only on some browsers -Css.global( - "h1,h2,h3,h4,h5,fieldset,ul,li,p,figure", - Css.[ - unsafe("paddingInlineStart", "0"), - unsafe("paddingInlineEnd", "0"), - unsafe("paddingBlockStart", "0"), - unsafe("paddingBlockEnd", "0"), - unsafe("marginInlineStart", "0"), - unsafe("marginInlineEnd", "0"), - unsafe("marginBlockStart", "0"), - unsafe("marginBlockEnd", "0"), - unsafe("WebkitPaddingBefore", "0"), - unsafe("WebkitPaddingStart", "0"), - unsafe("WebkitPaddingEnd", "0"), - unsafe("WebkitPaddingAfter", "0"), - unsafe("WebkitMarginBefore", "0"), - unsafe("WebkitMarginAfter", "0"), - ], -); - -Css.global("p", Css.[marginTop(`rem(1.)), marginBottom(`rem(1.))]); diff --git a/frontend/website-redesign/src/components/ActionButton.re b/frontend/website-redesign/src/components/ActionButton.re deleted file mode 100644 index 5d9cdc08602..00000000000 --- a/frontend/website-redesign/src/components/ActionButton.re +++ /dev/null @@ -1,69 +0,0 @@ -module Styles = { - open Css; - - let ctaButton = - style([ - background(`rgba((71, 137, 196, 0.1))), - border(`px(1), `solid, Theme.Colors.hyperlink), - borderRadius(`px(6)), - textDecoration(`none), - padding(`rem(1.0)), - paddingTop(`rem(0.7)), - minWidth(`rem(15.3)), - hover([ - opacity(0.9), - backgroundColor(Theme.Colors.azureAlpha(0.2)), - border(`px(1), `solid, Theme.Colors.hyperlinkHover), - cursor(`pointer), - ]), - media("(min-width: 70rem)", [height(`rem(6.875))]), - media("(min-width: 82rem)", [height(`rem(6.0))]), - ]); - - let ctaContent = - style([display(`flex), selector("p", [fontSize(`px(36))])]); - - let ctaText = style([marginLeft(`px(13))]); - - let ctaHeading = - style([ - Theme.Typeface.ibmplexsans, - fontWeight(`num(600)), - fontSize(`rem(1.875)), - lineHeight(`rem(2.1875)), - color(Theme.Colors.teal), - textAlign(`left), - paddingBottom(`rem(0.3)), - ]); - - let ctaBody = - style([ - Theme.Typeface.ibmplexsans, - fontStyle(`normal), - fontWeight(`normal), - fontSize(`rem(0.8125)), - color(Theme.Colors.teal), - textAlign(`left), - marginTop(`rem(0.0625)), - ]); - let ctaIcon = - style([ - marginTop(`px(2)), - minWidth(`px(36)), - maxHeight(`px(48)), - flexShrink(0.), - ]); -}; - -[@react.component] -let make = (~icon, ~heading, ~text, ~href) => { - -
-

icon

-
-

heading

-

text

-
-
-
; -}; diff --git a/frontend/website-redesign/src/components/Alert.re b/frontend/website-redesign/src/components/Alert.re deleted file mode 100644 index 9798968c6b0..00000000000 --- a/frontend/website-redesign/src/components/Alert.re +++ /dev/null @@ -1,44 +0,0 @@ -module Style = { - open Css; - - let main = c => - style([ - border(px(1), `solid, c), - borderRadius(px(9)), - overflow(`hidden), - ]); - - let inner = - merge([style([margin(`zero), padding2(~v=`rem(0.), ~h=`rem(1.))])]); - - let title = c => - merge([ - Theme.Body.basic, - style([ - textTransform(`capitalize), - fontWeight(`num(600)), - color(`hex("FFFFFF")), - backgroundColor(c), - margin(`zero), - padding2(~v=`rem(0.5), ~h=`rem(1.)), - ]), - ]); -}; - -[@react.component] -let make = (~kind="", ~children) => { - let (title, color) = - switch (kind) { - | "warning" => ("warning", Theme.Colors.rosebudAlpha(0.8)) - | "danger" => ("danger", Theme.Colors.rosebudAlpha(0.8)) - | "welcome" => ("welcome", Theme.Colors.tealBlueAlpha(0.8)) - | "status" => ("status", Theme.Colors.indiaAlpha(0.8)) - | _ => ("note", Theme.Colors.marineAlpha(0.8)) - }; -
-

{React.string(title)}

-
children
-
; -}; - -let default = make; diff --git a/frontend/website-redesign/src/components/AnnouncementBar.re b/frontend/website-redesign/src/components/AnnouncementBar.re deleted file mode 100644 index dd3c9cc5058..00000000000 --- a/frontend/website-redesign/src/components/AnnouncementBar.re +++ /dev/null @@ -1,108 +0,0 @@ -module Icon = { - let svg = - - - - - - - - - - - ; -}; - -[@react.component] -let make = () => { - <> - - -
- Icon.svg -

- {React.string("Token Program is live")} -

-
-

- {React.string({j|Apply Now\u00A0→|j})} -

-
- ; -}; diff --git a/frontend/website-redesign/src/components/Button.re b/frontend/website-redesign/src/components/Button.re deleted file mode 100644 index bfb56293f72..00000000000 --- a/frontend/website-redesign/src/components/Button.re +++ /dev/null @@ -1,39 +0,0 @@ -module Styles = { - open Css; - let button = (bgColor, bgColorHover) => - merge([ - Theme.Body.basic_semibold, - style([ - width(`rem(14.)), - height(`rem(3.)), - backgroundColor(bgColor), - borderRadius(`px(6)), - textDecoration(`none), - fontSize(`rem(1.)), - color(white), - padding2(~v=`px(12), ~h=`px(24)), - textAlign(`center), - alignSelf(`center), - hover([backgroundColor(bgColorHover)]), - media( - Theme.MediaQuery.tablet, - [marginLeft(`rem(0.)), alignSelf(`flexStart)], - ), - ]), - ]); -}; - -[@react.component] -let make = - ( - ~link, - ~label, - ~bgColor=Theme.Colors.hyperlink, - ~bgColorHover=Theme.Colors.hyperlinkAlpha(1.), - ) => { - - - {React.string(label)} - - ; -}; diff --git a/frontend/website-redesign/src/components/ChallengePointsTable.re b/frontend/website-redesign/src/components/ChallengePointsTable.re deleted file mode 100644 index c585ffb02e9..00000000000 --- a/frontend/website-redesign/src/components/ChallengePointsTable.re +++ /dev/null @@ -1,265 +0,0 @@ -module Styles = { - open Css; - let text = { - style([ - Theme.Typeface.ibmplexsans, - color(`hex("344B65")), - fontWeight(`num(600)), - lineHeight(`rem(2.)), - fontStyle(`normal), - fontSize(`rem(1.125)), - letterSpacing(`rem(-0.03)), - ]); - }; - - let container = { - merge([ - text, - style([ - display(`flex), - flexDirection(`column), - flexWrap(`wrap), - media( - Theme.MediaQuery.notMobile, - [ - width(`percent(100.)), - flexDirection(`row), - justifyContent(`spaceEvenly), - ], - ), - ]), - ]); - }; - - let releaseTitle = { - style([ - fontWeight(`num(600)), - fontSize(`rem(2.)), - letterSpacing(`rem(-0.03)), - display(`flex), - width(`percent(100.)), - justifyContent(`flexStart), - paddingTop(`rem(2.)), - media( - Theme.MediaQuery.notMobile, - [width(`percent(30.)), flexDirection(`row)], - ), - media(Theme.MediaQuery.tablet, [justifyContent(`center)]), - ]); - }; - - let tableContainer = { - style([ - width(`percent(100.)), - media( - Theme.MediaQuery.notMobile, - [maxWidth(`rem(40.)), width(`percent(70.)), flexDirection(`row)], - ), - ]); - }; - - let gridContainer = { - style([ - marginTop(`rem(1.)), - background(`hex("F5F5F5")), - borderTop(`px(1), `solid, Css_Colors.black), - borderBottom(`px(1), `solid, Css_Colors.black), - selector( - "div:nth-child(even)", - [background(`rgba((172, 151, 96, 0.06)))], - ), - media(Theme.MediaQuery.notMobile, [marginTop(`zero)]), - ]); - }; - - let tableRow = { - style([ - padding2(~v=`zero, ~h=`rem(1.)), - padding(`px(8)), - display(`grid), - gridTemplateColumns([ - `percent(6.), - `percent(6.), - `auto, - `percent(15.), - ]), - media( - Theme.MediaQuery.notMobile, - [ - gridTemplateColumns([ - `percent(12.5), - `percent(5.), - `auto, - `percent(20.), - ]), - ], - ), - ]); - }; - - let topRow = { - merge([ - tableRow, - style([ - display(`none), - letterSpacing(`px(2)), - fontSize(`rem(0.875)), - textTransform(`uppercase), - padding(`zero), - media( - Theme.MediaQuery.notMobile, - [ - display(`grid), - gridTemplateColumns([ - `percent(12.5), - `percent(5.), - `auto, - `percent(23.5), - ]), - ], - ), - ]), - ]); - }; - - let bottomRow = { - merge([ - tableRow, - style([marginTop(`rem(0.5)), textTransform(`uppercase)]), - ]); - }; - - let challengeLabel = { - style([gridColumn(3, 4)]); - }; - - let pointsLabel = { - style([gridColumn(4, 5)]); - }; - - let totalPointsTextLabel = { - style([gridColumn(3, 4)]); - }; - - let totalPointsLabel = { - style([gridColumn(4, 5)]); - }; - - let star = { - style([justifySelf(`flexEnd)]); - }; - - let rank = { - style([fontWeight(`normal), justifySelf(`center)]); - }; - - let points = { - style([ - textAlign(`right), - media(Theme.MediaQuery.notMobile, [paddingRight(`rem(5.))]), - ]); - }; - - let disclaimer = { - style([ - display(`flex), - justifyContent(`flexStart), - fontSize(`rem(1.)), - marginTop(`rem(1.)), - marginBottom(`rem(5.)), - media(Theme.MediaQuery.notMobile, [justifyContent(`flexEnd)]), - ]); - }; -}; - -module Row = { - [@react.component] - let make = (~star, ~rank, ~name, ~points) => { -
- - {switch (star) { - | Some(star) => React.string(star) - | None => React.null - }} - - - {React.string(string_of_int(rank))} - - {React.string(name)} - - {switch (points) { - | Some(points) => React.string(string_of_int(points)) - | None => React.null - }} - -
; - }; -}; - -type challenge = { - name: string, - points: option(int), -}; -type release = { - name: string, - challenges: array(challenge), -}; - -[@react.component] -let make = (~releaseTitle, ~challenges) => { - let calculateTotalPoints = () => { - challenges - |> Array.fold_left( - (totalPoints, challenge) => { - switch (challenge.points) { - | Some(points) => totalPoints + points - | None => totalPoints - } - }, - 0, - ) - |> string_of_int; - }; - let renderChallengePointsTable = () => { - challenges - |> Array.mapi((index, challenge) => { - let {name, points} = challenge; - ; - }) - |> React.array; - }; - -
-
{React.string(releaseTitle)}
-
-
- - {React.string("Challenge Name")} - - {React.string("* Points")} -
-
- {renderChallengePointsTable()} -
-
- - {React.string("Total Points *")} - - - {React.string(calculateTotalPoints())} - -
-
- - {React.string("** Scores are updated manually every few days")} - -
-
-
; -}; diff --git a/frontend/website-redesign/src/components/Challenges.re b/frontend/website-redesign/src/components/Challenges.re deleted file mode 100644 index 3499381a0d4..00000000000 --- a/frontend/website-redesign/src/components/Challenges.re +++ /dev/null @@ -1,91 +0,0 @@ -type challenge = { - id: int, - name: string, - description: string, -}; - -type testnet = { - name: string, - is_active: bool, -}; - -external parseChallenge: Js.Json.t => challenge = "%identity"; -external parseTestnet: Js.Json.t => testnet = "%identity"; - -let fetchArray = endpoint => { - ReFetch.fetch( - "http://points.o1test.net/api/v1/" ++ endpoint, - ~method_=Get, - ~headers={ - "Accept": "application/json", - "Content-Type": "application/json", - }, - ) - |> Promise.bind(Bs_fetch.Response.json) - |> Promise.map(r => { - let results = - Option.bind(Js.Json.decodeObject(r), o => - Js.Dict.get(o, "results") - ); - switch (Option.bind(results, Js.Json.decodeArray)) { - | Some(arr) => arr - | None => [||] - }; - }) - |> Js.Promise.catch(_ => Promise.return([||])); -}; - -let fetchTestnet = uri => - fetchArray(uri) - |> Promise.map(Array.map(parseTestnet)) - |> Promise.map(a => - Array.to_list(a) - |> List.find_opt(t => t.is_active) - |> Option.map(t => t.name) - ); - -let fetchChallenges = uri => - Promise.map(Array.map(parseChallenge), fetchArray(uri)); - -// Used in getInitialProps of Testnet.re -let fetchAllChallenges = () => { - Js.Promise.all4(( - fetchTestnet("testnets/"), - fetchChallenges("ranking-challenges/"), - fetchChallenges("continuous-challenges/"), - fetchChallenges("threshold-challenges/"), - )); -}; - -module Styles = { - open Css; - let weekHeader = - merge([Theme.H2.basic, style([padding2(~v=`rem(1.), ~h=`zero)])]); -}; - -let renderChallenges = (challenges: array(challenge)) => { - Array.map( - (c: challenge) => -
-

{React.string(c.name)}

-

{React.string(c.description)}

-
, - challenges, - ) - |> React.array; -}; - -[@react.component] -let make = (~challenges, ~testnetName) => { - let (ranking, continuous, threshold) = challenges; - switch (testnetName) { - | None => React.null - | Some(testnet) => - <> -

{React.string(testnet)}

- {renderChallenges(ranking)} - {renderChallenges(continuous)} - {renderChallenges(threshold)} - - }; -}; diff --git a/frontend/website-redesign/src/components/ContentfulImage.re b/frontend/website-redesign/src/components/ContentfulImage.re deleted file mode 100644 index 35d0bdfff1d..00000000000 --- a/frontend/website-redesign/src/components/ContentfulImage.re +++ /dev/null @@ -1,15 +0,0 @@ -[@react.component] -let make = (~src, ~className=?, ~alt) => - ; diff --git a/frontend/website-redesign/src/components/CookieWarning.re b/frontend/website-redesign/src/components/CookieWarning.re index 2a18c6d2072..029d8956573 100644 --- a/frontend/website-redesign/src/components/CookieWarning.re +++ b/frontend/website-redesign/src/components/CookieWarning.re @@ -24,17 +24,17 @@ module Styles = { justifyContent(`spaceBetween), display(`flex), width(`percent(100.)), - background(Theme.Colors.slateAlpha(0.8)), + background(Theme.Colors.gray), ]); - let content = merge([Theme.Body.basic_semibold, style([color(white)])]); + let content = merge([Theme.Type.paragraph, style([color(white)])]); let button = merge([ - Theme.Body.small, + Theme.Type.paragraph, style([ opacity(1.), - color(Theme.Colors.slate), + color(Theme.Colors.gray), background(white), borderRadius(px(3)), padding2(~v=`rem(0.75), ~h=`rem(1.5)), diff --git a/frontend/website-redesign/src/components/CryptoAppsSection.re b/frontend/website-redesign/src/components/CryptoAppsSection.re deleted file mode 100644 index a7c07359837..00000000000 --- a/frontend/website-redesign/src/components/CryptoAppsSection.re +++ /dev/null @@ -1,294 +0,0 @@ -let middleElementWidthRems = 21.5; - -let topMarginUnderHeading = `rem(2.5); -// nudge so it looks like the center of the coda icon hits bar -let topMarginNegativeNudgeVeryLarge = `rem(-1.5); - -module Code = { - [@react.component] - let make = (~src) => { -
-
-        {React.string(src)}
-      
-
; - }; -}; - -module ImageCollage = { - [@react.component] - let make = (~className) => { -
- - - Coda icon on a phone, connected to devices all around the world. -
; - }; -}; - -[@react.component] -let make = () => { -
- - <div - className=Css.( - style([ - position(`relative), - left(`zero), - top(`zero), - minHeight(`rem(38.)), - ]) - )> - <ImageCollage - className=Css.( - style([ - display(`none), - media(Theme.MediaQuery.veryLarge, [display(`block)]), - ]) - ) - /> - <div - className=Css.( - style([ - display(`flex), - flexWrap(`wrapReverse), - justifyContent(`spaceBetween), - alignItems(`center), - marginLeft(`auto), - marginRight(`auto), - marginBottom(`zero), - maxWidth(`rem(78.0)), - media( - Theme.MediaQuery.notMobile, - [justifyContent(`spaceAround)], - ), - media(Theme.MediaQuery.full, [marginBottom(`rem(2.0))]), - // vertically/horiz center absolutely - media( - Theme.MediaQuery.veryLarge, - [ - flexWrap(`nowrap), - position(`absolute), - top(`percent(50.0)), - left(`percent(50.0)), - transforms([ - `translateX(`percent(-50.0)), - `translateY(`percent(-50.0)), - ]), - width(`percent(100.0)), - ], - ), - ]) - )> - <Code - src={|<script src="coda_api.js"></script> -<script> - onClick(button) - .then(() => Coda.requestWallet()) - .then((wallet) => - wallet.sendTransaction(...)) -</script>|} - /> - // This keeps the right hand text aligned with the inclusive app section. - <div - className=Css.( - style([ - width(`rem(middleElementWidthRems)), - height(`rem(0.)), - display(`none), - media(Theme.MediaQuery.veryLarge, [display(`block)]), - ]) - ) - /> - <SideText - className=Css.( - style([ - marginTop(topMarginUnderHeading), - media( - Theme.MediaQuery.veryLarge, - [ - marginTop(topMarginNegativeNudgeVeryLarge), - marginLeft(`zero), - marginRight(`zero), - ], - ), - media( - Theme.MediaQuery.notMobile, - [marginLeft(`rem(1.0)), marginRight(`rem(1.0))], - ), - ]) - ) - paragraphs=[| - `styled([ - `emph( - "Build apps and games that take advantage of the new capabilities enabled by cryptocurrency with just a script tag and a few lines of javascript.", - ), - ]), - `str( - "Your users will have a seamless, secure experience without having to download any extensions or trust additional 3rd parties.", - ), - |] - /> - </div> - <ImageCollage - className=Css.( - style([ - display(`block), - marginBottom(`rem(4.0)), - media(Theme.MediaQuery.veryLarge, [display(`none)]), - ]) - ) - /> - </div> - </div>; -}; diff --git a/frontend/website-redesign/src/components/DocsComponents.re b/frontend/website-redesign/src/components/DocsComponents.re deleted file mode 100644 index 3e232075c44..00000000000 --- a/frontend/website-redesign/src/components/DocsComponents.re +++ /dev/null @@ -1,246 +0,0 @@ -module Style = { - open Css; - let header = - style([ - marginTop(rem(2.)), - textAlign(`left), - marginBottom(`rem(0.5)), - color(Theme.Colors.denimTwo), - hover([selector(".headerlink", [display(`inlineBlock)])]), - ]); - - let headerLink = - style([ - display(`none), - width(rem(1.)), - height(rem(1.)), - fontSize(`px(16)), - lineHeight(`px(24)), - marginLeft(rem(0.5)), - color(`transparent), - hover([color(`transparent)]), - backgroundSize(`cover), - backgroundImage(url("/static/img/link.svg")), - ]); - - let list = - merge([ - style([ - margin2(~v=`rem(1.), ~h=`zero), - marginLeft(rem(1.5)), - padding(`zero), - ]), - Theme.Body.basic, - ]); -}; - -module type Component = {let element: React.element;}; - -module Wrap = (C: Component) => { - let make = props => { - ReasonReact.cloneElement(C.element, ~props, [||]); - }; - - [@bs.obj] - external makeProps: (~children: 'a, unit) => {. "children": 'a} = ""; -}; - -module WrapHeader = (C: Component) => { - let make = props => { - switch (Js.Undefined.toOption(props##id)) { - | None => ReasonReact.cloneElement(C.element, ~props, [||]) - | Some(id) => - // Somewhat dangerously add a headerlink to the header's children - let children = - Js.Array.concat( - [| - <a - className={"headerlink " ++ Style.headerLink} - href={"#" ++ id} - />, - |], - [|props##children|], - ); - ReasonReact.cloneElement(C.element, ~props, children); - }; - }; -}; - -open Css; - -module H1 = - WrapHeader({ - let element = - <h1 - className={merge([ - Theme.H1.hero, - Style.header, - style([alignItems(`baseline), fontWeight(`light)]), - ])} - />; - }); - -module H2 = - WrapHeader({ - let element = - <h2 - className={merge([ - Theme.H2.basic, - Style.header, - style([alignItems(`baseline), fontWeight(`light)]), - ])} - />; - }); - -module H3 = - WrapHeader({ - let element = - <h3 - className={merge([ - Theme.H3.basic, - Style.header, - style([alignItems(`center), fontWeight(`medium)]), - ])} - />; - }); - -module H4 = - WrapHeader({ - let element = <h4 className={merge([Theme.H4.basic, Style.header])} />; - }); - -module P = - Wrap({ - let element = - <p - className={style([ - color(Theme.Colors.saville), - fontWeight(`extraLight), - ...Theme.Body.basicStyles, - ])} - />; - }); - -module A = - Wrap({ - let element = <a className=Theme.Link.basic />; - }); - -module Strong = - Wrap({ - let element = - <strong - className={style([ - fontWeight(`num(600)), - color(Theme.Colors.saville), - ])} - />; - }); - -[@bs.scope ("navigator", "clipboard")] [@bs.val] -external writeText: string => Js.Promise.t(unit) = "writeText"; - -module Pre = { - [@react.component] - let make = (~children) => { - let text = - Js.String.trim( - Js.String.make( - (ReactExt.Children.only(children) |> ReactExt.props)##children, - ), - ); - <div className={style([position(`relative)])}> - <div - className={style([ - position(`absolute), - top(`px(6)), - right(`px(6)), - width(`px(24)), - height(`px(24)), - height(`px(24)), - opacity(0.2), - cursor(`pointer), - backgroundImage( - `url( - "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiAvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMwMSAxMzBIMTUzVjM3MUgxMzdWMTIyQzEzNyAxMTcuNTgyIDE0MC41ODIgMTE0IDE0NSAxMTRIMzAxVjEzMFpNMTg2IDM4NlYxNjJIMzI2VjM4NkgxODZaTTE3MCAxNTRDMTcwIDE0OS41ODIgMTczLjU4MiAxNDYgMTc4IDE0NkgzMzRDMzM4LjQxOCAxNDYgMzQyIDE0OS41ODIgMzQyIDE1NFYzOTRDMzQyIDM5OC40MTggMzM4LjQxOCA0MDIgMzM0IDQwMkgxNzhDMTczLjU4MiA0MDIgMTcwIDM5OC40MTggMTcwIDM5NFYxNTRaIiBmaWxsPSJibGFjayIvPgo8L3N2Zz4K", - ), - ), - backgroundSize(`cover), - hover([opacity(0.7)]), - ])} - onClick={_ => { - // TODO: Change copy icon to checkmark or something when copy - writeText(text) - |> Promise.iter(() => {Js.log("copied")}) - }} - /> - <pre - className={style([ - backgroundColor(Theme.Colors.slateAlpha(0.05)), - borderRadius(`px(9)), - padding2(~v=`rem(0.5), ~h=`rem(1.)), - overflow(`scroll), - selector("code", [Theme.Typeface.pragmataPro]), - ])}> - children - </pre> - </div>; - }; -}; - -module Code = - Wrap({ - let element = - <code - className={style([ - Theme.Typeface.pragmataPro, - color(Theme.Colors.midnight), - ])} - />; - }); - -module Ul = - Wrap({ - let element = <ul className=Style.list />; - }); - -module Ol = - Wrap({ - let element = <ol className=Style.list />; - }); - -module Img = - Wrap({ - let element = <img width="100%" />; - }); - -module DaemonCommandExample = { - let defaultArgs = ["coda daemon", "-peer $SEED1", "-peer $SEED2"]; - [@react.component] - let make = (~args: array(string)=[||]) => { - let allArgs = defaultArgs @ Array.to_list(args); - let argsLength = - List.fold_left((a, e) => a + String.length(e), 0, allArgs); - let sep = argsLength > 60 ? " \\\n " : " "; - let processedArgs = - String.concat(sep, defaultArgs @ Array.to_list(args)); - <Pre> <Code> {React.string(processedArgs)} </Code> </Pre>; - }; -}; - -let allComponents = () => { - "Alert": Alert.make, - "DaemonCommandExample": DaemonCommandExample.make, - "h1": H1.make, - "h2": H2.make, - "h3": H3.make, - "h4": H4.make, - "p": P.make, - "a": A.make, - "strong": Strong.make, - "pre": Pre.make, - "code": Code.make, - "ul": Ul.make, - "ol": Ol.make, - "img": Img.make, -}; diff --git a/frontend/website-redesign/src/components/DocsSideNav.re b/frontend/website-redesign/src/components/DocsSideNav.re deleted file mode 100644 index 3f1f464e2c5..00000000000 --- a/frontend/website-redesign/src/components/DocsSideNav.re +++ /dev/null @@ -1,194 +0,0 @@ -module Style = { - open Css; - let sideNav = - style([ - minWidth(rem(15.)), - listStyleType(`none), - firstChild([marginLeft(`zero)]), - media( - Theme.MediaQuery.somewhatLarge, - [ - marginRight(rem(2.)), - marginTop(rem(2.)), - position(`sticky), - top(rem(2.5)), - ], - ), - ]); - - let page = - merge([ - Theme.Link.basic, - style([ - display(`inlineBlock), - marginBottom(`rem(0.5)), - height(`rem(1.5)), - ]), - ]); - - let currentPage = - merge([ - page, - style([ - fontWeight(`bolder), - position(`relative), - before([ - position(`absolute), - left(rem(-0.75)), - contentRule("\\2022 "), - ]), - ]), - ]); - - let navFolder = - style([ - display(`block), - flexDirection(`row), - justifyContent(`spaceBetween), - selector( - "a", - [ - marginBottom(`rem(0.5)), - height(`rem(1.5)), - cursor(`pointer), - textDecoration(`none), - Theme.Typeface.ibmplexsans, - hover([color(Theme.Colors.hyperlinkHover)]), - ], - ), - ]); - let folderLabel = - style([ - display(`flex), - justifyContent(`spaceBetween), - color(Theme.Colors.marine), - ]); - let childPage = style([marginLeft(`rem(1.)), listStyleType(`none)]); - let flip = style([transform(rotate(`deg(180.)))]); -}; - -module CurrentSlugProvider = { - let (context, make, makeProps) = ReactExt.createContext(""); -}; - -module FolderSlugProvider = { - let (context, make, makeProps) = ReactExt.createContext(None); -}; - -let slugConcat = (n1, n2) => { - String.length(n2) > 0 ? n1 ++ "/" ++ n2 : n1; -}; - -module Page = { - [@react.component] - let make = (~title, ~slug) => { - let currentSlug = React.useContext(CurrentSlugProvider.context); - let folderSlug = React.useContext(FolderSlugProvider.context); - let fullSlug = - switch (folderSlug) { - | Some(fs) => slugConcat(fs, slug) - | None => slug - }; - let isCurrentPage = currentSlug == fullSlug; - let href = slugConcat("/docs", fullSlug); - <li> - <Next.Link href> - <a className={isCurrentPage ? Style.currentPage : Style.page}> - {React.string(title)} - </a> - </Next.Link> - </li>; - }; -}; - -module Folder = { - [@react.component] - let make = (~title, ~slug, ~children) => { - let currentSlug = React.useContext(CurrentSlugProvider.context); - let hasCurrentSlug = ref(false); - - // Check if the children's props contain the current slug - ReactExt.Children.forEach(children, (. child) => { - switch (ReactExt.props(child)##slug) { - | Some(childSlug) when slugConcat(slug, childSlug) == currentSlug => - hasCurrentSlug := true - | _ => () - } - }); - - let (expanded, setExpanded) = React.useState(() => hasCurrentSlug^); - - let toggleExpanded = - React.useCallback(e => { - ReactEvent.Mouse.preventDefault(e); - setExpanded(expanded => !expanded); - }); - - <li key=title className=Style.navFolder> - <div> - <a - href="#" - onClick=toggleExpanded - ariaExpanded=expanded - className=Style.folderLabel> - {React.string(title)} - <Spacer width=1.0 /> - <img - src="/static/img/chevron-down.svg" - width="16" - height="16" - className={expanded ? Style.flip : ""} - /> - </a> - </div> - {!expanded - ? React.null - : <FolderSlugProvider value={Some(slug)}> - <ul className=Style.childPage> children </ul> - </FolderSlugProvider>} - </li>; - }; -}; - -[@react.component] -let make = (~currentSlug) => { - <aside> - <CurrentSlugProvider value=currentSlug> - <ul className=Style.sideNav> - <Page title="Overview" slug="" /> - <Page title="Getting Started" slug="getting-started" /> - <Page title="My First Transaction" slug="my-first-transaction" /> - <Page title="Become a Node Operator" slug="node-operator" /> - <Page title="Contributing to Coda" slug="contributing" /> - <Folder title="Developers" slug="developers"> - <Page title="Developers Overview" slug="" /> - <Page title="Codebase Overview" slug="codebase-overview" /> - <Page title="Repository Structure" slug="directory-structure" /> - <Page title="Code Reviews" slug="code-reviews" /> - <Page title="Style Guide" slug="style-guide" /> - <Page title="Sandbox Node" slug="sandbox-node" /> - <Page title="GraphQL API" slug="graphql-api" /> - </Folder> - <Folder title="Coda Protocol Architecture" slug="architecture"> - <Page title="Coda Overview" slug="" /> - <Page title="Lifecycle of a Payment" slug="lifecycle-payment" /> - <Page title="Consensus" slug="consensus" /> - <Page title="Proof of Stake" slug="proof-of-stake" /> - <Page title="Snark Workers" slug="snark-workers" /> - </Folder> - <Folder title="SNARKs" slug="snarks"> - <Page title="SNARKs Overview" slug="" /> - <Page title="Getting started using SNARKs" slug="snarky" /> - <Page title="Which SNARK is right for me?" slug="constructions" /> - <Page title="The snarkyjs-crypto library" slug="snarkyjs-crypto" /> - <Page title="The snarky-universe library" slug="snarky-universe" /> - </Folder> - <Page title="Snapps" slug="snapps" /> - <Page title="CLI Reference" slug="cli-reference" /> - <Page title="Troubleshooting" slug="troubleshooting" /> - <Page title="FAQ" slug="faq" /> - <Page title="Glossary" slug="glossary" /> - </ul> - </CurrentSlugProvider> - </aside>; -}; diff --git a/frontend/website-redesign/src/components/Dropdown.re b/frontend/website-redesign/src/components/Dropdown.re deleted file mode 100644 index a23a79e8635..00000000000 --- a/frontend/website-redesign/src/components/Dropdown.re +++ /dev/null @@ -1,100 +0,0 @@ -module Styles = { - open Css; - let currentItemTitle = - style([ - display(`inlineFlex), - alignItems(`center), - marginTop(`px(4)), - marginLeft(`rem(0.5)), - ]); - - let container = { - merge([ - Theme.Body.medium, - style([ - position(`relative), - width(`percent(100.)), - letterSpacing(`rem(-0.0125)), - fontWeight(`num(500)), - border(`px(1), `solid, Theme.Colors.hyperlinkAlpha(0.3)), - borderRadius(`px(4)), - padding(`px(5)), - cursor(`pointer), - after([ - // Render triangle icon at the end of the dropdown - unsafe("content", ""), - position(`absolute), - width(`zero), - height(`zero), - borderLeft(`px(7), `solid, transparent), - borderRight(`px(7), `solid, transparent), - borderTop(`px(7), `solid, Theme.Colors.teal), - borderRadius(`px(4)), - right(`px(15)), - top(`percent(40.)), - ]), - ]), - ]); - }; - - let collapsedDropdown = { - style([ - position(`absolute), - left(`zero), - right(`zero), - fontWeight(`num(500)), - backgroundColor(Theme.Colors.white), - pointerEvents(`none), - border(`px(1), `solid, Theme.Colors.hyperlinkAlpha(0.3)), - opacity(0.), - ]); - }; - - let expandedDropdown = { - merge([ - collapsedDropdown, - style([ - top(`rem(2.3)), - borderRadius(`px(4)), - pointerEvents(`auto), - opacity(1.), - zIndex(1), - selector( - "li", - [ - display(`block), - textDecoration(`none), - padding(`px(10)), - hover([background(Theme.Colors.gandalf)]), - ], - ), - ]), - ]); - }; -}; - -[@react.component] -let make = (~items, ~currentItem, ~onItemPress) => { - let (menuOpen, toggleMenu) = React.useState(() => false); - - let onDropdownItemPress = item => { - onItemPress(item); - toggleMenu(_ => !menuOpen); - }; - - <div className=Styles.container onClick={_ => {toggleMenu(_ => !menuOpen)}}> - <span className=Styles.currentItemTitle> - {React.string(currentItem)} - </span> - <ul - className={menuOpen ? Styles.expandedDropdown : Styles.collapsedDropdown}> - {items - |> Array.map(item => { - <li key=item onClick={_ => {onDropdownItemPress(item)}}> - {React.string(item)} - </li> - }) - |> React.array} - </ul> - </div>; -}; diff --git a/frontend/website-redesign/src/components/GenesisCTA.re b/frontend/website-redesign/src/components/GenesisCTA.re deleted file mode 100644 index 4756dd40ee1..00000000000 --- a/frontend/website-redesign/src/components/GenesisCTA.re +++ /dev/null @@ -1,17 +0,0 @@ -[@react.component] -let make = () => { - <div className=Css.(style([marginBottom(px(8)), textAlign(`left)]))> - <p className=Theme.Body.basic> - {React.string( - "Get started on Coda by applying for the Genesis Token Program.", - )} - </p> - <Spacer height=1. /> - <Button - link="/genesis" - label="Join Genesis" - bgColor=Theme.Colors.hyperlink - bgColorHover={Theme.Colors.hyperlinkAlpha(1.)} - /> - </div>; -}; diff --git a/frontend/website-redesign/src/components/GetInvolvedSection.re b/frontend/website-redesign/src/components/GetInvolvedSection.re deleted file mode 100644 index 288bc3de353..00000000000 --- a/frontend/website-redesign/src/components/GetInvolvedSection.re +++ /dev/null @@ -1,371 +0,0 @@ -module KnowledgeBase = { - module SubSection = { - [@react.component] - let make = (~className="", ~title, ~content) => { - let items = - content - |> Array.mapi((i, {title, url}: ContentType.KnowledgeBase.link) => - <li - key={string_of_int(i)} - className=Css.( - style([ - marginBottom(`rem(0.5)), - color(Theme.Colors.hyperlink), - listStyle(`none, `inside, `none), - marginLeft(`rem(1.5)), - marginRight(`rem(1.)), - before([ - contentRule({js|*|js}), - color(Theme.Colors.hyperlink), - display(`inlineBlock), - marginLeft(`rem(-1.)), - marginRight(`rem(0.6)), - verticalAlign(`bottom), - ]), - ]) - )> - <a - href=url - className=Css.( - merge([Theme.Link.basic, style([cursor(`pointer)])]) - )> - {React.string(title)} - </a> - </li> - ) - |> React.array; - - <div className> - <h5 - className=Css.( - merge([ - Theme.H5.basic, - style([ - marginLeft(`zero), - color(Theme.Colors.slate), - marginRight(`zero), - marginTop(`rem(1.)), - marginBottom(`rem(0.75)), - media( - Theme.MediaQuery.notMobile, - [marginTop(`rem(1.)), marginLeft(`rem(0.5))], - ), - ]), - ]) - )> - {React.string(title)} - </h5> - <ul - className=Css.( - style([ - marginRight(`zero), - paddingBottom(`zero), - paddingLeft(`zero), - paddingRight(`zero), - marginBottom(`zero), - maxWidth(`rem(24.5)), - ]) - )> - items - </ul> - </div>; - }; - }; - - [@react.component] - let make = (~links) => { - let (baseOpen, setOpen) = React.useState(() => false); - <fieldset - className=Css.( - style([ - textAlign(`center), - Theme.Typeface.ibmplexserif, - display(`block), - border(`px(1), `solid, Theme.Colors.hyperlinkAlpha(0.3)), - borderRadius(`px(18)), - maxWidth(`rem(58.625)), - marginLeft(`auto), - marginRight(`auto), - unsafe("minWidth", "min-content"), - paddingBottom(`rem(1.)), - media(Theme.MediaQuery.notMobile, [paddingBottom(`rem(2.))]), - ]) - )> - {ReactDOMRe.createElement( - "legend", - ~props= - ReactDOMRe.objToDOMProps({ - "align": "center", - "className": - Css.( - style([ - textAlign(`center), - marginTop(`zero), - marginBottom(`zero), - ]) - ), - }), - [| - <h4 - className=Css.( - style([ - textAlign(`center), - letterSpacing(`rem(0.1875)), - border(`px(1), `solid, Theme.Colors.saville), - paddingLeft(`rem(1.25)), - paddingRight(`rem(1.25)), - paddingTop(`rem(0.25)), - paddingBottom(`rem(0.25)), - textTransform(`uppercase), - fontWeight(`medium), - color(Theme.Colors.midnight), - ]) - )> - {React.string("Knowledge base")} - </h4>, - |], - )} - <div - className=Css.( - style([ - position(`relative), - display(`flex), - justifyContent(`spaceAround), - flexWrap(`wrap), - textAlign(`left), - paddingLeft(`rem(1.0)), - paddingRight(`rem(1.0)), - paddingTop(`rem(1.5)), - paddingBottom(`rem(1.5)), - height(baseOpen ? auto : `rem(15.)), - overflow(`hidden), - after([ - contentRule(""), - position(`absolute), - bottom(`zero), - left(`zero), - height(`rem(2.)), - width(`percent(100.)), - pointerEvents(`none), - backgroundImage( - `linearGradient(( - `deg(0.), - [ - (`zero, Theme.Colors.white), - (`percent(100.), Theme.Colors.whiteAlpha(0.0)), - ], - )), - ), - ]), - ]) - )> - <SubSection - title="Articles" - content={links.ContentType.KnowledgeBase.articles} - /> - <SubSection - title="Videos & Podcasts" - content={links.ContentType.KnowledgeBase.videos} - /> - </div> - {baseOpen - ? React.null - : <label - className=Css.( - merge([ - Theme.Link.basic, - style([ - color(Theme.Colors.hyperlink), - marginTop(`rem(1.0)), - marginLeft(`auto), - marginRight(`auto), - marginBottom(`rem(-1.0)), - width(`rem(10.)), - height(`rem(2.5)), - display(`block), - cursor(`pointer), - ]), - ]) - ) - onClick={_ => {setOpen(_ => !baseOpen)}}> - {React.string({js|View all ↓|js})} - </label>} - </fieldset>; - }; -}; -module SocialLink = { - let colorVarName = "--svg-color-social"; - [@react.component] - let make = (~link, ~name, ~svg) => { - <a - name={"getinvolved-" ++ name} - href=link - className=Css.( - style([ - padding(`rem(1.)), - cursor(`pointer), - display(`flex), - textDecoration(`none), - justifyContent(`center), - alignItems(`center), - color(Theme.Colors.fadedBlue), - // Original color of svg - unsafe(colorVarName, Theme.Colors.(string(greyBlue))), - hover([ - color(Theme.Colors.hyperlink), - unsafe(colorVarName, Theme.Colors.(string(hyperlink))), - ]), - ]) - )> - <div className=Css.(style([marginRight(`rem(1.))]))> svg </div> - <h3 className=Theme.H3.wideNoColor> {React.string(name)} </h3> - </a>; - }; -}; - -module Svg = { - let className = - Css.(style([unsafe("fill", "var(" ++ SocialLink.colorVarName ++ ")")])); - let twitter = - <svg - width="34px" - height="28px" - viewBox="0 0 34 28" - version="1.1" - xmlns="http://www.w3.org/2000/svg" - xmlnsXlink="http://www.w3.org/1999/xlink"> - <path - fill=Theme.Colors.(string(greyBlue)) - className - d="M30.51,6.98 C30.53,7.28 30.5,7.59 30.52,7.90 C30.53,17.24 23.52,28 10.70,28 C6.75,28 3.09,26.84 0,24.83 C0.56,24.89 1.10,24.92 1.68,24.92 C4.94,24.92 7.93,23.80 10.33,21.90 C7.27,21.83 4.70,19.80 3.82,17.00 C4.25,17.06 4.68,17.11 5.13,17.11 C5.76,17.11 6.39,17.02 6.97,16.87 C3.78,16.21 1.38,13.37 1.38,9.93 L1.38,9.84 C2.31,10.37 3.39,10.70 4.53,10.74 C2.65,9.47 1.42,7.31 1.42,4.86 C1.42,3.54 1.77,2.34 2.37,1.29 C5.80,5.58 10.96,8.38 16.74,8.68 C16.63,8.16 16.57,7.61 16.57,7.07 C16.57,3.17 19.68,0 23.54,0 C25.54,0 27.36,0.85 28.63,2.23 C30.20,1.93 31.71,1.33 33.05,0.53 C32.53,2.17 31.43,3.54 29.99,4.42 C31.39,4.27 32.75,3.87 34,3.33 C33.05,4.72 31.86,5.97 30.51,6.98 Z" - id="IconTwitter" - /> - </svg>; - - let discord = - <svg - xmlns="http://www.w3.org/2000/svg" - xmlnsXlink="http://www.w3.org/1999/xlink" - width="34" - height="38"> - <defs> <path id="a" d="M0 0h34v38H0z" /> </defs> - <g fill="none" fillRule="evenodd"> - <path - fill=Theme.Colors.(string(greyBlue)) - className - d="M19.944 16.424c-.912 0-1.632.8-1.632 1.776s.7359 1.776 1.632 1.776c.9119 0 1.6319-.8 1.6319-1.776s-.72-1.776-1.6318-1.776m-5.84 0c-.912 0-1.632.8-1.632 1.776s.7358 1.776 1.632 1.776c.912 0 1.632-.8 1.632-1.776.016-.976-.72-1.776-1.632-1.776" - /> - <g> - <mask id="b" fill="#fff"> <use xlinkHref="#a" /> </mask> - <path - fill=Theme.Colors.(string(greyBlue)) - className - d="M22.5178 24.814s-.6996-.817-1.2825-1.539c2.5453-.703 3.5168-2.261 3.5168-2.261-.7968.513-1.5543.8741-2.2343 1.121-.9714.399-1.9042.665-2.8172.817-1.8653.342-3.5748.247-5.032-.0189-1.1076-.2092-2.0594-.5132-2.8561-.817-.4467-.1712-.9324-.38-1.4181-.6462-.0583-.038-.1166-.0568-.1749-.095-.0389-.0188-.0585-.038-.0777-.0568-.3497-.19-.544-.3232-.544-.3232s.9326 1.52 3.4 2.242c-.5829.722-1.3017 1.577-1.3017 1.577-4.2937-.1328-5.9257-2.8878-5.9257-2.8878 0-6.118 2.7977-11.0772 2.7977-11.0772 2.7977-2.052 5.4594-1.995 5.4594-1.995l.1943.228c-3.4972.988-5.1097 2.489-5.1097 2.489s.4274-.2278 1.146-.551c2.0791-.893 3.7305-1.14 4.4105-1.1968.1166-.0192.2138-.0382.3303-.0382a16.8172 16.8172 0 013.9246-.038c1.8457.209 3.8272.7412 5.848 1.824 0 0-1.535-1.425-4.8379-2.4128l.2722-.3042s2.6617-.057 5.4592 1.995c0 0 2.798 4.9592 2.798 11.0772 0 0-1.6515 2.755-5.9452 2.8878M30.0172 0H3.983C1.7875 0 .0001 1.7481.0001 3.914v25.688c0 2.1662 1.7874 3.9142 3.9828 3.9142h22.032l-1.0299-3.515 2.487 2.2608 2.351 2.128L34 38V3.914C34 1.7481 32.2126 0 30.0173 0" - mask="url(#b)" - /> - </g> - </g> - </svg>; - - let telegram = - <svg - width="36px" - height="30px" - viewBox="0 0 36 30" - version="1.1" - xmlns="http://www.w3.org/2000/svg" - xmlnsXlink="http://www.w3.org/1999/xlink"> - <g - id="coda_website" - stroke="none" - strokeWidth="1" - fill="none" - fillRule="evenodd"> - <g - id="coda_homepage" - transform="translate(-1074.000000, -3292.000000)" - fill=Theme.Colors.(string(greyBlue)) - className> - <g id="Community" transform="translate(418.000000, 3032.000000)"> - <g id="Telegram" transform="translate(656.000000, 260.000000)"> - <path - d="M35.8974224,2.73110855 L30.4647954,28.1890674 C30.0549375,29.985818 28.9860922,30.4330092 27.4672069,29.5865401 L19.1896835,23.5255016 L15.1955776,27.3425983 C14.7535739,27.781804 14.3838981,28.1491396 13.5320365,28.1491396 L14.1267323,19.7722893 L29.4682781,5.99720177 C30.1353018,5.40627048 29.3236223,5.0788626 28.4315785,5.66979389 L9.46560267,17.5363331 L1.30058933,14.9969256 C-0.475461794,14.4459221 -0.507607516,13.2321173 1.67026514,12.3856482 L33.6070397,0.159758876 C35.0857429,-0.391244625 36.3796082,0.487166754 35.8974224,2.73110855 Z" - id="IconTelegram" - /> - </g> - </g> - </g> - </g> - </svg>; -}; - -[@react.component] -let make = (~links) => { - <div> - <h1 - className=Css.( - merge([ - Theme.H1.hero, - style([ - color(Theme.Colors.denimTwo), - marginTop(`rem(6.)), - marginBottom(`rem(1.5)), - media(Theme.MediaQuery.notMobile, [textAlign(`center)]), - ]), - ]) - )> - {React.string("Get involved")} - </h1> - <div - className=Css.( - style([ - display(`flex), - justifyContent(`center), - flexWrap(`wrap), - alignItems(`flexStart), - maxWidth(`rem(46.0)), - media( - Theme.MediaQuery.notMobile, - [ - justifyContent(`center), - margin3(~top=`zero, ~h=`auto, ~bottom=`rem(2.)), - ], - ), - ]) - )> - <NewsletterWidget center=true /> - </div> - <div - className=Css.( - style([ - media(Theme.MediaQuery.notMobile, [marginBottom(`rem(2.4))]), - display(`flex), - flexWrap(`wrap), - justifyContent(`spaceAround), - alignItems(`center), - marginTop(`rem(1.0)), - marginBottom(`rem(1.25)), - maxWidth(`rem(63.)), - marginLeft(`auto), - marginRight(`auto), - ]) - )> - <SocialLink - link="https://twitter.com/codaprotocol" - name="Twitter" - svg=Svg.twitter - /> - <SocialLink - link="https://bit.ly/CodaDiscord" - name="Discord" - svg=Svg.discord - /> - <SocialLink - link="https://t.me/codaprotocol" - name="Telegram" - svg=Svg.telegram - /> - </div> - <KnowledgeBase links /> - </div>; -}; diff --git a/frontend/website-redesign/src/components/HeroSection.re b/frontend/website-redesign/src/components/HeroSection.re deleted file mode 100644 index 0610a9ac269..00000000000 --- a/frontend/website-redesign/src/components/HeroSection.re +++ /dev/null @@ -1,227 +0,0 @@ -module Copy = { - [@react.component] - let make = () => { - <div - className=Css.( - style([ - display(`flex), - flexDirection(`column), - justifyContent(`center), - width(`percent(100.0)), - maxWidth(`rem(37.0)), - minWidth(`rem(17.5)), - media("(min-width: 30rem)", [minWidth(`rem(24.0))]), - media( - Theme.MediaQuery.full, - [width(`percent(60.0)), minWidth(`rem(24.0))], - ), - media(Theme.MediaQuery.somewhatLarge, [minWidth(`rem(32.))]), - ]) - )> - <div - className=Css.( - style([media(Theme.MediaQuery.full, [minWidth(`rem(25.5))])]) - )> - <h1 - className=Css.( - merge([ - Theme.H1.hero, - style([ - color(Theme.Colors.denimTwo), - marginTop(`zero), - marginBottom(`zero), - media(Theme.MediaQuery.full, [marginTop(`rem(1.5))]), - ]), - ]) - )> - {React.string( - {j|A cryptocurrency with a tiny portable blockchain.|j}, - )} - </h1> - <p - className=Css.( - merge([ - Theme.Body.big, - style([ - marginTop(`rem(2.0)), - maxWidth(`rem(30.0)), - // align with the grid - media( - Theme.MediaQuery.full, - [marginTop(`rem(1.75)), marginBottom(`rem(2.0))], - ), - ]), - ]) - )> - <span> - {React.string( - "Coda swaps the traditional blockchain for a tiny cryptographic proof, enabling a cryptocurrency as accessible as any other app or website. This makes it ", - )} - </span> - <span className=Theme.Body.big_semibold> - {React.string( - "dramatically easier to develop user friendly crypto apps", - )} - </span> - <span> - {React.string( - {j| that run natively in the browser, and enables more inclusive, sustainable\u00A0consensus.|j}, - )} - </span> - <br /> - </p> - </div> - <GenesisCTA /> - </div>; - }; -}; - -module Graphic = { - module Big = { - let svg = - <Svg - className=Css.(style([marginTop(`rem(-0.625))])) - link="/static/img/hero-illustration.svg" - dims=(9.5625, 33.375) - alt="Huge tower of blocks representing the data required by other blockchains." - />; - }; - - module Info = { - [@react.component] - let make = - ( - ~className="", - ~sizeEmphasis, - ~name, - ~size, - ~label, - ~textColor, - ~children, - ) => { - <div - className=Css.( - merge([ - className, - style([ - display(`flex), - flexDirection(`column), - justifyContent(`flexEnd), - alignItems(`center), - ]), - ]) - )> - children - <div> - <h3 - className=Css.( - merge([ - Theme.H3.basic, - style([ - color(textColor), - fontWeight(`medium), - marginTop(`rem(1.25)), - marginBottom(`zero), - ]), - ]) - )> - {React.string(name)} - </h3> - <h3 - className=Css.( - merge([ - Theme.H3.basic, - style([ - color(textColor), - marginTop(`zero), - marginBottom(`zero), - fontWeight(sizeEmphasis ? `bold : `normal), - ]), - ]) - )> - {React.string(size)} - </h3> - </div> - <h5 - className=Css.( - merge([ - Theme.H5.basic, - style([marginTop(`rem(1.125)), marginBottom(`rem(0.375))]), - ]) - )> - {React.string(label)} - </h5> - </div>; - }; - }; - - [@react.component] - let make = () => { - Css.( - <div - className={style([ - width(`percent(100.0)), - maxWidth(`rem(20.0)), - marginRight(`rem(2.0)), - media(Theme.MediaQuery.veryVeryLarge, [marginRight(`rem(4.75))]), - ])}> - <div - className={style([ - display(`flex), - justifyContent(`spaceAround), - width(`percent(100.0)), - media(Theme.MediaQuery.full, [justifyContent(`spaceBetween)]), - ])}> - <Info - sizeEmphasis=false - name="Coda" - size="22kB" - label="Fixed" - textColor=Theme.Colors.bluishGreen> - <img - className={style([width(`rem(0.625))])} - src="/static/img/coda-icon.png" - alt="Small Coda logo representing its small, fixed blockchain size." - /> - </Info> - <Info - className={style([ - marginRight(`rem(-1.5)), - media(Theme.MediaQuery.full, [marginRight(`zero)]), - ])} - sizeEmphasis=true - name="Other blockchains" - size="2TB+" - label="Increasing" - textColor=Theme.Colors.rosebud> - Big.svg - </Info> - </div> - </div> - ); - }; -}; - -[@react.component] -let make = () => { - <div - className=Css.( - style([ - display(`flex), - justifyContent(`spaceAround), - flexWrap(`wrap), - maxWidth(`rem(73.0)), - media( - Theme.MediaQuery.full, - [flexWrap(`nowrap), justifyContent(`spaceBetween)], - ), - media( - Theme.MediaQuery.somewhatLarge, - [marginLeft(`px(80)), marginRight(`px(80))], - ), - ]) - )> - <Copy /> - <Graphic /> - </div>; -}; diff --git a/frontend/website-redesign/src/components/HoverCard.re b/frontend/website-redesign/src/components/HoverCard.re deleted file mode 100644 index 09d01c0f2f2..00000000000 --- a/frontend/website-redesign/src/components/HoverCard.re +++ /dev/null @@ -1,101 +0,0 @@ -module Styles = { - open Css; - - let ctaButton = - style([ - background(Theme.Colors.hyperlinkAlpha(0.3 *. 0.2)), - borderRadius(`px(6)), - textDecoration(`none), - padding(`rem(1.43)), - paddingTop(`rem(1.625)), - margin(`auto), - height(`rem(14.25)), - width(`rem(21.25)), - media( - "(min-width: 60rem)", - [height(`rem(12.5)), width(`rem(23.8))], - ), - media( - "(min-width: 105rem)", - [height(`rem(11.5)), width(`rem(32.5))], - ), - hover([ - backgroundColor(`hex("FAFCFD")), - cursor(`pointer), - boxShadow( - ~x=`zero, - ~y=`px(4), - ~blur=`px(8), - ~spread=`zero, - `rgba((0, 0, 0, 0.25)), - ), - selector("svg", [SVG.fill(Theme.Colors.hyperlink)]), - ]), - ]); - - let ctaContent = style([display(`flex)]); - - let ctaText = style([width(`percent(100.))]); - - let ctaHeading = - merge([ - Theme.H2.basic, - style([ - fontWeight(`bold), - color(Theme.Colors.marine), - textAlign(`left), - paddingBottom(`rem(0.3)), - ]), - ]); - - let ctaBody = - merge([ - Theme.Body.basic, - style([marginTop(`rem(1.)), color(Theme.Colors.midnight)]), - ]); - - let ctaIcon = - style([ - marginTop(`px(2)), - minWidth(`px(36)), - maxHeight(`px(48)), - flexShrink(0.), - ]); - let arrow = - style([ - marginTop(`rem(0.9)), - marginLeft(`rem(1.0)), - SVG.fill(Theme.Colors.hyperlinkAlpha(0.3)), - ]); - - let headingRow = - style([ - display(`flex), - flexDirection(`row), - justifyContent(`spaceBetween), - ]); -}; - -[@react.component] -let make = (~heading, ~text, ~href) => { - <a href className=Styles.ctaButton> - <div className=Styles.ctaContent> - <div className=Styles.ctaText> - <div className=Styles.headingRow> - <h2 className=Styles.ctaHeading> heading </h2> - <svg - className=Styles.arrow - width="27" - height="17" - viewBox="0 0 27 17" - xmlns="http://www.w3.org/2000/svg"> - <path - d="M17.7329 16.716L15.1769 14.16L17.6249 11.712L19.2809 10.308L19.2449 10.164L16.1849 10.344H0.452881V6.52801H16.1849L19.2449 6.70801L19.2809 6.56401L17.6249 5.16001L15.1769 2.71201L17.7329 0.156006L26.0129 8.43601L17.7329 16.716Z" - /> - </svg> - </div> - <p className=Styles.ctaBody> text </p> - </div> - </div> - </a>; -}; diff --git a/frontend/website-redesign/src/components/Icon.re b/frontend/website-redesign/src/components/Icon.re new file mode 100644 index 00000000000..9832f7f5079 --- /dev/null +++ b/frontend/website-redesign/src/components/Icon.re @@ -0,0 +1,961 @@ +type kind = + | World + | Discord + | Twitter + | Facebook + | Telegram + | WeChat + | Forums + | Github + | Wiki + | Email + | Location + | ArrowUpMedium + | ArrowLeftLarge + | ArrowRightLarge + | ArrowRightMedium + | ChevronDownLarge + | ChevronDown + | ChevronUp + | ChevronRight + | Info + | Plus + | ExternalLink + | BulletPoint + | Copy + | NodeOperators + | Developers + | Documentation + | GenesisProgram + | GrantsProgram + | Testnet + | InstallSDK + | CoreProtocol + | Community + | TechnicalGrants + | SubmitYourOwn + | Comet + | CommunityGrants + | Browser + | BurgerMenu + | CloseMenu + | Box; + +module Styles = { + open Css; + let svg = size => { + style([height(size), width(size)]); + }; +}; + +[@react.component] +let make = (~kind, ~size=`px(24)) => { + <svg className={Styles.svg(size)}> + {switch (kind) { + | World => + <path + d="M12 0C5.37306 0 0 5.37306 0 12C0 18.6269 5.37306 24 12 24C18.6269 24 24 18.6269 24 12C24 5.37306 18.6269 0 12 0ZM12.4898 22.9176C12.4653 22.9176 12.4359 22.9176 12.4114 22.9224V18.2547H16.2269C15.3698 20.7967 14.018 22.5747 12.4898 22.9176ZM7.6702 18.2547H11.3927V22.9127C11.3878 22.9127 11.3878 22.9127 11.3829 22.9127C9.86449 22.5551 8.52245 20.782 7.6702 18.2547ZM1.08245 12.5094H5.70122C5.73551 14.209 5.94612 15.8057 6.29878 17.2359H2.4049C1.63102 15.8204 1.16082 14.2139 1.08245 12.5094ZM16.2269 5.74531H12.4114V1.07755C12.4359 1.07755 12.4653 1.07755 12.4898 1.08245C14.018 1.42531 15.3698 3.20327 16.2269 5.74531ZM16.5306 6.76408C16.9078 8.18939 17.138 9.79592 17.1771 11.4906H12.4065V6.76408H16.5306ZM11.3829 1.08735C11.3878 1.08735 11.3878 1.08735 11.3927 1.08735V5.74531H7.6702C8.52245 3.21796 9.86449 1.4449 11.3829 1.08735ZM11.3927 6.76408V11.4906H6.72C6.75918 9.79592 6.98939 8.18449 7.36653 6.76408H11.3927ZM5.70122 11.4906H1.08245C1.16082 9.78122 1.63102 8.17959 2.4049 6.76408H6.29878C5.94612 8.19429 5.73551 9.79102 5.70122 11.4906ZM6.72 12.5094H11.3927V17.2359H7.36653C6.98939 15.8106 6.75918 14.2041 6.72 12.5094ZM12.4114 17.2359V12.5094H17.182C17.1429 14.2041 16.9127 15.8155 16.5355 17.2359H12.4114ZM18.1959 12.5094H22.9176C22.8392 14.2188 22.369 15.8204 21.5951 17.2359H17.5984C17.951 15.8057 18.1616 14.209 18.1959 12.5094ZM18.1959 11.4906C18.1616 9.79102 17.951 8.19429 17.5984 6.76408H21.5951C22.369 8.17959 22.8392 9.78612 22.9176 11.4906H18.1959ZM20.9633 5.74531H17.3143C16.7608 3.96245 15.9673 2.49796 15.0171 1.49388C17.4563 2.19429 19.5478 3.71755 20.9633 5.74531ZM8.84082 1.53306C7.9102 2.53714 7.13143 3.98694 6.58286 5.74531H3.03673C4.42775 3.75673 6.46531 2.25306 8.84082 1.53306ZM3.03673 18.2547H6.58286C7.13143 20.0131 7.9102 21.4629 8.84082 22.4669C6.46531 21.7469 4.42775 20.2433 3.03673 18.2547ZM15.0171 22.5061C15.9673 21.502 16.7608 20.0327 17.3143 18.2498H20.9633C19.5478 20.2824 17.4563 21.8106 15.0171 22.5061Z" + fill="#2D2D2D" + /> + | Discord => + <path + d="M20.7273 6.125C20.7273 6.125 18.2258 4.21781 15.2727 4L15.0065 4.51903C17.676 5.156 18.9011 6.06656 20.1818 7.1875C17.9744 6.08994 15.7964 5.0625 12 5.0625C8.20364 5.0625 6.02564 6.08994 3.81818 7.1875C5.09891 6.06656 6.55636 5.054 8.99345 4.51903L8.72727 4C5.62909 4.28422 3.27273 6.125 3.27273 6.125C3.27273 6.125 0.479455 10.0701 0 17.8125C2.81455 20.975 7.09091 21 7.09091 21L7.98545 19.8397C6.46691 19.3255 4.75418 18.408 3.27273 16.75C5.03891 18.0516 7.70455 19.4062 12 19.4062C16.2955 19.4062 18.9611 18.0516 20.7273 16.75C19.2464 18.408 17.5336 19.3255 16.0145 19.8397L16.9091 21C16.9091 21 21.1855 20.975 24 17.8125C23.5205 10.0701 20.7273 6.125 20.7273 6.125ZM8.45455 15.6875C7.39964 15.6875 6.54545 14.7366 6.54545 13.5625C6.54545 12.3884 7.39964 11.4375 8.45455 11.4375C9.50945 11.4375 10.3636 12.3884 10.3636 13.5625C10.3636 14.7366 9.50945 15.6875 8.45455 15.6875ZM15.5455 15.6875C14.4905 15.6875 13.6364 14.7366 13.6364 13.5625C13.6364 12.3884 14.4905 11.4375 15.5455 11.4375C16.6004 11.4375 17.4545 12.3884 17.4545 13.5625C17.4545 14.7366 16.6004 15.6875 15.5455 15.6875Z" + fill="#2D2D2D" + /> + | Twitter => + <path + d="M22.2857 5.80545C21.5207 6.13586 20.7056 6.35487 19.8557 6.4612C20.73 5.94723 21.3973 5.13957 21.711 4.16607C20.8959 4.64459 19.9959 4.98259 19.0367 5.17122C18.2627 4.35975 17.1596 3.85718 15.9562 3.85718C13.6213 3.85718 11.7416 5.72316 11.7416 8.01071C11.7416 8.33985 11.7699 8.65633 11.8393 8.95763C8.33315 8.78926 5.23072 7.13468 3.14658 4.61421C2.78272 5.23578 2.56929 5.94723 2.56929 6.71312C2.56929 8.15123 3.32144 9.42602 4.44258 10.1641C3.76501 10.1514 3.10029 9.95771 2.53715 9.65262C2.53715 9.66528 2.53715 9.68174 2.53715 9.6982C2.53715 11.7161 3.99901 13.3922 5.91601 13.7783C5.57272 13.8707 5.19858 13.915 4.81029 13.915C4.54029 13.915 4.26772 13.8998 4.01187 13.8441C4.55829 15.4886 6.10887 16.6975 7.95258 16.7368C6.51772 17.842 4.69587 18.5078 2.72358 18.5078C2.37772 18.5078 2.04601 18.4926 1.71429 18.4509C3.58244 19.637 5.79644 20.3143 8.18401 20.3143C15.9446 20.3143 20.1874 13.9846 20.1874 8.49809C20.1874 8.31453 20.181 8.1373 20.172 7.96134C21.009 7.37647 21.7123 6.64603 22.2857 5.80545Z" + fill="#2D2D2D" + /> + | Facebook => + <path + d="M9.42854 8.57138H6.85712V11.9999H9.42854V22.2857H13.7143V11.9999H16.836L17.1428 8.57138H13.7143V7.14252C13.7143 6.32395 13.8788 5.99995 14.67 5.99995H17.1428V1.71423H13.8788C10.7965 1.71423 9.42854 3.07109 9.42854 5.66995V8.57138Z" + fill="#2D2D2D" + /> + | Telegram => + <path + d="M9.78635 15.0864L9.44606 20.3881C9.93293 20.3881 10.1438 20.1565 10.3967 19.8783L12.6793 17.462L17.4091 21.2987C18.2766 21.8342 18.8877 21.5522 19.1217 20.4147L22.2264 4.30074L22.2272 4.29979C22.5024 2.87942 21.7635 2.32399 20.9183 2.67244L2.66933 10.4114C1.42387 10.9469 1.44273 11.7159 2.45761 12.0644L7.12315 13.6718L17.9603 6.1607C18.4703 5.78662 18.934 5.9936 18.5526 6.36768L9.78635 15.0864Z" + fill="#2D2D2D" + /> + | WeChat => + <path + fillRule="evenodd" + clipRule="evenodd" + d="M11.0884 10.9858C12.4365 9.72179 14.097 9.16233 16.0066 9.06591C15.8982 7.94485 15.4879 6.99697 14.8187 6.15244C12.9659 3.81444 9.54162 2.83325 6.49452 3.79515C4.26211 4.49997 2.61916 5.85205 1.95013 8.08152C1.227 10.4915 2.19328 12.8323 4.48562 14.3964C4.84265 14.6405 4.89667 14.8489 4.78003 15.2234C4.67054 15.5752 4.59394 15.9366 4.51147 16.3258C4.47447 16.5004 4.43629 16.6805 4.39343 16.8679C4.60892 16.7377 4.81479 16.6113 5.01442 16.4888C5.51366 16.1824 5.97388 15.8999 6.44814 15.6413C6.64815 15.5322 6.92836 15.5049 7.16449 15.5241C7.65173 15.5638 8.13701 15.6251 8.64582 15.6894C8.85097 15.7153 9.05994 15.7417 9.27442 15.7674C9.10454 13.8276 9.72624 12.2628 11.0884 10.9858ZM6.37093 7.46382C6.84035 7.47708 7.23555 7.87419 7.21796 8.31498C7.20022 8.76667 6.79792 9.12208 6.31801 9.11035C5.83393 9.09846 5.4668 8.72673 5.481 8.26285C5.49504 7.80514 5.89032 7.45018 6.37093 7.46382ZM10.9424 8.30225C10.9341 7.85971 11.3322 7.4719 11.8034 7.46352C12.2828 7.45506 12.6716 7.81772 12.6755 8.27748C12.6802 8.74586 12.3118 9.10852 11.8261 9.11416C11.3416 9.1198 10.951 8.76095 10.9424 8.30225ZM19.7491 20.3071C19.9286 20.3986 20.1104 20.4912 20.2969 20.5715C20.2838 20.5212 20.2741 20.4709 20.2646 20.4217C20.2448 20.319 20.2259 20.2209 20.1788 20.1379C19.8011 19.4724 20.0129 19.057 20.6015 18.5522C22.6358 16.8079 22.8316 14.0518 21.1653 11.9755C19.2557 9.59612 15.2838 9.02447 12.5754 10.7393C9.52806 12.6687 9.15171 16.2788 11.7856 18.6333C13.1705 19.8711 14.8501 20.3761 16.7248 20.1907C16.9788 20.1656 17.2334 20.095 17.486 20.0249C17.8456 19.9251 18.2015 19.8264 18.547 19.8613C18.9554 19.9025 19.3466 20.1019 19.7491 20.3071ZM14.1303 13.4726C14.1157 13.8401 13.7988 14.1313 13.4138 14.1309C13.0316 14.1304 12.7125 13.8342 12.6994 13.4681C12.6854 13.0848 13.0197 12.754 13.4189 12.7557C13.822 12.7573 14.1457 13.0836 14.1303 13.4726ZM17.1449 13.4149C17.1601 13.0502 17.4775 12.7547 17.851 12.7572C18.2484 12.7599 18.5623 13.0827 18.5473 13.4736C18.5333 13.8451 18.228 14.1275 17.8417 14.1262C17.4423 14.1253 17.1287 13.805 17.1449 13.4149Z" + fill="#2D2D2D" + /> + | Forums => + <path + d="M6.34629 22.0893L10.1433 18.3338H15.7429C20.3013 18.3338 24 14.6755 24 10.1669C24 5.65835 20.3062 2 15.7429 2H8.25706C3.69382 2 0 5.65835 0 10.1669C0 13.7767 2.36758 16.8326 5.64879 17.9112V21.8027C5.64879 22.1671 6.08596 22.3468 6.34629 22.0893ZM15.3942 9.15638C15.9591 9.15638 16.4159 9.6082 16.4159 10.1669C16.4159 10.7256 15.9591 11.1775 15.3942 11.1775C14.8293 11.1775 14.3725 10.7256 14.3725 10.1669C14.3725 9.6082 14.8293 9.15638 15.3942 9.15638ZM12 9.15638C12.5649 9.15638 13.0217 9.6082 13.0217 10.1669C13.0217 10.7256 12.5649 11.1775 12 11.1775C11.4351 11.1775 10.9783 10.7256 10.9783 10.1669C10.9783 9.6082 11.4351 9.15638 12 9.15638ZM8.60581 9.15638C9.17069 9.15638 9.62751 9.6082 9.62751 10.1669C9.62751 10.7256 9.17069 11.1775 8.60581 11.1775C8.04093 11.1775 7.58412 10.7256 7.58412 10.1669C7.58412 9.6082 8.04093 9.15638 8.60581 9.15638Z" + fill="#2D2D2D" + /> + | Github => + <path + fillRule="evenodd" + clipRule="evenodd" + d="M12.0001 0C5.37349 0 0 5.50832 0 12.3037C0 17.7399 3.4384 22.352 8.20642 23.9789C8.80613 24.0928 9.02633 23.7119 9.02633 23.387C9.02633 23.0936 9.01515 22.1243 9.00998 21.0962C5.67157 21.8405 4.96712 19.6445 4.96712 19.6445C4.42124 18.2224 3.63473 17.8442 3.63473 17.8442C2.54596 17.0806 3.7168 17.0963 3.7168 17.0963C4.92181 17.1829 5.55631 18.3642 5.55631 18.3642C6.6266 20.2452 8.36355 19.7014 9.04838 19.387C9.15607 18.592 9.46702 18.0488 9.81023 17.7417C7.14485 17.4306 4.34295 16.3756 4.34295 11.6611C4.34295 10.3178 4.81172 9.22021 5.57937 8.35853C5.45477 8.04848 5.04403 6.79723 5.69561 5.10246C5.69561 5.10246 6.70331 4.77177 8.99648 6.36366C9.9537 6.09104 10.9803 5.95432 12.0001 5.94964C13.0199 5.95432 14.0473 6.09104 15.0063 6.36366C17.2967 4.77177 18.303 5.10246 18.303 5.10246C18.9562 6.79723 18.5452 8.04848 18.4206 8.35853C19.1901 9.22021 19.6556 10.3178 19.6556 11.6611C19.6556 16.3868 16.8484 17.4274 14.1763 17.732C14.6067 18.1138 14.9902 18.8626 14.9902 20.0105C14.9902 21.6566 14.9763 22.9815 14.9763 23.387C14.9763 23.7144 15.1923 24.098 15.8006 23.9772C20.566 22.3485 24 17.7381 24 12.3037C24 5.50832 18.6273 0 12.0001 0Z" + fill="#2D2D2D" + /> + | Wiki => + <path + fillRule="evenodd" + clipRule="evenodd" + d="M24 4.96632C24 5.05173 23.9726 5.12882 23.9198 5.19965C23.8649 5.2684 23.8079 5.30382 23.7425 5.30382C23.2169 5.35382 22.7842 5.52048 22.4507 5.8059C22.115 6.08923 21.771 6.63298 21.4142 7.43298L15.9683 19.5455C15.9325 19.658 15.8332 19.7142 15.6686 19.7142C15.5398 19.7142 15.4406 19.658 15.3689 19.5455L12.3145 13.2413L8.80211 19.5455C8.73034 19.658 8.63113 19.7142 8.50237 19.7142C8.34617 19.7142 8.24274 19.658 8.19208 19.5455L2.84116 7.43298C2.50765 6.6809 2.15515 6.1559 1.78364 5.85798C1.41425 5.56007 0.897098 5.37465 0.236412 5.30382C0.17942 5.30382 0.124538 5.27465 0.0759895 5.21423C0.0253298 5.1559 0 5.08715 0 5.01007C0 4.81215 0.0569921 4.71423 0.170976 4.71423C0.648021 4.71423 1.14617 4.73507 1.66755 4.77673C2.15092 4.82048 2.60686 4.84132 3.03325 4.84132C3.46807 4.84132 3.981 4.82048 4.57203 4.77673C5.1905 4.73507 5.73931 4.71423 6.21636 4.71423C6.33034 4.71423 6.38734 4.81215 6.38734 5.01007C6.38734 5.2059 6.35145 5.30382 6.28179 5.30382C5.80475 5.33923 5.42902 5.46007 5.15462 5.66215C4.88021 5.86632 4.74301 6.13298 4.74301 6.46423C4.74301 6.63298 4.8 6.8434 4.91398 7.09548L9.33615 16.9517L11.8459 12.2726L9.50712 7.43298C9.08707 6.57048 8.7409 6.01215 8.47071 5.76215C8.20053 5.51423 7.79103 5.36007 7.24222 5.30382C7.19156 5.30382 7.14512 5.27465 7.09868 5.21423C7.05224 5.1559 7.02902 5.08715 7.02902 5.01007C7.02902 4.81215 7.07757 4.71423 7.17889 4.71423C7.65594 4.71423 8.09288 4.73507 8.49182 4.77673C8.87599 4.82048 9.28549 4.84132 9.72032 4.84132C10.1467 4.84132 10.5984 4.82048 11.0755 4.77673C11.5673 4.73507 12.0507 4.71423 12.5277 4.71423C12.6417 4.71423 12.6987 4.81215 12.6987 5.01007C12.6987 5.2059 12.6649 5.30382 12.5931 5.30382C11.639 5.3684 11.162 5.63507 11.162 6.1059C11.162 6.31632 11.2718 6.6434 11.4934 7.08507L13.0406 10.1851L14.5794 7.34965C14.7926 6.94965 14.9003 6.61215 14.9003 6.33715C14.9003 5.69132 14.4232 5.34757 13.4691 5.30382C13.3826 5.30382 13.3404 5.2059 13.3404 5.01007C13.3404 4.93923 13.3615 4.87257 13.4037 4.81007C13.448 4.74548 13.4902 4.71423 13.5325 4.71423C13.8744 4.71423 14.2945 4.73507 14.7926 4.77673C15.2697 4.82048 15.6623 4.84132 15.9683 4.84132C16.1879 4.84132 16.5129 4.82257 16.9393 4.78715C17.4797 4.73923 17.9335 4.71423 18.2966 4.71423C18.381 4.71423 18.4232 4.79757 18.4232 4.96632C18.4232 5.19132 18.3451 5.30382 18.1889 5.30382C17.6338 5.36007 17.1863 5.51215 16.8485 5.75798C16.5108 6.00382 16.0887 6.56215 15.5842 7.43298L13.5325 11.1767L16.3103 16.7622L20.4116 7.34965C20.553 7.0059 20.6248 6.68923 20.6248 6.40173C20.6248 5.71215 20.1478 5.34757 19.1937 5.30382C19.1071 5.30382 19.0649 5.2059 19.0649 5.01007C19.0649 4.81215 19.1282 4.71423 19.257 4.71423C19.6053 4.71423 20.019 4.73507 20.496 4.77673C20.9372 4.82048 21.3087 4.84132 21.6063 4.84132C21.9208 4.84132 22.2839 4.82048 22.6955 4.77673C23.124 4.73507 23.5082 4.71423 23.8501 4.71423C23.9493 4.71423 24 4.79757 24 4.96632Z" + fill="#2D2D2D" + /> + | Email => + <path + d="M1.56785 6.6355C2.17204 6.93961 10.5416 11.1553 10.8536 11.312C11.1656 11.4687 11.5692 11.543 11.9753 11.543C12.3814 11.543 12.785 11.4687 13.097 11.312C13.409 11.1553 21.7785 6.93961 22.3827 6.6355C22.9881 6.33023 23.5601 5.14282 22.4496 5.14282H1.50223C0.391656 5.14282 0.963656 6.33023 1.56785 6.6355ZM22.6637 9.19255C21.9766 9.528 13.5179 13.6601 13.097 13.8668C12.676 14.0734 12.3814 14.0977 11.9753 14.0977C11.5692 14.0977 11.2745 14.0734 10.8536 13.8668C10.4326 13.6601 2.02223 9.52684 1.33508 9.19139C0.852227 8.95461 0.85718 9.23202 0.85718 9.44559C0.85718 9.65916 0.85718 17.9107 0.85718 17.9107C0.85718 18.3982 1.55794 19.0714 2.09527 19.0714H21.9048C22.4421 19.0714 23.1429 18.3982 23.1429 17.9107C23.1429 17.9107 23.1429 9.66032 23.1429 9.44675C23.1429 9.23318 23.1478 8.95577 22.6637 9.19255Z" + fill="#2D2D2D" + /> + | Location => + <path + d="M11.7958 0C7.41843 0 3.85718 3.56125 3.85718 7.93857C3.85718 9.7016 4.983 12.5759 7.29878 16.7259C8.93687 19.6611 10.548 22.1085 10.6157 22.2112L11.7958 24L12.9758 22.2113C13.0436 22.1085 14.6548 19.6612 16.2927 16.726C18.6086 12.5759 19.7343 9.70165 19.7343 7.93862C19.7344 3.56125 16.1731 0 11.7958 0ZM11.7958 12C9.52316 12 7.68076 10.1576 7.68076 7.88497C7.68076 5.61229 9.52316 3.76994 11.7958 3.76994C14.0684 3.76994 15.9108 5.61229 15.9108 7.88497C15.9108 10.1576 14.0684 12 11.7958 12Z" + fill="#2D2D2D" + /> + | ArrowUpMedium => + <svg> + <rect x="11" y="4" width="1" height="16" fill="#2D2D2D" /> + <rect x="12" y="5" width="1" height="1" fill="#2D2D2D" /> + <rect x="13" y="6" width="1" height="1" fill="#2D2D2D" /> + <rect x="14" y="7" width="1" height="1" fill="#2D2D2D" /> + <rect x="15" y="8" width="1" height="1" fill="#2D2D2D" /> + <rect x="16" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="6" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="7" y="8" width="1" height="1" fill="#2D2D2D" /> + <rect x="8" y="7" width="1" height="1" fill="#2D2D2D" /> + <rect x="9" y="6" width="1" height="1" fill="#2D2D2D" /> + <rect x="10" y="5" width="1" height="1" fill="#2D2D2D" /> + </svg> + | ArrowLeftLarge => + <svg> + <rect + width="24" + height="1" + transform="matrix(-1 0 0 1 24 11)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 2 12)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 2 10)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 3 9)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 4 8)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 5 7)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 6 6)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 7 5)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 8 4)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 9 3)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 10 2)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 3 13)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 4 14)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 5 15)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 6 16)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 7 17)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 8 18)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 9 19)" + fill="#2D2D2D" + /> + <rect + width="1" + height="1" + transform="matrix(-1 0 0 1 10 20)" + fill="#2D2D2D" + /> + </svg> + + | ArrowRightLarge => + <svg> + <rect y="11" width="24" height="1" fill="#2D2D2D" /> + <rect x="22" y="12" width="1" height="1" fill="#2D2D2D" /> + <rect x="22" y="10" width="1" height="1" fill="#2D2D2D" /> + <rect x="21" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="20" y="8" width="1" height="1" fill="#2D2D2D" /> + <rect x="19" y="7" width="1" height="1" fill="#2D2D2D" /> + <rect x="18" y="6" width="1" height="1" fill="#2D2D2D" /> + <rect x="17" y="5" width="1" height="1" fill="#2D2D2D" /> + <rect x="16" y="4" width="1" height="1" fill="#2D2D2D" /> + <rect x="15" y="3" width="1" height="1" fill="#2D2D2D" /> + <rect x="14" y="2" width="1" height="1" fill="#2D2D2D" /> + <rect x="21" y="13" width="1" height="1" fill="#2D2D2D" /> + <rect x="20" y="14" width="1" height="1" fill="#2D2D2D" /> + <rect x="19" y="15" width="1" height="1" fill="#2D2D2D" /> + <rect x="18" y="16" width="1" height="1" fill="#2D2D2D" /> + <rect x="17" y="17" width="1" height="1" fill="#2D2D2D" /> + <rect x="16" y="18" width="1" height="1" fill="#2D2D2D" /> + <rect x="15" y="19" width="1" height="1" fill="#2D2D2D" /> + <rect x="14" y="20" width="1" height="1" fill="#2D2D2D" /> + </svg> + | ArrowRightMedium => + <svg> + <rect + x="20" + y="11" + width="1" + height="16" + transform="rotate(90 20 11)" + fill="#2D2D2D" + /> + <rect + x="19" + y="12" + width="1" + height="1" + transform="rotate(90 19 12)" + fill="#2D2D2D" + /> + <rect + x="18" + y="13" + width="1" + height="1" + transform="rotate(90 18 13)" + fill="#2D2D2D" + /> + <rect + x="17" + y="14" + width="1" + height="1" + transform="rotate(90 17 14)" + fill="#2D2D2D" + /> + <rect + x="16" + y="15" + width="1" + height="1" + transform="rotate(90 16 15)" + fill="#2D2D2D" + /> + <rect + x="15" + y="16" + width="1" + height="1" + transform="rotate(90 15 16)" + fill="#2D2D2D" + /> + <rect + x="15" + y="6" + width="1" + height="1" + transform="rotate(90 15 6)" + fill="#2D2D2D" + /> + <rect + x="16" + y="7" + width="1" + height="1" + transform="rotate(90 16 7)" + fill="#2D2D2D" + /> + <rect + x="17" + y="8" + width="1" + height="1" + transform="rotate(90 17 8)" + fill="#2D2D2D" + /> + <rect + x="18" + y="9" + width="1" + height="1" + transform="rotate(90 18 9)" + fill="#2D2D2D" + /> + <rect + x="19" + y="10" + width="1" + height="1" + transform="rotate(90 19 10)" + fill="#2D2D2D" + /> + </svg> + | ChevronDownLarge => + <svg> + <rect x="3" y="8" width="1" height="1" fill="#2D2D2D" /> + <rect x="4" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="5" y="10" width="1" height="1" fill="#2D2D2D" /> + <rect x="6" y="11" width="1" height="1" fill="#2D2D2D" /> + <rect x="7" y="12" width="1" height="1" fill="#2D2D2D" /> + <rect x="8" y="13" width="1" height="1" fill="#2D2D2D" /> + <rect x="9" y="14" width="1" height="1" fill="#2D2D2D" /> + <rect x="10" y="15" width="1" height="1" fill="#2D2D2D" /> + <rect x="11" y="16" width="1" height="1" fill="#2D2D2D" /> + <rect x="12" y="17" width="1" height="1" fill="#2D2D2D" /> + <rect x="13" y="16" width="1" height="1" fill="#2D2D2D" /> + <rect x="14" y="15" width="1" height="1" fill="#2D2D2D" /> + <rect x="15" y="14" width="1" height="1" fill="#2D2D2D" /> + <rect x="16" y="13" width="1" height="1" fill="#2D2D2D" /> + <rect x="17" y="12" width="1" height="1" fill="#2D2D2D" /> + <rect x="18" y="11" width="1" height="1" fill="#2D2D2D" /> + <rect x="19" y="10" width="1" height="1" fill="#2D2D2D" /> + <rect x="20" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="21" y="8" width="1" height="1" fill="#2D2D2D" /> + </svg> + | ChevronDown => + <svg> + <rect x="14.5" y="11" width="1" height="1" fill="#2D2D2D" /> + <rect x="13.5" y="12" width="1" height="1" fill="#2D2D2D" /> + <rect x="15.5" y="10" width="1" height="1" fill="#2D2D2D" /> + <rect x="8.5" y="11" width="1" height="1" fill="#2D2D2D" /> + <rect x="7.5" y="10" width="1" height="1" fill="#2D2D2D" /> + <rect x="6.5" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="16.5" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="9.5" y="12" width="1" height="1" fill="#2D2D2D" /> + <rect x="10.5" y="13" width="1" height="1" fill="#2D2D2D" /> + <rect x="12.5" y="13" width="1" height="1" fill="#2D2D2D" /> + <rect x="11.5" y="14" width="1" height="1" fill="#2D2D2D" /> + </svg> + | ChevronUp => + <svg> + <rect + x="9.5" + y="13" + width="1" + height="1" + transform="rotate(180 9.5 13)" + fill="#2D2D2D" + /> + <rect + x="10.5" + y="12" + width="1" + height="1" + transform="rotate(180 10.5 12)" + fill="#2D2D2D" + /> + <rect + x="8.5" + y="14" + width="1" + height="1" + transform="rotate(180 8.5 14)" + fill="#2D2D2D" + /> + <rect + x="15.5" + y="13" + width="1" + height="1" + transform="rotate(180 15.5 13)" + fill="#2D2D2D" + /> + <rect + x="16.5" + y="14" + width="1" + height="1" + transform="rotate(180 16.5 14)" + fill="#2D2D2D" + /> + <rect + x="17.5" + y="15" + width="1" + height="1" + transform="rotate(180 17.5 15)" + fill="#2D2D2D" + /> + <rect + x="7.5" + y="15" + width="1" + height="1" + transform="rotate(180 7.5 15)" + fill="#2D2D2D" + /> + <rect + x="14.5" + y="12" + width="1" + height="1" + transform="rotate(180 14.5 12)" + fill="#2D2D2D" + /> + <rect + x="13.5" + y="11" + width="1" + height="1" + transform="rotate(180 13.5 11)" + fill="#2D2D2D" + /> + <rect + x="11.5" + y="11" + width="1" + height="1" + transform="rotate(180 11.5 11)" + fill="#2D2D2D" + /> + <rect + x="12.5" + y="10" + width="1" + height="1" + transform="rotate(180 12.5 10)" + fill="#2D2D2D" + /> + </svg> + | ChevronRight => + <svg> + <rect + x="11" + y="9.5" + width="1" + height="1" + transform="rotate(-90 11 9.5)" + fill="#2D2D2D" + /> + <rect + x="12" + y="10.5" + width="1" + height="1" + transform="rotate(-90 12 10.5)" + fill="#2D2D2D" + /> + <rect + x="10" + y="8.5" + width="1" + height="1" + transform="rotate(-90 10 8.5)" + fill="#2D2D2D" + /> + <rect + x="11" + y="15.5" + width="1" + height="1" + transform="rotate(-90 11 15.5)" + fill="#2D2D2D" + /> + <rect + x="10" + y="16.5" + width="1" + height="1" + transform="rotate(-90 10 16.5)" + fill="#2D2D2D" + /> + <rect + x="9" + y="17.5" + width="1" + height="1" + transform="rotate(-90 9 17.5)" + fill="#2D2D2D" + /> + <rect + x="9" + y="7.5" + width="1" + height="1" + transform="rotate(-90 9 7.5)" + fill="#2D2D2D" + /> + <rect + x="12" + y="14.5" + width="1" + height="1" + transform="rotate(-90 12 14.5)" + fill="#2D2D2D" + /> + <rect + x="13" + y="13.5" + width="1" + height="1" + transform="rotate(-90 13 13.5)" + fill="#2D2D2D" + /> + <rect + x="13" + y="11.5" + width="1" + height="1" + transform="rotate(-90 13 11.5)" + fill="#2D2D2D" + /> + <rect + x="14" + y="12.5" + width="1" + height="1" + transform="rotate(-90 14 12.5)" + fill="#2D2D2D" + /> + </svg> + | Info => + <svg> + <circle cx="12" cy="12" r="11.5" stroke="#2D2D2D" /> + <rect x="10.5" y="10.5" width="3" height="7.5" fill="#2D2D2D" /> + <rect x="10.5" y="6" width="3" height="3" fill="#2D2D2D" /> + </svg> + | Plus => + <path + fillRule="evenodd" + clipRule="evenodd" + d="M12.5 4.5H11.5V11.5H4.5V12.5H11.5V19.5H12.5V12.5H19.5V11.5H12.5V4.5Z" + fill="#2D2D2D" + /> + | ExternalLink => + <path + fillRule="evenodd" + clipRule="evenodd" + d="M17 7H16H15H14H13V8H14H15V9H14V10H13V11H12V12H11V13H10V14H11V13H12V12H13V11H14V10H15V9H16V10V11H17V10V9V8V7ZM7 9H8H11V10H8V16H14V13H15V16V17H14H8H7V16V10V9Z" + fill="#2D2D2D" + /> + | BulletPoint => + <svg> + <rect x="9" y="9" width="6" height="6" rx="3" fill="#2D2D2D" /> + </svg> + | ArrowRightLarge => + <svg> + <rect y="11" width="24" height="1" fill="#2D2D2D" /> + <rect x="22" y="12" width="1" height="1" fill="#2D2D2D" /> + <rect x="22" y="10" width="1" height="1" fill="#2D2D2D" /> + <rect x="21" y="9" width="1" height="1" fill="#2D2D2D" /> + <rect x="20" y="8" width="1" height="1" fill="#2D2D2D" /> + <rect x="19" y="7" width="1" height="1" fill="#2D2D2D" /> + <rect x="18" y="6" width="1" height="1" fill="#2D2D2D" /> + <rect x="17" y="5" width="1" height="1" fill="#2D2D2D" /> + <rect x="16" y="4" width="1" height="1" fill="#2D2D2D" /> + <rect x="15" y="3" width="1" height="1" fill="#2D2D2D" /> + <rect x="14" y="2" width="1" height="1" fill="#2D2D2D" /> + <rect x="21" y="13" width="1" height="1" fill="#2D2D2D" /> + <rect x="20" y="14" width="1" height="1" fill="#2D2D2D" /> + <rect x="19" y="15" width="1" height="1" fill="#2D2D2D" /> + <rect x="18" y="16" width="1" height="1" fill="#2D2D2D" /> + <rect x="17" y="17" width="1" height="1" fill="#2D2D2D" /> + <rect x="16" y="18" width="1" height="1" fill="#2D2D2D" /> + <rect x="15" y="19" width="1" height="1" fill="#2D2D2D" /> + <rect x="14" y="20" width="1" height="1" fill="#2D2D2D" /> + </svg> + | Copy => + <svg> + <rect x="9.5" y="6.5" width="9" height="13" stroke="#2D2D2D" /> + <rect x="7" y="3" width="10" height="1" fill="#2D2D2D" /> + <rect + width="1" + height="15" + transform="matrix(1 0 0 -1 6 18)" + fill="#2D2D2D" + /> + </svg> + | NodeOperators => + <svg> + <rect + x="0.5" + y="0.5" + width="23" + height="23" + rx="0.5" + stroke="#2D2D2D" + /> + <path d="M5.4 8.40002L9 12L5.4 15.6" stroke="#2D2D2D" /> + <line x1="10.8" y1="15.1" x2="18.6" y2="15.1" stroke="#2D2D2D" /> + </svg> + | Developers => + <svg> + <path d="M18 7.19995L22.8 12L18 16.7999" stroke="#2D2D2D" /> + <path + d="M6.00001 7.19995L1.20001 12L6.00001 16.7999" + stroke="#2D2D2D" + /> + <line + x1="16.0535" + y1="3.81053" + x2="8.25348" + y2="20.6105" + stroke="#2D2D2D" + /> + </svg> + | Documentation => + <svg + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg"> + <g> + <rect + x="2.90002" + y="2.90002" + width="20.6" + height="20.6" + rx="0.5" + fill="white" + stroke="#2D2D2D" + /> + <rect + x="0.5" + y="0.5" + width="20.6" + height="20.6" + rx="0.5" + fill="white" + stroke="#2D2D2D" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M16.8 4.80005H4.79999V5.70005H16.8V4.80005ZM15 8.40005H4.79999V9.30005H15V8.40005ZM4.79999 12H16.8V12.9H4.79999V12ZM12.6 15.6H4.79999V16.5H12.6V15.6Z" + fill="#2D2D2D" + /> + </g> + <defs> + <clipPath id="clip0"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> + | GenesisProgram => + <svg> + <g> + <path + d="M22.9 12C22.9 18.0199 18.0199 22.9 12 22.9C5.98007 22.9 1.09998 18.0199 1.09998 12C1.09998 5.98007 5.98007 1.09998 12 1.09998C18.0199 1.09998 22.9 5.98007 22.9 12Z" + stroke="#2D2D2D" + /> + <path + d="M17.3942 12C17.3942 15.0879 16.7731 17.8587 15.7921 19.8391C14.7957 21.8507 13.5126 22.9 12.2471 22.9C10.9816 22.9 9.69852 21.8507 8.70206 19.8391C7.72109 17.8587 7.10004 15.0879 7.10004 12C7.10004 8.9121 7.72109 6.14124 8.70206 4.1609C9.69852 2.1493 10.9816 1.09998 12.2471 1.09998C13.5126 1.09998 14.7957 2.1493 15.7921 4.1609C16.7731 6.14124 17.3942 8.9121 17.3942 12Z" + stroke="#2D2D2D" + /> + <line x1="1" y1="11.5" x2="23" y2="11.5" stroke="#2D2D2D" /> + <ellipse + cx="19.2353" + cy="3.91768" + rx="1.8" + ry="1.8" + fill="#2D2D2D" + /> + <circle cx="22.2" cy="16.8" r="1.8" fill="#2D2D2D" /> + <ellipse cx="1.8" cy="6.74116" rx="1.8" ry="1.8" fill="#2D2D2D" /> + <path + d="M11.4 1.8C11.4 2.79411 10.5941 3.6 9.59999 3.6C8.60588 3.6 7.79999 2.79411 7.79999 1.8C7.79999 0.805887 8.60588 0 9.59999 0C10.5941 0 11.4 0.805887 11.4 1.8Z" + fill="#2D2D2D" + /> + <ellipse cx="13.8" cy="22.2" rx="1.8" ry="1.8" fill="#2D2D2D" /> + <ellipse cx="3.00001" cy="18.6" rx="1.8" ry="1.8" fill="#2D2D2D" /> + <ellipse cx="12" cy="11.4" rx="1.8" ry="1.8" fill="#2D2D2D" /> + </g> + <defs> + <clipPath id="clip0"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> + | GrantsProgram => + <svg> + <rect + x="0.5" + y="0.5" + width="23" + height="23" + rx="2.5" + stroke="#2D2D2D" + /> + <path + d="M12 18.0136C12.1916 18.0246 12.3798 17.959 12.5231 17.8314C12.6664 17.7037 12.7532 17.5243 12.7643 17.3327L12.8842 16.421C12.3024 16.5558 11.6975 16.5558 11.1158 16.421L11.2317 17.3347C11.2461 17.5256 11.3344 17.7034 11.4779 17.8302C11.6214 17.957 11.8087 18.0228 12 18.0136ZM17.1834 17.8171H18.6119V9.66269C18.6119 8.54957 18.0971 7.80192 17.1834 7.51995V17.8171ZM5.38806 17.8171H6.81655V7.51504C5.90876 7.79701 5.38806 8.54466 5.38806 9.65778V17.8171ZM12.8842 16.421C13.8146 16.1882 14.4296 15.524 14.5789 14.3578L15.4759 7.43055C14.4424 7.67715 13.8775 8.46311 13.7114 9.7403L12.8842 16.421ZM11.1158 16.421L10.2895 9.7403C10.1225 8.46311 9.55761 7.67715 8.52799 7.43055L9.42497 14.3578C9.57431 15.5211 10.1726 16.1852 11.1197 16.421H11.1158ZM17.1834 7.51701V6.86859C17.1834 6.30367 16.8514 5.98438 16.4024 5.98438C15.9534 5.98438 15.638 6.25062 15.5555 6.83125L15.472 7.42957C16.0408 7.31775 16.6282 7.34641 17.1834 7.51308V7.51701ZM6.81655 7.51308C7.13864 7.40939 7.47541 7.35862 7.81375 7.36276C8.05359 7.35778 8.29323 7.3802 8.52799 7.42957L8.44547 6.83125C8.36196 6.25062 8.04659 5.98438 7.59761 5.98438C7.14862 5.98438 6.81655 6.29974 6.81655 6.86859V7.51308Z" + fill="#2D2D2D" + /> + </svg> + | Testnet => + <svg> + <rect + x="0.5" + y="0.5" + width="23" + height="23" + rx="11.5" + stroke="#2D2D2D" + /> + <path + d="M6.59998 12.28L11.46 16.2001L17.4 7.80005" + stroke="#2D2D2D" + strokeLinecap="round" + /> + </svg> + | InstallSDK => + <svg> + <path + d="M12.5 13L2 18L12.5 23L23 18L12.5 13Z" + fill="white" + stroke="#2D2D2D" + strokeMiterlimit="16" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M12.5 9L2 14L12.5 19L23 14L12.5 9Z" + fill="white" + stroke="#2D2D2D" + strokeMiterlimit="16" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M12.5 5L2 10L12.5 15L23 10L12.5 5Z" + fill="white" + stroke="#2D2D2D" + strokeMiterlimit="16" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M12.5 1L2 6L12.5 11L23 6L12.5 1Z" + fill="white" + stroke="#2D2D2D" + strokeMiterlimit="16" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + | CoreProtocol => + <path + d="M12 20.1614C12.2601 20.1763 12.5154 20.0874 12.7099 19.9141C12.9045 19.7409 13.0222 19.4974 13.0373 19.2374L13.2 18.0001C12.4105 18.1831 11.5895 18.1831 10.8 18.0001L10.9573 19.2401C10.9768 19.4992 11.0967 19.7405 11.2915 19.9126C11.4862 20.0847 11.7404 20.1739 12 20.1614ZM19.0347 19.8947H20.9733V8.82806C20.9733 7.31739 20.2747 6.30273 19.0347 5.92006V19.8947ZM3.02667 19.8947H4.96534V5.91339C3.73334 6.29606 3.02667 7.31073 3.02667 8.82139V19.8947ZM13.2 18.0001C14.4627 17.6841 15.2973 16.7827 15.5 15.2001L16.7173 5.79873C15.3147 6.13339 14.548 7.20006 14.3227 8.93339L13.2 18.0001ZM10.8 18.0001L9.67867 8.93339C9.45201 7.20006 8.68534 6.13339 7.28801 5.79873L8.50534 15.2001C8.70801 16.7787 9.52001 17.6801 10.8053 18.0001H10.8ZM19.0347 5.91606V5.03606C19.0347 4.26939 18.584 3.83606 17.9747 3.83606C17.3653 3.83606 16.9373 4.19739 16.8253 4.98539L16.712 5.79739C17.4839 5.64564 18.2812 5.68454 19.0347 5.91073V5.91606ZM4.96534 5.91073C5.40245 5.77 5.8595 5.70111 6.31867 5.70673C6.64418 5.69997 6.9694 5.73039 7.28801 5.79739L7.17601 4.98539C7.06267 4.19739 6.63467 3.83606 6.02534 3.83606C5.41601 3.83606 4.96534 4.26406 4.96534 5.03606V5.91073Z" + fill="#2D2D2D" + /> + | Community => + <svg> + <path + d="M22.9 12C22.9 18.0199 18.0199 22.9 12 22.9C5.98007 22.9 1.09998 18.0199 1.09998 12C1.09998 5.98007 5.98007 1.09998 12 1.09998C18.0199 1.09998 22.9 5.98007 22.9 12Z" + stroke="#2D2D2D" + /> + <path + d="M17.3941 12C17.3941 15.0879 16.773 17.8587 15.7921 19.8391C14.7956 21.8507 13.5126 22.9 12.247 22.9C10.9815 22.9 9.69846 21.8507 8.702 19.8391C7.72103 17.8587 7.09998 15.0879 7.09998 12C7.09998 8.9121 7.72103 6.14124 8.702 4.1609C9.69846 2.1493 10.9815 1.09998 12.247 1.09998C13.5126 1.09998 14.7956 2.1493 15.7921 4.1609C16.773 6.14124 17.3941 8.9121 17.3941 12Z" + stroke="#2D2D2D" + /> + <line x1="1" y1="12.5" x2="23" y2="12.5" stroke="#2D2D2D" /> + </svg> + | TechnicalGrants => + <svg> + <g> + <circle cx="11.9999" cy="12" r="5.03846" stroke="#2D2D2D" /> + <path + d="M0.5 7.59172L7.59172 0.5H16.4083L23.5 7.59172V16.4083L16.4083 23.5H7.59172L0.5 16.4083V7.59172Z" + stroke="#2D2D2D" + strokeLinecap="round" + strokeLinejoin="round" + /> + </g> + <defs> + <clipPath id="clip0"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> + | SubmitYourOwn => + <path + d="M22.8 4.28567L18.9112 1.19995L1.80005 18.9428V22.7999H5.68894L22.8 4.28567Z" + stroke="#2D2D2D" + strokeLinecap="round" + strokeLinejoin="round" + /> + | Comet => + <svg> + <g> + <circle cx="18.6827" cy="5.31722" r="4.21724" stroke="#2D2D2D" /> + <line + x1="13.9655" + y1="10.7415" + x2="1.30704" + y2="23.3999" + stroke="#2D2D2D" + strokeLinecap="round" + strokeLinejoin="round" + /> + <line + x1="12.1514" + y1="8.34032" + x2="1.2645" + y2="13.4209" + stroke="#2D2D2D" + strokeLinecap="round" + strokeLinejoin="round" + /> + <line + x1="16.6403" + y1="12.2393" + x2="13.0255" + y2="23.0837" + stroke="#2D2D2D" + strokeLinecap="round" + strokeLinejoin="round" + /> + </g> + <defs> + <clipPath id="clip0"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> + | CommunityGrants => + <svg> + <path + d="M23.5 17.44V17.4625V17.4848V17.5071V17.5293V17.5514V17.5735V17.5955V17.6175V17.6393V17.6612V17.6829V17.7046V17.7262V17.7478V17.7693V17.7907V17.8121V17.8334V17.8546V17.8758V17.8969V17.918V17.939V17.9599V17.9807V18.0015V18.0223V18.0429V18.0635V18.0841V18.1046V18.125V18.1453V18.1656V18.1859V18.206V18.2261V18.2462V18.2662V18.2861V18.3059V18.3257V18.3455V18.3651V18.3847V18.4043V18.4238V18.4432V18.4626V18.4819V18.5011V18.5203V18.5394V18.5585V18.5774V18.5964V18.6153V18.6341V18.6528V18.6715V18.6902V18.7087V18.7272V18.7457V18.7641V18.7824V18.8007V18.8189V18.8371V18.8551V18.8732V18.8912V18.9091V18.9269V18.9447V18.9625V18.9801V18.9978V19.0153V19.0328V19.0503V19.0676V19.085V19.1022V19.1195V19.1366V19.1537V19.1707V19.1877V19.2046V19.2215V19.2383V19.255V19.2717V19.2884V19.3049V19.3215V19.3379V19.3543V19.3707V19.3869V19.4032V19.4193V19.4355V19.4515V19.4675V19.4835V19.4994V19.5152V19.531V19.5467V19.5624V19.578V19.5935V19.609V19.6245V19.6399V19.6552V19.6705V19.6857V19.7009V19.716V19.731V19.746V19.761V19.7759V19.7907V19.8055V19.8202V19.8349V19.8495V19.8641V19.8786V19.893V19.9074V19.9218V19.9361V19.9503V19.9645V19.9786V19.9927V20.0067V20.0207V20.0346V20.0485V20.0623V20.076V20.0897V20.1034V20.117V20.1305V20.144V20.1575V20.1709V20.1842V20.1975V20.2107V20.2239V20.237V20.2501V20.2631V20.2761V20.289V20.3019V20.3147V20.3275V20.3402V20.3528V20.3654V20.378V20.3905V20.403V20.4154V20.4277V20.44V20.4523V20.4645V20.4766V20.4888V20.5008V20.5128V20.5248V20.5367V20.5485V20.5603V20.5721V20.5838V20.5954V20.607V20.6186V20.6301V20.6415V20.6529V20.6643V20.6756V20.6869V20.6981V20.7092V20.7204V20.7314V20.7424V20.7534V20.7643V20.7752V20.786V20.7968V20.8075V20.8182V20.8288V20.8394V20.8499V20.8604V20.8709V20.8813V20.8916V20.9019V20.9121V20.9223V20.9325V20.9426V20.9527V20.9627V20.9727V20.9826V20.9925V21.0023V21.0121V21.0218V21.0315V21.0411V21.0507V21.0603V21.0698V21.0793V21.0887V21.098V21.1074V21.1166V21.1259V21.1351V21.1442V21.1533V21.1624V21.1714V21.1803V21.1892V21.1981V21.207V21.2157V21.2245V21.2332V21.2418V21.2504V21.259V21.2675V21.276V21.2844V21.2928V21.3012V21.3095V21.3177V21.3259V21.3341V21.3422V21.3503V21.3583V21.3663V21.3743V21.3822V21.3901V21.3979V21.4057V21.4134V21.4211V21.4288V21.4364V21.444V21.4515V21.459V21.4664V21.4738V21.4812V21.4885V21.4958V21.5031V21.5102V21.5174V21.5245V21.5316V21.5386V21.5456V21.5526V21.5595V21.5663V21.5732V21.58V21.5867V21.5934V21.6001V21.6067V21.6133V21.6198V21.6264V21.6328V21.6392V21.6456V21.652V21.6583V21.6646V21.6708V21.677V21.6831V21.6892V21.6953V21.7014V21.7073V21.7133V21.7192V21.7251V21.7309V21.7367V21.74H10.1V21.7377V21.7304V21.7231V21.7158V21.7084V21.701V21.6935V21.686V21.6785V21.6709V21.6633V21.6556V21.6479V21.6401V21.6323V21.6245V21.6166V21.6087V21.6007V21.5927V21.5846V21.5766V21.5684V21.5603V21.5521V21.5438V21.5355V21.5272V21.5188V21.5104V21.502V21.4935V21.485V21.4764V21.4678V21.4592V21.4505V21.4418V21.4331V21.4243V21.4155V21.4066V21.3977V21.3888V21.3798V21.3708V21.3618V21.3527V21.3436V21.3345V21.3253V21.3161V21.3068V21.2976V21.2882V21.2789V21.2695V21.2601V21.2506V21.2412V21.2316V21.2221V21.2125V21.2029V21.1932V21.1835V21.1738V21.1641V21.1543V21.1445V21.1346V21.1248V21.1149V21.1049V21.095V21.085V21.0749V21.0649V21.0548V21.0447V21.0345V21.0243V21.0141V21.0039V20.9936V20.9833V20.973V20.9627V20.9523V20.9419V20.9314V20.921V20.9105V20.9V20.8894V20.8789V20.8683V20.8576V20.847V20.8363V20.8256V20.8149V20.8041V20.7933V20.7825V20.7717V20.7608V20.7499V20.739V20.7281V20.7171V20.7061V20.6951V20.6841V20.6731V20.662V20.6509V20.6398V20.6286V20.6174V20.6063V20.595V20.5838V20.5725V20.5613V20.55V20.5386V20.5273V20.5159V20.5045V20.4931V20.4817V20.4703V20.4588V20.4473V20.4358V20.4243V20.4127V20.4012V20.3896V20.378V20.3663V20.3547V20.343V20.3314V20.3197V20.3079V20.2962V20.2845V20.2727V20.2609V20.2491V20.2373V20.2255V20.2136V20.2017V20.1898V20.1779V20.166V20.1541V20.1422V20.1302V20.1182V20.1062V20.0942V20.0822V20.0702V20.0581V20.046V20.034V20.0219V20.0098V19.9977V19.9855V19.9734V19.9612V19.9491V19.9369V19.9247V19.9125V19.9003V19.888V19.8758V19.8635V19.8513V19.839V19.8267V19.8144V19.8021V19.7898V19.7775V19.7651V19.7528V19.7404V19.7281V19.7157V19.7033V19.6909V19.6785V19.6661V19.6537V19.6413V19.6288V19.6164V19.604V19.5915V19.579V19.5666V19.5541V19.5416V19.5291V19.5166V19.5041V19.4916V19.4791V19.4666V19.4541V19.4415V19.429V19.4165V19.4039V19.3914V19.3788V19.3663V19.3537V19.3411V19.3286V19.316V19.3034V19.2909V19.2783V19.2657V19.2531V19.2405V19.2279V19.2153V19.2027V19.1901V19.1776V19.165V19.1524V19.1398V19.1272V19.1146V19.102V19.0894V19.0768V19.0642V19.0516V19.039V19.0264V19.0138V19.0012V18.9886V18.976V18.9634V18.9508V18.9382V18.9256V18.913V18.9004V18.8879V18.8753V18.8627V18.8501V18.8376V18.825V18.8125V18.7999V18.7874V18.7748V18.7623V18.7497V18.7372V18.7247V18.7121V18.6996V18.6871V18.6746V18.6621V18.6496V18.6371V18.6246V18.6122V18.5997V18.5872V18.5748V18.5623V18.5499V18.5375V18.5251V18.5126V18.5002V18.4878V18.4754V18.4631V18.4507V18.4383V18.426V18.4136V18.4013V18.389V18.3767V18.3644V18.3521V18.3398V18.3275V18.3153V18.303V18.2908V18.2785V18.2663V18.2541V18.2419V18.2298V18.2176V18.2054V18.1933V18.1812V18.169V18.1569V18.1449V18.1328V18.1207V18.1087V18.0966V18.0846V18.0726V18.0606V18.0487V18.0367V18.0248V18.0128V18.0009V17.989V17.9771V17.9653V17.9534V17.9416V17.9298V17.918V17.9062V17.8944V17.8827V17.871V17.8592V17.8475V17.8359V17.8242V17.8126V17.801V17.7894V17.7778V17.7662V17.7547V17.7431V17.7316V17.7202V17.7087V17.6972V17.6858V17.6744V17.663V17.6517V17.6403V17.629V17.6177V17.6064V17.5952V17.584V17.5728V17.5616V17.5504V17.5393V17.5281V17.517V17.506V17.4949V17.4839V17.4729V17.4619V17.451V17.44C10.1 13.9046 13.0817 11.0067 16.8 11.0067C20.5182 11.0067 23.5 13.9046 23.5 17.44Z" + stroke="#2D2D2D" + /> + <path + d="M20.3282 6.68076C20.3282 8.76881 18.6355 10.4615 16.5475 10.4615C14.4594 10.4615 12.7667 8.76881 12.7667 6.68076C12.7667 4.59272 14.4594 2.90002 16.5475 2.90002C18.6355 2.90002 20.3282 4.59272 20.3282 6.68076Z" + stroke="#2D2D2D" + /> + <path + d="M13.9 17.44V17.4625V17.4848V17.5071V17.5293V17.5514V17.5735V17.5955V17.6175V17.6393V17.6612V17.6829V17.7046V17.7262V17.7478V17.7693V17.7907V17.8121V17.8334V17.8546V17.8758V17.8969V17.918V17.939V17.9599V17.9807V18.0015V18.0223V18.0429V18.0635V18.0841V18.1046V18.125V18.1453V18.1656V18.1859V18.206V18.2261V18.2462V18.2662V18.2861V18.3059V18.3257V18.3455V18.3651V18.3847V18.4043V18.4238V18.4432V18.4626V18.4819V18.5011V18.5203V18.5394V18.5585V18.5774V18.5964V18.6153V18.6341V18.6528V18.6715V18.6902V18.7087V18.7272V18.7457V18.7641V18.7824V18.8007V18.8189V18.8371V18.8551V18.8732V18.8912V18.9091V18.9269V18.9447V18.9625V18.9801V18.9978V19.0153V19.0328V19.0503V19.0676V19.085V19.1022V19.1195V19.1366V19.1537V19.1707V19.1877V19.2046V19.2215V19.2383V19.255V19.2717V19.2884V19.3049V19.3215V19.3379V19.3543V19.3707V19.3869V19.4032V19.4193V19.4355V19.4515V19.4675V19.4835V19.4994V19.5152V19.531V19.5467V19.5624V19.578V19.5935V19.609V19.6245V19.6399V19.6552V19.6705V19.6857V19.7009V19.716V19.731V19.746V19.761V19.7759V19.7907V19.8055V19.8202V19.8349V19.8495V19.8641V19.8786V19.893V19.9074V19.9218V19.9361V19.9503V19.9645V19.9786V19.9927V20.0067V20.0207V20.0346V20.0485V20.0623V20.076V20.0897V20.1034V20.117V20.1305V20.144V20.1575V20.1709V20.1842V20.1975V20.2107V20.2239V20.237V20.2501V20.2631V20.2761V20.289V20.3019V20.3147V20.3275V20.3402V20.3528V20.3654V20.378V20.3905V20.403V20.4154V20.4277V20.44V20.4523V20.4645V20.4766V20.4888V20.5008V20.5128V20.5248V20.5367V20.5485V20.5603V20.5721V20.5838V20.5954V20.607V20.6186V20.6301V20.6415V20.6529V20.6643V20.6756V20.6869V20.6981V20.7092V20.7204V20.7314V20.7424V20.7534V20.7643V20.7752V20.786V20.7968V20.8075V20.8182V20.8288V20.8394V20.8499V20.8604V20.8709V20.8813V20.8916V20.9019V20.9121V20.9223V20.9325V20.9426V20.9527V20.9627V20.9727V20.9826V20.9925V21.0023V21.0121V21.0218V21.0315V21.0411V21.0507V21.0603V21.0698V21.0793V21.0887V21.098V21.1074V21.1166V21.1259V21.1351V21.1442V21.1533V21.1624V21.1714V21.1803V21.1892V21.1981V21.207V21.2157V21.2245V21.2332V21.2418V21.2504V21.259V21.2675V21.276V21.2844V21.2928V21.3012V21.3095V21.3177V21.3259V21.3341V21.3422V21.3503V21.3583V21.3663V21.3743V21.3822V21.3901V21.3979V21.4057V21.4134V21.4211V21.4288V21.4364V21.444V21.4515V21.459V21.4664V21.4738V21.4812V21.4885V21.4958V21.5031V21.5102V21.5174V21.5245V21.5316V21.5386V21.5456V21.5526V21.5595V21.5663V21.5732V21.58V21.5867V21.5934V21.6001V21.6067V21.6133V21.6198V21.6264V21.6328V21.6392V21.6456V21.652V21.6583V21.6646V21.6708V21.677V21.6831V21.6892V21.6953V21.7014V21.7073V21.7133V21.7192V21.7251V21.7309V21.7367V21.74H0.5V21.7377V21.7304V21.7231V21.7158V21.7084V21.701V21.6935V21.686V21.6785V21.6709V21.6633V21.6556V21.6479V21.6401V21.6323V21.6245V21.6166V21.6087V21.6007V21.5927V21.5846V21.5766V21.5684V21.5603V21.5521V21.5438V21.5355V21.5272V21.5188V21.5104V21.502V21.4935V21.485V21.4764V21.4678V21.4592V21.4505V21.4418V21.4331V21.4243V21.4155V21.4066V21.3977V21.3888V21.3798V21.3708V21.3618V21.3527V21.3436V21.3345V21.3253V21.3161V21.3068V21.2976V21.2882V21.2789V21.2695V21.2601V21.2506V21.2412V21.2316V21.2221V21.2125V21.2029V21.1932V21.1835V21.1738V21.1641V21.1543V21.1445V21.1346V21.1248V21.1149V21.1049V21.095V21.085V21.0749V21.0649V21.0548V21.0447V21.0345V21.0243V21.0141V21.0039V20.9936V20.9833V20.973V20.9627V20.9523V20.9419V20.9314V20.921V20.9105V20.9V20.8894V20.8789V20.8683V20.8576V20.847V20.8363V20.8256V20.8149V20.8041V20.7933V20.7825V20.7717V20.7608V20.7499V20.739V20.7281V20.7171V20.7061V20.6951V20.6841V20.6731V20.662V20.6509V20.6398V20.6286V20.6174V20.6063V20.595V20.5838V20.5725V20.5613V20.55V20.5386V20.5273V20.5159V20.5045V20.4931V20.4817V20.4703V20.4588V20.4473V20.4358V20.4243V20.4127V20.4012V20.3896V20.378V20.3663V20.3547V20.343V20.3314V20.3197V20.3079V20.2962V20.2845V20.2727V20.2609V20.2491V20.2373V20.2255V20.2136V20.2017V20.1898V20.1779V20.166V20.1541V20.1422V20.1302V20.1182V20.1062V20.0942V20.0822V20.0702V20.0581V20.046V20.034V20.0219V20.0098V19.9977V19.9855V19.9734V19.9612V19.9491V19.9369V19.9247V19.9125V19.9003V19.888V19.8758V19.8635V19.8513V19.839V19.8267V19.8144V19.8021V19.7898V19.7775V19.7651V19.7528V19.7404V19.7281V19.7157V19.7033V19.6909V19.6785V19.6661V19.6537V19.6413V19.6288V19.6164V19.604V19.5915V19.579V19.5666V19.5541V19.5416V19.5291V19.5166V19.5041V19.4916V19.4791V19.4666V19.4541V19.4415V19.429V19.4165V19.4039V19.3914V19.3788V19.3663V19.3537V19.3411V19.3286V19.316V19.3034V19.2909V19.2783V19.2657V19.2531V19.2405V19.2279V19.2153V19.2027V19.1901V19.1776V19.165V19.1524V19.1398V19.1272V19.1146V19.102V19.0894V19.0768V19.0642V19.0516V19.039V19.0264V19.0138V19.0012V18.9886V18.976V18.9634V18.9508V18.9382V18.9256V18.913V18.9004V18.8879V18.8753V18.8627V18.8501V18.8376V18.825V18.8125V18.7999V18.7874V18.7748V18.7623V18.7497V18.7372V18.7247V18.7121V18.6996V18.6871V18.6746V18.6621V18.6496V18.6371V18.6246V18.6122V18.5997V18.5872V18.5748V18.5623V18.5499V18.5375V18.5251V18.5126V18.5002V18.4878V18.4754V18.4631V18.4507V18.4383V18.426V18.4136V18.4013V18.389V18.3767V18.3644V18.3521V18.3398V18.3275V18.3153V18.303V18.2908V18.2785V18.2663V18.2541V18.2419V18.2298V18.2176V18.2054V18.1933V18.1812V18.169V18.1569V18.1449V18.1328V18.1207V18.1087V18.0966V18.0846V18.0726V18.0606V18.0487V18.0367V18.0248V18.0128V18.0009V17.989V17.9771V17.9653V17.9534V17.9416V17.9298V17.918V17.9062V17.8944V17.8827V17.871V17.8592V17.8475V17.8359V17.8242V17.8126V17.801V17.7894V17.7778V17.7662V17.7547V17.7431V17.7316V17.7202V17.7087V17.6972V17.6858V17.6744V17.663V17.6517V17.6403V17.629V17.6177V17.6064V17.5952V17.584V17.5728V17.5616V17.5504V17.5393V17.5281V17.517V17.506V17.4949V17.4839V17.4729V17.4619V17.451V17.44C0.5 13.9046 3.48174 11.0067 7.2 11.0067C10.9183 11.0067 13.9 13.9046 13.9 17.44Z" + stroke="#2D2D2D" + /> + <path + d="M10.7281 6.68076C10.7281 8.76881 9.03541 10.4615 6.94736 10.4615C4.85932 10.4615 3.16663 8.76881 3.16663 6.68076C3.16663 4.59272 4.85932 2.90002 6.94736 2.90002C9.03541 2.90002 10.7281 4.59272 10.7281 6.68076Z" + stroke="#2D2D2D" + /> + </svg> + | Browser => + <svg> + <rect + x="0.5" + y="0.5" + width="23" + height="23" + rx="0.5" + stroke="#2D2D2D" + /> + <rect y="4.19995" width="24" height="1" fill="#2D2D2D" /> + <path + d="M18.1 14.1C18.1 17.6346 15.2347 20.5 11.7 20.5C8.16543 20.5 5.30005 17.6346 5.30005 14.1C5.30005 10.5653 8.16543 7.69995 11.7 7.69995C15.2347 7.69995 18.1 10.5653 18.1 14.1Z" + stroke="#2D2D2D" + /> + <rect + x="4.80005" + y="13.7999" + width="13.8" + height="1" + fill="#2D2D2D" + /> + <path + d="M14.5 14.1C14.5 15.9475 14.1408 17.5957 13.5824 18.7633C13.0065 19.9674 12.3081 20.5 11.7 20.5C11.0919 20.5 10.3936 19.9674 9.81764 18.7633C9.25923 17.5957 8.90002 15.9475 8.90002 14.1C8.90002 12.2524 9.25923 10.6042 9.81764 9.43664C10.3936 8.23246 11.0919 7.69995 11.7 7.69995C12.3081 7.69995 13.0065 8.23246 13.5824 9.43664C14.1408 10.6042 14.5 12.2524 14.5 14.1Z" + stroke="#2D2D2D" + /> + </svg> + | BurgerMenu => + <svg> + <rect + x="2.40002" + y="7.19995" + width="19.2" + height="1" + fill="#2D2D2D" + /> + <rect x="2.40002" y="11.4" width="19.2" height="1" fill="#2D2D2D" /> + <rect x="2.40002" y="15.6" width="19.2" height="1" fill="#2D2D2D" /> + </svg> + | CloseMenu => + <svg> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M12.2309 11.3823L7.44854 6.59998L6.74143 7.30708L11.5238 12.0894L6.71545 16.8978L7.42256 17.6049L12.2309 12.7965L16.9238 17.4894L17.6309 16.7823L12.938 12.0894L17.6049 7.42252L16.8978 6.71542L12.2309 11.3823Z" + fill="#2D2D2D" + /> + </svg> + | Box => + <svg> + <path + d="M12 3L3 6.375V17.625L12 21L21 17.625V6.375L12 3Z" + stroke="#2D2D2D" + /> + <path d="M3 6.375L12 9.75L21 6.375" stroke="#2D2D2D" /> + <path d="M12 9.75V21" stroke="#2D2D2D" /> + </svg> + }} + </svg>; +}; diff --git a/frontend/website-redesign/src/components/Image.re b/frontend/website-redesign/src/components/Image.re deleted file mode 100644 index 0a72d532554..00000000000 --- a/frontend/website-redesign/src/components/Image.re +++ /dev/null @@ -1,16 +0,0 @@ -[@react.component] -let make = (~className, ~name, ~alt) => { - <img - className - src={name ++ ".png"} - srcSet={ - (name ++ ".png") - ++ " 1x, " - ++ (name ++ "@2x.png") - ++ " 2x, " - ++ (name ++ "@3x.png") - ++ " 3x" - } - alt - />; -}; diff --git a/frontend/website-redesign/src/components/InclusiveSection.re b/frontend/website-redesign/src/components/InclusiveSection.re deleted file mode 100644 index 22affac6f69..00000000000 --- a/frontend/website-redesign/src/components/InclusiveSection.re +++ /dev/null @@ -1,224 +0,0 @@ -module Legend = { - module Square = { - [@react.component] - let make = (~className, ~borderColor, ~fillColor, ~dims) => { - let borderRule = - switch (borderColor) { - | None => [] - | Some(color) => [Css.border(`px(3), `solid, color)] - }; - - <div - className=Css.( - merge([ - className, - style([ - width(fst(dims)), - height(snd(dims)), - backgroundColor(fillColor), - ...borderRule, - ]), - ]) - ) - />; - }; - }; - - module SmallRow = { - [@react.component] - let make = (~themeColor, ~copy) => { - <div className=Css.(style([display(`flex), alignItems(`center)]))> - <Square - className=Css.( - style([ - marginRight(`rem(0.5)), - media(Theme.MediaQuery.notMobile, [marginRight(`rem(0.75))]), - ]) - ) - borderColor=None - fillColor=themeColor - dims=(`rem(1.0), `rem(1.0)) - /> - <h3 - className=Css.( - merge([ - Theme.H3.basic, - style([ - fontWeight(`medium), - marginTop(`zero), - marginBottom(`zero), - color(themeColor), - ]), - ]) - )> - {React.string(copy)} - </h3> - </div>; - }; - }; - - [@react.component] - let make = (~className) => { - <div - className=Css.( - merge([ - className, - style([ - justifyContent(`flexStart), - alignItems(`center), - media(Theme.MediaQuery.notMobile, [justifyContent(`center)]), - ]), - ]) - )> - <div - ariaHidden=true - className=Css.( - style([ - display(`flex), - marginTop(`zero), - marginBottom(`zero), - marginRight(`rem(1.0)), - media(Theme.MediaQuery.notMobile, [marginRight(`rem(2.25))]), - ]) - )> - <Square - className=Css.(style([marginRight(`rem(0.75))])) - borderColor={Some(Theme.Colors.clover)} - fillColor=Theme.Colors.lightClover - dims=(`rem(2.5), `rem(2.5)) - /> - <h5 - className=Css.( - merge([ - Theme.H5.tight, - style([ - width(`rem(8.0)), - marginTop(`zero), - marginBottom(`zero), - ]), - ]) - )> - {React.string("Consensus Participants")} - </h5> - </div> - <div ariaHidden=true> - <SmallRow themeColor=Theme.Colors.teal copy="Individuals" /> - <SmallRow themeColor=Theme.Colors.navy copy="Organizations" /> - </div> - </div>; - }; -}; - -module Figure = { - [@react.component] - let make = (~link, ~captionColor, ~dims, ~caption, ~alt) => { - let (w, h) = dims; - <figure - className=Css.( - style([ - marginTop(`rem(2.0)), - display(`flex), - flexDirection(`column), - alignItems(`center), - justifyContent(`center), - width(`rem(19.5)), - media(Theme.MediaQuery.notMobile, [width(`rem(20.625))]), - ]) - )> - <Svg - className=Css.( - style([ - // on mobile we want to square our figures with the height size - width(`rem(h)), - media(Theme.MediaQuery.notMobile, [width(`rem(w))]), - ]) - ) - dims - alt - link - /> - <figcaption - className=Css.( - merge([ - Theme.H3.basic, - style([ - marginTop(`rem(1.5)), - color(captionColor), - fontWeight(`medium), - textAlign(`center), - ]), - ]) - )> - {React.string(caption)} - </figcaption> - </figure>; - }; -}; - -let legendQuery = "(min-width: 68.8125rem)"; - -[@react.component] -let make = () => { - <div className=Css.(style([marginTop(`rem(2.5))]))> - <Title fontColor=Theme.Colors.denimTwo text="Inclusive consensus" /> - <Legend - className=Css.( - style([display(`none), media(legendQuery, [display(`flex)])]) - ) - /> - <div - className=Css.( - style([ - display(`flex), - justifyContent(`spaceBetween), - alignItems(`center), - flexWrap(`wrapReverse), - media(Theme.MediaQuery.notMobile, [justifyContent(`spaceAround)]), - ]) - )> - <Figure - link="/static/img/coda-figure.svg" - dims=(15.125, 15.125) - caption="Coda" - alt="Figure showing everyone participating in consensus, including individual users of Coda." - captionColor=Theme.Colors.clover - /> - <Figure - link="/static/img/other-blockchains-figure.svg" - dims=(CryptoAppsSection.middleElementWidthRems, 13.75) - caption="Other Blockchains" - alt="Figure showing few participants in consensus, most of which are organizations, rather than individuals." - captionColor=Theme.Colors.navy - /> - <div> - <div - className=Css.(style([display(`flex), justifyContent(`center)]))> - <SideText - paragraphs=[| - `styled([ - `emph( - "Simple, fair consensus designed so you can participate", - ), - `str( - ". Participation is proportional to how much stake you have in the protocol with no lockups, no forced delegation, and low bandwidth requirements.", - ), - ]), - `str( - "With just a small stake you'll be able to participate directly in consensus.", - ), - |] - /> - </div> - <Legend - className=Css.( - style([ - display(`flex), - marginTop(`rem(2.0)), - media(legendQuery, [display(`none)]), - ]) - ) - /> - </div> - </div> - </div>; -}; diff --git a/frontend/website-redesign/src/components/InvestorsSection.re b/frontend/website-redesign/src/components/InvestorsSection.re deleted file mode 100644 index 6bb923439ee..00000000000 --- a/frontend/website-redesign/src/components/InvestorsSection.re +++ /dev/null @@ -1,78 +0,0 @@ -let twoColumnMedia = "(min-width: 34rem)"; - -module Investor = { - [@react.component] - let make = (~name) => { - <div - className=Css.( - style([ - display(`flex), - alignItems(`center), - backgroundColor(Theme.Colors.greyishAlpha(1.0)), - height(`rem(1.75)), - marginRight(`rem(0.75)), - marginBottom(`rem(0.625)), - ]) - )> - <h4 - className=Css.( - merge([ - Theme.H3.Technical.title, - style(Theme.paddingX(`rem(0.1875))), - ]) - )> - {React.string(name)} - </h4> - </div>; - }; -}; - -[@react.component] -let make = () => { - <div className=Css.(style([display(`flex), flexDirection(`column)]))> - <h3 className=Theme.H3.Technical.boxed> - {React.string("O(1) Investors")} - </h3> - <div - className=Css.( - style([ - maxWidth(`rem(78.)), - display(`inlineFlex), - flexWrap(`wrap), - marginTop(`rem(3.)), - marginLeft(`auto), - marginRight(`auto), - justifyContent(`center), - ]) - )> - <Investor name="Metastable" /> - <Investor name="Accomplice" /> - <Investor name="Electric Capital" /> - <Investor name="Polychain Capital" /> - <Investor name="Paradigm" /> - <Investor name="Coinbase Ventures" /> - <Investor name="Dragonfly" /> - <Investor name="Dekrypt Capital" /> - <Investor name="Scifi vc" /> - <Investor name="libertus" /> - <Investor name="general catalyst" /> - <Investor name="multicoin capital" /> - <Investor name="collaborative fund" /> - <Investor name="kilowatt capital" /> - <Investor name="naval ravikant" /> - <Investor name="elad gil" /> - <Investor name="linda xie" /> - <Investor name="fred ehrsam" /> - <Investor name="jack herrick" /> - <Investor name="charlie noyes" /> - <Investor name="ed roman" /> - <Investor name="andrew keys" /> - <Investor name="kindred ventures" /> - <Investor name="curious endeavors" /> - <Investor name="blockchange" /> - <Investor name="ogroup" /> - <Investor name="nima capital" /> - <Investor name="evolve vc" /> - </div> - </div>; -}; diff --git a/frontend/website-redesign/src/components/Leaderboard.re b/frontend/website-redesign/src/components/Leaderboard.re deleted file mode 100644 index 24ba2c6b03c..00000000000 --- a/frontend/website-redesign/src/components/Leaderboard.re +++ /dev/null @@ -1,458 +0,0 @@ -type member = { - name: string, - genesisMember: bool, - phasePoints: int, - releasePoints: int, - allTimePoints: int, - releaseRank: int, - phaseRank: int, - allTimeRank: int, -}; - -type entry = array(string); - -external parseEntry: Js.Json.t => entry = "%identity"; - -let safeArrayGet = (index, a) => { - switch (Belt.Array.get(a, index)) { - | Some(v) => v - | None => "" - }; -}; - -let safeParseInt = str => - try(int_of_string(str)) { - | Failure(_) => 0 - }; - -let fetchLeaderboard = () => { - Sheets.fetchRange( - ~sheet="1Nq_Y76ALzSVJRhSFZZm4pfuGbPkZs2vTtCnVQ1ehujE", - ~range="Member_Profile_Data!A2:Z", - ) - |> Promise.map(res => { - Array.map(parseEntry, res) - |> Array.map(entry => { - { - name: entry |> safeArrayGet(0), - genesisMember: - entry |> safeArrayGet(1) |> String.length == 0 ? false : true, - allTimePoints: entry |> safeArrayGet(2) |> safeParseInt, - phasePoints: entry |> safeArrayGet(3) |> safeParseInt, - releasePoints: entry |> safeArrayGet(4) |> safeParseInt, - allTimeRank: entry |> safeArrayGet(5) |> safeParseInt, - phaseRank: entry |> safeArrayGet(6) |> safeParseInt, - releaseRank: entry |> safeArrayGet(7) |> safeParseInt, - } - }) - }) - |> Js.Promise.catch(_ => Promise.return([||])); -}; - -module Toggle = { - type t = - | All - | Genesis - | NonGenesis; - - let toggles = [|All, Genesis, NonGenesis|]; - - let toggle_of_string = toggle => { - switch (toggle) { - | "All Participants" => All - | "Genesis Members" => Genesis - | "Non-Genesis Members" => NonGenesis - | _ => All - }; - }; - - let string_of_toggle = toggle => { - switch (toggle) { - | All => "All Participants" - | Genesis => "Genesis Members" - | NonGenesis => "Non-Genesis Members" - }; - }; -}; - -module Filter = { - type t = - | Release - | Phase - | AllTime; - - let string_of_filter = filter => { - switch (filter) { - | Release => "This Release" - | Phase => "This Phase" - | AllTime => "All Time" - }; - }; - - let filter_of_string = filter => { - switch (filter) { - | "This Release" => Release - | "This Phase" => Phase - | "All Time" => AllTime - | _ => AllTime - }; - }; - - let filters = [|Release, Phase, AllTime|]; -}; - -module Styles = { - open Css; - - let leaderboardContainer = - style([ - width(`percent(100.)), - margin2(~v=`zero, ~h=`auto), - selector("hr", [margin(`zero)]), - ]); - - let leaderboard = - style([ - background(white), - width(`percent(100.)), - borderRadius(px(3)), - paddingTop(`rem(1.)), - Theme.Typeface.ibmplexsans, - fontSize(rem(1.5)), - lineHeight(rem(1.5)), - color(Theme.Colors.leaderboardMidnight), - selector( - "div:nth-child(even)", - [ - backgroundColor(`rgba((245, 245, 245, 1.))), - hover([backgroundColor(`hex("E0E0E0"))]), - ], - ), - ]); - - let desktopLeaderboardRow = - style([ - cursor(`pointer), - padding2(~v=`rem(1.), ~h=`rem(1.)), - height(`rem(3.5)), - display(`grid), - gridColumnGap(rem(1.5)), - gridTemplateColumns([ - rem(1.), - rem(5.5), - rem(5.5), - rem(3.5), - rem(3.5), - ]), - hover([backgroundColor(`hex("E0E0E0"))]), - media( - Theme.MediaQuery.tablet, - [ - width(`percent(100.)), - gridTemplateColumns([ - rem(3.5), - `auto, - rem(9.), - rem(8.), - rem(8.), - ]), - ], - ), - ]); - - let headerRow = - merge([ - desktopLeaderboardRow, - style([ - display(`none), - paddingBottom(`rem(0.5)), - fontSize(`rem(1.)), - fontWeight(`semiBold), - textTransform(`uppercase), - letterSpacing(`rem(0.125)), - media(Theme.MediaQuery.notMobile, [display(`grid)]), - hover([backgroundColor(white)]), - ]), - ]); - - let activeColumn = - style([ - position(`relative), - justifySelf(`flexEnd), - after([ - position(`absolute), - left(`percent(100.)), - contentRule(""), - height(`rem(1.5)), - width(`rem(1.5)), - backgroundImage(`url("/static/img/arrowDown.svg")), - backgroundRepeat(`noRepeat), - backgroundPosition(`px(4), `px(9)), - ]), - ]); - - let inactiveColumn = - style([ - display(`none), - justifySelf(`flexEnd), - media(Theme.MediaQuery.tablet, [display(`inline)]), - ]); - - let topTen = style([position(`absolute)]); - - let cell = - style([height(`rem(2.)), whiteSpace(`nowrap), overflowX(`hidden)]); - let flexEnd = style([justifySelf(`flexEnd)]); - let rank = merge([cell, flexEnd]); - let username = - merge([cell, style([textOverflow(`ellipsis), fontWeight(`semiBold)])]); - let pointsCell = merge([cell, style([justifySelf(`flexEnd)])]); - let activePointsCell = - merge([cell, style([justifySelf(`flexEnd), fontWeight(`semiBold)])]); - let inactivePointsCell = - merge([ - pointsCell, - style([ - media(Theme.MediaQuery.tablet, [display(`inline)]), - display(`none), - opacity(0.5), - ]), - ]); - - let loading = - style([ - padding(`rem(5.)), - color(Theme.Colors.leaderboardMidnight), - textAlign(`center), - ]); - - let desktopLayout = - style([ - display(`none), - media(Theme.MediaQuery.notMobile, [display(`unset)]), - ]); - - let mobileLayout = - style([ - display(`unset), - media(Theme.MediaQuery.notMobile, [display(`none)]), - ]); - - let mobileLeaderboardRow = - style([ - display(`grid), - gridTemplateColumns([rem(5.), `auto]), - gridColumnGap(rem(1.5)), - cursor(`pointer), - padding2(~v=`rem(1.), ~h=`rem(1.)), - fontWeight(`semiBold), - fontSize(`px(16)), - lineHeight(`px(24)), - ]); - - let firstColumn = style([textAlign(`right), color(`hex("757575"))]); - - let mobilePointStar = - merge([ - firstColumn, - style([ - before([ - contentRule("*"), - color(Css_Colors.red), - marginRight(`rem(0.5)), - ]), - ]), - ]); -}; - -module LeaderboardRow = { - open Filter; - let getRank = (sort, member) => { - switch (sort) { - | Phase => member.phaseRank - | Release => member.releaseRank - | AllTime => member.allTimeRank - }; - }; - - let getPoints = (column, member) => - switch (column) { - | Phase => member.phasePoints - | Release => member.releasePoints - | AllTime => member.allTimePoints - }; - - let renderPoints = (sort, column, member) => { - <span - key={member.name ++ string_of_filter(column)} - className=Styles.( - sort === column ? activePointsCell : inactivePointsCell - )> - {React.string(string_of_int(getPoints(column, member)))} - </span>; - }; - - let getUserSlug = member => { - "/memberProfile" - ++ "?allTimeRank=" - ++ member.allTimeRank->string_of_int - ++ "&allTimePoints=" - ++ member.allTimePoints->string_of_int - ++ "&phaseRank=" - ++ member.phaseRank->string_of_int - ++ "&phasePoints=" - ++ member.phasePoints->string_of_int - ++ "&releaseRank=" - ++ member.releaseRank->string_of_int - ++ "&releasePoints=" - ++ member.releasePoints->string_of_int - ++ "&genesisMember=" - ++ member.genesisMember->string_of_bool - ++ "&name=" - ++ member.name - |> Js.String.replaceByRe([%re "/#/g"], "%23"); /* replace "#" with percent encoding for the URL to properly parse */ - }; - - module DesktopLayout = { - [@react.component] - let make = (~sort, ~rank, ~member) => { - //<Next.Link href=""_as=userSlug> - <div className=Styles.desktopLeaderboardRow> - - <span className=Styles.rank> - {React.string(string_of_int(rank))} - </span> - <span className=Styles.username> {React.string(member.name)} </span> - {Array.map(column => {renderPoints(sort, column, member)}, filters) - |> React.array} - </div>; - // </Next.Link>; - }; - }; - - module MobileLayout = { - [@react.component] - let make = (~sort, ~rank, ~member) => { - //<Next.Link href=""_as=userSlug> - <div className=Styles.mobileLeaderboardRow> - - <span className=Styles.firstColumn> {React.string("Rank")} </span> - <span> {React.string("#" ++ string_of_int(rank))} </span> - <span className=Styles.firstColumn> {React.string("Name")} </span> - <span> {React.string(member.name)} </span> - <span className=Styles.mobilePointStar> - {React.string("Points")} - </span> - <span> - {React.string(string_of_int(getPoints(sort, member)))} - </span> - </div>; - //</Next.Link>; - }; - }; - - [@react.component] - let make = (~sort, ~member) => { - let _userSlug = getUserSlug(member); - let rank = getRank(sort, member); - - <div> - <div className=Styles.desktopLayout> - <DesktopLayout sort rank member /> - </div> - <div className=Styles.mobileLayout> - <MobileLayout sort rank member /> - </div> - </div>; - }; -}; - -type state = { - loading: bool, - members: array(member), -}; - -type actions = - | UpdateMembers(array(member)); - -let reducer = (_, action) => { - switch (action) { - | UpdateMembers(members) => {loading: false, members} - }; -}; - -[@react.component] -let make = - ( - ~filter: Filter.t=Release, - ~toggle: Toggle.t=All, - ~search: string="", - ~onFilterPress: string => unit=?, - ) => { - open Toggle; - open Filter; - let initialState = {loading: true, members: [||]}; - let (state, dispatch) = React.useReducer(reducer, initialState); - - React.useEffect0(() => { - fetchLeaderboard() |> Promise.iter(e => dispatch(UpdateMembers(e))); - None; - }); - - let sortRank = member => - switch (filter) { - | Phase => member.phaseRank - | Release => member.releaseRank - | AllTime => member.allTimeRank - }; - - Array.sort((a, b) => sortRank(a) - sortRank(b), state.members); - - let filteredMembers = - Js.Array.filter( - member => - switch (toggle) { - | All => true - | Genesis => member.genesisMember - | NonGenesis => !member.genesisMember - }, - state.members, - ) - |> Js.Array.filter(member => - search === "" - ? true - : Js.String.includes( - String.lowercase_ascii(search), - String.lowercase_ascii(member.name), - ) - ) - |> Js.Array.filter(member => sortRank(member) !== 0); - - let renderRow = member => - <LeaderboardRow key={member.name} sort=filter member />; - - let renderColumnHeader = column => - <span - key={Filter.string_of_filter(column)} - onClick={_ => {onFilterPress(string_of_filter(column))}} - className={ - column === filter ? Styles.activeColumn : Styles.inactiveColumn - }> - {React.string(string_of_filter(column))} - </span>; - - <div className=Styles.leaderboardContainer> - <div id="testnet-leaderboard" className=Styles.leaderboard> - <div className=Styles.headerRow> - <span className=Styles.flexEnd> {React.string("Rank")} </span> - <span> {React.string("Name")} </span> - {Array.map(renderColumnHeader, Filter.filters) |> React.array} - </div> - <hr /> - <div className=Styles.topTen /> - {state.loading - ? <div className=Styles.loading> {React.string("Loading...")} </div> - : Array.map(renderRow, filteredMembers) |> React.array} - </div> - </div>; -}; diff --git a/frontend/website-redesign/src/components/Markdown.re b/frontend/website-redesign/src/components/Markdown.re deleted file mode 100644 index 9c1433849fe..00000000000 --- a/frontend/website-redesign/src/components/Markdown.re +++ /dev/null @@ -1,36 +0,0 @@ -// Remove cloneElement once https://github.com/reasonml/reason-react/pull/469 is merged -let katexStylesheet = { - ReasonReact.cloneElement( - <link - rel="stylesheet" - href="https://cdn.jsdelivr.net/npm/katex@0.11.0/dist/katex.min.css" - integrity="sha384-BdGj8xC2eZkQaxoQ8nSLefg4AV4/AwB3Fj+8SUSo7pnKP6Eoy18liIKTPn9oBYNG" - />, - ~props={"crossOrigin": "anonymous"}, - [||], - ); -}; - -// We need an uncurried reference to createElement for rehype2react -[@bs.module "react"] -external createElement: (. React.component('props), 'props) => React.element = - "createElement"; - -[@react.component] -let make = (~content) => { - open Unified.Transformers; - let result = - Unified.create() - ->Unified.use(markdown, {"footnotes": true}) - ->Unified.use(math, ()) - ->Unified.use(remarkRehype, {"allowDangerousHTML": true}) - ->Unified.use(rehypeRaw, ()) - ->Unified.use(katex, ()) - ->Unified.use( - rehypeReact, - {"createElement": createElement, "Fragment": ReasonReact.fragment}, - ) - ->Unified.processSync(~content); - - result.contents; -}; diff --git a/frontend/website-redesign/src/components/MemberProfile.re b/frontend/website-redesign/src/components/MemberProfile.re deleted file mode 100644 index bac4144407b..00000000000 --- a/frontend/website-redesign/src/components/MemberProfile.re +++ /dev/null @@ -1,168 +0,0 @@ -module Styles = { - open Css; - let outerBox = - style([ - display(`flex), - justifyContent(`center), - alignContent(`center), - ]); - let container = - style([ - position(`relative), - display(`flex), - paddingBottom(`rem(3.)), - justifyContent(`center), - alignContent(`center), - width(`rem(21.25)), - height(`rem(31.5)), - borderRadius(`px(6)), - background(`hex("F5F5F5")), - border(`px(1), `solid, Theme.Colors.teal), - ]); - let innerFlex = style([display(`flex), flexDirection(`column)]); - let info = - style([ - display(`flex), - height(`rem(29.375)), - justifyContent(`spaceBetween), - flexDirection(`column), - ]); - let profilePic = - style([ - position(`absolute), - borderRadius(`percent(50.)), - background(white), - marginTop(`rem(-3.)), - border(`px(1), `solid, Theme.Colors.saville), - padding(`px(5)), - height(`rem(6.25)), - width(`rem(6.25)), - ]); - let memberName = - style([ - height(`px(32)), - marginTop(`px(62)), - display(`flex), - alignItems(`center), - margin3(~top=`rem(4.6), ~h=`auto, ~bottom=`zero), - ]); - let icon = - style([paddingTop(`px(2)), height(`auto), alignSelf(`center)]); - let genesisLabel = - style([ - margin2(~v=`rem(0.6875), ~h=`auto), - borderRadius(`px(4)), - background(`hex("757575")), - Theme.Typeface.ibmplexsans, - fontSize(`rem(0.68)), - textTransform(`uppercase), - letterSpacing(`px(1)), - lineHeight(`rem(1.)), - color(white), - height(`rem(1.)), - width(`rem(12.0)), - padding2(~h=`rem(0.5), ~v=`zero), - ]); - let quote = - merge([ - Theme.Body.basic, - style([margin2(~v=`zero, ~h=`rem(1.5)), alignSelf(`center)]), - ]); - let socials = - style([ - display(`flex), - justifyContent(`spaceAround), - flexDirection(`column), - margin2(~v=`zero, ~h=`auto), - selector("> :last-child", [marginBottom(`zero)]), - ]); - let socialTag = - style([ - display(`flex), - alignItems(`center), - marginBottom(`rem(0.5)), - selector("p", [marginTop(`zero), marginBottom(`zero)]), - ]); - - let ctaButton = - merge([ - Theme.Body.basic_semibold, - style([ - width(`rem(14.)), - height(`rem(3.)), - backgroundColor(Theme.Colors.hyperlink), - borderRadius(`px(6)), - textDecoration(`none), - color(white), - padding2(~v=`px(12), ~h=`px(24)), - textAlign(`center), - alignSelf(`center), - hover([backgroundColor(Theme.Colors.hyperlinkHover)]), - ]), - ]); - - let link = - merge([ - Theme.Body.basic_small, - style([ - textDecoration(`none), - hover([color(Theme.Colors.hyperlinkHover)]), - ]), - ]); -}; -[@react.component] -let make = (~name, ~photo, ~quote, ~location, ~twitter, ~github, ~blogPost) => { - <div className=Styles.outerBox> - <div className=Styles.container> - <img src=photo alt=name className=Styles.profilePic /> - <div className=Styles.innerFlex> - <span className=Styles.memberName> - <img src="/static/img/Icon.Discord.svg" className=Styles.icon /> - <Spacer width=0.31 /> - <h4 className=Theme.H4.header> {React.string(name)} </h4> - </span> - <p className=Styles.genesisLabel> - {React.string("Genesis Founding Member")} - </p> - <span className=Styles.info> - <p className=Styles.quote> {React.string(quote)} </p> - <div className=Styles.socials> - <div className=Styles.socialTag> - <img src="/static/img/Location.svg" /> - <Spacer width=0.34 /> - <p className=Theme.Body.basic_small> - {React.string(location)} - </p> - </div> - <div className=Styles.socialTag> - <img src="/static/img/Icon.Twitter.svg" /> - <Spacer width=0.34 /> - <a - href={"https://twitter.com/" ++ twitter} className=Styles.link> - {React.string(twitter)} - </a> - </div> - {switch (github) { - | Some(github) => - <div className=Styles.socialTag> - <img src="/static/img/Icon.Git.svg" /> - <Spacer width=0.34 /> - <a - href={"https://github.com/" ++ github} - className=Styles.link> - {React.string(github)} - </a> - </div> - | _ => React.null - }} - </div> - <Next.Link href="/blog/[slug]" _as={"/blog/" ++ blogPost}> - <a className=Styles.ctaButton> - {React.string({js|Learn More|js})} - </a> - </Next.Link> - </span> - </div> - </div> - </div>; -}; diff --git a/frontend/website-redesign/src/components/Nav.re b/frontend/website-redesign/src/components/Nav.re deleted file mode 100644 index 55610e1a725..00000000000 --- a/frontend/website-redesign/src/components/Nav.re +++ /dev/null @@ -1,374 +0,0 @@ -// Nav styles adapted from https://medium.com/creative-technology-concepts-code/responsive-mobile-dropdown-navigation-using-css-only-7218e4498a99 - -module Style = { - open Css; - open Theme; - - module MediaQuery = { - let menu = "(min-width: 62rem)"; - let menuMax = "(max-width: 61.9375rem)"; - }; - let bottomNudge = Css.marginBottom(`rem(2.0)); - let bottomNudgeOffset = offset => Css.marginBottom(`rem(2.0 -. offset)); - - let collapsedMenuItems = - style([ - marginTop(`zero), - marginBottom(`zero), - display(`none), - // when it's not hidden, make the dropdown appear - position(`absolute), - right(`rem(1.0)), - top(`rem(0.0)), - backgroundColor(Colors.white), - // always visible and flexed on full - media( - MediaQuery.menu, - [ - display(`flex), - justifyContent(`spaceBetween), - position(`static), - alignItems(`center), - width(`percent(100.0)), - ], - ), - ]); - - let triangle = (c, offset) => [ - unsafe("content", ""), - width(`zero), - height(`zero), - position(`absolute), - borderLeft(`px(4 + offset), `solid, c), - borderRight(`px(4 + offset), `solid, transparent), - borderTop(`px(4 + offset), `solid, c), - borderBottom(`px(4 + offset), `solid, transparent), - right(`px(15 - offset)), - top(`px((-3) - offset)), - transforms([`rotate(`deg(45.))]), - media(MediaQuery.menu, [display(`none)]), - ]; - - let expandedMenuBorderColor = Theme.Colors.hyperlinkLight; - let expandedMenuItems = - merge([ - collapsedMenuItems, - style([ - media( - // Make expanded menu not show up on a wide screen - MediaQuery.menuMax, - Theme.paddingY(`rem(0.3)) - @ [ - border(`px(1), `solid, expandedMenuBorderColor), - boxShadow( - ~x=`zero, - ~y=`zero, - ~blur=`px(12), - ~spread=`zero, - `rgba((0, 0, 0, 0.12)), - ), - borderRadius(`px(10)), - marginTop(`zero), - marginRight(`rem(-0.6)), - display(`flex), - maxWidth(`rem(10.)), - flexDirection(`column), - alignItems(`flexStart), - position(`absolute), - before( - triangle(expandedMenuBorderColor, 1) - @ [ - boxShadow( - ~x=`zero, - ~y=`zero, - ~blur=`px(12), - ~spread=`zero, - `rgba((0, 0, 0, 0.12)), - ), - zIndex(-1), - ], - ), - after(triangle(white, 0) @ [zIndex(1)]), - ], - ), - ]), - ]); - - let menuToggleButton = - merge([ - Theme.Link.basic, - style( - Theme.paddingY(`rem(0.5)) - @ [ - marginLeft(`rem(1.0)), - border(`zero, `solid, `transparent), - cursor(`pointer), - display(`flex), - justifyContent(`flexEnd), - position(`relative), - userSelect(`none), - backgroundColor(`transparent), - outline(`zero, `none, `transparent), - focus([color(Theme.Colors.hyperlinkHover)]), - // The menu is always shown on full-size - media(MediaQuery.menu, [display(`none)]), - ], - ), - ]); -}; - -module DropdownMenu = { - [@react.component] - let make = (~children) => { - let (menuOpen, toggleMenu) = React.useState(() => false); - <> - <button - className=Style.menuToggleButton - id="nav-menu-btn" - onClick={_ => toggleMenu(_ => !menuOpen)}> - {React.string("Menu")} - </button> - <div className=Css.(style([zIndex(1), position(`relative)]))> - <ul - id="nav-menu" - className={ - menuOpen ? Style.expandedMenuItems : Style.collapsedMenuItems - }> - children - </ul> - </div> - </>; - }; -}; - -// TODO Please fix these styles so we don't need to mapi... -module NavWrapper = { - [@react.component] - let make = (~keepAnnouncementBar, ~children) => { - let items = - children - |> Array.mapi((idx, elem) => - if (idx == Array.length(children) - 1) { - <li - className={Css.style([ - Css.paddingLeft(`rem(0.75)), // we need to skip padding right here as it's on the edge - Css.listStyle(`none, `inside, `none), - Css.media( - Style.MediaQuery.menuMax, - [Css.width(`percent(100.)), Css.padding(`zero)], - ), - ])}> - elem - </li>; - } else { - <> - <li - className={Css.style( - Theme.paddingX(`rem(0.75)) - @ Theme.paddingY(`rem(0.5)) - @ [ - Css.listStyle(`none, `inside, `none), - Css.media( - Style.MediaQuery.menuMax, - [Css.width(`percent(100.)), Css.padding(`zero)], - ), - ], - )}> - elem - </li> - <hr - ariaHidden=true - className=Css.( - style([ - borderTop( - `rem(0.0625), - `solid, - Theme.Colors.hyperlinkAlpha(0.15), - ), - marginTop(`zero), - marginBottom(`zero), - borderBottomWidth(`zero), - borderLeftWidth(`zero), - borderRightWidth(`zero), - width(`percent(85.)), - media(Style.MediaQuery.menu, [display(`none)]), - ]) - ) - /> - </>; - } - ) - |> ReactExt.staticArray; - - <nav - className=Css.( - style([ - display(`flex), - justifyContent(`spaceBetween), - alignItems(`flexEnd), - flexWrap(`wrap), - padding2(~v=`zero, ~h=`rem(1.25)), - marginTop(`rem(2.0)), - media( - Theme.MediaQuery.notMobile, - [padding2(~v=`zero, ~h=`rem(3.)), marginTop(`rem(2.0))], - ), - media( - Theme.MediaQuery.full, - [maxWidth(`rem(89.)), marginLeft(`auto), marginRight(`auto)], - ), - media( - Theme.MediaQuery.statusLift(keepAnnouncementBar), - [flexWrap(`nowrap), alignItems(`center)], - ), - ]) - )> - <Next.Link href="/"> - <a - className=Css.( - style([ - display(`flex), - Style.bottomNudge, - width(`percent(50.0)), - marginTop(`zero), - media( - Theme.MediaQuery.statusLift(keepAnnouncementBar), - [ - width(`auto), - marginRight(`rem(0.75)), - marginTop(`zero), - Style.bottomNudgeOffset(0.1875), - ], - ), - media(Style.MediaQuery.menu, [marginTop(`zero)]), - ]) - )> - <Image className="" name="/static/img/coda-logo" alt="Coda Home" /> - </a> - </Next.Link> - <div - className=Css.( - style([ - order(3), - width(`percent(100.0)), - Style.bottomNudge, - display(`none), // just hide when status lift happens - media( - Theme.MediaQuery.statusLift(keepAnnouncementBar), - [ - order(2), - width(`auto), - marginLeft(`zero), - ...keepAnnouncementBar - ? [display(`block)] : [display(`none)], - ], - ), - media(Style.MediaQuery.menu, [width(`percent(40.0))]), - ]) - )> - <div - className=Css.( - style([ - width(`rem(22.25)), - media( - Theme.MediaQuery.statusLift(keepAnnouncementBar), - [width(`rem(22.25)), margin(`auto)], - ), - ]) - )> - <AnnouncementBar /> - </div> - </div> - <div - className=Css.( - style([ - position(`relative), - width(`auto), - maxWidth(px(500)), - order(2), - Style.bottomNudgeOffset(0.5), - media( - Theme.MediaQuery.statusLift(keepAnnouncementBar), - [order(3), width(`auto), Style.bottomNudge], - ), - media(Style.MediaQuery.menu, [width(`percent(50.0))]), - ]) - )> - <DropdownMenu> items </DropdownMenu> - </div> - </nav>; - }; -}; - -let menuStyle = - Theme.paddingX(`rem(1.8)) - @ Theme.paddingY(`rem(0.5)) - @ Css.[ - height(`auto), - margin(`zero), - borderWidth(`zero), - Theme.Typeface.ibmplexsans, - color(Theme.Colors.saville), - fontSize(`rem(1.0)), - lineHeight(`rem(1.5)), - fontWeight(`medium), - letterSpacing(`rem(0.)), - fontStyle(`normal), - display(`block), - width(`percent(100.)), - textTransform(`none), - outline(`zero, `none, `transparent), - focus([color(Theme.Colors.hyperlink)]), - hover([backgroundColor(`transparent), color(Theme.Colors.hyperlink)]), - ]; - -module SimpleButton = { - open Theme; - - [@react.component] - let make = (~name, ~link, ~target="_self") => { - let router = Next.Router.useRouter(); - let currentSlug = Js.String.split("/", router.route); - let isActive = { - switch (currentSlug[1]) { - | first => link == "/" ++ first - | exception Not_found => false - }; - }; - - <Next.Link href=link> - <a - target - className=Css.( - merge([ - Body.basic, - style( - Theme.paddingY(`rem(0.75)) - @ [ - margin(`zero), - textDecoration(`none), - whiteSpace(`nowrap), - hover([color(Theme.Colors.hyperlink)]), - isActive ? color(Colors.hyperlink) : color(Colors.saville), - media(Style.MediaQuery.menuMax, menuStyle), - ], - ), - ]) - )> - {React.string(name)} - </a> - </Next.Link>; - }; -}; - -[@react.component] -let make = () => { - <NavWrapper keepAnnouncementBar=true> - [| - <SimpleButton name="Docs" link="/docs" />, - <SimpleButton name="Blog" link="/blog" />, - <SimpleButton name="Careers" link="/jobs" />, - <SimpleButton name="Testnet" link="/testnet" />, - |] - </NavWrapper>; -}; diff --git a/frontend/website-redesign/src/components/NewsletterWidget.re b/frontend/website-redesign/src/components/NewsletterWidget.re deleted file mode 100644 index 240a6b448fc..00000000000 --- a/frontend/website-redesign/src/components/NewsletterWidget.re +++ /dev/null @@ -1,141 +0,0 @@ -module Styles = { - open Css; - - let container = - merge([ - Theme.Body.basic_semibold, - style([ - position(`relative), - width(`percent(100.)), - fontWeight(`normal), - media(Theme.MediaQuery.notMobile, [width(`auto)]), - ]), - ]); - - let successMessage = - style([ - display(`flex), - alignItems(`center), - justifyContent(`center), - position(`absolute), - bottom(`zero), - left(`zero), - height(px(40)), - width(px(400)), - background(white), - border(px(1), `solid, Theme.Colors.jungle), - color(Theme.Colors.jungle), - borderRadius(px(4)), - transition("all", ~duration=150), - ]); - - let textField = - style([ - display(`inlineFlex), - alignItems(`center), - height(px(40)), - borderRadius(px(4)), - width(`percent(100.)), - fontSize(rem(1.)), - color(Theme.Colors.teal), - padding(px(12)), - border(px(1), `solid, Theme.Colors.hyperlinkAlpha(0.3)), - active([ - outline(px(0), `solid, `transparent), - padding(px(11)), - borderWidth(px(2)), - borderColor(Theme.Colors.hyperlinkAlpha(1.)), - ]), - focus([ - outline(px(0), `solid, `transparent), - padding(px(11)), - borderWidth(px(2)), - borderColor(Theme.Colors.hyperlinkAlpha(1.)), - ]), - hover([borderColor(Theme.Colors.hyperlinkAlpha(1.))]), - media(Theme.MediaQuery.notMobile, [width(px(272))]), - ]); - - let submit = - style([ - display(`inlineFlex), - alignItems(`center), - justifyContent(`center), - color(white), - backgroundColor(Theme.Colors.clover), - border(px(0), `solid, `transparent), - marginTop(`rem(0.5)), - marginLeft(`zero), - height(px(40)), - width(px(120)), - fontWeight(`semiBold), - fontSize(`percent(100.)), - borderRadius(px(4)), - cursor(`pointer), - unsafe("WebkitAppearance", "none"), - active([outline(px(0), `solid, `transparent)]), - focus([outline(px(0), `solid, `transparent)]), - hover([backgroundColor(Theme.Colors.jungle)]), - disabled([backgroundColor(Theme.Colors.slateAlpha(0.3))]), - media( - Theme.MediaQuery.notMobile, - [marginLeft(`rem(0.5)), marginTop(`zero)], - ), - ]); -}; - -[@bs.new] -external urlSearchParams: Js.t('a) => Fetch.urlSearchParams = - "URLSearchParams"; - -[@react.component] -let make = (~center as centerText=false) => { - let (successState, showSuccess) = React.useState(() => false); - let (email, setEmail) = React.useState(() => ""); - - <form - className=Styles.container - onSubmit={e => { - ReactEvent.Form.preventDefault(e); - ReFetch.fetch( - "https://jfs501bgik.execute-api.us-east-2.amazonaws.com/dev/subscribe", - ~method_=Post, - ~body= - Fetch.BodyInit.makeWithUrlSearchParams( - urlSearchParams({"email": email}), - ), - ~mode=NoCORS, - ) - |> Promise.iter(_ => { - showSuccess(_ => true); - ignore @@ Js.Global.setTimeout(() => showSuccess(_ => false), 5000); - }); - }}> - <div - className=Css.( - style([ - marginBottom(px(8)), - textAlign(centerText ? `center : `left), - ]) - )> - {React.string("Subscribe to our newsletter for updates")} - </div> - {successState - ? <div className=Styles.successMessage> - {React.string({js|✓ Check your email|js})} - </div> - : <> - <input - type_="email" - value=email - placeholder="janedoe@example.com" - onChange={e => { - let value = ReactEvent.Form.target(e)##value; - setEmail(_ => value); - }} - className=Styles.textField - /> - <input type_="submit" value="Subscribe" className=Styles.submit /> - </>} - </form>; -}; diff --git a/frontend/website-redesign/src/components/Page.re b/frontend/website-redesign/src/components/Page.re index 8201028640c..5c1d3e01c5f 100644 --- a/frontend/website-redesign/src/components/Page.re +++ b/frontend/website-redesign/src/components/Page.re @@ -1,128 +1,3 @@ -module Footer = { - module Link = { - let footerStyle = - Css.( - style([ - Theme.Typeface.ibmplexsans, - color(Theme.Colors.slate), - textDecoration(`none), - display(`inline), - hover([color(Theme.Colors.hyperlink)]), - fontSize(`rem(1.0)), - fontWeight(`light), - lineHeight(`rem(1.56)), - ]) - ); - [@react.component] - let make = (~last=false, ~link, ~name, ~children) => { - <li className=Css.(style([display(`inline)]))> - <a - href=link - className=footerStyle - name={"footer-" ++ name} - target="_blank"> - children - </a> - {last - ? React.null - : <span className=footerStyle ariaHidden=true> - {React.string({js| · |js})} - </span>} - </li>; - }; - }; - - [@react.component] - let make = (~bgcolor) => { - <footer className=Css.(style([backgroundColor(bgcolor)]))> - <section - className=Css.( - style( - [ - maxWidth(`rem(96.0)), - marginLeft(`auto), - marginRight(`auto), - // Not using Theme.paddingY here because we need the background - // color the same (so can't use margin), but we also need some - // top spacing. - paddingTop(`rem(4.75)), - paddingBottom(`rem(2.)), - ] - @ Theme.paddingX(`rem(4.0)), - ) - )> - <div - className=Css.( - style([ - display(`flex), - justifyContent(`center), - textAlign(`center), - marginBottom(`rem(2.0)), - ]) - )> - <ul - className=Css.( - style([listStyleType(`none), ...Theme.paddingX(`zero)]) - )> - <Link link="mailto:contact@o1labs.org" name="mail"> - {React.string("contact@o1labs.org")} - </Link> - <Link link="https://o1labs.org" name="o1www"> - {React.string("o1labs.org")} - </Link> - <Link - link="https://github.com/CodaProtocol/coda-grants" name="grants"> - {React.string("Project Grants")} - </Link> - <Link link="https://twitter.com/codaprotocol" name="twitter"> - {React.string("Twitter")} - </Link> - <Link link="https://github.com/CodaProtocol/coda" name="github"> - {React.string("GitHub")} - </Link> - <Link link="https://codawiki.com" name="wiki"> - {React.string("Community Wiki")} - </Link> - <Link link="https://forums.codaprotocol.com" name="discourse"> - {React.string("Discourse")} - </Link> - <Link link="https://reddit.com/r/coda" name="reddit"> - {React.string("Reddit")} - </Link> - <Link link="https://t.me/codaprotocol" name="telegram"> - {React.string("Telegram")} - </Link> - <Link link="/tos" name="tos"> - {React.string("Terms of service")} - </Link> - <Link link="/privacy" name="privacy"> - {React.string("Privacy Policy")} - </Link> - <Link link="/jobs" name="hiring"> - {React.string("We're Hiring")} - </Link> - <Link - link="https://s3.us-east-2.amazonaws.com/static.o1test.net/presskit.zip" - name="presskit" - last=true> - {React.string("Press Kit")} - </Link> - </ul> - </div> - <p - className=Css.( - merge([ - Theme.Body.small, - style([textAlign(`center), color(Theme.Colors.saville)]), - ]) - )> - {React.string({j|© 2020 O(1) Labs|j})} - </p> - </section> - </footer>; - }; -}; - let siteDescription = "Coda is the first cryptocurrency with a succinct blockchain. Our lightweight blockchain means anyone can use Coda directly from any device, in less data than a few tweets."; [@react.component] @@ -172,9 +47,7 @@ let make = {React.string("img:-moz-loading { visibility: hidden; }")} </style> </Next.Head> - <Nav /> <div> children </div> - <Footer bgcolor=footerColor /> <CookieWarning /> </>; }; diff --git a/frontend/website-redesign/src/components/ProfileHero.re b/frontend/website-redesign/src/components/ProfileHero.re deleted file mode 100644 index f3295158339..00000000000 --- a/frontend/website-redesign/src/components/ProfileHero.re +++ /dev/null @@ -1,306 +0,0 @@ -module Styles = { - open Css; - let linkRow = - style([ - media(Theme.MediaQuery.veryVeryLarge, [marginTop(`rem(4.8))]), - ]); - let header = - merge([ - Theme.H1.basic, - style([ - fontSize(`rem(1.5)), - lineHeight(`rem(2.)), - marginBottom(`rem(0.)), - media( - Theme.MediaQuery.notMobile, - [fontSize(`rem(3.)), lineHeight(`rem(3.))], - ), - ]), - ]); - let links = - merge([ - Theme.Link.basic, - style([fontSize(`rem(1.5)), color(Theme.Colors.saville)]), - ]); - let icon = - style([ - margin2(~v=`zero, ~h=`px(4)), - position(`relative), - top(`px(1)), - ]); - let heroRight = - style([ - display(`flex), - position(`relative), - top(`zero), - flexDirection(`column), - paddingLeft(`rem(1.)), - alignItems(`center), - unsafe("width", "fit-content"), - media( - Theme.MediaQuery.tablet, - [paddingLeft(`zero), marginBottom(`rem(3.)), alignItems(`center)], - ), - ]); - let link = merge([Theme.Link.basic, style([lineHeight(`px(28))])]); - let participantDetails = - merge([ - Theme.Body.basic_semibold, - style([ - display(`none), - media( - Theme.MediaQuery.notMobile, - [display(`inlineBlock), color(Theme.Colors.saville)], - ), - ]), - ]); - - let flexColumn = style([display(`flex), flexDirection(`column)]); - let middleRow = - style([ - display(`flex), - flexDirection(`column), - media( - Theme.MediaQuery.notMobile, - [justifyContent(`spaceBetween), marginTop(`rem(5.))], - ), - media( - Theme.MediaQuery.veryVeryLarge, - [flexDirection(`row), marginTop(`rem(4.8)), width(`rem(75.))], - ), - ]); - let buttonAndLinks = - merge([ - flexColumn, - style([ - marginTop(`rem(3.)), - justifyContent(`spaceBetween), - media( - Theme.MediaQuery.notMobile, - [ - marginLeft(`auto), - marginRight(`auto), - marginTop(`rem(5.25)), - flexDirection(`row), - width(`rem(35.)), - ], - ), - media( - Theme.MediaQuery.veryVeryLarge, - [ - flexDirection(`column), - marginTop(`zero), - marginRight(`zero), - width(`rem(18.75)), - ], - ), - ]), - ]); - let linksColumn = - merge([ - flexColumn, - style([ - position(`relative), - marginTop(`rem(2.)), - left(`rem(2.0)), - width(`rem(18.)), - media(Theme.MediaQuery.notMobile, [marginTop(`zero)]), - media( - Theme.MediaQuery.veryVeryLarge, - [position(`unset), marginTop(`rem(2.))], - ), - ]), - ]); -}; - -module Links = { - [@react.component] - let make = () => { - <div className=Styles.buttonAndLinks> - <Button - link="" - label="Current Challenges" - bgColor=Theme.Colors.clover - bgColorHover=Theme.Colors.jungle - /> - <div className=Styles.linksColumn> - <Next.Link href=""> - <a className=Styles.link> - <Svg - link="/static/img/Icon.Link.svg" - dims=(1.0, 1.0) - className=Styles.icon - alt="an arrow pointing to the right with a square around it" - /> - {React.string("Leaderboard FAQ")} - </a> - </Next.Link> - <Next.Link href=""> - <a className=Styles.link> - <Svg - link="/static/img/Icon.Link.svg" - dims=(0.9425, 0.8725) - className=Styles.icon - alt="an arrow pointing to the right with a square around it" - /> - {React.string("Discord #Leaderboard Channel")} - </a> - </Next.Link> - </div> - </div>; - }; -}; - -module Points = { - module Styles = { - open Css; - let pointsColumn = style([display(`flex), flexDirection(`column)]); - let flexColumn = pointsColumn; - let rankAndPoints = - style([ - display(`flex), - flexDirection(`row), - marginTop(`rem(1.3)), - justifyContent(`spaceBetween), - width(`rem(12.5)), - ]); - - let pointsRow = - style([ - display(`flex), - flexDirection(`row), - justifyContent(`center), - marginTop(`rem(6.)), - selector( - "> :last-child", - [ - display(`none), - media(Theme.MediaQuery.notMobile, [display(`inlineBlock)]), - ], - ), - selector( - "> :first-child", - [ - display(`none), - media(Theme.MediaQuery.notMobile, [display(`inlineBlock)]), - ], - ), - media( - Theme.MediaQuery.notMobile, - [ - width(`rem(51.)), - justifyContent(`spaceBetween), - marginTop(`zero), - ], - ), - media( - Theme.MediaQuery.veryVeryLarge, - [width(`rem(46.5)), justifyContent(`spaceBetween)], - ), - ]); - let linkRow = - merge([ - pointsRow, - style([ - marginBottom(`rem(4.75)), - marginTop(`rem(1.3)), - media(Theme.MediaQuery.notMobile, [marginTop(`rem(5.))]), - media(Theme.MediaQuery.veryVeryLarge, [marginTop(`zero)]), - ]), - ]); - let pointType = - merge([ - Theme.H4.header, - style([ - display(`block), - position(`relative), - top(`px(5)), - textAlign(`center), - ]), - ]); - let rank = - merge([ - Theme.H6.extraSmall, - style([ - textTransform(`uppercase), - color(Theme.Colors.saville), - fontSize(`rem(1.)), - lineHeight(`rem(1.5)), - ]), - ]); - let points = merge([flexColumn, style([marginLeft(`rem(2.))])]); - let value = - merge([ - Theme.H3.basic, - style([ - fontSize(`rem(2.25)), - fontWeight(`semiBold), - color(Theme.Colors.saville), - marginTop(`px(10)), - ]), - ]); - }; - - module PointsColumn = { - [@react.component] - let make = (~pointType, ~rank, ~points) => { - <div className=Styles.pointsColumn> - <span className=Styles.pointType> {React.string(pointType)} </span> - <div className=Styles.rankAndPoints> - <span className=Styles.pointsColumn> - <span className=Styles.rank> {React.string("Rank")} </span> - <span className=Styles.value> {React.string(rank)} </span> - </span> - <div className=Styles.points> - <span className=Styles.rank> {React.string("Points *")} </span> - <span className=Styles.value> {React.string(points)} </span> - </div> - </div> - </div>; - }; - }; - - let parsePointOrRank = n => { - n == 0 ? "N/A" : string_of_int(n); - }; - - [@react.component] - let make = (~member: Leaderboard.member) => { - <div className=Styles.pointsRow> - <PointsColumn - pointType="This Release" - rank={parsePointOrRank(member.releaseRank)} - points={parsePointOrRank(member.releasePoints)} - /> - <PointsColumn - pointType="This Phase" - rank={parsePointOrRank(member.phaseRank)} - points={parsePointOrRank(member.phasePoints)} - /> - <PointsColumn - pointType="All Time" - rank={parsePointOrRank(member.allTimeRank)} - points={parsePointOrRank(member.allTimePoints)} - /> - </div>; - }; -}; - -[@react.component] -let make = (~member: Leaderboard.member) => { - <div className=Styles.linkRow> - <Next.Link href="/testnet"> - <a className=Theme.Link.basic> {React.string("Testnet")} </a> - </Next.Link> - <span className=Styles.icon> Icons.rightCarrot </span> - <Next.Link href="/leaderboard"> - <a className=Theme.Link.basic> {React.string("Leaderboard")} </a> - </Next.Link> - <span className=Styles.icon> Icons.rightCarrot </span> - <span className=Styles.participantDetails> - {React.string("Participant Details")} - </span> - <p className=Styles.header> {React.string(member.name)} </p> - <div className=Styles.middleRow> <Points member /> <Links /> </div> - </div>; -}; diff --git a/frontend/website-redesign/src/components/RunScript.re b/frontend/website-redesign/src/components/RunScript.re deleted file mode 100644 index 46b7ba0460a..00000000000 --- a/frontend/website-redesign/src/components/RunScript.re +++ /dev/null @@ -1,4 +0,0 @@ -[@react.component] -let make = (~children) => { - <script dangerouslySetInnerHTML={"__html": children} />; -}; diff --git a/frontend/website-redesign/src/components/SideText.re b/frontend/website-redesign/src/components/SideText.re deleted file mode 100644 index af959f6a186..00000000000 --- a/frontend/website-redesign/src/components/SideText.re +++ /dev/null @@ -1,42 +0,0 @@ -[@react.component] -let make = (~className="", ~paragraphs) => { - let ps = - paragraphs - |> Array.map(entry => { - let content = - switch (entry) { - | `str(s) => [|<span> {React.string(s)} </span>|] - | `styled(xs) => - List.map( - x => { - switch (x) { - | `emph(s) => - <span className=Theme.Body.basic_semibold> - {React.string(s)} - </span> - | `str(s) => <span> {React.string(s)} </span> - } - }, - xs, - ) - |> Array.of_list - }; - - <p - className=Css.( - merge([Theme.Body.basic, style([marginBottom(`rem(1.5))])]) - )> - {ReactExt.staticArray(content)} - </p>; - }); - - <div - className=Css.( - merge([ - className, - style([media(Theme.MediaQuery.notMobile, [width(`rem(20.625))])]), - ]) - )> - {ReactExt.staticArray(ps)} - </div>; -}; diff --git a/frontend/website-redesign/src/components/Spacer.re b/frontend/website-redesign/src/components/Spacer.re deleted file mode 100644 index 11a0ca39a93..00000000000 --- a/frontend/website-redesign/src/components/Spacer.re +++ /dev/null @@ -1,9 +0,0 @@ -[@react.component] -let make = (~width=0., ~height=0.) => - <div - className={Css.style([ - Css.width(`rem(width)), - Css.height(`rem(height)), - Css.flexShrink(0.), - ])} - />; diff --git a/frontend/website-redesign/src/components/StatusBadge.re b/frontend/website-redesign/src/components/StatusBadge.re deleted file mode 100644 index c5eaf6be7b0..00000000000 --- a/frontend/website-redesign/src/components/StatusBadge.re +++ /dev/null @@ -1,137 +0,0 @@ -module Styles = { - open Css; - let wrapper = (bgColor, fgColor) => - style([ - backgroundColor(white), - border(`px(2), `solid, fgColor), - color(fgColor), - fontWeight(`medium), - textTransform(`uppercase), - height(`rem(2.)), - borderRadius(`px(5)), - display(`inlineFlex), - justifyContent(`center), - alignItems(`center), - padding2(~v=`zero, ~h=`rem(1.)), - selector( - "svg", - [marginLeft(`rem(0.5)), SVG.fill(Theme.Colors.slateAlpha(0.5))], - ), - hover([ - backgroundColor(bgColor), - selector("svg", [SVG.fill(fgColor)]), - ]), - ]); - let statusCircle = - style([ - width(`px(14)), - height(`px(14)), - borderRadius(`percent(50.)), - backgroundColor(`currentColor), - marginRight(`rem(0.5)), - ]); - let link = - style([ - textDecoration(`none), - display(`inline), - margin2(~v=`zero, ~h=`rem(0.5)), - ]); -}; - -let url = "https://status.codaprotocol.com"; -let apiPath = "/api/v2/summary.json"; - -type component = { - id: string, - name: string, - status: string, -}; -type response = {components: array(component)}; - -external parseStatusResponse: Js.Json.t => response = "%identity"; - -type service = [ | `Summary | `Network | `Faucet | `EchoBot | `GraphQLProxy]; - -type status = - | Unknown - | Operational - | DegradedPerformance - | PartialOutage - | MajorOutage - | UnderMaintenance; - -let parseStatus = status => - switch (status) { - | "operational" => Operational - | "degraded_performance" => DegradedPerformance - | "partial_outage" => PartialOutage - | "major_outage" => MajorOutage - | "under_maintenance" => UnderMaintenance - | s => - Js.Console.warn("Unknown status `" ++ s ++ "`"); - Unknown; - }; - -let parseServiceName = name => - switch (name) { - | "Network" => `Network - | "Faucet" => `Faucet - | "Echo Bot" => `EchoBot - | "GraphQL Proxy" => `GraphQLProxy - | "Coda Testnet" - | "Summary" => `Summary - | s => - Js.Console.warn("Unknown status service `" ++ s ++ "`"); - `Summary; - }; - -module Inner = { - [@react.component] - let make = (~service: service) => { - let (status, setStatus) = React.useState(() => Unknown); - React.useEffect0(() => { - ReFetch.fetch(url ++ apiPath) - |> Promise.bind(ReFetch.Response.json) - |> Promise.map(parseStatusResponse) - |> Promise.iter(response => { - let components = - response.components - |> Array.to_list - |> List.filter(c => parseServiceName(c.name) == service); - switch (components) { - | [] => Js.Console.warn("Error retrieving status") - | [{status}, ..._] => setStatus(_ => parseStatus(status)) - }; - }); - None; - }); - let (statusStr, bgColor, fgColor) = { - Theme.Colors.( - switch (status) { - | Unknown => ("Unknown", greyishAlpha(0.1), grey) - | Operational => ("Operational", kernelAlpha(0.1), kernel) - | DegradedPerformance => ("Degraded", amberAlpha(0.1), amber) - | PartialOutage => ("Partial Outage", amberAlpha(0.1), amber) - | MajorOutage => ("Major Outage", amberAlpha(0.1), amber) - | UnderMaintenance => ("Under Maintenance", amberAlpha(0.1), amber) - } - ); - }; - <a href=url className=Styles.link target="_blank"> - <span className={Styles.wrapper(bgColor, fgColor)}> - <span className=Styles.statusCircle /> - <span className=Css.(style([color(Theme.Colors.slate)]))> - {React.string(statusStr)} - </span> - Icons.externalLink - </span> - </a>; - }; -}; - -let (make, makeProps) = Inner.(make, makeProps); - -// For use from MDX code -let default = (props: {. "service": string}) => { - <Inner service={parseServiceName(props##service)} />; -}; diff --git a/frontend/website-redesign/src/components/StepButton.re b/frontend/website-redesign/src/components/StepButton.re deleted file mode 100644 index 88431dfeded..00000000000 --- a/frontend/website-redesign/src/components/StepButton.re +++ /dev/null @@ -1,73 +0,0 @@ -open Css; - -module Style = { - let container = - style([ - position(`relative), - height(`rem(19.68)), - borderRadius(`px(6)), - boxSizing(`borderBox), - backgroundColor(Theme.Colors.babyBlue), - backgroundImage(`url("/static/img/Bg.SecurityWave.png")), - padding2(~v=`rem(2.5), ~h=`rem(3.12)), - border(`px(1), `solid, Theme.Colors.marine), - width(`rem(20.)), - media( - Theme.MediaQuery.tablet, - [width(`rem(17.5)), padding2(~v=`rem(2.5), ~h=`rem(2.5))], - ), - media( - Theme.MediaQuery.desktop, - [width(`rem(21.25)), padding2(~v=`rem(2.5), ~h=`rem(3.12))], - ), - display(`flex), - flexDirection(`column), - justifyContent(`spaceBetween), - ]); - - let image = style([alignSelf(`center)]); - let background = - style([ - position(`absolute), - top(`zero), - right(`zero), - display(`inlineBlock), - ]); - - let label = - merge([ - Theme.H3.basic, - style([alignSelf(`center), color(Theme.Colors.marine)]), - ]); - let labelSemiBold = merge([label, style([fontWeight(`semiBold)])]); - let ctaButton = - merge([ - Theme.Body.basic_semibold, - style([ - width(`rem(14.)), - height(`rem(3.)), - backgroundColor(Theme.Colors.hyperlink), - borderRadius(`px(6)), - textDecoration(`none), - color(white), - padding2(~v=`px(12), ~h=`px(24)), - textAlign(`center), - alignSelf(`center), - hover([backgroundColor(Theme.Colors.hyperlinkHover)]), - ]), - ]); -}; - -[@react.component] -let make = (~target=?, ~labelStep, ~label, ~image, ~buttonLabel, ~buttonLink) => { - <div className=Style.container ariaLabel=label> - <label className=Style.label> - <span className=Style.labelSemiBold> {React.string(labelStep)} </span> - {React.string(label)} - </label> - <img src=image className=Style.image /> - <a ?target className=Style.ctaButton href=buttonLink> - {React.string(buttonLabel)} - </a> - </div>; -}; diff --git a/frontend/website-redesign/src/components/Summary.re b/frontend/website-redesign/src/components/Summary.re deleted file mode 100644 index f15263382cd..00000000000 --- a/frontend/website-redesign/src/components/Summary.re +++ /dev/null @@ -1,343 +0,0 @@ -module Moment = { - type t; -}; - -[@bs.module] external momentWithDate: Js.Date.t => Moment.t = "moment"; -[@bs.send] external format: (Moment.t, string) => string = "format"; - -type statistics = { - genesisMembers: string, - blockCount: string, - participants: string, -}; - -let fetchStatistics = () => { - Sheets.fetchRange( - ~sheet="1Nq_Y76ALzSVJRhSFZZm4pfuGbPkZs2vTtCnVQ1ehujE", - ~range="Data!A2:C", - ) - |> Promise.bind(res => { - let entry = Leaderboard.parseEntry(res[0]); - { - genesisMembers: entry |> Leaderboard.safeArrayGet(0), - blockCount: entry |> Leaderboard.safeArrayGet(1), - participants: entry |> Leaderboard.safeArrayGet(2), - } - ->Some - ->Promise.return; - }) - |> Js.Promise.catch(_ => Promise.return(None)); -}; - -module Styles = { - open Css; - - let header = - merge([ - Theme.H1.basic, - style([ - marginTop(`zero), - fontSize(`rem(3.)), - lineHeight(`rem(4.)), - media(Theme.MediaQuery.notMobile, [marginTop(`rem(4.))]), - ]), - ]); - - let heroRow = - style([ - display(`flex), - flexDirection(`column), - paddingTop(`rem(2.8)), - media(Theme.MediaQuery.notMobile, [alignItems(`center)]), - media( - Theme.MediaQuery.veryVeryLarge, - [flexDirection(`row), paddingTop(`zero), marginTop(`rem(3.5))], - ), - ]); - - let heroH3 = - merge([ - Theme.Body.big_semibold, - style([ - display(none), - textAlign(`left), - fontWeight(`semiBold), - color(Theme.Colors.leaderboardMidnight), - media( - Theme.MediaQuery.notMobile, - [ - display(`block), - marginTop(`rem(3.5)), - marginBottom(`rem(1.5)), - ], - ), - ]), - ]); - - let asterisk = - merge([ - Theme.Body.basic, - style([ - display(none), - media(Theme.MediaQuery.notMobile, [display(`inline)]), - ]), - ]); - let disclaimer = - merge([ - Theme.Body.basic_small, - style([ - marginTop(`rem(3.6)), - media( - Theme.MediaQuery.notMobile, - [display(`inline), marginTop(`rem(4.6))], - ), - ]), - ]); - let buttonRow = - style([ - display(`flex), - flexDirection(`column), - marginTop(`rem(3.)), - media( - Theme.MediaQuery.notMobile, - [flexDirection(`row), justifyContent(`flexStart)], - ), - media(Theme.MediaQuery.tablet, [marginTop(`zero)]), - ]); - - let heroLeft = - style([ - media(Theme.MediaQuery.tablet, [marginBottom(`rem(3.))]), - media( - Theme.MediaQuery.veryVeryLarge, - [maxWidth(`rem(38.)), marginRight(`rem(7.))], - ), - ]); - let heroRight = - style([ - display(`flex), - position(`relative), - top(`zero), - flexDirection(`column), - paddingLeft(`rem(1.)), - alignItems(`center), - unsafe("width", "fit-content"), - media( - Theme.MediaQuery.tablet, - [paddingLeft(`zero), marginBottom(`rem(8.)), alignItems(`center)], - ), - ]); - let flexColumn = - style([ - display(`flex), - flexDirection(`column), - justifyContent(`center), - ]); - - let heroLinks = - style([ - media( - Theme.MediaQuery.notMobile, - [padding2(~v=`rem(0.), ~h=`rem(6.0))], - ), - ]); - - let link = merge([Theme.Link.basic, style([lineHeight(`px(28))])]); - let updatedDate = - merge([Theme.Body.basic, style([color(Theme.Colors.teal)])]); - let icon = - style([marginRight(`px(8)), position(`relative), top(`px(1))]); -}; - -module StatisticsRow = { - module Styles = { - open Css; - let statistic = - style([ - Theme.Typeface.ibmplexsans, - textTransform(`uppercase), - fontSize(`rem(1.0)), - color(Theme.Colors.saville), - letterSpacing(`px(2)), - fontWeight(`semiBold), - alignSelf(`center), - ]); - - let value = - merge([ - statistic, - style([ - display(`flex), - fontSize(`rem(2.25)), - justifyContent(`center), - ]), - ]); - let container = - style([ - display(`flex), - flexWrap(`wrap), - justifyContent(`spaceAround), - media( - Theme.MediaQuery.tablet, - [gridTemplateColumns([`rem(12.), `rem(12.), `rem(12.)])], - ), - ]); - let flexColumn = - style([ - display(`flex), - flexDirection(`column), - justifyContent(`center), - ]); - let lastStatistic = - merge([ - flexColumn, - style([ - marginTop(`rem(1.)), - media("(min-width: 26.8rem)", [marginTop(`zero)]), - ]), - ]); - }; - [@react.component] - let make = (~statistics) => { - <div className=Styles.container> - <div className=Styles.flexColumn> - <h2 className=Styles.statistic> {React.string("Participants")} </h2> - <span className=Styles.value> - {React.string(statistics.participants)} - </span> - </div> - <div className=Styles.flexColumn> - <h2 className=Styles.statistic> {React.string("Blocks")} </h2> - <span className=Styles.value> - {React.string(statistics.blockCount)} - </span> - </div> - <div className=Styles.lastStatistic> - <span className=Styles.statistic> - {React.string("Genesis Members")} - </span> - <span className=Styles.value> - {React.string(statistics.genesisMembers)} - </span> - </div> - </div>; - }; -}; - -module HeroText = { - [@react.component] - let make = () => { - <div> - <p className=Styles.heroH3> - {React.string( - "Coda rewards community members with testnet points* for completing challenges \ - that contribute to the development of the protocol.", - )} - </p> - <span className=Styles.asterisk> {React.string("*")} </span> - <div className=Styles.disclaimer> - {React.string( - "Testnet Points (abbreviated 'pts') are designed solely to track contributions \ - to the Testnet and Testnet Points have no cash or other monetary value. \ - Testnet Points are not transferable and are not redeemable or exchangeable \ - for any cryptocurrency or digital assets. We may at any time amend or eliminate Testnet Points.", - )} - </div> - </div>; - }; -}; - -type state = {statistics: option(statistics)}; -let initialState = {statistics: None}; - -type actions = - | UpdateStatistics(statistics); - -let reducer = (_, action) => { - switch (action) { - | UpdateStatistics(statistics) => {statistics: Some(statistics)} - }; -}; - -[@react.component] -let make = (~lastManualUpdatedDate) => { - let (state, dispatch) = React.useReducer(reducer, initialState); - let dateAsMoment = momentWithDate(lastManualUpdatedDate); - let date = format(dateAsMoment, "MMMM Do YYYY"); - - React.useEffect0(() => { - fetchStatistics() - |> Promise.iter(e => - Belt.Option.mapWithDefault(e, (), statistics => - dispatch(UpdateStatistics(statistics)) - ) - ); - None; - }); - - <> - <h1 className=Styles.header> {React.string("Testnet Leaderboard")} </h1> - <div className=Styles.heroRow> - <div className=Styles.heroLeft> - {switch (state.statistics) { - | Some(statistics) => <StatisticsRow statistics /> - | None => React.null - }} - <HeroText /> - </div> - <div className=Styles.heroRight> - <div className=Styles.buttonRow> - <Button - link="https://bit.ly/3dNmPle" - label="Current Challenges" - bgColor=Theme.Colors.clover - bgColorHover=Theme.Colors.jungle - /> - <Spacer width=2.0 height=1.0 /> - <Button - link="/genesis" - label="Genesis Program" - bgColor=Theme.Colors.clover - bgColorHover=Theme.Colors.jungle - /> - </div> - <Spacer height=4.8 /> - <div className=Styles.heroLinks> - <div className=Styles.flexColumn> - <Next.Link href=""> - <a className=Styles.link> - <Svg - link="/static/img/Icon.Link.svg" - dims=(1.0, 1.0) - className=Styles.icon - alt="an arrow pointing to the right with a square around it" - /> - {React.string("Leaderboard FAQ")} - </a> - </Next.Link> - <Next.Link href=""> - <a className=Styles.link> - <Svg - link="/static/img/Icon.Link.svg" - dims=(0.9425, 0.8725) - className=Styles.icon - alt="an arrow pointing to the right with a square around it" - /> - {React.string("Discord #Leaderboard Channel")} - </a> - </Next.Link> - <span className=Styles.updatedDate> - <Svg - link="/static/img/Icon.Info.svg" - className=Styles.icon - dims=(1.0, 1.0) - alt="a undercase letter i inside a blue circle" - /> - {React.string("Last manual update " ++ date)} - </span> - </div> - </div> - </div> - </div> - </>; -}; diff --git a/frontend/website-redesign/src/components/SustainableSection.re b/frontend/website-redesign/src/components/SustainableSection.re deleted file mode 100644 index 9de7007b797..00000000000 --- a/frontend/website-redesign/src/components/SustainableSection.re +++ /dev/null @@ -1,140 +0,0 @@ -[@react.component] -let make = () => { - <div - className=Css.( - style([ - marginTop(`rem(2.5)), - media(Theme.MediaQuery.full, [marginTop(`rem(11.25))]), - ]) - )> - <div - className=Css.( - style([ - width(`percent(100.0)), - media( - Theme.MediaQuery.notMobile, - [ - display(`flex), - justifyContent(`center), - width(`percent(100.0)), - ], - ), - ]) - )> - <h1 - className=Css.( - merge([ - Theme.H1.hero, - style([ - color(Theme.Colors.clover), - position(`relative), - display(`inlineBlock), - marginTop(`zero), - marginBottom(`zero), - media(Theme.MediaQuery.notSmallMobile, [margin(`auto)]), - ]), - ]) - )> - {React.string("Sustainable scalability")} - <div - className=Css.( - style([ - display(`none), - media( - Theme.MediaQuery.full, - [ - display(`block), - position(`absolute), - top(`zero), - left(`zero), - transforms([ - `translateX(`percent(-50.0)), - `translateY(`percent(-25.0)), - ]), - ], - ), - ]) - )> - <Svg link="/static/img/leaf.svg" dims=(6.25, 6.25) alt="" /> - </div> - </h1> - </div> - <div - className=Css.( - style([ - marginTop(`rem(2.375)), - display(`flex), - maxWidth(`rem(81.5)), - justifyContent(`spaceBetween), - alignItems(`center), - flexWrap(`wrapReverse), - media(Theme.MediaQuery.full, [marginTop(`rem(4.375))]), - media(Theme.MediaQuery.notMobile, [justifyContent(`spaceAround)]), - ]) - )> - <div - className=Css.( - style([ - userSelect(`none), - media(Theme.MediaQuery.notMobile, [marginBottom(`rem(2.375))]), - ]) - )> - <Svg - inline=true - className=Css.( - style([ - width(`rem(18.75)), - media(Theme.MediaQuery.notMobile, [width(`rem(23.9375))]), - ]) - ) - link="/static/img/chart-blockchain-size.svg" - dims=(23.125, 16.8125) - alt="Line graph comparing the size requirements of Coda to other blockchains. \ - Other blockchain's size requirements increase significantly over time, on the order \ - of 2TB+, whereas Coda staking nodes and user nodes remain constant, at around 1GB \ - and 22kb of data respectively." - /> - </div> - <div - className=Css.( - style([ - userSelect(`none), - media(Theme.MediaQuery.notMobile, [marginBottom(`rem(2.375))]), - ]) - )> - <Svg - inline=true - className=Css.( - style([ - width(`rem(18.75)), - media(Theme.MediaQuery.notMobile, [width(`rem(23.9375))]), - ]) - ) - link="/static/img/chart-blockchain-energy.svg" - dims=(23.125, 16.8125) - alt="Line graph comparing the energy usage of Coda to other blockchains. \ - Over time, the energy requirements for proof of work blockchains to process \ - a single transaction will go up, whereas the Coda network will remain constant." - /> - </div> - <div className=Css.(style([marginBottom(`rem(2.375))]))> - <SideText - paragraphs=[| - `styled([ - `str( - "With Coda's constant sized blockchain and energy efficient consensus, Coda will be", - ), - `emph( - " sustainable even as it scales to thousands of transactions per second, millions of users, and years of transactions history", - ), - `str("."), - ]), - `str( - "Help compress Coda by participating in snarking. Just like mining, with snarking anyone can contribute their compute to the network to help compress the blockchain.", - ), - |] - /> - </div> - </div> - </div>; -}; diff --git a/frontend/website-redesign/src/components/Svg.re b/frontend/website-redesign/src/components/Svg.re deleted file mode 100644 index c99ee4c7a77..00000000000 --- a/frontend/website-redesign/src/components/Svg.re +++ /dev/null @@ -1,36 +0,0 @@ -module Size = { - // rem (width, height) - type t = (float, float); - - let remX = fst; - let remY = snd; - - let pixelsX = ((x, _)) => x *. 16.0 |> Js.Math.ceil; - let pixelsY = ((_, y)) => y *. 16.0 |> Js.Math.ceil; -}; - -[@react.component] -let make = (~link, ~dims, ~inline=false, ~className=?, ~alt) => { - <object - data=link - type_="image/svg+xml" - width={Js.Int.toString(Size.pixelsX(dims))} - height={Js.Int.toString(Size.pixelsY(dims))} - role={String.length(alt) == 0 ? "presentation" : "img"} - ariaHidden={String.length(alt) == 0} - alt - ariaLabel=alt - className={ - switch (className) { - | None => - Css.( - style([ - width(`rem(Size.remX(dims))), - height(`rem(Size.remY(dims))), - ]) - ) - | Some(className) => className - } - } - />; -}; diff --git a/frontend/website-redesign/src/components/TeamSection.re b/frontend/website-redesign/src/components/TeamSection.re deleted file mode 100644 index 1c5738f9858..00000000000 --- a/frontend/website-redesign/src/components/TeamSection.re +++ /dev/null @@ -1,585 +0,0 @@ -module Member = { - [@react.component] - let make = (~name, ~title, ~description, ~imageName=?) => { - let lastName = Js.String.split(" ", name)[1]; - let imageSrc = - "/static/img/" - ++ ( - switch (imageName) { - | Some(imageName) => imageName - | _ => String.lowercase_ascii(lastName) - } - ) - ++ ".jpg"; - <div - className=Css.( - merge([ - Theme.Technical.border(Css.border), - style([ - display(`flex), - flexDirection(`column), - width(`rem(20.5)), - minWidth(`rem(20.5)), - flexGrow(1.), - maxWidth(`rem(23.75)), - marginTop(`rem(1.5625)), - marginBottom(`rem(1.5625)), - marginLeft(`zero), - marginRight(`zero), - media( - Theme.MediaQuery.notMobile, - [ - minHeight(`rem(27.5)), - marginLeft(`rem(1.5625)), - marginRight(`rem(1.5625)), - width(`percent(100.)), - ], - ), - ]), - ]) - )> - <div - className=Css.( - merge([ - Theme.Technical.border(Css.borderBottom), - style([ - display(`flex), - flexDirection(`row), - alignItems(`center), - ]), - ]) - )> - <img - className=Css.( - style([ - maxWidth(`rem(5.5)), - maxHeight(`rem(5.5)), - height(`auto), - width(`auto), - unsafe("WebkitFilter", "grayscale(1)"), - unsafe("filter", "grayscale(1)"), - marginLeft(`rem(0.875)), - marginTop(`rem(0.625)), - marginBottom(`rem(0.625)), - ...Theme.paddingX(`rem(1.)), - ]) - ) - src=imageSrc - alt={j|Portrait photo of $name.|j} - /> - <div - className=Css.( - style([ - display(`flex), - flexDirection(`column), - alignItems(`flexStart), - justifyContent(`flexStart), - ]) - )> - <div - className=Css.( - style([ - display(`flex), - justifyContent(`center), - alignItems(`center), - backgroundColor(Theme.Colors.tealBlue), - height(`rem(1.75)), - ]) - )> - <h3 - className=Css.( - merge([ - Theme.H3.Technical.title, - style([ - marginTop(`rem(0.0625)), - // hack to remove top margin for IE11 - media( - "all and (-ms-high-contrast: none), (-ms-high-contrast: active)", - [margin(`auto)], - ), - // hack to remove top margin for Edge - selector( - "@supports (-ms-ime-align:auto)", - [margin(`auto)], - ), - ...Theme.paddingX(`rem(0.1875)), - ]), - ]) - )> - {React.string(name)} - </h3> - </div> - <h5 - className=Css.( - merge([ - Theme.Technical.basic, - style([ - textAlign(`left), - whiteSpace(`nowrap), - marginTop(`rem(0.125)), - ]), - ]) - )> - {React.string(title)} - </h5> - </div> - </div> - <p - className=Css.( - merge([ - style([ - marginLeft(`rem(1.875)), - marginRight(`rem(2.)), - ...Theme.paddingY(`rem(0.5)), - ]), - Theme.Body.Technical.basic, - ]) - )> - {React.string(description)} - </p> - </div>; - }; -}; - -module Section = { - [@react.component] - let make = (~name, ~children) => { - let checkboxName = name ++ "-checkbox"; - let labelName = name ++ "-label"; - <div className=Css.(style([display(`flex), flexDirection(`column)]))> - <h3 className=Theme.H3.Technical.boxed> {React.string(name)} </h3> - <input - type_="checkbox" - id=checkboxName - className=Css.( - style([ - display(`none), - selector( - ":checked + div", - [height(`auto), after([display(`none)])], - ), - selector(":checked ~ #" ++ labelName, [display(`none)]), - ]) - ) - /> - <div - className=Css.( - style([ - position(`relative), - height(`rem(45.)), - overflow(`hidden), - display(`flex), - flexWrap(`wrap), - marginLeft(`auto), - marginRight(`auto), - justifyContent(`center), - after([ - contentRule(""), - position(`absolute), - bottom(`px(-1)), - left(`zero), - height(`rem(8.)), - width(`percent(100.)), - pointerEvents(`none), - backgroundImage( - `linearGradient(( - `deg(0.), - [ - (`zero, Theme.Colors.navyBlue), - (`percent(100.), Theme.Colors.navyBlueAlpha(0.0)), - ], - )), - ), - ]), - ]) - )> - children - </div> - <label - id=labelName - className=Css.( - merge([ - Theme.Link.basic, - style([ - Theme.Typeface.pragmataPro, - fontWeight(`bold), - display(`block), - height(`rem(4.)), - width(`rem(20.)), - marginLeft(`auto), - marginRight(`auto), - marginTop(`rem(1.0)), - marginBottom(`rem(3.0)), - textAlign(`center), - cursor(`pointer), - ]), - ]) - ) - htmlFor=checkboxName> - {React.string({js|View all ↓|js})} - </label> - <RunScript> - {Printf.sprintf( - {|document.getElementById("%s").checked = false;|}, - checkboxName, - )} - </RunScript> - </div>; - }; -}; - -let advisor = "Advisor"; -let headerHeight = `rem(6.125); -let headerStyle = - Css.( - style([ - lineHeight(headerHeight), - color(Theme.Colors.white), - Theme.Typeface.rubik, - fontSize(`rem(2.1)), - textAlign(`center), - display(`inlineBlock), - media(Theme.MediaQuery.notMobile, [fontSize(`rem(2.8))]), - ]) - ); -[@react.component] -let make = () => { - <> - <div - className=Css.( - style([ - transforms([`translateY(`percent(-50.0))]), - height(headerHeight), - marginLeft(`auto), - marginRight(`auto), - marginBottom(`rem(3.0)), - maxWidth(`rem(27.125)), - backgroundColor(Theme.Colors.navyBlue), - // TODO: How do you use the boxShadow in bs-css - unsafe( - "boxShadow", - "0 2px 50px 0 rgba(0, 0, 0, 0.2), 0 7px 8px 0 rgba(0, 0, 0, 0.5)", - ), - textAlign(`center), - whiteSpace(`nowrap), - ]) - )> - <span - className=Css.( - merge([ - headerStyle, - style([fontWeight(`light), marginRight(`rem(1.))]), - ]) - )> - {React.string("Built by ")} - </span> - <span - className=Css.(merge([headerStyle, style([fontWeight(`medium)])]))> - {React.string(" O(1) Labs")} - </span> - </div> - <Section name="Team"> - <Member - name="Evan Shapiro" - title="CEO" - description="Evan Shapiro graduated from Carnegie Mellon with a BS in computer \ - science. He then obtained his research MS while working in the CMU \ - Personal Robotics Lab, where he did research for the HERB robotics \ - platform. He has also worked as a software engineer for Mozilla." - /> - <Member - name="Izaak Meckler" - title="CTO" - description="Izaak Meckler is a mathematician and computer scientist. Most \ - recently, he was a PhD student studying cryptography at UC Berkeley. \ - Prior to that, he worked as a software engineer at trading firm Jane \ - Street, and has contributed to numerous open source projects including \ - the Elm compiler." - /> - <Member - name="Brad Cohn" - title="Strategy & Operations" - description="Brad Cohn has diverse work experience, including stints in an \ - electrophysiology lab, high frequency trading firm, a technology think \ - tank, and a hedge fund. He most recently came from Bridgewater \ - Associates where he was an engineer on the currency team and Ray \ - Dalio's research team before joining a group of engineers dedicated to \ - rearchitecting core investment systems. He holds a BS in math from \ - UChicago with a minor in computational neuroscience." - /> - <Member - name="Brandon Kase" - title="Head of Product Engineering" - description="Brandon Kase loves functional programming. He was first introduced to \ - it while pursuing his BS in computer science at Carnegie Mellon. He \ - has worked as a software engineer for Highlight (acquired by \ - Pinterest), Pinterest, Facebook, and Mozilla. Brandon is excited about \ - the safety and clarity strong statically typed functional programming \ - techniques can bring to the software industry. He also enjoys \ - proselytizing, so you may find him speaking at a conference near you." - /> - <Member - name="Ember Arlynx" - title="Protocol Engineer" - description="Ember Arlynx is a seasoned open source contributor, recently \ - working primarily on the Rust compiler and libraries. They studied \ - computer science at Clarkson University and have worked at Dyn, \ - Mozilla, Leap Motion, and NICTA. They are especially interested in \ - formal verification, the seL4 microkernel, and what high powered \ - functional programming can do for trustworthy software." - /> - <Member - name="Deepthi Kumar" - title="Protocol Engineer" - description="Deepthi is a functional programming enthusiast and software engineer. \ - In her recently completed master's work, Deepthi designed GitQL, a \ - novel embedded DSL for querying textual changes in software \ - repositories. Her interests span programming languages and program \ - analysis. Deepthi holds an MS in computer science from Oregon State \ - University and a BE from Visvesvaraya Technological University." - /> - <Member - name="Nathan Holland" - title="Protocol Engineer" - description="Nathan is a passionate, self-taught programmer who loves programming \ - languages and paradigms and using high-level abstractions to create \ - high-performance systems. Some of his favorite projects have been \ - developing an array programming languages that targeted GPUs, an \ - Elixir DSL for service buses, a MySql binary log deserializer, and a \ - VR-based window manager on Linux. Most recently, Nathan was building a \ - unique educational program to teach people how to program from the \ - ground up using simplified programming languages and a simple virtual \ - machine." - /> - <Member - name="Nacera Rodstein" - title="Operations Associate" - description="Nacera has had a career spanning startups, medium sized companies, and \ - corporations. After earning her BS and MS from IAE in Lille, France, \ - Nacera moved to San Francisco. Over the next decade, she worked with \ - Bleacher Report (through growth from 10 to 60 employees and an \ - acquisition by Turner), Mokum Solutions, Sephora, Venture Beat, AMSI, \ - Oracle, and a software sales business which she helped start up and \ - scale." - /> - <Member - name="Paul Steckler" - title="Protocol Engineer" - description="Paul is a functional programmer and researcher. In the academic realm, \ - he's followed his interest in PLs, type systems, and formal \ - verification through collaborations with INRIA, the MIT PLV Group, and \ - NICTA. He also worked on the initial implementation of Alacris, a \ - cryptocurrency solution layered on top of existing blockchains. He \ - holds a PhD in computer science from Northeastern University." - /> - <Member - name="Harold Herbert" - title="Head of Design" - description="Harold previously designed brands, products, and experiences at Hired, \ - Flipboard, Zillow, and with a range of technology companies while \ - running an independent design studio. He believes that all design is \ - experience design. Regardless of the medium, the end goal is for the \ - well-being of the user." - /> - <Member - name="Vanishree Rao" - title="Protocol Researcher" - description="Vanishree is a theoretical and applied cryptographer with deep \ - experience in industry and academia. She earned her PhD at UCLA \ - through her work on zk-proofs, multiparty computation, hashing, and \ - pseudorandom functions, among other projects. She then worked in \ - industry at Xerox PARC and Intertrust Technologies. Vanishree enjoys \ - developing cryptographic solutions for real-world challenges and \ - communicating intuitive explanations of complex cryptography concepts." - /> - <Member - name="Matthew Ryan" - title="Protocol Engineer" - description="Matthew Ryan is a self-taught programmer with a strong interest in \ - computer-aided theorem proving, formal program verification, and \ - functional programming. He has been involved with several open-source \ - projects, and passionately believes in the open-source philosophy. He \ - has a BSc in Mathematics from the University of Warwick, U.K., where \ - he studied cryptography." - /> - <Member - name="Jiawei Tang" - title="Protocol Engineer" - description="Jiawei loves writing interpreters and type checkers. He received his \ - BS in computer science from Indiana University, and he's fascinated by \ - categorical semantics and dependent type theory. Currently, he is \ - implementing a toy dependently typed language called Pie." - /> - <Member - name="Carey Janecka" - title="Product Engineer" - description="Carey loves working on crazy ideas. He's designed and \ - built products for SpaceX, Coinbase and a variety of early-stage \ - companies. Nothing gets him more excited than working on simple user \ - interfaces for complex systems. He's excited for the applications that \ - can be built on top of Coda and enabling others to build cool things." - /> - <Member - name="Claire Kart" - title="Head of Marketing & Community" - description="Claire's career has focused on using technology to reimagine financial \ - services and building community to increase engagement and opportunities for individuals. \ - Prior to joining the team at O(1) Labs, she was at Ripple, where she led a number of \ - strategic projects and served as the main liaison to the XRP community. Prior to that, \ - Claire was an early employee at SoFi, were she was involved in the day-to-day operations \ - across all functions of the marketing team during four years of hyper growth, including \ - leading their member engagement strategy. Earlier in her career, she designed and \ - implemented a community-based micro grant program in rural India that has sponsored \ - 300+ women to attend university. Originally from rural Pennsylvania, Claire graduated \ - with distinction from Dartmouth College (A.B.) and holds an MBA from the University \ - of Texas at Austin." - /> - <Member - name="Conner Swann" - title="Protocol Reliability Eng" - description="Conner is an infrastructure enthusiast with extensive \ - experience operating distributed systems at scale. His journey \ - through the technology sector has taken him from People Analytics \ - to Healthcare Tech and now to the Crypto space. He enjoys the challenge \ - of applying DevOps methodologies and tooling to emerging industries, and \ - looks forward to contributing back to the wider Open Source community. \ - Conner is a California Native and has a BSc in Computer Science from \ - Northern Arizona University." - /> - <Member - name={js|Emre Tekisalp|js} - title="Head of Business Development" - description="Emre's career has focused on bringing new economic \ - opportunities to societies using the power of technology. Before O(1) \ - Labs, he spent two years at Coinbase's Business Development team where \ - he led a number of strategic programs during a period when the company \ - grew 10x. Before Coinbase, Emre was a Product Manager at Intel's wearable \ - devices group. Originally from Istanbul, Turkey, Emre has an MBA degree \ - from Columbia University." - /> - <Member - name="Christine Yip" - title="Community Manager" - description="Christine is an early contributor in the community with broad \ - experience in multidisciplinary engineering teams. She previously worked for \ - global firms in the US, The Netherlands, Czech Republic, and Hong Kong. \ - She believes that we can take more ownership of our lives than ever before by \ - using blockchain technology. She supports the community and Coda by combining their \ - efforts in achieving a decentralized future." - /> - <Member - name="Michelle Wong" - title="Product Engineer" - description="Michelle believes that great products are built upon \ - empathy for the user and iterative processes. She recently graduated \ - from Smith College with a BA in Computer Science and is excited about \ - developing products that contribute to the evolution of decentralized technology. " - /> - <Member - name="Sherry Lin" - title="Marketing Manager" - description="Sherry is a marketing and communications professional who enjoys \ - telling stories that resonate. Her previous experiences have been in the hardware \ - (semiconductor) space, but she is really interested in how blockchain can solve problems \ - by disrupting the status quo. She is excited to work on developing blockchain technology \ - that will open up more opportunities to more people. Sherry holds a BA in Communications/International \ - Studies from Northwestern University." - /> - <Member - name="Kate El-Bizri" - title="Visual Designer" - description="In addition to a BFA in Visual Design, Kate has a Bachelor's degree in psychology. \ - Her philosophy is that understanding what motivates and drives our behaviors creates effective design systems.\ - Through both agency and in-house, she's worked with many companies from small startups to large-scale \ - Fortune 100 companies to communicate their stories to the world. She believes everyone is creative at heart, \ - and that creative inspiration can come from anywhere through engaging with the world around us." - /> - <Member - name="Ahmad Wilson" - title="Protocol Reliability Eng" - description="Ahmad is a computer scientist and self-proclaimed \"tech-head\" \ - interested in software infrastructure, user-interfaces and AI/automation. \ - He holds a MSc in HCI & AI from Brown University, and a BS in CS from Morehouse College. \ - He has developed software for startups and larger corporations such as Yelp and Microsoft for over a decade. \ - He's a fan of New England sports teams (Go Pats!), gardening, sci-fi and learning about \ - cryptocurrency and the future of the decentralized web." - /> - <Member - name="Bijan Shahrokhi" - title="Product Manager" - description="Bijan has been a product leader in the fintech industry for over 10 years and in blockchain for \ - over 5 years. Prior to joining O(1) Labs, Bijan was Head of Product at Harbor, a Layer 2 compliance protocol on Ethereum. " - /> - <Member - name="Aneesha Raines" - title="Engineering Manager" - description=" - Aneesha's career in software engineering has spanned a wide range of \ - technology companies from biotech startup to big enterprise. \ - She has an MSE in computer engineering from the University of Michigan \ - and most recently came from an identity company as an Engineering Manager. \ - Her primary background is in QA, so believes in delivering high quality, scalable and maintainable software. \ - She loves team building and working with individuals to achieve their goals." - /> - </Section> - <Section name="Advisors"> - <Member - name="Jill Carlson" - title=advisor - description="Jill has worked with the IMF and is an advisor to cryptocurrency and blockchain-based ventures. \ - Previously, Jill ran strategy at blockchain start up Chain, where she managed \ - initiatives with Nasdaq and State Street. Jill has conducted academic research \ - on cryptocurrency at the University of Oxford, where she focused on the economic \ - and political implications of bitcoin. Jill began her career as a credit trader at Goldman Sachs. \ - She holds a MSc from Magdalen College, Oxford, and an AB from Harvard, where she studied Classics." - /> - <Member - name="Paul Davison" - title=advisor - description="Paul Davison is the CEO of CoinList - the leading platform for high \ - quality, compliant token sales and airdrops. Prior to CoinList, Paul \ - was the Founder/CEO of Highlight (acquired by Pinterest), an EIR at \ - Benchmark Capital, and a VP at Metaweb (acquired by Google). He holds \ - a BS from Stanford University and an MBA from Stanford Business School." - /> - <Member - name="Joseph Bonneau" - title=advisor - description="Joseph is an assistant professor at NYU. His research has spanned a \ - variety of topics in cryptography and security including HTTPS and web security, passwords \ - and authentication, cryptocurrencies, end-to-end encrypted communication tools, \ - and side-channel cryptanalysis. He is co-author of the popular textbook \"Bitcoin \ - and Cryptocurrency Technologies\" and co-taught the first MOOC on cryptocurrencies. \ - He holds a PhD from the University of Cambridge and BS and MS degrees in computer science \ - and cryptography from Stanford University." - /> - <Member - name="Akis Kattis" - title=advisor - description="Akis is a PhD candidate in Computer Science at NYU's Courant \ - Institute, where he is advised by Professors Joseph Bonneau and \ - Yevgenyi Dodis. His research revolves around cryptography, privacy, \ - and security, currently focusing on the privacy and scalability issues \ - affecting cryptocurrencies. He also works on differential privacy and \ - its applications to distributed systems and private learning. Akis \ - holds an MSc in theoretical computer science from the University of \ - Toronto and a BSE from Princeton University." - /> - <Member - name={js|Benedikt Bünz|js} - title=advisor - imageName="bunz" - description="Benedikt is a PhD student in the Applied Crypto Group at Stanford and \ - he is advised by Dan Boneh. His research focuses on improving the \ - cryptography of cryptocurrencies. He has done research on zero \ - knowledge proofs (Bulletproofs), verifiable delay functions, super \ - light clients, confidential smart contracts and proofs of solvency." - /> - <Member - name="Amit Sahai" - title=advisor - description="Amit Sahai is a Professor of Computer Science at UCLA, Fellow of the ACM, and Fellow of the IACR. His research interests are in security, cryptography, and theoretical computer science. He is the co-inventor of Attribute-Based Encryption, Functional Encryption, Indistinguishability Obfuscation, author of over 100 technical research papers, and invited speaker at institutions such as MIT, Stanford, and Berkeley. He has also received honors from the Alfred P. Sloan Foundation, Okawa Foundation, Xerox Foundation, Google Research, the BSF, and the ACM. He earned his PhD in Computer Science from MIT and served on the faculty at Princeton before joining UCLA in 2004." - /> - </Section> - </>; -}; diff --git a/frontend/website-redesign/src/components/Terminal.re b/frontend/website-redesign/src/components/Terminal.re deleted file mode 100644 index 5a49582be7f..00000000000 --- a/frontend/website-redesign/src/components/Terminal.re +++ /dev/null @@ -1,165 +0,0 @@ -module Style = { - open Css; - let containerWidth = `rem(37.); - let wrapper = style([display(`flex), flexDirection(`column)]); - let container = - style([ - display(`flex), - flexDirection(`column), - alignItems(`flexStart), - justifyContent(`flexStart), - width(`rem(18.)), - height(`rem(15.)), - maxWidth(`percent(100.)), - backgroundColor(Theme.Colors.midnight), - color(Theme.Colors.offWhite), - padding(`rem(1.)), - Theme.Typeface.ibmplexmono, - borderBottomLeftRadius(`px(5)), - borderBottomRightRadius(`px(5)), - media( - Theme.MediaQuery.notMobile, - [width(containerWidth), height(`rem(22.)), padding(`rem(2.))], - ), - ]); - let item = - style([ - marginBottom(`rem(0.5)), - fontSize(`rem(0.7)), - media(Theme.MediaQuery.notMobile, [fontSize(`rem(1.2))]), - ]); - let prompt = style([color(Theme.Colors.grey), marginRight(`rem(1.))]); - let header = - style([ - position(`relative), - display(`flex), - backgroundColor(Theme.Colors.darkGreyBlue), - height(`rem(2.)), - alignItems(`center), - color(Theme.Colors.grey), - borderTopLeftRadius(`px(5)), - borderTopRightRadius(`px(5)), - ]); - let circles = - style([ - position(`absolute), - display(`flex), - alignItems(`center), - marginLeft(`rem(0.5)), - ]); - let circle = c => - style([ - backgroundColor(c), - height(`rem(0.75)), - width(`rem(0.75)), - borderRadius(`rem(0.375)), - margin2(~v=`zero, ~h=`rem(0.5)), - ]); - let headerText = - style([ - alignSelf(`center), - justifySelf(`center), - marginLeft(`auto), - marginRight(`auto), - Theme.Typeface.ibmplexmono, - ]); -}; - -let useIncrement = (~initial, ~total, ~increment, ~delay) => { - let (amount, setAmount) = React.useState(() => initial); - React.useEffect1( - () => - if (total > amount) { - let id = - Js.Global.setTimeout( - () => setAmount(n => min(total, n + increment)), - delay, - ); - Some(() => Js.Global.clearTimeout(id)); - } else { - None; - }, - [|amount|], - ); - amount; -}; - -module Wrapper = { - [@react.component] - let make = (~lineDelay, ~children) => { - let arr = ReactExt.Children.toArray(children); - let total = Array.length(arr); - let numDisplayed = - useIncrement( - ~initial=min(total, 1), - ~total, - ~increment=1, - ~delay=lineDelay, - ); - <div className=Style.wrapper> - <div className=Style.header> - <div className=Style.headerText> {React.string("bash")} </div> - <div className=Style.circles> - <div className={Style.circle(Theme.Colors.rosebud)} /> - <div className={Style.circle(Theme.Colors.amber)} /> - <div className={Style.circle(Theme.Colors.clover)} /> - </div> - </div> - <div className=Style.container> - {React.array(Array.sub(arr, 0, numDisplayed))} - </div> - </div>; - }; -}; - -module Line = { - [@react.component] - let make = (~delay=75, ~prompt=?, ~value) => { - let numDisplayed = - useIncrement( - ~initial=delay == 0 ? String.length(value) : 0, - ~total=String.length(value), - ~increment=1, - ~delay, - ); - let displayed = String.sub(value, 0, numDisplayed); - <div className=Style.item> - {ReactExt.fromOpt( - ~f= - prompt => - <span className=Style.prompt> {React.string(prompt)} </span>, - prompt, - )} - {React.string(displayed)} - </div>; - }; -}; - -module MultiLine = { - [@react.component] - let make = (~values) => { - <> - {values - |> Array.mapi((i, v) => { - <div key={string_of_int(i)} className=Style.item> - {React.string(v)} - </div> - }) - |> React.array} - </>; - }; -}; - -module Progress = { - [@react.component] - let make = (~delay=4, ~char={js|█|js}) => { - let total = 100; - let numDisplayed = useIncrement(~initial=0, ~total, ~increment=1, ~delay); - let numChars = numDisplayed / 3; - let displayed = String.concat("", List.init(numChars, _ => char)); - <div className=Style.item> - {React.string(displayed)} - {React.string(" " ++ string_of_int(numDisplayed) ++ "%")} - </div>; - }; -}; diff --git a/frontend/website-redesign/src/components/Title.re b/frontend/website-redesign/src/components/Title.re deleted file mode 100644 index 45307d3ff4f..00000000000 --- a/frontend/website-redesign/src/components/Title.re +++ /dev/null @@ -1,36 +0,0 @@ -// TODO: On mobile left align - -[@react.component] -let make = (~noBottomMargin=false, ~fontColor, ~text) => { - <div - className=Css.( - style([ - media( - Theme.MediaQuery.notMobile, - [ - display(`flex), - justifyContent(`center), - width(`percent(100.0)), - ], - ), - ...noBottomMargin ? [] : [marginBottom(`rem(2.25))], - ]) - )> - <h1 - className=Css.( - merge([ - Theme.H1.hero, - style([ - marginTop(`zero), - marginBottom(`zero), - display(`inlineBlock), - color(fontColor), - maxWidth(`rem(30.0)), - media(Theme.MediaQuery.full, [maxWidth(`percent(100.0))]), - ]), - ]) - )> - {React.string(text)} - </h1> - </div>; -}; diff --git a/frontend/website-redesign/src/components/ToggleButton.re b/frontend/website-redesign/src/components/ToggleButton.re deleted file mode 100644 index 1c8c5108500..00000000000 --- a/frontend/website-redesign/src/components/ToggleButton.re +++ /dev/null @@ -1,53 +0,0 @@ -module ButtonStyles = { - open Css; - - let textStyles = - merge([Theme.H6.extraSmall, style([textTransform(`uppercase)])]); - - let hover = - hover([ - backgroundColor(Theme.Colors.hyperlinkHover), - color(Theme.Colors.white), - textShadow(~y=`px(1), Theme.Colors.blackAlpha(0.25)), - ]); - - let button = - merge([ - textStyles, - style([ - hover, - display(`flex), - justifyContent(`center), - alignItems(`center), - width(`rem(13.5)), - height(`rem(2.5)), - textAlign(`center), - backgroundColor(Theme.Colors.gandalf), - color(Theme.Colors.denimTwo), - cursor(`pointer), - ]), - ]); - - let selectedButton = - merge([ - button, - style([ - boxShadow(~blur=`px(30), Theme.Colors.blackAlpha(0.1)), - textShadow(~y=`px(1), Theme.Colors.blackAlpha(0.25)), - backgroundColor(Theme.Colors.hyperlink), - color(Theme.Colors.white), - ]), - ]); -}; - -[@react.component] -let make = (~currentToggle, ~onTogglePress, ~label) => { - <div - className={ - currentToggle == label - ? ButtonStyles.selectedButton : ButtonStyles.button - } - onClick={_ => onTogglePress(label)}> - {React.string(label)} - </div>; -}; diff --git a/frontend/website-redesign/src/components/WhitepaperButton.re b/frontend/website-redesign/src/components/WhitepaperButton.re deleted file mode 100644 index 3097171124a..00000000000 --- a/frontend/website-redesign/src/components/WhitepaperButton.re +++ /dev/null @@ -1,66 +0,0 @@ -open Css; - -module Style = { - let container = - style([ - position(`relative), - height(`rem(15.)), - borderRadius(`px(6)), - boxSizing(`borderBox), - backgroundColor(`transparent), - padding(`zero), - border(`px(1), `solid, Theme.Colors.marine), - overflow(`hidden), - width(`percent(100.)), - media(Theme.MediaQuery.notMobile, [width(`rem(27.5))]), - media(Theme.MediaQuery.veryLarge, [width(`rem(33.125))]), - hover([backgroundColor(Theme.Colors.tan)]), - ]); - - let ellipticBackground = - style([ - position(`absolute), - top(`zero), - right(`zero), - display(`inlineBlock), - ]); - - let label = - merge([ - Theme.H4.semiBold, - style([ - position(`absolute), - top(`rem(1.875)), - left(`rem(1.875)), - color(Theme.Colors.saville), - ]), - ]); - - let icon = - style([ - position(`absolute), - bottom(`rem(2.0625)), - left(`rem(1.875)), - ]); -}; - -// the page looking icon in the button -module Icon = { - module Style = { - let container = style([position(`relative)]); - }; - - [@react.component] - let make = (~sigil) => { - <div className=Style.container> sigil </div>; - }; -}; - -[@react.component] -let make = (~label, ~href, ~sigil) => { - <a href className=Style.container ariaLabel=label> - <span className=Style.ellipticBackground> EllipticBackground.svg </span> - <label className=Style.label> {React.string(label)} </label> - <span className=Style.icon> <Icon sigil /> </span> - </a>; -}; diff --git a/frontend/website-redesign/src/components/Wrapped.re b/frontend/website-redesign/src/components/Wrapped.re deleted file mode 100644 index 12ee53bc4d2..00000000000 --- a/frontend/website-redesign/src/components/Wrapped.re +++ /dev/null @@ -1,24 +0,0 @@ -[@react.component] -let make = (~overflowHidden=false, ~children) => { - <div - className=Css.( - style( - (overflowHidden ? [overflow(`hidden)] : []) - @ [ - margin(`auto), - media( - Theme.MediaQuery.full, - [ - maxWidth(`rem(89.0)), - minHeight(`rem(153.)), - margin(`auto), - ...Theme.paddingX(`rem(3.0)), - ], - ), - ...Theme.paddingX(`rem(1.25)), - ], - ) - )> - children - </div>; -}; diff --git a/frontend/website-redesign/src/components/svg/EllipticBackground.re b/frontend/website-redesign/src/components/svg/EllipticBackground.re deleted file mode 100644 index 8913c0ea518..00000000000 --- a/frontend/website-redesign/src/components/svg/EllipticBackground.re +++ /dev/null @@ -1,182 +0,0 @@ -let svg = - <svg - width="280" - height="240" - viewBox="0 0 280 240" - fill="none" - xmlns="http://www.w3.org/2000/svg"> - <g opacity="0.2"> - <g clipPath="url(#clip0)"> - <path - d="M315.701 -28.3111C306.733 -18.7952 231.007 30.3777 208.854 13.3556C188.684 -2.12139 179.708 -43.7171 153.324 -61.4541C126.941 -79.1911 92.9 -56.9328 69.2302 -8.75009C46.0595 38.0645 49.1125 86.7513 72.1254 100.945C98.3784 117.104 131.371 107.982 155.534 120.606C184.058 135.523 179.265 238.559 178.607 244.292" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip1)"> - <path - d="M326.636 -20.9591C317.669 -11.4431 241.942 37.7297 219.79 20.7076C199.619 5.23066 190.643 -36.365 164.26 -54.1021C137.877 -71.8391 103.835 -49.5808 80.1656 -1.39804C56.9949 45.4166 60.0479 94.1034 83.0608 108.297C109.314 124.456 142.307 115.334 166.469 127.958C194.993 142.876 190.201 245.911 189.543 251.644" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip2)"> - <path - d="M336.73 -14.1734C327.763 -4.65746 252.036 44.5154 229.884 27.4933C209.713 12.0163 200.737 -29.5794 174.354 -47.3164C147.97 -65.0534 113.929 -42.7951 90.2595 5.3876C67.0887 52.2022 70.1417 100.889 93.1547 115.083C119.408 131.241 152.401 122.12 176.563 134.744C205.087 149.661 200.294 252.697 199.636 258.43" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip3)"> - <path - d="M347.666 -6.82185C338.698 2.6941 262.971 51.867 240.819 34.8448C220.648 19.3679 211.672 -22.2278 185.289 -39.9648C158.906 -57.7019 124.865 -35.4435 101.195 12.7392C78.0241 59.5538 81.077 108.241 104.09 122.434C130.343 138.593 163.336 129.471 187.499 142.095C216.023 157.013 211.23 260.049 210.572 265.782" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip4)"> - <path - d="M357.76 -0.0352234C348.792 9.48073 273.065 58.6536 250.913 41.6314C230.742 26.1545 221.766 -15.4412 195.383 -33.1782C169 -50.9153 134.959 -28.6569 111.289 19.5258C88.1181 66.3404 91.1711 115.027 114.184 129.221C140.437 145.38 173.43 136.258 197.593 148.882C226.117 163.799 221.324 266.835 220.666 272.568" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip5)"> - <path - d="M368.695 7.31585C359.727 16.8318 284.001 66.0046 261.848 48.9825C241.677 33.5055 232.701 -8.09014 206.318 -25.8272C179.935 -43.5642 145.894 -21.3059 122.224 26.8768C99.0534 73.6915 102.106 122.378 125.119 136.572C151.372 152.731 184.365 143.609 208.528 156.233C237.052 171.15 232.259 274.186 231.601 279.919" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip6)"> - <path - d="M378.789 14.103C369.821 23.6189 294.095 72.7917 271.942 55.7696C251.771 40.2927 242.795 -1.30303 216.412 -19.0401C190.029 -36.7771 155.988 -14.5188 132.318 33.6639C109.147 80.4786 112.2 129.165 135.213 143.359C161.466 159.518 194.459 150.396 218.622 163.02C247.146 177.937 242.353 280.973 241.695 286.706" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip7)"> - <path - d="M389.724 21.4535C380.756 30.9695 305.03 80.1423 282.877 63.1202C262.707 47.6432 253.731 6.04755 227.347 -11.6895C200.964 -29.4265 166.923 -7.16817 143.253 41.0145C120.083 87.8292 123.136 136.516 146.149 150.71C172.402 166.868 205.394 157.746 229.557 170.371C258.081 185.288 253.288 288.324 252.63 294.057" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip8)"> - <path - d="M400.659 28.8056C391.692 38.3215 315.965 87.4944 293.813 70.4723C273.642 54.9953 264.666 13.3996 238.283 -4.33742C211.9 -22.0744 177.858 0.18388 154.189 48.3666C131.018 95.1812 134.071 143.868 157.084 158.062C183.337 174.22 216.33 165.099 240.493 177.723C269.016 192.64 264.224 295.676 263.566 301.409" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - <g clipPath="url(#clip9)"> - <path - d="M411.595 36.1567C402.627 45.6726 326.9 94.8455 304.748 77.8233C284.577 62.3464 275.601 20.7507 249.218 3.01366C222.835 -14.7234 188.794 7.53495 165.124 55.7177C141.953 102.532 145.006 151.219 168.019 165.413C194.272 181.572 227.265 172.45 251.428 185.074C279.952 199.991 275.159 303.027 274.501 308.76" - stroke="#516679" - strokeWidth="1.5" - strokeLinecap="round" - strokeLinejoin="round" - /> - </g> - </g> - <defs> - <clipPath id="clip0"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 137.86 -150)" - fill="white" - /> - </clipPath> - <clipPath id="clip1"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 148.796 -142.648)" - fill="white" - /> - </clipPath> - <clipPath id="clip2"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 158.89 -135.862)" - fill="white" - /> - </clipPath> - <clipPath id="clip3"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 169.825 -128.511)" - fill="white" - /> - </clipPath> - <clipPath id="clip4"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 179.919 -121.725)" - fill="white" - /> - </clipPath> - <clipPath id="clip5"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 190.854 -114.374)" - fill="white" - /> - </clipPath> - <clipPath id="clip6"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 200.948 -107.586)" - fill="white" - /> - </clipPath> - <clipPath id="clip7"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 211.883 -100.236)" - fill="white" - /> - </clipPath> - <clipPath id="clip8"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 222.819 -92.8838)" - fill="white" - /> - </clipPath> - <clipPath id="clip9"> - <rect - width="216.908" - height="308.825" - transform="matrix(0.829892 0.557924 -0.446402 0.894832 233.754 -85.5327)" - fill="white" - /> - </clipPath> - </defs> - </svg>; diff --git a/frontend/website-redesign/src/components/svg/Icons.re b/frontend/website-redesign/src/components/svg/Icons.re deleted file mode 100644 index 95b317304b8..00000000000 --- a/frontend/website-redesign/src/components/svg/Icons.re +++ /dev/null @@ -1,148 +0,0 @@ -let technical = - <svg - width="63" - height="87" - viewBox="0 0 63 87" - fill="white" - xmlns="http://www.w3.org/2000/svg"> - <path - d="M62.3688 0.00100783H0.631966C0.279244 0.00100783 0 0.281466 0 0.635723V86.3653C0 86.7195 0.279244 87 0.631966 87H51.8354C51.9971 87 52.144 86.941 52.2616 86.8376L62.7893 77.4301C62.9216 77.312 62.9951 77.1349 62.9951 76.9577L63 0.634717C63 0.280459 62.7208 0 62.368 0L62.3688 0.00100783ZM1.26906 1.27533H61.7166V76.398L48.147 77.9232C47.9413 77.9527 47.7649 78.0708 47.662 78.2479C47.5591 78.425 47.5591 78.6465 47.6326 78.8236L50.8022 85.7267L1.26924 85.7316L1.26906 1.27533ZM52.0461 85.3271L49.1852 79.108L60.4381 77.8336L52.0461 85.3271Z" - fill="#344B65" - fillOpacity="0.7" - /> - <path - d="M31 61.9998L18.4 54.7282C18.1834 54.6199 18.1117 54.3316 18.2566 54.1516C18.3648 53.935 18.6531 53.8633 18.8331 54.0081L31.0001 60.9914L43.1684 53.9714C43.385 53.8631 43.6367 53.9349 43.745 54.1149C43.8533 54.3314 43.7816 54.5831 43.6016 54.6914L31 61.9998Z" - fill="black" - /> - <path - d="M43.8884 51.5969C43.8884 52.2677 42.8801 52.2677 42.8801 51.5969C42.8801 50.9247 43.8884 50.9247 43.8884 51.5969Z" - fill="black" - /> - <path - d="M43.8884 49.5081C43.8884 50.1802 42.8801 50.1802 42.8801 49.5081C42.8801 48.8359 43.8884 48.8359 43.8884 49.5081Z" - fill="black" - /> - <path - d="M43.8884 47.4202C43.8884 48.0924 42.8801 48.0924 42.8801 47.4202C42.8801 46.748 43.8884 46.748 43.8884 47.4202Z" - fill="black" - /> - <path - d="M43.8884 45.3318C43.8884 46.004 42.8801 46.004 42.8801 45.3318C42.8801 44.6596 43.8884 44.6596 43.8884 45.3318Z" - fill="black" - /> - <path - d="M43.8884 43.28C43.8884 43.9522 42.8801 43.9522 42.8801 43.28C42.8801 42.6078 43.8884 42.6078 43.8884 43.28Z" - fill="black" - /> - <path - d="M19.12 51.5969C19.12 52.2677 18.1117 52.2677 18.1117 51.5969C18.1117 50.9247 19.12 50.9247 19.12 51.5969Z" - fill="black" - /> - <path - d="M19.12 49.5081C19.12 50.1802 18.1117 50.1802 18.1117 49.5081C18.1117 48.8359 19.12 48.8359 19.12 49.5081Z" - fill="black" - /> - <path - d="M19.12 47.4202C19.12 48.0924 18.1117 48.0924 18.1117 47.4202C18.1117 46.748 19.12 46.748 19.12 47.4202Z" - fill="black" - /> - <path - d="M19.12 45.3318C19.12 46.004 18.1117 46.004 18.1117 45.3318C18.1117 44.6596 19.12 44.6596 19.12 45.3318Z" - fill="black" - /> - <path - d="M19.12 43.28C19.12 43.9522 18.1117 43.9522 18.1117 43.28C18.1117 42.6078 19.12 42.6078 19.12 43.28Z" - fill="black" - /> - <path - d="M31 48.0683C30.9283 48.0683 30.8566 48.0318 30.7834 47.9966L23.1165 43.6035C22.9731 43.5318 22.9 43.387 22.9 43.2435C22.9 43.1001 22.9717 42.9552 23.1165 42.8835L30.7849 38.4552C30.9283 38.3834 31.0732 38.3834 31.2166 38.4552L38.885 42.8835C39.0284 42.9552 39.1015 43.1001 39.1015 43.2435C39.1015 43.387 39.0298 43.5318 38.885 43.6035L31.2166 48.0319C31.1435 48.0684 31.0718 48.0684 31 48.0684L31 48.0683ZM24.1967 43.2436L31 47.1683L37.8033 43.245L31 39.3203L24.1967 43.2436Z" - fill="black" - /> - <path - d="M31 56.9967L22.9367 52.3167V43.2436C22.9367 42.9919 23.1167 42.8119 23.3684 42.8119C23.6201 42.8119 23.8001 42.9919 23.8001 43.2436V51.8469L31.0001 55.9883L38.2369 51.8116V43.2432C38.2369 42.9915 38.4169 42.8115 38.6686 42.8115C38.9203 42.8115 39.1003 42.9915 39.1003 43.2432V52.3149L31 56.9967Z" - fill="black" - /> - <path - d="M31 53.9367C30.7483 53.9367 30.5683 53.7567 30.5683 53.505V47.6719C30.5683 47.4202 30.7483 47.2402 31 47.2402C31.2517 47.2402 31.4317 47.4202 31.4317 47.6719V53.5403C31.4317 53.7569 31.2517 53.9369 31 53.9369V53.9367Z" - fill="black" - /> - <path - d="M28.2284 35.4684H22.4316C19.8033 35.4684 17.68 33.3449 17.68 30.7167C17.68 28.0884 19.8034 26 22.4316 26H28.2633C30.8916 26 33.0149 28.1234 33.0149 30.7516C33.0149 31.0034 32.8349 31.1834 32.5832 31.1834C32.3315 31.1834 32.1515 31.0034 32.1515 30.7516C32.1515 28.6282 30.4232 26.8633 28.2631 26.8633H22.4315C20.2715 26.8633 18.5431 28.5916 18.5431 30.7516C18.5431 32.9117 20.2714 34.64 22.4315 34.64H28.2631C28.5148 34.64 28.6948 34.82 28.6948 35.0717C28.6597 35.2883 28.4797 35.4683 28.228 35.4683L28.2284 35.4684Z" - fill="black" - /> - <path - d="M39.5684 35.4681H33.7716C31.1433 35.4681 29.02 33.3447 29.02 30.7165C29.02 30.4648 29.2 30.2848 29.4517 30.2848C29.7034 30.2848 29.8834 30.4648 29.8834 30.7165C29.8834 32.8399 31.6117 34.6049 33.7718 34.6049H39.6034C41.7634 34.6049 43.4918 32.8766 43.4918 30.7165C43.4918 28.5564 41.7283 26.8634 39.5685 26.8634H33.7718C33.5201 26.8634 33.3401 26.6834 33.3401 26.4317C33.3401 26.18 33.5201 26 33.7718 26H39.6034C42.1965 26 44.3201 28.1234 44.3201 30.7516C44.3201 33.3799 42.1967 35.4684 39.5685 35.4684L39.5684 35.4681Z" - fill="black" - /> - <path - d="M39.5684 32.6968C39.3167 32.6968 39.1367 32.5168 39.1367 32.2651C39.1367 32.0134 39.3167 31.8334 39.5684 31.8334C40.1801 31.8334 40.685 31.33 40.685 30.7168C40.685 30.1051 40.1815 29.6002 39.5684 29.6002H35.7167C35.465 29.6002 35.285 29.4202 35.285 29.1685C35.285 28.9168 35.465 28.7368 35.7167 28.7368H39.5684C40.6484 28.7368 41.5118 29.6002 41.5118 30.6802C41.5118 31.7602 40.6484 32.6968 39.5684 32.6968Z" - fill="black" - /> - <path - d="M25.9967 32.6969H22.1083C21.0283 32.6969 20.1649 31.8335 20.1649 30.7535C20.1649 29.6735 21.0283 28.8101 22.1083 28.8101C22.3601 28.8101 22.5401 28.9901 22.5401 29.2418C22.5401 29.4935 22.3601 29.6735 22.1083 29.6735C21.4966 29.6735 20.9918 30.1769 20.9918 30.7901C20.9918 31.4018 21.4952 31.9066 22.1083 31.9066H25.96C26.2117 31.9066 26.3917 32.0866 26.3917 32.3383C26.4283 32.5169 26.2117 32.6969 25.9965 32.6969L25.9967 32.6969Z" - fill="black" - /> - </svg>; - -let economic = - <svg - width="63" - height="87" - viewBox="0 0 63 87" - fill="none" - xmlns="http://www.w3.org/2000/svg"> - <path - d="M62.3688 0.00100783H0.631966C0.279244 0.00100783 0 0.281466 0 0.635723V86.3653C0 86.7195 0.279244 87 0.631966 87H51.8354C51.9971 87 52.144 86.941 52.2616 86.8376L62.7893 77.4301C62.9216 77.312 62.9951 77.1349 62.9951 76.9577L63 0.634717C63 0.280459 62.7208 0 62.368 0L62.3688 0.00100783ZM1.26906 1.27533H61.7166V76.398L48.147 77.9232C47.9413 77.9527 47.7649 78.0708 47.662 78.2479C47.5591 78.425 47.5591 78.6465 47.6326 78.8236L50.8022 85.7267L1.26924 85.7316L1.26906 1.27533ZM52.0461 85.3271L49.1852 79.108L60.4381 77.8336L52.0461 85.3271Z" - fill="#344B65" - fillOpacity="0.7" - /> - <path - d="M45.9456 32H16.2106C14.944 32 13.918 33.026 13.918 34.2926V50.6274C13.918 51.8926 14.944 52.92 16.2106 52.92H45.9456C47.2109 52.92 48.2383 51.8926 48.2383 50.6274V34.2926C48.2383 33.026 47.2109 32 45.9456 32ZM47.4745 45.4732L38.3987 45.4718C37.5548 45.4718 36.8698 44.7883 36.8698 43.9443V40.9754C36.8698 40.1314 37.5548 39.4465 38.3987 39.4465H47.4731L47.4745 45.4732ZM47.4745 38.6827H38.3987C37.1321 38.6827 36.1061 39.7086 36.1061 40.9753V43.9443C36.1061 45.2095 37.1321 46.2369 38.3987 46.2369H47.4731V50.6273C47.4731 51.0328 47.3126 51.4211 47.026 51.7077C46.7394 51.9943 46.3511 52.1548 45.9456 52.1548H16.2106C15.3666 52.1548 14.6817 51.4713 14.6817 50.6273V49.4036H21.177C21.3704 50.1487 22.0868 50.6359 22.8506 50.5385C23.6128 50.4411 24.186 49.792 24.186 49.0225C24.186 48.253 23.6128 47.6025 22.8506 47.5065C22.0868 47.4091 21.3704 47.8949 21.177 48.6399H14.6817V46.8818H26.9085L28.1881 48.0625H28.1895C28.062 48.2846 27.9946 48.5368 27.9946 48.7933C27.9946 49.4108 28.3672 49.9682 28.9375 50.2047C29.5092 50.4411 30.1669 50.3107 30.6039 49.8737C31.0409 49.4366 31.1713 48.7789 30.9349 48.2072C30.6985 47.6369 30.1411 47.2644 29.5221 47.2644C29.2369 47.2644 28.9561 47.3461 28.7168 47.5008L27.2108 46.1181H14.6818V45.0105H20.6613V43.4128C21.4164 43.2652 21.9451 42.5789 21.8936 41.8108C21.842 41.0428 21.2273 40.4338 20.4592 40.3866C19.6912 40.3407 19.0092 40.8737 18.8659 41.6289C18.724 42.3854 19.1653 43.1305 19.8975 43.367V44.2453H14.6817V39.6227H22.7059L27.6737 43.8253C27.5734 44.0302 27.5218 44.2552 27.5204 44.483C27.519 45.188 28.0004 45.8013 28.6853 45.9689C29.3702 46.1366 30.081 45.8142 30.4062 45.188C30.73 44.5618 30.5839 43.7952 30.0523 43.3324C29.5207 42.8696 28.7412 42.8295 28.1666 43.2364L23.9024 39.6227H25.3696C25.5617 40.3677 26.2781 40.8535 27.0418 40.756C27.8055 40.6586 28.3773 40.0095 28.3773 39.2401C28.3773 38.4706 27.8055 37.8215 27.0418 37.7241C26.2781 37.6266 25.5616 38.1124 25.3696 38.8575H19.0879V36.413H21.1699C21.3619 37.158 22.0783 37.6438 22.842 37.5464C23.6058 37.4489 24.1775 36.7998 24.1775 36.0304C24.1775 35.2609 23.6058 34.6118 22.842 34.5144C22.0783 34.4169 21.3619 34.9027 21.1699 35.6478H18.3227V38.8574H14.6818V34.2924C14.6818 33.4484 15.3667 32.7635 16.2107 32.7635H45.9457C46.3512 32.7635 46.7395 32.924 47.0261 33.2106C47.3126 33.4972 47.4731 33.8869 47.4731 34.2924L47.4745 38.6827ZM21.8805 49.0226C21.8805 48.7131 22.0668 48.4336 22.352 48.3161C22.6386 48.1972 22.9667 48.2631 23.1845 48.4824C23.4037 48.7002 23.4696 49.0283 23.3507 49.3148C23.2332 49.6 22.9538 49.7863 22.6443 49.7863C22.223 49.7863 21.8806 49.4438 21.8806 49.0226L21.8805 49.0226ZM28.7584 48.7933C28.7584 48.4838 28.9447 48.2044 29.2298 48.0869C29.5164 47.968 29.8445 48.0339 30.0623 48.2531C30.2815 48.4709 30.3475 48.799 30.2285 49.0856C30.111 49.3707 29.8316 49.557 29.5221 49.557C29.1009 49.557 28.7584 49.2146 28.7584 48.7933L28.7584 48.7933ZM20.3517 42.6792C20.0436 42.6792 19.7642 42.4929 19.6467 42.2077C19.5277 41.9212 19.5936 41.593 19.8114 41.3752C20.0307 41.156 20.3588 41.0901 20.6439 41.209C20.9305 41.3265 21.1168 41.6059 21.1168 41.9155C21.1168 42.1175 21.0351 42.3123 20.8918 42.4557C20.7486 42.599 20.5551 42.6792 20.3516 42.6792L20.3517 42.6792ZM28.2885 44.4631C28.2885 44.1551 28.4748 43.8756 28.7599 43.7581C29.0465 43.6392 29.3746 43.7051 29.5924 43.9229C29.8117 44.1421 29.8776 44.4703 29.7586 44.7554C29.6411 45.042 29.3617 45.2283 29.0522 45.2283C28.8502 45.2283 28.6553 45.1466 28.512 45.0033C28.3687 44.86 28.2885 44.6666 28.2885 44.4631L28.2885 44.4631ZM26.0833 39.2404C26.0833 38.9309 26.2696 38.6529 26.5562 38.5339C26.8413 38.4165 27.1694 38.4809 27.3887 38.7002C27.6065 38.918 27.6724 39.2475 27.5534 39.5327C27.4359 39.8178 27.1565 40.0041 26.8484 40.0041C26.4258 40.0041 26.0833 39.6631 26.0833 39.2404L26.0833 39.2404ZM21.8807 36.0307C21.8807 35.7212 22.0669 35.4432 22.3521 35.3243C22.6387 35.2068 22.9668 35.2713 23.1846 35.4905C23.4038 35.7083 23.4697 36.0379 23.3508 36.323C23.2333 36.6081 22.9539 36.7944 22.6444 36.7944C22.2231 36.7944 21.8807 36.4534 21.8807 36.0307L21.8807 36.0307Z" - fill="#344B65" - /> - <path - d="M39.0978 43.3597C39.4631 43.3612 39.7927 43.1419 39.9331 42.8052C40.075 42.4685 39.9976 42.0801 39.7411 41.8208C39.4832 41.5629 39.0949 41.4841 38.7567 41.6245C38.42 41.7635 38.1993 42.093 38.1993 42.457C38.1993 42.6963 38.2925 42.9255 38.4616 43.0946C38.6306 43.2637 38.8585 43.3597 39.0978 43.3597Z" - fill="#344B65" - /> - </svg>; -let page = - <svg - width="63" - height="87" - viewBox="0 0 63 87" - fill="none" - xmlns="http://www.w3.org/2000/svg"> - <path - d="M62.3688 0.00100783H0.631966C0.279244 0.00100783 0 0.281466 0 0.635723V86.3653C0 86.7195 0.279244 87 0.631966 87H51.8354C51.9971 87 52.144 86.941 52.2616 86.8376L62.7893 77.4301C62.9216 77.312 62.9951 77.1349 62.9951 76.9577L63 0.634717C63 0.280459 62.7208 0 62.368 0L62.3688 0.00100783ZM1.26906 1.27533H61.7166V76.398L48.147 77.9232C47.9413 77.9527 47.7649 78.0708 47.662 78.2479C47.5591 78.425 47.5591 78.6465 47.6326 78.8236L50.8022 85.7267L1.26924 85.7316L1.26906 1.27533ZM52.0461 85.3271L49.1852 79.108L60.4381 77.8336L52.0461 85.3271Z" - fill="#344B65" - fillOpacity="0.7" - /> - </svg>; - -let externalLink = - <svg - width="11" - height="11" - viewBox="0 0 11 11" - fill="none" - xmlns="http://www.w3.org/2000/svg"> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M4.33278 7.69396L5.19444 8.55563L8.25 5.50007L5.19444 2.44452L4.33278 3.30619L5.90944 4.88896H0V6.11119H5.90944L4.33278 7.69396ZM9.77778 0H1.22222C0.543889 0 0 0.55 0 1.22222V3.66667H1.22222V1.22222H9.77778V9.77778H1.22222V7.33333H0V9.77778C0 10.45 0.543889 11 1.22222 11H9.77778C10.45 11 11 10.45 11 9.77778V1.22222C11 0.55 10.45 0 9.77778 0Z" - /> - </svg>; - -let rightCarrot = - -<svg - width="10" - height="11" - viewBox="0 0 10 15" - fill="none" - xmlns="http://www.w3.org/2000/svg"> - <path - d="M0 11.208L6.48 7.248V7.08L0 3.12V0L9.648 6.144V8.16L0 14.352V11.208Z" - fill="#3D5878" - /> -</svg>; diff --git a/frontend/website-redesign/src/pages/Blog.re b/frontend/website-redesign/src/pages/Blog.re deleted file mode 100644 index 97ca3f177e5..00000000000 --- a/frontend/website-redesign/src/pages/Blog.re +++ /dev/null @@ -1,113 +0,0 @@ -module Style = { - open Css; - let title = - style([ - color(Theme.Colors.saville), - fontSize(`rem(2.25)), - letterSpacing(`rem(-0.0625)), - fontWeight(`semiBold), - textDecoration(`none), - Theme.Typeface.ibmplexsans, - media(Theme.MediaQuery.notMobile, [fontSize(`rem(3.))]), - hover([color(Theme.Colors.hyperlinkHover)]), - ]); - - let subtitle = - merge([Theme.Body.big, style([margin(`zero), fontWeight(`normal)])]); - - let postList = - style([ - listStyleType(`none), - maxWidth(`rem(43.)), - marginLeft(`auto), - marginRight(`auto), - ]); - - let postListItem = style([marginBottom(`rem(2.))]); - - let date = - style([ - Theme.Typeface.ibmplexsans, - fontSize(`rem(0.75)), - letterSpacing(`rem(0.0875)), - fontWeight(`normal), - color(Theme.Colors.slateAlpha(0.5)), - ]); - - let author = - style([ - Theme.Typeface.ibmplexsans, - fontSize(`rem(0.75)), - letterSpacing(`rem(0.0875)), - fontWeight(`normal), - color(Theme.Colors.slate), - textTransform(`uppercase), - ]); -}; - -[@react.component] -let make = (~posts) => { - <Page title="Coda Protocol Blog"> - <Wrapped> - <Next.Head> Markdown.katexStylesheet </Next.Head> - <ul className=Style.postList> - {React.array( - Array.map( - (post: ContentType.BlogPost.t) => { - <li key={post.slug} className=Style.postListItem> - <Next.Link - href="/blog/[slug]" - _as={"/blog/" ++ post.slug} - passHref=true> - <a className=Style.title> {React.string(post.title)} </a> - </Next.Link> - {ReactExt.fromOpt(Js.Undefined.toOption(post.subtitle), ~f=s => - <div className=Style.subtitle> {React.string(s)} </div> - )} - <Spacer height=1. /> - <div className=Style.author> - {React.string("by " ++ post.author)} - </div> - <div className=Style.date> {React.string(post.date)} </div> - <Spacer height=1.5 /> - <div className=Theme.Body.basic> - {React.string(post.snippet)} - </div> - <Spacer height=1. /> - <Next.Link - href="/blog/[slug]" - _as={"/blog/" ++ post.slug} - passHref=true> - <a className=Theme.Link.basic> - {React.string({js|Read more →|js})} - </a> - </Next.Link> - </li> - }, - posts, - ), - )} - </ul> - </Wrapped> - </Page>; -}; - -// TODO: pagination -Next.injectGetInitialProps(make, _ => { - Contentful.getEntries( - Lazy.force(Contentful.client), - { - "include": 0, - "content_type": ContentType.BlogPost.id, - "order": "-fields.date", - }, - ) - |> Promise.map((entries: ContentType.BlogPost.entries) => { - let posts = - Array.map( - (e: ContentType.BlogPost.entry) => e.fields, - entries.items, - ); - {"posts": posts}; - }) -}); diff --git a/frontend/website-redesign/src/pages/BlogPost.re b/frontend/website-redesign/src/pages/BlogPost.re deleted file mode 100644 index 21780683c60..00000000000 --- a/frontend/website-redesign/src/pages/BlogPost.re +++ /dev/null @@ -1,191 +0,0 @@ -module Style = { - open Css; - let title = - style([ - color(Theme.Colors.saville), - fontSize(`rem(3.)), - letterSpacing(`rem(-0.01)), - fontWeight(`bold), - textDecoration(`none), - Theme.Typeface.ibmplexsans, - ]); - - let author = Blog.Style.author; - let subtitle = Blog.Style.subtitle; - let date = Blog.Style.date; - - let wrapper = - style([ - padding2(~v=`rem(1.), ~h=`rem(1.)), - media( - Theme.MediaQuery.notMobile, - [maxWidth(`rem(48.)), marginLeft(`auto), marginRight(`auto)], - ), - ]); - - let mediaMedium = media("screen and (min-width:30em)"); - let mediaLarge = media("screen and (min-width:60em)"); - - let notLarge = selector(".not-large"); - let notMobile = selector(".not-mobile"); - let onlyLarge = selector(".large-only"); - let onlyMobile = selector(".mobile-only"); - - let blogContent = - style([ - position(`relative), - selector("p", [lineHeight(`abs(1.5))]), - selector( - "h2", - [ - Theme.Typeface.ddinexp, - fontSize(`rem(1.125)), - letterSpacing(`em(0.1666)), - textTransform(`uppercase), - marginBottom(`rem(1.75)), - marginTop(`rem(1.75)), - lineHeight(`abs(1.25)), - ], - ), - selector("img", [width(`percent(100.))]), - selector( - "hr", - [ - backgroundImage( - linearGradient( - `deg(90.), - [ - (`percent(25.), `rgb((27, 104, 191))), - (`percent(0.), `rgba((255, 255, 255, 0.))), - ], - ), - ), - backgroundSize(`size((`rem(0.25), `rem(0.125)))), - backgroundRepeat(`repeatX), - width(`percent(100.)), - height(`rem(0.125)), - border(`zero, `none, white), - marginTop(`rem(2.)), - marginBottom(`rem(2.)), - ], - ), - color(Theme.Colors.saville), - Theme.Typeface.ibmplexsans, - /* selector(".side-footnote-container", [height(`zero)]), */ - selector(".footnotes", [mediaLarge([display(`none)])]), - selector("a", Theme.Link.basicStyles), - selector("a.footnote-ref", [fontSize(`rem(0.5))]), - selector( - ".side-footnote", - [ - position(`absolute), - left(`percent(100.)), - width(`rem(10.)), - paddingLeft(`rem(1.)), - marginTop(`rem(-0.5)), - fontSize(`rem(0.75)), - display(`none), - mediaLarge([display(`block)]), - ], - ), - // Visibility (based on screen width) - notLarge([display(`block)]), - onlyMobile([display(`block)]), - notMobile([display(`none)]), - onlyLarge([display(`none)]), - selector("ul", [paddingLeft(`rem(1.))]), - selector("ul > li", [paddingLeft(`rem(0.5))]), - selector("ul > li > ul", [marginLeft(`rem(1.))]), - selector( - "img + em", - [ - fontSize(`px(13)), - color(`hex("757575")), - width(`percent(100.)), - display(`inlineBlock), - textAlign(`center), - ], - ), - mediaMedium([ - selector(".not-large, .not-mobile", [display(`block)]), - selector(".mobile-only, .large-only", [display(`none)]), - selector("ul", [marginLeft(`rem(-1.0)), paddingLeft(`rem(0.))]), - selector("ul > li", [paddingLeft(`rem(1.0))]), - selector("ul > li > ul", [marginLeft(`rem(1.))]), - ]), - mediaLarge([ - selector(".large-only, .not-mobile", [display(`block)]), - selector(".mobile-only, .not-large", [display(`none)]), - ]), - ]); -}; - -[@react.component] -let make = (~post: option(ContentType.BlogPost.t)) => { - switch (post) { - | None => - <Page title="Coda Protocol Blog"> - <div> {React.string("Couldn't find that blog post!")} </div> - <Next.Link href="/blog"> - <a> {React.string("Check out the rest of our posts instead")} </a> - </Next.Link> - </Page> - | Some( - ( - {title, subtitle, author, date, text: content, snippet, slug}: ContentType.BlogPost.t - ), - ) => - // Manually set the canonical route to remove .html - <Page title description=snippet route={"/blog/" ++ slug}> - <Next.Head> Markdown.katexStylesheet </Next.Head> - <div className=Style.wrapper> - <div className=Style.title id="title"> {React.string(title)} </div> - {ReactExt.fromOpt(Js.Undefined.toOption(subtitle), ~f=s => - <div className=Style.subtitle id="subtitle"> - {React.string(s)} - </div> - )} - <Spacer height=2.0 /> - <div className=Style.author id="author"> - {React.string("by " ++ author)} - </div> - <div className=Style.date id="date"> {React.string(date)} </div> - <Spacer height=2.0 /> - <div className=Style.blogContent id="content"> - <Markdown content /> - </div> - </div> - </Page> - }; -}; - -let cache: Js.Dict.t(option(ContentType.BlogPost.t)) = Js.Dict.empty(); - -Next.injectGetInitialProps(make, ({Next.query}) => { - switch (Js.Dict.get(query, "slug")) { - | Some(slug) => - let slug = ContentType.stripHTMLSuffix(slug); - switch (Js.Dict.get(cache, slug)) { - | Some(post) => Js.Promise.resolve({"post": post}) - | None => - Contentful.getEntries( - Lazy.force(Contentful.client), - { - "include": 0, - "content_type": ContentType.BlogPost.id, - "fields.slug": slug, - }, - ) - |> Promise.map((entries: ContentType.BlogPost.entries) => { - let post = - switch (entries.items) { - | [|item|] => Some(item.fields) - | _ => None - }; - Js.Dict.set(cache, slug, post); - {"post": post}; - }) - }; - | None => Js.Promise.resolve({"post": None}) - } -}); diff --git a/frontend/website-redesign/src/pages/Careers.re b/frontend/website-redesign/src/pages/Careers.re deleted file mode 100644 index ecda0833070..00000000000 --- a/frontend/website-redesign/src/pages/Careers.re +++ /dev/null @@ -1,381 +0,0 @@ -module Style = { - open Css; - let page = - style([ - maxWidth(`rem(60.)), - paddingLeft(`rem(1.25)), - paddingRight(`rem(1.25)), - margin(`auto), - ]); - let careersGallery = - style([ - display(`flex), - justifyContent(`spaceBetween), - flexDirection(`column), - marginBottom(`rem(1.5)), - ]); - let galleryRow = - style([ - display(`none), - media(Theme.MediaQuery.notMobile, [display(`inherit_)]), - selector( - "*", - [ - height(`rem(15.)), - boxSizing(`borderBox), - padding(`rem(0.3)), - unsafe("objectFit", "cover"), - ], - ), - ]); - - let galleryRowMobile = - style([media(Theme.MediaQuery.notMobile, [display(`none)])]); - - let text = style([maxWidth(`rem(50.)), margin(`auto)]); - let h2 = - merge([ - Theme.H2.basic, - style([ - fontWeight(`light), - color(Theme.Colors.teal), - fontSize(`rem(1.5)), - lineHeight(`rem(2.25)), - media( - Theme.MediaQuery.notMobile, - [fontSize(`rem(2.25)), lineHeight(`rem(3.0))], - ), - ]), - ]); - let headingItem = - style([ - display(`block), - media( - Theme.MediaQuery.notMobile, - [display(`flex), justifyContent(`spaceBetween)], - ), - ]); - let heading = - merge([ - Theme.H2.basic, - style([ - color(Theme.Colors.teal), - marginTop(`zero), - marginBottom(`zero), - ]), - ]); - let headingItemText = - merge([ - Theme.Body.basic, - style([ - marginTop(`rem(1.)), - marginBottom(`zero), - media( - Theme.MediaQuery.notMobile, - [width(`percent(65.)), marginTop(`zero)], - ), - ]), - ]); - let hr = - style([ - height(`px(2)), - backgroundColor(`hex("E5E9F2")), - border(`zero, `none, white), - ]); - - let flexBetween = style([display(`flex), justifyContent(`spaceBetween)]); - - let benefits = - style([ - display(`block), - media( - Theme.MediaQuery.notMobile, - [display(`flex), justifyContent(`spaceBetween)], - ), - ]); - - let benefitsList = style([marginTop(`rem(1.0)), flexDirection(`column)]); - let benefitTitle = - merge([ - Theme.H3.basic, - style([ - color(Theme.Colors.saville), - marginTop(`zero), - marginBottom(`zero), - width(`percent(30.)), - fontSize(`rem(1.)), - textAlign(`right), - paddingRight(`rem(2.)), - ]), - ]); - let benefitsListItems = - style([listStyleType(`none), width(`percent(70.))]); - let benefitDetails = - merge([ - Theme.Body.basic, - style([marginTop(`zero), marginBottom(`zero)]), - ]); - let jobsList = - style([ - display(`block), - padding2(~v=`zero, ~h=`rem(0.75)), - media( - Theme.MediaQuery.notMobile, - [ - display(`flex), - justifyContent(`spaceBetween), - padding2(~v=`zero, ~h=`zero), - ], - ), - ]); - let applyHeading = merge([heading, style([width(`percent(50.))])]); - let jobListItems = - style([ - listStyleType(`none), - width(`percent(100.)), - marginTop(`rem(2.0)), - media( - Theme.MediaQuery.notMobile, - [marginTop(`zero), width(`percent(50.))], - ), - ]); -}; -module ImageGallery = { - [@react.component] - let make = () => { - <div className=Style.careersGallery> - <div className=Style.galleryRow> - <img - src="/static/img/careers/group-outside.jpg" - className=Css.(style([width(`percent(35.))])) - /> - <img - src="/static/img/careers/group-in-house.jpg" - className=Css.(style([width(`percent(65.))])) - /> - </div> - <div className=Style.galleryRow> - <img - src="/static/img/careers/nacera-outside.jpg" - className=Css.(style([width(`percent(30.))])) - /> - <img - src="/static/img/careers/john-cooking.jpg" - className=Css.(style([width(`percent(37.))])) - /> - <img - src="/static/img/careers/vanishree-talking.jpg" - className=Css.(style([width(`percent(33.))])) - /> - </div> - <div className=Style.galleryRowMobile> - <img - src="/static/img/careers/group-outside.jpg" - className=Css.(style([width(`percent(100.))])) - /> - </div> - </div>; - }; -}; -module HeadingItem = { - [@react.component] - let make = (~h2, ~p, ~linkText=?, ~url=?) => { - <div className=Style.headingItem> - <h2 className=Style.heading> {React.string(h2)} </h2> - <p className=Style.headingItemText> - {React.string(p)} - {switch (linkText, url) { - | (Some(linkText), Some(url)) => - <a href=url className=Theme.Link.basic> - {React.string(" " ++ linkText)} - </a> - | _ => React.null - }} - </p> - </div>; - }; -}; - -module ValuesSection = { - [@react.component] - let make = () => { - <> - <HeadingItem - h2="Open Source" - p="We passionately believe in the open-source philosophy, and make our software free for the entire world to use." - linkText={js|Take a look →|js} - url="https://github.com/CodaProtocol/coda" - /> - <Spacer height=3.5 /> - <HeadingItem - h2="Collaboration" - p="The problems we face are novel and challenging. We take them on as a team." - /> - <Spacer height=3.5 /> - <HeadingItem - h2="Inclusion" - p="We're working on technologies with the potential to reimagine social structures. We believe it's important to incorporate diverse perspectives from conception through realization. " - /> - </>; - }; -}; - -module BenefitItem = { - [@react.component] - let make = (~title, ~details) => { - <div - className=Css.( - merge([Style.flexBetween, style([marginBottom(`rem(1.5))])]) - )> - <h3 className=Style.benefitTitle> {React.string(title)} </h3> - <ul className=Style.benefitsListItems> - {ReactExt.staticArray( - Array.map( - item => - <li className=Style.benefitDetails> {React.string(item)} </li>, - details, - ), - )} - </ul> - </div>; - }; -}; -module BenefitsSection = { - [@react.component] - let make = () => { - <div className=Style.benefits> - <h2 className=Style.heading> {React.string("Benefits")} </h2> - <div className=Style.benefitsList> - <BenefitItem - title="Healthcare" - details=[| - "We cover 100% of employee premiums for platinum healthcare plans with zero deductible, and 99% of vision and dental premiums", - |] - /> - <BenefitItem - title="401k" - details=[|"401k contribution matching up to 3% of salary"|] - /> - <BenefitItem - title="Education" - details=[| - "$750 annual budget for conferences of your choice (we cover company-related conferences)", - "Office library", - "Twice-a-week learning lunches", - |] - /> - <BenefitItem - title="Equipment" - details=[| - "Top-of-the-line laptop, $500 monitor budget and $500 peripheral budget", - |] - /> - <BenefitItem - title="Time off" - details=[| - "Unlimited vacation, with encouragement for employees to take off at least 14 days annually", - |] - /> - <BenefitItem - title="Meals" - details=[|"Healthy snacks and provided lunch twice a week"|] - /> - <BenefitItem - title="Other" - details=[| - "Relocation package", - "Parental leave", - "Commuting benefits", - "Bike-friendly culture", - "Take up to 1 day of PTO per year to volunteer", - "We match nonprofit donations up to $500 per year", - "...and many others!", - |] - /> - </div> - </div>; - }; -}; - -module ApplySection = { - [@react.component] - let make = (~posts) => { - <div className=Style.jobsList> - <h2 className=Style.applyHeading> {React.string("Apply")} </h2> - <ul className=Style.jobListItems> - {React.array( - Array.map( - (post: ContentType.JobPost.t) => { - <li key={post.slug}> - <Next.Link - href="/jobs/[slug]" - _as={"/jobs/" ++ post.slug} - passHref=true> - <a className=Theme.Link.basic> - {React.string(post.title)} - </a> - </Next.Link> - </li> - }, - posts, - ), - )} - </ul> - </div>; - }; -}; - -module CareersSpacer = { - [@react.component] - let make = () => { - <> - <Spacer height=3.5 /> - <hr className=Style.hr /> - <Spacer height=3.5 /> - </>; - }; -}; - -[@react.component] -let make = (~posts) => { - <Page title="Work with us!"> - <div className=Style.page> - <h1 className=Theme.H3.wings> {React.string("Work with us!")} </h1> - <Spacer height=2.0 /> - <ImageGallery /> - <div className=Style.text> - <h1 className=Style.h2> - {React.string( - {js|We're using cryptography and cryptocurrency to build computing systems that put people back in control of their digital\u00A0lives.|js}, - )} - </h1> - <CareersSpacer /> - <ValuesSection /> - <CareersSpacer /> - <BenefitsSection /> - <CareersSpacer /> - <ApplySection posts /> - <Spacer height=3.5 /> - </div> - </div> - </Page>; -}; - -Next.injectGetInitialProps(make, _ => { - Contentful.getEntries( - Lazy.force(Contentful.client), - { - "include": 0, - "content_type": ContentType.JobPost.id, - "order": "fields.title", - }, - ) - |> Promise.map((entries: ContentType.JobPost.entries) => { - let posts = - Array.map( - (e: ContentType.JobPost.entry) => e.fields, - entries.items, - ); - {"posts": posts}; - }) -}); diff --git a/frontend/website-redesign/src/pages/Demo.re b/frontend/website-redesign/src/pages/Demo.re new file mode 100644 index 00000000000..34b0d2acdba --- /dev/null +++ b/frontend/website-redesign/src/pages/Demo.re @@ -0,0 +1,78 @@ +module Styles = { + open Css; + let page = + style([ + marginLeft(`auto), + marginRight(`auto), + display(`flex), + width(`rem(50.)), + flexDirection(`column), + justifyContent(`spaceBetween), + alignContent(`spaceAround), + media(Theme.MediaQuery.tablet, [maxWidth(`rem(68.))]), + ]); +}; + +[@react.component] +let make = () => { + <Page title="Demo page of components"> + <div className=Styles.page> + <h1 className=Theme.Type.h1jumbo> {React.string("H1 Jumbo")} </h1> + <h1 className=Theme.Type.h1> {React.string("H1")} </h1> + <h2 className=Theme.Type.h2> {React.string("H2")} </h2> + <h3 className=Theme.Type.h3> {React.string("H3")} </h3> + <h4 className=Theme.Type.h4> {React.string("H4")} </h4> + <h5 className=Theme.Type.h4> {React.string("H5")} </h5> + <h6 className=Theme.Type.h4> {React.string("H6")} </h6> + <div className=Theme.Type.pageLabel> {React.string("Page label")} </div> + <div className=Theme.Type.label> {React.string("Label")} </div> + <div className=Theme.Type.buttonLabel> + {React.string("Button label")} + </div> + <a className=Theme.Type.link> {React.string("Link")} </a> + <a className=Theme.Type.navLink> {React.string("Nav Link")} </a> + <a className=Theme.Type.sidebarLink> {React.string("Sidebar Link")} </a> + <div className=Theme.Type.tooltip> {React.string("Tooltip")} </div> + <div className=Theme.Type.creditName> + {React.string("Credit name")} + </div> + <div className=Theme.Type.metadata> {React.string("Metadata")} </div> + <div className=Theme.Type.announcement> + {React.string("Announcement")} + </div> + <div className=Theme.Type.errorMessage> + {React.string("Error message")} + </div> + <div className=Theme.Type.pageSubhead> + {React.string( + "Page subhead / Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporus incididunt ut labore et dolore.", + )} + </div> + <div className=Theme.Type.sectionSubhead> + {React.string( + "Section Subhead / Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporus incididunt ut labore et.", + )} + </div> + <p className=Theme.Type.paragraph> + {React.string( + "Paragraph (Grotesk) / Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + )} + </p> + <p className=Theme.Type.paragraphSmall> + {React.string( + "Paragraph Small (Grotesk) / Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + )} + </p> + <p className=Theme.Type.paragraphMono> + {React.string( + "Paragraph (Mono) / Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmodorus temporus incididunt ut labore et dolore.", + )} + </p> + <p className=Theme.Type.quote> + {React.string( + "Quote / Lorem ipsum dolor sit amet, consectetur amet adipiscing elit, sed do eiusmod tempor.", + )} + </p> + </div> + </Page>; +}; diff --git a/frontend/website-redesign/src/pages/Developers.re b/frontend/website-redesign/src/pages/Developers.re deleted file mode 100644 index d3ae7427067..00000000000 --- a/frontend/website-redesign/src/pages/Developers.re +++ /dev/null @@ -1,195 +0,0 @@ -module Styles = { - open Css; - let page = - style([ - marginLeft(`auto), - marginRight(`auto), - media(Theme.MediaQuery.tablet, [maxWidth(`rem(50.66))]), - media(Theme.MediaQuery.desktop, [maxWidth(`rem(68.))]), - ]); - - let lineBreak = - style([ - height(px(2)), - borderTop(px(1), `dashed, Theme.Colors.marine), - borderLeft(`zero, solid, transparent), - borderBottom(px(1), `dashed, Theme.Colors.marine), - ]); - - let heroImage = - style([ - display(`none), - media( - Theme.MediaQuery.tablet, - [display(`flex), marginLeft(`rem(1.))], - ), - ]); - - let header = - style([ - display(`flex), - flexDirection(`column), - width(`percent(100.)), - color(Theme.Colors.saville), - textAlign(`center), - margin2(~v=rem(3.5), ~h=`zero), - ]); - - let heroRow = - style([ - display(`flex), - flexDirection(`column), - justifyContent(`spaceBetween), - alignItems(`center), - media(Theme.MediaQuery.tablet, [flexDirection(`row)]), - ]); - - let heroText = - merge([ - header, - style([ - maxWidth(`px(500)), - marginLeft(`zero), - textAlign(`left), - color(Theme.Colors.midnight), - ]), - ]); - - let heroHeading = merge([Theme.H1.hero, style([marginTop(`rem(1.53))])]); - - let heroCopy = merge([Theme.Body.basic]); - - let heroH3 = - merge([ - Theme.H3.basic, - style([ - textAlign(`left), - fontWeight(`normal), - color(Theme.Colors.midnight), - ]), - ]); - - let ctaButton = - merge([ - Theme.Body.basic_semibold, - style([ - width(`rem(14.)), - height(`rem(3.)), - backgroundColor(Theme.Colors.hyperlink), - borderRadius(`px(6)), - textDecoration(`none), - color(white), - padding2(~v=`px(12), ~h=`px(24)), - textAlign(`center), - alignSelf(`center), - hover([backgroundColor(Theme.Colors.hyperlinkHover)]), - media( - Theme.MediaQuery.tablet, - [marginLeft(`rem(0.)), alignSelf(`flexStart)], - ), - ]), - ]); - - let buttonRow = - style([ - display(`grid), - gridTemplateColumns([`repeat((`num(1), `rem(21.25)))]), - gridTemplateRows([`repeat((`num(1), `rem(14.25)))]), - media( - Theme.MediaQuery.tablet, - [ - gridTemplateColumns([`repeat((`num(2), `rem(23.8)))]), - gridTemplateRows([`repeat((`num(2), `rem(12.5)))]), - ], - ), - media( - Theme.MediaQuery.desktop, - [ - gridTemplateColumns([`repeat((`num(2), `rem(32.5)))]), - gridTemplateRows([`repeat((`num(2), `rem(11.5)))]), - ], - ), - gridRowGap(rem(2.5625)), - gridColumnGap(rem(3.)), - justifyContent(`center), - marginLeft(`auto), - marginRight(`auto), - marginTop(rem(5.18)), - marginBottom(rem(3.)), - ]); -}; - -let description = "Coda is 100% open-source, built for and by community members like yourself. Find resources on how to join the network as a node operator, begin contributing code, and stay up to date on developer tooling and grants."; - -[@react.component] -let make = () => { - <Page title="Coda Developer Portal" description> - <Wrapped> - <div className=Styles.page> - <div className=Styles.heroRow> - <div className=Styles.heroText> - <h1 className=Styles.heroHeading> - {React.string("Coda Developer Portal")} - </h1> - <Spacer height=1. /> - <p className=Styles.heroCopy> - {React.string( - "Coda makes it dead simple for node operators, developers, and entrepreneurs to use cryptocurrencies. Deploy nodes, write code, and access your funds on full nodes that can live anywhere -- in your phone, or even in a web browser.", - )} - </p> - <p className=Styles.heroCopy> - {React.string( - "Coda is 100% open-source, built for and by community members like yourself. Find resources below on how to join the network as a node operator, begin contributing code, and stay up to date on developer tooling and grants.", - )} - </p> - <Spacer height=1. /> - <a href="/docs/getting-started" className=Styles.ctaButton> - {React.string({js| Get Started →|js})} - </a> - </div> - <Svg - link="/static/img/Developers.svg" - dims=(29.75, 25.76) - alt="Collage of developer images" - className=Styles.heroImage - /> - </div> - <br /> - <hr className=Styles.lineBreak /> - <div> - <div className=Styles.buttonRow> - <HoverCard - heading={React.string({js| Testnet Docs |js})} - text={React.string( - "Learn how to install Coda and connect to the network.", - )} - href="/docs/getting-started" - /> - <HoverCard - heading={React.string({js| Grants |js})} - text={React.string( - "Receive funding to work on Coda related projects and research.", - )} - href="https://github.com/CodaProtocol/coda-grants" - /> - <HoverCard - heading={React.string({js| Developer Docs |js})} - text={React.string( - "Contribute to Coda source code and core products.", - )} - href="/docs/developers" - /> - // TODO: Put SDK waitlist link here - <HoverCard - heading={React.string({js| Coda SDK |js})} - text={React.string( - "Sign up for the Coda SDK waitlist to integrate digital payments into your app.", - )} - href="https://docs.google.com/forms/d/e/1FAIpQLSc1obbB_0ON8Ptfhc56jZ_NfwzxhmNtMuVuLNDqoO8Y46eWiw/viewform?usp=sf_link" - /> - </div> - </div> - </div> - </Wrapped> - </Page>; -}; diff --git a/frontend/website-redesign/src/pages/Docs.re b/frontend/website-redesign/src/pages/Docs.re deleted file mode 100644 index 104478ba646..00000000000 --- a/frontend/website-redesign/src/pages/Docs.re +++ /dev/null @@ -1,99 +0,0 @@ -// This is the layout for the docs MDX pages - -module Style = { - open! Css; - - let content = - style([ - maxWidth(`rem(43.)), - media(Theme.MediaQuery.notMobile, [marginLeft(`rem(1.))]), - selector( - "p > code, li > code", - [ - boxSizing(`borderBox), - padding2(~v=`px(2), ~h=`px(6)), - backgroundColor(Theme.Colors.slateAlpha(0.05)), - borderRadius(`px(4)), - ], - ), - ]); - - let page = - style([ - display(`block), - justifyContent(`center), - margin(`auto), - marginTop(`rem(4.)), - padding2(~v=`zero, ~h=`rem(2.)), - media(Theme.MediaQuery.full, [display(`flex)]), - media(Theme.MediaQuery.notMobile, [padding2(~v=`zero, ~h=`rem(3.))]), - ]); - - let editLink = - style([ - media(Theme.MediaQuery.tablet, [position(`relative), float(`right)]), - display(`flex), - alignItems(`center), - marginTop(`rem(3.25)), - marginBottom(`rem(0.5)), - hover([color(Theme.Colors.hyperlinkHover)]), - ...Theme.Link.basicStyles, - ]); -}; - -module EditLink = { - [@react.component] - let make = (~route) => { - <a - name="Edit Link" - target="_blank" - href={ - "https://github.com/CodaProtocol/coda/edit/develop/frontend/website/pages" - ++ route - ++ ".mdx" - } - className=Style.editLink> - <svg - fill="currentColor" - xmlns="http://www.w3.org/2000/svg" - width="16" - height="16" - viewBox="0 0 24 24"> - <path - d="M7.127 22.562l-7.127 1.438 1.438-7.128 5.689 5.69zm1.414-1.414l11.228-11.225-5.69-5.692-11.227 11.227 5.689 5.69zm9.768-21.148l-2.816 2.817 5.691 5.691 2.816-2.819-5.691-5.689z" - /> - </svg> - <span className=Css.(style([marginLeft(`rem(0.25))]))> - {React.string("Edit")} - </span> - </a>; - }; -}; - -type metadata = {title: string}; - -[@react.component] -let make = (~metadata, ~children) => { - let router = Next.Router.useRouter(); - let currentSlug = - Js.String.replaceByRe(Js.Re.fromString("^/docs/?"), "", router.route); - <Page title={metadata.title}> - <Next.Head> - <link rel="stylesheet" href="/static/css/a11y-light.css" /> - </Next.Head> - <div className=Style.page> - <DocsSideNav currentSlug /> - <div className=Style.content> - <EditLink route={router.route} /> - <Next.MDXProvider components={DocsComponents.allComponents()}> - children - </Next.MDXProvider> - </div> - </div> - </Page>; -}; - -let default = - (. metadata) => - (. props: {. "children": React.element}) => - make({"metadata": metadata, "children": props##children}); diff --git a/frontend/website-redesign/src/pages/Genesis.re b/frontend/website-redesign/src/pages/Genesis.re deleted file mode 100644 index a486f351e89..00000000000 --- a/frontend/website-redesign/src/pages/Genesis.re +++ /dev/null @@ -1,422 +0,0 @@ -module Styles = { - open Css; - let page = - style([ - marginLeft(`auto), - marginRight(`auto), - media(Theme.MediaQuery.tablet, [maxWidth(`rem(68.))]), - ]); - - let lineBreak = - style([ - height(px(2)), - borderTop(px(1), `dashed, Theme.Colors.marine), - borderLeft(`zero, solid, transparent), - borderBottom(px(1), `dashed, Theme.Colors.marine), - ]); - - let heroImage = - style([ - display(`none), - media( - Theme.MediaQuery.tablet, - [display(`flex), marginRight(`rem(-6.)), marginLeft(`rem(1.))], - ), - ]); - - let header = - style([ - display(`flex), - flexDirection(`column), - width(`percent(100.)), - color(Theme.Colors.saville), - textAlign(`center), - ]); - - let heroRow = - style([ - display(`flex), - flexDirection(`column), - justifyContent(`spaceBetween), - alignItems(`center), - media( - Theme.MediaQuery.tablet, - [ - flexDirection(`row), - alignItems(`flexEnd), - padding2(~v=`rem(3.5), ~h=`zero), - ], - ), - ]); - - let heroText = - merge([ - header, - style([ - maxWidth(`px(500)), - marginLeft(`zero), - textAlign(`left), - color(Theme.Colors.midnight), - ]), - ]); - - let heroHeading = - merge([ - Theme.H1.hero, - style([fontWeight(`semiBold), marginTop(`rem(1.53))]), - ]); - - let heroCopy = merge([Theme.Body.basic]); - - let heroH3 = - merge([ - Theme.H3.basic, - style([ - textAlign(`left), - fontWeight(`semiBold), - color(Theme.Colors.marine), - ]), - ]); - - let ctaButton = - merge([ - Theme.Body.basic_semibold, - style([ - width(`rem(14.)), - height(`rem(3.)), - backgroundColor(Theme.Colors.clover), - borderRadius(`px(6)), - textDecoration(`none), - color(white), - padding2(~v=`px(12), ~h=`px(24)), - textAlign(`center), - alignSelf(`center), - hover([backgroundColor(Theme.Colors.jungle)]), - media( - Theme.MediaQuery.tablet, - [marginLeft(`rem(0.)), alignSelf(`flexStart)], - ), - ]), - ]); - - let whitePaperButtonRow = - style([ - display(`grid), - gridTemplateColumns([`percent(100.)]), - gridTemplateRows([auto]), - gridRowGap(`rem(0.7)), - media( - Theme.MediaQuery.notMobile, - [display(`flex), flexDirection(`row)], - ), - ]); - - let stepRowFlex = style([display(`flex), justifyContent(`flexStart)]); - let stepRow = - style([ - display(`grid), - gridTemplateColumns([`repeat((`num(1), `rem(20.)))]), - gridTemplateRows([auto]), - gridRowGap(`rem(1.0)), - gridColumnGap(`rem(2.43)), - margin(`auto), - media( - Theme.MediaQuery.tablet, - [ - gridTemplateColumns([`repeat((`num(3), `rem(17.5)))]), - gridColumnGap(`rem(1.43)), - margin(`zero), - ], - ), - media( - Theme.MediaQuery.desktop, - [ - gridTemplateColumns([`repeat((`num(3), `rem(20.)))]), - gridColumnGap(`rem(2.43)), - ], - ), - ]); - - let textBlock = style([maxWidth(`rem(43.75)), width(`percent(100.))]); - let legalListBlock = - style([maxWidth(`rem(43.)), width(`percent(100.))]); - let legalListItem = style([marginBottom(`rem(0.25))]); - let legalListList = style([marginLeft(`rem(1.625))]); - let textBlockHeading = - style([ - Theme.Typeface.ibmplexsans, - color(Theme.Colors.saville), - fontWeight(`medium), - fontSize(`rem(2.)), - ]); - - let profileRow = - style([ - display(`flex), - flexDirection(`column), - justifyContent(`center), - margin(`auto), - selector("> :last-child", [marginBottom(`zero), marginRight(`zero)]), - media( - Theme.MediaQuery.tablet, - [justifyContent(`flexStart), flexDirection(`row)], - ), - ]); - - let profile = - style([ - marginRight(`rem(2.)), - marginBottom(`rem(5.)), - media(Theme.MediaQuery.tablet, [marginBottom(`zero)]), - ]); -}; - -[@react.component] -let make = (~profiles) => { - <Page - title="Genesis" - description="Join Genesis. Become one of 1000 community members to receive a grant of 66,000 coda tokens. You'll participate in activities that will strengthen the Coda network and community."> - <Wrapped> - <div className=Styles.page> - <div className=Styles.heroRow> - <div className=Styles.heroText> - <h1 className=Styles.heroHeading> {React.string("Genesis")} </h1> - <Spacer height=2. /> - <h3 className=Styles.heroH3> - {React.string( - "Become one of 1000 community members to receive a token grant.", - )} - </h3> - <Spacer height=1. /> - <p className=Styles.heroCopy> - {React.string( - "You'll complete challenges on testnet, learn how to operate the protocol, receive public recognition on our leaderboard, and help to strengthen the Coda network and community.", - )} - </p> - <Spacer height=2. /> - <a - href=" https://forms.gle/Eer4yM1gb5SvLCk79" - target="_blank" - className=Styles.ctaButton> - {React.string({js| Apply Now |js})} - </a> - </div> - <Image - name="/static/img/genesisHero" - alt="Genesis Program hero image with a light blue theme." - className=Styles.heroImage - /> - </div> - <Spacer height=3. /> - <h1 className=Styles.textBlockHeading> - {React.string("Become a Genesis Founding Member")} - </h1> - <div className=Styles.textBlock> - <p className=Styles.heroCopy> - {React.string( - "Becoming a Genesis founding member is the highest honor in the Coda community. - You'll have an opportunity to strengthen and harden the protocol, create tooling - and documentation, and build the community.", - )} - </p> - <Spacer height=0.25 /> - <p className=Styles.heroCopy> - {React.string( - "When the protocol launches in mainnet, you will be the backbone of robust, - decentralized participation. Together, we will enable the first blockchain - that is truly decentralized at scale. ", - )} - </p> - </div> - <Spacer height=3. /> - <div className=Styles.stepRowFlex> - <div className=Styles.stepRow> - <StepButton - labelStep="Step 1: " - label="Apply Now" - image="/static/img/ApplyCircle.svg" - buttonLabel="Apply" - buttonLink=" https://forms.gle/Eer4yM1gb5SvLCk79" - target="_blank" - /> - <StepButton - labelStep="Step 2: " - label="Join Discord" - image="/static/img/DiscordCircle.svg" - buttonLabel="Join" - buttonLink="http://bit.ly/GenesisDiscord" - target="_blank" - /> - <StepButton - labelStep="Step 3: " - label="Participate in Testnet" - image="/static/img/TestnetCircle.svg" - buttonLabel="Get Started" - buttonLink="http://bit.ly/GenesisTestnet" - /> - </div> - </div> - <Spacer height=7. /> - <h1 className=Styles.textBlockHeading> - {React.string("Meet the Genesis Founding Members")} - </h1> - <div className=Styles.textBlock> - <p className=Styles.heroCopy> - {React.string( - "Meet a few of the 40 members who are part of Genesis Cohort 1. These community members are crucial to strengthening the Coda network. They are the backbone of the global Coda community.", - )} - </p> - </div> - <Spacer height=4. /> - <div className=Styles.profileRow> - {React.array( - Array.map( - (p: ContentType.GenesisProfile.t) => { - <div className=Styles.profile> - <MemberProfile - key={p.name} - name={p.name} - photo={p.profilePhoto.fields.file.url} - quote={"\"" ++ p.quote ++ "\""} - location={p.memberLocation} - twitter={p.twitter} - github={p.github} - blogPost={p.blogPost.fields.slug} - /> - </div> - }, - profiles, - ), - )} - </div> - <Spacer height=4. /> - <h1 className=Styles.textBlockHeading> {React.string("Details")} </h1> - <Spacer height=1. /> - <div className=Styles.legalListBlock> - <p className=Styles.heroCopy> - {React.string( - "Up to 1000 members will be selected from our testnet community to receive a distribution of 66,000 tokens as founding members of Genesis.", - )} - </p> - <ul className={Css.merge([Styles.heroCopy, Styles.legalListList])}> - <li className=Styles.legalListItem> - {React.string( - "At mainnet launch, 6.6% of the protocol will be distributed in this manner.", - )} - </li> - <li className=Styles.legalListItem> - {React.string( - "Distributions will be locked up for up to four years after mainnet launch.", - )} - </li> - <li className=Styles.legalListItem> - {React.string( - "Starting on mainnet launch, Genesis founding members will have to participate as block producers and continuously stake all tokens received from the Genesis Program.", - )} - </li> - <li className=Styles.legalListItem> - {React.string( - "New Genesis founding members will be announced on a rolling basis.", - )} - </li> - <li className=Styles.legalListItem> - {React.string( - "To learn more about the selection criteria and requirements, see the ", - )} - <Next.Link href="/tcGenesis"> - <a className=Theme.Link.basic> - {React.string("Terms and Conditions.")} - </a> - </Next.Link> - </li> - </ul> - </div> - <Spacer height=4.25 /> - <h1 className=Styles.textBlockHeading> - {React.string("Resources")} - </h1> - <Spacer height=2. /> - <div className=Styles.whitePaperButtonRow> - <WhitepaperButton - label="Technical whitepaper" - sigil=Icons.technical - href="https://eprint.iacr.org/2020/352.pdf" - /> - <Spacer width=2.5 /> - <WhitepaperButton - label="Economics whitepaper" - sigil=Icons.economic - href="/static/pdf/economicsWP.pdf" - /> - </div> - <Spacer height=1.5 /> - <a - className=Theme.Link.basic - href="https://forums.codaprotocol.com/t/genesis-token-program-faq/270"> - {React.string("FAQ")} - </a> - <Spacer height=1. /> - <Next.Link href="/tcGenesis"> - <a className=Theme.Link.basic> - {React.string("Terms and Conditions ")} - </a> - </Next.Link> - <Spacer height=5.65 /> - <h1 className=Styles.textBlockHeading> - {React.string("About Coda Protocol")} - </h1> - <div className=Styles.textBlock> - <Spacer height=1.875 /> - <p className=Styles.heroCopy> - <a className=Theme.Link.basic href="https://codaprotocol.com"> - {React.string("Coda Protocol")} - </a> - {React.string( - ", the world's lightest blockchain, provides a foundation for the decentralized digital economy (Web 3.0), - offering scalability to thousands of transactions per second, millions of users, and years of transaction - history without sacrificing security. By utilizing recursive zk-SNARKs, the Coda blockchain always stays - the same size" - ++ {js|—|js} - ++ "about 20 kilobytes (the size of a few tweets). Recursive zk-SNARKs allow nodes to rapidly - share and update proof of the correct blockchain state across the network. This breakthrough application - of zk-SNARKs solves the issues of scalability and high barrier to entry for nodes that have plagued - legacy blockchains to-date. By making it easier for nodes to participate, Coda improves decentralization - and therefore security of the network. The Coda blockchain can be easily accessed from any device, - including phones and browsers, and can be seamlessly integrated into new decentralized applications (dapps).", - )} - </p> - <Spacer height=1.3 /> - <p className=Styles.heroCopy> - {React.string("For regular updates on Coda, follow us on ")} - <a - className=Theme.Link.basic - href="https://twitter.com/codaprotocol?lang=en"> - {React.string("Twitter")} - </a> - {React.string(".")} - </p> - </div> - </div> - </Wrapped> - </Page>; -}; - -Next.injectGetInitialProps(make, _ => { - Contentful.getEntries( - Lazy.force(Contentful.client), - { - "include": 1, - "content_type": ContentType.GenesisProfile.id, - "order": "-fields.publishDate", - "limit": 3, - }, - ) - |> Promise.map((entries: ContentType.GenesisProfile.entries) => { - let profiles = - Array.map( - (e: ContentType.GenesisProfile.entry) => e.fields, - entries.items, - ); - {"profiles": profiles}; - }) -}); diff --git a/frontend/website-redesign/src/pages/Index.re b/frontend/website-redesign/src/pages/Index.re index 155fd3192dd..8a75148024e 100644 --- a/frontend/website-redesign/src/pages/Index.re +++ b/frontend/website-redesign/src/pages/Index.re @@ -5,47 +5,12 @@ module Styles = { }; [@react.component] -let make = (~links) => { - <Page title="Coda Cryptocurrency Protocol" footerColor=Theme.Colors.navyBlue> +let make = () => { + <Page title="Coda Cryptocurrency Protocol" footerColor=Theme.Colors.orange> <div className=Styles.page> - <section - className=Css.( - style([ - marginTop(`rem(-0.3125)), - media(Theme.MediaQuery.full, [marginTop(`rem(-0.25))]), - ]) - )> - <Wrapped> - <HeroSection /> - <CryptoAppsSection /> - <InclusiveSection /> - <SustainableSection /> - <GetInvolvedSection links /> - </Wrapped> - <div - className=Css.( - style([ - backgroundColor(Theme.Colors.navyBlue), - marginTop(`rem(13.)), - ]) - )> - <Wrapped> <TeamSection /> <InvestorsSection /> </Wrapped> - </div> - </section> + <h1 className=Theme.Type.h1jumbo> + {React.string("This is the homepage")} + </h1> </div> </Page>; }; - -Next.injectGetInitialProps(make, _ => { - Contentful.getEntries( - Lazy.force(Contentful.client), - {"include": 0, "sys.id": "15yfHjBude059Ak1YXgW9w"} // Entry ID of Knowledge Base file - ) - |> Promise.map((entries: ContentType.KnowledgeBase.entries) => { - let links = Array.map( - (e: ContentType.KnowledgeBase.entry) => e.fields.links, - entries.items, - )[0]; - {"links": links}; - }) -}); diff --git a/frontend/website-redesign/src/pages/JobPost.re b/frontend/website-redesign/src/pages/JobPost.re deleted file mode 100644 index d4ecee9f18f..00000000000 --- a/frontend/website-redesign/src/pages/JobPost.re +++ /dev/null @@ -1,161 +0,0 @@ -module Style = { - open Css; - let title = merge([Theme.H1.hero, style([color(Theme.Colors.saville)])]); - - let wrapper = - style([ - padding2(~v=`rem(1.), ~h=`rem(1.)), - media( - Theme.MediaQuery.notMobile, - [maxWidth(`rem(48.)), marginLeft(`auto), marginRight(`auto)], - ), - ]); - - let jobContent = - style([ - position(`relative), - selector("p", [fontSize(`rem(1.125)), lineHeight(`rem(1.875))]), - selector( - "h2", - [ - Theme.Typeface.ibmplexsans, - fontSize(`rem(1.68)), - marginBottom(`rem(1.75)), - marginTop(`rem(1.75)), - lineHeight(`abs(1.25)), - ], - ), - selector("img", [width(`percent(100.))]), - selector( - "hr", - [ - backgroundImage( - linearGradient( - `deg(90.), - [ - (`percent(25.), `rgb((27, 104, 191))), - (`percent(0.), `rgba((255, 255, 255, 0.))), - ], - ), - ), - backgroundSize(`size((`rem(0.25), `rem(0.125)))), - backgroundRepeat(`repeatX), - width(`percent(100.)), - height(`rem(0.125)), - border(`zero, `none, white), - marginTop(`rem(2.)), - marginBottom(`rem(2.)), - ], - ), - color(Theme.Colors.saville), - Theme.Typeface.ibmplexsans, - selector( - "a", - [ - fontSize(`rem(1.125)), - lineHeight(`rem(1.875)), - ...Theme.Link.basicStyles, - ], - ), - selector( - "ul", - [ - paddingLeft(`rem(1.)), - fontSize(`rem(1.125)), - lineHeight(`rem(1.875)), - ], - ), - selector("ul > li", [paddingLeft(`rem(0.5))]), - selector("ul > li > ul", [marginLeft(`rem(1.))]), - ]); -}; - -[@react.component] -let make = (~post: option(ContentType.JobPost.t)) => { - switch (post) { - | None => - <Page title="Work with us!"> - <div> {React.string("Couldn't find that job post!")} </div> - <Next.Link href="/careers"> - <a> {React.string("Check out the rest of our jobs instead")} </a> - </Next.Link> - </Page> - | Some(({title, jobDescription: content, slug}: ContentType.JobPost.t)) => - // Manually set the canonical route to remove .html - <Page title route={"/jobs/" ++ slug}> - <Next.Head> Markdown.katexStylesheet </Next.Head> - <div className=Style.wrapper> - <div className=Style.title> {React.string(title)} </div> - <Spacer height=2.0 /> - <div className=Style.jobContent> - <Markdown content /> - <Spacer height=1.0 /> - <h2> {React.string("About Us")} </h2> - <p> - {React.string( - "O(1) Labs is aiming to develop the first cryptocurrency protocol that can deliver on the promise of supporting real-world applications and widespread use. Our team is based in San Francisco, and we are funded by top investors (including Polychain, Metastable, Max Levchin, and Naval Ravikant).", - )} - </p> - <p> - {React.string( - "We're bringing Coda Protocol to market, a cryptocurrency that compresses the blockchain from hundreds of gigabytes down to the size of a few tweets. It can scale to thousands of transactions per second and millions of users while remaining decentralized enough for cellphones to be fully verifying nodes.", - )} - </p> - <p> - {React.string( - "We're working on technologies with the potential to reimagine social structures. We believe it's important to incorporate diverse perspectives from conception through realization.", - )} - </p> - <p> - {React.string( - "This is a chance to join a small, collaborative team and have a ton of independence while working on fascinating cross-disciplinary problems that span cryptography, engineering, product design, economics, and sociology. We also offer competitive compensation both in salary and equity as well as top-of-the-market benefits.", - )} - </p> - <p> - {React.string( - "If you'd be interested in talking further, please get in touch by sending an email with your resume and the subject \"" - ++ title - ++ " Applicant\" to ", - )} - <a - href={ - "mailto:jobs@o1labs.org?subject=\"" ++ title ++ " Applicant\"" - }> - {React.string("jobs@o1labs.org.")} - </a> - </p> - <p> - {React.string( - "We are committed to building a diverse, inclusive company. People of color, LGBTQ individuals, women, and people with disabilities are strongly encouraged to apply.", - )} - </p> - </div> - </div> - </Page> - }; -}; - -Next.injectGetInitialProps(make, ({Next.query}) => { - switch (Js.Dict.get(query, "slug")) { - | Some(slug) => - let slug = ContentType.stripHTMLSuffix(slug); - Contentful.getEntries( - Lazy.force(Contentful.client), - { - "include": 0, - "content_type": ContentType.JobPost.id, - "fields.slug": slug, - }, - ) - |> Promise.map((entries: ContentType.JobPost.entries) => { - let post = - switch (entries.items) { - | [|item|] => Some(item.fields) - | _ => None - }; - {"post": post}; - }); - - | None => Promise.return({"post": None}) - } -}); diff --git a/frontend/website-redesign/src/pages/LeaderboardPage.re b/frontend/website-redesign/src/pages/LeaderboardPage.re deleted file mode 100644 index a951b7853ef..00000000000 --- a/frontend/website-redesign/src/pages/LeaderboardPage.re +++ /dev/null @@ -1,247 +0,0 @@ -module Styles = { - open Css; - let page = - style([ - maxWidth(`rem(58.0)), - margin(`auto), - media(Theme.MediaQuery.tablet, [maxWidth(`rem(89.))]), - ]); - let filters = - style([ - display(`flex), - flexDirection(`column), - media(Theme.MediaQuery.notMobile, [flexDirection(`row)]), - justifyContent(`spaceBetween), - width(`percent(100.)), - marginTop(`rem(2.)), - ]); - let searchBar = - style([ - display(`flex), - flexDirection(`column), - marginTop(`rem(3.)), - media( - Theme.MediaQuery.notMobile, - [marginTop(`zero), marginRight(`rem(1.)), width(`percent(48.))], - ), - ]); - let textField = - style([ - display(`inlineFlex), - alignItems(`center), - height(px(40)), - borderRadius(px(4)), - width(`percent(100.)), - fontSize(rem(1.)), - color(Theme.Colors.teal), - padding(px(12)), - marginTop(`rem(0.5)), - border(px(1), `solid, Theme.Colors.hyperlinkAlpha(0.3)), - active([ - outline(px(0), `solid, `transparent), - padding(px(11)), - borderWidth(px(2)), - borderColor(Theme.Colors.hyperlinkAlpha(1.)), - ]), - focus([ - outline(px(0), `solid, `transparent), - padding(px(11)), - borderWidth(px(2)), - borderColor(Theme.Colors.hyperlinkAlpha(1.)), - ]), - hover([borderColor(Theme.Colors.hyperlinkAlpha(1.))]), - selector( - "::placeholder", - [ - fontSize(`px(12)), - fontWeight(normal), - color(Theme.Colors.slateAlpha(0.7)), - ], - ), - media( - Theme.MediaQuery.tablet, - [ - width(`percent(100.)), - maxWidth(`rem(38.5)), - marginRight(`rem(1.)), - ], - ), - media(Theme.MediaQuery.veryVeryLarge, [width(`percent(100.))]), - ]); -}; - -module SearchBar = { - [@react.component] - let make = (~onUsernameEntered, ~username) => { - <div className=Styles.searchBar> - <span className=Theme.H5.semiBold> - {React.string("Find Participant")} - </span> - <input - type_="text" - value=username - placeholder="NAME" - onChange={e => { - let value = ReactEvent.Form.target(e)##value; - onUsernameEntered(value); - }} - className=Styles.textField - /> - </div>; - }; -}; - -module ToggleButtons = { - module Styles = { - open Css; - - let flexColumn = - style([ - display(`none), - media( - Theme.MediaQuery.tablet, - [ - display(`flex), - flexDirection(`column), - justifyContent(`center), - height(`rem(4.5)), - ], - ), - ]); - - let buttonRow = - merge([ - style([ - display(`flex), - width(`rem(40.5)), - borderRadius(`px(4)), - overflow(`hidden), - selector( - "*:not(:last-child)", - [borderRight(`px(1), `solid, Theme.Colors.grey)], - ), - ]), - ]); - }; - - [@react.component] - let make = (~currentToggle, ~onTogglePress, ~toggleLabels) => { - let renderToggleButtons = () => { - toggleLabels - |> Array.map(label => { - <ToggleButton currentToggle onTogglePress label key=label /> - }) - |> React.array; - }; - - <div className=Styles.flexColumn> - <h3 className=Theme.H5.semiBold> {React.string("View")} </h3> - <Spacer height=0.5 /> - <div className=Styles.buttonRow> {renderToggleButtons()} </div> - </div>; - }; -}; - -module FilterDropdown = { - module Styles = { - open Css; - let flexColumn = - style([ - display(`flex), - flexDirection(`column), - justifyContent(`center), - height(`rem(4.5)), - width(`percent(100.)), - marginTop(`rem(2.0)), - media(Theme.MediaQuery.tablet, [display(`none)]), - media( - Theme.MediaQuery.notMobile, - [width(`percent(48.)), marginTop(`zero)], - ), - ]); - }; - - [@react.component] - let make = (~currentFilter, ~onFilterPress, ~filterLabels) => { - <div className=Styles.flexColumn> - <h3 className=Theme.H5.semiBold> {React.string("View")} </h3> - <Spacer height=0.5 /> - <Dropdown - items=filterLabels - currentItem=currentFilter - onItemPress=onFilterPress - /> - </div>; - }; -}; - -type state = { - currentToggle: Leaderboard.Toggle.t, - currentFilter: Leaderboard.Filter.t, - username: string, -}; - -let initialState = {currentToggle: All, currentFilter: Release, username: ""}; - -type action = - | Toggled(Leaderboard.Toggle.t) - | Filtered(Leaderboard.Filter.t) - | UsernameEntered(string); - -let reducer = (prevState, action) => { - switch (action) { - | Toggled(toggle) => {...prevState, currentToggle: toggle} - | Filtered(filter) => {...prevState, currentFilter: filter} - | UsernameEntered(input) => {...prevState, username: input} - }; -}; - -[@react.component] -let make = (~lastManualUpdatedDate) => { - open Leaderboard.Toggle; - open Leaderboard.Filter; - let (state, dispatch) = React.useReducer(reducer, initialState); - let onTogglePress = toggle => { - toggle->toggle_of_string->Toggled->dispatch; - }; - - let onFilterPress = filter => { - filter->filter_of_string->Filtered->dispatch; - }; - - let onUsernameEntered = username => { - dispatch(UsernameEntered(username)); - }; - - <Page title="Testnet Leaderboard"> - <Wrapped> - <div className=Styles.page> <Summary lastManualUpdatedDate /> </div> - <div className=Styles.filters> - <SearchBar onUsernameEntered username={state.username} /> - <ToggleButtons - currentToggle={string_of_toggle(state.currentToggle)} - onTogglePress - toggleLabels={Array.map( - toggle => {string_of_toggle(toggle)}, - toggles, - )} - /> - <FilterDropdown - currentFilter={string_of_filter(state.currentFilter)} - onFilterPress - filterLabels={Array.map( - filter => {string_of_filter(filter)}, - filters, - )} - /> - </div> - <Spacer height=1.5 /> - <Leaderboard - search={state.username} - filter={state.currentFilter} - toggle={state.currentToggle} - onFilterPress - /> - </Wrapped> - </Page>; -}; diff --git a/frontend/website-redesign/src/pages/MarkdownPage.re b/frontend/website-redesign/src/pages/MarkdownPage.re deleted file mode 100644 index 330ea664e53..00000000000 --- a/frontend/website-redesign/src/pages/MarkdownPage.re +++ /dev/null @@ -1,67 +0,0 @@ -// This is the layout for generic MDX pages - -module Style = { - open Css; - - let content = - style([ - maxWidth(`rem(43.)), - marginLeft(`rem(1.)), - selector( - "p > code, li > code", - [ - boxSizing(`borderBox), - padding2(~v=`px(2), ~h=`px(6)), - backgroundColor(Theme.Colors.slateAlpha(0.05)), - borderRadius(`px(4)), - ], - ), - selector( - "table", - [ - fontFamily("IBM Plex Sans, Sans-Serif"), - color(Theme.Colors.saville), - width(`percent(100.)), - ], - ), - selector( - "table, th, td", - [ - border(`px(1), solid, Theme.Colors.saville), - borderCollapse(`collapse), - padding(`px(4)), - ], - ), - ]); - - let page = - style([ - display(`block), - justifyContent(`center), - margin(`auto), - paddingLeft(`rem(1.)), - paddingRight(`rem(1.)), - marginTop(`rem(4.)), - media(Theme.MediaQuery.full, [display(`flex)]), - ]); -}; - -type metadata = {title: string}; - -[@react.component] -let make = (~metadata, ~children) => { - <Page title={metadata.title}> - <div className=Style.page> - <div className=Style.content> - <Next.MDXProvider components={DocsComponents.allComponents()}> - children - </Next.MDXProvider> - </div> - </div> - </Page>; -}; - -let default = - (. metadata) => - (. props: {. "children": React.element}) => - make({"metadata": metadata, "children": props##children}); diff --git a/frontend/website-redesign/src/pages/MemberProfilePage.re b/frontend/website-redesign/src/pages/MemberProfilePage.re deleted file mode 100644 index 00044bd1ceb..00000000000 --- a/frontend/website-redesign/src/pages/MemberProfilePage.re +++ /dev/null @@ -1,305 +0,0 @@ -module Styles = { - open Css; - let page = - style([ - maxWidth(`rem(58.0)), - margin(`auto), - media(Theme.MediaQuery.tablet, [maxWidth(`rem(89.))]), - ]); - - let border = - selector( - "> :not(:last-child)", - [ - after([ - unsafe("content", ""), - display(`flex), - justifyContent(`center), - marginLeft(`zero), - marginRight(`zero), - borderBottom(`px(1), `dashed, `rgb((200, 200, 200))), - media( - Theme.MediaQuery.desktop, - [marginLeft(`percent(16.)), marginRight(`percent(7.))], - ), - ]), - ], - ); - - let table = - style([ - selector("> div", [marginTop(`rem(5.))]), - media(Theme.MediaQuery.notMobile, [border]), - ]); - - let loading = - style([ - Theme.Typeface.ibmplexsans, - padding(`rem(5.)), - color(Theme.Colors.leaderboardMidnight), - textAlign(`center), - ]); -}; - -/* Adds the remaining length to the array parameter. - This is done because the Google Sheets API truncates trailing empty cells. - */ -let normalizeGoogleSheets = (length, a) => { - let rowLength = Array.length(a); - if (rowLength < length) { - Array.append(a, ArrayLabels.make(length - rowLength, "")); - } else { - a; - }; -}; - -let fetchRelease = (username, release) => { - let (releaseName, range, challengeColumnOffset) = release; - Sheets.fetchRange( - ~sheet="1Nq_Y76ALzSVJRhSFZZm4pfuGbPkZs2vTtCnVQ1ehujE", - ~range, - ) - |> Promise.map(res => { - let rows = Array.map(Leaderboard.parseEntry, res); - - let numberOfChallenges = - rows->Belt.Array.slice(~offset=0, ~len=1)->Array.get(0) - |> Array.length; - - let challengeTitles = - rows - ->Belt.Array.slice(~offset=0, ~len=1) - ->Array.get(0) - ->Belt.Array.slice( - ~offset=challengeColumnOffset, - ~len=numberOfChallenges, - ); - - let userInfo = - rows - ->Belt.Array.keep(entry => - String.lowercase_ascii(entry[0]) - == String.lowercase_ascii(username) - ) - ->Array.get(0) - ->Belt.Array.slice( - ~offset=challengeColumnOffset, - ~len=numberOfChallenges, - ) - |> normalizeGoogleSheets(Array.length(challengeTitles)); /* This is done so we have an equal number of point entries and challenges */ - - let challengeInfo = - userInfo - |> Belt.Array.zip(challengeTitles) - |> Array.map(user => { - let (challengeTitle, challengePoints) = user; - switch (challengePoints) { - | "" => { - ChallengePointsTable.name: challengeTitle, - points: None, - } - | points => { - ChallengePointsTable.name: challengeTitle, - points: Some(int_of_string(points)), - } - }; - }); - - Some({ - ChallengePointsTable.name: releaseName, - challenges: challengeInfo, - }); - }) - |> Js.Promise.catch(_ => Promise.return(None)); -}; - -let fetchReleases = name => { - [| - ("Release 3.1", "3.1!B3:Z", 4), /* offset for challenge titles in 3.1 starts on the 4th column */ - ("Release 3.2a", "3.2a!B3:Z", 2), /* offset for challenge titles in 3.2a starts on the 2nd column */ - ("Release 3.2b", "3.2b!B3:Z", 2) /* offset for challenge titles in 3.2b starts on the 2nd column */ - |] - |> Array.map(release => fetchRelease(name, release)) - |> Js.Promise.all - |> Js.Promise.then_(releaseValues => { - Belt.Array.keepMap(releaseValues, release => release) - |> Js.Promise.resolve - }); -}; - -let parseMember = map => { - let memberProperties = [| - Js.Dict.get(map, "genesisMember"), - Js.Dict.get(map, "phasePoints"), - Js.Dict.get(map, "releasePoints"), - Js.Dict.get(map, "allTimePoints"), - Js.Dict.get(map, "allTimeRank"), - Js.Dict.get(map, "phaseRank"), - Js.Dict.get(map, "releaseRank"), - |]; - - /* Return None if a property is not present in the URL */ - if (Belt.Array.keep(memberProperties, property => { - Belt.Option.isNone(property) - }) - |> Array.length > 0) { - None; - } else { - { - Leaderboard.name: Js.Dict.get(map, "name")->Belt.Option.getExn, - genesisMember: - Js.Dict.get(map, "genesisMember")->Belt.Option.getExn - |> bool_of_string, - phasePoints: - Js.Dict.get(map, "phasePoints")->Belt.Option.getExn |> int_of_string, - releasePoints: - Js.Dict.get(map, "releasePoints")->Belt.Option.getExn |> int_of_string, - allTimePoints: - Js.Dict.get(map, "allTimePoints")->Belt.Option.getExn |> int_of_string, - allTimeRank: - Js.Dict.get(map, "allTimeRank")->Belt.Option.getExn |> int_of_string, - phaseRank: - Js.Dict.get(map, "phaseRank")->Belt.Option.getExn |> int_of_string, - releaseRank: - Js.Dict.get(map, "releaseRank")->Belt.Option.getExn |> int_of_string, - } - ->Some; - }; -}; - -type state = { - loading: bool, - error: bool, - releases: array(ChallengePointsTable.release), - currentMember: option(Leaderboard.member), -}; - -let initialState = { - loading: true, - error: false, - releases: [||], - currentMember: None, -}; - -type actions = - | UpdateReleaseInfo(array(ChallengePointsTable.release)) - | UpdateCurrentUser(Leaderboard.member) - | UpdateCurrentReleaseAndUser( - array(ChallengePointsTable.release), - Leaderboard.member, - ) - | UpdateError(bool); - -let reducer = (prevState, action) => { - switch (action) { - | UpdateReleaseInfo(releases) => {...prevState, loading: false, releases} - | UpdateCurrentUser(member) => {...prevState, currentMember: Some(member)} - | UpdateCurrentReleaseAndUser(releases, member) => { - loading: false, - error: false, - currentMember: Some(member), - releases, - } - | UpdateError(error) => {...prevState, error} - }; -}; - -module Footer = { - module Styles = { - open Css; - let footer = - style([ - width(`percent(100.)), - background(`rgba((242, 183, 5, 0.1))), - color(Theme.Colors.saville), - padding(`rem(1.)), - ]); - let header = merge([Theme.H5.semiBold, style([fontSize(`rem(1.5))])]); - let copy = - merge([ - Theme.H5.semiBold, - style([fontSize(`rem(1.5)), fontWeight(`light)]), - ]); - - let bold = merge([header, style([fontSize(`rem(1.25))])]); - let disclaimer = merge([copy, style([fontSize(`rem(1.1))])]); - }; - [@react.component] - let make = () => { - <div className=Styles.footer> - <p className=Styles.header> - {React.string( - "Testnet points are displayed for releases in the current testnet phase.", - )} - </p> - <p className=Styles.copy> - {React.string( - "Point totals from all testnet phases are included when calculating total testnet points.", - )} - </p> - <Spacer height=1. /> - <p className=Styles.bold> {React.string("* Testnet Points")} </p> - <p className=Styles.disclaimer> - {React.string( - "Testnet Points (abbreviated 'pts') are designed solely to track contributions to the \ - Testnet and Testnet Points have no cash or other monetary value. Testnet Points are not \ - transferable and are not redeemable or exchangeable for any cryptocurrency or digital assets. \ - We may at any time amend or eliminate Testnet Points.", - )} - </p> - </div>; - }; -}; -[@react.component] -let make = () => { - let (state, dispatch) = React.useReducer(reducer, initialState); - let router = Next.Router.useRouter(); - - React.useEffect1( - () => { - switch (parseMember(router.query)) { - | Some(member) => - fetchReleases(member.name) - |> Promise.iter(releases => - dispatch(UpdateCurrentReleaseAndUser(releases, member)) - ) - | None => dispatch(UpdateError(true)) - }; - None; - }, - [|router.query|], - ); - - <Page title="Member Profile"> - <Wrapped> - <div className=Styles.page> - {switch (state.currentMember) { - | Some(member) => <div> <ProfileHero member /> </div> - | None => React.null - }} - <div className=Styles.table> - {state.releases - |> Array.map((release: ChallengePointsTable.release) => { - <div key={release.name}> - <ChallengePointsTable - releaseTitle={release.name} - challenges={release.challenges} - /> - </div> - }) - |> React.array} - </div> - {!state.error && state.loading - ? <div className=Styles.loading> - {React.string("Loading...")} - </div> - : React.null} - {state.error - ? <div className=Styles.loading> - {React.string("User Not Available")} - </div> - : <Footer />} - </div> - </Wrapped> - </Page>; -}; diff --git a/frontend/website-redesign/src/pages/Testnet.re b/frontend/website-redesign/src/pages/Testnet.re deleted file mode 100644 index aab1880b727..00000000000 --- a/frontend/website-redesign/src/pages/Testnet.re +++ /dev/null @@ -1,403 +0,0 @@ -module Styles = { - open Css; - - let markdownStyles = - style([ - selector("a", [cursor(`pointer), ...Theme.Link.basicStyles]), - selector( - "h4", - Theme.H4.wideStyles - @ [textAlign(`left), fontSize(`rem(1.)), fontWeight(`light)], - ), - selector( - "code", - [Theme.Typeface.pragmataPro, color(Theme.Colors.midnight)], - ), - selector( - "p > code, li > code", - [ - boxSizing(`borderBox), - padding2(~v=`px(2), ~h=`px(6)), - backgroundColor(Theme.Colors.slateAlpha(0.05)), - borderRadius(`px(4)), - ], - ), - ]); - - let page = - style([ - selector( - "hr", - [ - height(px(4)), - borderTop(px(1), `dashed, Theme.Colors.marine), - borderLeft(`zero, solid, transparent), - borderBottom(px(1), `dashed, Theme.Colors.marine), - ], - ), - ]); - - let header = - style([ - display(`flex), - flexDirection(`column), - width(`percent(100.)), - color(Theme.Colors.slate), - textAlign(`center), - margin2(~v=rem(3.5), ~h=`zero), - ]); - - let content = - style([ - display(`flex), - justifyContent(`center), - flexDirection(`column), - width(`percent(100.)), - marginBottom(`rem(1.5)), - maxWidth(`rem(58.)), - ]); - - let leaderboardCopy = - style([maxWidth(`rem(36.5)), margin2(~v=`zero, ~h=`auto)]); - - let rowStyles = [ - display(`grid), - gridColumnGap(rem(1.5)), - gridTemplateColumns([rem(1.), rem(5.5), rem(5.5), rem(3.5)]), - media( - Theme.MediaQuery.notMobile, - [ - width(`percent(100.)), - gridTemplateColumns([rem(2.5), `auto, rem(6.), rem(3.5)]), - ], - ), - ]; - - let copy = - style([ - maxWidth(rem(28.)), - margin3(~top=`zero, ~h=`auto, ~bottom=rem(2.)), - media(Theme.MediaQuery.somewhatLarge, [marginLeft(rem(5.))]), - media(Theme.MediaQuery.notMobile, [width(rem(28.))]), - ...Theme.Body.basicStyles, - ]); - - let headerLink = - merge([ - Theme.Link.basic, - Theme.H3.basic, - style([ - fontWeight(`semiBold), - marginTop(rem(1.5)), - marginLeft(rem(1.75)), - ]), - ]); - - let sidebarHeader = - merge([ - Theme.H4.wide, - style([textAlign(`left), fontSize(`rem(1.)), fontWeight(`light)]), - ]); - - let dashboardHeader = - merge([ - header, - style([marginTop(rem(1.5)), marginBottom(`rem(1.5))]), - ]); - - let dashboard = - style([ - width(`percent(100.)), - height(`rem(70.)), - border(`px(0), `solid, white), - borderRadius(px(3)), - ]); - - let expandButton = - merge([ - Theme.Link.basic, - style([ - backgroundColor(Theme.Colors.hyperlink), - color(white), - marginLeft(`auto), - marginRight(`auto), - marginBottom(`rem(1.5)), - display(`flex), - cursor(`pointer), - borderRadius(`px(4)), - padding2(~v=`rem(0.25), ~h=`rem(3.)), - fontWeight(`semiBold), - lineHeight(`rem(2.5)), - hover([backgroundColor(Theme.Colors.hyperlinkHover), color(white)]), - ]), - ]); - - let gradientSectionExpanded = - style([ - height(`auto), - width(`percent(100.)), - position(`relative), - overflow(`hidden), - display(`flex), - flexWrap(`wrap), - marginLeft(`auto), - marginRight(`auto), - justifyContent(`center), - ]); - - let gradientSection = - merge([ - gradientSectionExpanded, - style([ - height(`rem(45.)), - after([ - contentRule(""), - position(`absolute), - bottom(`px(-1)), - left(`zero), - height(`rem(8.)), - width(`percent(100.)), - pointerEvents(`none), - backgroundImage( - `linearGradient(( - `deg(0.), - [ - (`zero, Theme.Colors.white), - (`percent(100.), Theme.Colors.whiteAlpha(0.)), - ], - )), - ), - ]), - ]), - ]); - - let buttonRow = - style([ - display(`grid), - gridTemplateColumns([`fr(1.0)]), - gridRowGap(rem(1.5)), - gridTemplateRows([`repeat((`num(4), `rem(6.0)))]), - justifyContent(`center), - marginLeft(`auto), - marginRight(`auto), - marginTop(rem(3.)), - marginBottom(rem(3.)), - media( - "(min-width: 45rem)", - [ - gridTemplateColumns([`repeat((`num(2), `fr(1.0)))]), - gridTemplateRows([`repeat((`num(2), `rem(6.0)))]), - gridColumnGap(rem(1.5)), - ], - ), - media( - "(min-width: 66rem)", - [ - gridTemplateColumns([`repeat((`num(2), `fr(1.0)))]), - gridTemplateRows([`repeat((`num(2), `rem(5.4)))]), - ], - ), - media( - "(min-width: 70rem)", - [ - gridTemplateColumns([`repeat((`num(4), `fr(1.0)))]), - gridTemplateRows([`repeat((`num(1), `rem(7.5)))]), - gridColumnGap(rem(1.0)), - ], - ), - ]); - - let discordIcon = style([marginTop(`px(-4))]); - let formIcon = style([marginTop(`px(3))]); - let heroRow = - style([ - display(`flex), - flexDirection(`column), - justifyContent(`spaceBetween), - alignItems(`center), - media("(min-width: 70rem)", [flexDirection(`row)]), - ]); - - let heroText = - merge([header, style([maxWidth(`px(500)), textAlign(`left)])]); - let disclaimer = - merge([Theme.Body.small, style([color(Theme.Colors.midnight)])]); -}; - -module Section = { - [@react.component] - let make = (~name, ~expanded, ~setExpanded, ~children) => { - <div className=Css.(style([display(`flex), flexDirection(`column)]))> - {if (expanded) { - <div className=Styles.gradientSectionExpanded> children </div>; - } else { - <> - <div className=Styles.gradientSection> children </div> - <div - className=Styles.expandButton - onClick={_ => setExpanded(_ => true)}> - <div> {React.string("Expand " ++ name)} </div> - <div className=Css.(style([marginLeft(`rem(0.5))]))> - {React.string({js| ↓|js})} - </div> - </div> - </>; - }} - </div>; - }; -}; - -[@react.component] -let make = (~challenges as _, ~testnetName as _) => { - let (expanded, setExpanded) = React.useState(() => false); - <Page title="Coda Testnet"> - <Wrapped> - <div className=Styles.page> - <div className=Styles.heroRow> - <div className=Styles.heroText> - <h1 className=Theme.H1.hero> - {React.string("Coda Public Testnet")} - </h1> - <p className=Theme.Body.basic> - {React.string( - "Coda's public testnet is live! There are weekly challenges for the community \ - to interact with the testnet and contribute to Coda's development. Each week \ - features a new competition to recognize and reward top contributors with testnet \ - points.", - )} - </p> - <br /> - <p className=Theme.Body.basic> - {React.string( - "By participating in the testnet, you'll be helping advance the first cryptocurrency that utilizes recursive zk-SNARKs and production-scale Ouroboros proof of stake consensus.", - )} - </p> - <p className=Theme.Body.basic> - {React.string("Testnet Status: ")} - <StatusBadge service=`Network /> - </p> - </div> - <Terminal.Wrapper lineDelay=2000> - <Terminal.Line prompt=">" value="coda daemon -peer ..." /> - <Terminal.Progress /> - <Terminal.MultiLine - values=[|"Daemon ready. Clients can now connect!"|] - /> - <Terminal.Line prompt=">" value="coda client status" /> - <Terminal.MultiLine - values=[| - "Max observed block length: 120", - "Peers: 23", - "Consensus time now: epoch=1, slot=13", - "Sync status: Synced", - |] - /> - </Terminal.Wrapper> - </div> - <div> - <div className=Styles.buttonRow> - <ActionButton - icon={React.string({js| 🚥 |js})} - heading={React.string({js| Get Started |js})} - text={React.string( - "Get started by installing Coda and running a node", - )} - href="/docs/getting-started/" - /> - <ActionButton - icon={ - <img - className=Styles.discordIcon - src="/static/img/discord.svg" - /> - } - heading={React.string({js| Discord |js})} - text={React.string( - "Connect with the community and participate in weekly challenges", - )} - href="https://bit.ly/CodaDiscord" - /> - <ActionButton - icon={React.string({js|💬|js})} - heading={React.string({js| Forum |js})} - text={React.string( - "Find longer discussions and in-depth content", - )} - href="https://forums.codaprotocol.com/" - /> - <ActionButton - icon={React.string({js| 🌟 |js})} - heading={React.string({js| Token Grant |js})} - text={React.string( - "Apply to be one of the early members to receive a Genesis token grant", - )} - href="/genesis" - /> - </div> - </div> - <hr /> - <Section name="Leaderboard" expanded setExpanded> - <div className=Styles.dashboardHeader> - <h1 className=Theme.H1.hero> - {React.string("Testnet Leaderboard")} - </h1> - // href="https://testnet-points-frontend-dot-o1labs-192920.appspot.com/" - <a - href="https://bit.ly/TestnetLeaderboard" - target="_blank" - className=Styles.headerLink> - {React.string({j|View Full Leaderboard\u00A0→|j})} - </a> - </div> - <div className=Styles.content> - <span className=Styles.leaderboardCopy> - <p className=Theme.Body.big_semibold> - {React.string( - "Coda rewards community members with testnet points for completing challenges that \ - contribute to the development of the protocol. *", - )} - </p> - <p className=Styles.disclaimer> - {React.string( - "* Testnet Points are designed solely to track contributions to the Testnet \ - and Testnet Points have no cash or other monetary value. Testnet Points and \ - are not transferable and are not redeemable or exchangeable for any cryptocurrency \ - or digital assets. We may at any time amend or eliminate Testnet Points.", - )} - </p> - </span> - <Leaderboard /> - </div> - </Section> - <hr /> - <div> - <div className=Styles.dashboardHeader> - <h1 className=Theme.H1.hero> - {React.string("Network Dashboard")} - </h1> - <a - href="https://o1testnet.grafana.net/d/Rgo87HhWz/block-producer-dashboard?orgId=1" - target="_blank" - className=Styles.headerLink> - {React.string({j|View Full Dashboard\u00A0→|j})} - </a> - </div> - <iframe - src="https://o1testnet.grafana.net/d/qx4y6dfWz/network-overview?orgId=1&refresh=1m" - className=Styles.dashboard - /> - </div> - </div> - </Wrapped> - </Page>; -}; - -Next.injectGetInitialProps(make, _ => - Challenges.fetchAllChallenges() - |> Promise.map(((testnetName, ranking, continuous, threshold)) => - { - "challenges": (ranking, continuous, threshold), - "testnetName": testnetName, - } - ) -); diff --git a/frontend/website/pages/docs/tokens.mdx b/frontend/website/pages/docs/tokens.mdx new file mode 100644 index 00000000000..74bba5bdea7 --- /dev/null +++ b/frontend/website/pages/docs/tokens.mdx @@ -0,0 +1,102 @@ +import Page from '@reason/pages/Docs'; +export default Page({title: "Tokens"}); + +# Tokens + +In the Coda protocol, users can create their own Tokens which can be minted (or created) and sent by using special token accounts. The Coda CLI (command-line interface) is the primary way to interact with tokens on the Coda blockchain. It provides a client interface that supports functionality to create new tokens, create new token accounts, and mint non-default tokens. In addition to the tokens interface, there are other advanced client and daemon commands (see [CLI Reference](/docs/cli-reference#cli-reference)). + +## Creating Tokens + +With the CLI, you are able to create your own tokens on Coda. Non-default tokens are a new type of token that is introduced to the Coda blockchain. These new types of tokens have a unique identifier that differentiate them from all other tokens in the blockchain. Users with an associated token account can then receive/send this new type of token that is totally separate from the native Coda token itself! When you create a new token, you are then able to mint more of the token to be used (see below in [Minting Tokens](/docs/tokens#minting-tokens)). + +When creating a new token, a new token ID is created as well as a token account for your public key. This token account owns the token and can mint more of the token. The account will also (eventually) have the power to enable/disable accounts, and to set whether new accounts may be created for the token. + +Please note that creating new tokens requires an additional fee on top of the ever-present transaction fee. This additional fee is the fee that must be paid when creating a new token account. This means there is a fee for the account creation on top of the transaction fee that is normally applied. + +### Create a new token + +``` +$ coda client create-token -sender <PUBLIC_KEY> +``` + +<Alert> + +The required field for creating a new token account is: + +- -**sender** : The public key from which you want to send the transaction + +</Alert> + +See +``` +$ coda client create-token -help +``` +to learn more about how to use the command. + +## Creating Token Accounts + +With the CLI, you are able to create a token account for existing tokens. Token accounts are like regular accounts but solely meant to interact with the non-default tokens that exist in the Coda protocol. You must create a separate unique token account for each type of token you wish to interact with. +<Alert kind="warning"> + +To send or receive an existing token, you must have a token account with the specified token. If there is no valid token account with the token, the transaction will fail. + +</Alert> + +### Create a new token account + +``` +$ coda client create-token-account -token-owner <PUBLICKEY> -receiver <PUBLICKEY> -sender <KEY> -token <TOKEN_ID> +``` + +<Alert> + + If the token owner is not given, the CLI will query to find the token owner. If no owner is found, the command will fail with an error. + +The required fields for creating a new token account are: + +- -**receiver** : The public key to create the new account for, you can reuse your normal public key here + +- -**sender** : The public key for which you want to create the account + +- -**token** : The ID of the token from which you want to send the transaction + +</Alert> + +See +``` +$ coda client create-token-account -help +``` +to learn more about how to use the command. + +## Minting Tokens + +With the CLI, you are able to mint your own tokens. Minting your own tokens simply increases the supply of a particular token. Minting tokens is how all non-default tokens are created, there are no other protocol-events or commands that can create non-default tokens. This command may only be issued by the token owner, but the tokens may be minted in any existing account for that token. + + +### Mint a token + +``` +$ coda client mint-tokens -amount <VALUE> -sender <PUBLIC-KEY> -token <TOKEN_ID> +``` + +<Alert> + +The required fields for creating a new token account are: + +- -**amount** : Number of new tokens to create + +- -**sender** : Public key from which you want to send the transaction + +- -**token** : The ID of the token to mint + +There is also an optional field that lets you specify the public key of the account to create the new tokens in: + +- -**receiver** : Public key of the account to create new tokens in + +</Alert> + +See +``` +$ coda client mint-tokens -help +``` +to learn more about how to use the command. diff --git a/frontend/website/src/components/DocsSideNav.re b/frontend/website/src/components/DocsSideNav.re index 3f1f464e2c5..060e66def7e 100644 --- a/frontend/website/src/components/DocsSideNav.re +++ b/frontend/website/src/components/DocsSideNav.re @@ -185,6 +185,7 @@ let make = (~currentSlug) => { </Folder> <Page title="Snapps" slug="snapps" /> <Page title="CLI Reference" slug="cli-reference" /> + <Page title="Tokens" slug="tokens" /> <Page title="Troubleshooting" slug="troubleshooting" /> <Page title="FAQ" slug="faq" /> <Page title="Glossary" slug="glossary" /> diff --git a/scripts/client-sdk-unit-tests.sh b/scripts/client-sdk-unit-tests.sh new file mode 100755 index 00000000000..d5128aeb84b --- /dev/null +++ b/scripts/client-sdk-unit-tests.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +set -eo pipefail + +# run client SDK tests in node + +echo "Building client SDK..." +source ~/.profile +make client_sdk +echo "Running unit tests in Javascript" +nodejs src/app/client_sdk/tests/run_unit_tests.js + +# the Rosetta encodings are not part of the client SDK as such, +# but the SDK relies on them, so it's reasonable to compare +# the encodings here, rather than create another CI test + +# native/consensus +echo "Building consensus native code for encodings..." +make rosetta_lib_encodings +echo "Running" +./_build/default/src/lib/rosetta_lib/test/test_encodings.exe > encodings.consensus + +# native/nonconsensus +echo "Building nonconsensus native code for encodings..." +make rosetta_lib_encodings_nonconsensus +echo "Running" +./_build/default/src/nonconsensus/rosetta_lib/test/test_encodings.exe > encodings.nonconsensus + +# js/nonconsensus +echo "Building nonconsensus Javascript code for encodings..." +make client_sdk +echo "Running" +nodejs src/app/client_sdk/tests/test_encodings.js > encodings.js.nonconsensus + +diff encodings.consensus encodings.nonconsensus + +if [ $? -ne 0 ]; then + echo "Consensus and nonconsensus code generate different encodings"; + exit 1 +fi + +diff encodings.nonconsensus encodings.js.nonconsensus + +if [ $? -ne 0 ]; then + echo "Nonconsensus native and Javascript code generate different encodings"; + exit 1 +fi + +echo "SUCCESS" diff --git a/scripts/compare_test_signatures.sh b/scripts/compare_test_signatures.sh index 8c87b2860e7..55c8eaf24ca 100755 --- a/scripts/compare_test_signatures.sh +++ b/scripts/compare_test_signatures.sh @@ -45,4 +45,3 @@ if [ $? -ne 0 ]; then fi echo "SUCCESS" - diff --git a/scripts/test.py b/scripts/test.py index 5d04812e876..c0441a31491 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -109,7 +109,7 @@ "ci/circleci: tracetool", "ci/circleci: build-wallet", "ci/circleci: compare-test-signatures", - "ci/circleci: build-client-sdk", + "ci/circleci: client-sdk-unit-tests", "ci/circleci: test-unit--nonconsensus_medium_curves", ] diff --git a/src/app/client_sdk/client_sdk.ml b/src/app/client_sdk/client_sdk.ml index d3bf279790f..5c52f9e1bf9 100644 --- a/src/app/client_sdk/client_sdk.ml +++ b/src/app/client_sdk/client_sdk.ml @@ -15,6 +15,7 @@ open Js_of_ocaml open Snark_params_nonconsensus open Signature_lib_nonconsensus open Coda_base_nonconsensus +open Rosetta_lib_nonconsensus open Js_util let _ = @@ -45,7 +46,7 @@ let _ = let sk = Js.to_string sk_base58_check_js |> Private_key.of_base58_check_exn in - Public_key.of_private_key_exn sk |> Raw.of_public_key + Public_key.of_private_key_exn sk |> Coding.of_public_key |> Js.string (** return public key in raw hex format for Rosetta *) method rawPublicKeyOfPublicKey (pk_base58_check_js : string_js) = @@ -53,12 +54,12 @@ let _ = Js.to_string pk_base58_check_js |> Public_key.Compressed.of_base58_check_exn in - Raw.of_public_key_compressed pk + Coding.of_public_key_compressed pk |> Js.string (** return public key, given that key in raw hex format for Rosetta *) method publicKeyOfRawPublicKey (pk_raw_js : string_js) = let pk_raw_str = Js.to_string pk_raw_js in - Raw.to_public_key_compressed pk_raw_str + Coding.to_public_key_compressed pk_raw_str |> Public_key.Compressed.to_base58_check |> Js.string (** sign arbitrary string with private key *) @@ -158,5 +159,5 @@ let _ = let signed = User_command.Poly.{payload; signer; signature} in User_command.check_signature signed - method runUnitTests () : bool Js.t = Raw.run_unit_tests () ; Js._true + method runUnitTests () : bool Js.t = Coding.run_unit_tests () ; Js._true end) diff --git a/src/app/client_sdk/dune b/src/app/client_sdk/dune index ed6c47521df..0a178ab0d98 100644 --- a/src/app/client_sdk/dune +++ b/src/app/client_sdk/dune @@ -2,7 +2,7 @@ (name client_sdk) (modes js) (js_of_ocaml (flags +toplevel.js +dynlink.js)) - (libraries snark_params_nonconsensus coda_base_nonconsensus random_oracle_nonconsensus + (libraries snark_params_nonconsensus rosetta_lib_nonconsensus coda_base_nonconsensus random_oracle_nonconsensus signature_lib_nonconsensus zarith_stubs_js integers integers_stubs_js js_of_ocaml digestif.ocaml) (preprocessor_deps ../../config.mlh) (preprocess (pps ppx_version ppx_custom_printf ppx_optcomp js_of_ocaml-ppx))) diff --git a/src/app/client_sdk/tests/test_encodings.js b/src/app/client_sdk/tests/test_encodings.js new file mode 100644 index 00000000000..1bf0095d0ed --- /dev/null +++ b/src/app/client_sdk/tests/test_encodings.js @@ -0,0 +1,12 @@ +// test_encodings.js -- print Rosetta encodings of a couple of public keys + +var coda = require("../../../../_build/default/src/app/client_sdk/client_sdk.bc.js").codaSDK; + +var pk1 = "B62qkef7po74VEvJYcLYsdZ83FuKidgNZ8Xiaitzo8gKJXaxLwxgG7T"; +var pk2 = "B62qnekV6LVbEttV7j3cxJmjSbxDWuXa5h3KeVEXHPGKTzthQaBufrY"; + +var enc1 = coda.rawPublicKeyOfPublicKey(pk1) +var enc2 = coda.rawPublicKeyOfPublicKey(pk2) + +console.log(enc1) +console.log(enc2) diff --git a/src/app/libp2p_helper/src/go.mod b/src/app/libp2p_helper/src/go.mod index ae3804596ca..a2bcd788f12 100644 --- a/src/app/libp2p_helper/src/go.mod +++ b/src/app/libp2p_helper/src/go.mod @@ -27,7 +27,6 @@ require ( github.com/libp2p/go-libp2p-crypto v0.1.0 github.com/libp2p/go-libp2p-discovery v0.5.0 github.com/libp2p/go-libp2p-kad-dht v0.8.2 - github.com/libp2p/go-libp2p-kbucket v0.4.2 // indirect github.com/libp2p/go-libp2p-peerstore v0.2.6 github.com/libp2p/go-libp2p-pnet v0.2.0 github.com/libp2p/go-libp2p-pubsub v0.3.2 diff --git a/src/app/rosetta/lib/construction.ml b/src/app/rosetta/lib/construction.ml index 74dc7ac40e3..ff63dc94aa8 100644 --- a/src/app/rosetta/lib/construction.ml +++ b/src/app/rosetta/lib/construction.ml @@ -103,9 +103,14 @@ module Derive = struct let open M.Let_syntax in (* TODO: Verify curve-type is tweedle *) let%map pk = - Public_key.Hex.decode req.public_key.hex_bytes - |> Result.map_error ~f:(fun _ -> Errors.create `Malformed_public_key) - |> env.lift + let pk_or_error = + try Ok (Rosetta_lib.Coding.to_public_key req.public_key.hex_bytes) + with exn -> Error (Core_kernel.Error.of_exn exn) + in + env.lift + @@ Result.map_error + ~f:(fun _ -> Errors.create `Malformed_public_key) + pk_or_error in { Construction_derive_response.address= Public_key.(compress pk |> Compressed.to_base58_check) @@ -284,7 +289,7 @@ module Payloads = struct ~error: (Errors.create ~context:"decompression" `Public_key_format_not_valid) ) - |> Result.map ~f:Public_key.Hex.encode + |> Result.map ~f:Rosetta_lib.Coding.of_public_key |> env.lift in let%bind user_command_payload = @@ -464,6 +469,7 @@ module Hash = struct ~error: (Errors.create ~context:"decompression" `Public_key_format_not_valid) ) + |> Result.map_error ~f:(fun _ -> Errors.create `Malformed_public_key) |> env.lift in let%bind payload = diff --git a/src/app/rosetta/lib/dune b/src/app/rosetta/lib/dune index c4b9d28208a..0c07b5fec44 100644 --- a/src/app/rosetta/lib/dune +++ b/src/app/rosetta/lib/dune @@ -15,6 +15,7 @@ logger models ppx_deriving_yojson.runtime + rosetta_lib yojson archive_lib signature_lib diff --git a/src/app/rosetta/lib/transaction.ml b/src/app/rosetta/lib/transaction.ml index efa5f577ddd..aef4149a79f 100644 --- a/src/app/rosetta/lib/transaction.ml +++ b/src/app/rosetta/lib/transaction.ml @@ -38,13 +38,11 @@ module Unsigned = struct let string_of_field field = assert (Snark_params.Tick.Field.size_in_bits = 255) ; - Snark_params.Tick.Field.unpack field - |> Random_oracle_input.Coding.string_of_field + Rosetta_lib.Coding.of_field field |> Hex.Safe.of_hex |> Option.value_exn let field_of_string s = assert (Snark_params.Tick.Field.size_in_bits = 255) ; - Random_oracle_input.Coding.field_of_string s ~size_in_bits:255 - |> Result.map ~f:(fun bits -> Snark_params.Tick.Field.project bits) + Hex.Safe.to_hex s |> Rosetta_lib.Coding.to_field let un_pk (`Pk pk) = pk diff --git a/src/app/test_executive/test_executive.ml b/src/app/test_executive/test_executive.ml index a9aa5143577..377e8b086ae 100644 --- a/src/app/test_executive/test_executive.ml +++ b/src/app/test_executive/test_executive.ml @@ -64,8 +64,8 @@ let main inputs = ~images in (* resources which require additional cleanup at end of test *) - let net_manager_ref = ref None in - let log_engine_ref = ref None in + let net_manager_ref : Engine.Network_manager.t option ref = ref None in + let log_engine_ref : Engine.Log_engine.t option ref = ref None in let cleanup_deferred_ref = ref None in let dispatch_cleanup reason test_error = let open Deferred.Let_syntax in @@ -79,13 +79,13 @@ let main inputs = in let%bind log_engine_error_set = Option.value_map !log_engine_ref - ~default:(Deferred.return Test_error.Set.empty) - ~f: - (Deferred.map ~f:(function - | Ok errors -> - errors - | Error err -> - Test_error.Set.hard_singleton err )) + ~default:(Deferred.return Test_error.Set.empty) ~f:(fun log_engine -> + match%map Engine.Log_engine.destroy log_engine with + | Ok errors -> + errors + | Error err -> + Test_error.Set.hard_singleton (Test_error.internal_error err) + ) in let%bind () = Option.value_map !net_manager_ref ~default:Deferred.unit diff --git a/src/hex_nonconsensus.opam b/src/hex_nonconsensus.opam new file mode 100644 index 00000000000..3f309a68f5b --- /dev/null +++ b/src/hex_nonconsensus.opam @@ -0,0 +1,6 @@ +opam-version: "1.2" +version: "0.1" +build: [ + ["dune" "build" "--only" "src" "--root" "." "-j" jobs "@install"] +] + diff --git a/src/lib/coda_base/signature.ml b/src/lib/coda_base/signature.ml index 3739953c435..b5e2848d3f1 100644 --- a/src/lib/coda_base/signature.ml +++ b/src/lib/coda_base/signature.ml @@ -11,6 +11,7 @@ open Snark_params.Tick [%%else] open Snark_params_nonconsensus +module Hex = Hex_nonconsensus.Hex [%%endif] diff --git a/src/lib/coda_base/sok_message.ml b/src/lib/coda_base/sok_message.ml index f4a5909abc8..ef98a4938f5 100644 --- a/src/lib/coda_base/sok_message.ml +++ b/src/lib/coda_base/sok_message.ml @@ -6,7 +6,7 @@ module Stable = struct module V1 = struct type t = {fee: Currency.Fee.Stable.V1.t; prover: Public_key.Compressed.Stable.V1.t} - [@@deriving sexp, yojson] + [@@deriving sexp, yojson, eq, compare] let to_latest = Fn.id end diff --git a/src/lib/coda_base/sok_message.mli b/src/lib/coda_base/sok_message.mli index 2130926dd87..7dd8423a654 100644 --- a/src/lib/coda_base/sok_message.mli +++ b/src/lib/coda_base/sok_message.mli @@ -15,12 +15,12 @@ end type t = Stable.Latest.t = {fee: Currency.Fee.Stable.V1.t; prover: Public_key.Compressed.Stable.V1.t} -[@@deriving sexp, yojson] +[@@deriving sexp, yojson, eq, compare] val create : fee:Currency.Fee.t -> prover:Public_key.Compressed.t -> t module Digest : sig - type t [@@deriving sexp, eq, yojson] + type t [@@deriving sexp, eq, yojson, hash, compare] module Stable : sig module V1 : sig diff --git a/src/lib/gossip_net/libp2p.ml b/src/lib/gossip_net/libp2p.ml index ce50bece944..7522d74af74 100644 --- a/src/lib/gossip_net/libp2p.ml +++ b/src/lib/gossip_net/libp2p.ml @@ -434,16 +434,22 @@ module Make (Rpc_intf : Coda_base.Rpc_intf.Rpc_interface_intf) : , [("exn", `String (Error.to_string_hum err))] ) )) in Error err ) - | Error monitor_exn -> ( + | Error monitor_exn -> (* call itself failed *) (* TODO: learn what other exceptions are raised here *) let exn = Monitor.extract_exn monitor_exn in - match exn with - | _ -> - [%log' error t.config.logger] - "RPC call raised an exception: $exn" - ~metadata:[("exn", `String (Exn.to_string exn))] ; - Deferred.return (Or_error.of_exn exn) ) + let () = + match Error.sexp_of_t (Error.of_exn exn) with + | Sexp.List (Sexp.Atom "connection attempt timeout" :: _) -> + Logger.debug t.config.logger ~module_:__MODULE__ + ~location:__LOC__ "RPC call raised an exception: $exn" + ~metadata:[("exn", `String (Exn.to_string exn))] + | _ -> + Logger.error t.config.logger ~module_:__MODULE__ + ~location:__LOC__ "RPC call raised an exception: $exn" + ~metadata:[("exn", `String (Exn.to_string exn))] + in + Deferred.return (Or_error.of_exn exn) in call () diff --git a/src/lib/integration_test_lib/dune b/src/lib/integration_test_lib/dune index b81caac9b62..5ca4dda11fb 100644 --- a/src/lib/integration_test_lib/dune +++ b/src/lib/integration_test_lib/dune @@ -2,5 +2,5 @@ (public_name integration_test_lib) (name integration_test_lib) (inline_tests) - (preprocess (pps ppx_coda ppx_version ppx_optcomp ppx_let ppx_inline_test ppx_custom_printf)) + (preprocess (pps ppx_coda ppx_version ppx_jane ppx_deriving.std)) (libraries core async coda_base runtime_config genesis_constants transition_frontier user_command_input)) diff --git a/src/lib/integration_test_lib/error_monad.ml b/src/lib/integration_test_lib/error_monad.ml new file mode 100644 index 00000000000..7064fc36dab --- /dev/null +++ b/src/lib/integration_test_lib/error_monad.ml @@ -0,0 +1,164 @@ +open Core_kernel +open Async_kernel + +module Hard_fail = struct + type t = + { hard_error: Error.t + [@equal + fun a b -> + String.equal (Error.to_string_hum a) (Error.to_string_hum b)] + ; soft_errors: Error.t list + [@equal + List.equal (fun a b -> + String.equal (Error.to_string_hum a) (Error.to_string_hum b) )] + } + [@@deriving eq, sexp_of, compare] +end + +module Accumulator = struct + type 'a t = + { computation_result: 'a + ; soft_errors: Error.t list + [@equal + List.equal (fun a b -> + String.equal (Error.to_string_hum a) (Error.to_string_hum b) )] + } + [@@deriving eq, sexp_of, compare] +end + +module ErrorReporting = Monad.Make (struct + type 'a t = ('a Accumulator.t, Hard_fail.t) Deferred.Result.t + + let return a = + Deferred.return (Ok {Accumulator.computation_result= a; soft_errors= []}) + + let bind res ~f = + match%bind res with + | Ok {Accumulator.computation_result= prev_result; soft_errors= err_list} + -> ( + let execProg = f prev_result in + match%bind execProg with + | Ok {Accumulator.computation_result= comp; soft_errors= next_list} -> + Deferred.return + (Ok + { Accumulator.computation_result= comp + ; Accumulator.soft_errors= List.append err_list next_list }) + | Error + {Hard_fail.hard_error= hard_err; Hard_fail.soft_errors= next_list} + -> + Deferred.return + (Error + { Hard_fail.hard_error= hard_err + ; soft_errors= List.append err_list next_list }) ) + | Error _ as error -> + Deferred.return error + + let map = `Define_using_bind +end) + +let%test_unit "error_monad_unit_test_1" = + Async.Thread_safe.block_on_async_exn (fun () -> + let open Deferred.Let_syntax in + let%map test1 = + let open ErrorReporting.Let_syntax in + let f nm = + let%bind n = nm in + Deferred.return + (Ok {Accumulator.computation_result= n + 1; soft_errors= []}) + in + f (f (f (f (f (return 0))))) + in + [%test_eq: (int Accumulator.t, Hard_fail.t) Result.t] test1 + (Ok {Accumulator.computation_result= 5; soft_errors= []}) ) + +let%test_unit "error_monad_unit_test_2" = + Async.Thread_safe.block_on_async_exn (fun () -> + let open Deferred.Let_syntax in + let%map test2 = + let open ErrorReporting.Let_syntax in + let%bind () = + Deferred.return + (Ok {Accumulator.computation_result= (); soft_errors= []}) + in + Deferred.return + (Ok {Accumulator.computation_result= "123"; soft_errors= []}) + in + [%test_eq: (string Accumulator.t, Hard_fail.t) Result.t] test2 + (Ok {Accumulator.computation_result= "123"; soft_errors= []}) ) + +let%test_unit "error_monad_unit_test_3" = + Async.Thread_safe.block_on_async_exn (fun () -> + let open Deferred.Let_syntax in + let%map test3 = + let open ErrorReporting.Let_syntax in + let%bind () = + Deferred.return + (Ok + { Accumulator.computation_result= () + ; soft_errors= [Error.of_string "a"] }) + in + Deferred.return + (Ok + { Accumulator.computation_result= "123" + ; soft_errors= [Error.of_string "b"] }) + in + [%test_eq: (string Accumulator.t, Hard_fail.t) Result.t] test3 + (Ok + { Accumulator.computation_result= "123" + ; soft_errors= List.map ["a"; "b"] ~f:Error.of_string }) ) + +let%test_unit "error_monad_unit_test_4" = + Async.Thread_safe.block_on_async_exn (fun () -> + let open Deferred.Let_syntax in + let%map test4 = + let open ErrorReporting.Let_syntax in + let%bind () = + Deferred.return + (Ok {Accumulator.computation_result= (); soft_errors= []}) + in + Deferred.return + (Error {Hard_fail.hard_error= Error.of_string "xyz"; soft_errors= []}) + in + [%test_eq: (string Accumulator.t, Hard_fail.t) Result.t] test4 + (Error {Hard_fail.hard_error= Error.of_string "xyz"; soft_errors= []}) + ) + +let%test_unit "error_monad_unit_test_5" = + Async.Thread_safe.block_on_async_exn (fun () -> + let open Deferred.Let_syntax in + let%map test5 = + let open ErrorReporting.Let_syntax in + let%bind () = + Deferred.return + (Ok + { Accumulator.computation_result= () + ; soft_errors= [Error.of_string "a"] }) + in + Deferred.return + (Error {Hard_fail.hard_error= Error.of_string "xyz"; soft_errors= []}) + in + [%test_eq: (string Accumulator.t, Hard_fail.t) Result.t] test5 + (Error + { Hard_fail.hard_error= Error.of_string "xyz" + ; soft_errors= [Error.of_string "a"] }) ) + +let%test_unit "error_monad_unit_test_6" = + Async.Thread_safe.block_on_async_exn (fun () -> + let open Deferred.Let_syntax in + let%map test6 = + let open ErrorReporting.Let_syntax in + let%bind () = + Deferred.return + (Ok + { Accumulator.computation_result= () + ; soft_errors= [Error.of_string "a"] }) + in + Deferred.return + (Error + { Hard_fail.hard_error= Error.of_string "xyz" + ; soft_errors= [Error.of_string "b"] }) + in + [%test_eq: (string Accumulator.t, Hard_fail.t) Result.t] test6 + (Error + { Hard_fail.hard_error= Error.of_string "xyz" + ; soft_errors= [Error.of_string "a"; Error.of_string "b"] }) ) diff --git a/src/lib/network_peer/envelope.ml b/src/lib/network_peer/envelope.ml index 6126e7007ff..002263d5e1b 100644 --- a/src/lib/network_peer/envelope.ml +++ b/src/lib/network_peer/envelope.ml @@ -38,10 +38,36 @@ module Sender = struct failwith "Sender.remote_exn of Local sender" | Remote x -> x + + let gen : t Quickcheck.Generator.t = + let open Quickcheck.Generator.Let_syntax in + let%bind ip = + match%map + Quickcheck.Generator.( + variant2 + (list_with_length 4 (Int.gen_incl 0 255)) + (list_with_length 8 (Int.gen_incl 0 65535))) + with + | `A octets -> + String.concat ~sep:"." (List.map ~f:Int.to_string octets) + | `B segments -> + String.concat ~sep:":" (List.map ~f:(Printf.sprintf "%x") segments) + in + let remote = + let inet = Unix.Inet_addr.of_string ip in + let%map peerid = String.gen_nonempty in + (inet, peerid) + in + match%map Option.quickcheck_generator remote with + | None -> + Local + | Some remote -> + Remote remote end module Incoming = struct - type 'a t = {data: 'a; sender: Sender.t} [@@deriving eq, sexp, yojson] + type 'a t = {data: 'a; sender: Sender.t} + [@@deriving eq, sexp, yojson, compare] let sender t = t.sender @@ -63,4 +89,10 @@ module Incoming = struct failwith "Incoming.sender_sender_exn of Local envelope" | Remote x -> x + + let gen gen_a = + let open Quickcheck.Generator.Let_syntax in + let%bind data = gen_a in + let%map sender = Sender.gen in + {data; sender} end diff --git a/src/lib/network_peer/envelope.mli b/src/lib/network_peer/envelope.mli index 06dd726e47a..e151863065c 100644 --- a/src/lib/network_peer/envelope.mli +++ b/src/lib/network_peer/envelope.mli @@ -2,13 +2,14 @@ open Core module Sender : sig type t = Local | Remote of (Unix.Inet_addr.Stable.V1.t * Peer.Id.t) - [@@deriving sexp, eq, yojson] + [@@deriving sexp, eq, yojson, compare] val remote_exn : t -> Unix.Inet_addr.Stable.V1.t * Peer.Id.t end module Incoming : sig - type 'a t = {data: 'a; sender: Sender.t} [@@deriving eq, sexp, yojson] + type 'a t = {data: 'a; sender: Sender.t} + [@@deriving eq, sexp, yojson, compare] val sender : 'a t -> Sender.t @@ -23,4 +24,6 @@ module Incoming : sig val local : 'a -> 'a t val remote_sender_exn : 'a t -> Unix.Inet_addr.Stable.V1.t * Peer.Id.t + + val gen : 'a Quickcheck.Generator.t -> 'a t Quickcheck.Generator.t end diff --git a/src/lib/network_pool/snark_pool.ml b/src/lib/network_pool/snark_pool.ml index c91fd1ed8c7..1ada4e9c316 100644 --- a/src/lib/network_pool/snark_pool.ml +++ b/src/lib/network_pool/snark_pool.ml @@ -99,28 +99,99 @@ module Make (Transition_frontier : Transition_frontier_intf) : val create : Verifier.t -> t + type proof_envelope = + (Ledger_proof.t One_or_two.t * Coda_base.Sok_message.t) + Envelope.Incoming.t + [@@deriving sexp] + + module Work_key : sig + type t = + (Transaction_snark.Statement.t One_or_two.t * Coda_base.Sok_message.t) + Envelope.Incoming.t + + include Comparable.S with type t := t + end + val verify : t - -> (Ledger_proof.t * Coda_base.Sok_message.t) list - -> bool Deferred.Or_error.t + -> proof_envelope list + -> [`Invalid of Work_key.Set.t] Deferred.Or_error.t end = struct + type proof_envelope = + (Ledger_proof.t One_or_two.t * Coda_base.Sok_message.t) + Envelope.Incoming.t + [@@deriving sexp] + + module Work_key = struct + module T = struct + type t = + (Transaction_snark.Statement.t One_or_two.t * Coda_base.Sok_message.t) + Envelope.Incoming.t + [@@deriving sexp, compare] + end + + let of_proof_envelope t = + Envelope.Incoming.map t ~f:(fun (ps, message) -> + (One_or_two.map ~f:Ledger_proof.statement ps, message) ) + + include T + include Comparable.Make (T) + end + type state = | Waiting | Verifying of - { out_for_verification: - (Ledger_proof.t * Coda_base.Sok_message.t) list - ; next_finished: bool Or_error.t Ivar.t sexp_opaque } + { out_for_verification: proof_envelope list + ; next_finished: + [`Invalid of Work_key.Set.t] Or_error.t Ivar.t sexp_opaque } [@@deriving sexp] type t = { mutable state: state - ; queue: (Ledger_proof.t * Coda_base.Sok_message.t) Queue.t + ; queue: proof_envelope Queue.t ; verifier: Verifier.t sexp_opaque } [@@deriving sexp] let create verifier = {state= Waiting; queue= Queue.create (); verifier} - let call_verifier t ps = Verifier.verify_transaction_snarks t.verifier ps + let call_verifier verifier (ps : proof_envelope list) = + let ps = + List.concat_map ps ~f:(fun env -> + let ps, message = env.data in + One_or_two.map ps ~f:(fun p -> (p, message)) |> One_or_two.to_list + ) + in + Verifier.verify_transaction_snarks verifier ps + + (*Worst case (if all the proofs are invalid): log n * (2^(log n) + 1) + In the average case this should show better performance. + We need to implement the trusted/untrusted batches from the snark pool batching RFC #4882 to avoid possible DoS/DDoS here*) + let find_invalid_proofs ps verifier = + let open Deferred.Or_error.Let_syntax in + let length = List.length ps in + let rec go ps set = + match ps with + | [] -> + return set + | [p] -> + return Work_key.(Set.add set (of_proof_envelope p)) + | ps -> ( + let left = List.take ps (length / 2) in + let right = List.drop ps (length / 2) in + let%bind res_l = call_verifier verifier left in + let%bind res_r = call_verifier verifier right in + match (res_l, res_r) with + | true, false -> + go right set + | false, true -> + go left set + | false, false -> + let%bind set' = go left set in + go right set' + | true, true -> + return set ) + in + go ps Work_key.Set.empty (* When new proofs come in put them in the queue. If state = Waiting, verify those proofs immediately. @@ -128,30 +199,145 @@ module Make (Transition_frontier : Transition_frontier_intf) : *) let rec start_verifier t finished = + let empty_set = Work_key.Set.empty in if Queue.is_empty t.queue then ( (* we looped in the else after verifier finished but no pending work. *) t.state <- Waiting ; - Ivar.fill finished (Ok true) ) + Ivar.fill finished (Ok (`Invalid empty_set)) ) else let out_for_verification = Queue.to_list t.queue in let next_finished = Ivar.create () in t.state <- Verifying {next_finished; out_for_verification} ; Queue.clear t.queue ; - let res = call_verifier t out_for_verification in - upon res (fun x -> - Ivar.fill finished x ; - start_verifier t next_finished ) - - let verify t proofs = - if List.is_empty proofs then Deferred.return (Ok true) - else ( - Queue.enqueue_all t.queue proofs ; - match t.state with - | Verifying {next_finished; _} -> - Ivar.read next_finished - | Waiting -> - let finished = Ivar.create () in - start_verifier t finished ; Ivar.read finished ) + let res = call_verifier t.verifier out_for_verification in + upon res (fun verification_res -> + let any_invalid_proofs = + let open Deferred.Or_error.Let_syntax in + match verification_res with + | Ok true -> + return (`Invalid empty_set) + | Ok false -> + (*ordering by sender with the assumption that all the proofs from a malicious sender would be invalid and therefore will increase the probability of them being in a single batch*) + let ordered_list = + List.sort out_for_verification ~compare:(fun e1 e2 -> + Envelope.Sender.compare e1.sender e2.sender ) + in + (*Find invalid proofs*) + let%map ps = find_invalid_proofs ordered_list t.verifier in + `Invalid ps + | Error e -> + Deferred.return (Error e) + in + upon any_invalid_proofs (fun y -> Ivar.fill finished y) ) ; + start_verifier t next_finished + + let verify t proofs : [`Invalid of Work_key.Set.t] Deferred.Or_error.t = + Queue.enqueue_all t.queue proofs ; + match t.state with + | Verifying {next_finished; _} -> + Ivar.read next_finished + | Waiting -> + let finished = Ivar.create () in + start_verifier t finished ; Ivar.read finished + + let%test_module "With valid and invalid proofs" = + ( module struct + open Coda_base + + let proof_level = Genesis_constants.Proof_level.for_unit_tests + + let logger = Logger.null () + + let gen_proofs = + let open Quickcheck.Generator.Let_syntax in + let data_gen = + let%bind statements = + One_or_two.gen Transaction_snark.Statement.gen + in + let%map {fee; prover} = Fee_with_prover.gen in + let message = Coda_base.Sok_message.create ~fee ~prover in + ( One_or_two.map statements ~f:Ledger_proof.For_tests.mk_dummy_proof + , message ) + in + Envelope.Incoming.gen data_gen + + let gen_invalid_proofs = + let open Quickcheck.Generator.Let_syntax in + let data_gen = + let%bind statements = + One_or_two.gen Transaction_snark.Statement.gen + in + let%bind {fee; prover} = Fee_with_prover.gen in + let%map invalid_prover = + Quickcheck.Generator.filter + Signature_lib.Public_key.Compressed.gen + ~f:(Signature_lib.Public_key.Compressed.( <> ) prover) + in + let sok_digest = + Coda_base.Sok_message.( + digest (create ~fee ~prover:invalid_prover)) + in + let message = Coda_base.Sok_message.create ~fee ~prover in + ( One_or_two.map statements ~f:(fun statement -> + Ledger_proof.create ~statement ~sok_digest + ~proof:Proof.transaction_dummy ) + , message ) + in + Envelope.Incoming.gen data_gen + + let run_test proof_lists = + let%bind verifier = + Verifier.create ~logger ~proof_level + ~pids:(Child_processes.Termination.create_pid_table ()) + ~conf_dir:None + in + let batcher = create verifier in + Deferred.List.iter proof_lists + ~f:(fun (invalid_proofs, proof_list) -> + let%map r = verify batcher proof_list in + let (`Invalid ps) = Or_error.ok_exn r in + assert (Work_key.Set.equal ps invalid_proofs) ) + + let gen ~(valid_count : [`Any | `Count of int]) + ~(invalid_count : [`Any | `Count of int]) = + let open Quickcheck.Generator.Let_syntax in + let gen_with_count count gen = + match count with + | `Any -> + Quickcheck.Generator.list_non_empty gen + | `Count c -> + Quickcheck.Generator.list_with_length c gen + in + let invalid_gen = gen_with_count invalid_count gen_invalid_proofs in + let valid_gen = gen_with_count valid_count gen_proofs in + let%map lst = + Quickcheck.Generator.(list (both valid_gen invalid_gen)) + in + List.map lst ~f:(fun (valid, invalid) -> + ( Work_key.(Set.of_list (List.map ~f:of_proof_envelope invalid)) + , List.permute valid @ invalid ) ) + + let%test_unit "all valid proofs" = + Quickcheck.test ~trials:10 + (gen ~valid_count:`Any ~invalid_count:(`Count 0)) + ~f:(fun proof_lists -> + Async.Thread_safe.block_on_async_exn (fun () -> + run_test proof_lists ) ) + + let%test_unit "some invalid proofs" = + Quickcheck.test ~trials:10 + (gen ~valid_count:`Any ~invalid_count:`Any) + ~f:(fun proof_lists -> + Async.Thread_safe.block_on_async_exn (fun () -> + run_test proof_lists ) ) + + let%test_unit "all invalid proofs" = + Quickcheck.test ~trials:10 + (gen ~valid_count:(`Count 0) ~invalid_count:`Any) + ~f:(fun proof_lists -> + Async.Thread_safe.block_on_async_exn (fun () -> + run_test proof_lists ) ) + end ) end module Resource_pool = struct @@ -327,22 +513,18 @@ module Make (Transition_frontier : Transition_frontier_intf) : Trust_system.record_envelope_sender t.config.trust_system t.logger sender in + let is_local = Envelope.Sender.(equal Local sender) in let log_and_punish ?(punish = true) statement e = - (* TODO: For now, we must not punish since we batch across messages received from - different senders and we don't isolate the bad proof in a batch, so we cannot - properly attribute blame. - *) - ignore punish ; - let punish = false in let metadata = [ ("work_id", `Int (Transaction_snark.Statement.hash statement)) ; ("prover", Signature_lib.Public_key.Compressed.to_yojson prover) ; ("fee", Currency.Fee.to_yojson fee) - ; ("error", `String (Error.to_string_hum e)) ] + ; ("error", `String (Error.to_string_hum e)) + ; ("sender", Envelope.Sender.to_yojson sender) ] in [%log' error t.logger] ~metadata - "Error verifying transaction snark: $error" ; - if punish then + "Error verifying transaction snark from $sender: $error" ; + if punish && not is_local then trust_record ( Trust_system.Actions.Sent_invalid_proof , Some ("Error verifying transaction snark: $error", metadata) ) @@ -351,38 +533,51 @@ module Make (Transition_frontier : Transition_frontier_intf) : let message = Coda_base.Sok_message.create ~fee ~prover in let verify proofs = let open Deferred.Let_syntax in - let bad_statements = - List.filter_map proofs ~f:(fun (p, s) -> - if - Transaction_snark.Statement.( <> ) (Ledger_proof.statement p) - s - then Some s - else None ) + let%bind statement_check = + One_or_two.Deferred_result.map proofs ~f:(fun (p, s) -> + let proof_statement = Ledger_proof.statement p in + if Transaction_snark.Statement.( = ) proof_statement s then + Deferred.Or_error.ok_unit + else + let e = Error.of_string "Statement and proof do not match" in + if is_local then + [%log' debug t.logger] + !"Statement and proof mismatch. Proof statement: \ + %{sexp:Transaction_snark.Statement.t} Statement \ + %{sexp: Transaction_snark.Statement.t}" + proof_statement s ; + let%map () = log_and_punish s e in + Error e ) in - match bad_statements with - | _ :: _ -> - let e = Error.of_string "Statement and proof do not match" in - let%map () = - Deferred.List.iter bad_statements ~f:(fun s -> - log_and_punish s e ) - in - false - | [] -> ( + match statement_check with + | Error _ -> + return false + | Ok _ -> ( let log ?punish e = - Deferred.List.iter proofs ~f:(fun (_, s) -> - log_and_punish ?punish s e ) + Deferred.List.iter (One_or_two.to_list proofs) + ~f:(fun (_, s) -> log_and_punish ?punish s e) in - match%bind - Batcher.verify t.batcher - (List.map proofs ~f:(fun (p, _) -> (p, message))) - with - | Ok true -> - Deferred.return true - | Ok false -> - (*Invalid proof*) - let e = Error.of_string "Invalid proof" in - let%map () = log e in - false + let proof_env = + { Envelope.Incoming.data= + (One_or_two.map proofs ~f:fst, message) + ; sender } + in + match%bind Batcher.verify t.batcher [proof_env] with + | Ok (`Invalid set) when Set.is_empty set -> + return true + | Ok (`Invalid set) -> + let work_key = + Envelope.Incoming.map proof_env ~f:(fun (ps, m) -> + ( One_or_two.map ps ~f:(fun p -> + Ledger_proof.statement p ) + , m ) ) + in + if Set.mem set work_key then + (* if this proof is in the set of invalid proofs*) + let e = Error.of_string "Invalid proof" in + let%map () = log e in + false + else return true | Error e -> (* Verifier crashed or other errors at our end. Don't punish the peer*) let%map () = log ~punish:false e in @@ -390,7 +585,7 @@ module Make (Transition_frontier : Transition_frontier_intf) : in match One_or_two.zip proofs statements with | Ok pairs -> - verify (One_or_two.to_list pairs) + verify pairs | Error e -> [%log' error t.logger] ~metadata:[("error", `String (Error.to_string_hum e))] @@ -569,8 +764,7 @@ let%test_module "random set test" = let open Deferred.Let_syntax in Deferred.List.iter sample_solved_work ~f:(fun (work, fee) -> let%map res = apply_diff resource_pool work fee in - assert (Result.is_ok res) ; - () ) + assert (Result.is_ok res) ) in resource_pool in diff --git a/src/lib/network_pool/snark_pool_diff.ml b/src/lib/network_pool/snark_pool_diff.ml index 43024cc2766..71b6d74fc4a 100644 --- a/src/lib/network_pool/snark_pool_diff.ml +++ b/src/lib/network_pool/snark_pool_diff.ml @@ -63,11 +63,44 @@ module Make ~f:Snark_work_lib.Work.Single.Spec.statement , {proof= res.proofs; fee= {fee= res.spec.fee; prover= res.prover}} ) - let verify pool - ({data= Add_solved_work (work, p); sender} : t Envelope.Incoming.t) = - Pool.verify_and_act pool ~work:(work, p) ~sender + let has_lower_fee pool work ~fee ~sender = + let reject_and_log_if_local reason = + [%log' trace (Pool.get_logger pool)] + "Rejecting snark work $work from $sender: $reason" + ~metadata: + [ ("work", Work.compact_json work) + ; ("sender", Envelope.Sender.to_yojson sender) + ; ("reason", `String reason) ] ; + Or_error.error_string reason + in + match Pool.request_proof pool work with + | None -> + Ok () + | Some {fee= {fee= prev; _}; _} -> ( + match Currency.Fee.compare fee prev with + | -1 -> + Ok () + | 0 -> + reject_and_log_if_local "fee equal to cheapest work we have" + | 1 -> + reject_and_log_if_local "fee higher than cheapest work we have" + | _ -> + failwith "compare didn't return -1, 0, or 1!" ) + + let verify pool ({data; sender} : t Envelope.Incoming.t) = + let (Add_solved_work (work, ({Priced_proof.fee; _} as p))) = data in + let is_local = match sender with Local -> true | _ -> false in + let verify () = Pool.verify_and_act pool ~work:(work, p) ~sender in + (*reject higher priced gossiped proofs*) + if is_local then verify () + else + match has_lower_fee pool work ~fee:fee.fee ~sender with + | Ok () -> + verify () + | _ -> + return false - (* This is called after verification has occurred. *) + (* This is called after verification has occurred.*) let unsafe_apply (pool : Pool.t) (t : t Envelope.Incoming.t) = let {Envelope.Incoming.data= diff; sender} = t in let is_local = match sender with Local -> true | _ -> false in @@ -78,31 +111,14 @@ module Make Ok (diff, ()) in Deferred.return - ( match diff with - | Add_solved_work (work, {Priced_proof.proof; fee}) -> ( - let reject_and_log_if_local reason = - if is_local then ( - [%log' trace (Pool.get_logger pool)] - "Rejecting locally generated snark work $work: $reason" - ~metadata: - [("work", Work.compact_json work); ("reason", `String reason)] ; - Error (`Locally_generated (diff, ())) ) - else Error (`Other (Error.of_string reason)) - in - let add_to_pool () = - Pool.add_snark ~is_local pool ~work ~proof ~fee |> to_or_error - in - match Pool.request_proof pool work with - | None -> - add_to_pool () - | Some {fee= {fee= prev; _}; _} -> ( - match Currency.Fee.compare fee.fee prev with - | -1 -> - add_to_pool () - | 0 -> - reject_and_log_if_local "fee equal to cheapest work we have" - | 1 -> - reject_and_log_if_local "fee higher than cheapest work we have" - | _ -> - failwith "compare didn't return -1, 0, or 1!" ) ) ) + (let (Add_solved_work (work, {Priced_proof.proof; fee})) = diff in + let add_to_pool () = + Pool.add_snark ~is_local pool ~work ~proof ~fee |> to_or_error + in + match has_lower_fee pool work ~fee:fee.fee ~sender with + | Ok () -> + add_to_pool () + | Error e -> + if is_local then Error (`Locally_generated (diff, ())) + else Error (`Other e)) end diff --git a/src/app/client_sdk/raw.ml b/src/lib/rosetta_lib/coding.ml similarity index 81% rename from src/app/client_sdk/raw.ml rename to src/lib/rosetta_lib/coding.ml index f2bc0027120..aa8ae3e0108 100644 --- a/src/app/client_sdk/raw.ml +++ b/src/lib/rosetta_lib/coding.ml @@ -1,7 +1,23 @@ -(* raw.ml -- raw hex encoding for Rosetta *) +(* coding.ml -- hex encoding/decoding for Rosetta *) + +[%%import +"/src/config.mlh"] open Core_kernel +[%%ifdef +consensus_mechanism] + +module Field = Snark_params.Tick.Field +open Signature_lib + +[%%else] + +module Field = Snark_params_nonconsensus.Field +open Signature_lib_nonconsensus + +[%%endif] + (* see RFC 0038, section "marshal-keys" for a specification *) let hex_char_to_bits4 = function @@ -48,7 +64,7 @@ let bits4_to_hex_char bits = s.[0] let of_field field = - let bits0 = Snark_params_nonconsensus.Field.unpack field |> List.rev in + let bits0 = Field.unpack field |> List.rev in assert (Int.equal (List.length bits0) 255) ; (* field elements are 255 bits, left-pad to get 32 bytes *) let bits = false :: bits0 in @@ -72,15 +88,13 @@ let to_field raw = in (* remove padding bit *) let bits = List.tl_exn bits0 |> List.rev in - Option.value_exn (Snark_params_nonconsensus.Field.of_bits bits) + Field.project bits let of_public_key pk = let field1, field2 = pk in of_field field1 ^ of_field field2 -let of_public_key_compressed pk = - let open Signature_lib_nonconsensus in - Public_key.decompress_exn pk |> of_public_key +let of_public_key_compressed pk = Public_key.decompress_exn pk |> of_public_key let to_public_key raw = let len = String.length raw in @@ -89,15 +103,12 @@ let to_public_key raw = let raw2 = String.sub raw ~pos:field_len ~len:field_len in (to_field raw1, to_field raw2) -let to_public_key_compressed raw = - let open Signature_lib_nonconsensus in - to_public_key raw |> Public_key.compress +let to_public_key_compressed raw = to_public_key raw |> Public_key.compress (* inline tests hard-to-impossible to setup with JS *) let field_example_test () = (* from RFC 0038 *) - let open Snark_params_nonconsensus in let field = Field.of_int 123123 in let hex = of_field field in let last_part = "01E0F3" in @@ -106,21 +117,29 @@ let field_example_test () = String.equal hex expected let field_hex_roundtrip_test () = - let open Snark_params_nonconsensus in let field0 = Field.of_int 123123 in let hex = of_field field0 in let field1 = to_field hex in Field.equal field0 field1 let pk_roundtrip_test () = - let open Snark_params_nonconsensus in - let open Signature_lib_nonconsensus in let field0 = Field.of_int 123123 in let field1 = Field.of_int 234234 in let hex = of_public_key (field0, field1) in let field0', field1' = to_public_key hex in Public_key.equal (field0, field1) (field0', field1') +let%test "field_example" = field_example_test () + +let%test "field_hex round-trip" = field_hex_roundtrip_test () + +let%test "public key round-trip" = pk_roundtrip_test () + +[%%ifndef +consensus_mechanism] + +(* for running tests from JS *) + let unit_tests = [ ("field example", field_example_test) ; ("field-hex round-trip", field_hex_roundtrip_test) @@ -130,3 +149,5 @@ let run_unit_tests () = List.iter unit_tests ~f:(fun (name, test) -> printf "Running %s test\n%!" name ; assert (test ()) ) + +[%%endif] diff --git a/src/lib/rosetta_lib/dune b/src/lib/rosetta_lib/dune new file mode 100644 index 00000000000..440c61fe877 --- /dev/null +++ b/src/lib/rosetta_lib/dune @@ -0,0 +1,9 @@ +(library + (name rosetta_lib) + (public_name rosetta_lib) + (library_flags -linkall) + (inline_tests) + (libraries core_kernel snark_params signature_lib) + (preprocessor_deps ../../config.mlh) + (preprocess (pps ppx_version ppx_optcomp ppx_inline_test)) + (synopsis "Rosetta-related support code")) diff --git a/src/lib/rosetta_lib/test/dune b/src/lib/rosetta_lib/test/dune new file mode 100644 index 00000000000..277ff57b7d4 --- /dev/null +++ b/src/lib/rosetta_lib/test/dune @@ -0,0 +1,9 @@ +(executable + (package rosetta_lib) + (name test_encodings) + (public_name test_encodings) + (modes native) + (modules test_encodings) + (libraries core_kernel signature_lib rosetta_lib) + (preprocessor_deps ../../../config.mlh) + (preprocess (pps ppx_version ppx_optcomp))) diff --git a/src/lib/rosetta_lib/test/test_encodings.ml b/src/lib/rosetta_lib/test/test_encodings.ml new file mode 100644 index 00000000000..7964d622297 --- /dev/null +++ b/src/lib/rosetta_lib/test/test_encodings.ml @@ -0,0 +1,33 @@ +(* test_encodings.ml -- print out Rosetta encodings *) + +[%%import +"/src/config.mlh"] + +open Core_kernel + +[%%ifdef +consensus_mechanism] + +open Signature_lib +open Rosetta_lib + +[%%else] + +open Signature_lib_nonconsensus +open Rosetta_lib_nonconsensus + +[%%endif] + +let pk1 = + Public_key.Compressed.of_base58_check_exn + "B62qkef7po74VEvJYcLYsdZ83FuKidgNZ8Xiaitzo8gKJXaxLwxgG7T" + +let pk2 = + Public_key.Compressed.of_base58_check_exn + "B62qnekV6LVbEttV7j3cxJmjSbxDWuXa5h3KeVEXHPGKTzthQaBufrY" + +let main () = + printf "%s\n%!" (Coding.of_public_key_compressed pk1) ; + printf "%s\n%!" (Coding.of_public_key_compressed pk2) + +let _ = main () diff --git a/src/lib/snark_worker/functor.ml b/src/lib/snark_worker/functor.ml index 27137e9dc52..24efd4febe8 100644 --- a/src/lib/snark_worker/functor.ml +++ b/src/lib/snark_worker/functor.ml @@ -170,6 +170,8 @@ module Make (Inputs : Intf.Inputs_intf) : +. (0.5 *. Random.float Worker_state.worker_wait_time) in (* No work to be done -- quietly take a brief nap *) + [%log info] "No jobs available. Napping for $time seconds" + ~metadata:[("time", `Float random_delay)] ; let%bind () = wait ~sec:random_delay () in go () | Ok (Some (work, public_key)) -> ( diff --git a/src/lib/verifier/dummy.ml b/src/lib/verifier/dummy.ml index 322836650c1..a4544d01fd6 100644 --- a/src/lib/verifier/dummy.ml +++ b/src/lib/verifier/dummy.ml @@ -17,12 +17,11 @@ let verify_blockchain_snark _ _ = Deferred.Or_error.return true let verify_transaction_snarks _ ts = (*Don't check if the proof has default sok becasue they were probably not - intended to be checked. If it has something value then check that against the + intended to be checked. If it has some value then check that against the message passed. This is particularly used to test that invalid proofs are not added to the snark pool*) List.for_all ts ~f:(fun (proof, message) -> - if Sok_message.Digest.(equal (snd proof) default) then true - else - let msg_digest = Sok_message.digest message in - Coda_base.Sok_message.Digest.equal (snd proof) msg_digest ) + let msg_digest = Sok_message.digest message in + Sok_message.Digest.(equal (snd proof) default) + || Coda_base.Sok_message.Digest.equal (snd proof) msg_digest ) |> Deferred.Or_error.return diff --git a/src/nonconsensus/coda_base/dune b/src/nonconsensus/coda_base/dune index 1954cff7cba..eea8fe3602d 100644 --- a/src/nonconsensus/coda_base/dune +++ b/src/nonconsensus/coda_base/dune @@ -8,6 +8,7 @@ coda_compile_config_nonconsensus currency_nonconsensus hash_prefix_states_nonconsensus + hex_nonconsensus outside_hash_image_nonconsensus signature_lib_nonconsensus snark_params_nonconsensus diff --git a/src/nonconsensus/hex/dune b/src/nonconsensus/hex/dune new file mode 100644 index 00000000000..4093f272b05 --- /dev/null +++ b/src/nonconsensus/hex/dune @@ -0,0 +1,6 @@ +(library + (name hex_nonconsensus) + (public_name hex_nonconsensus) + (inline_tests) + (preprocess (pps ppx_jane ppx_version ppx_inline_test)) + (libraries core_kernel)) diff --git a/src/nonconsensus/hex/hex.ml b/src/nonconsensus/hex/hex.ml new file mode 120000 index 00000000000..2b4caf60bd8 --- /dev/null +++ b/src/nonconsensus/hex/hex.ml @@ -0,0 +1 @@ +../../lib/hex/hex.ml \ No newline at end of file diff --git a/src/nonconsensus/rosetta_lib/coding.ml b/src/nonconsensus/rosetta_lib/coding.ml new file mode 120000 index 00000000000..2634cfdbc0b --- /dev/null +++ b/src/nonconsensus/rosetta_lib/coding.ml @@ -0,0 +1 @@ +../../lib/rosetta_lib/coding.ml \ No newline at end of file diff --git a/src/nonconsensus/rosetta_lib/dune b/src/nonconsensus/rosetta_lib/dune new file mode 100644 index 00000000000..6a724d50e93 --- /dev/null +++ b/src/nonconsensus/rosetta_lib/dune @@ -0,0 +1,9 @@ +(library + (name rosetta_lib_nonconsensus) + (public_name rosetta_lib_nonconsensus) + (library_flags -linkall) + (inline_tests) + (libraries core_kernel snark_params_nonconsensus signature_lib_nonconsensus) + (preprocessor_deps ../../config.mlh) + (preprocess (pps ppx_version ppx_optcomp ppx_inline_test)) + (synopsis "Rosetta-related support code for nonconsensus")) diff --git a/src/nonconsensus/rosetta_lib/test/dune b/src/nonconsensus/rosetta_lib/test/dune new file mode 100644 index 00000000000..6c2431f83e8 --- /dev/null +++ b/src/nonconsensus/rosetta_lib/test/dune @@ -0,0 +1,9 @@ +(executable + (package rosetta_lib) + (name test_encodings) + (public_name test_encodings) + (modes native) + (modules test_encodings) + (libraries core_kernel signature_lib_nonconsensus rosetta_lib_nonconsensus) + (preprocessor_deps ../../../config.mlh) + (preprocess (pps ppx_version ppx_optcomp))) diff --git a/src/nonconsensus/rosetta_lib/test/test_encodings.ml b/src/nonconsensus/rosetta_lib/test/test_encodings.ml new file mode 120000 index 00000000000..7500f2d8ded --- /dev/null +++ b/src/nonconsensus/rosetta_lib/test/test_encodings.ml @@ -0,0 +1 @@ +../../../lib/rosetta_lib/test/test_encodings.ml \ No newline at end of file diff --git a/src/rosetta_lib.opam b/src/rosetta_lib.opam new file mode 100644 index 00000000000..a1b56499734 --- /dev/null +++ b/src/rosetta_lib.opam @@ -0,0 +1,5 @@ +opam-version: "1.2" +version: "0.1" +build: [ + ["dune" "build" "--only" "src" "--root" "." "-j" jobs "@install"] +] diff --git a/src/rosetta_lib_nonconsensus.opam b/src/rosetta_lib_nonconsensus.opam new file mode 100644 index 00000000000..a1b56499734 --- /dev/null +++ b/src/rosetta_lib_nonconsensus.opam @@ -0,0 +1,5 @@ +opam-version: "1.2" +version: "0.1" +build: [ + ["dune" "build" "--only" "src" "--root" "." "-j" jobs "@install"] +]