Create docs navigation sidebar (#40)

* crawl files and create directory tree for sidebar

* dropdown

* Working on dropdown links and styling

* setup header nav

* Styles

* DocumentNav sidebar done

* wrap up header sidebar

* setup top level nav

* update root level data and fix link bug

* doc links yaml

* nav links for docs

* remove character

* prettier

* fix build error

* MDX style

* Update src/components/UI/docs/DocsLinks.tsx

Co-authored-by: Paul Wackerow <54227730+wackerow@users.noreply.github.com>

* Abstract LinksList component into its own file

* change requests

* AccordionButton styles

* AccordionButton styled

* fix broken links

* prettier

* prettier

* fix broken default code snippet

* fix accordion spacing

* fix gap at top of DocsNav lg

* fix but of persistent header link

* remove test content

* setup Notes and prettier

* rehype

* Note component

* Note font styling

* convert old notes to use component

* Breadcrumb cleanup and prettier

* MDXComponents -> MDComponent and documentation

Co-authored-by: Paul Wackerow <54227730+wackerow@users.noreply.github.com>
This commit is contained in:
Corwin Smith 2022-12-01 01:06:59 +01:00 committed by GitHub
parent fc52cc75e4
commit 0b9ff8b1e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 916 additions and 230 deletions

View File

@ -49,3 +49,11 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
## Adding a new documentation page
Documentation pages are located in the `/docs` folder in the root directory of the project.
When you want to add a new page, add the new file in the appropriate folder in the `/docs` page. `index.md` files will be the default page for a directory, and `{pagename}.md` will define subpages for a directory.
After adding this page, you will need to add it `/src/data/documentation-links.yaml` which adds documentation structure which you will see on the left sidebar in the documentation pages.

View File

@ -12,11 +12,8 @@ If you'd like to contribute to the Geth source code, please fork the [Github rep
Please make sure your contributions adhere to our coding guidelines: Please make sure your contributions adhere to our coding guidelines:
- Code must adhere to the official Go formatting guidelines (i.e. uses gofmt). - Code must adhere to the official Go formatting guidelines (i.e. uses gofmt).
- Code must be documented adhering to the official Go commentary guidelines. - Code must be documented adhering to the official Go commentary guidelines.
- Pull requests need to be based on and opened against the master branch. - Pull requests need to be based on and opened against the master branch.
- Commit messages should be prefixed with the package(s) they modify. - Commit messages should be prefixed with the package(s) they modify.
E.g. "eth, rpc: make trace configs optional" E.g. "eth, rpc: make trace configs optional"

View File

@ -176,7 +176,6 @@ Return:
Things to note about the call tracer: Things to note about the call tracer:
- Calls to precompiles are also included in the result - Calls to precompiles are also included in the result
- In case a frame reverts, the field `output` will contain the raw return data - In case a frame reverts, the field `output` will contain the raw return data
- In case the top level frame reverts, its `revertReason` field will contain the parsed reason of revert as returned by the Solidity contract - In case the top level frame reverts, its `revertReason` field will contain the parsed reason of revert as returned by the Solidity contract
@ -186,7 +185,6 @@ Things to note about the call tracer:
`callTracer` accepts two options: `callTracer` accepts two options:
- `onlyTopCall: true` instructs the tracer to only process the main (top-level) call and none of the sub-calls. This avoids extra processing for each call frame if only the top-level call info are required. - `onlyTopCall: true` instructs the tracer to only process the main (top-level) call and none of the sub-calls. This avoids extra processing for each call frame if only the top-level call info are required.
- `withLog: true` instructs the tracer to also collect the logs emitted during each call. - `withLog: true` instructs the tracer to also collect the logs emitted during each call.
Example invokation with the `onlyTopCall` flag: Example invokation with the `onlyTopCall` flag:

View File

@ -6,15 +6,10 @@ description: Instructions for setting up Geth in developer mode
It is often convenient for developers to work in an environment where changes to client or application software can be deployed and tested rapidly and without putting real-world users or assets at risk. For this purpose, Geth has a `--dev` flag that spins up Geth in "developer mode". This creates a single-node Ethereum test network with no connections to any external peers. It exists solely on the local machine. Starting Geth in developer mode does the following: It is often convenient for developers to work in an environment where changes to client or application software can be deployed and tested rapidly and without putting real-world users or assets at risk. For this purpose, Geth has a `--dev` flag that spins up Geth in "developer mode". This creates a single-node Ethereum test network with no connections to any external peers. It exists solely on the local machine. Starting Geth in developer mode does the following:
- Initializes the data directory with a testing genesis block - Initializes the data directory with a testing genesis block
- Sets max peers to 0 (meaning Geth does not search for peers) - Sets max peers to 0 (meaning Geth does not search for peers)
- Turns off discovery by other nodes (meaning the node is invisible to other nodes) - Turns off discovery by other nodes (meaning the node is invisible to other nodes)
- Sets the gas price to 0 (no cost to send transactions) - Sets the gas price to 0 (no cost to send transactions)
- Uses the Clique proof-of-authority consensus engine which allows blocks to be mined as-needed without excessive CPU and memory consumption - Uses the Clique proof-of-authority consensus engine which allows blocks to be mined as-needed without excessive CPU and memory consumption
- Uses on-demand block generation, producing blocks when transactions are waiting to be mined - Uses on-demand block generation, producing blocks when transactions are waiting to be mined
This configuration enables developers to experiment with Geth's source code or develop new applications without having to sync to a pre-existing public network. Blocks are only mined when there are pending transactions. Developers can break things on this network without affecting other users. This page will demonstrate how to spin up a local Geth testnet and a simple smart contract will be deployed to it using the Remix online integrated development environment (IDE). This configuration enables developers to experiment with Geth's source code or develop new applications without having to sync to a pre-existing public network. Blocks are only mined when there are pending transactions. Developers can break things on this network without affecting other users. This page will demonstrate how to spin up a local Geth testnet and a simple smart contract will be deployed to it using the Remix online integrated development environment (IDE).

View File

@ -78,7 +78,7 @@ The console will hang because Clef is waiting for manual approval. Switch to the
It is critical to backup the account password safely and securely as it cannot be retrieved or reset. It is critical to backup the account password safely and securely as it cannot be retrieved or reset.
{% include note.html content=" If the password provided on account creation is lost or forgotten, there is no way to retrive it and the account will simply stay locked forever. The password MUST be backed up safely and securely! **IT IS CRITICAL TO BACKUP THE KEYSTORE AND REMEMBER PASSWORDS**" %} <Note>If the password provided on account creation is lost or forgotten, there is no way to retrive it and the account will simply stay locked forever. The password MUST be backed up safely and securely! **IT IS CRITICAL TO BACKUP THE KEYSTORE AND REMEMBER PASSWORDS**</Note>
The newly generated key files can be viewed in `<datadir>/keystore/`. The file naming format is `UTC--<date>--<address>` where `date` is the date and time of key creation formatted according to [UTC 8601](https://www.iso.org/iso-8601-date-and-time-format.html) with zero time offset and seconds precise to eight decimal places. `address` is the 40 hexadecimal characters that make up the account address without a leading `0x`, for example: The newly generated key files can be viewed in `<datadir>/keystore/`. The file naming format is `UTC--<date>--<address>` where `date` is the date and time of key creation formatted according to [UTC 8601](https://www.iso.org/iso-8601-date-and-time-format.html) with zero time offset and seconds precise to eight decimal places. `address` is the 40 hexadecimal characters that make up the account address without a leading `0x`, for example:

View File

@ -3,13 +3,13 @@ title: Light client
description: Introduction to Geth's light sync mode description: Introduction to Geth's light sync mode
--- ---
{% include note.html content="Light nodes do not currently work on proof-of-stake Ethereum, but new proof-of-stake light clients are expected to ship soon!" %} <Note>Light nodes do not currently work on proof-of-stake Ethereum, but new proof-of-stake light clients are expected to ship soon!</Note>
Running a full node is the most trustless, private, decentralized and censorship resistant way to interact with Ethereum. It is also the best choice for the health of the network, because a decentralized network relies on having many individual nodes that independently verify the head of the chain. In a full node a copy of the blockchain is stored locally enabling users to verify incoming data against a local source of truth. However, running a full node requires a lot of disk space and non-negligible CPU allocation and takes hours (for snap sync) or days (for full sync) to sync the blockchain from genesis. Geth also offers a light mode that overcomes these issues and provides some of the benefits of running a node but requires only a fraction of the resources. Running a full node is the most trustless, private, decentralized and censorship resistant way to interact with Ethereum. It is also the best choice for the health of the network, because a decentralized network relies on having many individual nodes that independently verify the head of the chain. In a full node a copy of the blockchain is stored locally enabling users to verify incoming data against a local source of truth. However, running a full node requires a lot of disk space and non-negligible CPU allocation and takes hours (for snap sync) or days (for full sync) to sync the blockchain from genesis. Geth also offers a light mode that overcomes these issues and provides some of the benefits of running a node but requires only a fraction of the resources.
Read more about the reasons to run nodes on [ethereum.org](https://ethereum.org/en/run-a-node/). Read more about the reasons to run nodes on [ethereum.org](https://ethereum.org/en/run-a-node/).
{% include note.html content=" Geth light clients **do not currently work** on proof-of-stake Ethereum. New light clients that work with the proof-of-stake consensus engine are expected to ship soon!" %} <Note>Geth light clients **do not currently work** on proof-of-stake Ethereum. New light clients that work with the proof-of-stake consensus engine are expected to ship soon!</Note>
## Light node vs full node {#light-node-vs-full-node} ## Light node vs full node {#light-node-vs-full-node}

View File

@ -3,7 +3,7 @@ title: Proof-of-work mining with Ethash
description: Introduction to proof-of-work mining with Geth description: Introduction to proof-of-work mining with Geth
--- ---
{% include note.html content=" Proof-of-work mining is no longer used to secure Ethereum Mainnet. The information below is included because the Ethash code is still part of Geth and it could be used to create a private proof-of-work network or testnet." %} <Note>Proof-of-work mining is no longer used to secure Ethereum Mainnet. The information below is included because the Ethash code is still part of Geth and it could be used to create a private proof-of-work network or testnet.</Note>
Blockchains grow when individual nodes create valid blocks and distribute them to their peers who check the blocks and add them to their own local databases. Blockchains grow when individual nodes create valid blocks and distribute them to their peers who check the blocks and add them to their own local databases.
Nodes that add blocks are rewarded with ether payouts. On Ethereum Mainnet, the proof-of-stake consensus engine randomly selects a node to produce each block. Nodes that add blocks are rewarded with ether payouts. On Ethereum Mainnet, the proof-of-stake consensus engine randomly selects a node to produce each block.

View File

@ -3,7 +3,7 @@ title: Pruning
description: Instructions for pruning a Geth node description: Instructions for pruning a Geth node
--- ---
{% include note.html content="Offline pruning is only for the hash-based state scheme. Soon, we will have a path-based state scheme which enables the pruning by default. Once the hash-based state scheme is no longer supported, offline pruning will be deprecated." %} <Note>Offline pruning is only for the hash-based state scheme. Soon, we will have a path-based state scheme which enables the pruning by default. Once the hash-based state scheme is no longer supported, offline pruning will be deprecated.</Note>
A snap-sync'd Geth node currently requires more than 650 GB of disk space to store the historic blockchain data. With default cache size the database grows by about 14 GB/week. This means that Geth users will rapidly run out of space on 1TB hard drives. To solve this problem without needing to purchase additional hardware, Geth can be pruned. Pruning is the process of erasing older data to save disk space. Since Geth `v1.10`, users have been able to trigger a snapshot offline prune to bring the total storage back down to the original ~650 GB in about 4-5 hours. This has to be done periodically to keep the total disk storage A snap-sync'd Geth node currently requires more than 650 GB of disk space to store the historic blockchain data. With default cache size the database grows by about 14 GB/week. This means that Geth users will rapidly run out of space on 1TB hard drives. To solve this problem without needing to purchase additional hardware, Geth can be pruned. Pruning is the process of erasing older data to save disk space. Since Geth `v1.10`, users have been able to trigger a snapshot offline prune to bring the total storage back down to the original ~650 GB in about 4-5 hours. This has to be done periodically to keep the total disk storage
within the bounds of the local hardware (e.g. every month or so for a 1TB disk). within the bounds of the local hardware (e.g. every month or so for a 1TB disk).
@ -13,13 +13,9 @@ To prune a Geth node at least 40 GB of free disk space is recommended. This mean
## Pruning rules {#pruning-rules} ## Pruning rules {#pruning-rules}
1. Do not try to prune an archive node. Archive nodes need to maintain ALL historic data by definition. 1. Do not try to prune an archive node. Archive nodes need to maintain ALL historic data by definition.
2. Ensure there is at least 40 GB of storage space still available on the disk that will be pruned. Failures have been reported with ~25GB of free space. 2. Ensure there is at least 40 GB of storage space still available on the disk that will be pruned. Failures have been reported with ~25GB of free space.
3. Geth is at least `v1.10` ideally > `v1.10.3` 3. Geth is at least `v1.10` ideally > `v1.10.3`
4. Geth is fully sync'd 4. Geth is fully sync'd
5. Geth has finished creating a snapshot that is at least 128 blocks old. This is true when "state snapshot generation" is no longer reported in the logs. 5. Geth has finished creating a snapshot that is at least 128 blocks old. This is true when "state snapshot generation" is no longer reported in the logs.
With these rules satisfied, Geth's database can be pruned. With these rules satisfied, Geth's database can be pruned.

View File

@ -21,7 +21,7 @@ In order to get the most value from the tutorials on this page, the following sk
Users that need to revisit these fundamentals can find helpful resources relating to the command line [here](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line), Ethereum and its testnets [here](https://ethereum.org/en/developers/tutorials/), http [here](https://developer.mozilla.org/en-US/docs/Web/HTTP) and Javascript [here](https://www.javascript.com/learn). Information on node architecture can be found [here](/docs/fundamentals/node-architecture) and our guide for configuring Geth to connect to a Users that need to revisit these fundamentals can find helpful resources relating to the command line [here](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line), Ethereum and its testnets [here](https://ethereum.org/en/developers/tutorials/), http [here](https://developer.mozilla.org/en-US/docs/Web/HTTP) and Javascript [here](https://www.javascript.com/learn). Information on node architecture can be found [here](/docs/fundamentals/node-architecture) and our guide for configuring Geth to connect to a
consensus client is [here](/docs/getting_started/consensus-clients). consensus client is [here](/docs/getting_started/consensus-clients).
{% include note.html content="If Geth was installed from source on Linux, `make` saves the binaries for Geth and the associated tools in `/build/bin`. To run these programs it is convenient to move them to the top level project directory (e.g. running `mv ./build/bin/* ./`) from `/go-ethereum`. Then `./` must be prepended to the commands in the code snippets in order to execute a particular program, e.g. `./geth` instead of simply `geth`. If the executables are not moved then either navigate to the `bin` directory to run them (e.g. `cd ./build/bin` and `./geth`) or provide their path (e.g. `./build/bin/geth`). These instructions can be ignored for other installations." %} <Note>If Geth was installed from source on Linux, `make` saves the binaries for Geth and the associated tools in `/build/bin`. To run these programs it is convenient to move them to the top level project directory (e.g. running `mv ./build/bin/* ./`) from `/go-ethereum`. Then `./` must be prepended to the commands in the code snippets in order to execute a particular program, e.g. `./geth` instead of simply `geth`. If the executables are not moved then either navigate to the `bin` directory to run them (e.g. `cd ./build/bin` and `./geth`) or provide their path (e.g. `./build/bin/geth`). These instructions can be ignored for other installations.</Note>
## Background {#background} ## Background {#background}

View File

@ -18,7 +18,7 @@ This returns a result which is also a JSON object, with values expressed as hexa
This is a low level and rather error-prone way to interact with Geth. Most developers prefer to use convenience libraries that abstract away some of the more tedious and awkward tasks such as converting values from hexadecimal strings into numbers, or converting between denominations of ether (Wei, Gwei, etc). One such library is [Web3.js](https://web3js.readthedocs.io/en/v1.7.3/). This is a low level and rather error-prone way to interact with Geth. Most developers prefer to use convenience libraries that abstract away some of the more tedious and awkward tasks such as converting values from hexadecimal strings into numbers, or converting between denominations of ether (Wei, Gwei, etc). One such library is [Web3.js](https://web3js.readthedocs.io/en/v1.7.3/).
The purpose of Geth's Javascript console is to provide a built-in environment to use a subset of the Web3.js libraries to interact with a Geth node. The purpose of Geth's Javascript console is to provide a built-in environment to use a subset of the Web3.js libraries to interact with a Geth node.
{% include note.html content="The web3.js version that comes bundled with Geth is not up to date with the official Web3.js documentation. There are several Web3.js libraries that are not available in the Geth Javascript Console. There are also administrative APIs included in the Geth console that are not documented in the Web3.js documentation. The full list of libraries available in the Geth console is available on the [JSON-RPC API page](/docs/interacting-with-geth/rpc/server)." %} <Note>The web3.js version that comes bundled with Geth is not up to date with the official Web3.js documentation. There are several Web3.js libraries that are not available in the Geth Javascript Console. There are also administrative APIs included in the Geth console that are not documented in the Web3.js documentation. The full list of libraries available in the Geth console is available on the [JSON-RPC API page](/docs/interacting-with-geth/rpc/server).</Note>
## Starting the console {#starting-the-console} ## Starting the console {#starting-the-console}

View File

@ -78,7 +78,7 @@ geth --ws --ws.origins http://myapp.example.com
As with `--http.corsdomain`, using the wildcard `--ws.origins '*'` allows access from any origin. As with `--http.corsdomain`, using the wildcard `--ws.origins '*'` allows access from any origin.
{% include note.html content=" By default, **account unlocking is forbidden when HTTP or Websocket access is enabled** (i.e. by passing `--http` or `ws` flag). This is because an attacker that manages to access the node via the externally-exposed HTTP/WS port can then control the unlocked account. It is possible to force account unlock by including the `--allow-insecure-unlock` flag but this is unsafe and **not recommended** except for expert users that completely understand how it can be used safely. This is not a hypothetical risk: **there are bots that continually scan for http-enabled Ethereum nodes to attack**" %} <Note>By default, **account unlocking is forbidden when HTTP or Websocket access is enabled** (i.e. by passing `--http` or `ws` flag). This is because an attacker that manages to access the node via the externally-exposed HTTP/WS port can then control the unlocked account. It is possible to force account unlock by including the `--allow-insecure-unlock` flag but this is unsafe and **not recommended** except for expert users that completely understand how it can be used safely. This is not a hypothetical risk: **there are bots that continually scan for http-enabled Ethereum nodes to attack**</Note>
### IPC Server {#ipc-server} ### IPC Server {#ipc-server}

View File

@ -29,7 +29,7 @@ The location is specified as `<filename>:<line>`.
Example: Example:
``` js ```js
> debug.backtraceAt("server.go:443") > debug.backtraceAt("server.go:443")
``` ```
@ -579,13 +579,16 @@ No specific call options:
Tracing a call with a destination and specific sender, disabling the storage and memory output (less data returned over RPC) Tracing a call with a destination and specific sender, disabling the storage and memory output (less data returned over RPC)
```js ```js
debug.traceCall({ debug.traceCall(
"from": "0xdeadbeef29292929192939494959594933929292", {
"to": "0xde929f939d939d393f939393f93939f393929023", from: '0xdeadbeef29292929192939494959594933929292',
"gas": "0x7a120", to: '0xde929f939d939d393f939393f93939f393929023',
"data": "0xf00d4b5d00000000000000000000000001291230982139282304923482304912923823920000000000000000000000001293123098123928310239129839291010293810" gas: '0x7a120',
}, data: '0xf00d4b5d00000000000000000000000001291230982139282304923482304912923823920000000000000000000000001293123098123928310239129839291010293810'
"latest", {"disableStorage": true, "disableMemory": true}) },
'latest',
{ disableStorage: true, disableMemory: true }
);
``` ```
It is possible to supply 'overrides' for both state-data (accounts/storage) and block data (number, timestamp etc). In the example below, a call which executes `NUMBER` is performed, and the overridden number is placed on the stack: It is possible to supply 'overrides' for both state-data (accounts/storage) and block data (number, timestamp etc). In the example below, a call which executes `NUMBER` is performed, and the overridden number is placed on the stack:
@ -731,26 +734,26 @@ Sets the logging verbosity pattern.
If you want to see messages from a particular Go package (directory) and all subdirectories, use: If you want to see messages from a particular Go package (directory) and all subdirectories, use:
``` js ```js
> debug.vmodule("eth/*=6") > debug.vmodule("eth/*=6")
``` ```
If you want to restrict messages to a particular package (e.g. p2p) but exclude subdirectories, use: If you want to restrict messages to a particular package (e.g. p2p) but exclude subdirectories, use:
``` js ```js
> debug.vmodule("p2p=6") > debug.vmodule("p2p=6")
``` ```
If you want to see log messages from a particular source file, use If you want to see log messages from a particular source file, use
``` js ```js
> debug.vmodule("server.go=6") > debug.vmodule("server.go=6")
``` ```
You can compose these basic patterns. If you want to see all output from peer.go in a package below eth (eth/peer.go, eth/downloader/peer.go) as well as output from package p2p at level <= 5, use: You can compose these basic patterns. If you want to see all output from peer.go in a package below eth (eth/peer.go, eth/downloader/peer.go) as well as output from package p2p at level <= 5, use:
``` js ```js
debug.vmodule("eth/*/peer.go=6,p2p=5") debug.vmodule('eth/*/peer.go=6,p2p=5');
``` ```
### debug_writeBlockProfile ### debug_writeBlockProfile

View File

@ -40,7 +40,6 @@ The _state override set_ is an optional address-to-state mapping, where each ent
The goal of the _state override set_ is manyfold: The goal of the _state override set_ is manyfold:
- It can be used by DApps to reduce the amount of contract code needed to be deployed on chain. Code that simply returns internal state or does pre-defined validations can be kept off chain and fed to the node on-demand. - It can be used by DApps to reduce the amount of contract code needed to be deployed on chain. Code that simply returns internal state or does pre-defined validations can be kept off chain and fed to the node on-demand.
- It can be used for smart contract analysis by extending the code deployed on chain with custom methods and invoking them. This avoids having to download and reconstruct the entire state in a sandbox to run custom code against. - It can be used for smart contract analysis by extending the code deployed on chain with custom methods and invoking them. This avoids having to download and reconstruct the entire state in a sandbox to run custom code against.
- It can be used to debug smart contracts in an already deployed large suite of contracts by selectively overriding some code or state and seeing how execution changes. Specialized tooling will probably be necessary. - It can be used to debug smart contracts in an already deployed large suite of contracts by selectively overriding some code or state and seeing how execution changes. Specialized tooling will probably be necessary.

View File

@ -3,7 +3,7 @@ title: personal Namespace
description: Documentation for the JSON-RPC API "personal" namespace description: Documentation for the JSON-RPC API "personal" namespace
--- ---
{% include note.html content="The personal namespace will be deprecated in the very near future." %} <Note>The personal namespace will be deprecated in the very near future.</Note>
The personal API managed private keys in the key store. It is deprecated in favour of using [Clef](/docs/tools/clef/Introduction) for interacting with accounts Please refer to the [ns_personal deprecation page](/docs/interacting-with-geth/rpc/ns_personal_deprecation) to see the equivalent methods. The following documentation should be treated as archive information and users should migrate tousing Clef for account interactions. The personal API managed private keys in the key store. It is deprecated in favour of using [Clef](/docs/tools/clef/Introduction) for interacting with accounts Please refer to the [ns_personal deprecation page](/docs/interacting-with-geth/rpc/ns_personal_deprecation) to see the equivalent methods. The following documentation should be treated as archive information and users should migrate tousing Clef for account interactions.

View File

@ -34,11 +34,8 @@ to cancel the subscription:
## Considerations {#considerations} ## Considerations {#considerations}
1. Notifications are sent for current events and not for past events. For use cases that depend on not to miss any notifications subscriptions are probably not the best option. 1. Notifications are sent for current events and not for past events. For use cases that depend on not to miss any notifications subscriptions are probably not the best option.
2. Subscriptions require a full duplex connection. Geth offers such connections in the form of WebSocket and IPC (enabled by default). 2. Subscriptions require a full duplex connection. Geth offers such connections in the form of WebSocket and IPC (enabled by default).
3. Subscriptions are coupled to a connection. If the connection is closed all subscriptions that are created over this connection are removed. 3. Subscriptions are coupled to a connection. If the connection is closed all subscriptions that are created over this connection are removed.
4. Notifications are stored in an internal buffer and sent from this buffer to the client. If the client is unable to keep up and the number of buffered notifications reaches a limit (currently 10k) the connection is closed. Keep in mind that subscribing to some events can cause a flood of notifications, e.g. listening for all logs/blocks when the node starts to synchronize. 4. Notifications are stored in an internal buffer and sent from this buffer to the client. If the client is unable to keep up and the number of buffered notifications reaches a limit (currently 10k) the connection is closed. Keep in mind that subscribing to some events can cause a flood of notifications, e.g. listening for all logs/blocks when the node starts to synchronize.
## Create subscription {#create-subscriptions} ## Create subscription {#create-subscriptions}

View File

@ -10,7 +10,6 @@ There are several ways to monitor the performance of a Geth node. Insights into
To follow along with the instructions on this page it will be useful to have: To follow along with the instructions on this page it will be useful to have:
- a running Geth instance. - a running Geth instance.
- basic working knowlegde of bash/terminal. - basic working knowlegde of bash/terminal.
[This video](https://www.youtube.com/watch?v=cOBab8IJMYI) provides an excellent introduction to Geth monitoring. [This video](https://www.youtube.com/watch?v=cOBab8IJMYI) provides an excellent introduction to Geth monitoring.

View File

@ -50,11 +50,11 @@ each with detailed installation instructions. They all share the common trait th
started with a specific URL that can be passed to Geth. started with a specific URL that can be passed to Geth.
[EthNetStats "Classic"](https://github.com/ethereum/eth-netstats) [EthNetStats "Classic"](https://github.com/ethereum/eth-netstats)
[EthNet Intelligence API](https://github.com/ethereum/eth-net-intelligence-api) [EthNet Intelligence API](https://github.com/ethereum/eth-net-intelligence-api)
[Goerli Ethstats client](https://github.com/goerli/ethstats-client) [Goerli Ethstats client](https://github.com/goerli/ethstats-client)
[Goerli Ethstats server](https://github.com/goerli/ethstats-server) [Goerli Ethstats server](https://github.com/goerli/ethstats-server)
If enabled, Geth spins up a minimal Ethstats reporting daemon that pushes statistics about the If enabled, Geth spins up a minimal Ethstats reporting daemon that pushes statistics about the

View File

@ -69,6 +69,7 @@ Initiate Geth:
```sh ```sh
$ geth --datadir ./ddir init genesis.json $ geth --datadir ./ddir init genesis.json
``` ```
```terminal ```terminal
... ...
INFO [06-16|11:14:54.123] Writing custom genesis block INFO [06-16|11:14:54.123] Writing custom genesis block
@ -90,6 +91,7 @@ These two things are independent of each other. First of all, however, `clef` mu
```sh ```sh
$ clef --keystore ./ddir/keystore --configdir ./clef --chainid 15 --suppress-bootwarn init $ clef --keystore ./ddir/keystore --configdir ./clef --chainid 15 --suppress-bootwarn init
``` ```
```terminal ```terminal
The master seed of clef will be locked with a password. The master seed of clef will be locked with a password.
Please specify a password. Do not forget this password! Please specify a password. Do not forget this password!
@ -117,6 +119,7 @@ With that done, `clef` can be made aware of the password. To do this `setpw <add
```sh ```sh
$ clef --keystore ./ddir/keystore --configdir ./clef --chainid 15 --suppress-bootwarn setpw 0x9CD932F670F7eDe5dE86F756A6D02548e5899f47 $ clef --keystore ./ddir/keystore --configdir ./clef --chainid 15 --suppress-bootwarn setpw 0x9CD932F670F7eDe5dE86F756A6D02548e5899f47
``` ```
```terminal ```terminal
Please enter a password to store for this address: Please enter a password to store for this address:
Password: Password:

View File

@ -12,6 +12,7 @@ First things first, Clef needs to store some data itself. Since that data might
```sh ```sh
$ clef init $ clef init
``` ```
```terminal ```terminal
WARNING! WARNING!
@ -134,7 +135,7 @@ geth attach goerli-data/geth.ipc
A simple request to list the accounts in the keystore will cause the Javascript console to hang. A simple request to list the accounts in the keystore will cause the Javascript console to hang.
```js ```js
eth.accounts eth.accounts;
``` ```
Switching to the Clef terminal reveals that this is because the request is awaiting explicit confirmation from the user. The log is identical to the one shown above, when the same request for account information was made to Clef via Netcat: Switching to the Clef terminal reveals that this is because the request is awaiting explicit confirmation from the user. The log is identical to the one shown above, when the same request for account information was made to Clef via Netcat:

View File

@ -30,6 +30,7 @@
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.3",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",
"rehype-raw": "^6.1.1",
"remark-gfm": "^3.0.1" "remark-gfm": "^3.0.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,114 +0,0 @@
import {
Flex,
Heading,
Link,
ListItem,
OrderedList,
Stack,
Table,
Text,
UnorderedList
} from '@chakra-ui/react';
import NextLink from 'next/link';
import { Code } from './UI/docs';
import { textStyles } from '../theme/foundations';
const { header1, header2, header3, header4 } = textStyles;
const MDXComponents = {
// paragraphs
p: ({ children }: any) => {
return (
<Text mb={7} lineHeight={1.5}>
{children}
</Text>
);
},
// links
a: ({ children, href }: any) => {
return (
<NextLink href={href} passHref>
<Link
isExternal={href.startsWith('http') && !href.includes('geth.ethereum.org')}
variant='light'
>
{children}
</Link>
</NextLink>
);
},
// headings
h1: ({ children }: any) => {
return (
<Heading as='h1' textAlign='start' mb={5} {...header1}>
{children}
</Heading>
);
},
h2: ({ children }: any) => {
return (
<Heading as='h2' textAlign='start' mt='16 !important' mb={4} {...header2}>
{children}
</Heading>
);
},
h3: ({ children }: any) => {
return (
<Heading as='h3' mt={5} mb={2.5} {...header3}>
{children}
</Heading>
);
},
h4: ({ children }: any) => {
return (
<Heading as='h4' mb={2.5} {...header4}>
{children}
</Heading>
);
},
// tables
table: ({ children }: any) => (
<Flex maxW='min(100%, 100vw)' overflowX='scroll'>
<Table
variant='striped'
colorScheme='greenAlpha'
border='1px'
borderColor='blackAlpha.50'
my={6}
size={{ base: 'sm', lg: 'md' }}
w='auto'
>
{children}
</Table>
</Flex>
),
// pre
pre: ({ children }: any) => (
<Stack mb={5}>
<pre>{children}</pre>
</Stack>
),
// code
code: ({ children, ...props }: any) => <Code {...props}>{children}</Code>,
// list
ul: ({ children }: any) => {
return (
<UnorderedList mb={7} px={4}>
{children}
</UnorderedList>
);
},
ol: ({ children }: any) => {
return (
<OrderedList mb={7} px={4}>
{children}
</OrderedList>
);
},
li: ({ children }: any) => {
return <ListItem color='primary'>{children}</ListItem>;
}
};
export default MDXComponents;

View File

@ -0,0 +1,33 @@
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, Stack } from '@chakra-ui/react';
import NextLink from 'next/link';
import { useRouter } from 'next/router';
import { FC } from 'react';
export const Breadcrumbs: FC = () => {
const router = useRouter();
let pathSplit = router.asPath.split('/');
pathSplit = pathSplit.splice(1, pathSplit.length);
return (
<>
{router.asPath !== '/docs' ? (
<Breadcrumb>
{pathSplit.map((path: string, idx: number) => {
return (
<BreadcrumbItem key={path}>
<NextLink href={`/${pathSplit.slice(0, idx + 1).join('/')}`} passHref>
<BreadcrumbLink color={idx + 1 === pathSplit.length ? 'body' : 'primary'}>
{path}
</BreadcrumbLink>
</NextLink>
</BreadcrumbItem>
);
})}
</Breadcrumb>
) : (
<Stack h='24px'></Stack>
)}
</>
);
};

View File

@ -73,5 +73,11 @@ export const Code: React.FC<Props> = ({ className, children, inline }) => {
{content} {content}
</SyntaxHighlighter> </SyntaxHighlighter>
); );
return <Stack>{content}</Stack>; return (
<Stack>
<ChakraCode overflow='auto' p={6} background='terminal-bg' color='terminal-text'>
{content}
</ChakraCode>
</Stack>
);
}; };

View File

@ -0,0 +1,81 @@
import { FC } from 'react';
import {
Accordion,
AccordionButton,
AccordionItem,
AccordionPanel,
Center,
Link,
Stack,
Text
} from '@chakra-ui/react';
import { AddIcon, MinusIcon } from '@chakra-ui/icons';
import NextLink from 'next/link';
import { LinksList } from './';
import { NavLink } from '../../../types';
interface Props {
navLinks: NavLink[];
}
export const DocsLinks: FC<Props> = ({ navLinks }) => (
<Stack border='2px' borderColor='primary'>
{navLinks.map(({ id, to, items }, idx) => {
return (
<Accordion key={id} allowToggle mt='0 !important' defaultIndex={[0]}>
<AccordionItem border='none'>
{({ isExpanded }) => (
<>
<AccordionButton
borderBottom={navLinks.length - 1 === idx ? 'none' : '2px'}
p={0}
borderColor='primary'
justifyContent='space-between'
placeContent='flex-end'
bg='button-bg'
>
<Stack
p={4}
borderRight={items ? '2px' : 'none'}
borderColor='primary'
w='100%'
bg='bg'
>
{to ? (
<NextLink href={to} passHref>
<Link>
<Text textStyle='docs-nav-dropdown'>{id}</Text>
</Link>
</NextLink>
) : (
<Text textStyle='docs-nav-dropdown'>{id}</Text>
)}
</Stack>
{items && (
<Stack minW='61px'>
<Center>
{isExpanded ? (
<MinusIcon w='20px' h='20px' color='primary' />
) : (
<AddIcon w='20px' h='20px' color='primary' />
)}
</Center>
</Stack>
)}
</AccordionButton>
{items && (
<AccordionPanel borderBottom='2px solid' borderColor='primary' px={0} py={4}>
<LinksList links={items} />
</AccordionPanel>
)}
</>
)}
</AccordionItem>
</Accordion>
);
})}
</Stack>
);

View File

@ -0,0 +1,59 @@
import { FC } from 'react';
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Stack,
Text
} from '@chakra-ui/react';
import { DocsLinks } from './DocsLinks';
import { NavLink } from '../../../types';
interface Props {
navLinks: NavLink[];
}
export const DocsNav: FC<Props> = ({ navLinks }) => {
return (
<Stack w={{ base: '100%', lg: 72 }}>
<Stack display={{ base: 'none', lg: 'block' }}>
<DocsLinks navLinks={navLinks} />
</Stack>
<Stack display={{ base: 'block', lg: 'none' }}>
<Accordion allowToggle>
<AccordionItem border='none'>
<AccordionButton
display='flex'
py={4}
px={8}
border='2px'
borderColor='primary'
placeContent='space-between'
bg='button-bg'
_hover={{
bg: 'primary',
color: 'bg'
}}
_expanded={{
bg: 'primary',
color: 'bg'
}}
>
<Text as='h4' textStyle='docs-nav-dropdown'>
Documentation
</Text>
<AccordionIcon />
</AccordionButton>
<AccordionPanel p={0}>
<DocsLinks navLinks={navLinks} />
</AccordionPanel>
</AccordionItem>
</Accordion>
</Stack>
</Stack>
);
};

View File

@ -0,0 +1,44 @@
import { FC } from 'react';
import { Divider, Link, Stack, Text } from '@chakra-ui/react';
import NextLink from 'next/link';
import { parseHeadingId } from '../../../utils/parseHeadingId';
import { useActiveHash } from '../../../hooks/useActiveHash';
interface Props {
content: string;
}
export const DocumentNav: FC<Props> = ({ content }) => {
const parsedHeadings = content
.split('\n\n')
.map(item => item.replace(/[\n\r]/g, ''))
.filter(item => item.startsWith('#'))
.map(item => parseHeadingId([item]))
.filter(item => item);
const activeHash = useActiveHash(parsedHeadings.map(heading => heading!.headingId));
return (
<Stack position='sticky' top='4'>
<Text as='h5' textStyle='document-nav-title'>
on this page
</Text>
<Divider borderColor='primary' my={`4 !important`} />
{parsedHeadings.map((heading, idx) => {
return (
<NextLink key={`${idx} ${heading?.title}`} href={`#${heading?.headingId}`}>
<Link m={0}>
<Text
color={activeHash === heading?.headingId ? 'body' : 'primary'}
textStyle='document-nav-link'
>
{heading?.title}
</Text>
</Link>
</NextLink>
);
})}
</Stack>
);
};

View File

@ -0,0 +1,35 @@
import { FC } from 'react';
import { Link, Stack, Text } from '@chakra-ui/react';
import NextLink from 'next/link';
import { NavLink } from '../../../types';
interface LinksListProps {
links: NavLink[];
}
export const LinksList: FC<LinksListProps> = ({ links }) => (
<Stack px={4}>
{links.map(({ id, to, items }) => {
return to ? (
<Stack key={id}>
<NextLink href={to} passHref key={id}>
<Link>
<Text textStyle='docs-nav-links' color={items ? 'primary' : 'body'}>
{id}
</Text>
</Link>
</NextLink>
{items && <LinksList links={items} />}
</Stack>
) : (
<Stack key={id}>
<Text textStyle='docs-nav-links' color={items ? 'primary' : 'body'}>
{id}
</Text>
{items && <LinksList links={items} />}
</Stack>
);
})}
</Stack>
);

View File

@ -0,0 +1,153 @@
import {
Flex,
Heading,
Link,
ListItem,
OrderedList,
Stack,
Table,
Text,
UnorderedList
} from '@chakra-ui/react';
import NextLink from 'next/link';
import { Code, Note } from '.';
import { textStyles } from '../../../theme/foundations';
import { parseHeadingId } from '../../../utils/parseHeadingId';
const { header1, header2, header3, header4 } = textStyles;
const MDComponents = {
// paragraphs
p: ({ children }: any) => {
return (
<Text mb='7 !important' lineHeight={1.5}>
{children}
</Text>
);
},
// links
a: ({ children, href }: any) => {
return (
<NextLink href={href} passHref>
<Link
isExternal={href.startsWith('http') && !href.includes('geth.ethereum.org')}
variant='light'
>
{children}
</Link>
</NextLink>
);
},
// headings
h1: ({ children }: any) => {
const heading = parseHeadingId(children);
return heading ? (
<Heading as='h1' textAlign='start' mb='5 !important' {...header1} id={heading.headingId}>
{heading.children}
</Heading>
) : (
<Heading as='h1' textAlign='start' mb='5 !important' {...header1}>
{children}
</Heading>
);
},
h2: ({ children }: any) => {
const heading = parseHeadingId(children);
return heading ? (
<Heading
as='h2'
textAlign='start'
mt='16 !important'
mb='4 !important'
{...header2}
id={heading.headingId}
>
{heading.children}
</Heading>
) : (
<Heading as='h2' textAlign='start' mt='16 !important' mb='4 !important' {...header2}>
{children}
</Heading>
);
},
h3: ({ children }: any) => {
const heading = parseHeadingId(children);
return heading ? (
<Heading as='h3' mt='5 !important' mb='2.5 !important' {...header3} id={heading.headingId}>
{heading.children}
</Heading>
) : (
<Heading as='h3' mt='5 !important' mb='2.5 !important' {...header3}>
{children}
</Heading>
);
},
h4: ({ children }: any) => {
const heading = parseHeadingId(children);
return heading ? (
<Heading as='h4' mb='2.5 !important' {...header4} id={heading.headingId}>
{heading.children}
</Heading>
) : (
<Heading as='h4' mb='2.5 !important' {...header4}>
{children}
</Heading>
);
},
// tables
table: ({ children }: any) => (
<Flex maxW='min(100%, 100vw)' overflowX='auto'>
<Table
variant='striped'
colorScheme='greenAlpha'
border='1px'
borderColor='blackAlpha.50'
my='6 !important'
size={{ base: 'sm', lg: 'md' }}
w='auto'
>
{children}
</Table>
</Flex>
),
// pre
pre: ({ children }: any) => (
<Stack mb={5}>
<pre>{children}</pre>
</Stack>
),
// code
code: ({ children, ...props }: any) => <Code {...props}>{children}</Code>,
// list
ul: ({ children }: any) => {
return (
<Stack>
<UnorderedList mb={7} px={4}>
{children}
</UnorderedList>
</Stack>
);
},
ol: ({ children }: any) => {
return (
<Stack>
<OrderedList mb={7} px={4}>
{children}
</OrderedList>
</Stack>
);
},
li: ({ children }: any) => {
return <ListItem color='primary'>{children}</ListItem>;
},
note: ({ children }: any) => {
return <Note>{children}</Note>;
}
};
export default MDComponents;

View File

@ -0,0 +1,17 @@
import { FC } from 'react';
import { Stack, Text } from '@chakra-ui/react';
interface Props {
children: string[];
}
export const Note: FC<Props> = ({ children }) => {
return (
<Stack w='100%' bg='button-bg' border='2px' borderColor='primary' p={4}>
<Text as='h4' textStyle='header4'>
Note
</Text>
<Text textStyle='note-text'>{children}</Text>
</Stack>
);
};

View File

@ -0,0 +1,8 @@
export * from './Breadcrumbs';
export * from './Code';
export * from './DocsLinks';
export * from './DocsNav';
export * from './DocumentNav';
export * from './LinkList';
export * from './Note';
export { default } from './MDComponents';

View File

@ -1 +0,0 @@
export * from './Code';

View File

@ -1,27 +0,0 @@
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react';
import NextLink from 'next/link';
import { useRouter } from 'next/router';
import { FC } from 'react';
export const Breadcrumbs: FC = () => {
const router = useRouter();
let pathSplit = router.asPath.split('/');
pathSplit = pathSplit.splice(1, pathSplit.length);
return (
<Breadcrumb>
{pathSplit.map((path: string, idx: number) => {
return (
<BreadcrumbItem key={path}>
<NextLink href={`/${pathSplit.slice(0, idx + 1).join('/')}`} passHref>
<BreadcrumbLink color={idx + 1 === pathSplit.length ? 'body' : 'primary'}>
{path}
</BreadcrumbLink>
</NextLink>
</BreadcrumbItem>
);
})}
</Breadcrumb>
);
};

View File

@ -1 +0,0 @@
export * from './Breadcrumbs';

View File

@ -1 +0,0 @@
export { default } from './MDXComponents';

View File

@ -0,0 +1,149 @@
- id: Getting started
to: /docs/getting-started
items:
- id: Hardware requirements
to: /docs/getting-started/hardware-requirements
- id: Installing Geth
to: /docs/getting-started/installing-geth
- id: Consensus clients
to: /docs/getting-started/consensus-clients
- id: Fundamentals
to: /docs/fundamentals
items:
- id: Node architecture
to: /docs/fundamentals/node-architecture
- id: Command-line options
to: /docs/fundamentals/command-line-options
- id: Security
to: /docs/fundamentals/security
- id: Sync-modes
to: /docs/fundamentals/sync-modes
- id: Account management
to: /docs/fundamentals/account-management
- id: Backup restore
to: /docs/fundamentals/backup-restore
- id: Logs
to: /docs/fundamentals/logs
- id: Peer-to-peer
to: /docs/fundamentals/peer-to-peer
- id: Pruning
to: /docs/fundamentals/pruning
- id: Light client
to: /docs/fundamentals/les
- id: Mining
to: /docs/fundamentals/mining
- id: Interacting with Geth
items:
- id: JSON-RPC Server
to: /docs/interacting-with-geth/rpc
items:
- id: Batch requests
to: /docs/interacting-with-geth/rpc/batch
- id: GraphQL server
to: /docs/interacting-with-geth/rpc/graphql
- id: admin Namespace
to: /docs/interacting-with-geth/rpc/ns-admin
- id: clique Namespace
to: /docs/interacting-with-geth/rpc/ns-clique
- id: debug Namespace
to: /docs/interacting-with-geth/rpc/ns-debug
- id: eth Namespace
to: /docs/interacting-with-geth/rpc/ns-eth
- id: les Namespace
to: /docs/interacting-with-geth/rpc/ns-les
- id: miner Namespace
to: /docs/interacting-with-geth/rpc/ns-miner
- id: net Namespace
to: /docs/interacting-with-geth/rpc/ns-net
- id: Personal namespace deprecation notes
to: /docs/interacting-with-geth/rpc/ns-personal-deprecation
- id: Personal Namespace
to: /docs/interacting-with-geth/rpc/ns-personal
- id: txpool Namespace
to: /docs/interacting-with-geth/rpc/ns-txpool
- id: Objects
to: /docs/interacting-with-geth/rpc/objects
- id: Real-time Events
to: /docs/interacting-with-geth/rpc/pubsub
- id: JavaScript Console
to: /docs/interacting-with-geth/javascript-console
- id: 'JavaScript Console 2: Contracts'
to: /docs/interacting-with-geth/javascript-console-contracts
- id: Developers
to: /docs/developers
items:
- id: Dapp developers
items:
- id: Go API
to: /docs/developers/dapp-developer/native
- id: Go Account Management
to: /docs/developers/dapp-developer/native-accounts
- id: Go Contract Bindings
to: /docs/developers/dapp-developer/native-bindings
- id: Geth for Mobile
to: /docs/developers/dapp-developer/mobile
- id: EVM tracing
to: /docs/developers/evm-tracing
items:
- id: Basic traces
to: /docs/developers/evm-tracing/basic-traces
- id: Built-in tracers
to: /docs/developers/evm-tracing/built-in-tracers
- id: Custom EVM tracer
to: /docs/developers/evm-tracing/custom-tracer
- id: Tutorial for Javascript tracing
to: /docs/developers/evm-tracing/javascript-tutorial
- id: Geth developer
items:
- id: Developer guide
to: /docs/developers/geth-developer/dev-guide
- id: Developer mode
to: /docs/developers/geth-developer/dev-mode
- id: Disclosures
to: /docs/developers/geth-developer/disclosures
- id: Issue handling workflow
to: /docs/developers/geth-developer/issue-handling-workflow
- id: DNS discovery setup guide
to: /docs/developers/geth-developer/dns-discovery-setup
- id: Code review guidelines
to: /docs/developers/geth-developer/code-review-guidelines
- id: Private networks
to: /docs/developers/geth-developer/private-network
- id: Contributing
to: /docs/developers/contributing
- id: Monitoring
items:
- id: Dashboards
to: /docs/monitoring/dashboards
- id: Ethstats
to: /docs/monitoring/ethstats
- id: Metrics
to: /docs/monitoring/metrics
- id: Tools
items:
- id: Clef
items:
- id: Introduction
to: /docs/tools/clef/introduction
- id: APIs
to: /docs/tools/clef/apis
- id: Rules
to: /docs/tools/clef/rules
- id: Setup
to: /docs/tools/clef/setup
- id: Datatypes
to: /docs/tools/clef/datatypes
- id: Tutorial
to: /docs/tools/clef/tutorial
- id: Clique-signing
to: /docs/tools/clef/clique-signing
- id: puppeth
to: /docs/tools/puppeth
- id: Abigen
to: /docs/tools/abigen
- id: devp2p
to: /docs/tools/devp2p
- id: FAQs
to: /docs/faq
- id: Resources
to: /docs/resources

View File

@ -0,0 +1,42 @@
import { useState, useEffect } from 'react';
/**
* A hook to determine which section of the page is currently in the viewport.
* @param {*} itemIds Array of document ids to observe
* @param {*} rootMargin
* @returns id of the element currently in viewport
*/
export const useActiveHash = (itemIds: Array<string>, rootMargin = `0% 0% -80% 0%`): string => {
const [activeHash, setActiveHash] = useState(``);
useEffect(() => {
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setActiveHash(`${entry.target.id}`);
}
});
},
{ rootMargin }
);
itemIds?.forEach(id => {
const element = document.getElementById(id);
if (element !== null) {
observer.observe(element);
}
});
return () => {
itemIds?.forEach(id => {
const element = document.getElementById(id);
if (element !== null) {
observer.unobserve(element);
}
});
};
}, [itemIds, rootMargin]);
return activeHash;
};

