Skip to content

Commit 3da08d4

Browse files
authored
Merge pull request #5 from DOS/sync-upstream-v2.8.0-alpha.2
Sync upstream v2.8.0-alpha.2 (merge conflicts)
2 parents a2cf116 + 4a211cb commit 3da08d4

4,124 files changed

Lines changed: 51638 additions & 40678 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/AGENTS.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Frontend application for Blockscout
2+
3+
## Architecture
4+
5+
See `./rules/architecture.mdc`.
6+
7+
## Design System Rules
8+
9+
See `./rules/design-system.mdc`.
10+
11+
## Code Style & Quality
12+
13+
See `./rules/code-quality.mdc`.
14+
15+
## TypeScript Conventions
16+
17+
See `./rules/typescript.mdc`.
18+
19+
## Environment Variables
20+
21+
See `./rules/env-vars.mdc`.
22+
23+
## Testing
24+
25+
- Unit tests (`*.spec.ts` / `*.spec.tsx`): See `./rules/tests-unit.mdc`.
26+
- Visual component tests (`*.pw.tsx`): See `./rules/tests-visual.mdc`.

.agents/rules/architecture.mdc

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
description: Project overview, tech stack, directory layout, data flow, and ongoing client/ architecture migration
3+
globs:
4+
alwaysApply: true
5+
---
6+
# Project Architecture
7+
8+
## What this is
9+
10+
Blockscout frontend — a blockchain explorer UI. Distributed as a Docker image; configured entirely via environment variables at runtime (see `.agents/rules/env-vars.mdc`).
11+
12+
## Tech stack
13+
14+
| Layer | Technology |
15+
|---|---|
16+
| Framework | Next.js 16 — **Pages Router only** (not App Router) |
17+
| UI | React 19 |
18+
| Component library | Chakra UI v3 (see `.agents/rules/design-system.mdc`) |
19+
| Server state | React Query 5 |
20+
| Web3 | Wagmi 2 / Viem 2 |
21+
| Schema validation | Valibot |
22+
| Unit tests | Vitest |
23+
| Visual tests | Playwright |
24+
| Package manager | pnpm (Node >=22.14.0) |
25+
26+
## Domain terminology
27+
28+
Feature and product codenames used throughout the codebase are defined in `docs/GLOSSARY.md`. Consult it whenever you encounter an unfamiliar term — e.g. `tac`, `bens`, `cctx`, `kettle`, `epoch`, `blobs`.
29+
30+
## Directory layout
31+
32+
```
33+
pages/ Next.js file-based routes — thin wrappers only (dynamic import + getServerSideProps)
34+
ui/ Legacy React UI components organized by feature (~65 subdirectories) → being migrated to client/
35+
lib/ Legacy business logic, API utilities, custom hooks, context providers → being migrated to client/
36+
client/ New home for all product code (see Migration section below)
37+
toolkit/ Design system — Chakra wrappers, theme tokens, shared hooks/components (stays here permanently)
38+
configs/app/ Runtime app configuration; must not import from client/
39+
nextjs/ Next.js config utilities: headers, rewrites, redirects, type-safe routes
40+
mocks/ Shared mock data for tests → being co-located under client/ slices/features
41+
deploy/ Docker scripts, env validator, build tools
42+
docs/ ENVS.md, GLOSSARY.md, CONTRIBUTING.md
43+
```
44+
45+
## Data flow
46+
47+
- **Getting data:** pages fetch data via React Query. Query keys and fetcher functions live in `lib/api/` (moving to `client/api/`).
48+
- **Global UI state:** React Context providers initialized in `pages/_app.tsx` — `AppContextProvider`, `SettingsContextProvider`, `MarketplaceContextProvider`, etc.
49+
- **Real-time data:** WebSocket via `SocketProvider` (moving to `client/api/socket/`).
50+
- **App config:** always read via `configs/app/` (which reads `window.__envs` at runtime) — never `process.env.*` directly in component code.
51+
52+
---
53+
54+
## Ongoing migration: `client/` architecture
55+
56+
The codebase is being progressively restructured. The long-term target moves all product code from `ui/` and `lib/` into a new `client/` directory with a clear domain-based layout.
57+
58+
**Blueprint:** `client/ARCH_REDESIGN.md`
59+
**Task backlog and current status:** `client/MIGRATION_TASKS.md`
60+
61+
### Target layout inside `client/`
62+
63+
| Directory | Contents |
64+
|---|---|
65+
| `client/shell/` | App chrome: layout, header, footer, navigation, top-bar, root contexts |
66+
| `client/api/` | API transport, fetch utilities, query client, WebSocket; migrated from `lib/api/` and `lib/socket/` |
67+
| `client/slices/` | Core explorer entities always present on any EVM chain (tx, block, address, token, contract, search, …) |
68+
| `client/features/` | Optional / config-gated areas: rollups, chain variants, account, rewards, marketplace, stats, … |
69+
| `client/shared/` | Cross-cutting utilities with no single domain owner (analytics, errors, hooks, router helpers, text utils, …) |
70+
71+
### Slice vs feature
72+
73+
- **Slice** — present on every vanilla EVM chain, no feature flag required. Examples: `tx`, `block`, `address`, `token`, `contract`.
74+
- **Feature** — config-gated or chain-specific. Examples: `rollup/optimism`, `chain-variants/celo`, `account`, `stats`, `gas-tracker`.
75+
76+
### Key rules for migrated code
77+
78+
- **No barrel `index.ts` files** inside `client/` unless the file defines a genuine public facade (not just `export * from ...`).
79+
- **`client/api` must not have runtime imports** from `client/slices/*` or `client/features/*`; `import type` is allowed.
80+
- **`configs/` never imports `client/`.**
81+
- **`pages/` files are thin wrappers** — a dynamic import and optionally `getServerSideProps`; no UI components or business logic inline.
82+
- **Naming:** kebab-case for directories and non-component modules; `PascalCase.tsx` for React components; `useCamelCase.ts` for hooks.
83+
- **Types:** each slice/feature owns its API response types in `<slice|feature>/types/api.ts`. Do not import from deeper internal paths across domain boundaries.
84+
- **When editing legacy `lib/` or `ui/` code:** check `client/MIGRATION_TASKS.md` to see if that area has a migration task in progress or planned. If so, note the target destination in your PR description.

