Moving Docs and Faq to separate lazy loaded module

This commit is contained in:
softsimon
2022-04-24 22:53:27 +04:00
parent c63ee1d80f
commit c256d714ab
19 changed files with 118 additions and 101 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
<div *ngFor="let item of tabData">
<p *ngIf="( item.type === 'category' ) && ( item.showConditions.indexOf(network.val) > -1 )">{{ item.title }}</p>
<a *ngIf="( item.type !== 'category' ) && ( item.showConditions.indexOf(network.val) > -1 )" [routerLink]="['./']" fragment="{{ item.fragment }}" (click)="navLinkClick($event)">{{ item.title }}</a>
</div>

View File

@@ -0,0 +1,13 @@
p {
color: #4a68b9;
font-weight: 700;
margin: 10px 0;
margin: 15px 0 10px 0;
}
a {
color: #fff;
text-decoration: none;
display: block;
margin: 5px 0;
}

View File

@@ -0,0 +1,31 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { restApiDocsData } from './api-docs-data';
import { faqData } from './api-docs-data';
@Component({
selector: 'app-api-docs-nav',
templateUrl: './api-docs-nav.component.html',
styleUrls: ['./api-docs-nav.component.scss']
})
export class ApiDocsNavComponent implements OnInit {
@Input() network: any;
@Input() whichTab: string;
@Output() navLinkClickEvent: EventEmitter<any> = new EventEmitter();
tabData: any[];
constructor() { }
ngOnInit(): void {
if( this.whichTab === 'rest' ) {
this.tabData = restApiDocsData;
} else if( this.whichTab = 'faq' ) {
this.tabData = faqData;
}
}
navLinkClick( event ) {
this.navLinkClickEvent.emit( event );
}
}

View File

