diff --git a/ui/components/CardTemplate/index.tsx b/ui/components/CardTemplate/index.tsx new file mode 100644 index 0000000..fd10f85 --- /dev/null +++ b/ui/components/CardTemplate/index.tsx @@ -0,0 +1,96 @@ +import { useIDL } from "@/context/IDL"; +import { checkNFT } from "@/helpers"; +import { useAnchorWallet, useConnection } from "@solana/wallet-adapter-react"; +import JSZip from "jszip"; +import Image from "next/image" +import { FC } from "react"; + +const CardTemplate: FC = ({ template, indexTemplate }) => { + const { IDL } = useIDL() + const { connection } = useConnection() + const wallet = useAnchorWallet(); + + const exportProject = async () => { + if (await checkNFT(connection, wallet)) { + const response = await fetch(`https://soda.shuttleapp.rs/get_project_files/${indexTemplate}`, { + method: "POST", + body: JSON.stringify({ idl: IDL }) + }) + const { files } = await response.json() + const zip = new JSZip(); + + // Iterate over each file in the response + files.forEach((file: any) => { + const { path, content } = file; + + // Create folders and file in memory + const folders = path.split('/'); + const fileName = folders.pop(); + + let folder = zip; + folders.forEach((folderName: any) => { + folder = folder.folder(folderName) as JSZip + }); + + // Set the content of the file + if (typeof content.String != "undefined") { + folder.file(fileName, content.String); + } else { + folder.file(fileName, content.Vec) + } + }); + + // Generate the zip file asynchronously + zip.generateAsync({ type: 'blob' }).then(blob => { + // Provide a way for the user to download the zip file + const url = URL.createObjectURL(blob); + // Example: Create a download link and trigger the click event + const downloadLink = document.createElement('a'); + downloadLink.href = url; + downloadLink.download = `${IDL.name || " "}.zip`; + downloadLink.click(); + + // Clean up the created URL object + URL.revokeObjectURL(url); + }); + } else { + alert("need to be coneected with a wallet with the Soda NFT") + } + } + + return ( +
+
+

+ { + !template?.price ? + "Free Template" + : + `${template?.price?.toString()} ${template.currency} ` + } +

+

v{template?.version}

+
+
+ < Image className="h-20 w-20" width={5} height={2} src={template.image || "/soda.svg"} alt={template.name} /> +

{template.name}

+

{template.description}

+
+ {/*
+

Brought to you by

+ +
+ {template.name} +
+
*/} + +
+ ) +} + +export default CardTemplate \ No newline at end of file diff --git a/ui/components/ClassicEditor/card/index.tsx b/ui/components/ClassicEditor/card/index.tsx deleted file mode 100644 index 70da2d0..0000000 --- a/ui/components/ClassicEditor/card/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { FC } from "react"; -import { TrashIcon } from "@heroicons/react/24/solid" -import { useIDL } from "@/context/IDL"; - -export const Card: FC = ({ prop, item, onClick, index, setEdit }) => { - const { IDL, setIDL } = useIDL() - - const deleteItem = () => { - const del = IDL[prop].toSpliced(index, 1) - setIDL({ - ...IDL, - [prop]: del - }) - } - - return ( - -
{setEdit({item, index})}} - > - { - e.stopPropagation() - deleteItem() - }} className="absolute z-20 text-border bottom-2 right-2 w-4 h-4 hover:text-yellow" /> -

{item.name}

-
- ) -} \ No newline at end of file diff --git a/ui/components/Layout/index.tsx b/ui/components/Layout/index.tsx index f9c9a12..9d65dfc 100644 --- a/ui/components/Layout/index.tsx +++ b/ui/components/Layout/index.tsx @@ -1,141 +1,105 @@ -import { FC, Fragment, useEffect, useState } from 'react' -import { Dialog, Transition } from '@headlessui/react' -import { - Bars3Icon, - XMarkIcon -} from '@heroicons/react/24/outline' -import { readTextFile } from "@tauri-apps/api/fs"; -import { open } from "@tauri-apps/api/dialog"; -import { invoke } from "@tauri-apps/api/tauri"; -import { emit, listen } from '@tauri-apps/api/event' +import { FC, useEffect, useState } from 'react' -import Image from 'next/image' import { useIDL } from '@/context/IDL' +import { ArrowDownTrayIcon, FolderArrowDownIcon, FolderOpenIcon, PencilSquareIcon, PlusIcon } from '@heroicons/react/24/solid'; +import { generateProjectFiles, openIDLFile, saveIDLFile, selectTemplateFolder, cleanProject } from "@/helpers"; +import { useRouter } from 'next/router'; +import { TauriEvent, listen } from '@tauri-apps/api/event'; +import { useTemplates } from '@/context/templates'; +const Layout: FC = ({ children }) => { + const router = useRouter() + const {templateFolder} = useTemplates(); + const { IDL, setIDL } = useIDL() + const openIDL = openIDLFile(setIDL); + const [baseFolder, setBaseFolder] = useState(undefined); + const generateIDL = saveIDLFile(setBaseFolder, IDL.version, IDL.name, IDL.instructions, IDL.accounts, IDL.types, IDL.events, IDL.errors, IDL.metadata); + const newProject = cleanProject(setIDL); + const exportData = generateProjectFiles(IDL.name, setBaseFolder); + const handleTemplateFolder = selectTemplateFolder(); + useEffect(() => { + (async () => { + const unlisten = await listen(TauriEvent.MENU, (event) => { + switch (event?.payload + ) { + case "new_project": + newProject(); + break; + case "open_idl": + openIDL(); + break; + case "change_template": + handleTemplateFolder(); + break; + case "generate_project": + exportData(); + break; + case "generate_idl": + generateIDL(); + break; + } + }); + return () => { + unlisten(); + }; + })(); + }, []); -function classNames(...classes: any) { - return classes.filter(Boolean).join(' ') -} - -const Layout: FC = ({ children, openIDL, newProject, generateIDL, handleTemplateFolder, exportData }) => { - const [sidebarOpen, setSidebarOpen] = useState(false) - const navigation = [ - { - name: 'Open IDL file', - href: '#', - event: openIDL - }, - { - name: 'New IDL', - href: '#', - event: newProject - }, - { - name: 'Save IDL', - href: '#', - event: generateIDL - }, - { - name: 'Select a template', - href: '#', - event: handleTemplateFolder - }, - { - name: 'Create Project', - href: '#', - event: exportData - }, - ] return ( - <> -
- - - +
+
+ { + router.asPath === "/templates" && + -
- -
- -
-
- -
- - -
-
-
+
- +
+ {children} +
+ ) } diff --git a/ui/components/NewEditor/Editor/SelectTemplate/CardTemplate/index.tsx b/ui/components/NewEditor/Editor/SelectTemplate/CardTemplate/index.tsx deleted file mode 100644 index 4a98dbb..0000000 --- a/ui/components/NewEditor/Editor/SelectTemplate/CardTemplate/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import Image from "next/image" - -const CardTemplate = ({ template }: { template: any }) => { - - return ( -
-
-

- { - !template?.price ? - "Free " - : - `${template?.price?.toString()} ${template.currency} ` - } - Template -

-

v{template?.version}

-
-
- {template.name} -

{template.name}

-
-
-

{template.description}

-

Brought to you by

-
- {template.broughtBy.name} -
-
- -
- ) -} - -export default CardTemplate \ No newline at end of file diff --git a/ui/components/NewEditor/Editor/SelectTemplate/index.tsx b/ui/components/NewEditor/Editor/SelectTemplate/index.tsx deleted file mode 100644 index f2b0dad..0000000 --- a/ui/components/NewEditor/Editor/SelectTemplate/index.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import ArrowBack from "@/public/ArrowBack.png" -import SolanaIcon from "@/public/SolanaIcon.png" - -import Image from "next/image"; -import { useRouter } from "next/router"; -import { useTemplates } from "@/context/templates"; -import CardTemplate from "./CardTemplate"; - - -const SelectTemplate = () => { - const { templates } = useTemplates() - const router = useRouter() - - return ( -
-
-
-
- back all project router.push("/newProject")} /> - -
- Templates -
- back all project -
-
- { - templates.map((template: any) => { - return ( - - ) - }) - } -
-
-
-
- ) -} - -export default SelectTemplate diff --git a/ui/components/NewEditor/Editor/index.tsx b/ui/components/NewEditor/Editor/index.tsx deleted file mode 100644 index aa871c8..0000000 --- a/ui/components/NewEditor/Editor/index.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { FC, useState } from "react"; -import { Section } from "@/components/NewEditor/section"; -import { useIDL } from "@/context/IDL"; -import SelectTemplate from "./SelectTemplate"; - -export const NewEditor: FC = ({generateIDL}) => { - - const [select, setSelect] = useState("instructions") - const [popUpTemplates, setPopUpTemplates] = useState(false) - const { IDL, setIDL } = useIDL() - - return ( -
-
- setIDL({ - ...IDL, - name: e.target.value - }) - } - className="w-3/12 h-20 p-5 bg-inputs text-chok text-base rounded-xl hover:shadow-md hover:shadow-border hover:text-green" - /> -
- {/* */} - {/* */} - -
- { - popUpTemplates && - - } -
-
- -
- { - Object.keys(IDL).map((name, index) => { - if( name !== "name" && name !== "version" && name !== "metadata" ) - return ( -
-
setSelect(name)} - > -

- {name} -

-
-
- ) - }) - } -
-
-
-
- ) -}; diff --git a/ui/components/NewEditor/NewItem/index.tsx b/ui/components/NewEditor/NewItem/index.tsx deleted file mode 100644 index d7dbe71..0000000 --- a/ui/components/NewEditor/NewItem/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { FC } from "react"; -import { PlusIcon } from "@heroicons/react/24/solid" - -export const NewItem: FC = ({ name, onClick }) => ( -
- - -
-); diff --git a/ui/components/NewEditor/card/index.tsx b/ui/components/NewEditor/card/index.tsx deleted file mode 100644 index 3539f54..0000000 --- a/ui/components/NewEditor/card/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { FC, useEffect, useRef, useState } from "react"; -import { TrashIcon } from "@heroicons/react/24/solid" -import { useIDL } from "@/context/IDL"; - -export const Card: FC = ({ name, onClick, deleteItem, instruction, index }) => { - const { IDL, setIDL } = useIDL() - const [showOptions, setShowOptions] = useState(false) - const [newName, setNewName] = useState(name) - const timeoutName = useRef() - - useEffect(()=> { - clearTimeout(timeoutName.current) - - timeoutName.current = setTimeout(()=> { - - setIDL({ - ...IDL, - [instruction]: IDL[instruction].map((inst: any, i: number) => { - if (index === i) { - return { - ...inst, - name: newName - } - } - return inst - }) - }) - }, 1000) - },[newName]) - - return ( -
{ setShowOptions(true) }} - onMouseOut={() => { setShowOptions(false) }} - > - { - setNewName(e.target.value) - }} - className=" w-full bg-inputs focus:outline-none" - /> - { - showOptions && -
- -
- } -
- ) -}; \ No newline at end of file diff --git a/ui/components/NewEditor/section/EditInstruction/Tabs/tab.tsx b/ui/components/NewEditor/section/EditInstruction/Tabs/tab.tsx deleted file mode 100644 index e929c86..0000000 --- a/ui/components/NewEditor/section/EditInstruction/Tabs/tab.tsx +++ /dev/null @@ -1,212 +0,0 @@ -import { useIDL } from '@/context/IDL' -import { FC, useEffect, useLayoutEffect, useRef, useState } from 'react' -import { isProperty } from './verifyType' -import { TrashIcon } from '@heroicons/react/24/solid' - -function classNames(...classes: any) { - return classes.filter(Boolean).join(' ') -} - -const Tab: FC = ({ addProperty, objConfig, elements, editProperty, deleteItem }) => { - const [newProperty, setNewProperty] = useState({}) - const [ stateElements, setStateElements] = useState() - - useEffect(()=> { - setStateElements(elements) - },[elements]) - - useEffect(() => { - const defaultProperty = objConfig.reduce((acc: any, prop: any) => { - return { - ...acc, - [prop.name]: prop?.options === "boolean" ? false : prop?.options?.[0] || "" - } - }, {}) - setNewProperty(defaultProperty) - }, []) - - - - const handlerNewProperty = (e: any) => { - setNewProperty({ - ...newProperty, - [e.target.id]: e.target.type === "checkbox" ? e.target.checked : e.target.value - }) - } - - - - - return ( -
-
-
- - - - { - objConfig.map(({ name }: { name: string }) => { - return ( - - ) - }) - } - - - - - { - objConfig.map(({ disabled, name, options }: any) => { - if (options === "boolean") { - return ( - - ) - } else if (options?.length) { - return ( - - ) - - } else { - return ( - - ) - } - }) - } - - - { - stateElements?.map((property: any, index: number) => { - return - { - objConfig.map(({ disabled, name, options }: any) => { - if (options === "boolean") { - return ( - - ) - } else if (options?.length) { - return ( - - ) - } else { - console.log(property?.[name]) - return ( - - ) - } - }) - } - - - - }) - } - -
- {name} -
- - - - - - - -
- editProperty(e, index)} - /> - - - - { - editProperty(e, index) - }} - /> - - { - e.stopPropagation() - deleteItem(index) - }} - className="z-20 text-chokw-4 h-4 hover:text-red" - /> -
-
-
-
- ) -} - -export default Tab \ No newline at end of file diff --git a/ui/components/NewEditor/section/EditInstruction/Tabs/verifyType.ts b/ui/components/NewEditor/section/EditInstruction/Tabs/verifyType.ts deleted file mode 100644 index 6a5070b..0000000 --- a/ui/components/NewEditor/section/EditInstruction/Tabs/verifyType.ts +++ /dev/null @@ -1,67 +0,0 @@ -interface Args { - name: string, - type: string -} -interface Fields { - name: string, - type: string, - index?: boolean -} -interface Variants { - name: string, -} -interface Accounts { - name: string, - isMut: boolean, - isSigner: boolean -} -type PropertyTypes = Args | Fields | Variants | Accounts; - -const isArgs = (item: PropertyTypes): item is Args => { - return "name" in item && "type" in item; -}; - -const isFields = (item: PropertyTypes): item is Fields => { - return "name" in item && "type" in item && "index" in item; -}; - -const isVariants = (item: PropertyTypes): item is Variants => { - return "name" in item; -}; - -const isAccounts = (item: PropertyTypes): item is Accounts => { - return "name" in item && "isMut" in item && "isSigner" in item; -}; - -export const isProperty = (item: PropertyTypes, property: string) => { - switch (property) { - case "args": - if (isArgs(item)) { - // Realizar acciones para Args - return item; - } - break; - case "fields": - if (isFields(item)) { - // Realizar acciones para Fields - return item; - } - break; - case "variants": - if (isVariants(item)) { - // Realizar acciones para Variants - return item; - } - break; - case "accounts": - if (isAccounts(item)) { - // Realizar acciones para Accounts - return item; - } - break; - default: - break; - } - - return false; -}; \ No newline at end of file diff --git a/ui/components/NewEditor/section/index.tsx b/ui/components/NewEditor/section/index.tsx deleted file mode 100644 index 31f28a5..0000000 --- a/ui/components/NewEditor/section/index.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { FC, useState, useEffect } from "react"; -import { NewItem } from "../NewItem"; -import { ArrowRightIcon, CheckIcon } from "@heroicons/react/24/solid" -import { Card } from "../card"; -import EditInstructions from "./EditInstruction"; -import { useIDL } from "@/context/IDL"; - -export const Section: FC = ({ instruction }) => { - const { IDL, setIDL } = useIDL() - const [newInstructionName, setNewIntructionName] = useState(""); - const [editingItem, setEditingItem] = useState(0); - - return ( -
- -
- - { - instruction !== "errors" && -
- setNewIntructionName(e.target.value)} - className=" w-full bg-inputs focus:outline-none" - /> -
- { - if (!IDL[instruction].find((inst: any) => inst.name === newInstructionName)) { - setIDL({ - ...IDL, - [instruction]: [ - ...IDL[instruction], - { name: newInstructionName } - ] - }) - } - } - } - /> -
-
- } - { - instruction !== "errors" && -
- - - { - IDL[instruction]?.map(({ name }: { name: string; }, index: number) => { - return ( -
- { - const del = IDL[instruction].toSpliced(index, 1) - setIDL({ - ...IDL, - [instruction]: del - }) - }} - onClick={() => { - setEditingItem(index) - }} - /> - -
- ) - } - )} -
- } -
- -
- ); -}; diff --git a/ui/components/PopUp/index.tsx b/ui/components/PopUp/index.tsx new file mode 100644 index 0000000..2a7ce54 --- /dev/null +++ b/ui/components/PopUp/index.tsx @@ -0,0 +1,88 @@ +import ArrowBack from "@/public/ArrowBack.png" + +import Image, { StaticImageData } from "next/image"; +import { FC, PropsWithChildren, useEffect, useRef } from "react"; + +type props = { + title: string, + closePopUp: () => void, + icon?: StaticImageData, + iconClassName?: string, + alert?: { + text: string, + confirm: () => void, + cancel: () => void + } +} + +const PopUp: FC = ({ children, title, closePopUp, icon, iconClassName, alert }: PropsWithChildren) => { + const popUpRef = useRef() + + useEffect(() => { + const handleClickOutside = (event: any) => { + if (popUpRef.current && !popUpRef.current.contains(event.target)) { + console.log("close") + closePopUp() + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, [popUpRef]); + + return ( +
+
+
+ back all project + +
+ {title} +
+ { + icon && + SolanaFoundation + } +
+ { + !alert ? + children + : + + } +
+
+ ) +} + +export default PopUp + +type propsAlert = { + text: string, + confirm: () => void, + cancel: () => void +} + +const Alert = ({ text, confirm, cancel }: propsAlert) => { + + return ( +
+

{text}

+
+ + +
+
+ ) +} \ No newline at end of file diff --git a/ui/components/ClassicEditor/EditItem/EditProp/CardProp/index.tsx b/ui/components/ViewCards/EditItem/EditProp/CardProp/index.tsx similarity index 60% rename from ui/components/ClassicEditor/EditItem/EditProp/CardProp/index.tsx rename to ui/components/ViewCards/EditItem/EditProp/CardProp/index.tsx index 47dd0a5..63e2c8b 100644 --- a/ui/components/ClassicEditor/EditItem/EditProp/CardProp/index.tsx +++ b/ui/components/ViewCards/EditItem/EditProp/CardProp/index.tsx @@ -1,11 +1,16 @@ import { FC, useEffect, useRef, useState } from "react"; import { TrashIcon } from "@heroicons/react/24/solid" import { useIDL } from "@/context/IDL"; +import PopUp from "@/components/PopUp"; export const CardsProp: FC = ({ prop, property, nameInstruction, indexItem, indexProperty, objConfig, nameConfig }) => { const { IDL, setIDL } = useIDL() const timeOutediting = useRef() + const [confirmation, setConfirmation] = useState(false) + const cancelDelete = () => { + setConfirmation(false) + } const deleteItem = () => { if (nameInstruction === "errors") { @@ -18,7 +23,6 @@ export const CardsProp: FC = ({ prop, property, nameInstruction, indexItem, } }) } - return setIDL(del) } const del = { @@ -48,7 +52,7 @@ export const CardsProp: FC = ({ prop, property, nameInstruction, indexItem, return inst }) } - setIDL(del) + return setIDL(del) } const editProperty = (e: any) => { @@ -59,7 +63,7 @@ export const CardsProp: FC = ({ prop, property, nameInstruction, indexItem, const editing = { ...IDL, [nameInstruction]: IDL[nameInstruction].map((prop: any, i: number) => { - + if (indexProperty === i) { return { ...prop, @@ -70,7 +74,7 @@ export const CardsProp: FC = ({ prop, property, nameInstruction, indexItem, } }) } - + return setIDL(editing) } @@ -80,7 +84,6 @@ export const CardsProp: FC = ({ prop, property, nameInstruction, indexItem, if (index === indexItem) { if (!inst?.[nameConfig]?.find((prop: any) => prop[e.target.value])) { if (nameInstruction === "instructions") { - console.log(nameConfig, e.target.id, e.target.checked) return { ...inst, [nameConfig]: inst?.[nameConfig].map((prop: any, i: number) => { @@ -139,79 +142,89 @@ export const CardsProp: FC = ({ prop, property, nameInstruction, indexItem, } return ( + <> +
{ }} + > + { + e.stopPropagation() + setConfirmation(true) + }} + className="absolute z-20 text-border bottom-2 right-2 w-4 h-4 hover:text-red cursor-pointer" + /> +
+ { + objConfig.map(({ disabled, name, options }: any) => { + if (options === "boolean") { + return ( +
+ + editProperty(e)} + /> +
+ ) + } else if (options?.length) { + return ( + + ) + } else { + return ( -
{ }} - > - { - e.stopPropagation() - deleteItem() - }} - className="absolute z-20 text-border bottom-2 right-2 w-4 h-4 hover:text-red cursor-pointer" - /> -
- { - objConfig.map(({ disabled, name, options }: any) => { - if (options === "boolean") { - return ( -
- editProperty(e)} + disabled={disabled} + className={`bg-backg w-min text-left text-red rounded-md border-none font-bold ring-1 hover:bg-inputs`} + placeholder={name} + defaultValue={property?.[name]} + onChange={(e) => { + editProperty(e) + }} /> -
- ) - } else if (options?.length) { - return ( - - ) - } else { - return ( - - { - // setItem(property) - editProperty(e) - }} - /> - ) - } - }) - } + ) + } + }) + } +
-
+ { + confirmation && + + } + ) } \ No newline at end of file diff --git a/ui/components/ClassicEditor/EditItem/EditProp/NewProp/index.tsx b/ui/components/ViewCards/EditItem/EditProp/NewProp/index.tsx similarity index 84% rename from ui/components/ClassicEditor/EditItem/EditProp/NewProp/index.tsx rename to ui/components/ViewCards/EditItem/EditProp/NewProp/index.tsx index d601e60..4d7d323 100644 --- a/ui/components/ClassicEditor/EditItem/EditProp/NewProp/index.tsx +++ b/ui/components/ViewCards/EditItem/EditProp/NewProp/index.tsx @@ -1,4 +1,5 @@ import { useIDL } from "@/context/IDL"; +import { CheckIcon } from '@heroicons/react/24/solid' import { FC, useEffect, useState } from "react"; export const NewProp: FC = ({ nameConfig, addProperty, objConfig }) => { @@ -13,7 +14,7 @@ export const NewProp: FC = ({ nameConfig, addProperty, objConfig }) => { } }, {}) setNewProperty(defaultProperty) - }, []) + }, [IDL]) const handlerNewProperty = (e: any) => { setNewProperty({ @@ -23,7 +24,6 @@ export const NewProp: FC = ({ nameConfig, addProperty, objConfig }) => { } return ( -
@@ -34,6 +34,7 @@ export const NewProp: FC = ({ nameConfig, addProperty, objConfig }) => {
= ({ nameConfig, addProperty, objConfig }) => { className='mt-2 bg-inputs rounded-md' id={name} disabled={disabled} - defaultValue={options[0]} + value={newProperty[name]} onChange={handlerNewProperty} > { @@ -68,26 +69,25 @@ export const NewProp: FC = ({ nameConfig, addProperty, objConfig }) => { } else { return ( ) } }) } - + />
) } diff --git a/ui/components/ClassicEditor/EditItem/EditProp/index.tsx b/ui/components/ViewCards/EditItem/EditProp/index.tsx similarity index 100% rename from ui/components/ClassicEditor/EditItem/EditProp/index.tsx rename to ui/components/ViewCards/EditItem/EditProp/index.tsx diff --git a/ui/components/ClassicEditor/EditItem/index.tsx b/ui/components/ViewCards/EditItem/index.tsx similarity index 75% rename from ui/components/ClassicEditor/EditItem/index.tsx rename to ui/components/ViewCards/EditItem/index.tsx index 15ef5d1..7cd2925 100644 --- a/ui/components/ClassicEditor/EditItem/index.tsx +++ b/ui/components/ViewCards/EditItem/index.tsx @@ -1,14 +1,13 @@ import { FC, useState, useEffect } from "react" import { type_args } from "@/const" import { useIDL } from "@/context/IDL" -import Tab from "@/components/NewEditor/section/EditInstruction/Tabs/tab" import { EditProp } from "./EditProp" import { ArrowLeftIcon } from "@heroicons/react/24/solid" const EditItem: FC = ({ indexItem, instruction, setEdit }) => { + const { IDL, setIDL } = useIDL() const [tabConfig, setTab] = useState("accounts") const [kind, setKind] = useState("") - const { IDL, setIDL } = useIDL() useEffect(() => { @@ -20,58 +19,61 @@ const EditItem: FC = ({ indexItem, instruction, setEdit }) => { }, [indexItem]) const addProperty = (newProperty: any) => { - if (instruction === "errors") { - const errProperty = { - ...newProperty, - code: 6000 + (IDL[instruction].length) + if (newProperty.name) { + + if (instruction === "errors") { + const errProperty = { + ...newProperty, + code: 6000 + (IDL[instruction].length) + } + return setIDL({ + ...IDL, + [instruction]: [ + ...IDL[instruction], + errProperty + ] + }) } - return setIDL({ + setIDL({ ...IDL, - [instruction]: [ - ...IDL[instruction], - errProperty - ] - }) - } - setIDL({ - ...IDL, - [instruction]: IDL[instruction].map((inst: any, index: number) => { - if (index === indexItem) { - if (instruction === "instructions" && !inst?.[tabConfig]?.includes(newProperty)) { - return { - ...inst, - [tabConfig]: [ - ...inst?.[tabConfig] || [], - newProperty - ] - } - } - if (instruction === "events" && !inst?.[tabConfig]?.includes(newProperty)) { - return { - ...inst, - fields: [ - ...inst?.fields || [], - newProperty - ] + [instruction]: IDL[instruction].map((inst: any, index: number) => { + if (index === indexItem) { + if (instruction === "instructions" && !inst?.[tabConfig]?.find((obj: any) => obj.name === newProperty.name)) { + return { + ...inst, + [tabConfig]: [ + ...inst?.[tabConfig] || [], + newProperty + ] + } } - } - if (!inst?.types?.[tabConfig]?.includes(newProperty)) { - return { - ...inst, - type: { - kind: kind, - [kind === "struct" ? "fields" : "variants"]: [ - ...inst?.type?.[kind === "struct" ? "fields" : "variants"] || [], + if (instruction === "events" && !inst?.[tabConfig]?.find((obj: any) => obj.name === newProperty.name)) { + return { + ...inst, + fields: [ + ...inst?.fields || [], newProperty ] + } + } + if (!inst?.types?.[tabConfig]?.find((obj: any) => obj.name === newProperty.name)) { + return { + ...inst, + type: { + kind: kind, + [kind === "struct" ? "fields" : "variants"]: [ + ...inst?.type?.[kind === "struct" ? "fields" : "variants"] || [], + newProperty + ] + } } } } - } - return inst + return inst + }) }) - }) + } } const render = { @@ -87,7 +89,7 @@ const EditItem: FC = ({ indexItem, instruction, setEdit }) => { key={name} >
setTab(name)} > @@ -154,13 +156,13 @@ const EditItem: FC = ({ indexItem, instruction, setEdit }) => { { instruction !== "errors" &&
setEdit(false)} /> -

+

{`${IDL?.[instruction]?.[indexItem]?.name?.charAt(0).toUpperCase() + IDL?.[instruction]?.[indexItem]?.name?.slice(1)}`}

diff --git a/ui/components/ClassicEditor/Editor/index.tsx b/ui/components/ViewCards/Editor/index.tsx similarity index 98% rename from ui/components/ClassicEditor/Editor/index.tsx rename to ui/components/ViewCards/Editor/index.tsx index dcb20c7..d9a88aa 100644 --- a/ui/components/ClassicEditor/Editor/index.tsx +++ b/ui/components/ViewCards/Editor/index.tsx @@ -5,11 +5,8 @@ import { Section } from "../section" const ClassicEditor: FC = ({ exportData }) => { - const { IDL, setIDL } = useIDL() - - const instructions = [ { name: "instructions", @@ -20,7 +17,6 @@ const ClassicEditor: FC = ({ exportData }) => { name: "accounts", item: IDL.accounts, initExpanded: false, - }, { name: "types", @@ -48,7 +44,7 @@ const ClassicEditor: FC = ({ exportData }) => { placeholder="Add project's name" value={IDL.name} onChange={(e) => setIDL({ ...IDL, name: e.target.value })} - className="p-5 mb-5 m-5 w-3/12 h-20 bg-inputs text-chok text-base rounded-xl hover:shadow-md hover:shadow-border hover:text-green" + className="p-5 mb-5 m-5 w-3/12 h-20 bg-inputs text-chok text-base rounded-xl hover:shadow-md hover:shadow-border hover:text-green-custom" />
{ diff --git a/ui/components/ClassicEditor/NewItem/index.tsx b/ui/components/ViewCards/NewItem/index.tsx similarity index 63% rename from ui/components/ClassicEditor/NewItem/index.tsx rename to ui/components/ViewCards/NewItem/index.tsx index 6d0404b..a0bc9ec 100644 --- a/ui/components/ClassicEditor/NewItem/index.tsx +++ b/ui/components/ViewCards/NewItem/index.tsx @@ -1,4 +1,5 @@ import { useIDL } from "@/context/IDL"; +import { CheckIcon } from '@heroicons/react/24/solid' import { FC, useEffect, useState } from "react"; export const NewItem: FC = ({ prop, setIsModalOpen, isModalOpen }) => { @@ -11,7 +12,7 @@ export const NewItem: FC = ({ prop, setIsModalOpen, isModalOpen }) => { }, [isModalOpen]) const save = () => { - if (!IDL[prop].find((inst: any) => inst.name === newInstructionName)) { + if (!IDL[prop].find((inst: any) => inst.name === newInstructionName) && newInstructionName ) { setIDL({ ...IDL, @@ -21,28 +22,28 @@ export const NewItem: FC = ({ prop, setIsModalOpen, isModalOpen }) => { ] }) } + setNewIntructionName("") } return (
setNewIntructionName(e.target.value)} - className="w-full text-center h-16 bg-inputs text-red rounded-md ring-1 ring-border" + className="w-full text-center h-16 p-4 bg-inputs text-red-custom rounded-md ring-1 ring-border" /> - + />
) } diff --git a/ui/components/ViewCards/card/index.tsx b/ui/components/ViewCards/card/index.tsx new file mode 100644 index 0000000..6d882e4 --- /dev/null +++ b/ui/components/ViewCards/card/index.tsx @@ -0,0 +1,52 @@ +import { FC, useState } from "react"; +import { TrashIcon } from "@heroicons/react/24/solid" +import { useIDL } from "@/context/IDL"; +import PopUp from "@/components/PopUp"; + +export const Card: FC = ({ prop, item, onClick, index, setEdit, explanationText }) => { + const { IDL, setIDL } = useIDL() + const [confirmation, setConfirmation] = useState(false) + + const deleteItem = () => { + const del = IDL[prop].toSpliced(index, 1) + return setIDL({ + ...IDL, + [prop]: del + }) + } + + const cancelDelete = () => { + setConfirmation(false) + } + + return ( + <> +
{ setEdit({ item, index }) }} + > + { + e.stopPropagation() + setConfirmation(true) + }} className="absolute z-20 text-border bottom-2 right-2 w-4 h-4 hover:text-yellow-custom" /> +
+

{item.name}

+

+ {explanationText} +

+
+
+ { + confirmation && + + } + + ) +} \ No newline at end of file diff --git a/ui/components/ClassicEditor/section/index.tsx b/ui/components/ViewCards/section/index.tsx similarity index 82% rename from ui/components/ClassicEditor/section/index.tsx rename to ui/components/ViewCards/section/index.tsx index 0d73e77..143034a 100644 --- a/ui/components/ClassicEditor/section/index.tsx +++ b/ui/components/ViewCards/section/index.tsx @@ -2,9 +2,10 @@ import { FC, useState, useEffect } from "react"; import { NewItem } from "../NewItem"; import { Card } from "../card"; import EditItem from "../EditItem"; -import { EditProp } from "../EditItem/EditProp"; +import { useIDL } from "@/context/IDL"; -export const Section: FC = ({ instruction, content, initExpanded = false, deleteItem }) => { +export const Section: FC = ({ instruction, content, initExpanded = false }) => { + const { clear } = useIDL() const [expanded, setExpanded] = useState(initExpanded); const [edit, setEdit] = useState() const [isModalOpen, setIsModalOpen] = useState(false); @@ -19,6 +20,10 @@ export const Section: FC = ({ instruction, content, initExpanded = false, d }, 500) }, [expanded]) + useEffect(() => { + setEdit(false) + },[clear]) + return (
= ({ instruction, content, initExpanded = false, d > {`${instruction.charAt(0).toUpperCase() + instruction.slice(1)}`}
-
+
{ instruction !== "errors" && !edit ? <> @@ -38,6 +43,7 @@ export const Section: FC = ({ instruction, content, initExpanded = false, d { content.map((item: any, index: number) => ( = ({ instruction, content, initExpanded = false, d
+ + + ); +}; diff --git a/ui/context/templates/index.tsx b/ui/context/templates/index.tsx index de7ce17..12705f5 100644 --- a/ui/context/templates/index.tsx +++ b/ui/context/templates/index.tsx @@ -8,21 +8,10 @@ const TemplateContext = createContext({ }); const TemplatesProvider = ({ children }: { children: ReactNode }) => { - const [templates, setTemplates] = useState([ - { - name: "Anchor", - icon: AnchorImg, - version: "1.0.0", - description: "Lorem, ipsum dolor sit amet consectetur adipisicing elit. Cum, molestiass .", - broughtBy: { - icon: SolanaFundationIcon, - name: "Solana Fundation" - } - } - ]); + const [templates, setTemplates] = useState([]); return ( - + {children} ); diff --git a/ui/helpers/cleanProject.ts b/ui/helpers/cleanProject.ts index 2b6b92b..b52181a 100644 --- a/ui/helpers/cleanProject.ts +++ b/ui/helpers/cleanProject.ts @@ -8,9 +8,7 @@ const cleanProject = (setIDL: Function) => { setIDL({ name: "", version: "0.1.0", - instructions: [{ - name: "initialize" - }], + instructions: [], accounts: [], types: [], events: [], diff --git a/ui/helpers/generateProjectFiles.ts b/ui/helpers/generateProjectFiles.ts index 5dbd1b3..76709ac 100644 --- a/ui/helpers/generateProjectFiles.ts +++ b/ui/helpers/generateProjectFiles.ts @@ -5,8 +5,6 @@ import handleBaseFolder from "./handleBaseFolder"; const generateProjectFiles = ( name: string, - templateFolder: any, - setTemplateFolder: Function, setBaseFolder: Function, ) => { return async () => { diff --git a/ui/helpers/openIDLFile.ts b/ui/helpers/openIDLFile.ts index 70b4ed2..5e7d492 100644 --- a/ui/helpers/openIDLFile.ts +++ b/ui/helpers/openIDLFile.ts @@ -2,7 +2,7 @@ import { open } from "@tauri-apps/api/dialog"; import { message } from "@tauri-apps/api/dialog"; import { readTextFile } from "@tauri-apps/api/fs"; -const openIDLFile = (IDL: any, setIDL: Function) => { +const openIDLFile = (setIDL: Function) => { return async () => { try { const result = await open({ diff --git a/ui/helpers/selectTemplateFolder.ts b/ui/helpers/selectTemplateFolder.ts index b972bc8..3fc9dcd 100644 --- a/ui/helpers/selectTemplateFolder.ts +++ b/ui/helpers/selectTemplateFolder.ts @@ -2,23 +2,24 @@ import { open } from "@tauri-apps/api/dialog"; import { message } from "@tauri-apps/api/dialog"; import { invoke } from "@tauri-apps/api/tauri"; -const selectTemplateFolder = (setTemplateFolder: Function) => { +const selectTemplateFolder = ( + // setTemplateFolder: Function +) => { return async () => { try { const result = await open({ multiple: false, title: "Select a template file", }); - if (typeof result === "string") { invoke("update_template", { templatePath: result }) .then(async () => { - setTemplateFolder(result) + // setTemplateFolder(result) await message(`Template path: ${result}`, "Template Selected"); }) .catch(async (e) => { await message(e?.error ?? "update_template Error", { title: "Error Trying to open selected file as a template", type: "error" }); }); - } + ; } catch (e) { await message(`${e}`, { diff --git a/ui/pages/_app.tsx b/ui/pages/_app.tsx index 7507136..993ae78 100644 --- a/ui/pages/_app.tsx +++ b/ui/pages/_app.tsx @@ -1,3 +1,4 @@ +import Layout from '@/components/Layout' import { IDLProvider } from '@/context/IDL' import { TemplatesProvider } from '@/context/templates' import '@/styles/globals.css' @@ -7,7 +8,9 @@ export default function App({ Component, pageProps }: AppProps) { return ( - + + + ) diff --git a/ui/pages/index.tsx b/ui/pages/index.tsx index bc402d6..1341610 100644 --- a/ui/pages/index.tsx +++ b/ui/pages/index.tsx @@ -1,96 +1,23 @@ -import Head from "next/head"; -import { useEffect, useState, Fragment, useRef } from "react"; -import { TauriEvent, listen } from "@tauri-apps/api/event"; -import { about, cleanProject, generateProjectFiles, nameSetter, openIDLFile, saveIDLFile, saveTemplateFile, selectTemplateFolder, templateFromFolder } from "@/helpers"; -import Layout from "@/components/Layout"; -import { useIDL } from "@/context/IDL"; -import { NewEditor } from "@/components/NewEditor/Editor"; -import ClassicEditor from "@/components/ClassicEditor/Editor"; -import { Dialog, Transition } from '@headlessui/react' -import { - PlusIcon, - FolderOpenIcon, - XMarkIcon, - ArrowDownTrayIcon, - FolderArrowDownIcon -} from '@heroicons/react/24/outline' +import { useEffect, useState } from "react"; +import { NewEditor } from "@/components/ViewTables/Editor"; +import ClassicEditor from "@/components/ViewCards/Editor"; import JSONEditor from "@/components/JSONEditor"; import { CodeBracketIcon } from "@heroicons/react/24/solid"; +import { selectTemplateFolder } from "@/helpers"; +import { TauriEvent, listen } from "@tauri-apps/api/event"; +import { useTemplates } from "@/context/templates"; export default function Home() { - - const { IDL, setIDL } = useIDL() - const [templateFolder, setTemplateFolder] = useState(undefined); const [selectedUI, setSelectedUI] = useState("cards") - const [baseFolder, setBaseFolder] = useState(undefined); - const exportData = generateProjectFiles(IDL.name, templateFolder, setTemplateFolder, setBaseFolder); - const handleTemplateFolder = selectTemplateFolder(setTemplateFolder); - const openIDL = openIDLFile(IDL, setIDL); - const newProject = cleanProject(setIDL); - const generateIDL = saveIDLFile(setBaseFolder, IDL.version, IDL.name, IDL.instructions, IDL.accounts, IDL.types, IDL.events, IDL.errors, IDL.metadata); - const [sidebarOpen, setSidebarOpen] = useState(false) const [widthJson, setWidthJson] = useState(false) const [hiddenJson, setHiddenJson] = useState(true) - - const navigation = [ - { - name: 'Open IDL file', - href: '#', - event: openIDL - }, - { - name: 'New IDL', - href: '#', - event: newProject - }, - { - name: 'Save IDL', - href: '#', - event: generateIDL - }, - { - name: 'Select a template', - href: '#', - event: handleTemplateFolder - }, - { - name: 'Create Project', - href: '#', - event: exportData - }, - ] + const {setTemplateFolder} = useTemplates(); + const handleTemplateFolder = selectTemplateFolder(); useEffect(() => { (async () => { const unlisten = await listen(TauriEvent.MENU, (event) => { - switch (event?.payload - ) { - case "new_project": - newProject(); - break; - case "open_idl": - openIDL(); - break; - case "change_template": - handleTemplateFolder(); - break; - case "generate_project": - exportData(); - break; - case "generate_idl": - generateIDL(); - break; - case "about": - about(); - break; - case "template_from_folder": - templateFromFolder(); - break; - case "save_template_file": - saveTemplateFile() - default: - break; - } + handleTemplateFolder(); }); return () => { unlisten(); @@ -100,14 +27,14 @@ export default function Home() { const render = () => { const view = { - cards: , - tables: + cards: , + tables: } if (selectedUI !== "json") { return (
-
+
{ if (widthJson) { @@ -120,10 +47,9 @@ export default function Home() { setTimeout(() => { setWidthJson(true) }, 0) - } }} - className="sticky ml-auto mr-2 top-2 w-6 h-6 text-white z-50 cursor-pointer hover:text-greenn " + className="absolute top-2 right-2 w-6 h-6 text-white z-20 cursor-pointer hover:text-green-customn " /> {view[selectedUI as keyof typeof render]}
@@ -135,120 +61,21 @@ export default function Home() { } else { return } - } return ( - <> - - Soda - - - - -
- - - -
- - -
- - - -
- -
-
-
- -
-
- -
-
-
-
-
-
-
-
- - - - -
-
-

Views:

- - - - -
+
+
+
+

select view:

+ + +
-
- {render()} -
- - +
+ {render()} +
+
); } diff --git a/ui/tailwind.config.js b/ui/tailwind.config.js index 47b508e..403b644 100644 --- a/ui/tailwind.config.js +++ b/ui/tailwind.config.js @@ -1,10 +1,12 @@ /** @type {import('tailwindcss').Config} */ +const colors = require('tailwindcss/colors') + module.exports = { content: [ "./app/**/*.{js,ts,jsx,tsx}", "./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", - + "./context/**/*.{js,ts,jsx,tsx}", "./src/**/*.{js,ts,jsx,tsx}", ], theme: { @@ -12,20 +14,19 @@ module.exports = { boxShadow: { 'tab': '0px 1px 0px -0.5px', 'tabSelected': "0px 0px 4px -2px " - } - }, - colors: { - 'backg': '#081635', - 'inputs': '#102042', - 'blue': '#000031', - 'sky': '#B1FCFE', - 'red': '#ED7043', - 'chok': '#B1FCFE', - 'green': '#7DFBA2', - 'yellow': '#FFFFA6', - 'white': '#FFFFFF', - 'border': '#334155', - 'export': '#387847', + }, + colors: { + 'backg': '#081635', + 'inputs': '#102042', + 'blue-custom': '#000031', + 'sky': '#B1FCFE', + 'red-custom': '#ED7043', + 'chok': '#B1FCFE', + 'green-custom': '#7DFBA2', + 'yellow-custom': '#FFFFA6', + 'border': '#334155', + 'export': '#387847', + }, }, }, plugins: [