diff --git a/Makefile.toml b/Makefile.toml index c252768..0043ea1 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -18,6 +18,10 @@ docker pull ghcr.io/hyperledger-solang/solang:latest ''' [tasks.deps] +description = "Install project dependencies" +script = [ + "cargo fetch" +] dependencies = ["deps-wasm", "deps-npm", "deps-docker"] [tasks.build-server] diff --git a/README.md b/README.md index 4020e1d..3bb11a1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Welcome to Solang Playground, a Solidity web editor for that enables editing, co ## Demo -You can experiment with a [hosted version of Solang Playground](https://hypersolang.ddnsfree.com/). +You can experiment with a [hosted version of Solang Playground](https://solang.io/). ## Building diff --git a/packages/frontend/src/app/page.tsx b/packages/frontend/src/app/page.tsx index 38d23e3..b43c4a4 100644 --- a/packages/frontend/src/app/page.tsx +++ b/packages/frontend/src/app/page.tsx @@ -2,9 +2,9 @@ import Console from "@/components/Console"; import Editor from "@/components/Editor"; -import Header from "@/components/Header"; -import SidePanel from "@/components/SidePanel"; +import { Header, FileTabs } from "@/components/Header"; import Sidebar from "@/components/Sidebar"; +import RightPanel from "@/components/RightPanel"; import HomeTab from "@/components/HomeTab"; import { Toaster } from "@/components/ui/sonner" import { useSelector } from "@xstate/store/react"; @@ -14,21 +14,21 @@ export default function Home() { const currentFile = useSelector(store, (state) => state.context.currentFile); console.log("[Home] currentFile", currentFile); return ( -
-
-
- - -
-
-
- - {/* */} -
- +
+
+
+ +
+ +
+ + {/* */}
- {/*
*/} + +
+
+
diff --git a/packages/frontend/src/components/AccountSelectionModal.tsx b/packages/frontend/src/components/AccountSelectionModal.tsx new file mode 100644 index 0000000..72e39a8 --- /dev/null +++ b/packages/frontend/src/components/AccountSelectionModal.tsx @@ -0,0 +1,191 @@ +"use client"; + +import { useState } from "react"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog"; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; +import { Label } from "./ui/label"; +import { FaUserCircle, FaPlus, FaCopy, FaCheck } from "react-icons/fa"; + +interface Account { + id: string; + name: string; + address: string; + balance: string; +} + +interface AccountSelectionModalProps { + isOpen: boolean; + onClose: () => void; + onAccountSelect: (account: string) => void; +} + +function AccountSelectionModal({ isOpen, onClose, onAccountSelect }: AccountSelectionModalProps) { + const [accounts] = useState([ + { + id: "1", + name: "Main Account", + address: "0x1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p", + balance: "1,234.56 XLM" + }, + { + id: "2", + name: "Test Account", + address: "0x2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q", + balance: "567.89 XLM" + }, + { + id: "3", + name: "Development Account", + address: "0x3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r", + balance: "890.12 XLM" + } + ]); + + const [isImporting, setIsImporting] = useState(false); + const [newAccountName, setNewAccountName] = useState(""); + const [newAccountKey, setNewAccountKey] = useState(""); + const [copiedAddress, setCopiedAddress] = useState(null); + + const handleAccountSelect = (account: Account) => { + onAccountSelect(account.address); + onClose(); + }; + + const handleImportAccount = () => { + setIsImporting(true); + // Add import logic here + setTimeout(() => { + setIsImporting(false); + setNewAccountName(""); + setNewAccountKey(""); + }, 1000); + }; + + const handleCopyAddress = (address: string) => { + navigator.clipboard.writeText(address); + setCopiedAddress(address); + setTimeout(() => setCopiedAddress(null), 2000); + }; + + const formatAddress = (address: string) => { + return `${address.slice(0, 8)}...${address.slice(-4)}`; + }; + + return ( + + + + + + Select Account + + + Choose an account to use for transactions + + + +
+ {/* Account List */} +
+ {accounts.map((account) => ( +
handleAccountSelect(account)} + className="bg-[#2d2d2d] p-4 rounded-md cursor-pointer hover:bg-[#3a3a3a] transition-colors border border-[#404040] hover:border-[#8b5cf6]" + > +
+
+

{account.name}

+
+ {formatAddress(account.address)} + +
+

{account.balance}

+
+
+
+ ))} +
+ + {/* Import New Account */} +
+

Import Account

+ +
+
+ + setNewAccountName(e.target.value)} + placeholder="Enter account name..." + className="bg-[#2d2d2d] border-[#404040] text-white placeholder-[#9ca3af] focus:border-[#8b5cf6] mt-1" + /> +
+ +
+ + setNewAccountKey(e.target.value)} + placeholder="Enter private key..." + className="bg-[#2d2d2d] border-[#404040] text-white placeholder-[#9ca3af] focus:border-[#8b5cf6] mt-1" + /> +
+ + +
+
+
+ + {/* Actions */} +
+ +
+
+
+ ); +} + +export default AccountSelectionModal; diff --git a/packages/frontend/src/components/CompilerOptionsModal.tsx b/packages/frontend/src/components/CompilerOptionsModal.tsx new file mode 100644 index 0000000..3e1741e --- /dev/null +++ b/packages/frontend/src/components/CompilerOptionsModal.tsx @@ -0,0 +1,226 @@ +"use client"; + +import { useState } from "react"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog"; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; +import { Label } from "./ui/label"; +import { Checkbox } from "./ui/checkbox"; +import { FaCog, FaCode, FaCheck, FaHammer } from "react-icons/fa"; +import useCompile from "@/hooks/useCompile"; +import { useSelector } from "@xstate/store/react"; +import { store } from "@/state"; +import { get } from "lodash"; +import { FileType } from "@/types/explorer"; +import ErrorModal from "./ErrorModal"; + +interface CompilerOptionsModalProps { + isOpen: boolean; + onClose: () => void; +} + +function CompilerOptionsModal({ isOpen, onClose }: CompilerOptionsModalProps) { + const [quickFlags, setQuickFlags] = useState({ + optimize: false, + emitIr: false, + emitAbi: false, + emitDebug: false, + noStrengthReduce: false, + noDeadStorage: false, + }); + const [customFlags, setCustomFlags] = useState(""); + const [isCompiling, setIsCompiling] = useState(false); + const [showErrorModal, setShowErrorModal] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + + const { compileFile } = useCompile(); + const selected = useSelector(store, (state) => state.context.currentFile); + const obj = useSelector(store, (state) => get(state.context, selected || '')) as FileType; + + const handleCompile = async () => { + setIsCompiling(true); + try { + const result = await compileFile(); + console.log('[-] compilation result', result); + + // Check if compilation failed + if (result.err) { + setErrorMessage(result.err); + setShowErrorModal(true); + return; + } + + // Only add to compiled list if compilation was successful + if (selected && selected !== 'home' && result.data) { + store.send({ type: "addCompiled", path: selected, name: obj.name }); + } + + // Only close modal if compilation was successful + if (result.data) { + onClose(); + } + } catch (error) { + console.error('Compilation failed:', error); + const errMsg = error instanceof Error ? error.message : 'Unknown compilation error'; + setErrorMessage(errMsg); + setShowErrorModal(true); + } finally { + setIsCompiling(false); + } + }; + + const handleQuickFlagChange = (flag: keyof typeof quickFlags) => { + setQuickFlags(prev => ({ + ...prev, + [flag]: !prev[flag] + })); + }; + + return ( + <> + + + + + + Compiler Options + + {/* Intentionally minimal — removed extra descriptive text */} + + +
+ {/* Quick Flags */} +
+

Quick Flags

+ +
+ + + + + + + + + + + +
+
+ + {/* Custom Flags */} +
+ +