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