Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
2e1175c
fix nextjs routes after migrating to turbopack
tom2drum Apr 1, 2026
fcc26b9
pin version of monaco-editor and pass it to the loader
tom2drum Apr 1, 2026
a664a20
Multichain explorer: add border to portfolio card (#3333)
tom2drum Apr 2, 2026
2d9c87f
Inputs: fix text line height (#3334)
tom2drum Apr 2, 2026
829141d
Hero banner: move heading copy to configurable text in hero banner JS…
tom2drum Apr 2, 2026
d28767d
DApp disclaimer always forces embeded page (#3336)
tom2drum Apr 2, 2026
f0c4053
Numeric widget: add optional value title from API (#3282) (#3337)
tom2drum Apr 2, 2026
f15de5d
Support both chain slug and chain id in multichain page parameters (#…
tom2drum Apr 3, 2026
022b324
UI: Additional info popup (paddings) (#3342)
tom2drum Apr 7, 2026
a640f69
Async CSV export (#3330)
tom2drum Apr 7, 2026
ec266dc
Agent tooling relocation, architecture redesign docs (#3343)
tom2drum Apr 7, 2026
efd6255
track: 0-1 in progress — blockscout/frontend#3345
tom2drum Apr 7, 2026
d9c2656
UX: Remove filter if tab is empty (#3347)
tom2drum Apr 7, 2026
db7032a
[Migration 0-1] Rename configs/app/features/ files to kebab-case (#3346)
tom2drum Apr 7, 2026
a7a43c1
track: 0-2 in progress — blockscout/frontend#3348
tom2drum Apr 7, 2026
a1060de
[Migration 0-2] Enable ESLint import/no-cycle + boundaries rules (#3349)
tom2drum Apr 8, 2026
ee922ef
Release v2.7.2 (#3326)
tom2drum Apr 8, 2026
4cc3368
Improve toast messages in the Revoke dapp (#3344)
maxaleks Apr 8, 2026
e942c6e
Add Content-Type header to /api/v2/key request
yvaskov Apr 14, 2026
ac09fab
Merge pull request #3352 from blockscout/temp-token-fix
yvaskov Apr 15, 2026
be5240d
update license
tom2drum Apr 21, 2026
7c2c631
Support full instance specifiers for admin and contract-info services…
tom2drum Apr 23, 2026
d61f535
Cross-chain: ICTT users index, bridged tokens tab, and stats layout (…
tom2drum Apr 27, 2026
5fc091d
Adjust scale in d3 to display correct resolution by week in stats (#3…
tom2drum Apr 27, 2026
4bfccf4
Refactor deployment workflows (#3362)
tom2drum Apr 27, 2026
129710f
Bump Next.js to 16.2.4 and refresh dependency versions (#3361)
tom2drum Apr 27, 2026
f4eefee
Support `http://localhost` (no `/api`) as Swagger server URL placehol…
Copilot Apr 27, 2026
950a751
Pass imageName: frontend-private to cleanup_docker workflow
alik-agaev Apr 28, 2026
a2e5a1b
cleanup: pass explicit namespace to cleanup_helmfile
alik-agaev Apr 28, 2026
54e31e4
update rules with "Strict comparison" section
tom2drum Apr 29, 2026
39d87ae
Fix popoper overflow issue and sticky table header issue (#3368)
tom2drum Apr 29, 2026
dc65fd1
update eqeqeq eslint rule
tom2drum Apr 29, 2026
8a59bec
Merge branch 'main' of github.com:blockscout/frontend
tom2drum Apr 29, 2026
03c4472
track: 1-1 in progress — blockscout/frontend#3369
tom2drum Apr 29, 2026
9ac0856
Broken layout on `Verify & publish contract` for `Solidity (Hardhat)`…
tom2drum Apr 29, 2026
5107ba2
Merge pull request #3365 from blockscout/fix/cleanup-docker-image-name
alik-agaev Apr 29, 2026
f1d84f1
Use sockets to update latest block/batch on home page (#3353)
maxaleks Apr 29, 2026
6e79864
migration skills and task list updates
tom2drum Apr 29, 2026
def1641
update lint command in the migration skill
tom2drum Apr 29, 2026
54b19bc
disable no-cycle eslint rule
tom2drum Apr 29, 2026
79e17ad
[Migration] 1-1: Migrate `client/api` (#3370)
Copilot Apr 29, 2026
50dd22e
track: 1-2 in progress — blockscout/frontend#3371
tom2drum Apr 29, 2026
8e0a55e
update research skill
tom2drum Apr 29, 2026
d901821
Multichain: support async csv export (#3373)
tom2drum Apr 30, 2026
7b580e1
[Migration 1-2] Migrate client/shared/ (#3372)
tom2drum Apr 30, 2026
1b7cf5d
fix multichain config build
tom2drum Apr 30, 2026
ce66d1b
Remove zkEvm rollup option (#3375)
Copilot Apr 30, 2026
ac972cd
Noves: unreadable tooltip in dark mode on `Asset Flows` tx tab (#3376)
tom2drum Apr 30, 2026
9ceeb42
Migration 2-1: pilot tx slice in client/ (#3377)
tom2drum May 1, 2026
e7709c4
track: 3-1 in progress — blockscout/frontend#3378
tom2drum May 1, 2026
56013d6
[Migration 3-1] Move block slice to client/ architecture (#3379)
tom2drum May 1, 2026
205c5d5
track: 3-2 in progress — blockscout/frontend#3380
tom2drum May 4, 2026
679313b
move tac into chain-variants
tom2drum May 4, 2026
5774a8f
update migration skills
tom2drum May 5, 2026
04c527a
Tokens page: modify search field hint (#3381)
tom2drum May 5, 2026
e8de7f3
API Keys page: allow modification of the helping text (#3384)
tom2drum May 5, 2026
7f91c18
Rework ads (#3383)
maxaleks May 5, 2026
a5a951f
[Migration 3-2] Slice: address (#3385)
tom2drum May 6, 2026
c9bb2f8
Add copilot-setup-steps.yml to pre-install pnpm dependencies (#3390)
Copilot May 6, 2026
e611111
Multichain explorer: fix "View all transfers" link on tx page (#3389)
tom2drum May 6, 2026
2a02c0a
Toolkit: input truncation, adaptive tabs list props, FormFieldSwitch …
tom2drum May 7, 2026
a4b36dd
Fix client slice import paths (#3391)
tom2drum May 7, 2026
a683540
Promote the Blockscout PRO API in `llms.txt` (#3388)
akolotov May 7, 2026
09e3435
pass control props to select and hard-code text color for solid dange…
tom2drum May 7, 2026
dffabf7
prepare release
tom2drum May 7, 2026
1d3da68
fix feature reporter build
tom2drum May 7, 2026
130817c
WIP: Merge upstream v2.8.0-alpha.1 (has conflicts)
github-actions[bot] May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
26 changes: 26 additions & 0 deletions .agents/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Frontend application for Blockscout

## Architecture

See `./rules/architecture.mdc`.

## Design System Rules

See `./rules/design-system.mdc`.

## Code Style & Quality

See `./rules/code-quality.mdc`.

## TypeScript Conventions

See `./rules/typescript.mdc`.

## Environment Variables

See `./rules/env-vars.mdc`.

## Testing

- Unit tests (`*.spec.ts` / `*.spec.tsx`): See `./rules/tests-unit.mdc`.
- Visual component tests (`*.pw.tsx`): See `./rules/tests-visual.mdc`.
84 changes: 84 additions & 0 deletions .agents/rules/architecture.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
description: Project overview, tech stack, directory layout, data flow, and ongoing client/ architecture migration
globs:
alwaysApply: true
---
# Project Architecture

## What this is

Blockscout frontend — a blockchain explorer UI. Distributed as a Docker image; configured entirely via environment variables at runtime (see `.agents/rules/env-vars.mdc`).

## Tech stack

| Layer | Technology |
|---|---|
| Framework | Next.js 16 — **Pages Router only** (not App Router) |
| UI | React 19 |
| Component library | Chakra UI v3 (see `.agents/rules/design-system.mdc`) |
| Server state | React Query 5 |
| Web3 | Wagmi 2 / Viem 2 |
| Schema validation | Valibot |
| Unit tests | Vitest |
| Visual tests | Playwright |
| Package manager | pnpm (Node >=22.14.0) |

## Domain terminology

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`.

## Directory layout

```
pages/ Next.js file-based routes — thin wrappers only (dynamic import + getServerSideProps)
ui/ Legacy React UI components organized by feature (~65 subdirectories) → being migrated to client/
lib/ Legacy business logic, API utilities, custom hooks, context providers → being migrated to client/
client/ New home for all product code (see Migration section below)
toolkit/ Design system — Chakra wrappers, theme tokens, shared hooks/components (stays here permanently)
configs/app/ Runtime app configuration; must not import from client/
nextjs/ Next.js config utilities: headers, rewrites, redirects, type-safe routes
mocks/ Shared mock data for tests → being co-located under client/ slices/features
deploy/ Docker scripts, env validator, build tools
docs/ ENVS.md, GLOSSARY.md, CONTRIBUTING.md
```

## Data flow

- **Getting data:** pages fetch data via React Query. Query keys and fetcher functions live in `lib/api/` (moving to `client/api/`).
- **Global UI state:** React Context providers initialized in `pages/_app.tsx` — `AppContextProvider`, `SettingsContextProvider`, `MarketplaceContextProvider`, etc.
- **Real-time data:** WebSocket via `SocketProvider` (moving to `client/api/socket/`).
- **App config:** always read via `configs/app/` (which reads `window.__envs` at runtime) — never `process.env.*` directly in component code.

---

## Ongoing migration: `client/` architecture

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.

**Blueprint:** `client/ARCH_REDESIGN.md`
**Task backlog and current status:** `client/MIGRATION_TASKS.md`

### Target layout inside `client/`

| Directory | Contents |
|---|---|
| `client/shell/` | App chrome: layout, header, footer, navigation, top-bar, root contexts |
| `client/api/` | API transport, fetch utilities, query client, WebSocket; migrated from `lib/api/` and `lib/socket/` |
| `client/slices/` | Core explorer entities always present on any EVM chain (tx, block, address, token, contract, search, …) |
| `client/features/` | Optional / config-gated areas: rollups, chain variants, account, rewards, marketplace, stats, … |
| `client/shared/` | Cross-cutting utilities with no single domain owner (analytics, errors, hooks, router helpers, text utils, …) |

### Slice vs feature

- **Slice** — present on every vanilla EVM chain, no feature flag required. Examples: `tx`, `block`, `address`, `token`, `contract`.
- **Feature** — config-gated or chain-specific. Examples: `rollup/optimism`, `chain-variants/celo`, `account`, `stats`, `gas-tracker`.

### Key rules for migrated code

- **No barrel `index.ts` files** inside `client/` unless the file defines a genuine public facade (not just `export * from ...`).
- **`client/api` must not have runtime imports** from `client/slices/*` or `client/features/*`; `import type` is allowed.
- **`configs/` never imports `client/`.**
- **`pages/` files are thin wrappers** — a dynamic import and optionally `getServerSideProps`; no UI components or business logic inline.
- **Naming:** kebab-case for directories and non-component modules; `PascalCase.tsx` for React components; `useCamelCase.ts` for hooks.
- **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.
- **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.
152 changes: 152 additions & 0 deletions .agents/rules/code-quality.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
---
description: Code quality rules for the Blockscout frontend
globs: *.tsx,*.ts
alwaysApply: false
---
# Code Quality

We use ESLint, cSpell and Typescript to maintain code quality and consistency across the project.
In order to check code quality run the following commands:
```bash
pnpm lint:eslint:fix
pnpm lint:tsc
pnpm lint:cspell
```

Moreover, please find below the general sense rules that linters do not cover.

## Code Style and Structure

### General Principles

- Write concise, readable TypeScript code
- Use functional and declarative programming patterns; avoid classes
- Prefer iteration and modularization over code duplication
- Implement early returns for better readability
- Structure components logically: exports, subcomponents, helpers, types

### Naming Conventions

- Prefer descriptive names with auxiliary verbs (isLoading, hasError)
- Prefix event handlers with "handle" (handleClick, handleSubmit)
- Favor default exports for React components

Names should be specific and self-documenting. Vague names hide intent and make the codebase harder to navigate.


```ts
// BAD
const useWidgets = () => { ... };

// GOOD
const useAddress3rdPartyWidgets = () => { ... };
```

This applies to hooks, components, functions, and variables alike..

## Specific rules

### Magic numbers

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.

```ts
// BAD
const visibleItems = items.slice(0, 4);

// GOOD
const MAX_VISIBLE_ITEMS = 4;
const visibleItems = items.slice(0, MAX_VISIBLE_ITEMS);
```

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.

### Static empty defaults

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.

```ts
// BAD
const items = data ?? [];

// GOOD
const EMPTY_ITEMS: Array<Item> = [];
const items = data ?? EMPTY_ITEMS;
```

Define the constant outside the component or hook.

### useMemo for derived arrays

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.

```ts
// BAD
const filtered = items.filter(isActive);
return <List items={filtered} />;

// GOOD
const filtered = useMemo(() => items.filter(isActive), [items]);
return <List items={filtered} />;
```

### eslint-disable comments

Every `eslint-disable` comment must include an explanation. Without one, the reason for the suppression is lost and the comment becomes a maintenance hazard.

```ts
// BAD
// eslint-disable-next-line @typescript-eslint/no-explicit-any

// GOOD
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- API response shape is dynamic and validated at runtime
```

### File path string interpolation

Prefer explicit file names over template literals in asset paths. Explicit names are easier to locate with search tools and eliminate accidental runtime errors.

```ts
// BAD
const src = `streak_${days}.png`;

// GOOD — map variants explicitly
const STREAK_IMAGES: Record<number, string> = {
30: 'streak_30.png',
60: 'streak_60.png',
};
```

### Prefer es-toolkit utilities

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

### Commented-out code

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.

### Links

- Use `toolkit/chakra/link` instead of `next/link`. Never import `Link` from `next/link` directly.
- 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`.

### Date and time

- Import `dayjs` only via `lib/date/dayjs.ts` — never directly from the `dayjs` package.
- Render all dates and times through the shared `Time` or `TimeWithTooltip` components. Do not format timestamps inline.

### Strict comparison

Use strict equality (`===`, `!==`) only — never loose equality (`==`, `!=`). Strict operators avoid type coercion surprises and align with TypeScript expectations.

```ts
// BAD
if (count == 0) { ... }
if (status != 'ok') { ... }

// GOOD
if (count === 0) { ... }
if (status !== 'ok') { ... }
```

When you need to treat both `null` and `undefined` as missing, write `value === null || value === undefined` instead of `value == null`.
124 changes: 124 additions & 0 deletions .agents/rules/design-system.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
description: Design system and styling rules for the Blockscout frontend
globs: *.tsx,*.ts
alwaysApply: false
---
# Design System

## Stack

The app uses **Chakra UI v3** as its component and styling foundation.

**Documentation:** https://chakra-ui.com/llms.txt — consult this to understand what components Chakra provides and how its styling system works.

## Project configuration

The design system is layered on top of Chakra UI inside `toolkit/`:

| Path | Purpose |
|---|---|
| `toolkit/chakra/` | Custom wrappers for Chakra components — always prefer these over bare Chakra imports |
| `toolkit/theme/theme.ts` | Theme entry point; uses Chakra v3's `createSystem` API to merge defaults with project config |
| `toolkit/theme/foundations/semanticTokens.ts` | Full list of semantic color tokens (text, bg, border, icon, component-level tokens) |
| `toolkit/theme/foundations/colors.ts` | Raw color palette referenced by semantic tokens |
| `toolkit/theme/recipes/` | Component style recipes (slot recipes and simple recipes) |
| `toolkit/components/` | Custom business components (forms, charts, tabs, etc.) built on top of Chakra |
| `toolkit/hooks/` | Shared React hooks (useDisclosure, useClipboard, etc.) |

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.

## Component import priority

Always check `toolkit/chakra/` before importing from Chakra UI directly. If a custom wrapper exists there, use it — never the bare Chakra component.

```ts
// BAD
import { Button } from '@chakra-ui/react';

// GOOD
import { Button } from 'toolkit/chakra/button';
```


## Colors

Never use raw color values (hex, RGB, HSL). Always reference a token. Three sources are valid:

1. **Semantic tokens** — context-aware, light/dark aware. Full list in `toolkit/theme/foundations/semanticTokens.ts`. Prefer these whenever a semantic meaning exists.

```tsx
<Text color="text.secondary" />
<Box bg="bg.secondary" borderColor="border.divider" />
```

Common groups: `text.*`, `bg.*`, `border.*`, `icon.*`, `link.*`, `button.*`, `badge.*`.

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.*`.

```tsx
<Box bg="blue.50" color="gray.700" />
```

3. **Brand colors** — also defined in `toolkit/theme/foundations/colors.ts`: `github`, `telegram`, `linkedin`, `discord`, `slack`, `twitter`, `opensea`, `facebook`, `medium`, `reddit`, `celo`, `clusters`.

```tsx
<Icon color="github" />
```

If a raw color value is truly unavoidable (e.g. a third-party embed), leave a comment explaining why.

## Design tokens

The project customizes the following Chakra token categories in `toolkit/theme/`. Always use these tokens instead of raw CSS values:

| Token type | File | Example |
|---|---|---|
| Border radius | `foundations/borders.ts` | `borderRadius="md"` instead of `borderRadius="12px"` |
| Shadows | `foundations/shadows.ts` | `boxShadow="size.md"` instead of a custom `box-shadow` |
| Z-index | `foundations/zIndex.ts` | `zIndex="modal"` instead of a raw number |
| Font weights | `theme.ts` (inline) | `fontWeight="semibold"` instead of `fontWeight={600}` |
| Durations | `foundations/durations.ts` | Use duration tokens for CSS transitions |
| Keyframes | `foundations/animations.ts` | Reference named keyframes for custom animations |

Available `radii` tokens: `none`, `sm` (4px), `base` (8px), `md` (12px), `lg` (16px), `xl` (24px), `full`.

Available `shadows` tokens: `size.xs`, `size.sm`, `size.base`, `size.md`, `size.lg`, `size.xl`, `size.2xl`, `action_bar`, `dark-lg`.

## Text styles

Do not set `fontSize` or `lineHeight` directly. Apply the appropriate `textStyle` token instead — it encodes both properties together along with `fontWeight` and `fontFamily`.

```tsx
// BAD
<Text fontSize="14px" lineHeight="20px">Label</Text>

// GOOD
<Text textStyle="text.sm">Label</Text>
```

Available text styles (defined in `toolkit/theme/foundations/typography.ts`):

| Token | fontSize / lineHeight |
|---|---|
| `heading.xl` | 32px / 40px |
| `heading.lg` | 24px / 32px |
| `heading.md` | 18px / 24px |
| `heading.sm` | 16px / 24px |
| `heading.xs` | 14px / 20px |
| `text.xl` | 20px / 28px |
| `text.md` | 16px / 24px |
| `text.sm` | 14px / 20px |
| `text.xs` | 12px / 16px |

For a regular text block, the `text.` prefix can be omitted.

## Compound component spacing

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.

This rule applies to all components from `toolkit/chakra/`.

## Duplicated style props

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.

Loading
Loading