@@ -0,0 +1,111 @@
<ng-container *ngIf="{ val: network$ | async } as network">
<div class="container-xl text-left">
<div id="faq" *ngIf="whichTab === 'faq'">
<div id="doc-nav-desktop" class="hide-on-mobile" [ngClass]="desktopDocsNavPosition">
<app-api-docs-nav (navLinkClickEvent)="anchorLinkClick( $event )" [network]="{ val: network$ | async }" [whichTab]="whichTab"></app-api-docs-nav>
</div>
<div class="doc-content">
<div class="doc-item-container" *ngFor="let item of faq">
<h3 *ngIf="item.type === 'category'">{{ item.title }}</h3>
<div *ngIf="item.type !== 'category'" class="endpoint-container" id="{{ item.fragment }}">
<a id="{{ item.fragment + '-tab-header' }}" class="section-header" (click)="anchorLinkClick( $event )" [routerLink]="['./']" fragment="{{ item.fragment }}"><table><tr><td>{{ item.title }}</td><td><span>{{ item.category }}</span></td></tr></table></a>
<div class="endpoint-content">
<div class="endpoint" [innerHTML]="item.answer | noSanitize"></div>
<div class="blockchain-wrapper" *ngIf="item.fragment === 'what-is-a-mempool-explorer'">
<app-blockchain></app-blockchain>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="restAPI" *ngIf="whichTab === 'rest'">
<div id="doc-nav-desktop" class="hide-on-mobile" [ngClass]="desktopDocsNavPosition">
<app-api-docs-nav (navLinkClickEvent)="anchorLinkClick( $event )" [network]="{ val: network$ | async }" [whichTab]="whichTab"></app-api-docs-nav>
</div>
<div class="doc-content">
<p class="hide-on-mobile no-bottom-space">Reference for the {{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} <ng-container i18n="api-docs.title">API service</ng-container>.</p>
<div class="doc-item-container" *ngFor="let item of restDocs">
<h3 *ngIf="( item.type === 'category' ) && ( item.showConditions.indexOf(network.val) > -1 )">{{ item.title }}</h3>
<div *ngIf="( item.type !== 'category' ) && ( item.showConditions.indexOf(network.val) > -1 )" class="endpoint-container" id="{{ item.fragment }}">
<a id="{{ item.fragment + '-tab-header' }}" class="section-header" (click)="anchorLinkClick( $event )" [routerLink]="['./']" fragment="{{ item.fragment }}">{{ item.title }} <span>{{ item.category }}</span></a>
<div class="endpoint-content">
<div class="endpoint">
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
<ng-container *ngIf="item.httpRequestMethod === 'GET' && network.val === 'bisq' && item.codeExample.hasOwnProperty('bisq');else liquid_link_example" #bisq_link_example>
<a [href]="wrapUrl(network.val, item.codeExample.bisq)" target="_blank">{{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }}</a>
</ng-container>
<ng-template #liquid_link_example>
<ng-container *ngIf="item.httpRequestMethod === 'GET' && network.val === 'liquid' && item.codeExample.hasOwnProperty('liquid');else default_link_example">
<a [href]="wrapUrl(network.val, item.codeExample.liquid)" target="_blank">{{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }}</a>
</ng-container>
</ng-template>
<ng-template #default_link_example>
<ng-container *ngIf="item.httpRequestMethod === 'GET'">
<a [href]="wrapUrl(network.val, item.codeExample.default)" target="_blank">{{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }}</a>
</ng-container>
</ng-template>
<div *ngIf="item.httpRequestMethod === 'POST'">{{ item.httpRequestMethod }} {{ item.urlString }}</div>
</div>
<div class="description">
<div class="subtitle" i18n>Description</div>
<ng-container *ngIf="network.val === 'bisq' && item.description.hasOwnProperty('bisq');else liquid_description" #bisq_description>
<div [innerHTML]="item.description.bisq" i18n></div>
</ng-container>
<ng-template #liquid_description>
<ng-container *ngIf="network.val === 'liquid' && item.description.hasOwnProperty('liquid');else default_description">
<div [innerHTML]="item.description.liquid" i18n></div>
</ng-container>
</ng-template>
<ng-template #default_description>
<div [innerHTML]="item.description.default" i18n></div>
</ng-template>
</div>
<ng-container *ngIf="network.val === 'bisq' && item.codeExample.hasOwnProperty('bisq');else liquid_code_example" #bisq_code_example>
<app-code-template [hostname]="hostname" [baseNetworkUrl]="baseNetworkUrl" [method]="item.httpRequestMethod" [code]="item.codeExample.bisq" [network]="network.val" ></app-code-template>
</ng-container>
<ng-template #liquid_code_example>
<ng-container *ngIf="network.val === 'liquid' && item.codeExample.hasOwnProperty('liquid');else default_code_example">
<app-code-template [hostname]="hostname" [baseNetworkUrl]="baseNetworkUrl" [method]="item.httpRequestMethod" [code]="item.codeExample.liquid" [network]="network.val" ></app-code-template>
</ng-container>
</ng-template>
<ng-template #default_code_example>
<app-code-template [hostname]="hostname" [baseNetworkUrl]="baseNetworkUrl" [method]="item.httpRequestMethod" [code]="item.codeExample.default" [network]="network.val" ></app-code-template>
</ng-template>
</div>
</div>
</div>
</div>
</div>
<div id="websocketAPI" *ngIf="( whichTab === 'websocket' ) && ( network.val !== 'bisq' )">
<div class="api-category">
<div class="websocket">
<div class="endpoint">
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
{{ wrapUrl(network.val, wsDocs, true) }}
</div>
<div class="description">
<div class="subtitle" i18n>Description</div>
<div i18n="api-docs.websocket.websocket">Default push: <code>{{ '{' }} action: 'want', data: ['blocks', ...] {{ '}' }}</code> to express what you want pushed. Available: <code>blocks</code>, <code>mempool-blocks</code>, <code>live-2h-chart</code>, and <code>stats</code>.<br><br>Push transactions related to address: <code>{{ '{' }} 'track-address': '3PbJ...bF9B' {{ '}' }}</code> to receive all new transactions containing that address as input or output. Returns an array of transactions. <code>address-transactions</code> for new mempool transactions, and <code>block-transactions</code> for new block confirmed transactions.</div>
</div>
<app-code-template [method]="'websocket'" [hostname]="hostname" [code]="wsDocs" [network]="network.val" ></app-code-template>
</div>
</div>
</div>
</div>
</ng-container>

View File

@@ -0,0 +1,256 @@
.text-small {
font-size: 12px;
}
code {
background-color: #1d1f31;
font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New;
}
tr {
white-space: inherit;
}
.nowrap {
white-space: nowrap;
}
li.nav-item {
width: 100%;
@media (min-width: 676px){
width: auto;
}
}
.no-bottom-space {
margin-bottom: 0;
}
.nav-tabs .nav-link.active {
border-bottom: 1px solid #fff;
@media (min-width: 676px){
border-bottom: 1px solid #11131f;
}
}
.code-tab {
width: auto;
margin: 20px auto 10px;
li.nav-item {
width: auto;
}
}
.code {
.tab-content {
padding: 0px;
}
.nav-tabs .nav-link.active {
border-bottom: 1px solid #11131f;
}
.subtitle {
display: flex;
justify-content: space-between;
}
}
.description {
margin-top: 20px;
}
.title {
font-weight: bold;
color: #ffffff;
font-size: 1.25rem;
}
.subtitle {
font-weight: bold;
}
.divider {
width: 100%;
margin: 30px auto;
height: 1px;
background: #333;
}
.difficulty {
padding: 15px;
}
#doc-nav-desktop {
width: 300px;
margin-top: -15px;
}
#doc-nav-desktop.relative {
float: left;
overflow: hidden;
}
#doc-nav-desktop.fixed {
float: unset;
position: fixed;
top: 20px;
overflow-y: auto;
height: calc(100vh - 50px);
scrollbar-color: #2d3348 #11131f;
scrollbar-width: thin;
}
::-webkit-scrollbar {
width: 3px;
}
::-webkit-scrollbar-track {
background: #11131f;
}
::-webkit-scrollbar-thumb {
background-color: #2d3348;
border-radius: 5px;
border: none;
}
.doc-content {
width: calc(100% - 330px);
float: right;
}
h3 {
margin: 2rem 0 0 0;
}
.endpoint-container:before {
display: block;
content: " ";
height: 1px;
margin-top: -1px;
visibility: hidden;
}
.endpoint-container .section-header {
display: block;
background-color: #2d3348;
color: #1bd8f4;
padding: 1rem 1.3rem 1rem 1.3rem;
font-weight: bold;
border-radius: 0.25rem;
margin: 20px 0 20px 0;
font-size: 24px;
position: relative;
}
.endpoint-container .section-header:hover {
text-decoration: none;
}
.endpoint-container .section-header span {
color: #fff;
background-color: #653b9c;
font-size: 12px;
text-transform: uppercase;
font-weight: 400;
padding: 8px 10px;
letter-spacing: 1px;
border-radius: 0.25rem;
font-family: monospace;
float: right;
}
.endpoint-container .section-header table {
width: 100%;
}
.endpoint-container .section-header table td:first-child {
padding-right: 24px;
}
#doc-nav-mobile {
position: fixed;
top: 20px;
width: calc(100% - 60px);
z-index: 100;
}
#doc-nav-mobile .card-body {
padding: 0 1.25rem 1.25rem 1.25rem;
}
#doc-nav-mobile > div {
background-color: #2d3348;
z-index: 100;
border-radius: 0 0 0.5rem 0.5rem;
height: 55vh;
overflow-y: auto;
}
#doc-nav-mobile button {
width: 100%;
background-color: #105fb0;
color: #fff;
border-color: #105fb0;
border-radius: 0.5rem 0.5rem 0 0;
}
.blockchain-wrapper {
position: relative;
width: 100%;
overflow: auto;
scrollbar-width: none;
}
.blockchain-wrapper::-webkit-scrollbar {
display: none;
}
@media (max-width: 992px) {
.hide-on-mobile {
display: none;
}
.doc-content {
width: 100%;
margin-top: -20px;
float: unset;
}
.endpoint-container {
position: relative;
overflow: hidden;
height: auto;
transition: 0.5s height ease;
}
.endpoint-container .section-header {
margin: 0;
font-size: 18px;
z-index: 1;
}
.endpoint-container .section-header span {
display: none;
}
.endpoint-container:before {
height: 5px;
margin-top: 10px;
}
.endpoint-container .endpoint-content {
width: 100%;
position: absolute;
top: -10000px;
opacity: 0;
transition: 0.5s opacity ease;
}
}
@media (min-width: 992px) {
.hide-on-desktop {
display: none;
}
h3 {
display: none;
}
.doc-item-container:last-of-type .endpoint-container {
margin-bottom: 4rem;
}
}

