diff --git a/apps/explorer-e2e/src/support/pages/base-page.js b/apps/explorer-e2e/src/support/pages/base-page.js index 75fa90c98..344b6e125 100644 --- a/apps/explorer-e2e/src/support/pages/base-page.js +++ b/apps/explorer-e2e/src/support/pages/base-page.js @@ -54,7 +54,7 @@ export default class BasePage { validateSearchDisplayed() { cy.getByTestId(this.blockExplorerHeader).should( 'have.text', - 'Vega Block Explorer' + 'Vega Explorer' ); cy.getByTestId(this.searchField).should('be.visible'); } diff --git a/apps/explorer/src/app/routes/home/index.tsx b/apps/explorer/src/app/routes/home/index.tsx index f1633ff56..032d9254b 100644 --- a/apps/explorer/src/app/routes/home/index.tsx +++ b/apps/explorer/src/app/routes/home/index.tsx @@ -1,7 +1,9 @@ +import { StatsManager } from '@vegaprotocol/mainnet-stats-manager'; + const Home = () => { return ( - Home page content + ); }; diff --git a/apps/stats-mainnet-e2e/.eslintrc.json b/apps/stats-mainnet-e2e/.eslintrc.json new file mode 100644 index 000000000..696cb8b12 --- /dev/null +++ b/apps/stats-mainnet-e2e/.eslintrc.json @@ -0,0 +1,10 @@ +{ + "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/apps/stats-mainnet-e2e/cypress.json b/apps/stats-mainnet-e2e/cypress.json new file mode 100644 index 000000000..51e27859e --- /dev/null +++ b/apps/stats-mainnet-e2e/cypress.json @@ -0,0 +1,14 @@ +{ + "baseUrl": "http://localhost:3010", + "projectId": "et4snf", + "fileServerFolder": ".", + "fixturesFolder": "./src/fixtures", + "integrationFolder": "./src/integration", + "modifyObstructiveCode": false, + "supportFile": "./src/support/index.ts", + "pluginsFile": false, + "video": true, + "videosFolder": "../../dist/cypress/apps/stats-mainnet-e2e/videos", + "screenshotsFolder": "../../dist/cypress/apps/stats-mainnet-e2e/screenshots", + "chromeWebSecurity": false +} diff --git a/apps/stats-mainnet-e2e/project.json b/apps/stats-mainnet-e2e/project.json new file mode 100644 index 000000000..bdf7accfc --- /dev/null +++ b/apps/stats-mainnet-e2e/project.json @@ -0,0 +1,28 @@ +{ + "root": "apps/stats-mainnet-e2e", + "sourceRoot": "apps/stats-mainnet-e2e/src", + "projectType": "application", + "targets": { + "e2e": { + "executor": "@nrwl/cypress:cypress", + "options": { + "cypressConfig": "apps/stats-mainnet-e2e/cypress.json", + "devServerTarget": "stats-mainnet:serve" + }, + "configurations": { + "production": { + "devServerTarget": "stats-mainnet:serve:production" + } + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["apps/stats-mainnet-e2e/**/*.{js,ts}"] + } + } + }, + "tags": [], + "implicitDependencies": ["stats-mainnet"] +} diff --git a/apps/stats-mainnet-e2e/src/fixtures/example.json b/apps/stats-mainnet-e2e/src/fixtures/example.json new file mode 100644 index 000000000..294cbed6c --- /dev/null +++ b/apps/stats-mainnet-e2e/src/fixtures/example.json @@ -0,0 +1,4 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io" +} diff --git a/apps/stats-mainnet-e2e/src/integration/app.spec.ts b/apps/stats-mainnet-e2e/src/integration/app.spec.ts new file mode 100644 index 000000000..77a688f7c --- /dev/null +++ b/apps/stats-mainnet-e2e/src/integration/app.spec.ts @@ -0,0 +1,7 @@ +describe('stats-mainnet', () => { + beforeEach(() => cy.visit('/')); + + it('should display header', () => { + cy.get('h3').should('have.text', '/ Mainnet'); + }); +}); diff --git a/apps/stats-mainnet-e2e/src/support/commands.ts b/apps/stats-mainnet-e2e/src/support/commands.ts new file mode 100644 index 000000000..310f1fa0e --- /dev/null +++ b/apps/stats-mainnet-e2e/src/support/commands.ts @@ -0,0 +1,33 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** + +// eslint-disable-next-line @typescript-eslint/no-namespace +declare namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + login(email: string, password: string): void; + } +} +// +// -- This is a parent command -- +Cypress.Commands.add('login', (email, password) => { + console.log('Custom command example: Login', email, password); +}); +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/stats-mainnet-e2e/src/support/index.ts b/apps/stats-mainnet-e2e/src/support/index.ts new file mode 100644 index 000000000..3d469a6b6 --- /dev/null +++ b/apps/stats-mainnet-e2e/src/support/index.ts @@ -0,0 +1,17 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands'; diff --git a/apps/stats-mainnet-e2e/tsconfig.json b/apps/stats-mainnet-e2e/tsconfig.json new file mode 100644 index 000000000..c4f818ecd --- /dev/null +++ b/apps/stats-mainnet-e2e/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "sourceMap": false, + "outDir": "../../dist/out-tsc", + "allowJs": true, + "types": ["cypress", "node"] + }, + "include": ["src/**/*.ts", "src/**/*.js"] +} diff --git a/apps/stats-mainnet/.babelrc b/apps/stats-mainnet/.babelrc new file mode 100644 index 000000000..61641ec8a --- /dev/null +++ b/apps/stats-mainnet/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [ + [ + "@nrwl/react/babel", + { + "runtime": "automatic" + } + ] + ], + "plugins": [] +} diff --git a/apps/stats-mainnet/.browserslistrc b/apps/stats-mainnet/.browserslistrc new file mode 100644 index 000000000..f1d12df4f --- /dev/null +++ b/apps/stats-mainnet/.browserslistrc @@ -0,0 +1,16 @@ +# This file is used by: +# 1. autoprefixer to adjust CSS to support the below specified browsers +# 2. babel preset-env to adjust included polyfills +# +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# If you need to support different browsers in production, you may tweak the list below. + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major version +last 2 iOS major versions +Firefox ESR +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/apps/stats-mainnet/.eslintrc.json b/apps/stats-mainnet/.eslintrc.json new file mode 100644 index 000000000..734ddacee --- /dev/null +++ b/apps/stats-mainnet/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/apps/stats-mainnet/jest.config.js b/apps/stats-mainnet/jest.config.js new file mode 100644 index 000000000..d4328090a --- /dev/null +++ b/apps/stats-mainnet/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + displayName: 'stats-mainnet', + preset: '../../jest.preset.js', + transform: { + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', + '^.+\\.[tj]sx?$': 'babel-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/apps/stats-mainnet', +}; diff --git a/apps/stats-mainnet/postcss.config.js b/apps/stats-mainnet/postcss.config.js new file mode 100644 index 000000000..cbdd9c22c --- /dev/null +++ b/apps/stats-mainnet/postcss.config.js @@ -0,0 +1,10 @@ +const { join } = require('path'); + +module.exports = { + plugins: { + tailwindcss: { + config: join(__dirname, 'tailwind.config.js'), + }, + autoprefixer: {}, + }, +}; diff --git a/apps/stats-mainnet/project.json b/apps/stats-mainnet/project.json new file mode 100644 index 000000000..e66aa17c6 --- /dev/null +++ b/apps/stats-mainnet/project.json @@ -0,0 +1,74 @@ +{ + "root": "apps/stats-mainnet", + "sourceRoot": "apps/stats-mainnet/src", + "projectType": "application", + "targets": { + "build": { + "executor": "@nrwl/web:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/stats-mainnet", + "index": "apps/stats-mainnet/src/index.html", + "baseHref": "/", + "main": "apps/stats-mainnet/src/main.tsx", + "polyfills": "apps/stats-mainnet/src/polyfills.ts", + "tsConfig": "apps/stats-mainnet/tsconfig.app.json", + "assets": [ + "apps/stats-mainnet/src/assets/favicon.ico", + "apps/stats-mainnet/src/assets" + ], + "styles": ["apps/stats-mainnet/src/styles/styles.css"], + "scripts": [], + "webpackConfig": "@nrwl/react/plugins/webpack" + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "apps/stats-mainnet/src/environments/environment.ts", + "with": "apps/stats-mainnet/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false + } + } + }, + "serve": { + "executor": "@nrwl/web:dev-server", + "options": { + "port": 3010, + "buildTarget": "stats-mainnet:build", + "hmr": true + }, + "configurations": { + "production": { + "buildTarget": "stats-mainnet:build:production", + "hmr": false + } + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["apps/stats-mainnet/**/*.{ts,tsx,js,jsx}"] + } + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["coverage/apps/stats-mainnet"], + "options": { + "jestConfig": "apps/stats-mainnet/jest.config.js", + "passWithNoTests": true + } + } + }, + "tags": [] +} diff --git a/apps/stats-mainnet/src/app.tsx b/apps/stats-mainnet/src/app.tsx new file mode 100644 index 000000000..42aa79564 --- /dev/null +++ b/apps/stats-mainnet/src/app.tsx @@ -0,0 +1,24 @@ +import React, { useState } from 'react'; +import { Header } from './components/header'; +import { StatsManager } from '@vegaprotocol/mainnet-stats-manager'; + +function App() { + const [darkMode, setDarkMode] = useState( + document.documentElement.classList.contains('dark-mode-preferred') + ); + + return ( + + + + + + + ); +} + +export default App; diff --git a/apps/stats-mainnet/src/assets/apple-touch-icon.png b/apps/stats-mainnet/src/assets/apple-touch-icon.png new file mode 100644 index 000000000..50cdf7782 Binary files /dev/null and b/apps/stats-mainnet/src/assets/apple-touch-icon.png differ diff --git a/apps/stats-mainnet/src/assets/favicon.ico b/apps/stats-mainnet/src/assets/favicon.ico new file mode 100644 index 000000000..03a276d66 Binary files /dev/null and b/apps/stats-mainnet/src/assets/favicon.ico differ diff --git a/apps/stats-mainnet/src/assets/logo.png b/apps/stats-mainnet/src/assets/logo.png new file mode 100644 index 000000000..0245ca6ca Binary files /dev/null and b/apps/stats-mainnet/src/assets/logo.png differ diff --git a/apps/stats-mainnet/src/assets/logo192.png b/apps/stats-mainnet/src/assets/logo192.png new file mode 100644 index 000000000..a229d08ba Binary files /dev/null and b/apps/stats-mainnet/src/assets/logo192.png differ diff --git a/apps/stats-mainnet/src/assets/manifest.json b/apps/stats-mainnet/src/assets/manifest.json new file mode 100644 index 000000000..949569331 --- /dev/null +++ b/apps/stats-mainnet/src/assets/manifest.json @@ -0,0 +1,20 @@ +{ + "short_name": "Mainnet Stats", + "name": "Vega Mainnet statistics", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/apps/stats-mainnet/src/assets/robots.txt b/apps/stats-mainnet/src/assets/robots.txt new file mode 100644 index 000000000..e9e57dc4d --- /dev/null +++ b/apps/stats-mainnet/src/assets/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/apps/stats-mainnet/src/components/header/header.tsx b/apps/stats-mainnet/src/components/header/header.tsx new file mode 100644 index 000000000..acbfcf2e8 --- /dev/null +++ b/apps/stats-mainnet/src/components/header/header.tsx @@ -0,0 +1,32 @@ +import { VegaLogo } from '@vegaprotocol/ui-toolkit'; +import { LightModeToggle, DarkModeToggle } from '../images'; +import { VegaBackgroundVideo } from '../videos'; +import { DarkModeState } from '../../config/types'; + +export const Header = ({ darkMode, setDarkMode }: DarkModeState) => { + return ( + + + + + + + + setDarkMode(!darkMode)} + aria-label="Switch theme color" + className={`transition-colors rounded-full cursor-pointer ${ + darkMode ? 'hover:bg-neutral-900' : 'hover:bg-neutral-200' + }`} + > + {darkMode ? : } + + + + + ); +}; diff --git a/apps/stats-mainnet/src/components/header/index.ts b/apps/stats-mainnet/src/components/header/index.ts new file mode 100644 index 000000000..ddd972315 --- /dev/null +++ b/apps/stats-mainnet/src/components/header/index.ts @@ -0,0 +1 @@ +export { Header } from './header'; diff --git a/apps/stats-mainnet/src/components/images/dark-mode-toggle.tsx b/apps/stats-mainnet/src/components/images/dark-mode-toggle.tsx new file mode 100644 index 000000000..42a7ac3b2 --- /dev/null +++ b/apps/stats-mainnet/src/components/images/dark-mode-toggle.tsx @@ -0,0 +1,18 @@ +export const DarkModeToggle = () => { + return ( + + + + + + + ); +}; diff --git a/apps/stats-mainnet/src/components/images/index.ts b/apps/stats-mainnet/src/components/images/index.ts new file mode 100644 index 000000000..fd1bfea32 --- /dev/null +++ b/apps/stats-mainnet/src/components/images/index.ts @@ -0,0 +1,2 @@ +export { DarkModeToggle } from './dark-mode-toggle'; +export { LightModeToggle } from './light-mode-toggle'; diff --git a/apps/stats-mainnet/src/components/images/light-mode-toggle.tsx b/apps/stats-mainnet/src/components/images/light-mode-toggle.tsx new file mode 100644 index 000000000..f71b5eb9d --- /dev/null +++ b/apps/stats-mainnet/src/components/images/light-mode-toggle.tsx @@ -0,0 +1,10 @@ +export const LightModeToggle = () => { + return ( + + + + ); +}; diff --git a/apps/stats-mainnet/src/components/videos/index.ts b/apps/stats-mainnet/src/components/videos/index.ts new file mode 100644 index 000000000..d43c5dd49 --- /dev/null +++ b/apps/stats-mainnet/src/components/videos/index.ts @@ -0,0 +1 @@ +export { VegaBackgroundVideo } from './vega-background-video'; diff --git a/apps/stats-mainnet/src/components/videos/vega-background-video.tsx b/apps/stats-mainnet/src/components/videos/vega-background-video.tsx new file mode 100644 index 000000000..9b36df0be --- /dev/null +++ b/apps/stats-mainnet/src/components/videos/vega-background-video.tsx @@ -0,0 +1,16 @@ +export const VegaBackgroundVideo = () => { + return ( + + + + ); +}; diff --git a/apps/stats-mainnet/src/config/types.ts b/apps/stats-mainnet/src/config/types.ts new file mode 100644 index 000000000..ebab4ed91 --- /dev/null +++ b/apps/stats-mainnet/src/config/types.ts @@ -0,0 +1,4 @@ +export interface DarkModeState { + darkMode: boolean; + setDarkMode: (arg0: boolean) => void; +} diff --git a/apps/stats-mainnet/src/index.html b/apps/stats-mainnet/src/index.html new file mode 100644 index 000000000..4476c74cc --- /dev/null +++ b/apps/stats-mainnet/src/index.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + Vega Mainnet Stats + + + + You need to enable JavaScript to run this app. + + + + diff --git a/apps/stats-mainnet/src/main.tsx b/apps/stats-mainnet/src/main.tsx new file mode 100644 index 000000000..9ad023d26 --- /dev/null +++ b/apps/stats-mainnet/src/main.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './styles/styles.css'; +import App from './app'; +import reportWebVitals from './reportWebVitals'; + +ReactDOM.render( + + + , + document.getElementById('root') +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/apps/stats-mainnet/src/polyfills.ts b/apps/stats-mainnet/src/polyfills.ts new file mode 100644 index 000000000..2adf3d05b --- /dev/null +++ b/apps/stats-mainnet/src/polyfills.ts @@ -0,0 +1,7 @@ +/** + * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. + * + * See: https://github.com/zloirock/core-js#babel + */ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; diff --git a/apps/stats-mainnet/src/react-app-env.d.ts b/apps/stats-mainnet/src/react-app-env.d.ts new file mode 100644 index 000000000..6431bc5fc --- /dev/null +++ b/apps/stats-mainnet/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/stats-mainnet/src/reportWebVitals.ts b/apps/stats-mainnet/src/reportWebVitals.ts new file mode 100644 index 000000000..49a2a16e0 --- /dev/null +++ b/apps/stats-mainnet/src/reportWebVitals.ts @@ -0,0 +1,15 @@ +import { ReportHandler } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: ReportHandler) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/apps/stats-mainnet/src/setupTests.ts b/apps/stats-mainnet/src/setupTests.ts new file mode 100644 index 000000000..8f2609b7b --- /dev/null +++ b/apps/stats-mainnet/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/apps/stats-mainnet/src/styles/AlphaLyrae-Medium.woff b/apps/stats-mainnet/src/styles/AlphaLyrae-Medium.woff new file mode 100644 index 000000000..38b19bca5 Binary files /dev/null and b/apps/stats-mainnet/src/styles/AlphaLyrae-Medium.woff differ diff --git a/apps/stats-mainnet/src/styles/styles.css b/apps/stats-mainnet/src/styles/styles.css new file mode 100644 index 000000000..1ecaa334a --- /dev/null +++ b/apps/stats-mainnet/src/styles/styles.css @@ -0,0 +1,39 @@ +@tailwind base; +@tailwind components; + +@font-face { + font-family: 'AlphaLyrae-Medium'; + src: url('./AlphaLyrae-Medium.woff'); +} + +.layout-grid { + display: grid; + grid-template-columns: 1fr; + grid-template-rows: repeat(2, auto) 1fr; +} + +.stats-grid { + display: grid; +} + +@media (min-width: 768px) { + .stats-grid { + grid-template-columns: 18rem 1fr; + grid-column-gap: 1.25rem; + align-items: flex-start; + } +} + +@media (min-width: 640px) { + .promoted-stats { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 768px) { + .promoted-stats { + grid-template-columns: repeat(1, minmax(0, 1fr)); + } +} + +@tailwind utilities; diff --git a/apps/stats-mainnet/tailwind.config.js b/apps/stats-mainnet/tailwind.config.js new file mode 100644 index 000000000..739782864 --- /dev/null +++ b/apps/stats-mainnet/tailwind.config.js @@ -0,0 +1,12 @@ +const { join } = require('path'); +const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind'); +const theme = require('../../libs/tailwindcss-config/src/theme'); + +module.exports = { + content: [ + join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme, + plugins: [], +}; diff --git a/apps/stats-mainnet/tsconfig.app.json b/apps/stats-mainnet/tsconfig.app.json new file mode 100644 index 000000000..252904bb7 --- /dev/null +++ b/apps/stats-mainnet/tsconfig.app.json @@ -0,0 +1,22 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/stats-mainnet/tsconfig.json b/apps/stats-mainnet/tsconfig.json new file mode 100644 index 000000000..9657042e4 --- /dev/null +++ b/apps/stats-mainnet/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/apps/stats-mainnet/tsconfig.spec.json b/apps/stats-mainnet/tsconfig.spec.json new file mode 100644 index 000000000..95ef66a08 --- /dev/null +++ b/apps/stats-mainnet/tsconfig.spec.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "**/*.test.ts", + "**/*.spec.ts", + "**/*.test.tsx", + "**/*.spec.tsx", + "**/*.test.js", + "**/*.spec.js", + "**/*.test.jsx", + "**/*.spec.jsx", + "**/*.d.ts" + ], + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ] +} diff --git a/libs/mainnet-stats-manager/.babelrc b/libs/mainnet-stats-manager/.babelrc new file mode 100644 index 000000000..ccae900be --- /dev/null +++ b/libs/mainnet-stats-manager/.babelrc @@ -0,0 +1,12 @@ +{ + "presets": [ + [ + "@nrwl/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [] +} diff --git a/libs/mainnet-stats-manager/.eslintrc.json b/libs/mainnet-stats-manager/.eslintrc.json new file mode 100644 index 000000000..734ddacee --- /dev/null +++ b/libs/mainnet-stats-manager/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/mainnet-stats-manager/README.md b/libs/mainnet-stats-manager/README.md new file mode 100644 index 000000000..160242035 --- /dev/null +++ b/libs/mainnet-stats-manager/README.md @@ -0,0 +1,7 @@ +# mainnet-stats-manager + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test mainnet-stats-manager` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/mainnet-stats-manager/jest.config.js b/libs/mainnet-stats-manager/jest.config.js new file mode 100644 index 000000000..de9ee9926 --- /dev/null +++ b/libs/mainnet-stats-manager/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + displayName: 'mainnet-stats-manager', + preset: '../../jest.preset.js', + transform: { + '^.+\\.[tj]sx?$': 'babel-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/libs/mainnet-stats-manager', +}; diff --git a/libs/mainnet-stats-manager/package.json b/libs/mainnet-stats-manager/package.json new file mode 100644 index 000000000..6eed0f1da --- /dev/null +++ b/libs/mainnet-stats-manager/package.json @@ -0,0 +1,4 @@ +{ + "name": "@vegaprotocol/mainnet-stats-manager", + "version": "0.0.1" +} diff --git a/libs/mainnet-stats-manager/project.json b/libs/mainnet-stats-manager/project.json new file mode 100644 index 000000000..2b9cb03a1 --- /dev/null +++ b/libs/mainnet-stats-manager/project.json @@ -0,0 +1,43 @@ +{ + "root": "libs/mainnet-stats-manager", + "sourceRoot": "libs/mainnet-stats-manager/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nrwl/web:rollup", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/mainnet-stats-manager", + "tsConfig": "libs/mainnet-stats-manager/tsconfig.lib.json", + "project": "libs/mainnet-stats-manager/package.json", + "entryFile": "libs/mainnet-stats-manager/src/index.ts", + "external": ["react/jsx-runtime"], + "rollupConfig": "@nrwl/react/plugins/bundle-rollup", + "compiler": "babel", + "assets": [ + { + "glob": "libs/mainnet-stats-manager/README.md", + "input": ".", + "output": "." + } + ] + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/mainnet-stats-manager/**/*.{ts,tsx,js,jsx}"] + } + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["coverage/libs/mainnet-stats-manager"], + "options": { + "jestConfig": "libs/mainnet-stats-manager/jest.config.js", + "passWithNoTests": true + } + } + } +} diff --git a/libs/mainnet-stats-manager/src/components/good-threshold-indicator/good-threshold-indicator.tsx b/libs/mainnet-stats-manager/src/components/good-threshold-indicator/good-threshold-indicator.tsx new file mode 100644 index 000000000..4844e7955 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/good-threshold-indicator/good-threshold-indicator.tsx @@ -0,0 +1,21 @@ +import { value, goodThreshold } from '../../config/types'; + +interface GoodThresholdIndicatorProps { + goodThreshold: goodThreshold | undefined; + value: value; +} + +export const GoodThresholdIndicator = ({ + goodThreshold, + value, +}: GoodThresholdIndicatorProps) => { + return ( + + ); +}; diff --git a/libs/mainnet-stats-manager/src/components/good-threshold-indicator/index.ts b/libs/mainnet-stats-manager/src/components/good-threshold-indicator/index.ts new file mode 100644 index 000000000..6ffd483b7 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/good-threshold-indicator/index.ts @@ -0,0 +1 @@ +export { GoodThresholdIndicator } from './good-threshold-indicator'; diff --git a/libs/mainnet-stats-manager/src/components/promoted-stats-item/index.ts b/libs/mainnet-stats-manager/src/components/promoted-stats-item/index.ts new file mode 100644 index 000000000..fe769eb91 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/promoted-stats-item/index.ts @@ -0,0 +1 @@ +export { PromotedStatsItem } from './promoted-stats-item'; diff --git a/libs/mainnet-stats-manager/src/components/promoted-stats-item/promoted-stats-item.tsx b/libs/mainnet-stats-manager/src/components/promoted-stats-item/promoted-stats-item.tsx new file mode 100644 index 000000000..0b6f9e4f5 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/promoted-stats-item/promoted-stats-item.tsx @@ -0,0 +1,26 @@ +import { Tooltip } from '../tooltip'; +import { StatFields } from '../../config/types'; +import { defaultFieldFormatter } from '../table-row'; +import { GoodThresholdIndicator } from '../good-threshold-indicator'; + +export const PromotedStatsItem = ({ + title, + formatter, + goodThreshold, + value, + description, +}: StatFields) => { + return ( + + + + + {title} + + + {formatter ? formatter(value) : defaultFieldFormatter(value)} + + + + ); +}; diff --git a/libs/mainnet-stats-manager/src/components/promoted-stats/index.ts b/libs/mainnet-stats-manager/src/components/promoted-stats/index.ts new file mode 100644 index 000000000..799945377 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/promoted-stats/index.ts @@ -0,0 +1 @@ +export { PromotedStats } from './promoted-stats'; diff --git a/libs/mainnet-stats-manager/src/components/promoted-stats/promoted-stats.tsx b/libs/mainnet-stats-manager/src/components/promoted-stats/promoted-stats.tsx new file mode 100644 index 000000000..5cda047d5 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/promoted-stats/promoted-stats.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +interface PromotedStatsProps { + children: React.ReactNode; +} + +export const PromotedStats = ({ children }: PromotedStatsProps) => { + return ( + + {children} + + ); +}; diff --git a/libs/mainnet-stats-manager/src/components/stats-manager/index.ts b/libs/mainnet-stats-manager/src/components/stats-manager/index.ts new file mode 100644 index 000000000..2c4a65880 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/stats-manager/index.ts @@ -0,0 +1 @@ +export { StatsManager } from './stats-manager'; diff --git a/libs/mainnet-stats-manager/src/components/stats-manager/stats-manager.tsx b/libs/mainnet-stats-manager/src/components/stats-manager/stats-manager.tsx new file mode 100644 index 000000000..8f01bbae2 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/stats-manager/stats-manager.tsx @@ -0,0 +1,120 @@ +import { useEffect, useState } from 'react'; +import classnames from 'classnames'; +import { statsFields } from '../../config/stats-fields'; +import { + Stats as IStats, + StructuredStats as IStructuredStats, +} from '../../config/types'; +import { Table } from '../table'; +import { TableRow } from '../table-row'; +import { PromotedStats } from '../promoted-stats'; +import { PromotedStatsItem } from '../promoted-stats-item'; + +interface statsManagerProps { + className?: string; +} + +export const StatsManager = ({ className }: statsManagerProps) => { + const [data, setData] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + async function getStats() { + try { + const [res1, res2] = await Promise.all([ + fetch('https://api.token.vega.xyz/statistics'), + fetch('https://api.token.vega.xyz/nodes-data'), + ]); + const [{ statistics }, { nodeData }] = await Promise.all([ + res1.json(), + res2.json(), + ]); + const returned = { ...nodeData, ...statistics }; + + if (!statistics || !nodeData) { + throw new Error('Failed to get data from endpoints'); + } + + // Loop through the stats fields config, grabbing values from the fetched + // data and building a set of promoted and standard table entries. + const structured = Object.entries(statsFields).reduce( + (acc, [key, value]) => { + const statKey = key as keyof IStats; + const statData = returned[statKey]; + + value.forEach((x) => { + const stat = { + ...x, + value: statData, + }; + + stat.promoted ? acc.promoted.push(stat) : acc.table.push(stat); + }); + + return acc; + }, + { promoted: [], table: [] } as IStructuredStats + ); + + setData(structured); + setError(null); + } catch (e) { + setData(null); + setError(e as Error); + } + } + + const interval = setInterval(getStats, 1000); + + return () => { + clearInterval(interval); + }; + }, []); + + const classes = classnames( + className, + 'stats-grid w-full self-start justify-self-center' + ); + + return ( + + + {(error && `/ ${error}`) || (data ? '/ Mainnet' : '/ Connecting...')} + + + {data?.promoted ? ( + + {data.promoted.map((stat, i) => { + return ( + + ); + })} + + ) : null} + + + {data?.table + ? data.table.map((stat, i) => { + return ( + + ); + }) + : null} + + + ); +}; diff --git a/libs/mainnet-stats-manager/src/components/table-row/index.ts b/libs/mainnet-stats-manager/src/components/table-row/index.ts new file mode 100644 index 000000000..665eaf966 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/table-row/index.ts @@ -0,0 +1 @@ +export { TableRow, defaultFieldFormatter } from './table-row'; diff --git a/libs/mainnet-stats-manager/src/components/table-row/table-row.tsx b/libs/mainnet-stats-manager/src/components/table-row/table-row.tsx new file mode 100644 index 000000000..4a6403ab5 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/table-row/table-row.tsx @@ -0,0 +1,28 @@ +import { Tooltip } from '../tooltip'; +import { StatFields } from '../../config/types'; +import { GoodThresholdIndicator } from '../good-threshold-indicator'; + +export const defaultFieldFormatter = (field: unknown) => + field === undefined ? 'no data' : field; + +export const TableRow = ({ + title, + formatter, + goodThreshold, + value, + description, +}: StatFields) => { + return ( + + + {title} + + {formatter ? formatter(value) : defaultFieldFormatter(value)} + + + + + + + ); +}; diff --git a/libs/mainnet-stats-manager/src/components/table/index.ts b/libs/mainnet-stats-manager/src/components/table/index.ts new file mode 100644 index 000000000..48232283c --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/table/index.ts @@ -0,0 +1 @@ +export { Table } from './table'; diff --git a/libs/mainnet-stats-manager/src/components/table/table.tsx b/libs/mainnet-stats-manager/src/components/table/table.tsx new file mode 100644 index 000000000..cf535f6df --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/table/table.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +interface TableProps { + children: React.ReactNode; +} + +export const Table = ({ children }: TableProps) => { + return ( + + {children} + + ); +}; diff --git a/libs/mainnet-stats-manager/src/components/tooltip/index.ts b/libs/mainnet-stats-manager/src/components/tooltip/index.ts new file mode 100644 index 000000000..c20c22cb1 --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/tooltip/index.ts @@ -0,0 +1 @@ +export { Tooltip } from './tooltip'; diff --git a/libs/mainnet-stats-manager/src/components/tooltip/tooltip.tsx b/libs/mainnet-stats-manager/src/components/tooltip/tooltip.tsx new file mode 100644 index 000000000..0fdfac4ce --- /dev/null +++ b/libs/mainnet-stats-manager/src/components/tooltip/tooltip.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { + Provider, + Root, + Trigger, + Content, + Arrow, +} from '@radix-ui/react-tooltip'; + +interface TooltipProps { + children: React.ReactElement; + description?: string; +} + +// Conditionally rendered tooltip if description content is provided. +export const Tooltip = ({ children, description }: TooltipProps) => + description ? ( + + + {children} + + + + {description} + + + + + ) : ( + children + ); diff --git a/libs/mainnet-stats-manager/src/config/stats-fields.ts b/libs/mainnet-stats-manager/src/config/stats-fields.ts new file mode 100644 index 000000000..c779c1c39 --- /dev/null +++ b/libs/mainnet-stats-manager/src/config/stats-fields.ts @@ -0,0 +1,174 @@ +import { Stats as IStats, StatFields as IStatFields } from './types'; + +// Stats fields config. Keys will correspond to graphql queries when used, and values +// contain the associated data and methods we need to render. A single query +// can be rendered in multiple ways (see 'upTime'). +export const statsFields: { [key in keyof IStats]: IStatFields[] } = { + status: [ + { + title: 'Status', + formatter: (status: string) => { + if (!status) { + return; + } + + const i = status.lastIndexOf('_'); + if (i === -1) { + return status; + } else { + return status.substr(i + 1); + } + }, + goodThreshold: (status: string) => + status === 'CONNECTED' || status === 'CHAIN_STATUS_CONNECTED', + promoted: true, + description: + 'Status is either connected, replaying, unspecified or disconnected', + }, + ], + blockHeight: [ + { + title: 'Height', + goodThreshold: (height: number) => height >= 60, + promoted: true, + description: 'Block height', + }, + ], + totalNodes: [ + { + title: 'Total nodes', + description: 'The total number of nodes registered on the network', + }, + ], + validatingNodes: [ + { + title: 'Validating nodes', + promoted: true, + description: 'Nodes participating in consensus', + }, + ], + inactiveNodes: [ + { + title: 'Inactive nodes', + goodThreshold: (totalInactive: number) => totalInactive < 1, + description: 'Nodes that are registered but not validating', + }, + ], + stakedTotal: [ + { + title: 'Total staked', + formatter: (total: string) => + total.length > 18 && + parseInt(total.substring(0, total.length - 18)).toLocaleString('en-US'), + description: 'Sum of VEGA associated with a Vega key', + }, + ], + backlogLength: [ + { + title: 'Backlog', + goodThreshold: (length: number, blockDuration: number) => { + return ( + length < 1000 || (length >= 1000 && blockDuration / 1000000000 <= 1) + ); + }, + description: 'Number of transactions waiting to be processed', + }, + ], + tradesPerSecond: [ + { + title: 'Trades / second', + goodThreshold: (trades: number) => trades >= 2, + description: 'Number of trades processed in the last second', + }, + ], + averageOrdersPerBlock: [ + { + title: 'Orders / block', + goodThreshold: (orders: number) => orders >= 2, + description: + 'Number of new orders processed in the last block. All pegged orders and liquidity provisions count as a single order', + }, + ], + ordersPerSecond: [ + { + title: 'Orders / second', + goodThreshold: (orders: number) => orders >= 2, + description: + 'Number of orders processed in the last second. All pegged orders and liquidity provisions count as a single order', + }, + ], + txPerBlock: [ + { + title: 'Transactions / block', + goodThreshold: (tx: number) => tx > 2, + description: 'Number of transactions processed in the last block', + }, + ], + blockDuration: [ + { + title: 'Block time', + formatter: (duration: number) => (duration / 1000000000).toFixed(3), + goodThreshold: (blockDuration: number) => + blockDuration > 0 && blockDuration <= 2000000000, + description: 'Seconds between the two most recent blocks', + }, + ], + vegaTime: [ + { + title: 'Time', + formatter: (time: Date) => new Date(time).toLocaleTimeString(), + goodThreshold: (time: Date) => { + const diff = new Date().getTime() - new Date(time).getTime(); + return diff > 0 && diff < 5000; + }, + description: 'The time on the blockchain', + }, + ], + appVersion: [ + { + title: 'App', + description: 'Vega node software version on this node', + }, + ], + chainVersion: [ + { + title: 'Tendermint', + description: 'Tendermint software version on this node', + }, + ], + uptime: [ + { + title: 'Uptime', + formatter: (t: string) => { + if (!t) { + return; + } + const secSinceStart = + (new Date().getTime() - new Date(t).getTime()) / 1000; + const days = Math.floor(secSinceStart / 60 / 60 / 24); + const hours = Math.floor((secSinceStart / 60 / 60) % 24); + const mins = Math.floor((secSinceStart / 60) % 60); + const secs = Math.floor(secSinceStart % 60); + return `${days}d ${hours}h ${mins}m ${secs}s`; + }, + promoted: true, + description: 'Time since genesis', + }, + { + title: 'Up since', + formatter: (t: string) => { + if (!t) { + return; + } + return `${new Date(t).toLocaleString().replace(',', ' ')}`; + }, + description: 'Genesis', + }, + ], + chainId: [ + { + title: 'Chain ID', + description: 'Identifier', + }, + ], +}; diff --git a/libs/mainnet-stats-manager/src/config/types.ts b/libs/mainnet-stats-manager/src/config/types.ts new file mode 100644 index 000000000..9a81b709e --- /dev/null +++ b/libs/mainnet-stats-manager/src/config/types.ts @@ -0,0 +1,36 @@ +export interface Stats { + blockHeight: string; + totalNodes: string; + validatingNodes: string; + inactiveNodes: string; + stakedTotal: string; + backlogLength: string; + tradesPerSecond: string; + averageOrdersPerBlock: string; + ordersPerSecond: string; + txPerBlock: string; + blockDuration: string; + status: string; + vegaTime: string; + appVersion: string; + chainVersion: string; + uptime: string; + chainId: string; +} + +export type value = any; +export type goodThreshold = (...args: value[]) => boolean; + +export interface StatFields { + title: string; + goodThreshold?: goodThreshold; + formatter?: (arg0: value) => any; + promoted?: boolean; + value?: value; + description?: string; +} + +export interface StructuredStats { + promoted: StatFields[]; + table: StatFields[]; +} diff --git a/libs/mainnet-stats-manager/src/index.ts b/libs/mainnet-stats-manager/src/index.ts new file mode 100644 index 000000000..02aeacf30 --- /dev/null +++ b/libs/mainnet-stats-manager/src/index.ts @@ -0,0 +1 @@ +export { StatsManager } from './components/stats-manager'; diff --git a/libs/mainnet-stats-manager/tsconfig.json b/libs/mainnet-stats-manager/tsconfig.json new file mode 100644 index 000000000..4c089585e --- /dev/null +++ b/libs/mainnet-stats-manager/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/mainnet-stats-manager/tsconfig.lib.json b/libs/mainnet-stats-manager/tsconfig.lib.json new file mode 100644 index 000000000..252904bb7 --- /dev/null +++ b/libs/mainnet-stats-manager/tsconfig.lib.json @@ -0,0 +1,22 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/libs/mainnet-stats-manager/tsconfig.spec.json b/libs/mainnet-stats-manager/tsconfig.spec.json new file mode 100644 index 000000000..67f149c4c --- /dev/null +++ b/libs/mainnet-stats-manager/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "**/*.test.ts", + "**/*.spec.ts", + "**/*.test.tsx", + "**/*.spec.tsx", + "**/*.test.js", + "**/*.spec.js", + "**/*.test.jsx", + "**/*.spec.jsx", + "**/*.d.ts" + ] +} diff --git a/libs/tailwindcss-config/src/theme.js b/libs/tailwindcss-config/src/theme.js index 2602a06f8..83aec4bf8 100644 --- a/libs/tailwindcss-config/src/theme.js +++ b/libs/tailwindcss-config/src/theme.js @@ -2,7 +2,9 @@ const defaultTheme = require('tailwindcss/defaultTheme'); module.exports = { screens: { - sm: '500px', + xs: '500px', + sm: '640px', + md: '768px', lg: '960px', }, colors: { @@ -63,7 +65,9 @@ module.exports = { 24: '1.5rem', 28: '1.75rem', 32: '2rem', + 40: '2.5rem', 44: '2.75rem', + 64: '4rem', }, opacity: { 0: '0', diff --git a/libs/ui-toolkit/src/components/vega-logo/index.ts b/libs/ui-toolkit/src/components/vega-logo/index.ts new file mode 100644 index 000000000..f34ea89ea --- /dev/null +++ b/libs/ui-toolkit/src/components/vega-logo/index.ts @@ -0,0 +1 @@ +export * from './vega-logo'; diff --git a/libs/ui-toolkit/src/components/vega-logo/lozenge.stories.tsx b/libs/ui-toolkit/src/components/vega-logo/lozenge.stories.tsx new file mode 100644 index 000000000..4e03ab8ca --- /dev/null +++ b/libs/ui-toolkit/src/components/vega-logo/lozenge.stories.tsx @@ -0,0 +1,11 @@ +import { Story, Meta } from '@storybook/react'; +import { VegaLogo } from './vega-logo'; + +export default { + component: VegaLogo, + title: 'Vega logo', +} as Meta; + +const Template: Story = () => ; + +export const Default = Template.bind({}); diff --git a/libs/ui-toolkit/src/components/vega-logo/vega-logo.spec.tsx b/libs/ui-toolkit/src/components/vega-logo/vega-logo.spec.tsx new file mode 100644 index 000000000..d13fcf2d3 --- /dev/null +++ b/libs/ui-toolkit/src/components/vega-logo/vega-logo.spec.tsx @@ -0,0 +1,10 @@ +import { render } from '@testing-library/react'; + +import { VegaLogo } from './vega-logo'; + +describe('Vega logo', () => { + it('should render successfully', () => { + const { baseElement } = render(); + expect(baseElement).toBeTruthy(); + }); +}); diff --git a/libs/ui-toolkit/src/components/vega-logo/vega-logo.tsx b/libs/ui-toolkit/src/components/vega-logo/vega-logo.tsx new file mode 100644 index 000000000..4545b46b8 --- /dev/null +++ b/libs/ui-toolkit/src/components/vega-logo/vega-logo.tsx @@ -0,0 +1,16 @@ +export const VegaLogo = () => { + return ( + + + + ); +}; diff --git a/libs/ui-toolkit/src/index.ts b/libs/ui-toolkit/src/index.ts index 638072c6b..27bb0a3a1 100644 --- a/libs/ui-toolkit/src/index.ts +++ b/libs/ui-toolkit/src/index.ts @@ -17,6 +17,7 @@ export { Splash } from './components/splash'; export { TextArea } from './components/text-area'; export { ThemeSwitcher } from './components/theme-switcher'; export { Dialog } from './components/dialog/dialog'; +export { VegaLogo } from './components/vega-logo'; // Utils export * from './utils/intent'; diff --git a/package.json b/package.json index 818aab10e..a93420ffd 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@nrwl/next": "13.8.1", "@radix-ui/react-dialog": "^0.1.5", "@radix-ui/react-tabs": "^0.1.5", + "@radix-ui/react-tooltip": "^0.1.7", "@sentry/react": "^6.18.1", "@sentry/tracing": "^6.18.1", "@types/uuid": "^8.3.4", @@ -51,7 +52,8 @@ "sha3": "^2.1.4", "tailwindcss": "^3.0.23", "tslib": "^2.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "web-vitals": "^2.1.4" }, "devDependencies": { "@babel/core": "7.12.13", diff --git a/tsconfig.base.json b/tsconfig.base.json index 40946e97c..3315e4bb9 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -17,6 +17,9 @@ "paths": { "@vegaprotocol/deal-ticket": ["libs/deal-ticket/src/index.ts"], "@vegaprotocol/graphql": ["libs/graphql/src/index.ts"], + "@vegaprotocol/mainnet-stats-manager": [ + "libs/mainnet-stats-manager/src/index.ts" + ], "@vegaprotocol/market-list": ["libs/market-list/src/index.ts"], "@vegaprotocol/react-helpers": ["libs/react-helpers/src/index.ts"], "@vegaprotocol/tailwindcss-config": [ diff --git a/workspace.json b/workspace.json index c9dcf01bb..4d72aaf7a 100644 --- a/workspace.json +++ b/workspace.json @@ -5,8 +5,11 @@ "explorer": "apps/explorer", "explorer-e2e": "apps/explorer-e2e", "graphql": "libs/graphql", + "mainnet-stats-manager": "libs/mainnet-stats-manager", "market-list": "libs/market-list", "react-helpers": "libs/react-helpers", + "stats-mainnet": "apps/stats-mainnet", + "stats-mainnet-e2e": "apps/stats-mainnet-e2e", "tailwindcss-config": "libs/tailwindcss-config", "trading": "apps/trading", "trading-e2e": "apps/trading-e2e", diff --git a/yarn.lock b/yarn.lock index b18e6114d..9ed729bc2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3199,6 +3199,14 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9" integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA== +"@radix-ui/popper@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/popper/-/popper-0.1.0.tgz#c387a38f31b7799e1ea0d2bb1ca0c91c2931b063" + integrity sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ== + dependencies: + "@babel/runtime" "^7.13.10" + csstype "^3.0.4" + "@radix-ui/primitive@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-0.1.0.tgz#6206b97d379994f0d1929809db035733b337e543" @@ -3206,6 +3214,14 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-arrow@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz#a871448a418cd3507d83840fdd47558cb961672b" + integrity sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-collection@0.1.4": version "0.1.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-0.1.4.tgz#734061ffd5bb93e88889d49b87391a73a63824c9" @@ -3290,6 +3306,21 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-layout-effect" "0.1.0" +"@radix-ui/react-popper@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.1.4.tgz#dfc055dcd7dfae6a2eff7a70d333141d15a5d029" + integrity sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/popper" "0.1.0" + "@radix-ui/react-arrow" "0.1.4" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-rect" "0.1.1" + "@radix-ui/react-use-size" "0.1.1" + "@radix-ui/rect" "0.1.1" + "@radix-ui/react-portal@0.1.4": version "0.1.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.4.tgz#17bdce3d7f1a9a0b35cb5e935ab8bc562441a7d2" @@ -3352,6 +3383,27 @@ "@radix-ui/react-roving-focus" "0.1.5" "@radix-ui/react-use-controllable-state" "0.1.0" +"@radix-ui/react-tooltip@^0.1.7": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-0.1.7.tgz#6f8c00d6e489565d14abf209ce0fb8853c8c8ee3" + integrity sha512-eiBUsVOHenZ0JR16tl970bB0DafJBz6mFgSGfIGIVpflFj0LIsIDiLMsYyvYdx1KwwsIUDTEZtxcPm/sWjPzqA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-popper" "0.1.4" + "@radix-ui/react-portal" "0.1.4" + "@radix-ui/react-presence" "0.1.2" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-slot" "0.1.2" + "@radix-ui/react-use-controllable-state" "0.1.0" + "@radix-ui/react-use-escape-keydown" "0.1.0" + "@radix-ui/react-use-previous" "0.1.1" + "@radix-ui/react-use-rect" "0.1.1" + "@radix-ui/react-visually-hidden" "0.1.4" + "@radix-ui/react-use-body-pointer-events@0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz#63e7fd81ca7ffd30841deb584cd2b7f460df2597" @@ -3390,6 +3442,43 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-use-previous@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-0.1.1.tgz#0226017f72267200f6e832a7103760e96a6db5d0" + integrity sha512-O/ZgrDBr11dR8rhO59ED8s5zIXBRFi8MiS+CmFGfi7MJYdLbfqVOmQU90Ghf87aifEgWe6380LA69KBneaShAg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-rect@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-0.1.1.tgz#6c15384beee59c086e75b89a7e66f3d2e583a856" + integrity sha512-kHNNXAsP3/PeszEmM/nxBBS9Jbo93sO+xuMTcRfwzXsmxT5gDXQzAiKbZQ0EecCPtJIzqvr7dlaQi/aP1PKYqQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/rect" "0.1.1" + +"@radix-ui/react-use-size@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz#f6b75272a5d41c3089ca78c8a2e48e5f204ef90f" + integrity sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-visually-hidden@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-0.1.4.tgz#6c75eae34fb5d084b503506fbfc05587ced05f03" + integrity sha512-K/q6AEEzqeeEq/T0NPChvBqnwlp8Tl4NnQdrI/y8IOY7BRR+Ug0PEsVk6g48HJ7cA1//COugdxXXVVK/m0X1mA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "0.1.4" + +"@radix-ui/rect@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-0.1.1.tgz#95b5ba51f469bea6b1b841e2d427e17e37d38419" + integrity sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw== + dependencies: + "@babel/runtime" "^7.13.10" + "@rollup/plugin-babel@^5.3.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" @@ -8961,7 +9050,7 @@ csstype@^2.5.7: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.20.tgz#9229c65ea0b260cf4d3d997cb06288e36a8d6dda" integrity sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA== -csstype@^3.0.2: +csstype@^3.0.2, csstype@^3.0.4: version "3.0.11" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== @@ -19675,6 +19764,11 @@ web-namespaces@^1.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== +web-vitals@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-2.1.4.tgz#76563175a475a5e835264d373704f9dde718290c" + integrity sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"