├── .husky └── pre-commit ├── public ├── robots.txt ├── icon-192x192.png ├── icon-512x512.png └── laika-labs.svg ├── src ├── constants │ └── api.ts ├── vite-env.d.ts ├── lib │ ├── utils.ts │ ├── codegens │ │ └── evm │ │ │ ├── index.ts │ │ │ ├── js-ethers.ts │ │ │ └── js-web3.ts │ └── collections.ts ├── routes │ ├── index.tsx │ ├── -components │ │ └── EVM │ │ │ ├── ContractRequest │ │ │ ├── ResponsePane │ │ │ │ ├── ReadResponse.tsx │ │ │ │ ├── WriteResponse.tsx │ │ │ │ └── index.tsx │ │ │ ├── RequestPane │ │ │ │ ├── TabsButton.tsx │ │ │ │ ├── ReadTab │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── ReadMethod.tsx │ │ │ │ ├── WriteTab │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── WriteMethod.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── StateTab.tsx │ │ │ │ └── ABITab.tsx │ │ │ ├── index.tsx │ │ │ └── SaveContractDialog │ │ │ │ ├── index.tsx │ │ │ │ └── CollectionTreePicker.tsx │ │ │ ├── Documentation │ │ │ ├── DocumentContent │ │ │ │ ├── ContentABI.tsx │ │ │ │ ├── FunctionContent.tsx │ │ │ │ └── index.tsx │ │ │ └── DocumentList.tsx │ │ │ ├── Collections │ │ │ ├── NewRequest │ │ │ │ ├── index.tsx │ │ │ │ └── ChainExplorerDialog.tsx │ │ │ ├── Folder │ │ │ │ ├── Rename.tsx │ │ │ │ ├── SmartContract.tsx │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ │ ├── Welcome.tsx │ │ │ ├── Toolbar │ │ │ ├── UnitConverter.tsx │ │ │ ├── index.tsx │ │ │ └── CodeSnippet.tsx │ │ │ └── index.tsx │ └── __root.tsx ├── components │ ├── ui │ │ ├── skeleton.tsx │ │ ├── label.tsx │ │ ├── sonner.tsx │ │ ├── textarea.tsx │ │ ├── input.tsx │ │ ├── badge.tsx │ │ ├── popover.tsx │ │ ├── tabs.tsx │ │ ├── card.tsx │ │ ├── tooltip.tsx │ │ ├── button.tsx │ │ ├── table.tsx │ │ ├── alert-dialog.tsx │ │ ├── form.tsx │ │ ├── dialog.tsx │ │ ├── command.tsx │ │ └── dropdown-menu.tsx │ ├── Announcement.tsx │ ├── Header.tsx │ ├── Footer.tsx │ ├── Sidenav.tsx │ ├── ThemeDropdown.tsx │ ├── ThemeProvider.tsx │ └── EVMProvider.tsx ├── icons │ └── ethereum.svg ├── store │ ├── docs.ts │ ├── responses.ts │ ├── chains.ts │ └── tabs.ts ├── hooks │ ├── useCopyToClipboard.ts │ └── useMediaQuery.ts ├── main.tsx ├── routeTree.gen.ts └── styles │ └── index.css ├── .lintstagedrc ├── tsconfig.json ├── .gitignore ├── .prettierrc ├── components.json ├── tsconfig.node.json ├── eslint.config.js ├── tsconfig.app.json ├── LICENSE ├── index.html ├── .cursor └── rules │ ├── component-structure.mdc │ ├── import-organization.mdc │ ├── typescript-conventions.mdc │ ├── project-structure.mdc │ └── ui-component-conventions.mdc ├── README.md ├── package.json ├── vite.config.ts └── CLAUDE.md /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | bunx lint-staged -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /src/constants/api.ts: -------------------------------------------------------------------------------- 1 | export const getabi: Record = {} 2 | -------------------------------------------------------------------------------- /public/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laika-labs/laika/HEAD/public/icon-192x192.png -------------------------------------------------------------------------------- /public/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laika-labs/laika/HEAD/public/icon-512x512.png -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "**/*.{js,jsx,ts,tsx}": [ 3 | "eslint", 4 | "prettier --write" 5 | ], 6 | "**/*.json": [ 7 | "prettier --write" 8 | ] 9 | } -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | 3 | import { EVM } from './-components/EVM' 4 | 5 | export const Route = createFileRoute('/')({ 6 | component: EVM, 7 | }) 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) { 4 | return
5 | } 6 | 7 | export { Skeleton } 8 | -------------------------------------------------------------------------------- /src/lib/codegens/evm/index.ts: -------------------------------------------------------------------------------- 1 | import { generate as jsEthers } from './js-ethers' 2 | import { generate as jsWeb3 } from './js-web3' 3 | 4 | export const codegens = [ 5 | { name: 'JS - Ethers.js (v6)', language: 'javascript', generate: jsEthers }, 6 | { name: 'JS - Web3.js (v4)', language: 'javascript', generate: jsWeb3 }, 7 | ] 8 | -------------------------------------------------------------------------------- /src/icons/ethereum.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Announcement.tsx: -------------------------------------------------------------------------------- 1 | export function Announcement() { 2 | return ( 3 |
4 | Laika just got rewrote from ground up, But you can access the legacy at{' '} 5 | 6 | https://legacy.getlaika.app 7 | 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/store/docs.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand' 2 | import { persist } from 'zustand/middleware' 3 | 4 | export const useEVMDocsStore = create<{ 5 | activeDocumentId: string | null 6 | setActiveDocument: (id: string | null) => void 7 | }>()( 8 | persist( 9 | (set) => ({ 10 | activeDocumentId: null, 11 | setActiveDocument: (id) => set({ activeDocumentId: id }), 12 | }), 13 | { 14 | name: 'evmDocs', 15 | }, 16 | ), 17 | ) 18 | -------------------------------------------------------------------------------- /src/routes/-components/EVM/ContractRequest/ResponsePane/ReadResponse.tsx: -------------------------------------------------------------------------------- 1 | import type { Response } from '@/store/responses' 2 | 3 | export function ReadResponse({ response }: { response: Response }) { 4 | return ( 5 |
6 |

7 | CALLED TO {response.functionName} at [ChainID={response.chainId} {response.address}] 8 |

9 |
{response.result}
10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeDropdown } from './ThemeDropdown' 2 | import laikaLogo from '/laika-labs.svg' 3 | 4 | export function Header() { 5 | return ( 6 |
7 | 8 | Laika Labs logo 9 | Laika 10 | 11 | 12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # Environment variables 27 | .env* 28 | 29 | # Ignore TanStack Router temporary files 30 | .tanstack/tmp/ 31 | 32 | # Claude Settings 33 | .claude/settings.local.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false, 4 | "singleQuote": true, 5 | "printWidth": 120, 6 | "importOrder": [ 7 | "", 8 | "", 9 | "^(react/(.*)$)|^(react$)", 10 | "", 11 | "", 12 | "^@/(.*)$", 13 | "", 14 | "^[./]" 15 | ], 16 | "importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"], 17 | "importOrderTypeScriptVersion": "5.9.2", 18 | "plugins": ["@ianvs/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"] 19 | } 20 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/styles/index.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "iconLibrary": "lucide", 14 | "aliases": { 15 | "components": "@/components", 16 | "utils": "@/lib/utils", 17 | "ui": "@/components/ui", 18 | "lib": "@/lib", 19 | "hooks": "@/hooks" 20 | }, 21 | "registries": {} 22 | } 23 | -------------------------------------------------------------------------------- /src/hooks/useCopyToClipboard.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useState } from 'react' 2 | 3 | export function useCopyToClipboard(): [string | null, (text: string) => Promise] { 4 | const [copiedText, setCopiedText] = useState(null) 5 | 6 | const copy = useCallback(async (text: string) => { 7 | if (!navigator?.clipboard) { 8 | return false 9 | } 10 | 11 | try { 12 | await navigator.clipboard.writeText(text) 13 | setCopiedText(text) 14 | return true 15 | } catch { 16 | setCopiedText(null) 17 | return false 18 | } 19 | }, []) 20 | 21 | return [copiedText, copy] 22 | } 23 | -------------------------------------------------------------------------------- /src/store/responses.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand' 2 | 3 | export interface Response { 4 | type: 'WRITE' | 'READ' 5 | functionName: string 6 | chainId: number 7 | address: `0x${string}` 8 | result?: string 9 | txHash?: `0x${string}` 10 | error?: Error 11 | } 12 | 13 | export const useResponseStore = create<{ 14 | responses: Response[] 15 | pushResponse: (response: Response) => void 16 | clearResponses: () => void 17 | }>((set) => ({ 18 | responses: [], 19 | pushResponse: (response) => set((state) => ({ responses: [...state.responses, response] })), 20 | clearResponses: () => set(() => ({ responses: [] })), 21 | })) 22 | -------------------------------------------------------------------------------- /src/routes/-components/EVM/ContractRequest/RequestPane/TabsButton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | export function TabsButton({ children, className, ...props }: React.ComponentProps<'button'>) { 4 | return ( 5 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import * as LabelPrimitive from '@radix-ui/react-label' 3 | 4 | import { cn } from '@/lib/utils' 5 | 6 | function Label({ className, ...props }: React.ComponentProps) { 7 | return ( 8 | 16 | ) 17 | } 18 | 19 | export { Label } 20 | -------------------------------------------------------------------------------- /src/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | import { Toaster as Sonner, type ToasterProps } from 'sonner' 2 | 3 | import { useTheme } from '../ThemeProvider' 4 | 5 | const Toaster = ({ ...props }: ToasterProps) => { 6 | const { resolvedTheme } = useTheme() 7 | 8 | return ( 9 | 21 | ) 22 | } 23 | 24 | export { Toaster } 25 | -------------------------------------------------------------------------------- /src/routes/-components/EVM/Documentation/DocumentContent/ContentABI.tsx: -------------------------------------------------------------------------------- 1 | import type { EVMABIMethod } from '@/store/collections' 2 | 3 | import { FunctionContent } from './FunctionContent' 4 | 5 | interface ABIProps { 6 | contractId: string 7 | title: string 8 | abi: EVMABIMethod[] 9 | } 10 | 11 | export function ContentABI({ title, abi, contractId }: ABIProps) { 12 | return ( 13 | <> 14 |

{title}

15 | {abi.map((event) => { 16 | return 17 | })} 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2023", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "verbatimModuleSyntax": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "erasableSyntaxOnly": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "noUncheckedSideEffectImports": true 23 | }, 24 | "include": ["vite.config.ts"] 25 | } 26 | -------------------------------------------------------------------------------- /src/hooks/useMediaQuery.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | export function useMediaQuery(query: string): boolean { 4 | const [matches, setMatches] = useState(() => { 5 | if (typeof window !== 'undefined') { 6 | return window.matchMedia(query).matches 7 | } 8 | return false 9 | }) 10 | 11 | useEffect(() => { 12 | if (typeof window === 'undefined') return 13 | 14 | const mediaQuery = window.matchMedia(query) 15 | setMatches(mediaQuery.matches) 16 | 17 | const handler = (event: MediaQueryListEvent) => { 18 | setMatches(event.matches) 19 | } 20 | 21 | mediaQuery.addEventListener('change', handler) 22 | return () => mediaQuery.removeEventListener('change', handler) 23 | }, [query]) 24 | 25 | return matches 26 | } 27 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import pluginQuery from '@tanstack/eslint-plugin-query' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import { defineConfig, globalIgnores } from 'eslint/config' 6 | import globals from 'globals' 7 | import tseslint from 'typescript-eslint' 8 | 9 | export default defineConfig([ 10 | globalIgnores(['dist']), 11 | ...pluginQuery.configs['flat/recommended'], 12 | { 13 | files: ['**/*.{ts,tsx}'], 14 | extends: [ 15 | js.configs.recommended, 16 | tseslint.configs.recommended, 17 | reactHooks.configs['recommended-latest'], 18 | reactRefresh.configs.vite, 19 | ], 20 | languageOptions: { 21 | ecmaVersion: 2020, 22 | globals: globals.browser, 23 | }, 24 | }, 25 | ]) 26 | -------------------------------------------------------------------------------- /src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) { 6 | return ( 7 |