View File

@@ -0,0 +1,164 @@
import { Component, OnInit, Input, ViewChild, ElementRef } from '@angular/core';
import { Env, StateService } from '../../services/state.service';
import { Observable, merge, of } from 'rxjs';
import { SeoService } from '../../services/seo.service';
import { tap } from 'rxjs/operators';
import { ActivatedRoute } from "@angular/router";
import { faqData, restApiDocsData, wsApiDocsData } from './api-docs-data';
@Component({
selector: 'app-api-docs',
templateUrl: './api-docs.component.html',
styleUrls: ['./api-docs.component.scss']
})
export class ApiDocsComponent implements OnInit {
hostname = document.location.hostname;
network$: Observable<string>;
active = 0;
env: Env;
code: any;
baseNetworkUrl = '';
@Input() whichTab: string;
desktopDocsNavPosition = "relative";
faq: any[];
restDocs: any[];
wsDocs: any;
screenWidth: number;
constructor(
private stateService: StateService,
private seoService: SeoService,
private route: ActivatedRoute,
) { }
ngAfterViewInit() {
const that = this;
setTimeout( () => {
if( this.route.snapshot.fragment ) {
this.openEndpointContainer( this.route.snapshot.fragment );
}
window.addEventListener('scroll', function() {
that.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative";
});
}, 1 );
}
ngOnInit(): void {
this.env = this.stateService.env;
this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`);
this.network$ = merge(of(''), this.stateService.networkChanged$).pipe(
tap((network: string) => {
if (this.env.BASE_MODULE === 'mempool' && network !== '') {
this.baseNetworkUrl = `/${network}`;
} else if (this.env.BASE_MODULE === 'liquid') {
if (!['', 'liquid'].includes(network)) {
this.baseNetworkUrl = `/${network}`;
}
}
return network;
})
);
if (document.location.port !== '') {
this.hostname = `${this.hostname}:${document.location.port}`;
}
this.hostname = `${document.location.protocol}//${this.hostname}`;
this.faq = faqData;
this.restDocs = restApiDocsData;
this.wsDocs = wsApiDocsData;
this.network$.subscribe((network) => {
this.active = (network === 'liquid' || network === 'liquidtestnet') ? 2 : 0;
});
}
anchorLinkClick( event: any ) {
let targetId = "";
if( event.target.nodeName === "A" ) {
targetId = event.target.hash.substring(1);
} else {
let element = event.target;
while( element.nodeName !== "A" ) {
element = element.parentElement;
}
targetId = element.hash.substring(1);
}
if( this.route.snapshot.fragment === targetId ) {
document.getElementById( targetId ).scrollIntoView();
}
this.openEndpointContainer( targetId );
}
openEndpointContainer( targetId ) {
const tabHeaderHeight = document.getElementById( targetId + "-tab-header" ).scrollHeight;
if( ( window.innerWidth <= 992 ) && ( ( this.whichTab === 'rest' ) || ( this.whichTab === 'faq' ) ) && targetId ) {
const endpointContainerEl = document.querySelector<HTMLElement>( "#" + targetId );
const endpointContentEl = document.querySelector<HTMLElement>( "#" + targetId + " .endpoint-content" );
const endPointContentElHeight = endpointContentEl.clientHeight;
if( endpointContentEl.classList.contains( "open" ) ) {
endpointContainerEl.style.height = "auto";
endpointContentEl.style.top = "-10000px";
endpointContentEl.style.opacity = "0";
endpointContentEl.classList.remove( "open" );
} else {
endpointContainerEl.style.height = endPointContentElHeight + tabHeaderHeight + 28 + "px";
endpointContentEl.style.top = tabHeaderHeight + 28 + "px";
endpointContentEl.style.opacity = "1";
endpointContentEl.classList.add( "open" );
}
}
}
wrapUrl(network: string, code: any, websocket: boolean = false) {
let curlResponse = [];
if (['', 'mainnet'].includes(network)){
curlResponse = code.codeSampleMainnet.curl;
}
if (network === 'testnet') {
curlResponse = code.codeSampleTestnet.curl;
}
if (network === 'signet') {
curlResponse = code.codeSampleSignet.curl;
}
if (network === 'liquid') {
curlResponse = code.codeSampleLiquid.curl;
}
if (network === 'liquidtestnet') {
curlResponse = code.codeSampleLiquidTestnet.curl;
}
if (network === 'bisq') {
curlResponse = code.codeSampleBisq.curl;
}
let curlNetwork = '';
if (this.env.BASE_MODULE === 'mempool') {
if (!['', 'mainnet'].includes(network)) {
curlNetwork = `/${network}`;
}
} else if (this.env.BASE_MODULE === 'liquid') {
if (!['', 'liquid'].includes(network)) {
curlNetwork = `/${network}`;
}
}
let text = code.codeTemplate.curl;
for (let index = 0; index < curlResponse.length; index++) {
const curlText = curlResponse[index];
const indexNumber = index + 1;
text = text.replace('%{' + indexNumber + '}', curlText);
}
if (websocket) {
const wsHostname = this.hostname.replace('https://', 'wss://');
wsHostname.replace('http://', 'ws://');
return `${wsHostname}${curlNetwork}${text}`;
}
return `${this.hostname}${curlNetwork}${text}`;
}
}

