Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions packages/contract-reader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A [Nuxt 4](https://nuxt.com) layer of Vue 3 components, composables and utilities for inspecting and interacting with verified EVM smart contracts. It powers [evm.now](https://evm.now) and is published so you can drop the same UI into your own dApp.

The layer covers the contract-explorer surface end to end: contract overview, grouped read/interact function panels with form generation, source-file viewer with Solidity syntax highlighting, and a composable that fetches verified metadata, ABI and source through [`@evmnow/sdk`](https://www.npmjs.com/package/@evmnow/sdk).
The layer covers the contract-explorer surface end to end: contract overview, grouped read/interact action panels with form generation, source-file viewer with Solidity syntax highlighting, and a composable that fetches verified metadata, ABI and source through [`@evmnow/sdk`](https://www.npmjs.com/package/@evmnow/sdk).

## Install

Expand Down Expand Up @@ -35,17 +35,17 @@ Each surface is also exported under its own subpath for projects that don't want
// components
import Overview from '@evmnow/contract-reader/components/Overview'
import Source from '@evmnow/contract-reader/components/Source'
import FunctionList from '@evmnow/contract-reader/components/Function/List'
import FunctionCards from '@evmnow/contract-reader/components/Function/Cards'
import FunctionDetail from '@evmnow/contract-reader/components/Function/Detail'
import ActionList from '@evmnow/contract-reader/components/Action/List'
import ActionCards from '@evmnow/contract-reader/components/Action/Cards'
import ActionDetail from '@evmnow/contract-reader/components/Action/Detail'

// composable
import { useContractMetadataSdk } from '@evmnow/contract-reader/composables/useContractMetadataSdk'

// types
import type {
ContractData,
ContractFunction,
ContractAction,
SourceFile,
} from '@evmnow/contract-reader/types/contract'
import type { ContractUIMetadata } from '@evmnow/contract-reader/types/metadata'
Expand All @@ -55,7 +55,7 @@ import type {
} from '@evmnow/contract-reader/types/actions'

// utils
import { groupFunctions } from '@evmnow/contract-reader/utils/abi'
import { groupActions } from '@evmnow/contract-reader/utils/abi'
import { highlightSolidity } from '@evmnow/contract-reader/utils/syntax'
```

Expand Down Expand Up @@ -91,21 +91,21 @@ Stale responses from older `get()` calls are dropped, so it's safe to react to i
<template>
<Overview :contract="contract" />

<FunctionList
:functions="contract.functions.read"
<ActionList
:actions="contract.actions.read"
:metadata="contract.metadata"
:selected="selected?.slug"
@select="selectFn"
@select="selectAction"
/>

<FunctionDetail
<ActionDetail
v-if="selected"
:address="contract.address"
:abi="contract.abi"
:chain-id="contract.chainId"
:fn="selected"
:read-function="readContractFunction"
:write-function="writeContractFunction"
:action="selected"
:read-function="readContract"
:write-function="writeContract"
:wallet-connected="walletConnected"
:connected-address="connectedAddress"
/>
Expand All @@ -116,26 +116,26 @@ Stale responses from older `get()` calls are dropped, so it's safe to react to i

`readFunction` / `writeFunction` take `ContractReadFn` / `ContractWriteFn` callbacks (`{ address, abi, functionName, args, value? }`) so you can wire them to viem, ethers, or the wallet implementation of your choice. The bundled wallet layer ships ready-made versions you can use directly.

`FunctionDetail` builds inputs from the ABI plus the metadata schema (semantic input types, autofill, validation, examples, tuple support) and renders the call result back into the matching field shape.
`ActionDetail` builds inputs from the ABI plus the metadata schema (semantic input types, autofill, validation, examples, tuple support, hidden/disabled preset params for variants like "Revoke Approval") and renders the call result back into the matching field shape.

### Components

| Component | Purpose |
| --- | --- |
| `Overview` | Description, stat tiles, long-form `about` markdown — slot-driven for full overrides. |
| `Source` | Multi-file Solidity viewer with Shiki highlighting, line-level deep-linking, file/line `href` builders. |
| `FunctionList` | Sidebar list of grouped functions with selection and optional `href` per item. |
| `FunctionCards` | Card grid alternative — each function expands inline into `FunctionDetail`. |
| `FunctionGroups` | Headless grouping primitive used by `List`/`Cards`; expose your own layout via slots. |
| `FunctionDetail` | Form generation, validation, examples, read-call execution, write-call submission. |
| `FunctionResult` / `FunctionResultFields` | Output rendering with semantic-type formatting. |
| `ActionList` | Sidebar list of grouped actions with selection and optional `href` per item. |
| `ActionCards` | Card grid alternative — each action expands inline into `ActionDetail`. |
| `ActionGroups` | Headless grouping primitive used by `List`/`Cards`; expose your own layout via slots. |
| `ActionDetail` | Form generation, validation, examples, read-call execution, write-call submission. Respects `hidden`/`disabled` param flags for variant actions. |
| `ActionResult` / `ActionResultFields` | Output rendering with semantic-type formatting. |
| `Markdown` / `InlineMarkdown` | Lightweight markdown renderers for descriptions and `about`. |
| `CopyButton` | Copy-to-clipboard helper. |
| `TransactionButton` | Shared submit-button styling for write actions. |

### Utilities

- `utils/abi` — `groupFunctions`, ABI grouping helpers, slug generation.
- `utils/abi` — `parseActions`, `groupActions`, ABI-to-action resolution helpers.
- `utils/contract` — derive `ContractData` from raw SDK output, proxy/diamond handling.
- `utils/inputs` — parse, validate and serialize human-entered values against ABI types and `SemanticType`s (eth, gwei, timestamp, basis points, enums, sliders…).
- `utils/format` — display formatters for addresses, amounts, durations, etc.
Expand All @@ -146,7 +146,7 @@ Stale responses from older `get()` calls are dropped, so it's safe to react to i

## Styling

The layer registers `app/assets/css/index.css`, which pulls in design tokens, base controls, and per-component stylesheets (`overview.css`, `function.css`, `source.css`, `markdown.css`, `result.css`). All selectors are namespaced under `.cr-*` and built on CSS variables, so you can theme the UI by overriding the tokens in your own stylesheet — no preprocessor required.
The layer registers `app/assets/css/index.css`, which pulls in design tokens, base controls, and per-component stylesheets (`overview.css`, `action.css`, `source.css`, `markdown.css`, `result.css`). All selectors are namespaced under `.cr-*` and built on CSS variables, so you can theme the UI by overriding the tokens in your own stylesheet — no preprocessor required.

## License

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@layer components {
.cr-functions,
.cr-function-cards {
.cr-actions,
.cr-action-cards {
display: grid;
gap: var(--cr-function-section-gap);
gap: var(--cr-action-section-gap);
align-content: start;
}

Expand All @@ -12,72 +12,72 @@
}

.cr-form {
gap: var(--cr-function-form-gap);
gap: var(--cr-action-form-gap);
}

.cr-overview {
gap: var(--cr-function-grid-gap);
gap: var(--cr-action-grid-gap);
}

.cr-function-detail {
.cr-action-detail {
display: grid;
gap: var(--spacer-sm);
}

.cr-function-description,
.cr-function-detail > .cr-warning,
.cr-function-detail > .cr-field,
.cr-function-detail > .cr-form {
margin-bottom: var(--cr-function-detail-gap);
.cr-action-description,
.cr-action-detail > .cr-warning,
.cr-action-detail > .cr-field,
.cr-action-detail > .cr-form {
margin-bottom: var(--cr-action-detail-gap);
}

.cr-function-action {
justify-self: var(--cr-function-detail-button-justify);
.cr-action-action {
justify-self: var(--cr-action-detail-button-justify);
}

.cr-function-cards,
.cr-function-group,
.cr-function-group-body {
.cr-action-cards,
.cr-action-group,
.cr-action-group-body {
min-width: 0;
}

.cr-function-group,
.cr-function-group-body,
.cr-function-card-grid,
.cr-action-group,
.cr-action-group-body,
.cr-action-card-grid,
.cr-field,
.cr-tuple-input {
display: grid;
}

.cr-function-group {
gap: var(--cr-function-group-gap);
.cr-action-group {
gap: var(--cr-action-group-gap);
}

.cr-function-group-body,
.cr-function-card-grid {
gap: var(--cr-function-gap);
.cr-action-group-body,
.cr-action-card-grid {
gap: var(--cr-action-gap);
}

.cr-field,
.cr-tuple-input {
gap: var(--cr-function-field-gap);
gap: var(--cr-action-field-gap);
}

.cr-examples {
display: flex;
flex-wrap: wrap;
gap: var(--cr-function-gap);
gap: var(--cr-action-gap);
}

.cr-group-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--cr-function-grid-gap);
gap: var(--cr-action-grid-gap);
margin: 0;
}

.cr-function-item {
.cr-action-item {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
Expand All @@ -86,39 +86,39 @@
text-align: left;
}

.cr-function-item-title,
.cr-function-item-signature,
.cr-function-card-title,
.cr-function-card-signature {
.cr-action-item-title,
.cr-action-item-signature,
.cr-action-card-title,
.cr-action-card-signature {
min-width: 0;
}

.cr-function-item-signature,
.cr-function-card-signature {
.cr-action-item-signature,
.cr-action-card-signature {
font-family: var(--cr-mono);
}

.cr-function-item-title,
.cr-function-card-title {
.cr-action-item-title,
.cr-action-card-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.cr-function-item-signature {
.cr-action-item-signature {
grid-column: 1 / -1;
}

.cr-function-card {
.cr-action-card {
display: grid;
min-width: 0;
}

.cr-function-card-header {
.cr-action-card-header {
display: grid;
width: 100%;
padding: var(--cr-function-card-header-padding-block)
var(--cr-function-card-header-padding-inline);
padding: var(--cr-action-card-header-padding-block)
var(--cr-action-card-header-padding-inline);
border: 0;
background: transparent;
color: inherit;
Expand All @@ -127,11 +127,11 @@
text-align: left;
}

.cr-function-card-signature {
.cr-action-card-signature {
overflow-wrap: anywhere;
}

.cr-function-card-expand {
.cr-action-card-expand {
display: grid;
grid-template-rows: 0fr;
opacity: 0;
Expand All @@ -140,17 +140,17 @@
opacity var(--speed);
}

.cr-function-card-expand.open {
.cr-action-card-expand.open {
grid-template-rows: 1fr;
opacity: 1;
}

.cr-function-card-collapse {
.cr-action-card-collapse {
min-height: 0;
overflow: hidden;
}

.cr-function-card-body {
.cr-action-card-body {
min-width: 0;
display: grid;
gap: var(--spacer);
Expand Down
6 changes: 3 additions & 3 deletions packages/contract-reader/app/assets/css/controls.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@layer components {
.cr-copy,
.cr-function-item {
.cr-action-item {
color: inherit;
cursor: pointer;
font: inherit;
Expand All @@ -14,11 +14,11 @@
}

.cr-copy:disabled,
.cr-function-item:disabled {
.cr-action-item:disabled {
cursor: not-allowed;
}

.cr-function-item {
.cr-action-item {
text-decoration: none;
}
}
6 changes: 3 additions & 3 deletions packages/contract-reader/app/assets/css/core.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
}

.cr-overview code,
.cr-function-item-signature {
.cr-action-item-signature {
display: block;
max-width: 100%;
color: var(--cr-muted);
Expand All @@ -49,8 +49,8 @@
text-transform: var(--cr-label-text-transform);
}

.cr-function-item-signature,
.cr-function-card-signature,
.cr-action-item-signature,
.cr-action-card-signature,
.cr-overview code,
.cr-field-type,
.cr-result-value,
Expand Down
2 changes: 1 addition & 1 deletion packages/contract-reader/app/assets/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@import './markdown.css';
@import './overview.css';
@import './controls.css';
@import './function.css';
@import './action.css';
@import './result.css';
@import './preview.css';
@import './source.css';
30 changes: 15 additions & 15 deletions packages/contract-reader/app/assets/css/tokens.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@
--cr-label-font-weight: 700;
--cr-label-letter-spacing: 0;
--cr-label-text-transform: uppercase;
--cr-function-gap: var(--size-2);
--cr-function-section-gap: var(--size-4);
--cr-function-group-gap: var(--size-2);
--cr-function-form-gap: var(--size-5);
--cr-function-grid-gap: var(--size-3);
--cr-function-field-gap: var(--size-2);
--cr-function-item-padding-block: var(--size-2);
--cr-function-item-padding-inline: var(--size-3);
--cr-function-item-min-block-size: calc(var(--size-6) + var(--size-2));
--cr-function-card-header-padding-block: var(--size-2);
--cr-function-card-header-padding-inline: var(--size-3);
--cr-function-card-body-padding: var(--size-3);
--cr-function-detail-gap: var(--size-4);
--cr-function-detail-button-justify: start;
--cr-action-gap: var(--size-2);
--cr-action-section-gap: var(--size-4);
--cr-action-group-gap: var(--size-2);
--cr-action-form-gap: var(--size-5);
--cr-action-grid-gap: var(--size-3);
--cr-action-field-gap: var(--size-2);
--cr-action-item-padding-block: var(--size-2);
--cr-action-item-padding-inline: var(--size-3);
--cr-action-item-min-block-size: calc(var(--size-6) + var(--size-2));
--cr-action-card-header-padding-block: var(--size-2);
--cr-action-card-header-padding-inline: var(--size-3);
--cr-action-card-body-padding: var(--size-3);
--cr-action-detail-gap: var(--size-4);
--cr-action-detail-button-justify: start;
--cr-input-help-margin-top: calc(
var(--size-1) - var(--cr-function-field-gap)
var(--size-1) - var(--cr-action-field-gap)
);
--cr-result-margin-top: 0;
--cr-result-padding: var(--size-4);
Expand Down
Loading