Skip to content

Commit df4ca25

Browse files
committed
init
0 parents  commit df4ca25

28 files changed

+668
-0
lines changed

Diff for: README.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# React + TypeScript + Vite
2+
3+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4+
5+
Currently, two official plugins are available:
6+
7+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9+
10+
## Expanding the ESLint configuration
11+
12+
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
13+
14+
- Configure the top-level `parserOptions` property like this:
15+
16+
```js
17+
export default tseslint.config({
18+
languageOptions: {
19+
// other options...
20+
parserOptions: {
21+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
22+
tsconfigRootDir: import.meta.dirname,
23+
},
24+
},
25+
})
26+
```
27+
28+
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
29+
- Optionally add `...tseslint.configs.stylisticTypeChecked`
30+
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
31+
32+
```js
33+
// eslint.config.js
34+
import react from 'eslint-plugin-react'
35+
36+
export default tseslint.config({
37+
// Set the react version
38+
settings: { react: { version: '18.3' } },
39+
plugins: {
40+
// Add the react plugin
41+
react,
42+
},
43+
rules: {
44+
// other rules...
45+
// Enable its recommended rules
46+
...react.configs.recommended.rules,
47+
...react.configs['jsx-runtime'].rules,
48+
},
49+
})
50+
```

Diff for: eslint.config.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
7+
export default tseslint.config(
8+
{ ignores: ['dist'] },
9+
{
10+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11+
files: ['**/*.{ts,tsx}'],
12+
languageOptions: {
13+
ecmaVersion: 2020,
14+
globals: globals.browser,
15+
},
16+
plugins: {
17+
'react-hooks': reactHooks,
18+
'react-refresh': reactRefresh,
19+
},
20+
rules: {
21+
...reactHooks.configs.recommended.rules,
22+
'react-refresh/only-export-components': [
23+
'warn',
24+
{ allowConstantExport: true },
25+
],
26+
},
27+
},
28+
)

Diff for: index.html

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite + React + TS</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>

Diff for: package.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "polkadotwtf",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"nats.ws": "^1.10.0",
14+
"react": "^18.3.1",
15+
"react-dom": "^18.3.1"
16+
},
17+
"devDependencies": {
18+
"@eslint/js": "^9.11.1",
19+
"@types/react": "^18.3.10",
20+
"@types/react-dom": "^18.3.0",
21+
"@vitejs/plugin-react": "^4.3.2",
22+
"eslint": "^9.11.1",
23+
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
24+
"eslint-plugin-react-refresh": "^0.4.12",
25+
"globals": "^15.9.0",
26+
"typescript": "^5.5.3",
27+
"typescript-eslint": "^8.7.0",
28+
"vite": "^5.4.8"
29+
}
30+
}

