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.
- package/Readme.MD +1515 -0
- package/cli.js +28 -0
- package/frontend/.vscode/settings.json +9 -0
- package/frontend/app/api/chat/route.ts +101 -0
- package/frontend/app/api/check-setup/route.ts +93 -0
- package/frontend/app/api/cleanup/route.ts +14 -0
- package/frontend/app/api/compile/route.ts +95 -0
- package/frontend/app/api/compile-stream/route.ts +98 -0
- package/frontend/app/api/complete/route.ts +86 -0
- package/frontend/app/api/deploy/route.ts +118 -0
- package/frontend/app/api/export-abi/route.ts +58 -0
- package/frontend/app/favicon.ico +0 -0
- package/frontend/app/globals.css +177 -0
- package/frontend/app/layout.tsx +29 -0
- package/frontend/app/ml/page.tsx +694 -0
- package/frontend/app/page.tsx +1132 -0
- package/frontend/app/providers.tsx +18 -0
- package/frontend/app/qlearning/page.tsx +188 -0
- package/frontend/app/raytracing/page.tsx +268 -0
- package/frontend/components/abi/ABIDialog.tsx +132 -0
- package/frontend/components/ai/AICompletionPopup.tsx +76 -0
- package/frontend/components/ai/ChatPanel.tsx +292 -0
- package/frontend/components/ai/QuickActions.tsx +128 -0
- package/frontend/components/blockchain/BlockchainContractBanner.tsx +64 -0
- package/frontend/components/blockchain/BlockchainLoadingDialog.tsx +188 -0
- package/frontend/components/deploy/DeployDialog.tsx +334 -0
- package/frontend/components/editor/FileTabs.tsx +181 -0
- package/frontend/components/editor/MonacoEditor.tsx +306 -0
- package/frontend/components/file-tree/ContextMenu.tsx +110 -0
- package/frontend/components/file-tree/DeleteConfirmDialog.tsx +61 -0
- package/frontend/components/file-tree/FileInputDialog.tsx +97 -0
- package/frontend/components/file-tree/FileNode.tsx +60 -0
- package/frontend/components/file-tree/FileTree.tsx +259 -0
- package/frontend/components/file-tree/FileTreeSkeleton.tsx +26 -0
- package/frontend/components/file-tree/FolderNode.tsx +105 -0
- package/frontend/components/github/GitHubLoadingDialog.tsx +201 -0
- package/frontend/components/github/GitHubMetadataBanner.tsx +61 -0
- package/frontend/components/github/LoadFromGitHubDialog.tsx +125 -0
- package/frontend/components/github/URLCopyButton.tsx +60 -0
- package/frontend/components/interact/ContractInteraction.tsx +323 -0
- package/frontend/components/interact/ContractPlaceholder.tsx +41 -0
- package/frontend/components/orbit/BenchmarkDialog.tsx +342 -0
- package/frontend/components/orbit/OrbitExplorer.tsx +273 -0
- package/frontend/components/project/ProjectActions.tsx +176 -0
- package/frontend/components/q-learning/ContractConfig.tsx +172 -0
- package/frontend/components/q-learning/MazeGrid.tsx +346 -0
- package/frontend/components/q-learning/PathAnimation.tsx +384 -0
- package/frontend/components/q-learning/QTableHeatmap.tsx +300 -0
- package/frontend/components/q-learning/TrainingForm.tsx +349 -0
- package/frontend/components/ray-tracing/ContractConfig.tsx +245 -0
- package/frontend/components/ray-tracing/MintingForm.tsx +280 -0
- package/frontend/components/ray-tracing/RenderCanvas.tsx +228 -0
- package/frontend/components/ray-tracing/RenderingPanel.tsx +259 -0
- package/frontend/components/ray-tracing/StyleControls.tsx +217 -0
- package/frontend/components/setup/SetupGuide.tsx +290 -0
- package/frontend/components/ui/KeyboardShortcutHint.tsx +74 -0
- package/frontend/components/ui/alert-dialog.tsx +157 -0
- package/frontend/components/ui/alert.tsx +66 -0
- package/frontend/components/ui/badge.tsx +46 -0
- package/frontend/components/ui/button.tsx +62 -0
- package/frontend/components/ui/card.tsx +92 -0
- package/frontend/components/ui/context-menu.tsx +252 -0
- package/frontend/components/ui/dialog.tsx +143 -0
- package/frontend/components/ui/dropdown-menu.tsx +257 -0
- package/frontend/components/ui/input.tsx +21 -0
- package/frontend/components/ui/label.tsx +24 -0
- package/frontend/components/ui/progress.tsx +31 -0
- package/frontend/components/ui/scroll-area.tsx +58 -0
- package/frontend/components/ui/select.tsx +190 -0
- package/frontend/components/ui/separator.tsx +28 -0
- package/frontend/components/ui/sheet.tsx +139 -0
- package/frontend/components/ui/skeleton.tsx +13 -0
- package/frontend/components/ui/slider.tsx +63 -0
- package/frontend/components/ui/sonner.tsx +40 -0
- package/frontend/components/ui/tabs.tsx +66 -0
- package/frontend/components/ui/textarea.tsx +18 -0
- package/frontend/components/wallet/ConnectButton.tsx +167 -0
- package/frontend/components/wallet/FaucetButton.tsx +256 -0
- package/frontend/components.json +22 -0
- package/frontend/eslint.config.mjs +18 -0
- package/frontend/hooks/useAICompletion.ts +75 -0
- package/frontend/hooks/useBlockchainLoader.ts +58 -0
- package/frontend/hooks/useChats.ts +137 -0
- package/frontend/hooks/useCompilation.ts +173 -0
- package/frontend/hooks/useFileTabs.ts +178 -0
- package/frontend/hooks/useGitHubLoader.ts +50 -0
- package/frontend/hooks/useKeyboardShortcuts.ts +47 -0
- package/frontend/hooks/usePanelState.ts +115 -0
- package/frontend/hooks/useProjectState.ts +276 -0
- package/frontend/hooks/useResponsive.ts +29 -0
- package/frontend/lib/abi-parser.ts +58 -0
- package/frontend/lib/blockchain-api.ts +374 -0
- package/frontend/lib/blockchain-explorers.ts +75 -0
- package/frontend/lib/blockchain-loader.ts +112 -0
- package/frontend/lib/cargo-template.ts +64 -0
- package/frontend/lib/compilation.ts +529 -0
- package/frontend/lib/constants.ts +31 -0
- package/frontend/lib/deployment.ts +176 -0
- package/frontend/lib/file-utils.ts +83 -0
- package/frontend/lib/github-api.ts +246 -0
- package/frontend/lib/github-loader.ts +369 -0
- package/frontend/lib/ml-contract-template.txt +900 -0
- package/frontend/lib/orbit-chains.ts +181 -0
- package/frontend/lib/output-formatter.ts +68 -0
- package/frontend/lib/project-manager.ts +632 -0
- package/frontend/lib/ray-tracing-abi.ts +206 -0
- package/frontend/lib/storage.ts +189 -0
- package/frontend/lib/templates.ts +1662 -0
- package/frontend/lib/url-parser.ts +188 -0
- package/frontend/lib/utils.ts +6 -0
- package/frontend/lib/wagmi-config.ts +24 -0
- package/frontend/next.config.ts +7 -0
- package/frontend/package-lock.json +16259 -0
- package/frontend/package.json +60 -0
- package/frontend/postcss.config.mjs +7 -0
- package/frontend/public/file.svg +1 -0
- package/frontend/public/globe.svg +1 -0
- package/frontend/public/ml-weights/.gitkeep +0 -0
- package/frontend/public/ml-weights/model.pkl +0 -0
- package/frontend/public/ml-weights/model_weights.json +27102 -0
- package/frontend/public/ml-weights/test_samples.json +7888 -0
- package/frontend/public/next.svg +1 -0
- package/frontend/public/vercel.svg +1 -0
- package/frontend/public/window.svg +1 -0
- package/frontend/scripts/check-env.js +52 -0
- package/frontend/scripts/setup.js +285 -0
- package/frontend/tailwind.config.ts +64 -0
- package/frontend/tsconfig.json +34 -0
- package/frontend/types/blockchain.ts +63 -0
- package/frontend/types/github.ts +54 -0
- package/frontend/types/project.ts +106 -0
- package/ml-training/README.md +56 -0
- package/ml-training/train_tiny_model.py +325 -0
- package/ml-training/update_template.py +59 -0
- package/package.json +30 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
5
|
+
import { Button } from '@/components/ui/button';
|
|
6
|
+
import { CheckCircle2, XCircle, Loader2, RefreshCw, Zap, AlertTriangle } from 'lucide-react';
|
|
7
|
+
|
|
8
|
+
interface SetupStatus {
|
|
9
|
+
rust: boolean;
|
|
10
|
+
cargo: boolean;
|
|
11
|
+
wasmTarget: boolean;
|
|
12
|
+
cargoStylus: boolean;
|
|
13
|
+
platform: 'darwin' | 'linux' | 'win32' | 'other';
|
|
14
|
+
rustVersion?: string;
|
|
15
|
+
needsUpdate?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function SetupGuide() {
|
|
19
|
+
const [status, setStatus] = useState<SetupStatus | null>(null);
|
|
20
|
+
const [loading, setLoading] = useState(true);
|
|
21
|
+
const [error, setError] = useState<string | null>(null);
|
|
22
|
+
|
|
23
|
+
const checkSetup = async () => {
|
|
24
|
+
setLoading(true);
|
|
25
|
+
setError(null);
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch('/api/check-setup');
|
|
28
|
+
if (!response.ok) throw new Error('Failed to check setup');
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
setStatus(data);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
33
|
+
} finally {
|
|
34
|
+
setLoading(false);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
checkSetup();
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
const isSetupComplete = status && status.rust && status.cargo && status.wasmTarget && status.cargoStylus && !status.needsUpdate;
|
|
43
|
+
|
|
44
|
+
if (loading) {
|
|
45
|
+
return (
|
|
46
|
+
<div className="fixed inset-0 bg-background/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
|
47
|
+
<Card className="w-full max-w-md">
|
|
48
|
+
<CardHeader>
|
|
49
|
+
<CardTitle className="text-lg md:text-xl">Checking Environment</CardTitle>
|
|
50
|
+
</CardHeader>
|
|
51
|
+
<CardContent className="flex items-center justify-center py-8">
|
|
52
|
+
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
53
|
+
</CardContent>
|
|
54
|
+
</Card>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (error) {
|
|
60
|
+
return (
|
|
61
|
+
<div className="fixed inset-0 bg-background/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
|
62
|
+
<Card className="w-full max-w-md">
|
|
63
|
+
<CardHeader>
|
|
64
|
+
<CardTitle className="text-lg md:text-xl">Setup Check Failed</CardTitle>
|
|
65
|
+
<CardDescription className="text-destructive text-sm">{error}</CardDescription>
|
|
66
|
+
</CardHeader>
|
|
67
|
+
<CardContent>
|
|
68
|
+
<Button onClick={checkSetup} className="w-full">
|
|
69
|
+
<RefreshCw className="mr-2 h-4 w-4" />
|
|
70
|
+
Try Again
|
|
71
|
+
</Button>
|
|
72
|
+
</CardContent>
|
|
73
|
+
</Card>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (isSetupComplete) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const getInstructions = () => {
|
|
83
|
+
if (!status) return null;
|
|
84
|
+
|
|
85
|
+
const isUnix = status.platform === 'darwin' || status.platform === 'linux';
|
|
86
|
+
const isWindows = status.platform === 'win32';
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div className="space-y-4 md:space-y-6">
|
|
90
|
+
{/* Rust Version Warning */}
|
|
91
|
+
{status.needsUpdate && (
|
|
92
|
+
<div className="bg-yellow-500/10 border border-yellow-500/20 p-4 rounded-md space-y-3">
|
|
93
|
+
<div className="flex items-start gap-3">
|
|
94
|
+
<AlertTriangle className="h-5 w-5 text-yellow-500 shrink-0 mt-0.5" />
|
|
95
|
+
<div className="space-y-2 flex-1">
|
|
96
|
+
<h4 className="font-semibold text-sm">Rust Version Too Old</h4>
|
|
97
|
+
<p className="text-xs md:text-sm text-muted-foreground">
|
|
98
|
+
Detected: {status.rustVersion || 'unknown'}
|
|
99
|
+
<br />
|
|
100
|
+
Required: 1.88.0+ (for cargo-stylus v0.6.3+)
|
|
101
|
+
</p>
|
|
102
|
+
<div className="bg-muted p-3 rounded-md">
|
|
103
|
+
<code className="text-xs md:text-sm">rustup update stable</code>
|
|
104
|
+
</div>
|
|
105
|
+
<p className="text-xs text-muted-foreground">
|
|
106
|
+
Then run <code className="bg-muted px-1 rounded">npm run setup</code> again
|
|
107
|
+
</p>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
112
|
+
|
|
113
|
+
{/* Quick Setup Section */}
|
|
114
|
+
<div className="bg-primary/10 border border-primary/20 p-4 rounded-md space-y-3">
|
|
115
|
+
<div className="flex items-start gap-3">
|
|
116
|
+
<Zap className="h-5 w-5 text-primary shrink-0 mt-0.5" />
|
|
117
|
+
<div className="space-y-2 flex-1">
|
|
118
|
+
<h4 className="font-semibold text-sm md:text-base">Quick Setup (Recommended)</h4>
|
|
119
|
+
<p className="text-xs md:text-sm text-muted-foreground">
|
|
120
|
+
Run this command in your terminal to automatically install all requirements:
|
|
121
|
+
</p>
|
|
122
|
+
<div className="bg-muted p-3 rounded-md">
|
|
123
|
+
<code className="text-xs md:text-sm">npm run setup</code>
|
|
124
|
+
</div>
|
|
125
|
+
<p className="text-xs text-muted-foreground">
|
|
126
|
+
This will check your Rust version and guide you through any needed updates
|
|
127
|
+
</p>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
{/* Manual Setup Instructions */}
|
|
133
|
+
<details className="space-y-4">
|
|
134
|
+
<summary className="cursor-pointer text-sm font-semibold text-muted-foreground hover:text-foreground">
|
|
135
|
+
Or install manually
|
|
136
|
+
</summary>
|
|
137
|
+
|
|
138
|
+
<div className="space-y-4 pt-4">
|
|
139
|
+
{status.needsUpdate && (
|
|
140
|
+
<div className="space-y-2">
|
|
141
|
+
<h4 className="font-semibold text-sm md:text-base">1. Update Rust</h4>
|
|
142
|
+
<div className="bg-muted p-3 md:p-4 rounded-md overflow-x-auto">
|
|
143
|
+
<code className="text-xs md:text-sm whitespace-pre">
|
|
144
|
+
rustup update stable
|
|
145
|
+
</code>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
{(!status.rust || !status.cargo) && (
|
|
151
|
+
<div className="space-y-2">
|
|
152
|
+
<h4 className="font-semibold text-sm md:text-base">
|
|
153
|
+
{status.needsUpdate ? '2' : '1'}. Install Rust
|
|
154
|
+
</h4>
|
|
155
|
+
{isUnix && (
|
|
156
|
+
<div className="bg-muted p-3 md:p-4 rounded-md overflow-x-auto">
|
|
157
|
+
<code className="text-xs md:text-sm whitespace-pre">
|
|
158
|
+
curl --proto='=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
159
|
+
</code>
|
|
160
|
+
</div>
|
|
161
|
+
)}
|
|
162
|
+
{isWindows && (
|
|
163
|
+
<div className="space-y-2">
|
|
164
|
+
<p className="text-xs md:text-sm text-muted-foreground">
|
|
165
|
+
Download and run the Rust installer from:
|
|
166
|
+
</p>
|
|
167
|
+
<a
|
|
168
|
+
href="https://rustup.rs"
|
|
169
|
+
target="_blank"
|
|
170
|
+
rel="noopener noreferrer"
|
|
171
|
+
className="text-xs md:text-sm text-primary hover:underline break-all"
|
|
172
|
+
>
|
|
173
|
+
https://rustup.rs
|
|
174
|
+
</a>
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
</div>
|
|
178
|
+
)}
|
|
179
|
+
|
|
180
|
+
{!status.wasmTarget && status.rust && (
|
|
181
|
+
<div className="space-y-2">
|
|
182
|
+
<h4 className="font-semibold text-sm md:text-base">
|
|
183
|
+
{(!status.rust || status.needsUpdate) ? '3' : '2'}. Add WASM Target
|
|
184
|
+
</h4>
|
|
185
|
+
<div className="bg-muted p-3 md:p-4 rounded-md overflow-x-auto">
|
|
186
|
+
<code className="text-xs md:text-sm whitespace-pre">
|
|
187
|
+
rustup target add wasm32-unknown-unknown
|
|
188
|
+
</code>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
{!status.cargoStylus && status.cargo && (
|
|
194
|
+
<div className="space-y-2">
|
|
195
|
+
<h4 className="font-semibold text-sm md:text-base">
|
|
196
|
+
{(!status.rust || status.needsUpdate || !status.wasmTarget) ? '4' : '3'}. Install Cargo Stylus
|
|
197
|
+
</h4>
|
|
198
|
+
<div className="bg-muted p-3 md:p-4 rounded-md overflow-x-auto space-y-2">
|
|
199
|
+
<code className="text-xs md:text-sm whitespace-pre block">
|
|
200
|
+
cargo install cargo-stylus
|
|
201
|
+
</code>
|
|
202
|
+
<p className="text-xs text-muted-foreground">
|
|
203
|
+
If this fails, try: <code className="bg-background px-1 rounded">cargo install cargo-stylus --locked</code>
|
|
204
|
+
</p>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
)}
|
|
208
|
+
|
|
209
|
+
{isWindows && (
|
|
210
|
+
<div className="bg-yellow-500/10 border border-yellow-500/20 p-3 md:p-4 rounded-md">
|
|
211
|
+
<p className="text-xs md:text-sm text-yellow-600 dark:text-yellow-500">
|
|
212
|
+
<strong>Windows:</strong> Run commands in PowerShell after installing Rust. For best experience, use WSL.
|
|
213
|
+
</p>
|
|
214
|
+
</div>
|
|
215
|
+
)}
|
|
216
|
+
|
|
217
|
+
{isUnix && (
|
|
218
|
+
<div className="bg-blue-500/10 border border-blue-500/20 p-3 md:p-4 rounded-md">
|
|
219
|
+
<p className="text-xs md:text-sm text-blue-600 dark:text-blue-500">
|
|
220
|
+
<strong>Note:</strong> Restart terminal or run <code className="text-xs">source $HOME/.cargo/env</code>
|
|
221
|
+
</p>
|
|
222
|
+
</div>
|
|
223
|
+
)}
|
|
224
|
+
</div>
|
|
225
|
+
</details>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<div className="fixed inset-0 bg-background/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
|
232
|
+
<Card className="w-full max-w-2xl max-h-[90vh] overflow-auto">
|
|
233
|
+
<CardHeader>
|
|
234
|
+
<CardTitle className="text-lg md:text-xl">Setup Required</CardTitle>
|
|
235
|
+
<CardDescription className="text-xs md:text-sm">
|
|
236
|
+
Configure your development environment for Arbitrum Stylus
|
|
237
|
+
</CardDescription>
|
|
238
|
+
</CardHeader>
|
|
239
|
+
<CardContent className="space-y-4 md:space-y-6">
|
|
240
|
+
{/* Status Checks */}
|
|
241
|
+
<div className="space-y-2">
|
|
242
|
+
<h3 className="font-semibold text-sm md:text-base mb-3">Environment Status</h3>
|
|
243
|
+
<StatusItem label="Rust Compiler" status={status?.rust || false} />
|
|
244
|
+
{status?.rustVersion && (
|
|
245
|
+
<div className="ml-7 text-xs text-muted-foreground">
|
|
246
|
+
Version: {status.rustVersion}
|
|
247
|
+
{status.needsUpdate && (
|
|
248
|
+
<span className="text-yellow-500 ml-2">(Update to 1.88+ required)</span>
|
|
249
|
+
)}
|
|
250
|
+
</div>
|
|
251
|
+
)}
|
|
252
|
+
<StatusItem label="Cargo Package Manager" status={status?.cargo || false} />
|
|
253
|
+
<StatusItem label="WASM Target" status={status?.wasmTarget || false} />
|
|
254
|
+
<StatusItem label="Cargo Stylus" status={status?.cargoStylus || false} />
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
{/* Platform Info */}
|
|
258
|
+
<div className="bg-muted p-3 rounded-md">
|
|
259
|
+
<p className="text-xs md:text-sm">
|
|
260
|
+
<span className="font-semibold">Platform:</span>{' '}
|
|
261
|
+
<span className="capitalize">{status?.platform}</span>
|
|
262
|
+
</p>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
{/* Instructions */}
|
|
266
|
+
{getInstructions()}
|
|
267
|
+
|
|
268
|
+
{/* Recheck Button */}
|
|
269
|
+
<Button onClick={checkSetup} className="w-full" size="lg">
|
|
270
|
+
<RefreshCw className="mr-2 h-4 w-4" />
|
|
271
|
+
Check Again
|
|
272
|
+
</Button>
|
|
273
|
+
</CardContent>
|
|
274
|
+
</Card>
|
|
275
|
+
</div>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function StatusItem({ label, status }: { label: string; status: boolean }) {
|
|
280
|
+
return (
|
|
281
|
+
<div className="flex items-center gap-2">
|
|
282
|
+
{status ? (
|
|
283
|
+
<CheckCircle2 className="h-4 w-4 md:h-5 md:w-5 text-green-500 shrink-0" />
|
|
284
|
+
) : (
|
|
285
|
+
<XCircle className="h-4 w-4 md:h-5 md:w-5 text-destructive shrink-0" />
|
|
286
|
+
)}
|
|
287
|
+
<span className="text-xs md:text-sm">{label}</span>
|
|
288
|
+
</div>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { Button } from '@/components/ui/button';
|
|
5
|
+
import { Keyboard, X } from 'lucide-react';
|
|
6
|
+
|
|
7
|
+
export function KeyboardShortcutHint() {
|
|
8
|
+
const [showHint, setShowHint] = useState(false);
|
|
9
|
+
const [hasSeenHint, setHasSeenHint] = useState(false);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// Check if user has seen the hint before
|
|
13
|
+
const seen = localStorage.getItem('keyboard-hint-seen');
|
|
14
|
+
if (!seen) {
|
|
15
|
+
// Show hint after a short delay
|
|
16
|
+
const timer = setTimeout(() => {
|
|
17
|
+
setShowHint(true);
|
|
18
|
+
}, 3000);
|
|
19
|
+
return () => clearTimeout(timer);
|
|
20
|
+
} else {
|
|
21
|
+
setHasSeenHint(true);
|
|
22
|
+
}
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
const dismissHint = () => {
|
|
26
|
+
setShowHint(false);
|
|
27
|
+
setHasSeenHint(true);
|
|
28
|
+
localStorage.setItem('keyboard-hint-seen', 'true');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (!showHint && !hasSeenHint) return null;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
{/* Floating hint for first-time users */}
|
|
36
|
+
{showHint && (
|
|
37
|
+
<div className="fixed bottom-4 right-4 z-50 bg-card border border-border rounded-lg p-4 shadow-lg max-w-sm">
|
|
38
|
+
<div className="flex items-start gap-3">
|
|
39
|
+
<Keyboard className="h-5 w-5 text-primary mt-0.5" />
|
|
40
|
+
<div className="flex-1">
|
|
41
|
+
<h4 className="font-semibold text-sm mb-2">Keyboard Shortcuts</h4>
|
|
42
|
+
<div className="text-xs text-muted-foreground space-y-1">
|
|
43
|
+
<div><kbd className="px-1.5 py-0.5 bg-muted rounded text-xs">⌘K</kbd> Toggle AI Assistant</div>
|
|
44
|
+
<div><kbd className="px-1.5 py-0.5 bg-muted rounded text-xs">⌘`</kbd> Toggle Output Panel</div>
|
|
45
|
+
<div><kbd className="px-1.5 py-0.5 bg-muted rounded text-xs">⌘↵</kbd> Compile Code</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<Button
|
|
49
|
+
variant="ghost"
|
|
50
|
+
size="icon"
|
|
51
|
+
className="h-6 w-6 -mt-1 -mr-1"
|
|
52
|
+
onClick={dismissHint}
|
|
53
|
+
>
|
|
54
|
+
<X className="h-4 w-4" />
|
|
55
|
+
</Button>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
)}
|
|
59
|
+
|
|
60
|
+
{/* Persistent keyboard shortcut button */}
|
|
61
|
+
{hasSeenHint && (
|
|
62
|
+
<Button
|
|
63
|
+
variant="ghost"
|
|
64
|
+
size="icon"
|
|
65
|
+
className="fixed bottom-10 right-10 z-40 h-10 w-10 rounded-full bg-card border border-border shadow-lg hover:shadow-xl transition-all"
|
|
66
|
+
onClick={() => setShowHint(true)}
|
|
67
|
+
title="Show keyboard shortcuts"
|
|
68
|
+
>
|
|
69
|
+
<Keyboard className="h-4 w-4" />
|
|
70
|
+
</Button>
|
|
71
|
+
)}
|
|
72
|
+
</>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { buttonVariants } from "@/components/ui/button"
|
|
8
|
+
|
|
9
|
+
function AlertDialog({
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
12
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function AlertDialogTrigger({
|
|
16
|
+
...props
|
|
17
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
|
18
|
+
return (
|
|
19
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function AlertDialogPortal({
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
26
|
+
return (
|
|
27
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function AlertDialogOverlay({
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
|
35
|
+
return (
|
|
36
|
+
<AlertDialogPrimitive.Overlay
|
|
37
|
+
data-slot="alert-dialog-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 AlertDialogContent({
|
|
48
|
+
className,
|
|
49
|
+
...props
|
|
50
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
|
|
51
|
+
return (
|
|
52
|
+
<AlertDialogPortal>
|
|
53
|
+
<AlertDialogOverlay />
|
|
54
|
+
<AlertDialogPrimitive.Content
|
|
55
|
+
data-slot="alert-dialog-content"
|
|
56
|
+
className={cn(
|
|
57
|
+
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
|
58
|
+
className
|
|
59
|
+
)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
</AlertDialogPortal>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function AlertDialogHeader({
|
|
67
|
+
className,
|
|
68
|
+
...props
|
|
69
|
+
}: React.ComponentProps<"div">) {
|
|
70
|
+
return (
|
|
71
|
+
<div
|
|
72
|
+
data-slot="alert-dialog-header"
|
|
73
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function AlertDialogFooter({
|
|
80
|
+
className,
|
|
81
|
+
...props
|
|
82
|
+
}: React.ComponentProps<"div">) {
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
data-slot="alert-dialog-footer"
|
|
86
|
+
className={cn(
|
|
87
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
88
|
+
className
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function AlertDialogTitle({
|
|
96
|
+
className,
|
|
97
|
+
...props
|
|
98
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
99
|
+
return (
|
|
100
|
+
<AlertDialogPrimitive.Title
|
|
101
|
+
data-slot="alert-dialog-title"
|
|
102
|
+
className={cn("text-lg font-semibold", className)}
|
|
103
|
+
{...props}
|
|
104
|
+
/>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function AlertDialogDescription({
|
|
109
|
+
className,
|
|
110
|
+
...props
|
|
111
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
112
|
+
return (
|
|
113
|
+
<AlertDialogPrimitive.Description
|
|
114
|
+
data-slot="alert-dialog-description"
|
|
115
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
116
|
+
{...props}
|
|
117
|
+
/>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function AlertDialogAction({
|
|
122
|
+
className,
|
|
123
|
+
...props
|
|
124
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
|
|
125
|
+
return (
|
|
126
|
+
<AlertDialogPrimitive.Action
|
|
127
|
+
className={cn(buttonVariants(), className)}
|
|
128
|
+
{...props}
|
|
129
|
+
/>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function AlertDialogCancel({
|
|
134
|
+
className,
|
|
135
|
+
...props
|
|
136
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
|
|
137
|
+
return (
|
|
138
|
+
<AlertDialogPrimitive.Cancel
|
|
139
|
+
className={cn(buttonVariants({ variant: "outline" }), className)}
|
|
140
|
+
{...props}
|
|
141
|
+
/>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
AlertDialog,
|
|
147
|
+
AlertDialogPortal,
|
|
148
|
+
AlertDialogOverlay,
|
|
149
|
+
AlertDialogTrigger,
|
|
150
|
+
AlertDialogContent,
|
|
151
|
+
AlertDialogHeader,
|
|
152
|
+
AlertDialogFooter,
|
|
153
|
+
AlertDialogTitle,
|
|
154
|
+
AlertDialogDescription,
|
|
155
|
+
AlertDialogAction,
|
|
156
|
+
AlertDialogCancel,
|
|
157
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
const alertVariants = cva(
|
|
7
|
+
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-card text-card-foreground",
|
|
12
|
+
destructive:
|
|
13
|
+
"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
variant: "default",
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
function Alert({
|
|
23
|
+
className,
|
|
24
|
+
variant,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
data-slot="alert"
|
|
30
|
+
role="alert"
|
|
31
|
+
className={cn(alertVariants({ variant }), className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
data-slot="alert-title"
|
|
41
|
+
className={cn(
|
|
42
|
+
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
|
|
43
|
+
className
|
|
44
|
+
)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function AlertDescription({
|
|
51
|
+
className,
|
|
52
|
+
...props
|
|
53
|
+
}: React.ComponentProps<"div">) {
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
data-slot="alert-description"
|
|
57
|
+
className={cn(
|
|
58
|
+
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
|
|
59
|
+
className
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { Alert, AlertTitle, AlertDescription }
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
14
|
+
secondary:
|
|
15
|
+
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
16
|
+
destructive:
|
|
17
|
+
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
18
|
+
outline:
|
|
19
|
+
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
variant: "default",
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
function Badge({
|
|
29
|
+
className,
|
|
30
|
+
variant,
|
|
31
|
+
asChild = false,
|
|
32
|
+
...props
|
|
33
|
+
}: React.ComponentProps<"span"> &
|
|
34
|
+
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
35
|
+
const Comp = asChild ? Slot : "span"
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Comp
|
|
39
|
+
data-slot="badge"
|
|
40
|
+
className={cn(badgeVariants({ variant }), className)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { Badge, badgeVariants }
|