From e0e2a1edf87c1fe3cba33bcd80906510ee8a4675 Mon Sep 17 00:00:00 2001 From: Sam Ruberti Date: Fri, 16 Jun 2023 11:57:41 -0400 Subject: [PATCH] feat: add basic_contract_caller ui --- README.md | 6 + basic-contract-caller/lib.rs | 7 + basic-contract-caller/other_contract/lib.rs | 5 + basic_contract_caller/frontend/.gitignore | 21 + basic_contract_caller/frontend/README.md | 4 + basic_contract_caller/frontend/index.html | 13 + basic_contract_caller/frontend/package.json | 30 ++ .../frontend/postcss.config.js | 6 + .../frontend/public/logo.svg | 1 + basic_contract_caller/frontend/src/App.tsx | 61 +++ basic_contract_caller/frontend/src/Global.css | 7 + basic_contract_caller/frontend/src/Other.tsx | 30 ++ .../src/assets/basic_contract_caller.json | 446 ++++++++++++++++++ .../frontend/src/assets/other_contract.json | 431 +++++++++++++++++ .../frontend/src/constants.ts | 2 + basic_contract_caller/frontend/src/main.tsx | 27 ++ .../frontend/src/vite-env.d.ts | 1 + .../frontend/tailwind.config.js | 2 + basic_contract_caller/frontend/tsconfig.json | 25 + .../frontend/tsconfig.node.json | 10 + basic_contract_caller/frontend/vite.config.ts | 7 + package.json | 5 +- ui/src/Accounts/Accounts.tsx | 4 +- ui/src/Button/Button.tsx | 4 +- ui/src/Link/Link.tsx | 26 + ui/src/Link/index.ts | 1 + ui/src/NumberInput/NumberInput.tsx | 9 +- ui/src/index.ts | 1 + 28 files changed, 1181 insertions(+), 11 deletions(-) create mode 100644 basic_contract_caller/frontend/.gitignore create mode 100644 basic_contract_caller/frontend/README.md create mode 100644 basic_contract_caller/frontend/index.html create mode 100644 basic_contract_caller/frontend/package.json create mode 100644 basic_contract_caller/frontend/postcss.config.js create mode 100644 basic_contract_caller/frontend/public/logo.svg create mode 100644 basic_contract_caller/frontend/src/App.tsx create mode 100644 basic_contract_caller/frontend/src/Global.css create mode 100644 basic_contract_caller/frontend/src/Other.tsx create mode 100644 basic_contract_caller/frontend/src/assets/basic_contract_caller.json create mode 100644 basic_contract_caller/frontend/src/assets/other_contract.json create mode 100644 basic_contract_caller/frontend/src/constants.ts create mode 100644 basic_contract_caller/frontend/src/main.tsx create mode 100644 basic_contract_caller/frontend/src/vite-env.d.ts create mode 100644 basic_contract_caller/frontend/tailwind.config.js create mode 100644 basic_contract_caller/frontend/tsconfig.json create mode 100644 basic_contract_caller/frontend/tsconfig.node.json create mode 100644 basic_contract_caller/frontend/vite.config.ts create mode 100644 ui/src/Link/Link.tsx create mode 100644 ui/src/Link/index.ts diff --git a/README.md b/README.md index a189131a..d61b79d1 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,12 @@ The `.contract` file combines the Wasm and metadata into one file and can be use 4. Run each example with `pnpm `. e.g. `pnpm flipper` 5. Visit [http://localhost:5173](http://localhost:5173) in your browser. +### Commands + +* `pnpm flipper` +* `pnpm incrementer` +* `pnpm contract_transfer` + All examples are built with [useink](https://use.ink/frontend/overview), a React hooks library built by the ink! team. ## License diff --git a/basic-contract-caller/lib.rs b/basic-contract-caller/lib.rs index f988caab..14df01c2 100755 --- a/basic-contract-caller/lib.rs +++ b/basic-contract-caller/lib.rs @@ -37,5 +37,12 @@ mod basic_contract_caller { self.other_contract.flip(); self.other_contract.get() } + + /// Get the address of the other contract after it has been instantiated. We can + /// use this so we can call the other contract on the frontend. + #[ink(message)] + pub fn other(&mut self) -> AccountId { + self.other_contract.account_id() + } } } diff --git a/basic-contract-caller/other_contract/lib.rs b/basic-contract-caller/other_contract/lib.rs index 53e51019..00eabdb4 100755 --- a/basic-contract-caller/other_contract/lib.rs +++ b/basic-contract-caller/other_contract/lib.rs @@ -29,5 +29,10 @@ mod other_contract { pub fn get(&self) -> bool { self.value } + + #[ink(message)] + pub fn account_id(&self) -> AccountId { + self.env().account_id() + } } } diff --git a/basic_contract_caller/frontend/.gitignore b/basic_contract_caller/frontend/.gitignore new file mode 100644 index 00000000..c13f37b6 --- /dev/null +++ b/basic_contract_caller/frontend/.gitignore @@ -0,0 +1,21 @@ +# Logs +logs +*.log +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/basic_contract_caller/frontend/README.md b/basic_contract_caller/frontend/README.md new file mode 100644 index 00000000..ad88c572 --- /dev/null +++ b/basic_contract_caller/frontend/README.md @@ -0,0 +1,4 @@ +# Have Questions? + +For any questions about building front end applications with [useink](https://use.ink/frontend/overview/), join the [Element chat](https://matrix.to/#/%23useink:parity.io). + diff --git a/basic_contract_caller/frontend/index.html b/basic_contract_caller/frontend/index.html new file mode 100644 index 00000000..e4d2ac59 --- /dev/null +++ b/basic_contract_caller/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + ink! Examples + + +
+ + + diff --git a/basic_contract_caller/frontend/package.json b/basic_contract_caller/frontend/package.json new file mode 100644 index 00000000..a50868f9 --- /dev/null +++ b/basic_contract_caller/frontend/package.json @@ -0,0 +1,30 @@ +{ + "name": "basic_contract_caller", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "ui": "workspace:ui@*" + }, + "devDependencies": { + "@types/react": "^18.0.37", + "@types/react-dom": "^18.0.11", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", + "@vitejs/plugin-react": "^4.0.0", + "autoprefixer": "^10.4.14", + "eslint": "^8.38.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.3.4", + "postcss": "^8.4.24", + "tailwindcss": "^3.3.2", + "typescript": "^5.0.2", + "vite": "^4.3.9" + } +} diff --git a/basic_contract_caller/frontend/postcss.config.js b/basic_contract_caller/frontend/postcss.config.js new file mode 100644 index 00000000..2aa7205d --- /dev/null +++ b/basic_contract_caller/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/basic_contract_caller/frontend/public/logo.svg b/basic_contract_caller/frontend/public/logo.svg new file mode 100644 index 00000000..c31ded82 --- /dev/null +++ b/basic_contract_caller/frontend/public/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/basic_contract_caller/frontend/src/App.tsx b/basic_contract_caller/frontend/src/App.tsx new file mode 100644 index 00000000..20b39b67 --- /dev/null +++ b/basic_contract_caller/frontend/src/App.tsx @@ -0,0 +1,61 @@ +import { Other } from './Other'; +import basicContractMetadata from './assets/basic_contract_caller.json'; +import { BASIC_CONTRACT_ROCOCO_ADDRESS } from './constants'; +import { useEffect } from 'react'; +import { Button, Card, ConnectButton, InkLayout } from 'ui'; +import { useCall, useContract, useTx, useWallet } from 'useink'; +import { useTxNotifications } from 'useink/notifications'; +import { isPendingSignature, pickDecoded, shouldDisable } from 'useink/utils'; + +function App() { + const { account } = useWallet(); + const basicContract = useContract( + BASIC_CONTRACT_ROCOCO_ADDRESS, + basicContractMetadata, + ); + const flipAndGet = useTx(basicContract, 'flipAndGet'); + useTxNotifications(flipAndGet); + + const other = useCall(basicContract, 'other'); + + useEffect(() => { + other?.send([], { defaultCaller: true }); + }, [other.send]); + + const otherAddress = pickDecoded(other.result); + + return ( + +
+ +

+ {basicContractMetadata.contract.name.toUpperCase()} +

+ + {account ? ( + + ) : ( + + )} +
+ + {otherAddress && } +
+
+ ); +} + +export default App; diff --git a/basic_contract_caller/frontend/src/Global.css b/basic_contract_caller/frontend/src/Global.css new file mode 100644 index 00000000..c2f5c12e --- /dev/null +++ b/basic_contract_caller/frontend/src/Global.css @@ -0,0 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + background-color: #1A1452; +} \ No newline at end of file diff --git a/basic_contract_caller/frontend/src/Other.tsx b/basic_contract_caller/frontend/src/Other.tsx new file mode 100644 index 00000000..84f93b69 --- /dev/null +++ b/basic_contract_caller/frontend/src/Other.tsx @@ -0,0 +1,30 @@ +import otherContractMetadata from './assets/other_contract.json'; +import { Card } from 'ui'; +import { useCallSubscription, useContract } from 'useink'; +import { pickDecoded } from 'useink/utils'; + +interface Props { + address: string; +} + +export const Other: React.FC = ({ address }) => { + const otherContract = useContract(address, otherContractMetadata); + const getOtherSub = useCallSubscription(otherContract, 'get', [], { + defaultCaller: true, + }); + + return ( + +

