Skip to content

Commit

Permalink
Merge pull request WTFAcademy#33 from murrayee/main
Browse files Browse the repository at this point in the history
feat: add pure editor mode
  • Loading branch information
AmazingAng authored Jul 29, 2023
2 parents 65399f1 + 819791f commit ab361c3
Show file tree
Hide file tree
Showing 18 changed files with 3,322 additions and 2,314 deletions.
1 change: 0 additions & 1 deletion .idea/runConfigurations/start_css.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion apps/demo/.env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
GENERATE_SOURCEMAP=false
GENERATE_SOURCEMAP=false
PORT=3001
150 changes: 111 additions & 39 deletions apps/demo/src/App.tsx

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions apps/demo/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,17 @@ body {
margin: 0 auto;
}

.float-button{
width: 50px;
height: 50px;
border-radius: 25px;
background: rgba(0,0,0,0.6);
color: white;
cursor: pointer;
z-index: 111;
position: fixed;
bottom: 60px;
right: 20px;
outline: none;
border: none;
}
2 changes: 1 addition & 1 deletion apps/doc/docs/get-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ import 'solive-core/dist/index.css';

Now you can see the SoLive Component on your page:

```solidity solive height="500px" consoleDefaultVisible="true" deployDefaultVisible="true"
```solidity solive height="500px" consoleDefaultVisible="true" deployDefaultVisible="true" mode="standard"
/**
* @filename Storage.sol
*/
Expand Down
4 changes: 2 additions & 2 deletions apps/doc/docs/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ SoLive is the first open-source lightweight browser-based Solidity Integrated De

Below is a SoLive Codeblock, try to play with the contract!

```solidity solive height="500px" consoleDefaultVisible="true" deployDefaultVisible="true"
```solidity solive height="500px" consoleDefaultVisible="true" deployDefaultVisible="true" mode="standard"
/**
* @filename Storage.sol
*/
Expand Down Expand Up @@ -57,4 +57,4 @@ SoLive is lightweight and flexible by design. It includes only the essential mod
1. Edit Module: We employ the Monaco Editor as the code editor.
2. Compile Module: We utilize `solcjs` to compile smart contracts based on the chosen Solidity version.
3. Deploy Module: We deploy the compiled contracts to the local EVM using a combination of `ethersjs V5` and `ethereumjs vm`.
4. Interact Module: To interact with the deployed contracts, we use `ethersjs V5` and a custom ABI-UI converter.
4. Interact Module: To interact with the deployed contracts, we use `ethersjs V5` and a custom ABI-UI converter.
2 changes: 1 addition & 1 deletion apps/next_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pnpm dev

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
You can start editing the page by modifying `pages/standardEditor.tsx`. The page auto-updates as you edit the file.

[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.

Expand Down
84 changes: 84 additions & 0 deletions packages/core/src/components/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Fragment, useState } from 'react';

import { Dialog, Transition } from '@headlessui/react';

export default function MyModal() {
const [isOpen, setIsOpen] = useState(true);

function closeModal() {
setIsOpen(false);
}

function openModal() {
setIsOpen(true);
}

return (
<>
<div className="fixed inset-0 flex items-center justify-center">
<button
type="button"
onClick={openModal}
className="rounded-md bg-black bg-opacity-20 px-4 py-2 text-sm font-medium text-white hover:bg-opacity-30 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
>
Open dialog
</button>
</div>

<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black bg-opacity-25" />
</Transition.Child>

<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-900"
>
Payment successful
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-gray-500">
Your payment has been successfully submitted. We’ve sent
you an email with all of the details of your order.
</p>
</div>

<div className="mt-4">
<button
type="button"
className="inline-flex justify-center rounded-md border border-transparent bg-blue-100 px-4 py-2 text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
onClick={closeModal}
>
Got it, thanks!
</button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
</>
);
}
27 changes: 15 additions & 12 deletions packages/core/src/components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ type TNavProps<T> = {
label: string;
id: string;
data?: T;
}
delDisabled?: boolean;
};