View File

@@ -0,0 +1,39 @@
<div class="code">
<ul ngbNav #navCodeTemplate="ngbNav" class="nav-tabs code-tab">
<li ngbNavItem *ngIf="code.codeTemplate.curl && method !== 'websocket'">
<a ngbNavLink (click)="adjustContainerHeight( $event )">cURL</a>
<ng-template ngbNavContent>
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapCurlTemplate(code)"></app-clipboard></div>
<pre><code [innerText]="wrapCurlTemplate(code)"></code></pre>
</ng-template>
</li>
<li ngbNavItem *ngIf="network !== 'liquidtestnet'">
<a ngbNavLink (click)="adjustContainerHeight( $event )" >CommonJS</a>
<ng-template ngbNavContent>
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapCommonJS(code)"></app-clipboard></div>
<div class="links">
<a [href]="npmGithubLink()" target="_blank">GitHub Repo</a>
</div>
<pre><code [innerText]="wrapCommonJS(code)"></code></pre>
</ng-template>
</li>
<li ngbNavItem>
<a ngbNavLink (click)="adjustContainerHeight( $event )" *ngIf="network !== 'liquidtestnet'">ES Module</a>
<ng-template ngbNavContent>
<div class="subtitle"><ng-container i18n="API Docs install lib">Install Package</ng-container> <app-clipboard [text]="wrapImportTemplate()"></app-clipboard></div>
<div class="links">
<a [href]="npmGithubLink()" target="_blank">GitHub Repo</a>
<a [href]="npmModuleLink()" target="_blank">NPM Package</a>
</div>
<pre><code [innerText]="wrapImportTemplate()"></code></pre>
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapEsModule(code)"></app-clipboard></div>
<pre><code [innerText]="wrapEsModule(code)"></code></pre>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="navCodeTemplate"></div>
<div *ngIf="code.codeTemplate && wrapResponse(code) !== ''" class="response">
<div class="subtitle"><ng-container i18n="API Docs API response">Response</ng-container> <app-clipboard [text]="wrapResponse(code)"></app-clipboard></div>
<pre><code [innerText]="wrapResponse(code)"></code></pre>
</div>
</div>