+ {otherContractMetadata.contract.name.toUpperCase()} +

+ +

+ Flipped:{' '} + + {pickDecoded(getOtherSub.result)?.toString()} + +

+
+ ); +}; diff --git a/basic_contract_caller/frontend/src/assets/basic_contract_caller.json b/basic_contract_caller/frontend/src/assets/basic_contract_caller.json new file mode 100644 index 00000000..ca8feda4 --- /dev/null +++ b/basic_contract_caller/frontend/src/assets/basic_contract_caller.json @@ -0,0 +1,446 @@ +{ + "source": { + "hash": "0x116670008181c58c5b65ea9c97a22b2a5eb205372a9428c6ee4560787edd1dbd", + "language": "ink! 4.2.0", + "compiler": "rustc 1.70.0", + "build_info": { + "build_mode": "Release", + "cargo_contract_version": "2.2.1", + "rust_toolchain": "stable-x86_64-apple-darwin", + "wasm_opt_settings": { + "keep_debug_symbols": false, + "optimization_passes": "Z" + } + } + }, + "contract": { + "name": "basic_contract_caller", + "version": "4.2.0", + "authors": [ + "Parity Technologies " + ] + }, + "spec": { + "constructors": [ + { + "args": [ + { + "label": "other_contract_code_hash", + "type": { + "displayName": [ + "Hash" + ], + "type": 3 + } + } + ], + "default": false, + "docs": [ + "In order to use the `OtherContract` we first need to **instantiate** it.", + "", + "To do this we will use the uploaded `code_hash` of `OtherContract`." + ], + "label": "new", + "payable": false, + "returnType": { + "displayName": [ + "ink_primitives", + "ConstructorResult" + ], + "type": 4 + }, + "selector": "0x9bae9d5e" + } + ], + "docs": [], + "environment": { + "accountId": { + "displayName": [ + "AccountId" + ], + "type": 0 + }, + "balance": { + "displayName": [ + "Balance" + ], + "type": 10 + }, + "blockNumber": { + "displayName": [ + "BlockNumber" + ], + "type": 12 + }, + "chainExtension": { + "displayName": [ + "ChainExtension" + ], + "type": 13 + }, + "hash": { + "displayName": [ + "Hash" + ], + "type": 3 + }, + "maxEventTopics": 4, + "timestamp": { + "displayName": [ + "Timestamp" + ], + "type": 11 + } + }, + "events": [], + "lang_error": { + "displayName": [ + "ink", + "LangError" + ], + "type": 6 + }, + "messages": [ + { + "args": [], + "default": false, + "docs": [ + " Using the `ContractRef` we can call all the messages of the `OtherContract` as", + " if they were normal Rust methods (because at the end of the day, they", + " are!)." + ], + "label": "flip_and_get", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 7 + }, + "selector": "0x2e233661" + }, + { + "args": [], + "default": false, + "docs": [ + " Get the address of the other contract after it has been instantiated. We can", + " use this so we can call the other contract on the frontend." + ], + "label": "other", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 9 + }, + "selector": "0x96396e0f" + } + ] + }, + "storage": { + "root": { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x00000000", + "ty": 0 + } + }, + "name": "account_id" + } + ], + "name": "CallBuilder" + } + }, + "name": "inner" + } + ], + "name": "OtherContractRef" + } + }, + "name": "other_contract" + } + ], + "name": "BasicContractCaller" + } + }, + "root_key": "0x00000000" + } + }, + "types": [ + { + "id": 0, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 1, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "AccountId" + ] + } + }, + { + "id": 1, + "type": { + "def": { + "array": { + "len": 32, + "type": 2 + } + } + } + }, + { + "id": 2, + "type": { + "def": { + "primitive": "u8" + } + } + }, + { + "id": 3, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 1, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "Hash" + ] + } + }, + { + "id": 4, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 5 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 6 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 5 + }, + { + "name": "E", + "type": 6 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 5, + "type": { + "def": { + "tuple": [] + } + } + }, + { + "id": 6, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 1, + "name": "CouldNotReadInput" + } + ] + } + }, + "path": [ + "ink_primitives", + "LangError" + ] + } + }, + { + "id": 7, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 8 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 6 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 8 + }, + { + "name": "E", + "type": 6 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 8, + "type": { + "def": { + "primitive": "bool" + } + } + }, + { + "id": 9, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 0 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 6 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 0 + }, + { + "name": "E", + "type": 6 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 10, + "type": { + "def": { + "primitive": "u128" + } + } + }, + { + "id": 11, + "type": { + "def": { + "primitive": "u64" + } + } + }, + { + "id": 12, + "type": { + "def": { + "primitive": "u32" + } + } + }, + { + "id": 13, + "type": { + "def": { + "variant": {} + }, + "path": [ + "ink_env", + "types", + "NoChainExtension" + ] + } + } + ], + "version": "4" +} \ No newline at end of file diff --git a/basic_contract_caller/frontend/src/assets/other_contract.json b/basic_contract_caller/frontend/src/assets/other_contract.json new file mode 100644 index 00000000..3c05b931 --- /dev/null +++ b/basic_contract_caller/frontend/src/assets/other_contract.json @@ -0,0 +1,431 @@ +{ + "source": { + "hash": "0x8b9fdab59f82fc96ba8f8bba270e706a3900ec4fe9c92a249263f3fb63f8cb58", + "language": "ink! 4.2.0", + "compiler": "rustc 1.70.0", + "build_info": { + "build_mode": "Release", + "cargo_contract_version": "2.2.1", + "rust_toolchain": "stable-x86_64-apple-darwin", + "wasm_opt_settings": { + "keep_debug_symbols": false, + "optimization_passes": "Z" + } + } + }, + "contract": { + "name": "other_contract", + "version": "4.2.0", + "authors": [ + "Parity Technologies " + ] + }, + "spec": { + "constructors": [ + { + "args": [ + { + "label": "init_value", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "default": false, + "docs": [], + "label": "new", + "payable": false, + "returnType": { + "displayName": [ + "ink_primitives", + "ConstructorResult" + ], + "type": 1 + }, + "selector": "0x9bae9d5e" + } + ], + "docs": [], + "environment": { + "accountId": { + "displayName": [ + "AccountId" + ], + "type": 6 + }, + "balance": { + "displayName": [ + "Balance" + ], + "type": 9 + }, + "blockNumber": { + "displayName": [ + "BlockNumber" + ], + "type": 12 + }, + "chainExtension": { + "displayName": [ + "ChainExtension" + ], + "type": 13 + }, + "hash": { + "displayName": [ + "Hash" + ], + "type": 10 + }, + "maxEventTopics": 4, + "timestamp": { + "displayName": [ + "Timestamp" + ], + "type": 11 + } + }, + "events": [], + "lang_error": { + "displayName": [ + "ink", + "LangError" + ], + "type": 3 + }, + "messages": [ + { + "args": [], + "default": false, + "docs": [], + "label": "flip", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 1 + }, + "selector": "0x633aa551" + }, + { + "args": [], + "default": false, + "docs": [], + "label": "get", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 4 + }, + "selector": "0x2f865bd9" + }, + { + "args": [], + "default": false, + "docs": [], + "label": "account_id", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 5 + }, + "selector": "0x2be79821" + } + ] + }, + "storage": { + "root": { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x00000000", + "ty": 0 + } + }, + "name": "value" + } + ], + "name": "OtherContract" + } + }, + "root_key": "0x00000000" + } + }, + "types": [ + { + "id": 0, + "type": { + "def": { + "primitive": "bool" + } + } + }, + { + "id": 1, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 2 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 3 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 2 + }, + { + "name": "E", + "type": 3 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 2, + "type": { + "def": { + "tuple": [] + } + } + }, + { + "id": 3, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 1, + "name": "CouldNotReadInput" + } + ] + } + }, + "path": [ + "ink_primitives", + "LangError" + ] + } + }, + { + "id": 4, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 0 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 3 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 0 + }, + { + "name": "E", + "type": 3 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 5, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 6 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 3 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 6 + }, + { + "name": "E", + "type": 3 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 6, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 7, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "AccountId" + ] + } + }, + { + "id": 7, + "type": { + "def": { + "array": { + "len": 32, + "type": 8 + } + } + } + }, + { + "id": 8, + "type": { + "def": { + "primitive": "u8" + } + } + }, + { + "id": 9, + "type": { + "def": { + "primitive": "u128" + } + } + }, + { + "id": 10, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 7, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "Hash" + ] + } + }, + { + "id": 11, + "type": { + "def": { + "primitive": "u64" + } + } + }, + { + "id": 12, + "type": { + "def": { + "primitive": "u32" + } + } + }, + { + "id": 13, + "type": { + "def": { + "variant": {} + }, + "path": [ + "ink_env", + "types", + "NoChainExtension" + ] + } + } + ], + "version": "4" +} \ No newline at end of file diff --git a/basic_contract_caller/frontend/src/constants.ts b/basic_contract_caller/frontend/src/constants.ts new file mode 100644 index 00000000..54cc8400 --- /dev/null +++ b/basic_contract_caller/frontend/src/constants.ts @@ -0,0 +1,2 @@ +export const BASIC_CONTRACT_ROCOCO_ADDRESS = + '5EnufwqqxnkWT6hc1LgjYWQGUsqQCtcr5192K2HuQJtRJgCi'; diff --git a/basic_contract_caller/frontend/src/main.tsx b/basic_contract_caller/frontend/src/main.tsx new file mode 100644 index 00000000..2ce2c515 --- /dev/null +++ b/basic_contract_caller/frontend/src/main.tsx @@ -0,0 +1,27 @@ +import App from './App.tsx'; +import './Global.css'; +import metadata from './assets/basic_contract_caller.json'; +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import 'ui/style.css'; +import { UseInkProvider } from 'useink'; +import { RococoContractsTestnet } from 'useink/chains'; +import { NotificationsProvider } from 'useink/notifications'; + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + + + + + , +); diff --git a/basic_contract_caller/frontend/src/vite-env.d.ts b/basic_contract_caller/frontend/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/basic_contract_caller/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/basic_contract_caller/frontend/tailwind.config.js b/basic_contract_caller/frontend/tailwind.config.js new file mode 100644 index 00000000..c120a39a --- /dev/null +++ b/basic_contract_caller/frontend/tailwind.config.js @@ -0,0 +1,2 @@ +import config from '../../ui/tailwind.config'; +export default config; \ No newline at end of file diff --git a/basic_contract_caller/frontend/tsconfig.json b/basic_contract_caller/frontend/tsconfig.json new file mode 100644 index 00000000..a7fc6fbf --- /dev/null +++ b/basic_contract_caller/frontend/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/basic_contract_caller/frontend/tsconfig.node.json b/basic_contract_caller/frontend/tsconfig.node.json new file mode 100644 index 00000000..42872c59 --- /dev/null +++ b/basic_contract_caller/frontend/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/basic_contract_caller/frontend/vite.config.ts b/basic_contract_caller/frontend/vite.config.ts new file mode 100644 index 00000000..4e7004eb --- /dev/null +++ b/basic_contract_caller/frontend/vite.config.ts @@ -0,0 +1,7 @@ +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/package.json b/package.json index 18650445..955eda91 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "lint:fix": "pnpm lint --apply-unsafe", "build:ui": "pnpm --filter ui build", "flipper": "pnpm --filter ui dev & pnpm --filter flipper dev", - "incrementer": "pnpm --filter ui dev & pnpm --filter incrementer dev" + "incrementer": "pnpm --filter ui dev & pnpm --filter incrementer dev", + "basic_contract_caller": "pnpm --filter ui dev & pnpm --filter basic_contract_caller dev" }, "packages": [ "ui", @@ -21,7 +22,7 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "useink": "^1.5.1" + "useink": "^1.7.5" }, "devDependencies": { "tailwindcss": "^3.3.2", diff --git a/ui/src/Accounts/Accounts.tsx b/ui/src/Accounts/Accounts.tsx index 8c9fd4e8..183c686b 100644 --- a/ui/src/Accounts/Accounts.tsx +++ b/ui/src/Accounts/Accounts.tsx @@ -15,7 +15,7 @@ export const Accounts: React.FC = ({ className }) => { return (
@@ -28,7 +28,7 @@ export const Accounts: React.FC = ({ className }) => {
= ({ ...rest }) => { const classes = classNames( - 'bg-brand-900 hover:opacity-80 transition ease-in-out px-6 py-2 border-none disabled:text-opacity-70', - 'text-base tracking-wide font-semibold rounded-full disabled:opacity-50 disabled:hover:bg-opacity-50', + 'bg-brand-900 hover:bg-brand-800 transition ease-in-out px-6 py-2 border-none', + 'text-base tracking-wide font-semibold rounded-full disabled:bg-brand-450', 'focus:ring-none disabled:cursor-not-allowed focus:outline-none focus:ring-0 focus:ring-offset-0 text-white', className, ); diff --git a/ui/src/Link/Link.tsx b/ui/src/Link/Link.tsx new file mode 100644 index 00000000..347d5cb9 --- /dev/null +++ b/ui/src/Link/Link.tsx @@ -0,0 +1,26 @@ +import classNames from 'classnames'; +import React, { + AnchorHTMLAttributes, + DetailedHTMLProps, + PropsWithChildren, +} from 'react'; + +type LinkHTMLProps = DetailedHTMLProps< + AnchorHTMLAttributes, + HTMLAnchorElement +>; + +type LinkProps = PropsWithChildren; + +export const Link: React.FC = ({ children, className, ...rest }) => { + const classes = classNames( + 'underline text-sm text-brand-300 font-semibold transition duration-25 hover:text-brand-450', + className, + ); + + return ( + + {children} + + ); +}; diff --git a/ui/src/Link/index.ts b/ui/src/Link/index.ts new file mode 100644 index 00000000..3db78f51 --- /dev/null +++ b/ui/src/Link/index.ts @@ -0,0 +1 @@ +export * from './Link'; diff --git a/ui/src/NumberInput/NumberInput.tsx b/ui/src/NumberInput/NumberInput.tsx index f3ae7cfd..535f104d 100644 --- a/ui/src/NumberInput/NumberInput.tsx +++ b/ui/src/NumberInput/NumberInput.tsx @@ -13,12 +13,11 @@ type Props = ClassNameable & { }; const COMMON_CLASSES = [ - 'bg-brand-500 text-white border-none focuse:outline-none focus-visible:outline-none', - 'focus:outline-none disabled:text-white/80 py-4 flex items-center justify-center', + 'bg-brand-500 disabled:bg-brand-450 text-white border-none focuse:outline-none focus-visible:outline-none', + 'focus:outline-none disabled:text-white/80 py-4 flex items-center justify-center disabled:cursor-not-allowed', ].join(' '); -const BUTTON_CLASSES = - 'hover:bg-brand-800 disabled:bg-brand-450 disabled:cursor-not-allowed'; +const BUTTON_CLASSES = 'hover:bg-brand-900'; export const NumberInput: React.FC = ({ value, @@ -52,7 +51,7 @@ export const NumberInput: React.FC = ({