├── .env.example ├── .eslintrc.json ├── public ├── favicon.ico ├── goldrush-logo.png ├── vercel.svg ├── thirteen.svg ├── next.svg └── covalent.svg ├── static └── grk-tx-banner.png ├── postcss.config.js ├── types ├── nav.ts └── shared.ts ├── next.config.mjs ├── lib ├── fonts.ts ├── utils.ts ├── store.tsx └── svg.tsx ├── components.json ├── components ├── theme-provider.tsx ├── tailwind-indicator.tsx ├── theme-toggle.tsx ├── ui │ ├── label.tsx │ ├── toaster.tsx │ ├── input.tsx │ ├── popover.tsx │ ├── tabs.tsx │ ├── card.tsx │ ├── button.tsx │ ├── dialog.tsx │ ├── use-toast.ts │ ├── alert-dialog.tsx │ ├── toast.tsx │ ├── command.tsx │ └── select.tsx ├── key-dialog.tsx ├── footer.tsx ├── main-nav.tsx ├── site-header.tsx ├── icons.tsx └── chain │ └── ChainSelector.tsx ├── config └── site.ts ├── app ├── settings │ ├── layout.tsx │ └── page.tsx ├── tx │ └── [chain] │ │ └── [tx_hash] │ │ ├── layout.tsx │ │ └── page.tsx ├── layout.tsx └── page.tsx ├── .gitignore ├── goldrush.config.ts ├── tsconfig.json ├── prettier.config.js ├── LICENSE ├── package.json ├── styles └── globals.css ├── tailwind.config.ts └── README.md /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_GOLDRUSH_API_KEY 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/covalenthq/goldrush-tx-receipt-ui/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/goldrush-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/covalenthq/goldrush-tx-receipt-ui/HEAD/public/goldrush-logo.png -------------------------------------------------------------------------------- /static/grk-tx-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/covalenthq/goldrush-tx-receipt-ui/HEAD/static/grk-tx-banner.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /types/nav.ts: -------------------------------------------------------------------------------- 1 | export interface NavItem { 2 | title: string 3 | href?: string 4 | disabled?: boolean 5 | external?: boolean 6 | } 7 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: false, 5 | } 6 | 7 | export default nextConfig 8 | -------------------------------------------------------------------------------- /lib/fonts.ts: -------------------------------------------------------------------------------- 1 | import { JetBrains_Mono as FontMono, Inter as FontSans } from "next/font/google" 2 | 3 | export const fontSans = FontSans({ 4 | subsets: ["latin"], 5 | variable: "--font-sans", 6 | }) 7 | 8 | export const fontMono = FontMono({ 9 | subsets: ["latin"], 10 | variable: "--font-mono", 11 | }) 12 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "tailwind": { 5 | "config": "tailwind.config.ts", 6 | "css": "app/globals.css", 7 | "baseColor": "slate", 8 | "cssVariables": true 9 | }, 10 | "rsc": false, 11 | "aliases": { 12 | "utils": "@/lib/utils", 13 | "components": "@/components" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { ThemeProvider as NextThemesProvider } from "next-themes" 5 | import { type ThemeProviderProps } from "next-themes/dist/types" 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /config/site.ts: -------------------------------------------------------------------------------- 1 | export type SiteConfig = typeof siteConfig 2 | 3 | export const siteConfig = { 4 | name: "GoldRush Transaction Receipt UI", 5 | description: 6 | "Beautifully designed components built with Radix UI and Tailwind CSS.", 7 | mainNav: [], 8 | links: { 9 | github: "https://github.com/covalenthq/goldrush-tx-receipt-ui", 10 | docs: "https://ui.shadcn.com", 11 | settings: "/settings", 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /app/settings/layout.tsx: -------------------------------------------------------------------------------- 1 | import "@/styles/globals.css" 2 | import { Flex} from '@radix-ui/themes'; 3 | import '@radix-ui/themes/styles.css'; 4 | 5 | interface DashboardLayoutProps { 6 | children: React.ReactNode 7 | } 8 | 9 | export default function DashboardLayout({ children }: DashboardLayoutProps) { 10 | 11 | return ( 12 | 13 | {children} 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /app/tx/[chain]/[tx_hash]/layout.tsx: -------------------------------------------------------------------------------- 1 | import "@/styles/globals.css" 2 | import { Flex } from "@radix-ui/themes" 3 | 4 | import "@radix-ui/themes/styles.css" 5 | 6 | interface DashboardLayoutProps { 7 | children: React.ReactNode 8 | } 9 | 10 | export default function DashboardLayout({ children }: DashboardLayoutProps) { 11 | return ( 12 | 16 | {children} 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/tailwind-indicator.tsx: -------------------------------------------------------------------------------- 1 | export function TailwindIndicator() { 2 | if (process.env.NODE_ENV === "production") return null 3 | 4 | return ( 5 |
6 |
xs
7 |
sm
8 |
md
9 |
lg
10 |
xl
11 |
2xl
12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /components/theme-toggle.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { Moon, Sun } from "lucide-react" 5 | import { useTheme } from "next-themes" 6 | 7 | import { Button } from "@/components/ui/button" 8 | 9 | export function ThemeToggle() { 10 | const { setTheme, theme } = useTheme() 11 | 12 | return ( 13 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as LabelPrimitive from "@radix-ui/react-label" 3 | import { cn } from "@/lib/utils" 4 | 5 | const labelVariants = () => 6 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 7 | 8 | const Label = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, ...props }, ref) => ( 12 | 17 | )) 18 | Label.displayName = LabelPrimitive.Root.displayName 19 | 20 | export { Label } 21 | -------------------------------------------------------------------------------- /goldrush.config.ts: -------------------------------------------------------------------------------- 1 | import { type GRKKitType } from "@/types/shared"; 2 | 3 | export const GRKKit: GRKKitType = { 4 | brand: { 5 | title: "GoldRush", 6 | subtitle: "Transaction Receipt UI", 7 | logo_url: "/goldrush-logo.png", 8 | github: "https://github.com/covalenthq/goldrush-tx-receipt-ui" 9 | }, 10 | theme: { 11 | borderRadius: 6, 12 | colors: { 13 | dark: { 14 | primary: "#FF4C8B", 15 | background: "#000426", 16 | foreground: "#FFFFFF", 17 | secondary: "#868E96", 18 | }, 19 | light: { 20 | primary: "#FF4C8B", 21 | background: "#FFFFFF", 22 | foreground: "#1C2024", 23 | secondary: "#868E96", 24 | }, 25 | }, 26 | mode: "dark", 27 | } 28 | }; 29 | 30 | export default GRKKit; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "noEmit": true, 9 | "incremental": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "baseUrl": ".", 17 | "paths": { 18 | "@/*": ["./*"] 19 | }, 20 | "plugins": [ 21 | { 22 | "name": "next" 23 | } 24 | ], 25 | "strictNullChecks": true 26 | }, 27 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 28 | "exclude": ["node_modules"] 29 | } 30 | -------------------------------------------------------------------------------- /components/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Toast, 3 | ToastClose, 4 | ToastDescription, 5 | ToastProvider, 6 | ToastTitle, 7 | ToastViewport, 8 | } from "@/components/ui/toast" 9 | import { useToast } from "@/components/ui/use-toast" 10 | 11 | export function Toaster() { 12 | const { toasts } = useToast() 13 | 14 | return ( 15 | 16 | {toasts.map(function ({ id, title, description, action, ...props }) { 17 | return ( 18 | 19 |
20 | {title && {title}} 21 | {description && ( 22 | {description} 23 | )} 24 |
25 | {action} 26 | 27 |
28 | ) 29 | })} 30 | 31 |
32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Config} */ 2 | module.exports = { 3 | endOfLine: "lf", 4 | semi: false, 5 | singleQuote: false, 6 | tabWidth: 2, 7 | trailingComma: "es5", 8 | importOrder: [ 9 | "^(react/(.*)$)|^(react$)", 10 | "^(next/(.*)$)|^(next$)", 11 | "", 12 | "", 13 | "^types$", 14 | "^@/types/(.*)$", 15 | "^@/config/(.*)$", 16 | "^@/lib/(.*)$", 17 | "^@/hooks/(.*)$", 18 | "^@/components/ui/(.*)$", 19 | "^@/components/(.*)$", 20 | "^@/styles/(.*)$", 21 | "^@/app/(.*)$", 22 | "", 23 | "^[./]", 24 | ], 25 | importOrderSeparation: false, 26 | importOrderSortSpecifiers: true, 27 | importOrderBuiltinModulesToTop: true, 28 | importOrderParserPlugins: ["typescript", "jsx", "decorators-legacy"], 29 | importOrderMergeDuplicateImports: true, 30 | importOrderCombineTypeAndValueImports: true, 31 | plugins: ["@ianvs/prettier-plugin-sort-imports"], 32 | } 33 | -------------------------------------------------------------------------------- /app/tx/[chain]/[tx_hash]/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useRouter } from "next/navigation" 4 | import { Chain } from "@covalenthq/client-sdk" 5 | import { TransactionReceipt } from "@covalenthq/goldrush-kit" 6 | import { Flex } from "@radix-ui/themes" 7 | 8 | import { Button } from "@/components/ui/button" 9 | 10 | export default function TX({ 11 | params, 12 | }: { 13 | params: { chain: Chain; tx_hash: string } 14 | }) { 15 | const router = useRouter() 16 | 17 | return ( 18 |
19 |
20 | 24 |
25 | 26 | { 29 | router.back() 30 | }} 31 | > 32 | 33 | 34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | } 22 | ) 23 | Input.displayName = "Input" 24 | 25 | export { Input } -------------------------------------------------------------------------------- /components/key-dialog.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { GOLDRUSH_API_KEY } from "@/lib/utils" 4 | import { 5 | AlertDialog, 6 | AlertDialogAction, 7 | AlertDialogContent, 8 | AlertDialogDescription, 9 | AlertDialogFooter, 10 | AlertDialogHeader, 11 | AlertDialogTitle, 12 | } from "@/components/ui/alert-dialog" 13 | 14 | export const KeyDialog = () => { 15 | return ( 16 | 17 | 18 | 19 | Covalent API key not found. 20 | 21 | This template requires a Covalent API key. Please add your key to 22 | your environment variables file. 23 | 24 | 25 | 26 | 27 | Get API key 28 | 29 | 30 | 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /public/thirteen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /types/shared.ts: -------------------------------------------------------------------------------- 1 | import { Chain, ChainItem } from "@covalenthq/client-sdk" 2 | 3 | export interface GRKKitType { 4 | theme: { 5 | borderRadius: number 6 | colors: { 7 | dark: { 8 | primary: string 9 | background: string 10 | foreground: string 11 | secondary: string 12 | } 13 | light: { 14 | primary: string 15 | background: string 16 | foreground: string 17 | secondary: string 18 | } 19 | } 20 | mode: string 21 | } 22 | brand: { 23 | title: string 24 | subtitle: string 25 | logo_url: string 26 | github: string 27 | } 28 | chains?: Chain[] 29 | } 30 | 31 | export interface ChainSelectorProps { 32 | open: boolean 33 | value: string 34 | chainName: string 35 | busy: boolean 36 | allChains: { 37 | foundational: ChainItem[] 38 | frontier: ChainItem[] 39 | community: ChainItem[] 40 | } 41 | setValue: React.Dispatch> 42 | setOpen: React.Dispatch> 43 | setChainName: React.Dispatch> 44 | } 45 | -------------------------------------------------------------------------------- /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 | 8 | export const GOLDRUSH_API_KEY = process.env.NEXT_PUBLIC_GOLDRUSH_API_KEY 9 | 10 | export const COLORS = { 11 | "black": "#000000", 12 | "slate": "#64748b", 13 | "gray": "#6b7280", 14 | "zinc": "#71717a", 15 | "neutral": "#737373", 16 | "stone": "#78716c", 17 | "white": "#F4F3F2", 18 | "red": "#ef4444", 19 | "orange": "#f97316", 20 | "amber": "#f59e0b", 21 | "yellow": "#eab308", 22 | "lime": "#84cc16", 23 | "green": "#22c55e", 24 | "emerald": "#10b981", 25 | "teal": "#14b8a6", 26 | "cyan": "#06b6d4", 27 | "sky": "#0ea5e9", 28 | "blue": "#3b82f6", 29 | "indigo": "#6366f1", 30 | "violet": "#8b5cf6", 31 | "purple": "#a855f7", 32 | "fuchsia": "#d946ef", 33 | "pink": "#ec4899", 34 | "rose": "#f43f5e" 35 | } 36 | 37 | export const BORDER_RADIUS : { 38 | [key: string]: number 39 | } = { 40 | "None": 0, 41 | "Small": 2, 42 | "Medium": 6, 43 | "Large": 8, 44 | "Full": 9999 45 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Covalent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /components/footer.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { PoweredByGoldRush } from "@/lib/svg" 3 | 4 | export const Footer: React.FC = () => { 5 | return ( 6 | 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/ui/popover.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as PopoverPrimitive from "@radix-ui/react-popover" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Popover = PopoverPrimitive.Root 7 | 8 | const PopoverTrigger = PopoverPrimitive.Trigger 9 | 10 | const PopoverContent = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 14 | 15 | 25 | 26 | )) 27 | PopoverContent.displayName = PopoverPrimitive.Content.displayName 28 | 29 | export { Popover, PopoverTrigger, PopoverContent } 30 | -------------------------------------------------------------------------------- /components/main-nav.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import Link from "next/link" 3 | import kit from "@/goldrush.config" 4 | import { NavItem } from "@/types/nav" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | interface MainNavProps { 9 | items?: NavItem[] 10 | } 11 | 12 | export function MainNav({ items }: Readonly) { 13 | return ( 14 |
15 | 19 |
20 | {`GoldRush 25 |
26 | 27 |

28 | {kit.brand.title} 29 |
30 | {kit.brand.subtitle} 31 |

32 | 33 | {items?.length ? ( 34 | 51 | ) : null} 52 |
53 | ) 54 | } -------------------------------------------------------------------------------- /components/site-header.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link" 2 | 3 | import { buttonVariants } from "@/components/ui/button" 4 | import { Icons } from "@/components/icons" 5 | import { MainNav } from "@/components/main-nav" 6 | import { ThemeToggle } from "@/components/theme-toggle" 7 | import kit from "@/goldrush.config" 8 | 9 | export function Header() { 10 | return ( 11 |
12 |
13 | 14 |
15 | 44 |
45 |
46 |
47 | ) 48 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "goldrush-tx-receipt-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "lint:fix": "next lint --fix", 11 | "preview": "next build && next start", 12 | "typecheck": "tsc --noEmit", 13 | "format:write": "prettier --write \"**/*.{ts,tsx,mdx}\" --cache", 14 | "format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache" 15 | }, 16 | "dependencies": { 17 | "@covalenthq/client-sdk": "^2.2.1", 18 | "@covalenthq/goldrush-kit": "^1.0.2", 19 | "@radix-ui/react-alert-dialog": "^1.0.5", 20 | "@radix-ui/react-label": "^2.0.2", 21 | "@radix-ui/react-popover": "^1.0.7", 22 | "@radix-ui/react-select": "^2.0.0", 23 | "@radix-ui/react-slot": "^1.0.2", 24 | "@radix-ui/react-tabs": "^1.0.4", 25 | "@radix-ui/react-toast": "^1.1.5", 26 | "@radix-ui/themes": "^2.0.1", 27 | "@vercel/analytics": "^1.1.1", 28 | "class-variance-authority": "^0.7.0", 29 | "clsx": "^1.2.1", 30 | "cmdk": "^0.2.0", 31 | "lucide-react": "0.105.0-alpha.4", 32 | "next": "^14.2.24", 33 | "next-themes": "^0.2.1", 34 | "react": "^18", 35 | "react-dom": "^18", 36 | "sharp": "^0.32.6", 37 | "tailwind-merge": "^1.13.2", 38 | "tailwindcss-animate": "^1.0.6" 39 | }, 40 | "devDependencies": { 41 | "@ianvs/prettier-plugin-sort-imports": "^3.7.2", 42 | "@types/node": "^20", 43 | "@types/react": "^18", 44 | "@types/react-dom": "^18", 45 | "@typescript-eslint/parser": "^5.61.0", 46 | "autoprefixer": "^10.0.1", 47 | "eslint": "^8", 48 | "eslint-config-next": "14.1.0", 49 | "eslint-config-prettier": "^8.8.0", 50 | "eslint-plugin-react": "^7.32.2", 51 | "eslint-plugin-tailwindcss": "^3.13.0", 52 | "postcss": "^8", 53 | "prettier": "^2.8.8", 54 | "tailwindcss": "^3.3.0", 55 | "typescript": "^5" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 222.2 47.4% 11.2%; 9 | 10 | --muted: 210 40% 96.1%; 11 | --muted-foreground: 215.4 16.3% 46.9%; 12 | 13 | --popover: 0 0% 100%; 14 | --popover-foreground: 222.2 47.4% 11.2%; 15 | 16 | --border: 214.3 31.8% 91.4%; 17 | --input: 214.3 31.8% 91.4%; 18 | 19 | --card: 0 0% 100%; 20 | --card-foreground: 222.2 47.4% 11.2%; 21 | 22 | --primary: 222.2 47.4% 11.2%; 23 | --primary-foreground: 210 40% 98%; 24 | 25 | --secondary: 210 40% 96.1%; 26 | --secondary-foreground: 222.2 47.4% 11.2%; 27 | 28 | --accent: 210 40% 96.1%; 29 | --accent-foreground: 222.2 47.4% 11.2%; 30 | 31 | --destructive: 0 100% 50%; 32 | --destructive-foreground: 210 40% 98%; 33 | 34 | --ring: 215 20.2% 65.1%; 35 | 36 | --radius: 0.5rem; 37 | } 38 | 39 | .dark { 40 | --background: 224 71% 4%; 41 | --foreground: 213 31% 91%; 42 | 43 | --muted: 223 47% 11%; 44 | --muted-foreground: 215.4 16.3% 56.9%; 45 | 46 | --accent: 216 34% 17%; 47 | --accent-foreground: 210 40% 98%; 48 | 49 | --popover: 224 71% 4%; 50 | --popover-foreground: 215 20.2% 65.1%; 51 | 52 | --border: 216 34% 17%; 53 | --input: 216 34% 17%; 54 | 55 | --card: 224 71% 4%; 56 | --card-foreground: 213 31% 91%; 57 | 58 | --primary: 210 40% 98%; 59 | --primary-foreground: 222.2 47.4% 1.2%; 60 | 61 | --secondary: 222.2 47.4% 11.2%; 62 | --secondary-foreground: 210 40% 98%; 63 | 64 | --destructive: 0 63% 31%; 65 | --destructive-foreground: 210 40% 98%; 66 | 67 | --ring: 216 34% 17%; 68 | 69 | --radius: 0.5rem; 70 | } 71 | } 72 | 73 | @layer base { 74 | body { 75 | @apply bg-background-light dark:bg-background-dark text-foreground-light dark:text-foreground-dark; 76 | font-feature-settings: "rlig" 1, "calt" 1; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/store.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useState, type ReactNode } from "react" 2 | import kit from "@/goldrush.config" 3 | import { GoldRushProvider } from "@covalenthq/goldrush-kit" 4 | import { useTheme } from "next-themes" 5 | 6 | import { GOLDRUSH_API_KEY } from "./utils" 7 | 8 | interface TXContextType { 9 | txHash: string 10 | setTxHash: Function 11 | chains: any 12 | setChains: Function 13 | tableState: { [key: string]: boolean } 14 | setTableState: Function 15 | color: string 16 | setColor: Function 17 | setBorderRadius: Function 18 | borderRadius: string 19 | } 20 | 21 | export const TXContext = createContext({} as TXContextType) 22 | 23 | interface TXProviderProps { 24 | children: ReactNode 25 | } 26 | 27 | export const TXProvider: React.FC = ({ children }) => { 28 | const [txHash, setTxHash] = useState("") 29 | const [chains, setChains] = useState<[]>([]) 30 | const [tableState, setTableState] = useState({}) 31 | const [color, setColor] = useState( 32 | localStorage.getItem("color") ? localStorage.getItem("color") : "slate" 33 | ) 34 | const [borderRadius, setBorderRadius] = useState( 35 | localStorage.getItem("border") ? localStorage.getItem("border") : "medium" 36 | ) 37 | 38 | return ( 39 | 47 | 61 | {children} 62 | 63 | 64 | ) 65 | } 66 | -------------------------------------------------------------------------------- /components/ui/tabs.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as TabsPrimitive from "@radix-ui/react-tabs" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Tabs = TabsPrimitive.Root 7 | 8 | const TabsList = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, ...props }, ref) => ( 12 | 20 | )) 21 | TabsList.displayName = TabsPrimitive.List.displayName 22 | 23 | const TabsTrigger = React.forwardRef< 24 | React.ElementRef, 25 | React.ComponentPropsWithoutRef 26 | >(({ className, ...props }, ref) => ( 27 | 35 | )) 36 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName 37 | 38 | const TabsContent = React.forwardRef< 39 | React.ElementRef, 40 | React.ComponentPropsWithoutRef 41 | >(({ className, ...props }, ref) => ( 42 | 50 | )) 51 | TabsContent.displayName = TabsPrimitive.Content.displayName 52 | 53 | export { Tabs, TabsList, TabsTrigger, TabsContent } 54 | -------------------------------------------------------------------------------- /components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Card = React.forwardRef< 6 | HTMLDivElement, 7 | React.HTMLAttributes 8 | >(({ className, ...props }, ref) => ( 9 |
17 | )) 18 | Card.displayName = "Card" 19 | 20 | const CardHeader = React.forwardRef< 21 | HTMLDivElement, 22 | React.HTMLAttributes 23 | >(({ className, ...props }, ref) => ( 24 |
29 | )) 30 | CardHeader.displayName = "CardHeader" 31 | 32 | const CardTitle = React.forwardRef< 33 | HTMLParagraphElement, 34 | React.HTMLAttributes 35 | >(({ className, ...props }, ref) => ( 36 |

44 | )) 45 | CardTitle.displayName = "CardTitle" 46 | 47 | const CardDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 |

56 | )) 57 | CardDescription.displayName = "CardDescription" 58 | 59 | const CardContent = React.forwardRef< 60 | HTMLDivElement, 61 | React.HTMLAttributes 62 | >(({ className, ...props }, ref) => ( 63 |

64 | )) 65 | CardContent.displayName = "CardContent" 66 | 67 | const CardFooter = React.forwardRef< 68 | HTMLDivElement, 69 | React.HTMLAttributes 70 | >(({ className, ...props }, ref) => ( 71 |
76 | )) 77 | CardFooter.displayName = "CardFooter" 78 | 79 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 80 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { Analytics } from "@vercel/analytics/react" 4 | 5 | import "@/styles/globals.css" 6 | import "@covalenthq/goldrush-kit/styles.css" 7 | import { Theme } from "@radix-ui/themes" 8 | 9 | import { fontSans } from "@/lib/fonts" 10 | import { cn } from "@/lib/utils" 11 | import { Header } from "@/components/site-header" 12 | import { ThemeProvider } from "@/components/theme-provider" 13 | 14 | import "@radix-ui/themes/styles.css" 15 | import { TXProvider } from "@/lib/store" 16 | import { Toaster } from "@/components/ui/toaster" 17 | import { Footer } from "@/components/footer" 18 | import { KeyDialog } from "@/components/key-dialog" 19 | import { useEffect, useState } from "react" 20 | import { Icons } from "@/components/icons" 21 | 22 | interface RootLayoutProps { 23 | children: React.ReactNode 24 | } 25 | 26 | export default function RootLayout({ children }: RootLayoutProps) { 27 | const [ready, setReady] = useState(false); 28 | useEffect(()=>{ 29 | if(typeof window !== "undefined"){ 30 | setReady(true) 31 | } 32 | },[]) 33 | return ( 34 | <> 35 | 36 | 37 | 43 | 44 | 45 |
46 |
47 | {ready ? 48 | 49 |
{children}
50 |
51 | : 52 |
53 | 54 |
55 | } 56 | 57 | 58 |
59 | 60 | 61 |
62 |
63 |
64 | 65 | 66 | 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | type Variant = "default" | "primary" | "outline" | "ghost" | "link" 7 | type Size = "default" | "sm" | "lg" | "icon" 8 | 9 | const buttonVariants = ({ 10 | variant = "default", 11 | size = "default", 12 | }: { variant?: Variant; size?: Size } = {}) => { 13 | const baseClasses = 14 | "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background" 15 | 16 | const variantClasses: Record = { 17 | default: 18 | "bg-primary-light dark:bg-primary-dark text-foreground-light dark:text-foreground-dark shadow hover:bg-opacity-90", 19 | primary: 20 | "bg-primary-light dark:bg-primary-dark text-foreground-light dark:text-foreground-dark shadow hover:bg-opacity-90", 21 | outline: 22 | "text-foreground-light dark:text-foreground-dark border bg-background-light dark:bg-background-dark hover:bg-primary-light dark:hover:bg-primary-dark border-secondary-light dark:border-secondary-dark shadow-sm", 23 | ghost: 24 | "hover:bg-primary-light hover:text-foreground-light dark:hover:bg-primary-dark dark:hover:text-foreground-dark", 25 | link: "text-primary-light dark:text-primary-dark underline-offset-4 hover:underline", 26 | } 27 | 28 | const sizeClasses: Record = { 29 | default: "h-9 px-4 py-2", 30 | sm: "h-8 rounded px-3 text-xs", 31 | lg: "h-10 rounded px-8", 32 | icon: "h-9 w-9", 33 | } 34 | 35 | return cn(baseClasses, variantClasses[variant], sizeClasses[size]) 36 | } 37 | 38 | export interface ButtonProps 39 | extends React.ButtonHTMLAttributes { 40 | asChild?: boolean 41 | variant?: Variant 42 | size?: Size 43 | } 44 | 45 | const Button = forwardRef( 46 | ( 47 | { 48 | className, 49 | variant = "default", 50 | size = "default", 51 | asChild = false, 52 | ...props 53 | }, 54 | ref 55 | ) => { 56 | const Comp = asChild ? Slot : "button" 57 | return ( 58 | 63 | ) 64 | } 65 | ) 66 | Button.displayName = "Button" 67 | 68 | export { Button, buttonVariants } 69 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | const { fontFamily } = require("tailwindcss/defaultTheme") 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | darkMode: ["class"], 6 | content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"], 7 | theme: { 8 | container: { 9 | center: true, 10 | padding: "2rem", 11 | screens: { 12 | "2xl": "1400px", 13 | }, 14 | }, 15 | extend: { 16 | colors: { 17 | danger: "#FA3D1D", 18 | success: "#4BD17E", 19 | primary: { 20 | dark: { 21 | DEFAULT: "var(--grk-primary-dark-DEFAULT)", 22 | 100: "var(--grk-primary-dark-100)", 23 | 200: "var(--grk-primary-dark-200)", 24 | 300: "var(--grk-primary-dark-300)", 25 | 400: "var(--grk-primary-dark-400)", 26 | 500: "var(--grk-primary-dark-500)", 27 | 600: "var(--grk-primary-dark-600)", 28 | 700: "var(--grk-primary-dark-700)", 29 | 800: "var(--grk-primary-dark-800)", 30 | 900: "var(--grk-primary-dark-900)", 31 | }, 32 | light: { 33 | DEFAULT: "var(--grk-primary-light-DEFAULT)", 34 | 100: "var(--grk-primary-light-100)", 35 | 200: "var(--grk-primary-light-200)", 36 | 300: "var(--grk-primary-light-300)", 37 | 400: "var(--grk-primary-light-400)", 38 | 500: "var(--grk-primary-light-500)", 39 | 600: "var(--grk-primary-light-600)", 40 | 700: "var(--grk-primary-light-700)", 41 | 800: "var(--grk-primary-light-800)", 42 | 900: "var(--grk-primary-light-900)", 43 | }, 44 | }, 45 | background: { 46 | light: "var(--grk-background-light)", 47 | dark: "var(--grk-background-dark)", 48 | }, 49 | foreground: { 50 | dark: "var(--grk-foreground-dark)", 51 | light: "var(--grk-foreground-light)", 52 | }, 53 | secondary: { 54 | dark: "var(--grk-secondary-dark)", 55 | light: "var(--grk-secondary-light)", 56 | }, 57 | fill: { 58 | DEFAULT: "var(--grk-primary-light)", 59 | }, 60 | ring: { 61 | DEFAULT: "var(--grk-primary-light)", 62 | }, 63 | stroke: { 64 | DEFAULT: "var(--grk-primary-light)", 65 | }, 66 | }, 67 | borderColor: { 68 | light: "var(--grk-secondary-light)", 69 | dark: "var(--grk-secondary-dark)", 70 | }, 71 | borderRadius: { 72 | DEFAULT: "var(--grk-border-radius)", 73 | }, 74 | 75 | keyframes: { 76 | "accordion-down": { 77 | from: { height: "0" }, 78 | to: { height: "var(--grk-radix-accordion-content-height)" }, 79 | }, 80 | "accordion-up": { 81 | from: { 82 | height: "var(--grk-radix-accordion-content-height)", 83 | }, 84 | to: { height: "0" }, 85 | }, 86 | }, 87 | animation: { 88 | "accordion-down": "accordion-down 0.2s ease-out", 89 | "accordion-up": "accordion-up 0.2s ease-out", 90 | }, 91 | }, 92 | }, 93 | plugins: [require("tailwindcss-animate")], 94 | } -------------------------------------------------------------------------------- /components/icons.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | LucideProps, 3 | Moon, 4 | SunMedium, 5 | Twitter, 6 | Settings, 7 | Loader2, 8 | type Icon as LucideIcon, 9 | } from "lucide-react" 10 | 11 | export type Icon = LucideIcon 12 | 13 | export const Icons = { 14 | sun: SunMedium, 15 | moon: Moon, 16 | twitter: Twitter, 17 | Settings: Settings, 18 | spinner: Loader2, 19 | logo: (props: LucideProps) => ( 20 | 21 | 25 | 26 | ), 27 | gitHub: (props: LucideProps) => ( 28 | 29 | 33 | 34 | ), 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | GoldRush Transactions Receipt Banner 4 | 5 |
6 | 7 | [![GitHub license](https://img.shields.io/github/license/covalenthq/goldrush-tx-receipt-ui)](https://github.com/covalenthq/goldrush-tx-receipt-ui/blob/main/LICENSE) 8 | [![GitHub last commit](https://img.shields.io/github/last-commit/covalenthq/goldrush-tx-receipt-ui)](https://github.com/covalenthq/goldrush-tx-receipt-ui/commits/master) 9 | [![GitHub contributors](https://img.shields.io/github/contributors/covalenthq/goldrush-tx-receipt-ui)](https://github.com/covalenthq/goldrush-tx-receipt-ui/graphs/contributors) 10 | [![GitHub issues](https://img.shields.io/github/issues/covalenthq/goldrush-tx-receipt-ui)](https://github.com/covalenthq/goldrush-tx-receipt-ui/issues) 11 | [![GitHub pull requests](https://img.shields.io/github/issues-pr/covalenthq/goldrush-tx-receipt-ui)](https://github.com/covalenthq/goldrush-tx-receipt-ui/pulls) 12 | [![GitHub stars](https://img.shields.io/github/stars/covalenthq/goldrush-tx-receipt-ui)](https://github.com/covalenthq/goldrush-tx-receipt-ui/stargazers) 13 | [![GitHub forks](https://img.shields.io/github/forks/covalenthq/goldrush-tx-receipt-ui)](https://github.com/covalenthq/goldrush-tx-receipt-ui/network/members) 14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 |

Beautifully designed transactions receipt template.

22 | 23 |
24 | Powered by GoldRush Kit. Open-source. Customizable. 200+ Chains. 25 |
26 | 27 | ## Ready-to-use customizable template 28 | 29 | View live template 30 | 31 | https://github.com/covalenthq/goldrush-tx-receipt-ui/assets/471422/2cbf6fda-f7f3-4f7f-81fd-65f1d9b71473 32 | 33 | ## One-click deploy 34 | 35 | Deploy your own Transactions Receipt UI. 36 | 37 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fcovalenthq%2Fgoldrush-tx-receipt-ui&env=NEXT_PUBLIC_GOLDRUSH_API_KEY&envDescription=Visit%20Covalent%20to%20sign%20up%20for%20an%20API%20key&envLink=https%3A%2F%2Fwww.covalenthq.com%2Fplatform%2Fauth%2Fregister%2F) 38 | 39 | ## Local Setup 40 | 41 | 1. Install package dependencies using `npm install`. 42 | 2. Create `.env.local` in your root directory and add your Covalent API key. 43 | ``` 44 | NEXT_PUBLIC_GOLDRUSH_API_KEY = "" 45 | ``` 46 | 3. To run the application, type the following into your terminal. 47 | ``` 48 | npm run dev 49 | ``` 50 | 51 | ## Documentation 52 | 53 | Visit GoldRush's [component documentation](https://www.covalenthq.com/docs/unified-api/quickstart/goldrush-kit/) or [github](https://github.com/covalenthq/goldrush-kit) for more information. 54 | 55 | ## Features 56 | 57 | - Quick App Development: Accelerate the creation of apps wherever you need a customizable and detailed transaction view. 58 | - Stunning Designs Fast: Quickly build visually appealing designs with Tailwind CSS. 59 | - Streamlined Workflow: Simplify development with the power and efficiency of Next.js 13. 60 | - Detailed view of any transaction, plus more: Detailed view of sender and recipients, transaction fees, gas fees, exchange rates and more. 61 | - Integrates seamlessly with the [GoldRush Decoder](https://github.com/covalenthq/goldrush-decoder) to display transactions for literally any protocol. 62 | 63 | 64 | ## 🤝 Contributing 65 | 66 | Contributions, issues and feature requests are welcome! 67 | Feel free to check issues page. 68 | 69 | ## Show your support 70 | 71 | Give a ⭐️ if this project helped you! 72 | 73 | 74 | 75 | ## 📝 License 76 | 77 | This project is MIT licensed. 78 | 79 | -------------------------------------------------------------------------------- /components/ui/dialog.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as DialogPrimitive from "@radix-ui/react-dialog" 3 | import { X } from "lucide-react" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const Dialog = DialogPrimitive.Root 8 | 9 | const DialogTrigger = DialogPrimitive.Trigger 10 | 11 | const DialogPortal = DialogPrimitive.Portal 12 | 13 | const DialogClose = DialogPrimitive.Close 14 | 15 | const DialogOverlay = React.forwardRef< 16 | React.ElementRef, 17 | React.ComponentPropsWithoutRef 18 | >(({ className, ...props }, ref) => ( 19 | 27 | )) 28 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName 29 | 30 | const DialogContent = React.forwardRef< 31 | React.ElementRef, 32 | React.ComponentPropsWithoutRef 33 | >(({ className, children, ...props }, ref) => ( 34 | 35 | 36 | 44 | {children} 45 | 46 | 47 | Close 48 | 49 | 50 | 51 | )) 52 | DialogContent.displayName = DialogPrimitive.Content.displayName 53 | 54 | const DialogHeader = ({ 55 | className, 56 | ...props 57 | }: React.HTMLAttributes) => ( 58 |
65 | ) 66 | DialogHeader.displayName = "DialogHeader" 67 | 68 | const DialogFooter = ({ 69 | className, 70 | ...props 71 | }: React.HTMLAttributes) => ( 72 |
79 | ) 80 | DialogFooter.displayName = "DialogFooter" 81 | 82 | const DialogTitle = React.forwardRef< 83 | React.ElementRef, 84 | React.ComponentPropsWithoutRef 85 | >(({ className, ...props }, ref) => ( 86 | 94 | )) 95 | DialogTitle.displayName = DialogPrimitive.Title.displayName 96 | 97 | const DialogDescription = React.forwardRef< 98 | React.ElementRef, 99 | React.ComponentPropsWithoutRef 100 | >(({ className, ...props }, ref) => ( 101 | 106 | )) 107 | DialogDescription.displayName = DialogPrimitive.Description.displayName 108 | 109 | export { 110 | Dialog, 111 | DialogPortal, 112 | DialogOverlay, 113 | DialogClose, 114 | DialogTrigger, 115 | DialogContent, 116 | DialogHeader, 117 | DialogFooter, 118 | DialogTitle, 119 | DialogDescription, 120 | } 121 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useContext, useEffect, useState } from "react" 4 | import { useRouter } from "next/navigation" 5 | import { ChainItem, GoldRushClient } from "@covalenthq/client-sdk" 6 | import { Flex } from "@radix-ui/themes" 7 | 8 | import { TXContext } from "@/lib/store" 9 | import { GOLDRUSH_API_KEY, cn } from "@/lib/utils" 10 | import { Button } from "@/components/ui/button" 11 | import { Input } from "@/components/ui/input" 12 | import { Label } from "@/components/ui/label" 13 | import { useToast } from "@/components/ui/use-toast" 14 | import ChainSelector from "@/components/chain/ChainSelector" 15 | 16 | export default function IndexPage() { 17 | const { txHash } = useContext(TXContext) 18 | const [allChains, setAllChains] = useState<{ 19 | foundational: ChainItem[] 20 | frontier: ChainItem[] 21 | community: ChainItem[] 22 | }>({ 23 | foundational: [], 24 | frontier: [], 25 | community: [], 26 | }) 27 | const [address, setAddress] = useState( 28 | txHash 29 | ? txHash 30 | : "0x7a038d2f5be4d196a3ff389497f8d61a639e4a32d353758b4f062cafbc5d475c" 31 | ) 32 | const [busy, setBusy] = useState(false) 33 | const router = useRouter() 34 | const [open, setOpen] = useState(false) 35 | const [chainName, setChainName] = useState("Ethereum Mainnet") 36 | const [value, setValue] = useState("eth-mainnet") 37 | const { toast } = useToast() 38 | 39 | const handleAllChains = async () => { 40 | setBusy(true) 41 | if (!GOLDRUSH_API_KEY) return 42 | 43 | const client = new GoldRushClient(GOLDRUSH_API_KEY) 44 | try { 45 | const allChainsResp = await client.BaseService.getAllChains() 46 | if (allChainsResp.error) { 47 | toast({ 48 | title: "Something went wrong.", 49 | description: allChainsResp.error_message, 50 | }) 51 | } 52 | if (allChainsResp.data && allChainsResp.data.items) { 53 | const foundational: ChainItem[] = [] 54 | const frontier: ChainItem[] = [] 55 | const community: ChainItem[] = [] 56 | 57 | allChainsResp.data.items.forEach((chain: ChainItem) => { 58 | if (chain.name && chain.priority_label === "Foundational") { 59 | foundational.push(chain) 60 | } else if (chain.name && chain.priority_label === "Frontier") { 61 | frontier.push(chain) 62 | } else { 63 | community.push(chain) 64 | } 65 | }) 66 | 67 | setAllChains({ 68 | foundational, 69 | frontier, 70 | community, 71 | }) 72 | } 73 | } catch (exception) { 74 | console.log(exception) 75 | } 76 | setBusy(false) 77 | } 78 | 79 | useEffect(() => { 80 | handleAllChains() 81 | }, []) 82 | 83 | return ( 84 |
85 | 86 |

87 | GoldRush Transaction Receipt UI 88 |

89 |

90 | Accessible and customizable components that you can copy and paste 91 | into your apps. Free. Open Source. And Next.js 13 Ready. 92 |

93 |
{ 95 | e.preventDefault() 96 | router.push(`/tx/${value}/${address}`) 97 | }} 98 | > 99 | 100 | 110 | 111 | { 118 | setAddress(e.target.value) 119 | }} 120 | /> 121 |
122 | 128 |
129 |
130 |
131 |
132 |
133 | ) 134 | } 135 | -------------------------------------------------------------------------------- /components/chain/ChainSelector.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import React from "react" 4 | import { ChainSelectorProps } from "@/types/shared" 5 | import { Check, ChevronsUpDown } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | import { Button } from "@/components/ui/button" 9 | import { 10 | Command, 11 | CommandEmpty, 12 | CommandGroup, 13 | CommandInput, 14 | CommandItem, 15 | CommandList, 16 | CommandSeparator, 17 | } from "@/components/ui/command" 18 | import { 19 | Popover, 20 | PopoverContent, 21 | PopoverTrigger, 22 | } from "@/components/ui/popover" 23 | 24 | const ChainSelector: React.FC = ({ 25 | open, 26 | value, 27 | chainName, 28 | busy, 29 | allChains, 30 | setValue, 31 | setOpen, 32 | setChainName, 33 | }) => { 34 | return ( 35 | 36 | 37 | 45 | 46 | 47 | 48 | 49 | 50 | No chain found. 51 | 52 | {allChains.foundational.map((chain) => ( 53 | { 57 | setValue(currentValue === value ? "" : currentValue) 58 | setChainName( 59 | chain.label === chainName ? "" : (chain.label ?? "") 60 | ) 61 | setOpen(false) 62 | }} 63 | className="flex items-center cursor-pointer" 64 | > 65 | 71 | {chain.label} 72 | 73 | ))} 74 | 75 | 76 | 77 | {allChains.frontier.map((chain) => ( 78 | { 82 | setValue(currentValue === value ? "" : currentValue) 83 | setChainName( 84 | chain.label === chainName ? "" : (chain.label ?? "") 85 | ) 86 | setOpen(false) 87 | }} 88 | className="flex items-center cursor-pointer" 89 | > 90 | 96 | {chain.label} 97 | 98 | ))} 99 | 100 | 101 | 102 | {allChains.community.map((chain) => ( 103 | { 107 | setValue(currentValue === value ? "" : currentValue) 108 | setChainName( 109 | chain.label === chainName ? "" : (chain.label ?? "") 110 | ) 111 | setOpen(false) 112 | }} 113 | className="flex items-center cursor-pointer" 114 | > 115 | 121 | {chain.label} 122 | 123 | ))} 124 | 125 | 126 | 127 | 128 | 129 | ) 130 | } 131 | 132 | export default ChainSelector -------------------------------------------------------------------------------- /components/ui/use-toast.ts: -------------------------------------------------------------------------------- 1 | // Inspired by react-hot-toast library 2 | import * as React from "react" 3 | 4 | import type { 5 | ToastActionElement, 6 | ToastProps, 7 | } from "@/components/ui/toast" 8 | 9 | const TOAST_LIMIT = 1 10 | const TOAST_REMOVE_DELAY = 1000000 11 | 12 | type ToasterToast = ToastProps & { 13 | id: string 14 | title?: React.ReactNode 15 | description?: React.ReactNode 16 | action?: ToastActionElement 17 | } 18 | 19 | const actionTypes = { 20 | ADD_TOAST: "ADD_TOAST", 21 | UPDATE_TOAST: "UPDATE_TOAST", 22 | DISMISS_TOAST: "DISMISS_TOAST", 23 | REMOVE_TOAST: "REMOVE_TOAST", 24 | } as const 25 | 26 | let count = 0 27 | 28 | function genId() { 29 | count = (count + 1) % Number.MAX_SAFE_INTEGER 30 | return count.toString() 31 | } 32 | 33 | type ActionType = typeof actionTypes 34 | 35 | type Action = 36 | | { 37 | type: ActionType["ADD_TOAST"] 38 | toast: ToasterToast 39 | } 40 | | { 41 | type: ActionType["UPDATE_TOAST"] 42 | toast: Partial 43 | } 44 | | { 45 | type: ActionType["DISMISS_TOAST"] 46 | toastId?: ToasterToast["id"] 47 | } 48 | | { 49 | type: ActionType["REMOVE_TOAST"] 50 | toastId?: ToasterToast["id"] 51 | } 52 | 53 | interface State { 54 | toasts: ToasterToast[] 55 | } 56 | 57 | const toastTimeouts = new Map>() 58 | 59 | const addToRemoveQueue = (toastId: string) => { 60 | if (toastTimeouts.has(toastId)) { 61 | return 62 | } 63 | 64 | const timeout = setTimeout(() => { 65 | toastTimeouts.delete(toastId) 66 | dispatch({ 67 | type: "REMOVE_TOAST", 68 | toastId: toastId, 69 | }) 70 | }, TOAST_REMOVE_DELAY) 71 | 72 | toastTimeouts.set(toastId, timeout) 73 | } 74 | 75 | export const reducer = (state: State, action: Action): State => { 76 | switch (action.type) { 77 | case "ADD_TOAST": 78 | return { 79 | ...state, 80 | toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), 81 | } 82 | 83 | case "UPDATE_TOAST": 84 | return { 85 | ...state, 86 | toasts: state.toasts.map((t) => 87 | t.id === action.toast.id ? { ...t, ...action.toast } : t 88 | ), 89 | } 90 | 91 | case "DISMISS_TOAST": { 92 | const { toastId } = action 93 | 94 | // ! Side effects ! - This could be extracted into a dismissToast() action, 95 | // but I'll keep it here for simplicity 96 | if (toastId) { 97 | addToRemoveQueue(toastId) 98 | } else { 99 | state.toasts.forEach((toast) => { 100 | addToRemoveQueue(toast.id) 101 | }) 102 | } 103 | 104 | return { 105 | ...state, 106 | toasts: state.toasts.map((t) => 107 | t.id === toastId || toastId === undefined 108 | ? { 109 | ...t, 110 | open: false, 111 | } 112 | : t 113 | ), 114 | } 115 | } 116 | case "REMOVE_TOAST": 117 | if (action.toastId === undefined) { 118 | return { 119 | ...state, 120 | toasts: [], 121 | } 122 | } 123 | return { 124 | ...state, 125 | toasts: state.toasts.filter((t) => t.id !== action.toastId), 126 | } 127 | } 128 | } 129 | 130 | const listeners: Array<(state: State) => void> = [] 131 | 132 | let memoryState: State = { toasts: [] } 133 | 134 | function dispatch(action: Action) { 135 | memoryState = reducer(memoryState, action) 136 | listeners.forEach((listener) => { 137 | listener(memoryState) 138 | }) 139 | } 140 | 141 | type Toast = Omit 142 | 143 | function toast({ ...props }: Toast) { 144 | const id = genId() 145 | 146 | const update = (props: ToasterToast) => 147 | dispatch({ 148 | type: "UPDATE_TOAST", 149 | toast: { ...props, id }, 150 | }) 151 | const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) 152 | 153 | dispatch({ 154 | type: "ADD_TOAST", 155 | toast: { 156 | ...props, 157 | id, 158 | open: true, 159 | onOpenChange: (open) => { 160 | if (!open) dismiss() 161 | }, 162 | }, 163 | }) 164 | 165 | return { 166 | id: id, 167 | dismiss, 168 | update, 169 | } 170 | } 171 | 172 | function useToast() { 173 | const [state, setState] = React.useState(memoryState) 174 | 175 | React.useEffect(() => { 176 | listeners.push(setState) 177 | return () => { 178 | const index = listeners.indexOf(setState) 179 | if (index > -1) { 180 | listeners.splice(index, 1) 181 | } 182 | } 183 | }, [state]) 184 | 185 | return { 186 | ...state, 187 | toast, 188 | dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), 189 | } 190 | } 191 | 192 | export { useToast, toast } 193 | -------------------------------------------------------------------------------- /components/ui/alert-dialog.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" 3 | 4 | import { cn } from "@/lib/utils" 5 | import { buttonVariants } from "@/components/ui/button" 6 | 7 | const AlertDialog = AlertDialogPrimitive.Root 8 | 9 | const AlertDialogTrigger = AlertDialogPrimitive.Trigger 10 | 11 | const AlertDialogPortal = AlertDialogPrimitive.Portal 12 | 13 | const AlertDialogOverlay = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef 16 | >(({ className, ...props }, ref) => ( 17 | 25 | )) 26 | AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName 27 | 28 | const AlertDialogContent = React.forwardRef< 29 | React.ElementRef, 30 | React.ComponentPropsWithoutRef 31 | >(({ className, ...props }, ref) => ( 32 | 33 | 34 | 42 | 43 | )) 44 | AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName 45 | 46 | const AlertDialogHeader = ({ 47 | className, 48 | ...props 49 | }: React.HTMLAttributes) => ( 50 |
57 | ) 58 | AlertDialogHeader.displayName = "AlertDialogHeader" 59 | 60 | const AlertDialogFooter = ({ 61 | className, 62 | ...props 63 | }: React.HTMLAttributes) => ( 64 |
71 | ) 72 | AlertDialogFooter.displayName = "AlertDialogFooter" 73 | 74 | const AlertDialogTitle = React.forwardRef< 75 | React.ElementRef, 76 | React.ComponentPropsWithoutRef 77 | >(({ className, ...props }, ref) => ( 78 | 83 | )) 84 | AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName 85 | 86 | const AlertDialogDescription = React.forwardRef< 87 | React.ElementRef, 88 | React.ComponentPropsWithoutRef 89 | >(({ className, ...props }, ref) => ( 90 | 95 | )) 96 | AlertDialogDescription.displayName = 97 | AlertDialogPrimitive.Description.displayName 98 | 99 | const AlertDialogAction = React.forwardRef< 100 | React.ElementRef, 101 | React.ComponentPropsWithoutRef 102 | >(({ className, ...props }, ref) => ( 103 | 108 | )) 109 | AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName 110 | 111 | const AlertDialogCancel = React.forwardRef< 112 | React.ElementRef, 113 | React.ComponentPropsWithoutRef 114 | >(({ className, ...props }, ref) => ( 115 | 124 | )) 125 | AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName 126 | 127 | export { 128 | AlertDialog, 129 | AlertDialogPortal, 130 | AlertDialogOverlay, 131 | AlertDialogTrigger, 132 | AlertDialogContent, 133 | AlertDialogHeader, 134 | AlertDialogFooter, 135 | AlertDialogTitle, 136 | AlertDialogDescription, 137 | AlertDialogAction, 138 | AlertDialogCancel, 139 | } 140 | -------------------------------------------------------------------------------- /components/ui/toast.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as ToastPrimitives from "@radix-ui/react-toast" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | import { X } from "lucide-react" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const ToastProvider = ToastPrimitives.Provider 9 | 10 | const ToastViewport = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, ...props }, ref) => ( 14 | 22 | )) 23 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName 24 | 25 | const toastVariants = cva( 26 | "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-right-full data-[state=open]:sm:slide-in-from-right-full", 27 | { 28 | variants: { 29 | variant: { 30 | default: "border bg-background text-foreground", 31 | destructive: 32 | "destructive group border-destructive bg-destructive text-destructive-foreground", 33 | }, 34 | }, 35 | defaultVariants: { 36 | variant: "default", 37 | }, 38 | } 39 | ) 40 | 41 | const Toast = React.forwardRef< 42 | React.ElementRef, 43 | React.ComponentPropsWithoutRef & 44 | VariantProps 45 | >(({ className, variant, ...props }, ref) => ( 46 | 51 | )) 52 | Toast.displayName = ToastPrimitives.Root.displayName 53 | 54 | const ToastAction = React.forwardRef< 55 | React.ElementRef, 56 | React.ComponentPropsWithoutRef 57 | >(({ className, ...props }, ref) => ( 58 | 66 | )) 67 | ToastAction.displayName = ToastPrimitives.Action.displayName 68 | 69 | const ToastClose = React.forwardRef< 70 | React.ElementRef, 71 | React.ComponentPropsWithoutRef 72 | >(({ className, ...props }, ref) => ( 73 | 82 | 83 | 84 | )) 85 | ToastClose.displayName = ToastPrimitives.Close.displayName 86 | 87 | const ToastTitle = React.forwardRef< 88 | React.ElementRef, 89 | React.ComponentPropsWithoutRef 90 | >(({ className, ...props }, ref) => ( 91 | 96 | )) 97 | ToastTitle.displayName = ToastPrimitives.Title.displayName 98 | 99 | const ToastDescription = React.forwardRef< 100 | React.ElementRef, 101 | React.ComponentPropsWithoutRef 102 | >(({ className, ...props }, ref) => ( 103 | 108 | )) 109 | ToastDescription.displayName = ToastPrimitives.Description.displayName 110 | 111 | type ToastProps = React.ComponentPropsWithoutRef 112 | 113 | type ToastActionElement = React.ReactElement 114 | 115 | export { 116 | type ToastProps, 117 | type ToastActionElement, 118 | ToastProvider, 119 | ToastViewport, 120 | Toast, 121 | ToastTitle, 122 | ToastDescription, 123 | ToastClose, 124 | ToastAction, 125 | } 126 | -------------------------------------------------------------------------------- /components/ui/command.tsx: -------------------------------------------------------------------------------- 1 | import { Dialog, DialogContent } from "@/components/ui/dialog"; 2 | import { type DialogProps } from "@radix-ui/react-dialog"; 3 | import { MagnifyingGlassIcon } from "@radix-ui/react-icons"; 4 | import { Command as CommandPrimitive } from "cmdk"; 5 | import { forwardRef } from "react"; 6 | import { cn } from "@/lib/utils" 7 | 8 | const Command = forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, ...props }, ref) => ( 12 | 20 | )); 21 | Command.displayName = CommandPrimitive.displayName; 22 | 23 | interface CommandDialogProps extends DialogProps {} 24 | 25 | const CommandDialog = ({ children, ...props }: CommandDialogProps) => { 26 | return ( 27 | 28 | 29 | 30 | {children} 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | const CommandInput = forwardRef< 38 | React.ElementRef, 39 | React.ComponentPropsWithoutRef 40 | >(({ className, ...props }, ref) => ( 41 |
42 | 43 | 51 |
52 | )); 53 | 54 | CommandInput.displayName = CommandPrimitive.Input.displayName; 55 | 56 | const CommandList = forwardRef< 57 | React.ElementRef, 58 | React.ComponentPropsWithoutRef 59 | >(({ className, ...props }, ref) => ( 60 | 68 | )); 69 | 70 | CommandList.displayName = CommandPrimitive.List.displayName; 71 | 72 | const CommandEmpty = forwardRef< 73 | React.ElementRef, 74 | React.ComponentPropsWithoutRef 75 | >((props, ref) => ( 76 | 81 | )); 82 | 83 | CommandEmpty.displayName = CommandPrimitive.Empty.displayName; 84 | 85 | const CommandGroup = forwardRef< 86 | React.ElementRef, 87 | React.ComponentPropsWithoutRef 88 | >(({ className, ...props }, ref) => ( 89 | 97 | )); 98 | 99 | CommandGroup.displayName = CommandPrimitive.Group.displayName; 100 | 101 | const CommandSeparator = forwardRef< 102 | React.ElementRef, 103 | React.ComponentPropsWithoutRef 104 | >(({ className, ...props }, ref) => ( 105 | 113 | )); 114 | CommandSeparator.displayName = CommandPrimitive.Separator.displayName; 115 | 116 | const CommandItem = forwardRef< 117 | React.ElementRef, 118 | React.ComponentPropsWithoutRef 119 | >(({ className, ...props }, ref) => ( 120 | 128 | )); 129 | 130 | CommandItem.displayName = CommandPrimitive.Item.displayName; 131 | 132 | const CommandShortcut = ({ 133 | className, 134 | ...props 135 | }: React.HTMLAttributes) => { 136 | return ( 137 | 144 | ); 145 | }; 146 | CommandShortcut.displayName = "CommandShortcut"; 147 | 148 | export { 149 | Command, 150 | CommandDialog, 151 | CommandInput, 152 | CommandList, 153 | CommandEmpty, 154 | CommandGroup, 155 | CommandItem, 156 | CommandShortcut, 157 | CommandSeparator, 158 | }; -------------------------------------------------------------------------------- /components/ui/select.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as SelectPrimitive from "@radix-ui/react-select" 3 | import { Check, ChevronDown, ChevronUp } from "lucide-react" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const Select = SelectPrimitive.Root 8 | 9 | const SelectGroup = SelectPrimitive.Group 10 | 11 | const SelectValue = SelectPrimitive.Value 12 | 13 | const SelectTrigger = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef 16 | >(({ className, children, ...props }, ref) => ( 17 | span]:line-clamp-1", 21 | className 22 | )} 23 | {...props} 24 | > 25 | {children} 26 | 27 | 28 | 29 | 30 | )) 31 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName 32 | 33 | const SelectScrollUpButton = React.forwardRef< 34 | React.ElementRef, 35 | React.ComponentPropsWithoutRef 36 | >(({ className, ...props }, ref) => ( 37 | 45 | 46 | 47 | )) 48 | SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName 49 | 50 | const SelectScrollDownButton = React.forwardRef< 51 | React.ElementRef, 52 | React.ComponentPropsWithoutRef 53 | >(({ className, ...props }, ref) => ( 54 | 62 | 63 | 64 | )) 65 | SelectScrollDownButton.displayName = 66 | SelectPrimitive.ScrollDownButton.displayName 67 | 68 | const SelectContent = React.forwardRef< 69 | React.ElementRef, 70 | React.ComponentPropsWithoutRef 71 | >(({ className, children, position = "popper", ...props }, ref) => ( 72 | 73 | 84 | 85 | 92 | {children} 93 | 94 | 95 | 96 | 97 | )) 98 | SelectContent.displayName = SelectPrimitive.Content.displayName 99 | 100 | const SelectLabel = React.forwardRef< 101 | React.ElementRef, 102 | React.ComponentPropsWithoutRef 103 | >(({ className, ...props }, ref) => ( 104 | 109 | )) 110 | SelectLabel.displayName = SelectPrimitive.Label.displayName 111 | 112 | const SelectItem = React.forwardRef< 113 | React.ElementRef, 114 | React.ComponentPropsWithoutRef 115 | >(({ className, children, ...props }, ref) => ( 116 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | {children} 131 | 132 | )) 133 | SelectItem.displayName = SelectPrimitive.Item.displayName 134 | 135 | const SelectSeparator = React.forwardRef< 136 | React.ElementRef, 137 | React.ComponentPropsWithoutRef 138 | >(({ className, ...props }, ref) => ( 139 | 144 | )) 145 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName 146 | 147 | export { 148 | Select, 149 | SelectGroup, 150 | SelectValue, 151 | SelectTrigger, 152 | SelectContent, 153 | SelectLabel, 154 | SelectItem, 155 | SelectSeparator, 156 | SelectScrollUpButton, 157 | SelectScrollDownButton, 158 | } 159 | -------------------------------------------------------------------------------- /public/covalent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/settings/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useRouter } from "next/navigation" 4 | import { useGoldRush } from "@covalenthq/goldrush-kit" 5 | 6 | import { BORDER_RADIUS, COLORS } from "@/lib/utils" 7 | import { Button } from "@/components/ui/button" 8 | 9 | export default function Settings({ 10 | params, 11 | }: Readonly<{ params: { slug: string } }>) { 12 | const { updateThemeHandler, theme } = useGoldRush() 13 | const router = useRouter() 14 | 15 | return ( 16 |
17 |
18 |

19 | Foreground Color Selection 20 |

21 |

22 | Select color to change the foreground of your portfolio. 23 |

24 |
25 |
26 | {Object.entries(COLORS).map(([_color, value]) => ( 27 |
56 | 57 |
58 |

59 | Background Color Selection 60 |

61 |

62 | Select color to change the background of your portfolio. 63 |

64 |
65 |
66 | {Object.entries(COLORS).map(([_color, value]) => ( 67 |
96 | 97 |
98 |

99 | Primary Color Selection 100 |

101 |

102 | Select color to change the primary of your portfolio. 103 |

104 |
105 |
106 | {Object.entries(COLORS).map(([_color, value]) => ( 107 |
136 | 137 |
138 |

139 | Secondary Color Selection 140 |

141 |

142 | Select color to change the secondary of your portfolio. 143 |

144 |
145 |
146 | {Object.entries(COLORS).map(([_color, value]) => ( 147 |
176 | 177 |
178 |

179 | Border Radius Selection 180 |

181 |

182 | Select border radius. 183 |

184 |
185 | 186 |
187 | {Object.entries(BORDER_RADIUS).map(([radius, value]) => ( 188 | 203 | ))} 204 |
205 | 213 |
214 | ) 215 | } -------------------------------------------------------------------------------- /lib/svg.tsx: -------------------------------------------------------------------------------- 1 | export const PoweredByGoldRush = () => { 2 | return ( 3 | 10 | 11 | 15 | 16 | 20 | 24 | 28 | 32 | 33 | 37 | 41 | 45 | 49 | 53 | 57 | 61 | 65 | 66 | 67 | 73 | 74 | 75 | 76 | ) 77 | } --------------------------------------------------------------------------------