Diff for: src/App.css

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#root {
2+
max-width: 1280px;
3+
margin: 0 auto;
4+
padding: 2rem;
5+
text-align: center;
6+
}
7+
8+
.logo {
9+
height: 6em;
10+
padding: 1.5em;
11+
will-change: filter;
12+
transition: filter 300ms;
13+
}
14+
.logo:hover {
15+
filter: drop-shadow(0 0 2em #646cffaa);
16+
}
17+
.logo.react:hover {
18+
filter: drop-shadow(0 0 2em #61dafbaa);
19+
}
20+
21+
@keyframes logo-spin {
22+
from {
23+
transform: rotate(0deg);
24+
}
25+
to {
26+
transform: rotate(360deg);
27+
}
28+
}
29+
30+
@media (prefers-reduced-motion: no-preference) {
31+
a:nth-of-type(2) .logo {
32+
animation: logo-spin infinite 20s linear;
33+
}
34+
}
35+
36+
.card {
37+
padding: 2em;
38+
}
39+
40+
.read-the-docs {
41+
color: #888;
42+
}

Diff for: src/App.tsx

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { useEffect, useState } from 'react';
2+
import { connect, StringCodec } from 'https://cdn.jsdelivr.net/npm/[email protected]/esm/nats.js';
3+
import './contentstyle.css'; // main content styles
4+
5+
type ChainMetrics = {
6+
tps: number;
7+
block: number;
8+
weight: number;
9+
kbps: number;
10+
};
11+
12+
type ChainName = 'Westend' | 'Polkadot' | 'Kusama' | 'Paseo';
13+
14+
const chains: ChainName[] = ['Westend', 'Polkadot', 'Kusama', 'Paseo'];
15+
16+
const App = () => {
17+
const [tpsData, setTpsData] = useState<Record<ChainName, ChainMetrics>>({
18+
Westend: { tps: 0, block: 0, weight: 0, kbps: 0 },
19+
Polkadot: { tps: 0, block: 0, weight: 0, kbps: 0 },
20+
Kusama: { tps: 0, block: 0, weight: 0, kbps: 0 },
21+
Paseo: { tps: 0, block: 0, weight: 0, kbps: 0 },
22+
});
23+
24+
const sc = new StringCodec();
25+
26+
useEffect(() => {
27+
const tpsTracker: Record<ChainName, { count: number; lastUpdated: number }> = {
28+
Westend: { count: 0, lastUpdated: Date.now() },
29+
Polkadot: { count: 0, lastUpdated: Date.now() },
30+
Kusama: { count: 0, lastUpdated: Date.now() },
31+
Paseo: { count: 0, lastUpdated: Date.now() },
32+
};
33+
34+
const updateTPS = (chain: ChainName, extrinsicsCount: number) => {
35+
const now = Date.now();
36+
const chainStats = tpsTracker[chain];
37+
38+
if (now - chainStats.lastUpdated >= 1000) {
39+
const tps = chainStats.count;
40+
const block = Math.floor(Math.random() * 100000); // mock block number
41+
const weight = Math.floor(Math.random() * 1000); // mock weight
42+
const kbps = Math.random() * 10; // mock kb/s
43+
44+
setTpsData((prevData) => ({
45+
...prevData,
46+
[chain]: { tps, block, weight, kbps },
47+
}));
48+
49+
chainStats.count = 0;
50+
chainStats.lastUpdated = now;
51+
}
52+
53+
chainStats.count += extrinsicsCount;
54+
};
55+
56+
const handleMessageForTPS = (msg: any) => {
57+
const blockData = sc.decode(msg.data);
58+
const parsedData = JSON.parse(blockData);
59+
const chain = msg.subject.split('.')[0] as ChainName;
60+
const extrinsicsCount = parsedData.extrinsics.length;
61+
62+
updateTPS(chain, extrinsicsCount);
63+
};
64+
65+
const setupNatsConnection = async () => {
66+
const nc = await connect({ servers: ['wss://dev.dotsentry.xyz/ws'] });
67+
68+
const subscriptions = await Promise.all(
69+
chains.map((chain) =>
70+
nc.subscribe(`${chain}.*.*.*.Blocks.*.BlockContent`),
71+
)
72+
);
73+
74+
subscriptions.forEach(async (sub: any) => {
75+
for await (const msg of sub) handleMessageForTPS(msg);
76+
});
77+
};
78+
79+
setupNatsConnection();
80+
}, []);
81+
82+
return (
83+
<div className="app-container">
84+
{/* Title Bar */}
85+
<div className="titlebar">
86+
<div className="logo"></div>
87+
<div className="headerlinks">
88+
<a href="#">Home</a>
89+
</div>
90+
<div className="dropdown">
91+
<button className="dropdowntext">Polkadot</button>
92+
<div className="dropdowncontent">
93+
<a href="#">Learn</a>
94+
<a href="#">Build</a>
95+
</div>
96+
</div>
97+
<div className="socialshare">
98+
<div className="twitter"></div>
99+
</div>
100+
<div className="currentTime" id="currentTime"></div>
101+
</div>
102+
<div className="divider"></div>
103+
{/* Main Window */}
104+
<div className="container largecontainer">
105+
<div className="windowtitle">
106+
<div className="windowtitlename">polkadot.wtf - built by erin</div>
107+
</div>
108+
109+
{/* Content Area */}
110+
<div className="contentarea">
111+
<div className="textbox">
112+
<table className="chain-table">
113+
<thead>
114+
<tr>
115+
<th>Chain Name</th>
116+
<th>Block</th>
117+
<th>TPS</th>
118+
<th>Weight</th>
119+
<th>KB/s</th>
120+
</tr>
121+
</thead>
122+
<tbody>
123+
{chains.map((chain, index) => (
124+
<tr key={index}>
125+
<td>{chain}</td>
126+
<td>{tpsData[chain].block}</td>
127+
<td>{tpsData[chain].tps}</td>
128+
<td>{tpsData[chain].weight}</td>
129+
<td>{tpsData[chain].kbps.toFixed(2)}</td>
130+
</tr>
131+
))}
132+
{[...Array(5)].map((_, i) => (
133+
<tr key={`placeholder-${i}`}>
134+
<td>Future Chain {i + 1}</td>
135+
<td>--</td>
136+
<td>--</td>
137+
<td>--</td>
138+
<td>--</td>
139+
</tr>
140+
))}
141+
</tbody>
142+
</table>
143+
</div>
144+
</div>
145+
</div>
146+
147+
{/* Bottom Panel */}
148+
<div className="bottompanel"></div>
149+
</div>
150+
);
151+
};
152+
153+
export default App;

Diff for: src/assets/Chicago.woff

21.5 KB
Binary file not shown.

Diff for: src/assets/geneva.ttf

14.1 KB
Binary file not shown.

Diff for: src/assets/react.svg

+1
Loading

0 commit comments

Comments
 (0)