View File

@@ -0,0 +1,97 @@
.text-small {
font-size: 12px;
}
code {
background-color: #1d1f31;
font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New;
}
tr {
white-space: inherit;
}
.nowrap {
white-space: nowrap;
}
li.nav-item {
width: 100%;
@media (min-width: 676px){
width: auto;
}
}
.nav-tabs .nav-link.active {
border-bottom: 1px solid #fff;
@media (min-width: 676px){
border-bottom: 1px solid #11131f;
}
}
.code-tab {
width: auto;
margin: 20px auto 10px;
li.nav-item {
width: auto;
}
}
.code {
.tab-content {
padding: 0px;
}
.nav-tabs .nav-link.active {
border-bottom: 1px solid #11131f;
}
.subtitle {
display: flex;
justify-content: space-between;
}
}
.description {
margin-top: 20px;
}
.title {
font-weight: bold;
color: #ffffff;
font-size: 1.25rem;
}
.subtitle {
font-weight: bold;
}
.divider {
width: 100%;
margin: 30px auto;
height: 1px;
background: #333;
}
.websocket {
padding: 15px;
}
.difficulty {
padding: 15px;
}
.links {
margin-bottom: 5px;
a {
font-size: 14px;
margin: 0px 10px 0px 0px;
}
}
pre {
display: block;
font-size: 87.5%;
color: #f18920;
background-color: #1d1f31;
padding: 30px;
code{
background-color: transparent;
white-space: break-spaces;
word-break: break-all;
}
}

View File

