create-stylus-ide 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/Readme.MD +1515 -0
  2. package/cli.js +28 -0
  3. package/frontend/.vscode/settings.json +9 -0
  4. package/frontend/app/api/chat/route.ts +101 -0
  5. package/frontend/app/api/check-setup/route.ts +93 -0
  6. package/frontend/app/api/cleanup/route.ts +14 -0
  7. package/frontend/app/api/compile/route.ts +95 -0
  8. package/frontend/app/api/compile-stream/route.ts +98 -0
  9. package/frontend/app/api/complete/route.ts +86 -0
  10. package/frontend/app/api/deploy/route.ts +118 -0
  11. package/frontend/app/api/export-abi/route.ts +58 -0
  12. package/frontend/app/favicon.ico +0 -0
  13. package/frontend/app/globals.css +177 -0
  14. package/frontend/app/layout.tsx +29 -0
  15. package/frontend/app/ml/page.tsx +694 -0
  16. package/frontend/app/page.tsx +1132 -0
  17. package/frontend/app/providers.tsx +18 -0
  18. package/frontend/app/qlearning/page.tsx +188 -0
  19. package/frontend/app/raytracing/page.tsx +268 -0
  20. package/frontend/components/abi/ABIDialog.tsx +132 -0
  21. package/frontend/components/ai/AICompletionPopup.tsx +76 -0
  22. package/frontend/components/ai/ChatPanel.tsx +292 -0
  23. package/frontend/components/ai/QuickActions.tsx +128 -0
  24. package/frontend/components/blockchain/BlockchainContractBanner.tsx +64 -0
  25. package/frontend/components/blockchain/BlockchainLoadingDialog.tsx +188 -0
  26. package/frontend/components/deploy/DeployDialog.tsx +334 -0
  27. package/frontend/components/editor/FileTabs.tsx +181 -0
  28. package/frontend/components/editor/MonacoEditor.tsx +306 -0
  29. package/frontend/components/file-tree/ContextMenu.tsx +110 -0
  30. package/frontend/components/file-tree/DeleteConfirmDialog.tsx +61 -0
  31. package/frontend/components/file-tree/FileInputDialog.tsx +97 -0
  32. package/frontend/components/file-tree/FileNode.tsx +60 -0
  33. package/frontend/components/file-tree/FileTree.tsx +259 -0
  34. package/frontend/components/file-tree/FileTreeSkeleton.tsx +26 -0
  35. package/frontend/components/file-tree/FolderNode.tsx +105 -0
  36. package/frontend/components/github/GitHubLoadingDialog.tsx +201 -0
  37. package/frontend/components/github/GitHubMetadataBanner.tsx +61 -0
  38. package/frontend/components/github/LoadFromGitHubDialog.tsx +125 -0
  39. package/frontend/components/github/URLCopyButton.tsx +60 -0
  40. package/frontend/components/interact/ContractInteraction.tsx +323 -0
  41. package/frontend/components/interact/ContractPlaceholder.tsx +41 -0
  42. package/frontend/components/orbit/BenchmarkDialog.tsx +342 -0
  43. package/frontend/components/orbit/OrbitExplorer.tsx +273 -0
  44. package/frontend/components/project/ProjectActions.tsx +176 -0
  45. package/frontend/components/q-learning/ContractConfig.tsx +172 -0
  46. package/frontend/components/q-learning/MazeGrid.tsx +346 -0
  47. package/frontend/components/q-learning/PathAnimation.tsx +384 -0
  48. package/frontend/components/q-learning/QTableHeatmap.tsx +300 -0
  49. package/frontend/components/q-learning/TrainingForm.tsx +349 -0
  50. package/frontend/components/ray-tracing/ContractConfig.tsx +245 -0
  51. package/frontend/components/ray-tracing/MintingForm.tsx +280 -0
  52. package/frontend/components/ray-tracing/RenderCanvas.tsx +228 -0
  53. package/frontend/components/ray-tracing/RenderingPanel.tsx +259 -0
  54. package/frontend/components/ray-tracing/StyleControls.tsx +217 -0
  55. package/frontend/components/setup/SetupGuide.tsx +290 -0
  56. package/frontend/components/ui/KeyboardShortcutHint.tsx +74 -0
  57. package/frontend/components/ui/alert-dialog.tsx +157 -0
  58. package/frontend/components/ui/alert.tsx +66 -0
  59. package/frontend/components/ui/badge.tsx +46 -0
  60. package/frontend/components/ui/button.tsx +62 -0
  61. package/frontend/components/ui/card.tsx +92 -0
  62. package/frontend/components/ui/context-menu.tsx +252 -0
  63. package/frontend/components/ui/dialog.tsx +143 -0
  64. package/frontend/components/ui/dropdown-menu.tsx +257 -0
  65. package/frontend/components/ui/input.tsx +21 -0
  66. package/frontend/components/ui/label.tsx +24 -0
  67. package/frontend/components/ui/progress.tsx +31 -0
  68. package/frontend/components/ui/scroll-area.tsx +58 -0
  69. package/frontend/components/ui/select.tsx +190 -0
  70. package/frontend/components/ui/separator.tsx +28 -0
  71. package/frontend/components/ui/sheet.tsx +139 -0
  72. package/frontend/components/ui/skeleton.tsx +13 -0
  73. package/frontend/components/ui/slider.tsx +63 -0
  74. package/frontend/components/ui/sonner.tsx +40 -0
  75. package/frontend/components/ui/tabs.tsx +66 -0
  76. package/frontend/components/ui/textarea.tsx +18 -0
  77. package/frontend/components/wallet/ConnectButton.tsx +167 -0
  78. package/frontend/components/wallet/FaucetButton.tsx +256 -0
  79. package/frontend/components.json +22 -0
  80. package/frontend/eslint.config.mjs +18 -0
  81. package/frontend/hooks/useAICompletion.ts +75 -0
  82. package/frontend/hooks/useBlockchainLoader.ts +58 -0
  83. package/frontend/hooks/useChats.ts +137 -0
  84. package/frontend/hooks/useCompilation.ts +173 -0
  85. package/frontend/hooks/useFileTabs.ts +178 -0
  86. package/frontend/hooks/useGitHubLoader.ts +50 -0
  87. package/frontend/hooks/useKeyboardShortcuts.ts +47 -0
  88. package/frontend/hooks/usePanelState.ts +115 -0
  89. package/frontend/hooks/useProjectState.ts +276 -0
  90. package/frontend/hooks/useResponsive.ts +29 -0
  91. package/frontend/lib/abi-parser.ts +58 -0
  92. package/frontend/lib/blockchain-api.ts +374 -0
  93. package/frontend/lib/blockchain-explorers.ts +75 -0
  94. package/frontend/lib/blockchain-loader.ts +112 -0
  95. package/frontend/lib/cargo-template.ts +64 -0
  96. package/frontend/lib/compilation.ts +529 -0
  97. package/frontend/lib/constants.ts +31 -0
  98. package/frontend/lib/deployment.ts +176 -0
  99. package/frontend/lib/file-utils.ts +83 -0
  100. package/frontend/lib/github-api.ts +246 -0
  101. package/frontend/lib/github-loader.ts +369 -0
  102. package/frontend/lib/ml-contract-template.txt +900 -0
  103. package/frontend/lib/orbit-chains.ts +181 -0
  104. package/frontend/lib/output-formatter.ts +68 -0
  105. package/frontend/lib/project-manager.ts +632 -0
  106. package/frontend/lib/ray-tracing-abi.ts +206 -0
  107. package/frontend/lib/storage.ts +189 -0
  108. package/frontend/lib/templates.ts +1662 -0
  109. package/frontend/lib/url-parser.ts +188 -0
  110. package/frontend/lib/utils.ts +6 -0
  111. package/frontend/lib/wagmi-config.ts +24 -0
  112. package/frontend/next.config.ts +7 -0
  113. package/frontend/package-lock.json +16259 -0
  114. package/frontend/package.json +60 -0
  115. package/frontend/postcss.config.mjs +7 -0
  116. package/frontend/public/file.svg +1 -0
  117. package/frontend/public/globe.svg +1 -0
  118. package/frontend/public/ml-weights/.gitkeep +0 -0
  119. package/frontend/public/ml-weights/model.pkl +0 -0
  120. package/frontend/public/ml-weights/model_weights.json +27102 -0
  121. package/frontend/public/ml-weights/test_samples.json +7888 -0
  122. package/frontend/public/next.svg +1 -0
  123. package/frontend/public/vercel.svg +1 -0
  124. package/frontend/public/window.svg +1 -0
  125. package/frontend/scripts/check-env.js +52 -0
  126. package/frontend/scripts/setup.js +285 -0
  127. package/frontend/tailwind.config.ts +64 -0
  128. package/frontend/tsconfig.json +34 -0
  129. package/frontend/types/blockchain.ts +63 -0
  130. package/frontend/types/github.ts +54 -0
  131. package/frontend/types/project.ts +106 -0
  132. package/ml-training/README.md +56 -0
  133. package/ml-training/train_tiny_model.py +325 -0
  134. package/ml-training/update_template.py +59 -0
  135. package/package.json +30 -0