.agents/rules/code-quality.mdc

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
description: Code quality rules for the Blockscout frontend
3+
globs: *.tsx,*.ts
4+
alwaysApply: false
5+
---
6+
# Code Quality
7+
8+
We use ESLint, cSpell and Typescript to maintain code quality and consistency across the project.
9+
In order to check code quality run the following commands:
10+
```bash
11+
pnpm lint:eslint:fix
12+
pnpm lint:tsc
13+
pnpm lint:cspell
14+
```
15+
16+
Moreover, please find below the general sense rules that linters do not cover.
17+
18+
## Code Style and Structure
19+
20+
### General Principles
21+
22+
- Write concise, readable TypeScript code
23+
- Use functional and declarative programming patterns; avoid classes
24+
- Prefer iteration and modularization over code duplication
25+
- Implement early returns for better readability
26+
- Structure components logically: exports, subcomponents, helpers, types
27+
28+
### Naming Conventions
29+
30+
- Prefer descriptive names with auxiliary verbs (isLoading, hasError)
31+
- Prefix event handlers with "handle" (handleClick, handleSubmit)
32+
- Favor default exports for React components
33+
34+
Names should be specific and self-documenting. Vague names hide intent and make the codebase harder to navigate.
35+
36+
37+
```ts
38+
// BAD
39+
const useWidgets = () => { ... };
40+
41+
// GOOD
42+
const useAddress3rdPartyWidgets = () => { ... };
43+
```
44+
45+
This applies to hooks, components, functions, and variables alike..
46+
47+
## Specific rules
48+
49+
### Magic numbers
50+
51+
Extract magic numbers into named `UPPER_SNAKE_CASE` constants, placed above the component or function that uses them. This makes intent clear and avoids silent duplication.
52+
53+
```ts
54+
// BAD
55+
const visibleItems = items.slice(0, 4);
56+
57+
// GOOD
58+
const MAX_VISIBLE_ITEMS = 4;
59+
const visibleItems = items.slice(0, MAX_VISIBLE_ITEMS);
60+
```
61+
62+
The same applies to magic strings used as discriminators, keys, or thresholds. In tests, unexplained magic values should also be extracted into named constants so their meaning is clear.
63+
64+
### Static empty defaults
65+
66+
Never define empty arrays or objects inline as default values — a new reference is created on every render, causing unnecessary re-renders or stale hook dependencies.
67+
68+
```ts
69+
// BAD
70+
const items = data ?? [];
71+
72+
// GOOD
73+
const EMPTY_ITEMS: Array<Item> = [];
74+
const items = data ?? EMPTY_ITEMS;
75+
```
76+
77+
Define the constant outside the component or hook.
78+
79+
### useMemo for derived arrays
80+
81+
Wrap `.filter()`, `.map()`, or `.reduce()` results in `useMemo` when the result is passed as a prop or used as a hook dependency. Without memoisation, a new array reference is produced on every render.
82+
83+
```ts
84+
// BAD
85+
const filtered = items.filter(isActive);
86+
return <List items={filtered} />;
87+
88+
// GOOD
89+
const filtered = useMemo(() => items.filter(isActive), [items]);
90+
return <List items={filtered} />;
91+
```
92+
93+
### eslint-disable comments
94+
95+
Every `eslint-disable` comment must include an explanation. Without one, the reason for the suppression is lost and the comment becomes a maintenance hazard.
96+
97+
```ts
98+
// BAD
99+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
100+
101+
// GOOD
102+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- API response shape is dynamic and validated at runtime
103+
```
104+
105+
### File path string interpolation
106+
107+
Prefer explicit file names over template literals in asset paths. Explicit names are easier to locate with search tools and eliminate accidental runtime errors.
108+
109+
```ts
110+
// BAD
111+
const src = `streak_${days}.png`;
112+
113+
// GOOD — map variants explicitly
114+
const STREAK_IMAGES: Record<number, string> = {
115+
30: 'streak_30.png',
116+
60: 'streak_60.png',
117+
};
118+
```
119+
120+
### Prefer es-toolkit utilities
121+
122+
Before writing custom utility logic (clamping, deep cloning, grouping, etc.), check whether `es-toolkit` already provides it. Prefer the library function over a manual implementation. Documentation: https://es-toolkit.dev/llms-full.txt
123+
124+
### Commented-out code
125+
126+
Remove commented-out code blocks. The git history preserves anything that might be needed later. TODOs are acceptable only when paired with a clear follow-up plan or issue reference.
127+
128+
### Links
129+
130+
- Use `toolkit/chakra/link` instead of `next/link`. Never import `Link` from `next/link` directly.
131+
- When links to **application pages** are constructed, verify that `nextjs-routes` or `nextjs/routes` utilities are used instead of string concatenation or template literals. The full list of application routes is available in `nextjs/nextjs-routes.d.ts`.
132+
133+
### Date and time
134+
135+
- Import `dayjs` only via `lib/date/dayjs.ts` — never directly from the `dayjs` package.
136+
- Render all dates and times through the shared `Time` or `TimeWithTooltip` components. Do not format timestamps inline.
137+
138+
### Strict comparison
139+
140+
Use strict equality (`===`, `!==`) only — never loose equality (`==`, `!=`). Strict operators avoid type coercion surprises and align with TypeScript expectations.
141+
142+
```ts
143+
// BAD
144+
if (count == 0) { ... }
145+
if (status != 'ok') { ... }
146+
147+
// GOOD
148+
if (count === 0) { ... }
149+
if (status !== 'ok') { ... }
150+
```
151+
152+
When you need to treat both `null` and `undefined` as missing, write `value === null || value === undefined` instead of `value == null`.