@@ -0,0 +1,333 @@
import { Component, Input, OnInit } from '@angular/core';
import { Env, StateService } from '../../services/state.service';
@Component({
selector: 'app-code-template',
templateUrl: './code-template.component.html',
styleUrls: ['./code-template.component.scss']
})
export class CodeTemplateComponent implements OnInit {
@Input() network: string;
@Input() code: any;
@Input() hostname: string;
@Input() baseNetworkUrl: string;
@Input() method: 'GET' | 'POST' | 'websocket' = 'GET';
env: Env;
constructor(
private stateService: StateService,
) { }
ngOnInit(): void {
this.env = this.stateService.env;
}
adjustContainerHeight( event ) {
if( ( window.innerWidth <= 992 ) && ( this.method !== "websocket" ) ) {
const urlObj = new URL( window.location + "" );
const endpointContainerEl = document.querySelector<HTMLElement>( urlObj.hash );
const endpointContentEl = document.querySelector<HTMLElement>( urlObj.hash + " .endpoint-content" );
window.setTimeout( function() {
endpointContainerEl.style.height = endpointContentEl.clientHeight + 90 + "px";
}, 550);
}
}
npmGithubLink(){
let npmLink = `https://github.com/mempool/mempool.js`;
if (this.network === 'bisq') {
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-bisq-js`;
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-liquid-js`;
}
return npmLink;
}
npmModuleLink() {
let npmLink = `https://www.npmjs.org/package/@mempool/mempool.js`;
if (this.network === 'bisq') {
npmLink = `https://www.npmjs.org/package/@mempool/bisq.js`;
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
npmLink = `https://www.npmjs.org/package/@mempool/liquid.js`;
}
return npmLink;
}
normalizeHostsESModule(codeText: string) {
if (this.env.BASE_MODULE === 'mempool') {
if (['liquid', 'bisq'].includes(this.network)) {
codeText = codeText.replace('%{0}', this.network);
} else {
codeText = codeText.replace('%{0}', 'bitcoin');
}
if(['', 'main', 'liquid', 'bisq', 'liquidtestnet'].includes(this.network)) {
codeText = codeText.replace('mempoolJS();', `mempoolJS({
hostname: '${document.location.hostname}'
});`);
} else {
codeText = codeText.replace('mempoolJS();', `mempoolJS({
hostname: '${document.location.hostname}',
network: '${this.network}'
});`);
}
}
if (this.env.BASE_MODULE === 'bisq') {
codeText = codeText.replace('} = mempoolJS();', ` = bisqJS();`);
codeText = codeText.replace('{ %{0}: ', '');
}
if (this.env.BASE_MODULE === 'liquid') {
codeText = codeText.replace('} = mempoolJS();', ` = liquidJS();`);
codeText = codeText.replace('{ %{0}: ', '');
}
return codeText;
}
normalizeHostsCommonJS(codeText: string) {
if (this.env.BASE_MODULE === 'mempool') {
if (['liquid', 'bisq'].includes(this.network)) {
codeText = codeText.replace('%{0}', this.network);
} else {
codeText = codeText.replace('%{0}', 'bitcoin');
}
if(['', 'main', 'liquid', 'bisq'].includes(this.network)) {
codeText = codeText.replace('mempoolJS();', `mempoolJS({
hostname: '${document.location.hostname}'
});`);
} else {
codeText = codeText.replace('mempoolJS();', `mempoolJS({
hostname: '${document.location.hostname}',
network: '${this.network}'
});`);
}
}
if (this.env.BASE_MODULE === 'bisq') {
codeText = codeText.replace('} = mempoolJS();', ` = bisqJS();`);
codeText = codeText.replace('{ %{0}: ', '');
}
if (this.env.BASE_MODULE === 'liquid') {
codeText = codeText.replace('} = mempoolJS();', ` = liquidJS();`);
codeText = codeText.replace('{ %{0}: ', '');
}
return codeText;
}
wrapEsModule(code: any) {
let codeText: string;
if (code.codeTemplate) {
codeText = this.normalizeHostsESModule(code.codeTemplate.esModule);
if(this.network === '' || this.network === 'main') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleMainnet.esModule);
}
if (this.network === 'testnet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleTestnet.esModule);
}
if (this.network === 'signet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
}
if (this.network === 'bisq') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleBisq.esModule);
}
let importText = `import mempoolJS from "@mempool/mempool.js";`;
if (this.env.BASE_MODULE === 'bisq') {
importText = `import bisqJS from "@mempool/bisq.js";`;
}
if (this.env.BASE_MODULE === 'liquid') {
importText = `import liquidJS from "@mempool/liquid.js";`;
}
return `${importText}
const init = async () => {
${codeText}
};
init();`;
}
}
wrapCommonJS(code: any) {
let codeText: string;
if (code.codeTemplate) {
codeText = this.normalizeHostsCommonJS(code.codeTemplate.commonJS);
if(this.network === '' || this.network === 'main') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleMainnet.esModule);
}
if (this.network === 'testnet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleTestnet.esModule);
}
if (this.network === 'signet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
}
if (this.network === 'bisq') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleBisq.esModule);
}
if (code.noWrap) {
return codeText;
}
let importText = `<script src="https://mempool.space/mempool.js"></script>`;
if (this.env.BASE_MODULE === 'bisq') {
importText = `<script src="https://bisq.markets/bisq.js"></script>`;
}
if (this.env.BASE_MODULE === 'liquid') {
importText = `<script src="https://liquid.network/liquid.js"></script>`;
}
let resultHtml = '<pre id="result"></pre>';
if (this.method === 'websocket') {
resultHtml = `<h2>Blocks</h2><pre id="result-blocks">Waiting for data</pre><br>
<h2>Mempool Info</h2><pre id="result-mempool-info">Waiting for data</pre><br>
<h2>Transactions</h2><pre id="result-transactions">Waiting for data</pre><br>
<h2>Mempool Blocks</h2><pre id="result-mempool-blocks">Waiting for data</pre><br>`;
}
return `<!DOCTYPE html>
<html>
<head>
${importText}
<script>
const init = async () => {
${codeText}
};
init();
</script>
</head>
<body>
${resultHtml}
</body>
</html>`;
}
}
wrapImportTemplate() {
let importTemplate = `# npm
npm install @mempool/mempool.js --save
# yarn
yarn add @mempool/mempool.js`;
if (this.env.BASE_MODULE === 'bisq') {
importTemplate = `# npm
npm install @mempool/bisq.js --save
# yarn
yarn add @mempool/bisq.js`;
}
if (this.env.BASE_MODULE === 'liquid') {
importTemplate = `# npm
npm install @mempool/liquid.js --save
# yarn
yarn add @mempool/liquid.js`;
}
return importTemplate;
}
wrapCurlTemplate(code: any) {
if (code.codeTemplate) {
if (this.network === 'testnet') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleTestnet);
}
if (this.network === 'signet') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleSignet);
}
if (this.network === 'liquid') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleLiquid);
}
if (this.network === 'liquidtestnet') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleLiquidTestnet);
}
if (this.network === 'bisq') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleBisq);
}
if (this.network === '' || this.network === 'main') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleMainnet);
}
}
}
wrapResponse(code: any) {
if (this.method === 'websocket') {
return '';
}
if (this.network === 'testnet') {
return code.codeSampleTestnet.response;
}
if (this.network === 'signet') {
return code.codeSampleSignet.response;
}
if (this.network === 'liquid') {
return code.codeSampleLiquid.response;
}
if (this.network === 'liquidtestnet') {
return code.codeSampleLiquidTestnet.response;
}
if (this.network === 'bisq') {
return code.codeSampleBisq.response;
}
return code.codeSampleMainnet.response;
}
replaceJSPlaceholder(text: string, code: any) {
for (let index = 0; index < code.length; index++) {
const textReplace = code[index];
const indexNumber = index + 1;
text = text.replace('%{' + indexNumber + '}', textReplace);
}
return text;
}
replaceCurlPlaceholder(curlText: any, code: any) {
let text = curlText;
text = text.replace( "[[hostname]]", this.hostname );
text = text.replace( "[[baseNetworkUrl]]", this.baseNetworkUrl );
for (let index = 0; index < code.curl.length; index++) {
const textReplace = code.curl[index];
const indexNumber = index + 1;
text = text.replace('%{' + indexNumber + '}', textReplace);
}
if (this.env.BASE_MODULE === 'mempool') {
if (this.network === 'main' || this.network === '') {
if (this.method === 'POST') {
return `curl -X POST -sSLd "${text}"`;
}
return `curl -sSL "${this.hostname}${text}"`;
}
if (this.method === 'POST') {
return `curl -X POST -sSLd "${text}"`;
}
return `curl -sSL "${this.hostname}/${this.network}${text}"`;
} else if (this.env.BASE_MODULE === 'liquid') {
if (this.method === 'POST') {
if (this.network !== 'liquid') {
text = text.replace('/api', `/${this.network}/api`);
}
return `curl -X POST -sSLd "${text}"`;
}
return ( this.network === 'liquid' ? `curl -sSL "${this.hostname}${text}"` : `curl -sSL "${this.hostname}/${this.network}${text}"` );
} else {
return `curl -sSL "${this.hostname}${text}"`;
}
}
}

