Skip to content

Commit

Permalink
feat(docs): added rpc-parser component for reference pages (#1331)
Browse files Browse the repository at this point in the history
* feat(docs): added rpc-parser component for reference pages

* feat(docs): added mm install msg

* feat(docs): change mm condition

* feat(docs): refactored styles

* feat(docs): added request/response section

* feat(docs): added error section

* feat(docs): added eth_call

* feat(docs): added tag labels

* feat(docs): added result section

* feat(docs): added condition for prod

* feat(docs): revert condition for prod

* feat(docs): fixes after review

* feat(docs): renamed to tsx

* feat(docs): fixes for styles & added props

* feat(docs): hide page from sidebar
  • Loading branch information
TrofimovAnton85 authored Jun 13, 2024
1 parent 7b03d9e commit 6c553f8
Show file tree
Hide file tree
Showing 21 changed files with 1,005 additions and 0 deletions.
1 change: 1 addition & 0 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ const config = {
},
},
],
"./src/plugins/plugin-json-rpc.ts",
isProd ?
[
"docusaurus-plugin-segment",
Expand Down
24 changes: 24 additions & 0 deletions src/components/ParserOpenRPC/AuthBox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import Link from "@docusaurus/Link";
import styles from "./styles.module.css";
import global from "../global.module.css";

interface AuthBoxProps {
isMetamaskInstalled: boolean;
}

const MetamaskInstallMessage = () => (
<div className={styles.msgWrapper}>
<strong className={styles.msgHeading}>Install MetaMask</strong>
<p className={styles.msgText}>Install MetaMask for your browser to enable interactive features</p>
<Link className={global.primaryBtn} href="https://metamask.io/download/">Install MetaMask</Link>
</div>
);

export const AuthBox = ({ isMetamaskInstalled }: AuthBoxProps) => {
return (
<>
{!isMetamaskInstalled ? <MetamaskInstallMessage /> : null}
</>
);
};
19 changes: 19 additions & 0 deletions src/components/ParserOpenRPC/AuthBox/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.msgWrapper {
text-align: center;
padding: 16px;
border-radius: 8px;
border: 1px solid #848C96;
margin-bottom: 24px;
}

.msgHeading {
display: block;
font-size: 16px;
line-height: 1.2;
margin: 0 0 10px;
}

.msgText {
font-size: 14px;
line-height: 22px;
}
31 changes: 31 additions & 0 deletions src/components/ParserOpenRPC/CollapseBox/CollapseBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import clsx from "clsx";
import { useCollapsible, Collapsible, useColorMode } from "@docusaurus/theme-common";
import styles from "./styles.module.css";
import React, { useEffect } from "react";

interface CollapseBoxProps {
children: JSX.Element;
isInitCollapsed?: boolean;
}

export const CollapseBox = ({ children, isInitCollapsed = false }: CollapseBoxProps) => {
const { collapsed, toggleCollapsed } = useCollapsible({ initialState: true });
const { colorMode } = useColorMode();
useEffect(() => {
if (isInitCollapsed) {
toggleCollapsed();
}
}, [isInitCollapsed]);
return (
<div className={clsx(styles.collapseWrapper, !collapsed && styles.collapsedWrapperView)}>
<button
className={clsx(styles.collapseBtn, !collapsed && styles.collapsedBtnView, colorMode === "light" && styles.collapsedBtnLightHover)}
onClick={toggleCollapsed}
>
{collapsed ? "Show child attributes" : "Hide child attributes"}
<div className={clsx(styles.collapseIcon, !collapsed && styles.collapsedIconView)}></div>
</button>
<Collapsible lazy collapsed={collapsed}>{children}</Collapsible>
</div>
);
};
91 changes: 91 additions & 0 deletions src/components/ParserOpenRPC/CollapseBox/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
.collapseWrapper {
border: 1px solid transparent;
border-radius: 8px;
overflow: hidden;
}

.collapsedWrapperView {
border-color: #848C96;
}

.collapseBtn {
background: none;
color: #1098FC;
font-size: 14px;
line-height: 1;
display: inline-flex;
justify-content: flex-start;
align-items: center;
min-width: 190px;
border-radius: 999px;
border: 1px solid #0376C9;
padding: 12px 22px;
margin-bottom: 1px;
cursor: pointer;
transition-property: 'border-color', 'background-color';
transition-duration: .2s;
transition-timing-function: ease;
}

.collapseIcon {
width: 10px;
height: 10px;
margin: 0 0 0 5px;
border-top: 2px solid #0376C9;
border-right: 2px solid #0376C9;
transform: rotate(45deg);
transition: transform .2s ease;
}

.collapseBtn:hover {
color: #141618;
background-color: #0376C9;
}

.collapsedBtnLightHover:hover {
color: #fff;
background-color: #036AB5;
}

.collapseBtn:hover .collapseIcon {
border-top-color: #141618;
border-right-color: #141618;
}

.collapsedBtnLightHover:hover .collapseIcon {
border-top-color: #fff;
border-right-color: #fff;
}

.collapsedBtnView {
border-color: transparent;
width: 100%;
border-radius: 0;
}

.collapsedBtnView:hover {
color: #0376C9;
text-decoration: underline;
background-color: #24272A;
}

.collapsedBtnView.collapsedBtnLightHover:hover {
background-color: #F2F4F6;
}

.collapsedBtnView:hover .collapseIcon {
border-top-color: #0376C9;
border-right-color: #0376C9;
}

.collapsedIconView {
margin: 0 0 2px 8px;
transform: rotate(135deg);
}

@media (width <= 767px) {
.collapseBtn {
width: 100%;
justify-content: center;
}
}
15 changes: 15 additions & 0 deletions src/components/ParserOpenRPC/DetailsBox/MDContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";

const parseMarkdown = (content: string) => {
return content
.replace(/\[(.*?)\]\((.*?)\)/g, "<a href=\"$2\">$1</a>")
.replace(/`(.*?)`/g, "<code>$1</code>");
};

interface MDContentProps {
content?: string;
}

export const MDContent = ({ content = "" }: MDContentProps) => (
<span dangerouslySetInnerHTML={{ __html: parseMarkdown(content) }} />
);
168 changes: 168 additions & 0 deletions src/components/ParserOpenRPC/DetailsBox/RenderParams.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import React from "react";
import { SchemaProperty } from "./SchemaProperty";
import { CollapseBox } from "../CollapseBox/CollapseBox";
import { MDContent } from "./MDContent";
import styles from "./styles.module.css";

const getRefSchemaFromComponents = (initRef, components) => {
const ref = initRef.replace("#/components/schemas/", "");
return components[ref];
};

const renderSchema = (schemaItem, schemas, name) => {
if (!schemaItem) return <div>Invalid schema</div>;

const resolveRef = (ref) => {
const newSchema = getRefSchemaFromComponents(ref, schemas);
return renderSchema(newSchema, schemas, name);
};

if (schemaItem?.schema?.$ref) return resolveRef(schemaItem.schema.$ref);
if (schemaItem?.$ref) return resolveRef(schemaItem.$ref);

const renderObject = (item, itemName) => (
<div>
<SchemaProperty
title={itemName || item.title}
type="object"
required={!!item.required}
description={item.description || item.title || ""}
/>
<div className="padding-bottom--md">
<CollapseBox isInitCollapsed={!!name}>
{Object.entries(item.properties).map(([key, value]) => (
<div key={key} className={styles.paramItemWrapper}>
{renderSchema(value, schemas, key)}
</div>
))}
</CollapseBox>
</div>
</div>
);

if (schemaItem?.schema?.type === "object" && schemaItem?.schema?.properties) {
return renderObject(schemaItem.schema, name || schemaItem?.schema?.title);
}

if (schemaItem.type === "object" && schemaItem.properties) {
return renderObject(schemaItem, name || schemaItem.title);
}

const renderArray = (item, itemName) => (
<div>
<SchemaProperty
title={itemName || item.title}
type="array"
required={!!item.required}
description={item.description || item.title || ""}
/>
<div className="padding-bottom--md">
<CollapseBox>
<div className={styles.paramItemWrapper}>
{renderSchema(item.items, schemas, "")}
</div>
</CollapseBox>
</div>
</div>
);

if (schemaItem.type === "array" && schemaItem.items) {
return renderArray(schemaItem, name || schemaItem.title);
}

if (schemaItem?.schema?.type === "array" && schemaItem?.schema?.items) {
return renderArray(schemaItem.schema, name || schemaItem.schema.title);
}

const renderCombinations = (item, itemName, type) => (
<div>
<SchemaProperty
title={itemName || item.title}
type={type}
required={!!item.required}
description={item.description || item.title || ""}
/>
<div className="padding-bottom--md">
<CollapseBox>
{item[type].map((option, index) => (
<div key={`${index}`} className={styles.paramItemWrapper}>
{renderSchema(option, schemas, option.title)}
</div>
))}
</CollapseBox>
</div>
</div>
);

if (schemaItem.oneOf) return renderCombinations(schemaItem, name, "oneOf");
if (schemaItem.allOf) return renderCombinations(schemaItem, name, "allOf");
if (schemaItem.anyOf) return renderCombinations(schemaItem, name, "anyOf");

const renderEnum = (enumValues, title, description) => {
const getDescription = (item) => {
const regex = new RegExp(`\`${item}\`: ([^;]+)(;|$)`);
const match = description.match(regex);
return match ? match[1] : "";
};
const blockEnum = title && description && title === "Block tag";
return (
<div className={styles.enumWrapper}>
<div className="padding--md">Possible enum values</div>
{enumValues.map((value, index) => (
<div key={index} className={styles.enumItem}>
<div className={styles.enumTitle}>{value}</div>
{blockEnum && <div style={{ paddingTop: "10px" }}><MDContent content={getDescription(value)} /></div>}
</div>
))}
</div>
);
};

if (schemaItem?.schema) {
return (
<div>
<SchemaProperty
title={name || schemaItem.schema.title}
type={schemaItem.schema.enum ? "enum" : schemaItem.schema.type}
required={!!schemaItem.required}
description={schemaItem.schema.description || schemaItem.schema.title || ""}
/>
{schemaItem.schema.enum && renderEnum(schemaItem.schema.enum, schemaItem.schema.title, schemaItem.schema.description)}
</div>
);
}

return (
<div>
<SchemaProperty
title={name || schemaItem.title}
type={schemaItem.enum ? "enum" : schemaItem.type}
required={!!schemaItem.required}
description={schemaItem.enum && schemaItem.title === "Block tag" ? "" : schemaItem.description || schemaItem.title}
/>
{schemaItem.enum && renderEnum(schemaItem.enum, schemaItem.title, schemaItem.description)}
</div>
);
};

export const renderParamSchemas = (inputSchema, schemas) => {
return (
<>
{inputSchema.map((item, i) => {
return (
<div key={`${i}`} className={styles.borderTopLine}>
{renderSchema(item, schemas, item.name)}
</div>
);
})}
</>
);
};

export const renderResultSchemas = (inputSchema, schemas) => {
return (
<>
{renderSchema(inputSchema, schemas, inputSchema.name)}
</>
);
};
Loading

0 comments on commit 6c553f8

Please sign in to comment.