type TProps = {
/**
Expand All @@ -18,11 +19,16 @@ type TProps = {
onClick?: (nav: TNavProps<any>, index: number) => void;
onDeleteClick?: (nav: TNavProps<any>, index: number) => void;
placeholderElement?: React.ReactNode;
}
};

function NavBar(props: TProps) {
const {
navs = [], globalId = '', activeNavId, onClick, onDeleteClick, placeholderElement,
navs = [],
globalId = '',
activeNavId,
onClick,
onDeleteClick,
placeholderElement,
} = props;
const [activeId, setActiveId] = useState(activeNavId || navs[0]?.id);

Expand All @@ -46,24 +52,21 @@ function NavBar(props: TProps) {
{navs.map((nav, index) => (
<div
key={`${globalId}_${nav.id}_${index}`}
className={`nav ${nav.id === activeId ? 'nav-active' : ''}${nav.id === 'empty' ? ' nav-empty' : ''}`}
className={`nav ${nav.id === activeId ? 'nav-active' : ''}${
nav.id === 'empty' ? ' nav-empty' : ''
}`}
onClick={() => handleClick(nav, index)}
>
<span>{nav.label}</span>
{
nav.id === activeId
&& (
{nav.id === activeId && !nav.delDisabled && (
<XMarkIcon
className="absolute right-2 w-3 h-3 cursor-pointer mt-[2px] text-[#94A0B3]"
onClick={() => handleDeleteClick(nav, index)}
/>
)
}
)}
</div>
))}
<div className="nav-placeholder">
{placeholderElement}
</div>
<div className="nav-placeholder">{placeholderElement}</div>
</div>
);
}
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/editor/contexts/deployedContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { TCompiledContract } from '../../types/contract';
type TContext = {
compiledContracts: TCompiledContract[];
addCompiledContract: (compiledContract: TCompiledContract) => void;
compiledUniqContracts: Record<string, TCompiledContract>;
addCompiledUniqContract: (compiledContract: TCompiledContract) => void;
clearCompiledContract: () => void;
selectedNetwork?: string;
setSelectedNetwork: (network: string) => void;
Expand All @@ -15,20 +17,30 @@ const DeployedContext = React.createContext<TContext | undefined>(undefined);
// Editor Provider
export function DeployedProvider({ children }: { children: React.ReactNode }) {
const [compiledContracts, setCompiledContracts] = useState<TCompiledContract[]>([]);
const [compiledUniqContracts, setCompiledUniqContracts] = useState<Record<string, TCompiledContract>>({});
const [selectedNetwork, setSelectedNetwork] = useState<string>();

const addCompiledContract = (compiledContract: TCompiledContract) => {
setCompiledContracts((old) => [...old, compiledContract]);
};

const addCompiledUniqContract = (compiledContract: TCompiledContract) => {
setCompiledUniqContracts({
...compiledUniqContracts,
[compiledContract.name]: compiledContract,
});
};

const clearCompiledContract = () => {
setCompiledContracts([]);
};

return (
<DeployedContext.Provider
value={{
compiledUniqContracts,
compiledContracts,
addCompiledUniqContract,
addCompiledContract,
clearCompiledContract,
setSelectedNetwork,
Expand Down
63 changes: 40 additions & 23 deletions packages/core/src/editor/contexts/editorContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import React, {
useEffect, useMemo, useReducer, useRef,
} from 'react';
import React, { useEffect, useReducer, useRef } from 'react';

import monacoForTypes, { editor } from 'monaco-editor';

Expand All @@ -17,13 +15,14 @@ export interface IEditorInitState {
}

export interface IEditorReducerActionType {
type: 'updateEditor' |
'updateMonaco' |
'updateModels' |
'updateModelIndex' |
'setCodeParser' |
'updateCodeParserLoading' |
'cleanModels'
type:
| 'updateEditor'
| 'updateMonaco'
| 'updateModels'
| 'updateModelIndex'
| 'setCodeParser'
| 'updateCodeParserLoading'
| 'cleanModels';
payload: Partial<IEditorInitState> & { id?: string };
}

Expand All @@ -35,17 +34,19 @@ export type TEditorReducerAction = {
setCodeParser: (m: any) => void;
updateCodeParserLoading: (m: boolean) => void;
cleanModels: () => void;
}
};

export type TEditorContext = {
state: IEditorInitState;
stateRef: React.MutableRefObject<IEditorInitState>;
dispatch: React.Dispatch<IEditorReducerActionType>;
actions: TEditorReducerAction;
id: string;
}
};

const EditorContext = React.createContext<TEditorContext | undefined>(undefined);
const EditorContext = React.createContext<TEditorContext | undefined>(
undefined,
);

// Editor Reducer And State
const editorInitState: IEditorInitState = {
Expand All @@ -57,7 +58,10 @@ const editorInitState: IEditorInitState = {
codeParserInitLoading: false,
};

const editorReducer = (state: IEditorInitState, action: IEditorReducerActionType): IEditorInitState => {
const editorReducer = (
state: IEditorInitState,
action: IEditorReducerActionType,
): IEditorInitState => {
switch (action.type) {
case 'updateEditor':
return { ...state, editor: action.payload.editor };
Expand All @@ -68,9 +72,15 @@ const editorReducer = (state: IEditorInitState, action: IEditorReducerActionType
case 'updateModelIndex':
return { ...state, modelIndex: action.payload.modelIndex };
case 'setCodeParser':
return { ...state, codeParser: action.payload.codeParser || {} as CodeParser };
return {
...state,
codeParser: action.payload.codeParser || ({} as CodeParser),
};
case 'updateCodeParserLoading':
return { ...state, codeParserInitLoading: action.payload.codeParserInitLoading || false };
return {
...state,
codeParserInitLoading: action.payload.codeParserInitLoading || false,
};
default:
return state;
}
Expand All @@ -80,11 +90,19 @@ const editorStateMap = new Map<string, IEditorInitState>();

// TODO: 待删减拆分后的部分
// Editor Provider
export function EditorProvider({ children, id }: { children: React.ReactNode, id: string }) {
const [state, dispatch] = useReducer<React.Reducer<IEditorInitState, IEditorReducerActionType>>(editorReducer, editorInitState);
export function EditorProvider({
children,
id,
}: {
children: React.ReactNode;
id: string;
}) {
const [state, dispatch] = useReducer<
React.Reducer<IEditorInitState, IEditorReducerActionType>
>(editorReducer, editorInitState);
const stateRef = useRef<IEditorInitState>(state);
// some provider need to access the state directly
const actions: TEditorReducerAction = useMemo(() => ({
const actions: TEditorReducerAction = {
updateEditor: (editor: BaseMonacoEditor) => dispatch({ type: 'updateEditor', payload: { editor } }),
updateMonaco: (monaco: typeof monacoForTypes) => dispatch({ type: 'updateMonaco', payload: { monaco } }),
updateModels: (models: ModelType[]) => dispatch({ type: 'updateModels', payload: { models } }),
Expand All @@ -95,22 +113,21 @@ export function EditorProvider({ children, id }: { children: React.ReactNode, id
payload: { codeParserInitLoading },
}),
cleanModels: () => dispatch({ type: 'updateModels', payload: { models: [] } }),
}), []);
};

useEffect(() => {
const oldState = editorStateMap.get(id) || {};
editorStateMap.set(id, Object.assign(oldState, state || {}));
stateRef.current = Object.assign(oldState, state || {});
}, [state, id]);

const contextState = useMemo(() => ({
const contextState = {
state,
dispatch,
stateRef,
actions,
id,
}), [state, dispatch, actions, id]);

};
return (
<EditorContext.Provider value={contextState}>
{children}
Expand Down
Loading

0 comments on commit ab361c3

Please sign in to comment.