View File

@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '../shared/shared.module';
import { ApiDocsComponent } from './/api-docs/api-docs.component';
import { DocsComponent } from './docs/docs.component';
import { ApiDocsNavComponent } from './api-docs/api-docs-nav.component';
import { CodeTemplateComponent } from './code-template/code-template.component';
import { DocsRoutingModule } from './docs.routing.module';
@NgModule({
declarations: [
ApiDocsComponent,
CodeTemplateComponent,
ApiDocsNavComponent,
DocsComponent,
],
imports: [
CommonModule,
SharedModule,
DocsRoutingModule,
]
})
export class DocsModule { }

View File

@@ -0,0 +1,58 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DocsComponent } from './docs/docs.component';
const browserWindow = window || {};
// @ts-ignore
const browserWindowEnv = browserWindow.__env || {};
let routes: Routes = [];
if (browserWindowEnv.BASE_MODULE && (browserWindowEnv.BASE_MODULE === 'bisq' || browserWindowEnv.BASE_MODULE === 'liquid')) {
routes = [
{
path: '',
redirectTo: 'api/rest'
},
{
path: 'api/:type',
component: DocsComponent
},
{
path: 'api',
redirectTo: 'api/rest'
},
{
path: '**',
redirectTo: 'api/rest'
}
];
} else {
routes = [
{
path: '',
redirectTo: 'faq'
},
{
path: 'api/:type',
component: DocsComponent
},
{
path: 'faq',
component: DocsComponent
},
{
path: 'api',
redirectTo: 'api/rest'
},
{
path: '**',
redirectTo: 'api/faq'
}
];
}
@NgModule({
imports: [RouterModule.forChild(routes)],
})
export class DocsRoutingModule { }