View File

@ -1,16 +1,24 @@
import fs from 'fs'; import fs from 'fs';
import matter from 'gray-matter'; import matter from 'gray-matter';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import { Stack, Heading, Text } from '@chakra-ui/react'; import { Flex, Stack, Heading, Text } from '@chakra-ui/react';
import ChakraUIRenderer from 'chakra-ui-markdown-renderer'; import ChakraUIRenderer from 'chakra-ui-markdown-renderer';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
import gfm from 'remark-gfm'; import gfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import { ParsedUrlQuery } from 'querystring'; import { ParsedUrlQuery } from 'querystring';
import type { GetStaticPaths, GetStaticProps, NextPage } from 'next'; import type { GetStaticPaths, GetStaticProps, NextPage } from 'next';
import MDXComponents from '../components/'; import MDComponents from '../components/UI/docs';
import { Breadcrumbs } from '../components/docs'; import { Breadcrumbs, DocsNav, DocumentNav } from '../components/UI/docs';
import { PageMetadata } from '../components/UI'; import { PageMetadata } from '../components/UI';
import { NavLink } from '../types';
import { getFileList } from '../utils/getFileList';
import { textStyles } from '../theme/foundations'; import { textStyles } from '../theme/foundations';
import { getParsedDate } from '../utils'; import { getParsedDate } from '../utils';
@ -22,21 +30,6 @@ const MATTER_OPTIONS = {
// This method crawls for all valid docs paths // This method crawls for all valid docs paths
export const getStaticPaths: GetStaticPaths = () => { export const getStaticPaths: GetStaticPaths = () => {
const getFileList = (dirName: string) => {
let files: string[] = [];
const items = fs.readdirSync(dirName, { withFileTypes: true });
for (const item of items) {
if (item.isDirectory()) {
files = [...files, ...getFileList(`${dirName}/${item.name}`)];
} else {
files.push(`/${dirName}/${item.name}`);
}
}
return files.map(file => file.replace('.md', '')).map(file => file.replace('/index', ''));
};
const paths: string[] = getFileList('docs'); // This is folder that get crawled for valid docs paths. Change if this path changes. const paths: string[] = getFileList('docs'); // This is folder that get crawled for valid docs paths. Change if this path changes.
return { return {
@ -52,6 +45,8 @@ export const getStaticProps: GetStaticProps = async context => {
let file; let file;
let lastModified; let lastModified;
const navLinks = yaml.load(fs.readFileSync('src/data/documentation-links.yaml', 'utf8'));
try { try {
file = fs.readFileSync(`${filePath}.md`, 'utf-8'); file = fs.readFileSync(`${filePath}.md`, 'utf-8');
lastModified = fs.statSync(`${filePath}.md`); lastModified = fs.statSync(`${filePath}.md`);
@ -66,6 +61,7 @@ export const getStaticProps: GetStaticProps = async context => {
props: { props: {
frontmatter, frontmatter,
content, content,
navLinks,
lastModified: getParsedDate(lastModified.mtime, { lastModified: getParsedDate(lastModified.mtime, {
month: 'numeric', month: 'numeric',
day: 'numeric', day: 'numeric',
@ -80,27 +76,62 @@ interface Props {
[key: string]: string; [key: string]: string;
}; };
content: string; content: string;
navLinks: NavLink[];
lastModified: string; lastModified: string;
} }
const DocPage: NextPage<Props> = ({ frontmatter, content, lastModified }) => { const DocPage: NextPage<Props> = ({ frontmatter, content, navLinks, lastModified }) => {
const router = useRouter();
useEffect(() => {
const id = router.asPath.split('#')[1];
const element = document.getElementById(id);
if (!element) {
return;
}
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, [router.asPath]);
return ( return (
<> <>
<PageMetadata title={frontmatter.title} description={frontmatter.description} /> <PageMetadata title={frontmatter.title} description={frontmatter.description} />
<main> <main>
<Stack mb={16}> <Flex direction={{ base: 'column', lg: 'row' }} gap={{ base: 4, lg: 8 }}>
<Breadcrumbs /> <Stack>
<Heading as='h1' mt='4 !important' mb={0} {...textStyles.header1}> <DocsNav navLinks={navLinks} />
{frontmatter.title} </Stack>
</Heading>
<Text as='span' mt='0 !important'> <Stack pb={4} width='100%'>
last edited {lastModified} <Stack mb={16}>
</Text> <Breadcrumbs />
</Stack> <Heading as='h1' mt='4 !important' mb={0} {...textStyles.header1}>
<ReactMarkdown remarkPlugins={[gfm]} components={ChakraUIRenderer(MDXComponents)}> {frontmatter.title}
{content} </Heading>
</ReactMarkdown> <Text as='span' mt='0 !important'>
last edited {lastModified}
</Text>
</Stack>
<Flex width='100%' placeContent='space-between'>
<Stack maxW='768px'>
<ReactMarkdown
remarkPlugins={[gfm]}
rehypePlugins={[rehypeRaw]}
components={ChakraUIRenderer(MDComponents)}
>
{content}
</ReactMarkdown>
</Stack>
<Stack display={{ base: 'none', xl: 'block' }} w={48}>
<DocumentNav content={content} />
</Stack>
</Flex>
</Stack>
</Flex>
</main> </main>
</> </>
); );

View File

@ -4,7 +4,7 @@ import { MDXProvider } from '@mdx-js/react';
import { Layout } from '../components/layouts'; import { Layout } from '../components/layouts';
import MDXComponents from '../components/'; import MDComponents from '../components/UI/docs';
import 'focus-visible/dist/focus-visible'; import 'focus-visible/dist/focus-visible';
import theme from '../theme'; import theme from '../theme';
@ -12,7 +12,7 @@ import theme from '../theme';
export default function App({ Component, pageProps }: AppProps) { export default function App({ Component, pageProps }: AppProps) {
return ( return (
<ChakraProvider theme={theme}> <ChakraProvider theme={theme}>
<MDXProvider components={MDXComponents}> <MDXProvider components={MDComponents}>
<Layout> <Layout>
<Component {...pageProps} /> <Component {...pageProps} />
</Layout> </Layout>

View File

@ -107,7 +107,7 @@ export const textStyles = {
color: 'body' color: 'body'
}, },
'footer-link-label': { 'footer-link-label': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
textTransform: 'uppercase', textTransform: 'uppercase',
lineHeight: '21.12px', lineHeight: '21.12px',
@ -139,13 +139,28 @@ export const textStyles = {
textAlign: 'center', textAlign: 'center',
fontSize: 'sm' fontSize: 'sm'
}, },
'docs-nav-dropdown': {
fontFamily: 'heading',
fontWeight: 400,
fontSize: '18px',
lineHeight: 6,
letterSpacing: '4%',
textAlign: 'left'
},
'docs-nav-links': {
fontFamily: 'heading',
weight: 400,
fontSize: 'md',
lineHeight: 8,
letterSpacing: '0.01em'
},
'header-button': { 'header-button': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
fontSize: { base: '0.86rem', sm: '1rem' } fontSize: { base: '0.86rem', sm: '1rem' }
}, },
'header-mobile-button': { 'header-mobile-button': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
textTransform: 'uppercase', textTransform: 'uppercase',
fontSize: '2xl' fontSize: '2xl'
}, },
@ -163,8 +178,25 @@ export const textStyles = {
lineHeight: '21.12px', lineHeight: '21.12px',
letterSpacing: '0.01rem' letterSpacing: '0.01rem'
}, },
// TODO: refactor w/ semantic tokens for light/dark mode 'document-nav-title': {
'link-light': {}, fontFamily: 'heading',
// TODO: refactor w/ semantic tokens for light/dark mode fontWeight: 400,
'text-light': {} fontSize: 'md',
lineHeight: '21.12px',
letterSpacing: '2%'
},
'document-nav-link': {
fontFamily: 'body',
fontWeight: 400,
fontSize: '13px',
lineHeight: 5,
letterSpacing: '1%',
mb: 4
},
'note-text': {
fontFamily: 'body',
fontWeight: 400,
fontSize: 'md',
lineHeight: '26px'
}
}; };

View File

@ -35,6 +35,12 @@ export interface ReleaseParams {
isStableRelease: boolean; isStableRelease: boolean;
} }
export interface NavLink {
id: string;
to?: string;
items?: NavLink[];
}
export interface OpenPGPSignaturesData { export interface OpenPGPSignaturesData {
'build server': string; 'build server': string;
'unique id': string; 'unique id': string;

16
src/utils/getFileList.ts Normal file
View File

@ -0,0 +1,16 @@
import fs from 'fs';
export const getFileList = (dirName: string) => {
let files: string[] = [];
const items = fs.readdirSync(dirName, { withFileTypes: true });
for (const item of items) {
if (item.isDirectory()) {
files = [...files, ...getFileList(`${dirName}/${item.name}`)];
} else {
files.push(`/${dirName}/${item.name}`);
}
}
return files.map(file => file.replace('.md', '')).map(file => file.replace('/index', ''));
};

View File

@ -0,0 +1,18 @@
const check = '{#';
export const parseHeadingId = (children: string[]) => {
if (children[children.length - 1].includes(check)) {
const temp = children[children.length - 1].split(check);
const headingId = temp[temp.length - 1].split('}')[0];
children[children.length - 1] = temp[0];
return {
children,
title: temp[0].replaceAll('#', ''),
headingId
};
}
return null;
};

103
yarn.lock
View File

@ -1269,6 +1269,11 @@
resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/parse5@^6.0.0":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb"
integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==
"@types/prop-types@*", "@types/prop-types@^15.0.0": "@types/prop-types@*", "@types/prop-types@^15.0.0":
version "15.7.5" version "15.7.5"
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz"
@ -2427,11 +2432,62 @@ has@^1.0.3:
dependencies: dependencies:
function-bind "^1.1.1" function-bind "^1.1.1"
hast-to-hyperscript@^10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-10.0.1.tgz#3decd7cb4654bca8883f6fcbd4fb3695628c4296"
integrity sha512-dhIVGoKCQVewFi+vz3Vt567E4ejMppS1haBRL6TEmeLeJVB1i/FJIIg/e6s1Bwn0g5qtYojHEKvyGA+OZuyifw==
dependencies:
"@types/unist" "^2.0.0"
comma-separated-tokens "^2.0.0"
property-information "^6.0.0"
space-separated-tokens "^2.0.0"
style-to-object "^0.3.0"
unist-util-is "^5.0.0"
web-namespaces "^2.0.0"
hast-util-from-parse5@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-7.1.0.tgz#c129dd3a24dd8a867ab8a029ca47e27aa54864b7"
integrity sha512-m8yhANIAccpU4K6+121KpPP55sSl9/samzQSQGpb0mTExcNh2WlvjtMwSWFhg6uqD4Rr6Nfa8N6TMypQM51rzQ==
dependencies:
"@types/hast" "^2.0.0"
"@types/parse5" "^6.0.0"
"@types/unist" "^2.0.0"
hastscript "^7.0.0"
property-information "^6.0.0"
vfile "^5.0.0"
vfile-location "^4.0.0"
web-namespaces "^2.0.0"
hast-util-parse-selector@^2.0.0: hast-util-parse-selector@^2.0.0:
version "2.2.5" version "2.2.5"
resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz" resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz"
integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==
hast-util-parse-selector@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-3.1.0.tgz#a519e27e8b61bd5a98fad494ed06131ce68d9c3f"
integrity sha512-AyjlI2pTAZEOeu7GeBPZhROx0RHBnydkQIXlhnFzDi0qfXTmGUWoCYZtomHbrdrheV4VFUlPcfJ6LMF5T6sQzg==
dependencies:
"@types/hast" "^2.0.0"
hast-util-raw@^7.2.0:
version "7.2.2"
resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-7.2.2.tgz#1974360b2d7f15b5ce26c2a4bac892d5d8185a18"
integrity sha512-0x3BhhdlBcqRIKyc095lBSDvmQNMY3Eulj2PLsT5XCyKYrxssI5yr3P4Kv/PBo1s/DMkZy2voGkMXECnFCZRLQ==
dependencies:
"@types/hast" "^2.0.0"
"@types/parse5" "^6.0.0"
hast-util-from-parse5 "^7.0.0"
hast-util-to-parse5 "^7.0.0"
html-void-elements "^2.0.0"
parse5 "^6.0.0"
unist-util-position "^4.0.0"
unist-util-visit "^4.0.0"
vfile "^5.0.0"
web-namespaces "^2.0.0"
zwitch "^2.0.0"
hast-util-to-estree@^2.0.0: hast-util-to-estree@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-2.1.0.tgz" resolved "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-2.1.0.tgz"
@ -2453,6 +2509,18 @@ hast-util-to-estree@^2.0.0:
unist-util-position "^4.0.0" unist-util-position "^4.0.0"
zwitch "^2.0.0" zwitch "^2.0.0"
hast-util-to-parse5@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-7.0.0.tgz#a39808e69005d10afeed1866029a1fb137df3f7c"
integrity sha512-YHiS6aTaZ3N0Q3nxaY/Tj98D6kM8QX5Q8xqgg8G45zR7PvWnPGPP0vcKCgb/moIydEJ/QWczVrX0JODCVeoV7A==
dependencies:
"@types/hast" "^2.0.0"
"@types/parse5" "^6.0.0"
hast-to-hyperscript "^10.0.0"
property-information "^6.0.0"
web-namespaces "^2.0.0"
zwitch "^2.0.0"
hast-util-whitespace@^2.0.0: hast-util-whitespace@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz" resolved "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz"
@ -2469,6 +2537,17 @@ hastscript@^6.0.0:
property-information "^5.0.0" property-information "^5.0.0"
space-separated-tokens "^1.0.0" space-separated-tokens "^1.0.0"
hastscript@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-7.1.0.tgz#e402ed48f46161cf2f093badbff30583a5c3c315"
integrity sha512-uBjaTTLN0MkCZxY/R2fWUOcu7FRtUVzKRO5P/RAfgsu3yFiMB1JWCO4AjeVkgHxAira1f2UecHK5WfS9QurlWA==
dependencies:
"@types/hast" "^2.0.0"
comma-separated-tokens "^2.0.0"
hast-util-parse-selector "^3.0.0"
property-information "^6.0.0"
space-separated-tokens "^2.0.0"
hey-listen@^1.0.8: hey-listen@^1.0.8:
version "1.0.8" version "1.0.8"
resolved "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz" resolved "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz"
@ -2486,6 +2565,11 @@ hoist-non-react-statics@^3.3.1:
dependencies: dependencies:
react-is "^16.7.0" react-is "^16.7.0"
html-void-elements@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f"
integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
ignore@^5.2.0: ignore@^5.2.0:
version "5.2.0" version "5.2.0"
resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz"
@ -3617,6 +3701,11 @@ parse-json@^5.0.0:
json-parse-even-better-errors "^2.3.0" json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6" lines-and-columns "^1.1.6"
parse5@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
path-exists@^4.0.0: path-exists@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
@ -3867,6 +3956,15 @@ regexpp@^3.2.0:
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
rehype-raw@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-6.1.1.tgz#81bbef3793bd7abacc6bf8335879d1b6c868c9d4"
integrity sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==
dependencies:
"@types/hast" "^2.0.0"
hast-util-raw "^7.2.0"
unified "^10.0.0"
remark-gfm@^3.0.1: remark-gfm@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f"
@ -4389,6 +4487,11 @@ vfile@^5.0.0:
unist-util-stringify-position "^3.0.0" unist-util-stringify-position "^3.0.0"
vfile-message "^3.0.0" vfile-message "^3.0.0"
web-namespaces@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692"
integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==
which-boxed-primitive@^1.0.2: which-boxed-primitive@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"