@@ -0,0 +1,139 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as SheetPrimitive from "@radix-ui/react-dialog"
5
+ import { XIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
10
+ return <SheetPrimitive.Root data-slot="sheet" {...props} />
11
+ }
12
+
13
+ function SheetTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
16
+ return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
17
+ }
18
+
19
+ function SheetClose({
20
+ ...props
21
+ }: React.ComponentProps<typeof SheetPrimitive.Close>) {
22
+ return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
23
+ }
24
+
25
+ function SheetPortal({
26
+ ...props
27
+ }: React.ComponentProps<typeof SheetPrimitive.Portal>) {
28
+ return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
29
+ }
30
+
31
+ function SheetOverlay({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
35
+ return (
36
+ <SheetPrimitive.Overlay
37
+ data-slot="sheet-overlay"
38
+ className={cn(
39
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ )
45
+ }
46
+
47
+ function SheetContent({
48
+ className,
49
+ children,
50
+ side = "right",
51
+ ...props
52
+ }: React.ComponentProps<typeof SheetPrimitive.Content> & {
53
+ side?: "top" | "right" | "bottom" | "left"
54
+ }) {
55
+ return (
56
+ <SheetPortal>
57
+ <SheetOverlay />
58
+ <SheetPrimitive.Content
59
+ data-slot="sheet-content"
60
+ className={cn(
61
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
62
+ side === "right" &&
63
+ "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
64
+ side === "left" &&
65
+ "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
66
+ side === "top" &&
67
+ "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
68
+ side === "bottom" &&
69
+ "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
70
+ className
71
+ )}
72
+ {...props}
73
+ >
74
+ {children}
75
+ <SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
76
+ <XIcon className="size-4" />
77
+ <span className="sr-only">Close</span>
78
+ </SheetPrimitive.Close>
79
+ </SheetPrimitive.Content>
80
+ </SheetPortal>
81
+ )
82
+ }
83
+
84
+ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
85
+ return (
86
+ <div
87
+ data-slot="sheet-header"
88
+ className={cn("flex flex-col gap-1.5 p-4", className)}
89
+ {...props}
90
+ />
91
+ )
92
+ }
93
+
94
+ function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
95
+ return (
96
+ <div
97
+ data-slot="sheet-footer"
98
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
99
+ {...props}
100
+ />
101
+ )
102
+ }
103
+
104
+ function SheetTitle({
105
+ className,
106
+ ...props
107
+ }: React.ComponentProps<typeof SheetPrimitive.Title>) {
108
+ return (
109
+ <SheetPrimitive.Title
110
+ data-slot="sheet-title"
111
+ className={cn("text-foreground font-semibold", className)}
112
+ {...props}
113
+ />
114
+ )
115
+ }
116
+
117
+ function SheetDescription({
118
+ className,
119
+ ...props
120
+ }: React.ComponentProps<typeof SheetPrimitive.Description>) {
121
+ return (
122
+ <SheetPrimitive.Description
123
+ data-slot="sheet-description"
124
+ className={cn("text-muted-foreground text-sm", className)}
125
+ {...props}
126
+ />
127
+ )
128
+ }
129
+
130
+ export {
131
+ Sheet,
132
+ SheetTrigger,
133
+ SheetClose,
134
+ SheetContent,
135
+ SheetHeader,
136
+ SheetFooter,
137
+ SheetTitle,
138
+ SheetDescription,
139
+ }
@@ -0,0 +1,13 @@
1
+ import { cn } from "@/lib/utils"
2
+
3
+ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
4
+ return (
5
+ <div
6
+ data-slot="skeleton"
7
+ className={cn("bg-accent animate-pulse rounded-md", className)}
8
+ {...props}
9
+ />
10
+ )
11
+ }
12
+
13
+ export { Skeleton }
@@ -0,0 +1,63 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as SliderPrimitive from "@radix-ui/react-slider"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function Slider({
9
+ className,
10
+ defaultValue,
11
+ value,
12
+ min = 0,
13
+ max = 100,
14
+ ...props
15
+ }: React.ComponentProps<typeof SliderPrimitive.Root>) {
16
+ const _values = React.useMemo(
17
+ () =>
18
+ Array.isArray(value)
19
+ ? value
20
+ : Array.isArray(defaultValue)
21
+ ? defaultValue
22
+ : [min, max],
23
+ [value, defaultValue, min, max]
24
+ )
25
+
26
+ return (
27
+ <SliderPrimitive.Root
28
+ data-slot="slider"
29
+ defaultValue={defaultValue}
30
+ value={value}
31
+ min={min}
32
+ max={max}
33
+ className={cn(
34
+ "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
35
+ className
36
+ )}
37
+ {...props}
38
+ >
39
+ <SliderPrimitive.Track
40
+ data-slot="slider-track"
41
+ className={cn(
42
+ "bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
43
+ )}
44
+ >
45
+ <SliderPrimitive.Range
46
+ data-slot="slider-range"
47
+ className={cn(
48
+ "bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
49
+ )}
50
+ />
51
+ </SliderPrimitive.Track>
52
+ {Array.from({ length: _values.length }, (_, index) => (
53
+ <SliderPrimitive.Thumb
54
+ data-slot="slider-thumb"
55
+ key={index}
56
+ className="border-primary ring-ring/50 block size-4 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
57
+ />
58
+ ))}
59
+ </SliderPrimitive.Root>
60
+ )
61
+ }
62
+
63
+ export { Slider }
@@ -0,0 +1,40 @@
1
+ "use client"
2
+
3
+ import {
4
+ CircleCheckIcon,
5
+ InfoIcon,
6
+ Loader2Icon,
7
+ OctagonXIcon,
8
+ TriangleAlertIcon,
9
+ } from "lucide-react"
10
+ import { useTheme } from "next-themes"
11
+ import { Toaster as Sonner, type ToasterProps } from "sonner"
12
+
13
+ const Toaster = ({ ...props }: ToasterProps) => {
14
+ const { theme = "system" } = useTheme()
15
+
16
+ return (
17
+ <Sonner
18
+ theme={theme as ToasterProps["theme"]}
19
+ className="toaster group"
20
+ icons={{
21
+ success: <CircleCheckIcon className="size-4" />,
22
+ info: <InfoIcon className="size-4" />,
23
+ warning: <TriangleAlertIcon className="size-4" />,
24
+ error: <OctagonXIcon className="size-4" />,
25
+ loading: <Loader2Icon className="size-4 animate-spin" />,
26
+ }}
27
+ style={
28
+ {
29
+ "--normal-bg": "var(--popover)",
30
+ "--normal-text": "var(--popover-foreground)",
31
+ "--normal-border": "var(--border)",
32
+ "--border-radius": "var(--radius)",
33
+ } as React.CSSProperties
34
+ }
35
+ {...props}
36
+ />
37
+ )
38
+ }
39
+
40
+ export { Toaster }
@@ -0,0 +1,66 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TabsPrimitive from "@radix-ui/react-tabs"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function Tabs({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof TabsPrimitive.Root>) {
12
+ return (
13
+ <TabsPrimitive.Root
14
+ data-slot="tabs"
15
+ className={cn("flex flex-col gap-2", className)}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ function TabsList({
22
+ className,
23
+ ...props
24
+ }: React.ComponentProps<typeof TabsPrimitive.List>) {
25
+ return (
26
+ <TabsPrimitive.List
27
+ data-slot="tabs-list"
28
+ className={cn(
29
+ "bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
30
+ className
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ function TabsTrigger({
38
+ className,
39
+ ...props
40
+ }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
41
+ return (
42
+ <TabsPrimitive.Trigger
43
+ data-slot="tabs-trigger"
44
+ className={cn(
45
+ "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ )
51
+ }
52
+
53
+ function TabsContent({
54
+ className,
55
+ ...props
56
+ }: React.ComponentProps<typeof TabsPrimitive.Content>) {
57
+ return (
58
+ <TabsPrimitive.Content
59
+ data-slot="tabs-content"
60
+ className={cn("flex-1 outline-none", className)}
61
+ {...props}
62
+ />
63
+ )
64
+ }
65
+
66
+ export { Tabs, TabsList, TabsTrigger, TabsContent }
@@ -0,0 +1,18 @@
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
+ <textarea
8
+ data-slot="textarea"
9
+ className={cn(
10
+ "border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ export { Textarea }
@@ -0,0 +1,167 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useMemo, useState } from 'react';
4
+ import { useAccount, useConnect, useDisconnect, useChainId, useSwitchChain } from 'wagmi';
5
+ import { Button } from '@/components/ui/button';
6
+ import { Wallet, LogOut, AlertCircle } from 'lucide-react';
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuItem,
11
+ DropdownMenuSeparator,
12
+ DropdownMenuTrigger,
13
+ } from '@/components/ui/dropdown-menu';
14
+ import { arbitrum, arbitrumSepolia } from 'wagmi/chains';
15
+ import { xaiSepolia, apechainCurtis, nitrogenTestnet, isOrbitChain } from '@/lib/orbit-chains';
16
+
17
+ export function ConnectButton() {
18
+ const [mounted, setMounted] = useState(false);
19
+ useEffect(() => setMounted(true), []);
20
+
21
+ const { address, isConnected, chain } = useAccount();
22
+ const { connect, connectors } = useConnect();
23
+ const { disconnect } = useDisconnect();
24
+ const chainId = useChainId();
25
+ const { switchChain } = useSwitchChain();
26
+
27
+ const supportedChains = useMemo(() => [
28
+ arbitrumSepolia,
29
+ arbitrum,
30
+ xaiSepolia,
31
+ apechainCurtis,
32
+ nitrogenTestnet,
33
+ ], []);
34
+ const activeChain = supportedChains.find((c) => c.id === chainId);
35
+ const isWrongNetwork = isConnected && !activeChain;
36
+
37
+ // ✅ Prevent hydration mismatch: render stable placeholder until mounted
38
+ if (!mounted) {
39
+ return (
40
+ <Button size="sm" variant="outline" disabled>
41
+ <Wallet className="h-4 w-4 mr-2" />
42
+ Connect Wallet
43
+ </Button>
44
+ );
45
+ }
46
+
47
+ if (!isConnected) {
48
+ return (
49
+ <DropdownMenu>
50
+ <DropdownMenuTrigger asChild>
51
+ <Button size="sm">
52
+ <Wallet className="h-4 w-4 mr-2" />
53
+ Connect Wallet
54
+ </Button>
55
+ </DropdownMenuTrigger>
56
+ <DropdownMenuContent align="end">
57
+ {connectors.map((connector) => (
58
+ <DropdownMenuItem
59
+ key={connector.id}
60
+ onClick={() => connect({ connector })}
61
+ >
62
+ {connector.name}
63
+ </DropdownMenuItem>
64
+ ))}
65
+ </DropdownMenuContent>
66
+ </DropdownMenu>
67
+ );
68
+ }
69
+
70
+ if (isWrongNetwork) {
71
+ return (
72
+ <DropdownMenu>
73
+ <DropdownMenuTrigger asChild>
74
+ <Button size="sm" variant="destructive">
75
+ <AlertCircle className="h-4 w-4 mr-2" />
76
+ Wrong Network
77
+ </Button>
78
+ </DropdownMenuTrigger>
79
+ <DropdownMenuContent align="end">
80
+ <div className="px-2 py-1.5 text-sm font-semibold">Switch to:</div>
81
+ <DropdownMenuSeparator />
82
+ {supportedChains.map((c) => (
83
+ <DropdownMenuItem
84
+ key={c.id}
85
+ onClick={() => switchChain({ chainId: c.id })}
86
+ >
87
+ {c.name}
88
+ </DropdownMenuItem>
89
+ ))}
90
+ </DropdownMenuContent>
91
+ </DropdownMenu>
92
+ );
93
+ }
94
+
95
+ const displayAddress = address ? `${address.slice(0, 6)}...${address.slice(-4)}` : '';
96
+
97
+ return (
98
+ <div className="flex gap-2">
99
+ {/* Chain Switcher */}
100
+ <DropdownMenu>
101
+ <DropdownMenuTrigger asChild>
102
+ <Button variant="outline" size="sm" className="hidden sm:flex">
103
+ {chain?.name || 'Unknown'}
104
+ {chain && isOrbitChain(chain.id) && (
105
+ <span className="ml-1.5 text-xs bg-primary/20 text-primary px-1.5 py-0.5 rounded">
106
+ Orbit
107
+ </span>
108
+ )}
109
+ </Button>
110
+ </DropdownMenuTrigger>
111
+ <DropdownMenuContent align="end">
112
+ <div className="px-2 py-1.5 text-xs font-semibold text-muted-foreground">
113
+ Arbitrum Networks
114
+ </div>
115
+ <DropdownMenuSeparator />
116
+ {supportedChains.filter(c => !isOrbitChain(c.id)).map((supportedChain) => (
117
+ <DropdownMenuItem
118
+ key={supportedChain.id}
119
+ onClick={() => switchChain({ chainId: supportedChain.id })}
120
+ disabled={chainId === supportedChain.id}
121
+ >
122
+ {supportedChain.name}
123
+ {chainId === supportedChain.id && ' ✓'}
124
+ </DropdownMenuItem>
125
+ ))}
126
+
127
+ <div className="px-2 py-1.5 text-xs font-semibold text-muted-foreground mt-2">
128
+ Orbit Chains
129
+ </div>
130
+ <DropdownMenuSeparator />
131
+ {supportedChains.filter(c => isOrbitChain(c.id)).map((supportedChain) => (
132
+ <DropdownMenuItem
133
+ key={supportedChain.id}
134
+ onClick={() => switchChain({ chainId: supportedChain.id })}
135
+ disabled={chainId === supportedChain.id}
136
+ className="text-xs"
137
+ >
138
+ {supportedChain.name}
139
+ {chainId === supportedChain.id && ' ✓'}
140
+ </DropdownMenuItem>
141
+ ))}
142
+ </DropdownMenuContent>
143
+ </DropdownMenu>
144
+
145
+ {/* Account Menu */}
146
+ <DropdownMenu>
147
+ <DropdownMenuTrigger asChild>
148
+ <Button variant="outline" size="sm">
149
+ <Wallet className="h-4 w-4 mr-2" />
150
+ {displayAddress}
151
+ </Button>
152
+ </DropdownMenuTrigger>
153
+ <DropdownMenuContent align="end">
154
+ <div className="px-2 py-1.5 text-sm">
155
+ <div className="font-semibold">Account</div>
156
+ <div className="text-xs text-muted-foreground font-mono">{address}</div>
157
+ </div>
158
+ <DropdownMenuSeparator />
159
+ <DropdownMenuItem onClick={() => disconnect()}>
160
+ <LogOut className="h-4 w-4 mr-2" />
161
+ Disconnect
162
+ </DropdownMenuItem>
163
+ </DropdownMenuContent>
164
+ </DropdownMenu>
165
+ </div>
166
+ );
167
+ }