View File

@@ -0,0 +1,48 @@
<div class="container-xl">
<div class="text-center">
<h2 i18n="documentation.title">Documentation</h2>
<ul ngbNav #nav="ngbNav" [(activeId)]="activeTab" class="nav-tabs">
<li [ngbNavItem]="0" *ngIf="showFaqTab">
<a ngbNavLink [routerLink]="['/docs/faq' | relativeUrl]">FAQ</a>
<ng-template ngbNavContent>
<app-api-docs [whichTab]="'faq'"></app-api-docs>
</ng-template>
</li>
<li [ngbNavItem]="1">
<a ngbNavLink [routerLink]="['/docs/api/rest' | relativeUrl]">API - REST</a>
<ng-template ngbNavContent>
<app-api-docs [whichTab]="'rest'"></app-api-docs>
</ng-template>
</li>
<li [ngbNavItem]="2" *ngIf="showWebSocketTab">
<a ngbNavLink [routerLink]="['/docs/api/websocket' | relativeUrl]">API - WebSocket</a>
<ng-template ngbNavContent>
<app-api-docs [whichTab]="'websocket'"></app-api-docs>
</ng-template>
</li>
</ul>
<div id="main-tab-content" [ngbNavOutlet]="nav" class="mt-2"></div>
<br>
<div id="footer" class="text-center">
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
|
<a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a>
</div>
</div>
</div>

View File

@@ -0,0 +1,9 @@
#main-tab-content {
text-align: left;
padding-top: 10px;
scroll-behavior: smooth;
}
#footer {
clear: both;
}

View File

@@ -0,0 +1,47 @@
import { Component, OnInit, HostBinding } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Env, StateService } from '../../services/state.service';
import { WebsocketService } from '../../services/websocket.service';
@Component({
selector: 'app-docs',
templateUrl: './docs.component.html',
styleUrls: ['./docs.component.scss']
})
export class DocsComponent implements OnInit {
activeTab = 0;
env: Env;
showWebSocketTab = true;
showFaqTab = true;
@HostBinding('attr.dir') dir = 'ltr';
constructor(
private route: ActivatedRoute,
private stateService: StateService,
private websocket: WebsocketService,
) { }
ngOnInit(): void {
this.websocket.want(['blocks']);
const url = this.route.snapshot.url;
if (url[0].path === "faq" ) {
this.activeTab = 0;
} else if( url[1].path === "rest" ) {
this.activeTab = 1;
} else {
this.activeTab = 2;
}
this.env = this.stateService.env;
this.showWebSocketTab = ( ! ( ( this.stateService.network === "bisq" ) || ( this.stateService.network === "liquidtestnet" ) ) );
this.showFaqTab = ( this.env.BASE_MODULE === 'mempool' ) ? true : false;
document.querySelector<HTMLElement>( "html" ).style.scrollBehavior = "smooth";
}
ngOnDestroy(): void {
document.querySelector<HTMLElement>( "html" ).style.scrollBehavior = "auto";
}
}