.agents/rules/design-system.mdc

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
---
2+
description: Design system and styling rules for the Blockscout frontend
3+
globs: *.tsx,*.ts
4+
alwaysApply: false
5+
---
6+
# Design System
7+
8+
## Stack
9+
10+
The app uses **Chakra UI v3** as its component and styling foundation.
11+
12+
**Documentation:** https://chakra-ui.com/llms.txt — consult this to understand what components Chakra provides and how its styling system works.
13+
14+
## Project configuration
15+
16+
The design system is layered on top of Chakra UI inside `toolkit/`:
17+
18+
| Path | Purpose |
19+
|---|---|
20+
| `toolkit/chakra/` | Custom wrappers for Chakra components — always prefer these over bare Chakra imports |
21+
| `toolkit/theme/theme.ts` | Theme entry point; uses Chakra v3's `createSystem` API to merge defaults with project config |
22+
| `toolkit/theme/foundations/semanticTokens.ts` | Full list of semantic color tokens (text, bg, border, icon, component-level tokens) |
23+
| `toolkit/theme/foundations/colors.ts` | Raw color palette referenced by semantic tokens |
24+
| `toolkit/theme/recipes/` | Component style recipes (slot recipes and simple recipes) |
25+
| `toolkit/components/` | Custom business components (forms, charts, tabs, etc.) built on top of Chakra |
26+
| `toolkit/hooks/` | Shared React hooks (useDisclosure, useClipboard, etc.) |
27+
28+
The `Provider` component at `toolkit/chakra/provider.tsx` wraps `ChakraProvider` with the custom theme and color mode support. It must be mounted at the app root.
29+
30+
## Component import priority
31+
32+
Always check `toolkit/chakra/` before importing from Chakra UI directly. If a custom wrapper exists there, use it — never the bare Chakra component.
33+
34+
```ts
35+
// BAD
36+
import { Button } from '@chakra-ui/react';
37+
38+
// GOOD
39+
import { Button } from 'toolkit/chakra/button';
40+
```
41+
42+
43+
## Colors
44+
45+
Never use raw color values (hex, RGB, HSL). Always reference a token. Three sources are valid:
46+
47+
1. **Semantic tokens** — context-aware, light/dark aware. Full list in `toolkit/theme/foundations/semanticTokens.ts`. Prefer these whenever a semantic meaning exists.
48+
49+
```tsx
50+
<Text color="text.secondary" />
51+
<Box bg="bg.secondary" borderColor="border.divider" />
52+
```
53+
54+
Common groups: `text.*`, `bg.*`, `border.*`, `icon.*`, `link.*`, `button.*`, `badge.*`.
55+
56+
2. **Project color palette** — scale and alpha colors defined in `toolkit/theme/foundations/colors.ts`: `gray`, `blue`, `red`, `orange`, `yellow`, `green`, `teal`, `cyan`, `purple`, `pink` (steps 50–900), `black`, `white`, `whiteAlpha.*`, `blackAlpha.*`.
57+
58+
```tsx
59+
<Box bg="blue.50" color="gray.700" />
60+
```
61+
62+
3. **Brand colors** — also defined in `toolkit/theme/foundations/colors.ts`: `github`, `telegram`, `linkedin`, `discord`, `slack`, `twitter`, `opensea`, `facebook`, `medium`, `reddit`, `celo`, `clusters`.
63+
64+
```tsx
65+
<Icon color="github" />
66+
```
67+
68+
If a raw color value is truly unavoidable (e.g. a third-party embed), leave a comment explaining why.
69+
70+
## Design tokens
71+
72+
The project customizes the following Chakra token categories in `toolkit/theme/`. Always use these tokens instead of raw CSS values:
73+
74+
| Token type | File | Example |
75+
|---|---|---|
76+
| Border radius | `foundations/borders.ts` | `borderRadius="md"` instead of `borderRadius="12px"` |
77+
| Shadows | `foundations/shadows.ts` | `boxShadow="size.md"` instead of a custom `box-shadow` |
78+
| Z-index | `foundations/zIndex.ts` | `zIndex="modal"` instead of a raw number |
79+
| Font weights | `theme.ts` (inline) | `fontWeight="semibold"` instead of `fontWeight={600}` |
80+
| Durations | `foundations/durations.ts` | Use duration tokens for CSS transitions |
81+
| Keyframes | `foundations/animations.ts` | Reference named keyframes for custom animations |
82+
83+
Available `radii` tokens: `none`, `sm` (4px), `base` (8px), `md` (12px), `lg` (16px), `xl` (24px), `full`.
84+
85+
Available `shadows` tokens: `size.xs`, `size.sm`, `size.base`, `size.md`, `size.lg`, `size.xl`, `size.2xl`, `action_bar`, `dark-lg`.
86+
87+
## Text styles
88+
89+
Do not set `fontSize` or `lineHeight` directly. Apply the appropriate `textStyle` token instead — it encodes both properties together along with `fontWeight` and `fontFamily`.
90+
91+
```tsx
92+
// BAD
93+
<Text fontSize="14px" lineHeight="20px">Label</Text>
94+
95+
// GOOD
96+
<Text textStyle="text.sm">Label</Text>
97+
```
98+
99+
Available text styles (defined in `toolkit/theme/foundations/typography.ts`):
100+
101+
| Token | fontSize / lineHeight |
102+
|---|---|
103+
| `heading.xl` | 32px / 40px |
104+
| `heading.lg` | 24px / 32px |
105+
| `heading.md` | 18px / 24px |
106+
| `heading.sm` | 16px / 24px |
107+
| `heading.xs` | 14px / 20px |
108+
| `text.xl` | 20px / 28px |
109+
| `text.md` | 16px / 24px |
110+
| `text.sm` | 14px / 20px |
111+
| `text.xs` | 12px / 16px |
112+
113+
For a regular text block, the `text.` prefix can be omitted.
114+
115+
## Compound component spacing
116+
117+
Do not override the default spacing of **internal parts** of compound components (e.g. adding custom padding to `DialogHeader` inside a `Dialog`, or to a `MenuList` item). The root component itself may be spaced freely; its sub-parts may not.
118+
119+
This rule applies to all components from `toolkit/chakra/`.
120+
121+
## Duplicated style props
122+
123+
Before adding a style prop, check whether the same property is already set by an inherited style or a parent component. Flag and remove redundant re-declarations.
124+

0 commit comments

Comments
 (0)