From 3aaa6446ee1d7c71b1da909c0504eb4eef9fdc3c Mon Sep 17 00:00:00 2001 From: yann300 Date: Sun, 18 Feb 2024 22:10:07 +0100 Subject: [PATCH 01/26] improve gist --- libs/remix-ui/workspace/src/lib/actions/index.ts | 11 ++++++----- libs/remix-ui/workspace/src/lib/actions/workspace.ts | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.ts index 67787e1d2c..998a39779c 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.ts @@ -72,9 +72,10 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React. dispatch(setWorkspaces(workspaces)) } if (params.gist) { - await createWorkspaceTemplate('code-sample', 'gist-template') - plugin.setWorkspace({ name: 'code-sample', isLocalhost: false }) - dispatch(setCurrentWorkspace({ name: 'code-sample', isGitRepo: false })) + const name = 'gist ' + params.gist + await createWorkspaceTemplate(name, 'gist-template') + plugin.setWorkspace({ name, isLocalhost: false }) + dispatch(setCurrentWorkspace({ name, isGitRepo: false })) await loadWorkspacePreset('gist-template') } else if (params.code || params.url || params.shareCode) { await createWorkspaceTemplate('code-sample', 'code-template') @@ -229,8 +230,8 @@ export const publishToGist = async (path?: string, type?: string) => { const folder = path || '/' try { - const name = extractNameFromKey(path) - const id = name && name.startsWith('gist-') ? name.split('-')[1] : null + const name = await plugin.call('filePanel', 'getCurrentWorkspace') + const id = name && name.startsWith('gist ') ? name.split(' ')[1] : null const packaged = await packageGistFiles(folder) // check for token diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 31ec69ab99..0bbdf6b368 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -345,9 +345,9 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe } if (data.files[element].type === 'application/json') { - obj['/' + 'gist-' + gistId + '/' + path] = { content: JSON.stringify(value.content, null, '\t') } + obj['/' + path] = { content: JSON.stringify(value.content, null, '\t') } } else - obj['/' + 'gist-' + gistId + '/' + path] = value + obj['/' + path] = value } plugin.fileManager.setBatchFiles(obj, 'workspace', true, (errorLoadingFile) => { if (errorLoadingFile) { From 9f15938a0a6e9484ce97457f6815305f8d6dc9a2 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 19 Feb 2024 14:12:02 +0100 Subject: [PATCH 02/26] fix saving and loading gist workspace/folder --- apps/remix-ide/src/app/panels/file-panel.js | 15 +++++++++++ .../src/app/tabs/locales/en/filePanel.json | 4 +-- .../remix-core-plugin/src/lib/gist-handler.ts | 2 +- .../workspace/src/lib/actions/index.ts | 18 ++++++------- .../workspace/src/lib/actions/workspace.ts | 12 ++++++--- .../src/lib/components/file-explorer-menu.tsx | 26 ++++++------------- .../src/lib/providers/FileSystemProvider.tsx | 4 +-- .../workspace/src/lib/reducers/workspace.ts | 8 +++--- .../workspace/src/lib/remix-ui-workspace.tsx | 7 +++-- .../remix-ui/workspace/src/lib/utils/index.ts | 11 +------- 10 files changed, 52 insertions(+), 55 deletions(-) diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 2e4feaf0e2..d8f55573f5 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -46,6 +46,7 @@ const profile = { 'loadTemplate', 'clone', 'isExpanded', + 'isGist' ], events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'], icon: 'assets/img/fileManager.webp', @@ -131,6 +132,20 @@ module.exports = class Filepanel extends ViewPlugin { }) } + /** + * return the gist id if the current workspace is a gist workspace, otherwise returns null + * @argument {String} workspaceName - the name of the workspace to check against. default to the current workspace. + * @returns {string} gist id or null + */ + isGist (workspaceName) { + workspaceName = workspaceName || this.currentWorkspaceMetadata && this.currentWorkspaceMetadata.name + const isGist = workspaceName.startsWith('gist') + if (isGist) { + return workspaceName.split(' ')[1] + } + return null + } + getCurrentWorkspace() { return this.currentWorkspaceMetadata } diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index 3847cae628..0e493a8e0c 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -62,10 +62,10 @@ "filePanel.compileForNahmii": "Compile for Nahmii", "filePanel.createNewFile": "Create new file", "filePanel.createNewFolder": "Create new folder", - "filePanel.publishToGist": "Publish all files to GitHub gist", + "filePanel.publishToGist": "Publish workspace to GitHub gist", "filePanel.uploadFile": "Upload files", "filePanel.uploadFolder": "Upload folder", - "filePanel.updateGist": "Update the current [gist] explorer", + "filePanel.updateGist": "Publish workspace to GitHub gist", "filePanel.viewAllBranches": "View all branches", "filePanel.createBranch": "Create branch", "filePanel.switchBranches": "Switch branches", diff --git a/libs/remix-core-plugin/src/lib/gist-handler.ts b/libs/remix-core-plugin/src/lib/gist-handler.ts index 5a1e04d98e..e204b21a1b 100644 --- a/libs/remix-core-plugin/src/lib/gist-handler.ts +++ b/libs/remix-core-plugin/src/lib/gist-handler.ts @@ -117,7 +117,7 @@ export class GistHandler extends Plugin { const obj: StringByString = {} Object.keys(data.files).forEach((element) => { const path = element.replace(/\.\.\./g, '/') - obj['/gist-' + gistId + '/' + path] = data.files[element] + obj['/' + path] = data.files[element] }) this.call('fileManager', 'setBatchFiles', obj, isElectron()? 'electron':'workspace', true, async (errorSavingFiles: any) => { if (errorSavingFiles) { diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.ts index 998a39779c..15344a2a4b 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.ts @@ -225,14 +225,19 @@ export type SolidityConfiguration = { runs: string } -export const publishToGist = async (path?: string, type?: string) => { +export const publishToGist = async (path?: string) => { // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. const folder = path || '/' try { - const name = await plugin.call('filePanel', 'getCurrentWorkspace') - const id = name && name.startsWith('gist ') ? name.split(' ')[1] : null - + let id + if (path) { + // check if the current folder is a gist folder + id = await plugin.call('filePanel', 'isGist', extractNameFromKey(path)) + } else { + // check if the current workspace is a gist workspace + id = await plugin.call('filePanel', 'isGist') + } const packaged = await packageGistFiles(folder) // check for token const config = plugin.registry.get('config').api @@ -521,11 +526,6 @@ const packageGistFiles = async (directory) => { if (/^\s+$/.test(content) || !content.length) { content = '// this line is added to create a gist. Empty file is not allowed.' } - if (path.indexOf('gist-') === 0) { - path = path.split('/') - path.shift() - path = path.join('/') - } path = path.replace(/\//g, '...') ret[path] = { content } }) diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 0bbdf6b368..7649e1400d 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -609,6 +609,7 @@ export const getWorkspaces = async (): Promise<{ name: string; isGitRepo: boolea Object.keys(items) .filter((item) => items[item].isDirectory) .map(async (folder) => { + const name = folder.replace(workspacesPath + '/', '') const isGitRepo: boolean = await plugin.fileProviders.browser.exists('/' + folder + '/.git') const hasGitSubmodules: boolean = await plugin.fileProviders.browser.exists('/' + folder + '/.gitmodules') if (isGitRepo) { @@ -618,17 +619,20 @@ export const getWorkspaces = async (): Promise<{ name: string; isGitRepo: boolea branches = await getGitRepoBranches(folder) currentBranch = await getGitRepoCurrentBranch(folder) return { - name: folder.replace(workspacesPath + '/', ''), + name, isGitRepo, branches, currentBranch, - hasGitSubmodules + hasGitSubmodules, + isGist: null } } else { + const gistId = await plugin.call('filePanel', 'isGist', name) return { - name: folder.replace(workspacesPath + '/', ''), + name, isGitRepo, - hasGitSubmodules + hasGitSubmodules, + isGist: gistId } } }) diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx index 243f68e1a9..bba7bbc39a 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx @@ -33,6 +33,13 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { placement: 'top', platforms:[appPlatformTypes.web] }, + { + action: 'updateGist', + title: 'Update the cdddurrent gist', + icon: 'fab fa-github', + placement: 'bottom-start', + platforms:[appPlatformTypes.web] + }, { action: 'uploadFile', title: 'Upload files into current workspace', @@ -46,13 +53,6 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { icon: 'far fa-folder-upload', placement: 'top', platforms:[appPlatformTypes.web] - }, - { - action: 'updateGist', - title: 'Update the current [gist] explorer', - icon: 'fab fa-github', - placement: 'bottom-start', - platforms:[appPlatformTypes.web] } ].filter( (item) => @@ -65,16 +65,6 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { }) const enableDirUpload = {directory: '', webkitdirectory: ''} - useEffect(() => { - const actions = { - updateGist: () => {} - } - - setState((prevState) => { - return {...prevState, actions} - }) - }, []) - return ( (!global.fs.browser.isSuccessfulWorkspace ? null : <> @@ -165,7 +155,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { props.createNewFile() } else if (action === 'createNewFolder') { props.createNewFolder() - } else if (action === 'publishToGist') { + } else if (action === 'publishToGist' || action == 'updateGist') { props.publishToGist() } else { state.actions[action]() diff --git a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx index c57585ce8a..8d7c1ac5bd 100644 --- a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx +++ b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx @@ -117,8 +117,8 @@ export const FileSystemProvider = (props: WorkspaceProps) => { await deleteAllWorkspaces() } - const dispatchPublishToGist = async (path?: string, type?: string) => { - await publishToGist(path, type) + const dispatchPublishToGist = async (path?: string) => { + await publishToGist(path) } const dispatchUploadFile = async (target?: SyntheticEvent, targetFolder?: string) => { diff --git a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts index 2d6b15a26c..d2f923ceb8 100644 --- a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts @@ -17,6 +17,7 @@ export interface BrowserState { name: string }[] currentBranch?: string + isGist: string }[] files: {[x: string]: Record} flatTree: FileType[] @@ -150,7 +151,6 @@ export const browserReducer = (state = browserInitialState, action: Actions) => case 'SET_WORKSPACES': { const payload = action.payload - return { ...state, browser: { @@ -986,8 +986,7 @@ const removeInputField = ( isDirectory: true, path, name: extractNameFromKey(path), - type: - extractNameFromKey(path).indexOf('gist-') === 0 ? 'gist' : 'folder', + type: 'folder', child: prevFiles ? prevFiles.child : {} }, Object @@ -1117,8 +1116,7 @@ const normalize = ( path, name: extractNameFromKey(path), isDirectory: filesList[key].isDirectory, - type: - extractNameFromKey(path).indexOf('gist-') === 0 ? 'gist' : 'folder' + type: 'folder' } } else { files[extractNameFromKey(key)] = { diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index e71d94ffd9..fc059dc90d 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -32,6 +32,7 @@ export function Workspace() { hasGitSubmodules?: boolean branches?: {remote: any; name: string}[] currentBranch?: string + isGist: string }>(null) const [showDropdown, setShowDropdown] = useState(false) const [showIconsMenu, hideIconsMenu] = useState(false) @@ -73,7 +74,7 @@ export function Workspace() { }, mouseOverElement: null, showContextMenu: false, - reservedKeywords: [ROOT_PATH, 'gist-'], + reservedKeywords: [ROOT_PATH], copyElement: [], dragStatus: false }) @@ -922,7 +923,6 @@ export function Workspace() { ) } - return (
)} {!(global.fs.browser.isRequestingWorkspace || global.fs.browser.isRequestingCloning) && global.fs.mode === 'browser' && currentWorkspace !== NO_WORKSPACE && ( - Date: Mon, 19 Feb 2024 14:36:58 +0100 Subject: [PATCH 03/26] remove uneeded gist type and add copy gist ID to clipboard --- .../drag-n-drop/src/lib/types/index.ts | 2 +- .../file-decorators/src/lib/types/index.ts | 2 +- .../workspace/src/lib/actions/index.ts | 4 ++-- .../src/lib/components/file-explorer.tsx | 2 +- .../workspace/src/lib/contexts/index.ts | 4 ++-- .../src/lib/providers/FileSystemProvider.tsx | 4 ++-- .../workspace/src/lib/remix-ui-workspace.tsx | 10 ++++++++-- libs/remix-ui/workspace/src/lib/types/index.ts | 4 ++-- libs/remix-ui/workspace/src/lib/utils/index.ts | 18 +++++------------- 9 files changed, 24 insertions(+), 26 deletions(-) diff --git a/libs/remix-ui/drag-n-drop/src/lib/types/index.ts b/libs/remix-ui/drag-n-drop/src/lib/types/index.ts index 8bd4b0066a..c81cad0b5b 100644 --- a/libs/remix-ui/drag-n-drop/src/lib/types/index.ts +++ b/libs/remix-ui/drag-n-drop/src/lib/types/index.ts @@ -4,7 +4,7 @@ export interface FileType { path: string, name: string, isDirectory: boolean, - type: 'folder' | 'file' | 'gist', + type: 'folder' | 'file', child?: File[] } diff --git a/libs/remix-ui/file-decorators/src/lib/types/index.ts b/libs/remix-ui/file-decorators/src/lib/types/index.ts index bb84b6d26c..e78a1a4136 100644 --- a/libs/remix-ui/file-decorators/src/lib/types/index.ts +++ b/libs/remix-ui/file-decorators/src/lib/types/index.ts @@ -24,6 +24,6 @@ export interface FileType { path: string, name?: string, isDirectory?: boolean, - type?: 'folder' | 'file' | 'gist', + type?: 'folder' | 'file', child?: File[] } \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.ts index 15344a2a4b..540abc8397 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.ts @@ -320,7 +320,7 @@ export const createNewFile = async (path: string, rootDir: string) => { } } -export const setFocusElement = async (elements: { key: string, type: 'file' | 'folder' | 'gist' }[]) => { +export const setFocusElement = async (elements: { key: string, type: 'file' | 'folder' }[]) => { dispatch(focusElement(elements)) } @@ -435,7 +435,7 @@ export const emitContextMenuEvent = async (cmd: customAction) => { await plugin.call(cmd.id, cmd.name, cmd) } -export const handleClickFile = async (path: string, type: 'file' | 'folder' | 'gist') => { +export const handleClickFile = async (path: string, type: 'file' | 'folder' ) => { if (type === 'file' && path.endsWith('.md')) { // just opening the preview await plugin.call('doc-viewer' as any, 'viewDocs', [path]) diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx index 6e2010f80b..b323e2a750 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx @@ -173,7 +173,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const handleClickFolder = async (path: string, type: 'folder' | 'file' | 'gist') => { + const handleClickFolder = async (path: string, type: 'folder' | 'file' ) => { if (state.ctrlKey) { if (props.focusElement.findIndex((item) => item.key === path) !== -1) { const focusElement = props.focusElement.filter((item) => item.key !== path) diff --git a/libs/remix-ui/workspace/src/lib/contexts/index.ts b/libs/remix-ui/workspace/src/lib/contexts/index.ts index c3ac0849a4..42e7f8bbf9 100644 --- a/libs/remix-ui/workspace/src/lib/contexts/index.ts +++ b/libs/remix-ui/workspace/src/lib/contexts/index.ts @@ -21,7 +21,7 @@ export const FileSystemContext = createContext<{ dispatchUploadFile: (target?: SyntheticEvent, targetFolder?: string) => Promise, dispatchUploadFolder: (target?: SyntheticEvent, targetFolder?: string) => Promise, dispatchCreateNewFile: (path: string, rootDir: string) => Promise, - dispatchSetFocusElement: (elements: { key: string, type: 'file' | 'folder' | 'gist' }[]) => Promise, + dispatchSetFocusElement: (elements: { key: string, type: 'file' | 'folder' }[]) => Promise, dispatchCreateNewFolder: (path: string, rootDir: string) => Promise, dispatchDeletePath: (path: string[]) => Promise, dispatchRenamePath: (oldPath: string, newPath: string) => Promise, @@ -31,7 +31,7 @@ export const FileSystemContext = createContext<{ dispatchCopyFolder: (src: string, dest: string) => Promise, dispatchRunScript: (path: string) => Promise, dispatchEmitContextMenuEvent: (cmd: customAction) => Promise, - dispatchHandleClickFile: (path: string, type: 'file' | 'folder' | 'gist') => Promise + dispatchHandleClickFile: (path: string, type: 'file' | 'folder' ) => Promise dispatchHandleExpandPath: (paths: string[]) => Promise, dispatchHandleDownloadFiles: () => Promise, dispatchHandleDownloadWorkspace: () => Promise, diff --git a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx index 8d7c1ac5bd..e4bbd25cec 100644 --- a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx +++ b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx @@ -133,7 +133,7 @@ export const FileSystemProvider = (props: WorkspaceProps) => { await createNewFile(path, rootDir) } - const dispatchSetFocusElement = async (elements: {key: string; type: 'file' | 'folder' | 'gist'}[]) => { + const dispatchSetFocusElement = async (elements: {key: string; type: 'file' | 'folder' }[]) => { await setFocusElement(elements) } @@ -173,7 +173,7 @@ export const FileSystemProvider = (props: WorkspaceProps) => { await emitContextMenuEvent(cmd) } - const dispatchHandleClickFile = async (path: string, type: 'file' | 'folder' | 'gist') => { + const dispatchHandleClickFile = async (path: string, type: 'file' | 'folder' ) => { await handleClickFile(path, type) } diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index fc059dc90d..3f9dde30f2 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -2,6 +2,7 @@ import React, {useState, useEffect, useRef, useContext, ChangeEvent} from 'react import {FormattedMessage, useIntl} from 'react-intl' import {Dropdown} from 'react-bootstrap' import {CustomIconsToggle, CustomMenu, CustomToggle, CustomTooltip, extractNameFromKey, extractParentFromKey} from '@remix-ui/helper' +import {CopyToClipboard} from '@remix-ui/clipboard' import {FileExplorer} from './components/file-explorer' // eslint-disable-line import {FileSystemContext} from './contexts' import './css/remix-ui-workspace.css' @@ -438,7 +439,7 @@ export function Workspace() { } } - const handleCopyClick = (path: string, type: 'folder' | 'gist' | 'file' | 'workspace') => { + const handleCopyClick = (path: string, type: 'folder' | 'file' | 'workspace') => { setState((prevState) => { return {...prevState, copyElement: [{key: path, type}]} }) @@ -507,7 +508,6 @@ export function Workspace() { const focusElement = global.fs.focusElement if (focusElement[0]) { if (focusElement[0].type === 'folder' && focusElement[0].key) return focusElement[0].key - else if (focusElement[0].type === 'gist' && focusElement[0].key) return focusElement[0].key else if (focusElement[0].type === 'file' && focusElement[0].key) return extractParentFromKey(focusElement[0].key) ? extractParentFromKey(focusElement[0].key) : ROOT_PATH else return ROOT_PATH } @@ -988,6 +988,12 @@ export function Workspace() { > saveSampleCodeWorkspace()} className="far fa-exclamation-triangle text-warning ml-2 align-self-center" aria-hidden="true"> } + + {selectedWorkspace && selectedWorkspace.isGist && selectedWorkspace.isGist} direction="bottom" icon="far fa-copy"> + + + } +
diff --git a/libs/remix-ui/workspace/src/lib/types/index.ts b/libs/remix-ui/workspace/src/lib/types/index.ts index 313f7a5dda..635c9925db 100644 --- a/libs/remix-ui/workspace/src/lib/types/index.ts +++ b/libs/remix-ui/workspace/src/lib/types/index.ts @@ -43,7 +43,7 @@ export interface FileType { path: string name: string isDirectory: boolean - type: 'folder' | 'file' | 'gist' + type: 'folder' | 'file' child?: File[] } @@ -319,4 +319,4 @@ export interface Action { export type Actions = {[A in keyof ActionPayloadTypes]: Action}[keyof ActionPayloadTypes] -export type WorkspaceElement = 'folder' | 'gist' | 'file' | 'workspace' +export type WorkspaceElement = 'folder' | 'file' | 'workspace' diff --git a/libs/remix-ui/workspace/src/lib/utils/index.ts b/libs/remix-ui/workspace/src/lib/utils/index.ts index 438599bd94..d29b524163 100644 --- a/libs/remix-ui/workspace/src/lib/utils/index.ts +++ b/libs/remix-ui/workspace/src/lib/utils/index.ts @@ -1,18 +1,18 @@ import { appPlatformTypes } from '@remix-ui/app' import { FileType } from '@remix-ui/file-decorators' -import { WorkspaceProps, MenuItems } from '../types' +import { MenuItems } from '../types' export const contextMenuActions: MenuItems = [{ id: 'newFile', name: 'New File', - type: ['folder', 'gist', 'workspace'], + type: ['folder', 'workspace'], multiselect: false, label: '', group: 0 }, { id: 'newFolder', name: 'New Folder', - type: ['folder', 'gist', 'workspace'], + type: ['folder', 'workspace'], multiselect: false, label: '', group: 0 @@ -26,7 +26,7 @@ export const contextMenuActions: MenuItems = [{ }, { id: 'delete', name: 'Delete', - type: ['file', 'folder', 'gist'], + type: ['file', 'folder'], multiselect: false, label: '', group: 0 @@ -80,14 +80,6 @@ export const contextMenuActions: MenuItems = [{ multiselect: false, label: '', group: 3 -}, { - id: 'pushChangesToGist', - name: 'Push changes to gist', - type: ['gist'], - multiselect: false, - label: '', - group: 4, - platform: appPlatformTypes.web }, { id: 'publishFolderToGist', name: 'Publish folder to gist', @@ -107,7 +99,7 @@ export const contextMenuActions: MenuItems = [{ }, { id: 'uploadFile', name: 'Load a Local File', - type: ['folder', 'gist', 'workspace'], + type: ['folder', 'workspace'], multiselect: false, label: 'Load a Local File', group: 4, From d9c484806c3225c4fa3ac99f0d20971e26f2fed0 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 19 Feb 2024 14:50:24 +0100 Subject: [PATCH 04/26] fix E2E --- apps/remix-ide-e2e/src/tests/gist.test.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 97d21c8e37..38ef449fd4 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -37,9 +37,9 @@ module.exports = { .addFile('File.sol', { content: '' }) .executeScriptInTerminal(`remix.loadgist('${gistid}')`) // .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() }) - .waitForElementVisible(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`) + .waitForElementVisible(`[data-id="treeViewLitreeViewItemREADME.txt"]`) - .openFile(`gist-${gistid}/README.txt`) + .openFile(`README.txt`) // Remix publish to gist /* .click('*[data-id="fileExplorerNewFilepublishToGist"]') .pause(2000) @@ -142,9 +142,9 @@ module.exports = { .setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId) .modalFooterOKClick('gisthandler') .pause(10000) - .openFile(`gist-${testData.validGistId}/README.txt`) - .waitForElementVisible(`div[data-path='default_workspace/gist-${testData.validGistId}/README.txt']`) - .assert.containsText(`div[data-path='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt') + .openFile(`README.txt`) + .waitForElementVisible(`div[data-path='default_workspace/README.txt']`) + .assert.containsText(`div[data-path='default_workspace/README.txt'] > span`, 'README.txt') }, 'Load Gist from URL and verify truncated files are loaded #group3': function (browser: NightwatchBrowser) { @@ -153,13 +153,12 @@ module.exports = { .url('http://127.0.0.1:8080/#gist=' + gistId) // loading the gist .refreshPage() .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 15000) - .waitForElementVisible(`#fileExplorerView li[data-path='gist-${gistId}/README.txt']`, 30000) - .openFile(`gist-${gistId}/scripts/deploy_with_ethers.ts`) + .waitForElementVisible(`#fileExplorerView li[data-path='README.txt']`, 30000) + .openFile(`scripts/deploy_with_ethers.ts`) .getEditorValue((content) => { browser.assert.ok(content !== '') }) - .rightClickCustom(`li[data-path='gist-${gistId}'] div`) // saving the gist - .click('[data-id="contextMenuItempublishFolderToGist"]') + .click('*[data-id="fileExplorerNewFileupdateGist"]') .modalFooterOKClick('fileSystem') .waitForElementVisible('*[data-shared="tooltipPopup"]', 5000) .assert.containsText('*[data-shared="tooltipPopup"]', 'Saving gist (' + gistId + ') ...') From d6aa344e683300ae1144755ed395c2bb7879d13d Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 19 Feb 2024 18:51:53 +0100 Subject: [PATCH 05/26] move gist publush to the workspace menu item --- .../src/app/tabs/locales/en/filePanel.json | 3 ++- .../src/lib/components/file-explorer-menu.tsx | 14 -------------- .../src/lib/components/workspace-hamburger.tsx | 12 ++++++++++++ .../workspace/src/lib/remix-ui-workspace.tsx | 1 + 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index 0e493a8e0c..9474dfbac2 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -62,7 +62,8 @@ "filePanel.compileForNahmii": "Compile for Nahmii", "filePanel.createNewFile": "Create new file", "filePanel.createNewFolder": "Create new folder", - "filePanel.publishToGist": "Publish workspace to GitHub gist", + "filePanel.publishToGist": "Publish to Gist", + "filePanel.workspace.publishToGist": "Publish workspace to GitHub gist", "filePanel.uploadFile": "Upload files", "filePanel.uploadFolder": "Upload folder", "filePanel.updateGist": "Publish workspace to GitHub gist", diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx index bba7bbc39a..1ae9e7a9ad 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx @@ -26,20 +26,6 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { placement: 'top', platforms:[appPlatformTypes.web, appPlatformTypes.desktop] }, - { - action: 'publishToGist', - title: 'Publish current workspace to GitHub gist', - icon: 'fab fa-github', - placement: 'top', - platforms:[appPlatformTypes.web] - }, - { - action: 'updateGist', - title: 'Update the cdddurrent gist', - icon: 'fab fa-github', - placement: 'bottom-start', - platforms:[appPlatformTypes.web] - }, { action: 'uploadFile', title: 'Upload files into current workspace', diff --git a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx index 00ee0db432..6d8fd1f0c6 100644 --- a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx +++ b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx @@ -9,6 +9,7 @@ export interface HamburgerMenuProps { downloadCurrentWorkspace: () => void deleteCurrentWorkspace: () => void deleteAllWorkspaces: () => void + pushChangesToGist: () => void cloneGitRepository: () => void downloadWorkspaces: () => void restoreBackup: () => void @@ -88,6 +89,17 @@ export function HamburgerMenu(props: HamburgerMenuProps) { platforms={[appPlatformTypes.web]} > + { + props.pushChangesToGist() + props.hideIconsMenu(!showIconsMenu) + }} + platforms={[appPlatformTypes.web]} + > + Date: Mon, 19 Feb 2024 18:55:20 +0100 Subject: [PATCH 06/26] remove uneeded param --- .../src/lib/components/file-explorer.tsx | 4 ++-- .../workspace/src/lib/remix-ui-workspace.tsx | 16 ++++++++-------- libs/remix-ui/workspace/src/lib/types/index.ts | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx index b323e2a750..c1ffe28bd5 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx @@ -143,12 +143,12 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const publishToGist = (path?: string, type?: string) => { + const publishToGist = (path?: string) => { props.modal( intl.formatMessage({ id: 'filePanel.createPublicGist' }), intl.formatMessage({ id: 'filePanel.createPublicGistMsg4' }, { name }), intl.formatMessage({ id: 'filePanel.ok' }), - () => toGist(path, type), + () => toGist(path), intl.formatMessage({ id: 'filePanel.cancel' }), () => { } ) diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 0a054e4c73..25d48e3115 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -571,34 +571,34 @@ export function Workspace() { } } - const pushChangesToGist = (path?: string, type?: string) => { + const pushChangesToGist = (path?: string) => { global.modal( intl.formatMessage({id: 'filePanel.createPublicGist'}), intl.formatMessage({id: 'filePanel.createPublicGistMsg1'}), intl.formatMessage({id: 'filePanel.ok'}), - () => toGist(path, type), + () => toGist(path), intl.formatMessage({id: 'filePanel.cancel'}), () => {} ) } - const publishFolderToGist = (path?: string, type?: string) => { + const publishFolderToGist = (path?: string) => { global.modal( intl.formatMessage({id: 'filePanel.createPublicGist'}), intl.formatMessage({id: 'filePanel.createPublicGistMsg2'}, {path}), intl.formatMessage({id: 'filePanel.ok'}), - () => toGist(path, type), + () => toGist(path), intl.formatMessage({id: 'filePanel.cancel'}), () => {} ) } - const publishFileToGist = (path?: string, type?: string) => { + const publishFileToGist = (path?: string) => { global.modal( intl.formatMessage({id: 'filePanel.createPublicGist'}), intl.formatMessage({id: 'filePanel.createPublicGistMsg3'}, {path}), intl.formatMessage({id: 'filePanel.ok'}), - () => toGist(path, type), + () => toGist(path), intl.formatMessage({id: 'filePanel.cancel'}), () => {} ) @@ -633,8 +633,8 @@ export function Workspace() { ) } - const toGist = (path?: string, type?: string) => { - global.dispatchPublishToGist(path, type) + const toGist = (path?: string) => { + global.dispatchPublishToGist(path) } const editModeOn = (path: string, type: string, isNew = false) => { diff --git a/libs/remix-ui/workspace/src/lib/types/index.ts b/libs/remix-ui/workspace/src/lib/types/index.ts index 635c9925db..c9b7350eb1 100644 --- a/libs/remix-ui/workspace/src/lib/types/index.ts +++ b/libs/remix-ui/workspace/src/lib/types/index.ts @@ -155,10 +155,10 @@ export interface FileExplorerContextMenuProps { renamePath: (path: string, type: string) => void downloadPath: (path: string) => void hideContextMenu: () => void - publishToGist?: (path?: string, type?: string) => void - pushChangesToGist?: (path?: string, type?: string) => void - publishFolderToGist?: (path?: string, type?: string) => void - publishFileToGist?: (path?: string, type?: string) => void + publishToGist?: (path?: string) => void + pushChangesToGist?: (path?: string) => void + publishFolderToGist?: (path?: string) => void + publishFileToGist?: (path?: string) => void runScript?: (path: string) => void emit?: (cmd: customAction) => void pageX: number From d9027bd0ec6bb2b8012b5c4d622398e3a97cf6d5 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 19 Feb 2024 19:13:59 +0100 Subject: [PATCH 07/26] remove unneeded param --- .../src/lib/components/file-explorer-context-menu.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx index 73a143acc9..08659f64e8 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx @@ -187,15 +187,15 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => break case 'Push changes to gist': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'pushToChangesoGist']) - pushChangesToGist(path, type) + pushChangesToGist(path) break case 'Publish folder to gist': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'publishFolderToGist']) - publishFolderToGist(path, type) + publishFolderToGist(path) break case 'Publish file to gist': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'publishFileToGist']) - publishFileToGist(path, type) + publishFileToGist(path) break case 'Run': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'runScript']) @@ -227,7 +227,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => break case 'Publish Workspace to Gist': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'publishWorkspace']) - publishFolderToGist(path, type) + publishFolderToGist(path) break default: _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', `${item.id}/${item.name}`]) From c94b2de42e5a8f1021b7e112539df2832f4b8e35 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 19 Feb 2024 19:14:43 +0100 Subject: [PATCH 08/26] update hamburger item label --- .../remix-ide/src/app/tabs/locales/en/filePanel.json | 3 ++- .../src/lib/components/workspace-hamburger.tsx | 6 ++++-- .../workspace/src/lib/remix-ui-workspace.tsx | 12 +++--------- libs/remix-ui/workspace/src/lib/types/index.ts | 9 +++++++++ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index 9474dfbac2..05fef4beab 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -66,7 +66,8 @@ "filePanel.workspace.publishToGist": "Publish workspace to GitHub gist", "filePanel.uploadFile": "Upload files", "filePanel.uploadFolder": "Upload folder", - "filePanel.updateGist": "Publish workspace to GitHub gist", + "filePanel.updateGist": "Update Gist", + "filePanel.workspace.updateGist": "Publish Gist update", "filePanel.viewAllBranches": "View all branches", "filePanel.createBranch": "Create branch", "filePanel.switchBranches": "Switch branches", diff --git a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx index 6d8fd1f0c6..8960ad22c6 100644 --- a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx +++ b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx @@ -2,8 +2,10 @@ import { appPlatformTypes } from '@remix-ui/app' import React from 'react' import {Dropdown} from 'react-bootstrap' import {HamburgerMenuItem, HamburgerSubMenuItem} from './workspace-hamburger-item' +import { WorkspaceMetadata } from '../types' export interface HamburgerMenuProps { + selectedWorkspace: WorkspaceMetadata createWorkspace: () => void renameCurrentWorkspace: () => void downloadCurrentWorkspace: () => void @@ -25,7 +27,7 @@ export interface HamburgerMenuProps { } export function HamburgerMenu(props: HamburgerMenuProps) { - const {showIconsMenu, hideWorkspaceOptions, hideLocalhostOptions, hideFileOperations} = props + const {showIconsMenu, hideWorkspaceOptions, hideLocalhostOptions, hideFileOperations, selectedWorkspace} = props return ( <> { diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 25d48e3115..68cd0b7608 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -9,7 +9,7 @@ import './css/remix-ui-workspace.css' import {ROOT_PATH, TEMPLATE_NAMES} from './utils/constants' import {HamburgerMenu} from './components/workspace-hamburger' -import {MenuItems, WorkSpaceState} from './types' +import {MenuItems, WorkSpaceState, WorkspaceMetadata} from './types' import {contextMenuActions} from './utils' import FileExplorerContextMenu from './components/file-explorer-context-menu' import { customAction } from '@remixproject/plugin-api' @@ -27,14 +27,7 @@ export function Workspace() { const LOCALHOST = ' - connect to localhost - ' const NO_WORKSPACE = ' - none - ' const [currentWorkspace, setCurrentWorkspace] = useState(NO_WORKSPACE) - const [selectedWorkspace, setSelectedWorkspace] = useState<{ - name: string - isGitRepo: boolean - hasGitSubmodules?: boolean - branches?: {remote: any; name: string}[] - currentBranch?: string - isGist: string - }>(null) + const [selectedWorkspace, setSelectedWorkspace] = useState(null) const [showDropdown, setShowDropdown] = useState(false) const [showIconsMenu, hideIconsMenu] = useState(false) const [showBranches, setShowBranches] = useState(false) @@ -952,6 +945,7 @@ export function Workspace() { > void createWorkspace: (name: string, workspaceTemplateName: string) => void From f3051b815a1f90fb66589fe08981faf860802d79 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 19 Feb 2024 19:17:49 +0100 Subject: [PATCH 09/26] move TemplateType to index --- libs/remix-ui/workspace/src/lib/actions/workspace.ts | 2 +- libs/remix-ui/workspace/src/lib/types/index.ts | 9 +++++++++ libs/remix-ui/workspace/src/lib/utils/constants.ts | 2 +- libs/remix-ui/workspace/src/lib/utils/types.ts | 8 -------- 4 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 libs/remix-ui/workspace/src/lib/utils/types.ts diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 7649e1400d..ec3557e54d 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -2,7 +2,7 @@ import React from 'react' import { bufferToHex } from '@ethereumjs/util' import { hash } from '@remix-project/remix-lib' import { TEMPLATE_METADATA, TEMPLATE_NAMES } from '../utils/constants' -import { TemplateType } from '../utils/types' +import { TemplateType } from '../types' import IpfsHttpClient from 'ipfs-http-client' import axios, { AxiosResponse } from 'axios' import { diff --git a/libs/remix-ui/workspace/src/lib/types/index.ts b/libs/remix-ui/workspace/src/lib/types/index.ts index 8f157b9ea6..7d812c75ec 100644 --- a/libs/remix-ui/workspace/src/lib/types/index.ts +++ b/libs/remix-ui/workspace/src/lib/types/index.ts @@ -56,6 +56,15 @@ export type WorkspaceMetadata = { isGist: string } +export type TemplateType = { + type: 'git' | 'plugin' + url?: string + branch?: string + name?: string + endpoint?: string + params?: any[] +} + export interface FilePanelType extends ViewPlugin { setWorkspace: ({ name, isLocalhost }, setEvent: boolean) => void createWorkspace: (name: string, workspaceTemplateName: string) => void diff --git a/libs/remix-ui/workspace/src/lib/utils/constants.ts b/libs/remix-ui/workspace/src/lib/utils/constants.ts index e5a4b21523..823bcabdc3 100644 --- a/libs/remix-ui/workspace/src/lib/utils/constants.ts +++ b/libs/remix-ui/workspace/src/lib/utils/constants.ts @@ -1,4 +1,4 @@ -import { TemplateType } from './types' +import { TemplateType } from '../types' export const ROOT_PATH = '/' export const solTestYml = ` name: Running Solidity Unit Tests diff --git a/libs/remix-ui/workspace/src/lib/utils/types.ts b/libs/remix-ui/workspace/src/lib/utils/types.ts deleted file mode 100644 index 750001bca5..0000000000 --- a/libs/remix-ui/workspace/src/lib/utils/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type TemplateType = { - type: 'git' | 'plugin' - url?: string - branch?: string - name?: string - endpoint?: string - params?: any[] - } \ No newline at end of file From 6748281240de45c2ce5a4cac3b4a94b8c74c65cb Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 20 Feb 2024 12:23:05 +0100 Subject: [PATCH 10/26] fix test --- apps/remix-ide-e2e/src/tests/gist.test.ts | 13 +++++++------ apps/remix-ide-e2e/src/tests/plugin_api.ts | 7 ++++--- .../remix-ui/workspace/src/lib/actions/workspace.ts | 3 +-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 38ef449fd4..e0a2e15996 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -110,8 +110,8 @@ module.exports = { .waitForElementVisible('[data-id="settingsTabRemoveGistToken"]') .click('[data-id="settingsTabRemoveGistToken"]') .clickLaunchIcon('filePanel') - .waitForElementVisible('*[data-id="fileExplorerNewFilepublishToGist"]') - .click('*[data-id="fileExplorerNewFilepublishToGist"]') + .click('*[data-id="workspacesMenuDropdown"]') + .click('*[data-id="workspacepublishToGist"]') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() }) .pause(10000) @@ -153,12 +153,13 @@ module.exports = { .url('http://127.0.0.1:8080/#gist=' + gistId) // loading the gist .refreshPage() .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 15000) - .waitForElementVisible(`#fileExplorerView li[data-path='README.txt']`, 30000) - .openFile(`scripts/deploy_with_ethers.ts`) + .waitForElementVisible(`#fileExplorerView li[data-path='contracts']`, 30000) + .openFile(`contracts/2_Owner.sol`) .getEditorValue((content) => { - browser.assert.ok(content !== '') + browser.assert.ok(content.indexOf('contract Owner {') !== -1) }) - .click('*[data-id="fileExplorerNewFileupdateGist"]') + .click('*[data-id="workspacesMenuDropdown"]') + .click('*[data-id="workspacepublishToGist"]') .modalFooterOKClick('fileSystem') .waitForElementVisible('*[data-shared="tooltipPopup"]', 5000) .assert.containsText('*[data-shared="tooltipPopup"]', 'Saving gist (' + gistId + ') ...') diff --git a/apps/remix-ide-e2e/src/tests/plugin_api.ts b/apps/remix-ide-e2e/src/tests/plugin_api.ts index 91a1df9ad4..69bbc140ca 100644 --- a/apps/remix-ide-e2e/src/tests/plugin_api.ts +++ b/apps/remix-ide-e2e/src/tests/plugin_api.ts @@ -128,6 +128,7 @@ const checkForAcceptAndRemember = async function (browser: NightwatchBrowser) { */ const clickAndCheckLog = async (browser: NightwatchBrowser, buttonText: string, methodResult: any, eventResult: any, payload: any, waitResult: boolean = true) => { // eslint-disable-line + console.log('clickAndCheckLog', buttonText, methodResult, eventResult, payload, waitResult) if (payload) { await setPayload(browser, payload) } else { @@ -295,7 +296,7 @@ module.exports = { }, null, '/') }, 'Should get all workspaces #group2': async function (browser: NightwatchBrowser) { - await clickAndCheckLog(browser, 'filePanel:getWorkspaces', [{name:"default_workspace",isGitRepo:false,hasGitSubmodules:false}, {name:"emptyworkspace",isGitRepo:false,hasGitSubmodules:false}, {name:"testspace",isGitRepo:false,hasGitSubmodules:false}], null, null) + await clickAndCheckLog(browser, 'filePanel:getWorkspaces', [{name:"default_workspace",isGitRepo:false,hasGitSubmodules:false,isGist:null}, {name:"emptyworkspace",isGitRepo:false,hasGitSubmodules:false,isGist:null}, {name:"testspace",isGitRepo:false,hasGitSubmodules:false,isGist:null}], null, null) }, 'Should have set workspace event #group2': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, { event: 'setWorkspace', args: [{ name: 'newspace', isLocalhost: false }] }, 'newspace') @@ -309,11 +310,11 @@ module.exports = { 'Should rename workspace #group2': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'filePanel:renameWorkspace', null, null, ['default_workspace', 'renamed']) - await clickAndCheckLog(browser, 'filePanel:getWorkspaces', [{name:"emptyworkspace",isGitRepo:false,hasGitSubmodules:false},{name:"testspace",isGitRepo:false,hasGitSubmodules:false},{name:"newspace",isGitRepo:false,hasGitSubmodules:false},{name:"renamed",isGitRepo:false,hasGitSubmodules:false}], null, null) + await clickAndCheckLog(browser, 'filePanel:getWorkspaces', [{name:"emptyworkspace",isGitRepo:false,hasGitSubmodules:false,isGist:null},{name:"testspace",isGitRepo:false,hasGitSubmodules:false,isGist:null},{name:"newspace",isGitRepo:false,hasGitSubmodules:false,isGist:null},{name:"renamed",isGitRepo:false,hasGitSubmodules:false,isGist:null}], null, null) }, 'Should delete workspace #group2': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'filePanel:deleteWorkspace', null, null, ['testspace']) - await clickAndCheckLog(browser, 'filePanel:getWorkspaces', [{name:"emptyworkspace",isGitRepo:false,hasGitSubmodules:false},{name:"newspace",isGitRepo:false,hasGitSubmodules:false},{name:"renamed",isGitRepo:false,hasGitSubmodules:false}], null, null) + await clickAndCheckLog(browser, 'filePanel:getWorkspaces', [{name:"emptyworkspace",isGitRepo:false,hasGitSubmodules:false,isGist:null},{name:"newspace",isGitRepo:false,hasGitSubmodules:false,isGist:null},{name:"renamed",isGitRepo:false,hasGitSubmodules:false,isGist:null}], null, null) }, // DGIT 'Should have changes on new workspace #group3': async function (browser: NightwatchBrowser) { diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index ec3557e54d..be45f3f4d7 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -627,12 +627,11 @@ export const getWorkspaces = async (): Promise<{ name: string; isGitRepo: boolea isGist: null } } else { - const gistId = await plugin.call('filePanel', 'isGist', name) return { name, isGitRepo, hasGitSubmodules, - isGist: gistId + isGist: plugin.isGist(name) // plugin is filePanel } } }) From cfe278d362bd84c650d2eaf86e4d08eacaea2cdc Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 21 Feb 2024 13:08:29 +0100 Subject: [PATCH 11/26] fix creating workspace from gist load --- apps/remix-ide-e2e/src/tests/gist.test.ts | 5 +++-- libs/remix-core-plugin/src/lib/gist-handler.ts | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index e0a2e15996..ff0c60f23a 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -143,8 +143,8 @@ module.exports = { .modalFooterOKClick('gisthandler') .pause(10000) .openFile(`README.txt`) - .waitForElementVisible(`div[data-path='default_workspace/README.txt']`) - .assert.containsText(`div[data-path='default_workspace/README.txt'] > span`, 'README.txt') + .waitForElementVisible(`div[data-path='gist ${testData.validGistId}/README.txt']`) + .assert.containsText(`div[data-path='gist ${testData.validGistId}/README.txt'] > span`, 'README.txt') }, 'Load Gist from URL and verify truncated files are loaded #group3': function (browser: NightwatchBrowser) { @@ -152,6 +152,7 @@ module.exports = { browser .url('http://127.0.0.1:8080/#gist=' + gistId) // loading the gist .refreshPage() + .currentWorkspaceIs('gist ' + gistId) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 15000) .waitForElementVisible(`#fileExplorerView li[data-path='contracts']`, 30000) .openFile(`contracts/2_Owner.sol`) diff --git a/libs/remix-core-plugin/src/lib/gist-handler.ts b/libs/remix-core-plugin/src/lib/gist-handler.ts index e204b21a1b..c3a53a75f1 100644 --- a/libs/remix-core-plugin/src/lib/gist-handler.ts +++ b/libs/remix-core-plugin/src/lib/gist-handler.ts @@ -114,6 +114,16 @@ export class GistHandler extends Plugin { return } + const gistIdWorkspace = 'gist ' + gistId + const workspaces = await this.call('filePanel', 'getWorkspaces') + const found = workspaces.find((workspace) => workspace.name === gistIdWorkspace) + if (found) { + await this.call('notification', 'alert', `workspace "${gistIdWorkspace}" already exist`) + return + } + await this.call('filePanel', 'createWorkspace', 'gist ' + gistId, '', true) + await this.call('filePanel', 'switchToWorkspace', { name: 'gist ' + gistId, isLocalHost: false }) + const obj: StringByString = {} Object.keys(data.files).forEach((element) => { const path = element.replace(/\.\.\./g, '/') From 88eeb772725c2740765e768011ea751120ce641e Mon Sep 17 00:00:00 2001 From: drafish Date: Wed, 17 Jan 2024 13:59:10 +0800 Subject: [PATCH 12/26] add learneth plugin --- apps/learneth/project.json | 58 +++++ apps/learneth/src/App.css | 19 ++ apps/learneth/src/App.test.tsx | 15 ++ apps/learneth/src/App.tsx | 51 ++++ apps/learneth/src/assets/.gitkeep | 0 .../Font_Awesome_5_solid_book-reader.svg | 5 + apps/learneth/src/assets/logo-background.svg | 1 + .../src/components/BackButton/index.scss | 55 ++++ .../src/components/BackButton/index.tsx | 91 +++++++ .../src/components/LoadingScreen/index.css | 17 ++ .../src/components/LoadingScreen/index.tsx | 16 ++ .../src/components/RepoImporter/index.css | 4 + .../src/components/RepoImporter/index.tsx | 165 ++++++++++++ .../learneth/src/components/SlideIn/index.css | 21 ++ .../learneth/src/components/SlideIn/index.tsx | 18 ++ apps/learneth/src/index.css | 13 + apps/learneth/src/index.html | 18 ++ apps/learneth/src/logo.svg | 1 + apps/learneth/src/main.tsx | 15 ++ apps/learneth/src/pages/Home/index.css | 23 ++ apps/learneth/src/pages/Home/index.tsx | 136 ++++++++++ apps/learneth/src/pages/Logo/index.css | 5 + apps/learneth/src/pages/Logo/index.tsx | 26 ++ apps/learneth/src/pages/StepDetail/index.scss | 59 +++++ apps/learneth/src/pages/StepDetail/index.tsx | 246 ++++++++++++++++++ apps/learneth/src/pages/StepList/index.scss | 152 +++++++++++ apps/learneth/src/pages/StepList/index.tsx | 44 ++++ apps/learneth/src/polyfills.ts | 7 + apps/learneth/src/profile.json | 21 ++ apps/learneth/src/react-app-env.d.ts | 1 + apps/learneth/src/redux/hooks.ts | 5 + apps/learneth/src/redux/models/loading.ts | 14 + apps/learneth/src/redux/models/remixide.ts | 233 +++++++++++++++++ apps/learneth/src/redux/models/workshop.ts | 179 +++++++++++++ apps/learneth/src/redux/store.ts | 117 +++++++++ apps/learneth/src/remix-client.ts | 38 +++ apps/learneth/src/setupTests.ts | 5 + apps/learneth/tsconfig.app.json | 23 ++ apps/learneth/tsconfig.json | 16 ++ apps/learneth/webpack.config.js | 92 +++++++ apps/remix-ide/project.json | 2 +- package.json | 9 + yarn.lock | 241 ++++++++++++++++- 43 files changed, 2274 insertions(+), 3 deletions(-) create mode 100644 apps/learneth/project.json create mode 100644 apps/learneth/src/App.css create mode 100644 apps/learneth/src/App.test.tsx create mode 100644 apps/learneth/src/App.tsx create mode 100644 apps/learneth/src/assets/.gitkeep create mode 100644 apps/learneth/src/assets/Font_Awesome_5_solid_book-reader.svg create mode 100644 apps/learneth/src/assets/logo-background.svg create mode 100644 apps/learneth/src/components/BackButton/index.scss create mode 100644 apps/learneth/src/components/BackButton/index.tsx create mode 100644 apps/learneth/src/components/LoadingScreen/index.css create mode 100644 apps/learneth/src/components/LoadingScreen/index.tsx create mode 100644 apps/learneth/src/components/RepoImporter/index.css create mode 100644 apps/learneth/src/components/RepoImporter/index.tsx create mode 100644 apps/learneth/src/components/SlideIn/index.css create mode 100644 apps/learneth/src/components/SlideIn/index.tsx create mode 100644 apps/learneth/src/index.css create mode 100644 apps/learneth/src/index.html create mode 100644 apps/learneth/src/logo.svg create mode 100644 apps/learneth/src/main.tsx create mode 100644 apps/learneth/src/pages/Home/index.css create mode 100644 apps/learneth/src/pages/Home/index.tsx create mode 100644 apps/learneth/src/pages/Logo/index.css create mode 100644 apps/learneth/src/pages/Logo/index.tsx create mode 100644 apps/learneth/src/pages/StepDetail/index.scss create mode 100644 apps/learneth/src/pages/StepDetail/index.tsx create mode 100644 apps/learneth/src/pages/StepList/index.scss create mode 100644 apps/learneth/src/pages/StepList/index.tsx create mode 100644 apps/learneth/src/polyfills.ts create mode 100644 apps/learneth/src/profile.json create mode 100644 apps/learneth/src/react-app-env.d.ts create mode 100644 apps/learneth/src/redux/hooks.ts create mode 100644 apps/learneth/src/redux/models/loading.ts create mode 100644 apps/learneth/src/redux/models/remixide.ts create mode 100644 apps/learneth/src/redux/models/workshop.ts create mode 100644 apps/learneth/src/redux/store.ts create mode 100644 apps/learneth/src/remix-client.ts create mode 100644 apps/learneth/src/setupTests.ts create mode 100644 apps/learneth/tsconfig.app.json create mode 100644 apps/learneth/tsconfig.json create mode 100644 apps/learneth/webpack.config.js diff --git a/apps/learneth/project.json b/apps/learneth/project.json new file mode 100644 index 0000000000..4dfbec33e1 --- /dev/null +++ b/apps/learneth/project.json @@ -0,0 +1,58 @@ +{ + "name": "learneth", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/learneth/src", + "projectType": "application", + "implicitDependencies": [], + "targets": { + "build": { + "executor": "@nrwl/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "development", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/learneth", + "index": "apps/learneth/src/index.html", + "baseHref": "./", + "main": "apps/learneth/src/main.tsx", + "polyfills": "apps/learneth/src/polyfills.ts", + "tsConfig": "apps/learneth/tsconfig.app.json", + "assets": ["apps/learneth/src/profile.json", "apps/learneth/src/assets/Font_Awesome_5_solid_book-reader.svg"], + "styles": ["apps/learneth/src/index.css"], + "scripts": [], + "webpackConfig": "apps/learneth/webpack.config.js" + }, + "configurations": { + "development": { + }, + "production": { + "fileReplacements": [ + { + "replace": "apps/learneth/src/environments/environment.ts", + "with": "apps/learneth/src/environments/environment.prod.ts" + } + ] + } + } + }, + "serve": { + "executor": "@nrwl/webpack:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "learneth:build", + "hmr": true, + "baseHref": "/" + }, + "configurations": { + "development": { + "buildTarget": "learneth:build:development", + "port": 2023 + }, + "production": { + "buildTarget": "learneth:build:production" + } + } + } + }, + "tags": [] +} diff --git a/apps/learneth/src/App.css b/apps/learneth/src/App.css new file mode 100644 index 0000000000..bf3b1f7aa8 --- /dev/null +++ b/apps/learneth/src/App.css @@ -0,0 +1,19 @@ +/* You can add global styles to this file, and also import other style files */ + + +h1{ + font-size: 1.2rem !important; + font-weight: 700; +} +h2{ + font-size: 1rem !important; + font-weight: 700; +} +h3{ + font-size: 1rem !important; +} + +p { + font-size: 0.9rem; +} + diff --git a/apps/learneth/src/App.test.tsx b/apps/learneth/src/App.test.tsx new file mode 100644 index 0000000000..701a48420e --- /dev/null +++ b/apps/learneth/src/App.test.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import { render, screen } from '@testing-library/react'; +import App from './App'; +import { store } from './redux/store'; + +test('renders learn react link', () => { + render( + + + , + ); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/apps/learneth/src/App.tsx b/apps/learneth/src/App.tsx new file mode 100644 index 0000000000..8582be5a75 --- /dev/null +++ b/apps/learneth/src/App.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { createBrowserRouter, RouterProvider } from 'react-router-dom'; +import { ToastContainer } from 'react-toastify'; +import LoadingScreen from './components/LoadingScreen'; +import LogoPage from './pages/Logo'; +import HomePage from './pages/Home'; +import StepListPage from './pages/StepList'; +import StepDetailPage from './pages/StepDetail'; +import 'react-toastify/dist/ReactToastify.css'; +import './App.css'; + +export const router = createBrowserRouter([ + { + path: '/', + element: , + }, + { + path: '/home', + element: , + }, + { + path: '/list', + element: , + }, + { + path: '/detail', + element: , + }, +]); + +function App(): JSX.Element { + return ( + <> + + + + + ); +} + +export default App; diff --git a/apps/learneth/src/assets/.gitkeep b/apps/learneth/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/learneth/src/assets/Font_Awesome_5_solid_book-reader.svg b/apps/learneth/src/assets/Font_Awesome_5_solid_book-reader.svg new file mode 100644 index 0000000000..2e31d1ca18 --- /dev/null +++ b/apps/learneth/src/assets/Font_Awesome_5_solid_book-reader.svg @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/apps/learneth/src/assets/logo-background.svg b/apps/learneth/src/assets/logo-background.svg new file mode 100644 index 0000000000..cbe3eaec20 --- /dev/null +++ b/apps/learneth/src/assets/logo-background.svg @@ -0,0 +1 @@ +remix_logo1 \ No newline at end of file diff --git a/apps/learneth/src/components/BackButton/index.scss b/apps/learneth/src/components/BackButton/index.scss new file mode 100644 index 0000000000..7f022076f7 --- /dev/null +++ b/apps/learneth/src/components/BackButton/index.scss @@ -0,0 +1,55 @@ +a { + + .arrow { + display: inline-block; + opacity: 0; + transform: scale(0.5); + transition: all 0.3s; + } + span { + display: inline-block; + padding-left: 5px; + transform: translateX(-0.875em); // size of icon + transition: transform 0.3s; + } + + + +} + +.workshoptitle{ + text-decoration: none; +} + +a:hover { + fa-icon { + opacity: 1; + transform: scale(1); + } + span { + transform: translateX(0); + } +} + +// .btn-close{ +// --bs-btn-close-color: #000; +// --bs-btn-close-bg: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3E%3C/svg%3E"); +// --bs-btn-close-opacity: 0.5; +// --bs-btn-close-hover-opacity: 0.75; +// --bs-btn-close-focus-shadow: 0 0 0 0.25rem #0d6efd40; +// --bs-btn-close-focus-opacity: 1; +// --bs-btn-close-disabled-opacity: 0.25; +// --bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%); +// background: #0000 var(--bs-btn-close-bg) center/1em auto no-repeat; +// border: 0; +// border-radius: .375rem; +// box-sizing: initial; +// height: 1em; +// opacity: var(--bs-btn-close-opacity); +// padding: .25em; +// width: 1em +// } + +// [data-bs-theme=dark] .btn-close { +// filter: var(--bs-btn-close-white-filter); +// } diff --git a/apps/learneth/src/components/BackButton/index.tsx b/apps/learneth/src/components/BackButton/index.tsx new file mode 100644 index 0000000000..22a2fbfff4 --- /dev/null +++ b/apps/learneth/src/components/BackButton/index.tsx @@ -0,0 +1,91 @@ +import React, {useState} from 'react' +import {Link, useNavigate} from 'react-router-dom' +import {Button, Modal, Tooltip, OverlayTrigger} from 'react-bootstrap' +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' +import {faHome, faBars, faChevronLeft, faChevronRight} from '@fortawesome/free-solid-svg-icons' +// import {useAppSelector} from '../../redux/hooks' +import './index.scss' + +function BackButton({entity}: any) { + const navigate = useNavigate() + const [show, setShow] = useState(false) + // const theme = useAppSelector((state) => state.remixide.theme) + const isDetailPage = location.pathname === '/detail' + const queryParams = new URLSearchParams(location.search) + const stepId = Number(queryParams.get('stepId')) + + return ( + + ) +} + +export default BackButton diff --git a/apps/learneth/src/components/LoadingScreen/index.css b/apps/learneth/src/components/LoadingScreen/index.css new file mode 100644 index 0000000000..88d2a5a3c7 --- /dev/null +++ b/apps/learneth/src/components/LoadingScreen/index.css @@ -0,0 +1,17 @@ +.spinnersOverlay { + background-color: rgba(51, 51, 51, 0.8); + z-index: 99; + opacity: 1; + height: 100%; + left: 0; + position: fixed; + top: 0; + width: 100%; +} +.spinnersLoading { + left: 50%; + margin: 0; + position: absolute; + top: 50%; + transform: translate(-50%,-50%); +} diff --git a/apps/learneth/src/components/LoadingScreen/index.tsx b/apps/learneth/src/components/LoadingScreen/index.tsx new file mode 100644 index 0000000000..43c27169ea --- /dev/null +++ b/apps/learneth/src/components/LoadingScreen/index.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import BounceLoader from 'react-spinners/BounceLoader'; +import './index.css'; +import { useAppSelector } from '../../redux/hooks'; + +const LoadingScreen: React.FC = () => { + const loading = useAppSelector((state) => state.loading.screen); + + return loading ? ( +
+ +
+ ) : null; +}; + +export default LoadingScreen; diff --git a/apps/learneth/src/components/RepoImporter/index.css b/apps/learneth/src/components/RepoImporter/index.css new file mode 100644 index 0000000000..e46d1a9675 --- /dev/null +++ b/apps/learneth/src/components/RepoImporter/index.css @@ -0,0 +1,4 @@ +.arrow-icon{ + width: 3px; + display: inline-block; +} diff --git a/apps/learneth/src/components/RepoImporter/index.tsx b/apps/learneth/src/components/RepoImporter/index.tsx new file mode 100644 index 0000000000..db00221fe8 --- /dev/null +++ b/apps/learneth/src/components/RepoImporter/index.tsx @@ -0,0 +1,165 @@ +import React, { useState, useEffect } from 'react'; +import { + Button, + Dropdown, + Form, + Tooltip, + OverlayTrigger, +} from 'react-bootstrap'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { + faQuestionCircle, + faInfoCircle, + faChevronRight, + faChevronDown, +} from '@fortawesome/free-solid-svg-icons'; +import { useAppDispatch } from '../../redux/hooks'; +import './index.css'; + +function RepoImporter({ list, selectedRepo }: any): JSX.Element { + const [open, setOpen] = useState(false); + const [name, setName] = useState(''); + const [branch, setBranch] = useState(''); + const dispatch = useAppDispatch(); + + useEffect(() => { + setName(selectedRepo.name); + setBranch(selectedRepo.branch); + }, [selectedRepo]); + + const panelChange = () => { + setOpen(!open); + }; + + const selectRepo = (repo: { name: string; branch: string }) => { + dispatch({ type: 'workshop/loadRepo', payload: repo }); + }; + + const importRepo = (event: { preventDefault: () => void }) => { + event.preventDefault(); + dispatch({ type: 'workshop/loadRepo', payload: { name, branch } }); + }; + + const resetAll = () => { + dispatch({ type: 'workshop/resetAll' }); + setName(''); + setBranch(''); + }; + + return ( + <> + {selectedRepo.name && ( +
+ Tutorials from: +

{selectedRepo.name}

+ + Date modified:{' '} + {new Date(selectedRepo.datemodified).toLocaleString()} + +
+ )} + +
+
+ +
+
Import another tutorial repo
+
+ + {open && ( +
+ + + Select a repo + + + {list.map((item: any) => ( + { + selectRepo(item); + }} + > + {item.name}-{item.branch} + + ))} + + +
+ reset list +
+
+ )} + +
+ + ); +} + +export default RepoImporter; diff --git a/apps/learneth/src/components/SlideIn/index.css b/apps/learneth/src/components/SlideIn/index.css new file mode 100644 index 0000000000..4f6e45324f --- /dev/null +++ b/apps/learneth/src/components/SlideIn/index.css @@ -0,0 +1,21 @@ +.slide-enter { + transform: translateY(100px); + opacity: 0; +} + +.slide-enter-active { + transform: translateY(0); + opacity: 1; + transition: opacity 400ms, transform 400ms cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +.slide-exit { + transform: translateY(0); + opacity: 1; +} + +.slide-exit-active { + transform: translateY(100px); + opacity: 0; + transition: opacity 400ms, transform 400ms cubic-bezier(0.6, 0.04, 0.98, 0.335); +} diff --git a/apps/learneth/src/components/SlideIn/index.tsx b/apps/learneth/src/components/SlideIn/index.tsx new file mode 100644 index 0000000000..c4830b6688 --- /dev/null +++ b/apps/learneth/src/components/SlideIn/index.tsx @@ -0,0 +1,18 @@ +import React, { type ReactNode, useEffect, useState } from 'react'; +import { CSSTransition } from 'react-transition-group'; +import './index.css'; + +const SlideIn: React.FC<{ children: ReactNode }> = ({ children }) => { + const [show, setShow] = useState(false); + useEffect(() => { + setShow(true); + }, []); + + return ( + + {children} + + ); +}; + +export default SlideIn; diff --git a/apps/learneth/src/index.css b/apps/learneth/src/index.css new file mode 100644 index 0000000000..ec2585e8c0 --- /dev/null +++ b/apps/learneth/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/apps/learneth/src/index.html b/apps/learneth/src/index.html new file mode 100644 index 0000000000..21ecda7ec6 --- /dev/null +++ b/apps/learneth/src/index.html @@ -0,0 +1,18 @@ + + + + + Learn ETH + + + + + + + + +
+ + + diff --git a/apps/learneth/src/logo.svg b/apps/learneth/src/logo.svg new file mode 100644 index 0000000000..9dfc1c058c --- /dev/null +++ b/apps/learneth/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/learneth/src/main.tsx b/apps/learneth/src/main.tsx new file mode 100644 index 0000000000..eac81ff2eb --- /dev/null +++ b/apps/learneth/src/main.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { Provider } from 'react-redux'; +import './index.css'; +import App from './App'; +import { store } from './redux/store'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement, +); +root.render( + + + , +); diff --git a/apps/learneth/src/pages/Home/index.css b/apps/learneth/src/pages/Home/index.css new file mode 100644 index 0000000000..2375651475 --- /dev/null +++ b/apps/learneth/src/pages/Home/index.css @@ -0,0 +1,23 @@ +.description-collapsed{ + height: 0px; + overflow: hidden; + word-wrap: break-word; + padding: 0px !important; + margin: 0px !important; +} + +.tag{ + display: inline; +} + +.arrow-icon{ + width: 12px; + display: inline-block; +} + +.workshop-link { + text-decoration: none; +} +.workshop-link:hover { + text-decoration: underline; +} diff --git a/apps/learneth/src/pages/Home/index.tsx b/apps/learneth/src/pages/Home/index.tsx new file mode 100644 index 0000000000..73ddb3e024 --- /dev/null +++ b/apps/learneth/src/pages/Home/index.tsx @@ -0,0 +1,136 @@ +import React, { useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { + faChevronRight, + faChevronDown, + faPlayCircle, +} from '@fortawesome/free-solid-svg-icons'; +import Markdown from 'react-markdown'; +import rehypeRaw from 'rehype-raw'; +import remarkGfm from 'remark-gfm'; +import { useAppDispatch, useAppSelector } from '../../redux/hooks'; +import RepoImporter from '../../components/RepoImporter'; +import './index.css'; + +function HomePage(): JSX.Element { + const [openKeys, setOpenKeys] = React.useState([]); + + const isOpen = (key: string) => openKeys.includes(key); + const handleClick = (key: string) => { + setOpenKeys( + isOpen(key) + ? openKeys.filter((item) => item !== key) + : [...openKeys, key], + ); + }; + + const dispatch = useAppDispatch(); + const { list, detail, selectedId } = useAppSelector( + (state) => state.workshop, + ); + + const selectedRepo = detail[selectedId]; + + const levelMap: any = { + 1: 'Beginner', + 2: 'Intermediate', + 3: 'Advanced', + }; + + useEffect(() => { + dispatch({ + type: 'workshop/init', + }); + }, []); + + return ( +
+ + {selectedRepo && ( +
+ {Object.keys(selectedRepo.group).map((level) => ( +
+
{levelMap[level]}:
+ {selectedRepo.group[level].map((item: any) => ( +
+ +
+ {levelMap[level] && ( +

+ {levelMap[level]} +

+ )} + + {selectedRepo.entities[item.id].metadata.data.tags?.map( + (tag: string) => ( +

+ {tag} +

+ ), + )} + + {selectedRepo.entities[item.id].steps && ( +
+ {selectedRepo.entities[item.id].steps.length} step(s) +
+ )} + +
+ + {selectedRepo.entities[item.id].description?.content} + +
+ +
+
+
+
+ ))} +
+ ))} +
+ )} +
+ ); +} + +export default HomePage; diff --git a/apps/learneth/src/pages/Logo/index.css b/apps/learneth/src/pages/Logo/index.css new file mode 100644 index 0000000000..7a827cacb8 --- /dev/null +++ b/apps/learneth/src/pages/Logo/index.css @@ -0,0 +1,5 @@ +.remixLogo { + position: absolute; + left: 0px; + right: 0px; +} diff --git a/apps/learneth/src/pages/Logo/index.tsx b/apps/learneth/src/pages/Logo/index.tsx new file mode 100644 index 0000000000..e62a814798 --- /dev/null +++ b/apps/learneth/src/pages/Logo/index.tsx @@ -0,0 +1,26 @@ +import React, {useEffect} from 'react' +// import remixClient from '../../remix-client'; +import {useAppDispatch} from '../../redux/hooks' +import logo from '../../assets/logo-background.svg' +import './index.css' + +const LogoPage: React.FC = () => { + const dispatch = useAppDispatch() + + useEffect(() => { + dispatch({type: 'remixide/connect'}) + // remixClient.on('theme', 'themeChanged', (theme: any) => { + // dispatch({ type: 'remixide/save', payload: { theme: theme.quality } }); + // }); + }, []) + + return ( +
+
+ +
+
+ ) +} + +export default LogoPage diff --git a/apps/learneth/src/pages/StepDetail/index.scss b/apps/learneth/src/pages/StepDetail/index.scss new file mode 100644 index 0000000000..e135826c8f --- /dev/null +++ b/apps/learneth/src/pages/StepDetail/index.scss @@ -0,0 +1,59 @@ +step-view { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + overflow: hidden; +} + +header, footer { + padding: 10px 5px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.menuspacer{ + // padding-top: 48px; + +} + +.errorloadingspacer{ + padding-top: 44px; + +} + +.title{ + pointer-events: none; +} + +h1 { + text-align: left; + font-size: 1.2rem !important; + word-break: break-word; +} + +markdown { + display: block; + flex: 1; + overflow: auto; + padding: 0px; + + h1 { + font-size: 1.2rem !important; + } + + h2 { + font-size: 1rem; + } + + h3 { + font-size: 1rem; + } + + h4 { + font-size: 1rem; + } +} + + diff --git a/apps/learneth/src/pages/StepDetail/index.tsx b/apps/learneth/src/pages/StepDetail/index.tsx new file mode 100644 index 0000000000..38ec41cec7 --- /dev/null +++ b/apps/learneth/src/pages/StepDetail/index.tsx @@ -0,0 +1,246 @@ +import React, { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import Markdown from 'react-markdown'; +import rehypeRaw from 'rehype-raw'; +import BackButton from '../../components/BackButton'; +import { useAppSelector, useAppDispatch } from '../../redux/hooks'; +import './index.scss'; + +function StepDetailPage() { + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const queryParams = new URLSearchParams(location.search); + const id = queryParams.get('id') as string; + const stepId = Number(queryParams.get('stepId')); + const { + workshop: { detail, selectedId }, + remixide: { errorLoadingFile, errors, success }, + } = useAppSelector((state: any) => state); + const entity = detail[selectedId].entities[id]; + const steps = entity.steps; + const step = steps[stepId]; + console.log(step); + + useEffect(() => { + dispatch({ + type: 'remixide/displayFile', + payload: step, + }); + dispatch({ + type: 'remixide/save', + payload: { errors: [], success: false }, + }); + window.scrollTo(0, 0); + }, [step]); + + useEffect(() => { + if (errors.length > 0 || success) { + window.scrollTo(0, document.documentElement.scrollHeight); + } + }, [errors, success]); + + return ( + <> +
+
+ +
+
+
+ {errorLoadingFile ? ( + <> +
+

{step.name}

+ +
+ + ) : ( + <> +
+

{step.name}

+ + )} +
+ + {step.markdown?.content} + +
+ {step.test?.content ? ( + <> + + {success && ( + + )} +
+ {success && ( +
+ Well done! No errors. +
+ )} + {errors.length > 0 && ( + <> + {!success && ( +
+ Errors +
+ )} + {errors.map((error: string, index: number) => ( +
+ {error} +
+ ))} + + )} +
+ + ) : ( + <> + + {stepId < steps.length - 1 && ( + + )} + {stepId === steps.length - 1 && ( + + )} + + )} + + ); +} + +export default StepDetailPage; diff --git a/apps/learneth/src/pages/StepList/index.scss b/apps/learneth/src/pages/StepList/index.scss new file mode 100644 index 0000000000..fcccaf4142 --- /dev/null +++ b/apps/learneth/src/pages/StepList/index.scss @@ -0,0 +1,152 @@ +:host { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +header { + padding: 10px 5px; +} + +.menuspacer{ + margin-top: 52px; + +} + +.steplink { + text-decoration: none; +} + +.title{ + pointer-events: none; +} + +h1 { + text-align: left; + font-size: 1.2rem !important; + word-break: break-word; +} +section { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + + + + + + + + .start { + padding: 5px 25px; + animation: jittery 2s 0.5s infinite; + box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.5); + color: white; + cursor: pointer; + } +} + +footer { + padding: 10px; + display: flex; + justify-content: space-between; + align-items: center; +} + +@keyframes jittery { + 5%, + 50% { + transform: scale(1); + box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.5); + } + 10% { + transform: scale(0.9); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); + } + 15% { + transform: scale(1.15); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); + } + 20% { + transform: scale(1.15) rotate(-5deg); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); + } + 25% { + transform: scale(1.15) rotate(5deg); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); + } + 30% { + transform: scale(1.15) rotate(-3deg); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); + } + 35% { + transform: scale(1.15) rotate(2deg); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); + } + 40% { + transform: scale(1.15) rotate(0); + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); + } +} + +.slide-in { + animation: slideIn 0.5s forwards; + visibility: hidden; +} + +@keyframes slideIn { + 0% { + transform: translateY(-100%); + visibility: visible; + } + 100% { + transform: translateY(0); + visibility: visible; + } +} + +@-moz-keyframes slideIn { + 0% { + transform: translateY(-100%); + visibility: visible; + } + 100% { + transform: translateY(0); + visibility: visible; + } +} + +@-webkit-keyframes slideIn { + 0% { + transform: translateY(-100%); + visibility: visible; + } + 100% { + transform: translateY(0); + visibility: visible; + } +} + +@-o-keyframes slideIn { + 0% { + transform: translateY(-100%); + visibility: visible; + } + 100% { + transform: translateY(0); + visibility: visible; + } +} + +@-ms-keyframes slideIn { + 0% { + transform: translateY(-100%); + visibility: visible; + } + 100% { + transform: translateY(0); + visibility: visible; + } +} diff --git a/apps/learneth/src/pages/StepList/index.tsx b/apps/learneth/src/pages/StepList/index.tsx new file mode 100644 index 0000000000..cba5fc583d --- /dev/null +++ b/apps/learneth/src/pages/StepList/index.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import Markdown from 'react-markdown'; +import BackButton from '../../components/BackButton'; +import SlideIn from '../../components/SlideIn'; +import { useAppSelector } from '../../redux/hooks'; +import './index.scss'; + +function StepListPage(): JSX.Element { + const queryParams = new URLSearchParams(location.search); + const id = queryParams.get('id') as string; + const { detail, selectedId } = useAppSelector((state) => state.workshop); + const entity = detail[selectedId].entities[id]; + + return ( + <> +
+
+ +
+
+
+

{entity.name}

+
+ {entity.text} +
+ +
+ {entity.steps.map((step: any, i: number) => ( + + {step.name} » + + ))} +
+
+ + ); +} + +export default StepListPage; diff --git a/apps/learneth/src/polyfills.ts b/apps/learneth/src/polyfills.ts new file mode 100644 index 0000000000..53c485753e --- /dev/null +++ b/apps/learneth/src/polyfills.ts @@ -0,0 +1,7 @@ +/** + * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. + * + * See: https://github.com/zloirock/core-js#babel + */ +import 'core-js/stable' +import 'regenerator-runtime/runtime' diff --git a/apps/learneth/src/profile.json b/apps/learneth/src/profile.json new file mode 100644 index 0000000000..8f381750ef --- /dev/null +++ b/apps/learneth/src/profile.json @@ -0,0 +1,21 @@ +{ + "name": "LearnEth", + "displayName": "LearnEth", + "description": "Learn Ethereum with Remix!", + "documentation": "https://remix-learneth-plugin.readthedocs.io/en/latest/index.html", + "version": "0.1.0", + "methods": [ + "startTutorial", + "addRepository" + ], + "kind": "none", + "icon": "/plugins/learneth/assets/Font_Awesome_5_solid_book-reader.svg", + "location": "sidePanel", + "url": "/plugins/learneth", + "repo": "https://github.com/ethereum/remix-project/tree/master/apps/learneth", + "maintainedBy": "Remix", + "authorContact": "", + "targets": [ + "remix" + ] +} diff --git a/apps/learneth/src/react-app-env.d.ts b/apps/learneth/src/react-app-env.d.ts new file mode 100644 index 0000000000..af825776d5 --- /dev/null +++ b/apps/learneth/src/react-app-env.d.ts @@ -0,0 +1 @@ +import 'react-scripts'; diff --git a/apps/learneth/src/redux/hooks.ts b/apps/learneth/src/redux/hooks.ts new file mode 100644 index 0000000000..c786a3e7ea --- /dev/null +++ b/apps/learneth/src/redux/hooks.ts @@ -0,0 +1,5 @@ +import { useDispatch, type TypedUseSelectorHook, useSelector } from 'react-redux'; +import { type AppDispatch, type RootState } from './store'; + +export const useAppDispatch: () => AppDispatch = useDispatch; +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/apps/learneth/src/redux/models/loading.ts b/apps/learneth/src/redux/models/loading.ts new file mode 100644 index 0000000000..d553dcce8a --- /dev/null +++ b/apps/learneth/src/redux/models/loading.ts @@ -0,0 +1,14 @@ +import { type ModelType } from '../store'; + +const Model: ModelType = { + namespace: 'loading', + state: { screen: true }, + reducers: { + save(state, { payload }) { + return { ...state, ...payload }; + }, + }, + effects: {}, +}; + +export default Model; diff --git a/apps/learneth/src/redux/models/remixide.ts b/apps/learneth/src/redux/models/remixide.ts new file mode 100644 index 0000000000..bb9f6ba8f6 --- /dev/null +++ b/apps/learneth/src/redux/models/remixide.ts @@ -0,0 +1,233 @@ +import {toast} from 'react-toastify' +import {type ModelType} from '../store' +import remixClient from '../../remix-client' +import {router} from '../../App' + +function getFilePath(file: string): string { + const name = file.split('/') + return name.length > 1 ? `${name[name.length - 1]}` : '' +} + +const Model: ModelType = { + namespace: 'remixide', + state: { + errors: [], + success: false, + errorLoadingFile: false, + // theme: '', + }, + reducers: { + save(state, {payload}) { + return {...state, ...payload} + }, + }, + effects: { + *connect(_, {put}) { + toast.info('connecting to the REMIX IDE') + + yield put({ + type: 'loading/save', + payload: { + screen: true, + }, + }) + + yield remixClient.onload() + + // const theme = yield remixClient.call('theme', 'currentTheme'); + + // yield put({ type: 'remixide/save', payload: { theme: theme.quality } }); + + toast.dismiss() + + yield put({ + type: 'loading/save', + payload: { + screen: false, + }, + }) + + yield router.navigate('/home') + }, + *displayFile({payload: step}, {select, put}) { + let content = '' + let path = '' + if (step.solidity?.file) { + content = step.solidity.content + path = getFilePath(step.solidity.file) + } + if (step.js?.file) { + content = step.js.content + path = getFilePath(step.js.file) + } + if (step.vy?.file) { + content = step.vy.content + path = getFilePath(step.vy.file) + } + + if (!content) { + return + } + + toast.info(`loading ${path} into IDE`) + yield put({ + type: 'loading/save', + payload: { + screen: true, + }, + }) + + const {detail, selectedId} = yield select((state) => state.workshop) + + const workshop = detail[selectedId] + console.log('loading ', step, workshop) + + path = `.learneth/${workshop.name}/${step.name}/${path}` + try { + const isExist = yield remixClient.call('fileManager', 'exists' as any, path) + if (!isExist) { + yield remixClient.call('fileManager', 'setFile', path, content) + } + yield remixClient.call('fileManager', 'switchFile', `${path}`) + yield put({ + type: 'remixide/save', + payload: {errorLoadingFile: false}, + }) + toast.dismiss() + } catch (error) { + toast.dismiss() + toast.error('File could not be loaded. Please try again.') + yield put({ + type: 'remixide/save', + payload: {errorLoadingFile: true}, + }) + } + yield put({ + type: 'loading/save', + payload: { + screen: false, + }, + }) + }, + *testStep({payload: step}, {select, put}) { + yield put({ + type: 'loading/save', + payload: { + screen: true, + }, + }) + + try { + yield put({ + type: 'remixide/save', + payload: {success: false}, + }) + const {detail, selectedId} = yield select((state) => state.workshop) + + const workshop = detail[selectedId] + + let path: string + if (step.solidity.file) { + path = getFilePath(step.solidity.file) + path = `.learneth/${workshop.name}/${step.name}/${path}` + yield remixClient.call('fileManager', 'switchFile', `${path}`) + } + + console.log('testing ', step.test.content) + + path = getFilePath(step.test.file) + path = `.learneth/${workshop.name}/${step.name}/${path}` + yield remixClient.call('fileManager', 'setFile', path, step.test.content) + + const result = yield remixClient.call('solidityUnitTesting', 'testFromPath', path) + console.log('result ', result) + + if (!result) { + yield put({ + type: 'remixide/save', + payload: {errors: ['Compiler failed to test this file']}, + }) + } else { + const success = result.totalFailing === 0 + + if (success) { + yield put({ + type: 'remixide/save', + payload: {errors: [], success: true}, + }) + } else { + yield put({ + type: 'remixide/save', + payload: { + errors: result.errors.map((error: {message: any}) => error.message), + }, + }) + } + } + } catch (err) { + console.log('TESTING ERROR', err) + yield put({ + type: 'remixide/save', + payload: {errors: [String(err)]}, + }) + } + yield put({ + type: 'loading/save', + payload: { + screen: false, + }, + }) + }, + *showAnswer({payload: step}, {select, put}) { + yield put({ + type: 'loading/save', + payload: { + screen: true, + }, + }) + + toast.info('loading answer into IDE') + + try { + console.log('loading ', step) + const content = step.answer.content + let path = getFilePath(step.answer.file) + + const {detail, selectedId} = yield select((state) => state.workshop) + + const workshop = detail[selectedId] + path = `.learneth/${workshop.name}/${step.name}/${path}` + yield remixClient.call('fileManager', 'setFile', path, content) + yield remixClient.call('fileManager', 'switchFile', `${path}`) + } catch (err) { + yield put({ + type: 'remixide/save', + payload: {errors: [String(err)]}, + }) + } + + toast.dismiss() + yield put({ + type: 'loading/save', + payload: { + screen: false, + }, + }) + }, + *testSolidityCompiler(_, {put, select}) { + try { + yield remixClient.call('solidity', 'getCompilationResult') + } catch (err) { + const errors = yield select((state) => state.remixide.errors) + yield put({ + type: 'remixide/save', + payload: { + errors: [...errors, "The `Solidity Compiler` is not yet activated.
Please activate it using the `SOLIDITY` button in the `Featured Plugins` section of the homepage."], + }, + }) + } + }, + }, +} + +export default Model diff --git a/apps/learneth/src/redux/models/workshop.ts b/apps/learneth/src/redux/models/workshop.ts new file mode 100644 index 0000000000..eadd44e5e5 --- /dev/null +++ b/apps/learneth/src/redux/models/workshop.ts @@ -0,0 +1,179 @@ +import axios from 'axios'; +import { toast } from 'react-toastify'; +import groupBy from 'lodash/groupBy'; +import pick from 'lodash/pick'; +import { type ModelType } from '../store'; +import remixClient from '../../remix-client'; +import { router } from '../../App'; + +// const apiUrl = 'http://localhost:3001'; +const apiUrl = 'https://static.220.14.12.49.clients.your-server.de:3000'; + +const Model: ModelType = { + namespace: 'workshop', + state: { + list: [], + detail: {}, + selectedId: '', + }, + reducers: { + save(state, { payload }) { + return { ...state, ...payload }; + }, + }, + effects: { + *init(_, { put }) { + const cache = localStorage.getItem('workshop.state'); + + if (cache) { + const workshopState = JSON.parse(cache); + yield put({ + type: 'workshop/save', + payload: workshopState, + }); + } else { + yield put({ + type: 'workshop/loadRepo', + payload: { + name: 'ethereum/remix-workshops', + branch: 'master', + }, + }); + } + }, + *loadRepo({ payload }, { put, select }) { + toast.info(`loading ${payload.name}/${payload.branch}`); + + yield put({ + type: 'loading/save', + payload: { + screen: true, + }, + }); + + const { list, detail } = yield select((state) => state.workshop); + + const url = `${apiUrl}/clone/${encodeURIComponent(payload.name)}/${ + payload.branch + }?${Math.random()}`; + console.log('loading ', url); + const { data } = yield axios.get(url); + console.log(data); + const repoId = `${payload.name}-${payload.branch}`; + + for (let i = 0; i < data.ids.length; i++) { + const { + steps, + metadata: { + data: { steps: metadataSteps }, + }, + } = data.entities[data.ids[i]]; + + let newSteps = []; + + if (metadataSteps) { + newSteps = metadataSteps.map((step: any) => { + return { + ...steps.find((item: any) => item.name === step.path), + name: step.name, + }; + }); + } else { + newSteps = steps.map((step: any) => ({ + ...step, + name: step.name.replace('_', ' '), + })); + } + + const stepKeysWithFile = [ + 'markdown', + 'solidity', + 'test', + 'answer', + 'js', + 'vy', + ]; + + for (let j = 0; j < newSteps.length; j++) { + const step = newSteps[j]; + for (let k = 0; k < stepKeysWithFile.length; k++) { + const key = stepKeysWithFile[k]; + if (step[key]) { + try { + step[key].content = (yield remixClient.call( + 'contentImport', + 'resolve', + step[key].file, + )).content; + } catch (error) { + console.error(error); + } + } + } + } + data.entities[data.ids[i]].steps = newSteps; + } + + const workshopState = { + detail: { + ...detail, + [repoId]: { + ...data, + group: groupBy( + data.ids.map((id: string) => + pick(data.entities[id], ['level', 'id']), + ), + (item: any) => item.level, + ), + ...payload, + }, + }, + list: detail[repoId] ? list : [...list, payload], + selectedId: repoId, + }; + yield put({ + type: 'workshop/save', + payload: workshopState, + }); + localStorage.setItem('workshop.state', JSON.stringify(workshopState)); + + toast.dismiss(); + yield put({ + type: 'loading/save', + payload: { + screen: false, + }, + }); + + if (payload.id) { + const { detail, selectedId } = workshopState; + const { ids, entities } = detail[selectedId]; + for (let i = 0; i < ids.length; i++) { + const entity = entities[ids[i]]; + if (entity.metadata.data.id === payload.id || i + 1 === payload.id) { + yield router.navigate(`/list?id=${ids[i]}`); + break; + } + } + } + }, + *resetAll(_, { put }) { + yield put({ + type: 'workshop/save', + payload: { + list: [], + detail: {}, + selectedId: '', + }, + }); + + localStorage.removeItem('workshop.state'); + + yield put({ + type: 'workshop/init', + }); + }, + }, +}; + +export default Model; diff --git a/apps/learneth/src/redux/store.ts b/apps/learneth/src/redux/store.ts new file mode 100644 index 0000000000..5bd2929a61 --- /dev/null +++ b/apps/learneth/src/redux/store.ts @@ -0,0 +1,117 @@ +import { + configureStore, + createSlice, + type PayloadAction, + type Reducer, +} from '@reduxjs/toolkit'; +import createSagaMiddleware from 'redux-saga'; +import { + call, + put, + takeEvery, + delay, + select, + all, + fork, + type ForkEffect, +} from 'redux-saga/effects'; + +// @ts-expect-error +const context = require.context('./models', false, /\.ts$/); +const models = context.keys().map((key: any) => context(key).default); + +export type StateType = Record; +export interface ModelType { + namespace: string; + state: StateType; + reducers: Record< + string, + (state: StateType, action: PayloadAction) => StateType + >; + effects: Record< + string, + ( + action: PayloadAction, + effects: { + call: typeof call; + put: typeof put; + delay: typeof delay; + select: typeof select; + }, + ) => Generator + >; +} + +function createReducer(model: ModelType): Reducer { + const reducers = model.reducers; + Object.keys(model.effects).forEach((key) => { + reducers[key] = (state: StateType, action: PayloadAction) => state; + }); + const slice = createSlice({ + name: model.namespace, + initialState: model.state, + reducers, + }); + return slice.reducer; +} + +const rootReducer = models.reduce((prev: any, model: ModelType) => { + return { ...prev, [model.namespace]: createReducer(model) }; +}, {}); + +function watchEffects(model: ModelType): ForkEffect { + return fork(function* () { + for (const key in model.effects) { + const effect = model.effects[key]; + yield takeEvery( + `${model.namespace}/${key}`, + function* (action: PayloadAction) { + yield put({ + type: 'loading/save', + payload: { + [`${model.namespace}/${key}`]: true, + }, + }); + yield effect(action, { + call, + put, + delay, + select, + }); + yield put({ + type: 'loading/save', + payload: { + [`${model.namespace}/${key}`]: false, + }, + }); + }, + ); + } + }); +} + +function* rootSaga(): Generator { + yield all(models.map((model: ModelType) => watchEffects(model))); +} + +const configureAppStore = (initialState = {}) => { + const reduxSagaMonitorOptions = {}; + const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions); + + const middleware = [sagaMiddleware]; + + const store = configureStore({ + reducer: rootReducer, + middleware: (gDM) => gDM().concat([...middleware]), + preloadedState: initialState, + devTools: process.env.NODE_ENV !== 'production', + }); + + sagaMiddleware.run(rootSaga); + return store; +}; + +export const store = configureAppStore(); + +export type AppDispatch = typeof store.dispatch; +export type RootState = ReturnType; diff --git a/apps/learneth/src/remix-client.ts b/apps/learneth/src/remix-client.ts new file mode 100644 index 0000000000..fe25ef028a --- /dev/null +++ b/apps/learneth/src/remix-client.ts @@ -0,0 +1,38 @@ +import { PluginClient } from '@remixproject/plugin'; +import { createClient } from '@remixproject/plugin-webview'; +import { store } from './redux/store'; +import { router } from './App'; + +class RemixClient extends PluginClient { + constructor() { + super(); + createClient(this); + } + + startTutorial(name: any, branch: any, id: any): void { + console.log('start tutorial', name, branch, id); + void router.navigate('/home'); + store.dispatch({ + type: 'workshop/loadRepo', + payload: { + name, + branch, + id, + }, + }); + } + + addRepository(name: any, branch: any) { + console.log('add repo', name, branch); + void router.navigate('/home'); + store.dispatch({ + type: 'workshop/loadRepo', + payload: { + name, + branch, + }, + }); + } +} + +export default new RemixClient(); diff --git a/apps/learneth/src/setupTests.ts b/apps/learneth/src/setupTests.ts new file mode 100644 index 0000000000..8f2609b7b3 --- /dev/null +++ b/apps/learneth/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/apps/learneth/tsconfig.app.json b/apps/learneth/tsconfig.app.json new file mode 100644 index 0000000000..af84f21cfc --- /dev/null +++ b/apps/learneth/tsconfig.app.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "jest.config.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/learneth/tsconfig.json b/apps/learneth/tsconfig.json new file mode 100644 index 0000000000..5aab5e7911 --- /dev/null +++ b/apps/learneth/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/learneth/webpack.config.js b/apps/learneth/webpack.config.js new file mode 100644 index 0000000000..fecff4fa70 --- /dev/null +++ b/apps/learneth/webpack.config.js @@ -0,0 +1,92 @@ +const { composePlugins, withNx } = require('@nrwl/webpack') +const webpack = require('webpack') +const TerserPlugin = require("terser-webpack-plugin") +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), (config) => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + // add fallback for node modules + config.resolve.fallback = { + ...config.resolve.fallback, + "crypto": require.resolve("crypto-browserify"), + "stream": require.resolve("stream-browserify"), + "path": require.resolve("path-browserify"), + "http": require.resolve("stream-http"), + "https": require.resolve("https-browserify"), + "constants": require.resolve("constants-browserify"), + "os": false, //require.resolve("os-browserify/browser"), + "timers": false, // require.resolve("timers-browserify"), + "zlib": require.resolve("browserify-zlib"), + "fs": false, + "module": false, + "tls": false, + "net": false, + "readline": false, + "child_process": false, + "buffer": require.resolve("buffer/"), + "vm": require.resolve('vm-browserify'), + } + + + // add externals + config.externals = { + ...config.externals, + solc: 'solc', + } + + // add public path + config.output.publicPath = './' + + // add copy & provide plugin + config.plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + url: ['url', 'URL'], + process: 'process/browser', + }) + ) + + // set the define plugin to load the WALLET_CONNECT_PROJECT_ID + config.plugins.push( + new webpack.DefinePlugin({ + WALLET_CONNECT_PROJECT_ID: JSON.stringify(process.env.WALLET_CONNECT_PROJECT_ID), + }) + ) + + // souce-map loader + config.module.rules.push({ + test: /\.js$/, + use: ["source-map-loader"], + enforce: "pre" + }) + + config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings + + + // set minimizer + config.optimization.minimizer = [ + new TerserPlugin({ + parallel: true, + terserOptions: { + ecma: 2015, + compress: false, + mangle: false, + format: { + comments: false, + }, + }, + extractComments: false, + }), + new CssMinimizerPlugin(), + ]; + + config.watchOptions = { + ignored: /node_modules/ + } + + config.experiments.syncWebAssembly = true + + return config; +}); diff --git a/apps/remix-ide/project.json b/apps/remix-ide/project.json index 395b9f4a6f..67c0a39cd3 100644 --- a/apps/remix-ide/project.json +++ b/apps/remix-ide/project.json @@ -3,7 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "apps/remix-ide/src", "projectType": "application", - "implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect", "circuit-compiler"], + "implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect", "circuit-compiler", "learneth"], "targets": { "build": { "executor": "@nrwl/webpack:webpack", diff --git a/package.json b/package.json index fdef679bf4..4da8e31e82 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "start": "nx start", "serve": "nx serve remix-ide --configuration=development", "serve:hot": "nx serve remix-ide --configuration=hot", + "serve:learneth": "nx serve learneth --configuration=development", "build": "nx build", "test": "nx test", "lint": "nx lint", @@ -136,11 +137,15 @@ "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", "@ethersphere/bee-js": "^3.2.0", + "@fortawesome/fontawesome-svg-core": "^6.5.1", + "@fortawesome/free-solid-svg-icons": "^6.5.1", + "@fortawesome/react-fontawesome": "^0.2.0", "@isomorphic-git/lightning-fs": "^4.4.1", "@microlink/react-json-view": "^1.23.0", "@openzeppelin/contracts": "^5.0.0", "@openzeppelin/upgrades-core": "^1.30.0", "@openzeppelin/wizard": "0.4.0", + "@reduxjs/toolkit": "^2.0.1", "@remixproject/engine": "0.3.42", "@remixproject/engine-electron": "0.3.42", "@remixproject/engine-web": "0.3.42", @@ -214,12 +219,16 @@ "react-markdown": "^8.0.5", "react-multi-carousel": "^2.8.2", "react-router-dom": "^6.16.0", + "react-spinners": "^0.13.8", "react-tabs": "^6.0.2", + "react-toastify": "^10.0.3", "react-virtualized": "^9.22.5", "react-virtuoso": "^4.6.2", "react-window": "^1.8.10", "react-zoom-pan-pinch": "^3.1.0", + "redux-saga": "^1.3.0", "regenerator-runtime": "0.13.7", + "rehype-raw": "^6.0.0", "remark-gfm": "^3.0.1", "rlp": "^3.0.0", "rss-parser": "^3.12.0", diff --git a/yarn.lock b/yarn.lock index ce81affdb8..a43b89d12f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2954,11 +2954,37 @@ intl-messageformat "10.1.0" tslib "2.4.0" +"@fortawesome/fontawesome-common-types@6.5.1": + version "6.5.1" + resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz#fdb1ec4952b689f5f7aa0bffe46180bb35490032" + integrity sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A== + "@fortawesome/fontawesome-free@^5.8.1": version "5.15.4" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz#ecda5712b61ac852c760d8b3c79c96adca5554e5" integrity sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg== +"@fortawesome/fontawesome-svg-core@^6.5.1": + version "6.5.1" + resolved "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz#9d56d46bddad78a7ebb2043a97957039fcebcf0a" + integrity sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ== + dependencies: + "@fortawesome/fontawesome-common-types" "6.5.1" + +"@fortawesome/free-solid-svg-icons@^6.5.1": + version "6.5.1" + resolved "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz#737b8d787debe88b400ab7528f47be333031274a" + integrity sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ== + dependencies: + "@fortawesome/fontawesome-common-types" "6.5.1" + +"@fortawesome/react-fontawesome@^0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" + integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== + dependencies: + prop-types "^15.8.1" + "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" @@ -5342,6 +5368,59 @@ unbzip2-stream "1.4.3" yargs "17.7.1" +"@redux-saga/core@^1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@redux-saga/core/-/core-1.3.0.tgz#2ce08b73d407fc6ea9e7f7d83d2e97d981a3a8b8" + integrity sha512-L+i+qIGuyWn7CIg7k1MteHGfttKPmxwZR5E7OsGikCL2LzYA0RERlaUY00Y3P3ZV2EYgrsYlBrGs6cJP5OKKqA== + dependencies: + "@babel/runtime" "^7.6.3" + "@redux-saga/deferred" "^1.2.1" + "@redux-saga/delay-p" "^1.2.1" + "@redux-saga/is" "^1.1.3" + "@redux-saga/symbols" "^1.1.3" + "@redux-saga/types" "^1.2.1" + typescript-tuple "^2.2.1" + +"@redux-saga/deferred@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz#aca373a08ccafd6f3481037f2f7ee97f2c87c3ec" + integrity sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g== + +"@redux-saga/delay-p@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz#e72ac4731c5080a21f75b61bedc31cb639d9e446" + integrity sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w== + dependencies: + "@redux-saga/symbols" "^1.1.3" + +"@redux-saga/is@^1.1.3": + version "1.1.3" + resolved "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz#b333f31967e87e32b4e6b02c75b78d609dd4ad73" + integrity sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q== + dependencies: + "@redux-saga/symbols" "^1.1.3" + "@redux-saga/types" "^1.2.1" + +"@redux-saga/symbols@^1.1.3": + version "1.1.3" + resolved "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz#b731d56201719e96dc887dc3ae9016e761654367" + integrity sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg== + +"@redux-saga/types@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz#9403f51c17cae37edf870c6bc0c81c1ece5ccef8" + integrity sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA== + +"@reduxjs/toolkit@^2.0.1": + version "2.0.1" + resolved "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz#0a5233c1e35c1941b03aece39cceade3467a1062" + integrity sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA== + dependencies: + immer "^10.0.3" + redux "^5.0.0" + redux-thunk "^3.1.0" + reselect "^5.0.1" + "@remix-run/router@1.14.0": version "1.14.0" resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.14.0.tgz#9bc39a5a3a71b81bdb310eba6def5bc3966695b7" @@ -6411,6 +6490,11 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/parse5@^6.0.0": + version "6.0.3" + resolved "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb" + integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g== + "@types/pbkdf2@^3.0.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" @@ -6914,7 +6998,6 @@ version "2.11.1" resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.11.1.tgz#6e0174ec9026940eaadeedc53417e222eb45f5aa" integrity sha512-UfQH0ho24aa2M1xYmanbJv2ggQPebKmQytp2j20QEvURJ2R0v7YKWZ+0PfwOs6o6cuGw6gGxy/0WQXQRZSAsfg== - dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "^1.0.13" "@walletconnect/jsonrpc-types" "^1.0.3" @@ -10790,6 +10873,11 @@ clsx@^2.0.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== +clsx@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" + integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== + cluster-key-slot@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" @@ -16120,11 +16208,71 @@ hasha@^3.0.0: dependencies: is-stream "^1.0.1" +hast-util-from-parse5@^7.0.0: + version "7.1.2" + resolved "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz#aecfef73e3ceafdfa4550716443e4eb7b02e22b0" + integrity sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw== + dependencies: + "@types/hast" "^2.0.0" + "@types/unist" "^2.0.0" + hastscript "^7.0.0" + property-information "^6.0.0" + vfile "^5.0.0" + vfile-location "^4.0.0" + web-namespaces "^2.0.0" + +hast-util-parse-selector@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz#25ab00ae9e75cbc62cf7a901f68a247eade659e2" + integrity sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA== + dependencies: + "@types/hast" "^2.0.0" + +hast-util-raw@^7.2.0: + version "7.2.3" + resolved "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz#dcb5b22a22073436dbdc4aa09660a644f4991d99" + integrity sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg== + dependencies: + "@types/hast" "^2.0.0" + "@types/parse5" "^6.0.0" + hast-util-from-parse5 "^7.0.0" + hast-util-to-parse5 "^7.0.0" + html-void-elements "^2.0.0" + parse5 "^6.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + vfile "^5.0.0" + web-namespaces "^2.0.0" + zwitch "^2.0.0" + +hast-util-to-parse5@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz#c49391bf8f151973e0c9adcd116b561e8daf29f3" + integrity sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^2.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + web-namespaces "^2.0.0" + zwitch "^2.0.0" + hast-util-whitespace@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== +hastscript@^7.0.0: + version "7.2.0" + resolved "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz#0eafb7afb153d047077fa2a833dc9b7ec604d10b" + integrity sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^2.0.0" + hast-util-parse-selector "^3.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -16248,6 +16396,11 @@ html-react-parser@^3.0.4: react-property "2.0.0" style-to-js "1.1.1" +html-void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" + integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A== + html2canvas@^1.0.0-rc.5: version "1.4.1" resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543" @@ -16571,6 +16724,11 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= +immer@^10.0.3: + version "10.0.3" + resolved "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz#a8de42065e964aa3edf6afc282dfc7f7f34ae3c9" + integrity sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A== + immutable@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" @@ -23072,6 +23230,11 @@ parse5@4.0.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== +parse5@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + parse5@^7.0.0: version "7.1.2" resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" @@ -23837,7 +24000,6 @@ preact@^10.16.0: version "10.19.3" resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.3.tgz#7a7107ed2598a60676c943709ea3efb8aaafa899" integrity sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ== - prebuild-install@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" @@ -24624,6 +24786,11 @@ react-router@6.21.0: dependencies: "@remix-run/router" "1.14.0" +react-spinners@^0.13.8: + version "0.13.8" + resolved "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz#5262571be0f745d86bbd49a1e6b49f9f9cb19acc" + integrity sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA== + react-tabs@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-6.0.2.tgz#bc1065c3828561fee285a8fd045f22e0fcdde1eb" @@ -24641,6 +24808,13 @@ react-textarea-autosize@~8.3.2: use-composed-ref "^1.3.0" use-latest "^1.2.1" +react-toastify@^10.0.3: + version "10.0.3" + resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.3.tgz#1b948fabf63393464eb2f82119485de58b9a9b2f" + integrity sha512-PBJwXjFKKM73tgb6iSld4GMs9ShBWGUvc9zPHmdDgT4CdSr32iqSNh6y/fFN/tosvkTS6/tBLptDxXiXgcjvuw== + dependencies: + clsx "^2.1.0" + react-transition-group@^4.4.1: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" @@ -25015,6 +25189,18 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" +redux-saga@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/redux-saga/-/redux-saga-1.3.0.tgz#a59ada7c28010189355356b99738c9fcb7ade30e" + integrity sha512-J9RvCeAZXSTAibFY0kGw6Iy4EdyDNW7k6Q+liwX+bsck7QVsU78zz8vpBRweEfANxnnlG/xGGeOvf6r8UXzNJQ== + dependencies: + "@redux-saga/core" "^1.3.0" + +redux-thunk@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3" + integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw== + redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" @@ -25034,6 +25220,11 @@ redux@^4.0.0, redux@^4.0.4: dependencies: "@babel/runtime" "^7.9.2" +redux@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== + regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -25232,6 +25423,15 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" +rehype-raw@^6.0.0: + version "6.1.1" + resolved "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz#81bbef3793bd7abacc6bf8335879d1b6c868c9d4" + integrity sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ== + dependencies: + "@types/hast" "^2.0.0" + hast-util-raw "^7.2.0" + unified "^10.0.0" + release-zalgo@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" @@ -25405,6 +25605,11 @@ reselect@^4.0.0: resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A== +reselect@^5.0.1: + version "5.1.0" + resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz#c479139ab9dd91be4d9c764a7f3868210ef8cd21" + integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg== + reset@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/reset/-/reset-0.1.0.tgz#9fc7314171995ae6cb0b7e58b06ce7522af4bafb" @@ -28407,6 +28612,25 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript-compare@^0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz#7ee40a400a406c2ea0a7e551efd3309021d5f425" + integrity sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA== + dependencies: + typescript-logic "^0.0.0" + +typescript-logic@^0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz#66ebd82a2548f2b444a43667bec120b496890196" + integrity sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q== + +typescript-tuple@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz#7d9813fb4b355f69ac55032e0363e8bb0f04dad2" + integrity sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q== + dependencies: + typescript-compare "^0.0.2" + typescript@^4.8.4: version "4.8.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" @@ -29157,6 +29381,14 @@ verror@1.3.6: dependencies: extsprintf "1.0.2" +vfile-location@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz#69df82fb9ef0a38d0d02b90dd84620e120050dd0" + integrity sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw== + dependencies: + "@types/unist" "^2.0.0" + vfile "^5.0.0" + vfile-message@^3.0.0: version "3.1.4" resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.4.tgz#15a50816ae7d7c2d1fa87090a7f9f96612b59dea" @@ -29340,6 +29572,11 @@ web-encoding@^1.0.2, web-encoding@^1.0.6: optionalDependencies: "@zxing/text-encoding" "0.9.0" +web-namespaces@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" + integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== + web-streams-polyfill@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965" From 020f0bcb16f404e64598ea0f48ac4ad069f68216 Mon Sep 17 00:00:00 2001 From: drafish Date: Wed, 17 Jan 2024 17:20:18 +0800 Subject: [PATCH 13/26] add npm scripts -- serve:plugin, build:plugin --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4da8e31e82..ddd68c6a00 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "start": "nx start", "serve": "nx serve remix-ide --configuration=development", "serve:hot": "nx serve remix-ide --configuration=hot", - "serve:learneth": "nx serve learneth --configuration=development", + "serve:plugin": "nx serve ${npm_config_plugin} --configuration=development", + "build:plugin": "NODE_ENV=production nx build ${npm_config_plugin} --configuration=production --skip-nx-cache", "build": "nx build", "test": "nx test", "lint": "nx lint", From 63cd218ff184d22b31abc89530f242a2ea30f8c4 Mon Sep 17 00:00:00 2001 From: drafish Date: Wed, 17 Jan 2024 17:20:47 +0800 Subject: [PATCH 14/26] update port for serve:learneth --- apps/learneth/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/learneth/project.json b/apps/learneth/project.json index 4dfbec33e1..e9cbc7582f 100644 --- a/apps/learneth/project.json +++ b/apps/learneth/project.json @@ -46,7 +46,7 @@ "configurations": { "development": { "buildTarget": "learneth:build:development", - "port": 2023 + "port": 2024 }, "production": { "buildTarget": "learneth:build:production" From 448540d24e4ed15ec786652f0cf4e83cdfde2475 Mon Sep 17 00:00:00 2001 From: drafish Date: Wed, 17 Jan 2024 17:21:04 +0800 Subject: [PATCH 15/26] update learneth profile.json --- apps/learneth/src/profile.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/learneth/src/profile.json b/apps/learneth/src/profile.json index 8f381750ef..9df7968088 100644 --- a/apps/learneth/src/profile.json +++ b/apps/learneth/src/profile.json @@ -9,9 +9,9 @@ "addRepository" ], "kind": "none", - "icon": "/plugins/learneth/assets/Font_Awesome_5_solid_book-reader.svg", + "icon": "plugins/learneth/assets/Font_Awesome_5_solid_book-reader.svg", "location": "sidePanel", - "url": "/plugins/learneth", + "url": "plugins/learneth/index.html", "repo": "https://github.com/ethereum/remix-project/tree/master/apps/learneth", "maintainedBy": "Remix", "authorContact": "", From b7f7e1993a7cc4d8c2047ef58caa83d5fed10ac1 Mon Sep 17 00:00:00 2001 From: drafish Date: Wed, 17 Jan 2024 17:21:45 +0800 Subject: [PATCH 16/26] add learneth to loadLocalPlugins --- apps/remix-ide/src/remixAppManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 8fa3fb15dd..c642e44e3c 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -89,7 +89,7 @@ let requiredModules = [ // services + layout views + system views // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] -const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler'] +const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler', 'learneth'] const sensitiveCalls = { fileManager: ['writeFile', 'copyFile', 'rename', 'copyDir'], From e4543a88fb95134a98dde7fabbe4ca340ceb2388 Mon Sep 17 00:00:00 2001 From: drafish Date: Wed, 17 Jan 2024 17:22:10 +0800 Subject: [PATCH 17/26] use hash router --- apps/learneth/src/App.tsx | 40 +++---- .../src/components/BackButton/index.tsx | 3 +- apps/learneth/src/pages/StepDetail/index.tsx | 104 ++++++++---------- apps/learneth/src/pages/StepList/index.tsx | 33 +++--- 4 files changed, 75 insertions(+), 105 deletions(-) diff --git a/apps/learneth/src/App.tsx b/apps/learneth/src/App.tsx index 8582be5a75..e61fbf7b74 100644 --- a/apps/learneth/src/App.tsx +++ b/apps/learneth/src/App.tsx @@ -1,15 +1,15 @@ -import React from 'react'; -import { createBrowserRouter, RouterProvider } from 'react-router-dom'; -import { ToastContainer } from 'react-toastify'; -import LoadingScreen from './components/LoadingScreen'; -import LogoPage from './pages/Logo'; -import HomePage from './pages/Home'; -import StepListPage from './pages/StepList'; -import StepDetailPage from './pages/StepDetail'; -import 'react-toastify/dist/ReactToastify.css'; -import './App.css'; +import React from 'react' +import {createHashRouter, RouterProvider} from 'react-router-dom' +import {ToastContainer} from 'react-toastify' +import LoadingScreen from './components/LoadingScreen' +import LogoPage from './pages/Logo' +import HomePage from './pages/Home' +import StepListPage from './pages/StepList' +import StepDetailPage from './pages/StepDetail' +import 'react-toastify/dist/ReactToastify.css' +import './App.css' -export const router = createBrowserRouter([ +export const router = createHashRouter([ { path: '/', element: , @@ -26,26 +26,16 @@ export const router = createBrowserRouter([ path: '/detail', element: , }, -]); +]) function App(): JSX.Element { return ( <> - + - ); + ) } -export default App; +export default App diff --git a/apps/learneth/src/components/BackButton/index.tsx b/apps/learneth/src/components/BackButton/index.tsx index 22a2fbfff4..cb476cd826 100644 --- a/apps/learneth/src/components/BackButton/index.tsx +++ b/apps/learneth/src/components/BackButton/index.tsx @@ -1,5 +1,5 @@ import React, {useState} from 'react' -import {Link, useNavigate} from 'react-router-dom' +import {Link, useLocation, useNavigate} from 'react-router-dom' import {Button, Modal, Tooltip, OverlayTrigger} from 'react-bootstrap' import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' import {faHome, faBars, faChevronLeft, faChevronRight} from '@fortawesome/free-solid-svg-icons' @@ -8,6 +8,7 @@ import './index.scss' function BackButton({entity}: any) { const navigate = useNavigate() + const location = useLocation() const [show, setShow] = useState(false) // const theme = useAppSelector((state) => state.remixide.theme) const isDetailPage = location.pathname === '/detail' diff --git a/apps/learneth/src/pages/StepDetail/index.tsx b/apps/learneth/src/pages/StepDetail/index.tsx index 38ec41cec7..2df3b9efe6 100644 --- a/apps/learneth/src/pages/StepDetail/index.tsx +++ b/apps/learneth/src/pages/StepDetail/index.tsx @@ -1,43 +1,44 @@ -import React, { useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; -import Markdown from 'react-markdown'; -import rehypeRaw from 'rehype-raw'; -import BackButton from '../../components/BackButton'; -import { useAppSelector, useAppDispatch } from '../../redux/hooks'; -import './index.scss'; +import React, {useEffect} from 'react' +import {useLocation, useNavigate} from 'react-router-dom' +import Markdown from 'react-markdown' +import rehypeRaw from 'rehype-raw' +import BackButton from '../../components/BackButton' +import {useAppSelector, useAppDispatch} from '../../redux/hooks' +import './index.scss' function StepDetailPage() { - const navigate = useNavigate(); - const dispatch = useAppDispatch(); - const queryParams = new URLSearchParams(location.search); - const id = queryParams.get('id') as string; - const stepId = Number(queryParams.get('stepId')); + const navigate = useNavigate() + const location = useLocation() + const dispatch = useAppDispatch() + const queryParams = new URLSearchParams(location.search) + const id = queryParams.get('id') as string + const stepId = Number(queryParams.get('stepId')) const { - workshop: { detail, selectedId }, - remixide: { errorLoadingFile, errors, success }, - } = useAppSelector((state: any) => state); - const entity = detail[selectedId].entities[id]; - const steps = entity.steps; - const step = steps[stepId]; - console.log(step); + workshop: {detail, selectedId}, + remixide: {errorLoadingFile, errors, success}, + } = useAppSelector((state: any) => state) + const entity = detail[selectedId].entities[id] + const steps = entity.steps + const step = steps[stepId] + console.log(step) useEffect(() => { dispatch({ type: 'remixide/displayFile', payload: step, - }); + }) dispatch({ type: 'remixide/save', - payload: { errors: [], success: false }, - }); - window.scrollTo(0, 0); - }, [step]); + payload: {errors: [], success: false}, + }) + window.scrollTo(0, 0) + }, [step]) useEffect(() => { if (errors.length > 0 || success) { - window.scrollTo(0, document.documentElement.scrollHeight); + window.scrollTo(0, document.documentElement.scrollHeight) } - }, [errors, success]); + }, [errors, success]) return ( <> @@ -57,7 +58,7 @@ function StepDetailPage() { dispatch({ type: 'remixide/displayFile', payload: step, - }); + }) }} > Load the file @@ -71,9 +72,7 @@ function StepDetailPage() { )}
- - {step.markdown?.content} - + {step.markdown?.content}
{step.test?.content ? ( <> @@ -85,7 +84,7 @@ function StepDetailPage() { dispatch({ type: 'remixide/displayFile', payload: step, - }); + }) }} > Load the file @@ -100,7 +99,7 @@ function StepDetailPage() { dispatch({ type: 'remixide/testStep', payload: step, - }); + }) }} > Check Answer @@ -112,7 +111,7 @@ function StepDetailPage() { dispatch({ type: 'remixide/showAnswer', payload: step, - }); + }) }} > Show answer @@ -126,11 +125,7 @@ function StepDetailPage() { - + how to setup your repo @@ -159,7 +116,7 @@ function RepoImporter({ list, selectedRepo }: any): JSX.Element {
- ); + ) } -export default RepoImporter; +export default RepoImporter diff --git a/apps/learneth/src/components/SlideIn/index.tsx b/apps/learneth/src/components/SlideIn/index.tsx index c4830b6688..4b034183c3 100644 --- a/apps/learneth/src/components/SlideIn/index.tsx +++ b/apps/learneth/src/components/SlideIn/index.tsx @@ -1,18 +1,18 @@ -import React, { type ReactNode, useEffect, useState } from 'react'; -import { CSSTransition } from 'react-transition-group'; -import './index.css'; +import React, {type ReactNode, useEffect, useState} from 'react' +import {CSSTransition} from 'react-transition-group' +import './index.css' -const SlideIn: React.FC<{ children: ReactNode }> = ({ children }) => { - const [show, setShow] = useState(false); +const SlideIn: React.FC<{children: ReactNode}> = ({children}) => { + const [show, setShow] = useState(false) useEffect(() => { - setShow(true); - }, []); + setShow(true) + }, []) return ( {children} - ); -}; + ) +} -export default SlideIn; +export default SlideIn diff --git a/apps/learneth/src/main.tsx b/apps/learneth/src/main.tsx index eac81ff2eb..f710e14a4d 100644 --- a/apps/learneth/src/main.tsx +++ b/apps/learneth/src/main.tsx @@ -1,15 +1,13 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import { Provider } from 'react-redux'; -import './index.css'; -import App from './App'; -import { store } from './redux/store'; +import React from 'react' +import ReactDOM from 'react-dom/client' +import {Provider} from 'react-redux' +import './index.css' +import App from './App' +import {store} from './redux/store' -const root = ReactDOM.createRoot( - document.getElementById('root') as HTMLElement, -); +const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement) root.render( - , -); + +) diff --git a/apps/learneth/src/pages/Home/index.tsx b/apps/learneth/src/pages/Home/index.tsx index 73ddb3e024..0823668695 100644 --- a/apps/learneth/src/pages/Home/index.tsx +++ b/apps/learneth/src/pages/Home/index.tsx @@ -1,48 +1,38 @@ -import React, { useEffect } from 'react'; -import { Link } from 'react-router-dom'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { - faChevronRight, - faChevronDown, - faPlayCircle, -} from '@fortawesome/free-solid-svg-icons'; -import Markdown from 'react-markdown'; -import rehypeRaw from 'rehype-raw'; -import remarkGfm from 'remark-gfm'; -import { useAppDispatch, useAppSelector } from '../../redux/hooks'; -import RepoImporter from '../../components/RepoImporter'; -import './index.css'; +import React, {useEffect} from 'react' +import {Link} from 'react-router-dom' +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' +import {faChevronRight, faChevronDown, faPlayCircle} from '@fortawesome/free-solid-svg-icons' +import Markdown from 'react-markdown' +import rehypeRaw from 'rehype-raw' +import remarkGfm from 'remark-gfm' +import {useAppDispatch, useAppSelector} from '../../redux/hooks' +import RepoImporter from '../../components/RepoImporter' +import './index.css' function HomePage(): JSX.Element { - const [openKeys, setOpenKeys] = React.useState([]); + const [openKeys, setOpenKeys] = React.useState([]) - const isOpen = (key: string) => openKeys.includes(key); + const isOpen = (key: string) => openKeys.includes(key) const handleClick = (key: string) => { - setOpenKeys( - isOpen(key) - ? openKeys.filter((item) => item !== key) - : [...openKeys, key], - ); - }; + setOpenKeys(isOpen(key) ? openKeys.filter((item) => item !== key) : [...openKeys, key]) + } - const dispatch = useAppDispatch(); - const { list, detail, selectedId } = useAppSelector( - (state) => state.workshop, - ); + const dispatch = useAppDispatch() + const {list, detail, selectedId} = useAppSelector((state) => state.workshop) - const selectedRepo = detail[selectedId]; + const selectedRepo = detail[selectedId] const levelMap: any = { 1: 'Beginner', 2: 'Intermediate', 3: 'Advanced', - }; + } useEffect(() => { dispatch({ type: 'workshop/init', - }); - }, []); + }) + }, []) return (
@@ -59,63 +49,37 @@ function HomePage(): JSX.Element { href="#" className="arrow-icon" onClick={() => { - handleClick(item.id); + handleClick(item.id) }} > - + { - handleClick(item.id); + handleClick(item.id) }} > {selectedRepo.entities[item.id].name} - +
-
- {levelMap[level] && ( -

- {levelMap[level]} -

- )} +
+ {levelMap[level] &&

{levelMap[level]}

} - {selectedRepo.entities[item.id].metadata.data.tags?.map( - (tag: string) => ( -

- {tag} -

- ), - )} + {selectedRepo.entities[item.id].metadata.data.tags?.map((tag: string) => ( +

+ {tag} +

+ ))} - {selectedRepo.entities[item.id].steps && ( -
- {selectedRepo.entities[item.id].steps.length} step(s) -
- )} + {selectedRepo.entities[item.id].steps &&
{selectedRepo.entities[item.id].steps.length} step(s)
}
- + {selectedRepo.entities[item.id].description?.content}
@@ -130,7 +94,7 @@ function HomePage(): JSX.Element {
)}
- ); + ) } -export default HomePage; +export default HomePage diff --git a/apps/learneth/src/pages/StepDetail/index.scss b/apps/learneth/src/pages/StepDetail/index.scss index e135826c8f..5b59a87727 100644 --- a/apps/learneth/src/pages/StepDetail/index.scss +++ b/apps/learneth/src/pages/StepDetail/index.scss @@ -13,11 +13,6 @@ header, footer { align-items: center; } -.menuspacer{ - // padding-top: 48px; - -} - .errorloadingspacer{ padding-top: 44px; diff --git a/apps/learneth/src/pages/StepList/index.scss b/apps/learneth/src/pages/StepList/index.scss index fcccaf4142..eb56db2b90 100644 --- a/apps/learneth/src/pages/StepList/index.scss +++ b/apps/learneth/src/pages/StepList/index.scss @@ -11,7 +11,6 @@ header { .menuspacer{ margin-top: 52px; - } .steplink { @@ -32,13 +31,6 @@ section { display: flex; flex-direction: column; align-items: center; - - - - - - - .start { padding: 5px 25px; animation: jittery 2s 0.5s infinite; diff --git a/apps/learneth/src/redux/hooks.ts b/apps/learneth/src/redux/hooks.ts index c786a3e7ea..256734f44f 100644 --- a/apps/learneth/src/redux/hooks.ts +++ b/apps/learneth/src/redux/hooks.ts @@ -1,5 +1,5 @@ -import { useDispatch, type TypedUseSelectorHook, useSelector } from 'react-redux'; -import { type AppDispatch, type RootState } from './store'; +import {useDispatch, type TypedUseSelectorHook, useSelector} from 'react-redux' +import {type AppDispatch, type RootState} from './store' -export const useAppDispatch: () => AppDispatch = useDispatch; -export const useAppSelector: TypedUseSelectorHook = useSelector; +export const useAppDispatch: () => AppDispatch = useDispatch +export const useAppSelector: TypedUseSelectorHook = useSelector diff --git a/apps/learneth/src/redux/models/loading.ts b/apps/learneth/src/redux/models/loading.ts index d553dcce8a..38e09ef7c2 100644 --- a/apps/learneth/src/redux/models/loading.ts +++ b/apps/learneth/src/redux/models/loading.ts @@ -1,14 +1,14 @@ -import { type ModelType } from '../store'; +import {type ModelType} from '../store' const Model: ModelType = { namespace: 'loading', - state: { screen: true }, + state: {screen: true}, reducers: { - save(state, { payload }) { - return { ...state, ...payload }; + save(state, {payload}) { + return {...state, ...payload} }, }, effects: {}, -}; +} -export default Model; +export default Model diff --git a/apps/learneth/src/redux/models/workshop.ts b/apps/learneth/src/redux/models/workshop.ts index eadd44e5e5..daf41b5ff9 100644 --- a/apps/learneth/src/redux/models/workshop.ts +++ b/apps/learneth/src/redux/models/workshop.ts @@ -1,13 +1,13 @@ -import axios from 'axios'; -import { toast } from 'react-toastify'; -import groupBy from 'lodash/groupBy'; -import pick from 'lodash/pick'; -import { type ModelType } from '../store'; -import remixClient from '../../remix-client'; -import { router } from '../../App'; +import axios from 'axios' +import {toast} from 'react-toastify' +import groupBy from 'lodash/groupBy' +import pick from 'lodash/pick' +import {type ModelType} from '../store' +import remixClient from '../../remix-client' +import {router} from '../../App' // const apiUrl = 'http://localhost:3001'; -const apiUrl = 'https://static.220.14.12.49.clients.your-server.de:3000'; +const apiUrl = 'https://static.220.14.12.49.clients.your-server.de:3000' const Model: ModelType = { namespace: 'workshop', @@ -17,20 +17,20 @@ const Model: ModelType = { selectedId: '', }, reducers: { - save(state, { payload }) { - return { ...state, ...payload }; + save(state, {payload}) { + return {...state, ...payload} }, }, effects: { - *init(_, { put }) { - const cache = localStorage.getItem('workshop.state'); + *init(_, {put}) { + const cache = localStorage.getItem('workshop.state') if (cache) { - const workshopState = JSON.parse(cache); + const workshopState = JSON.parse(cache) yield put({ type: 'workshop/save', payload: workshopState, - }); + }) } else { yield put({ type: 'workshop/loadRepo', @@ -38,80 +38,67 @@ const Model: ModelType = { name: 'ethereum/remix-workshops', branch: 'master', }, - }); + }) } }, - *loadRepo({ payload }, { put, select }) { - toast.info(`loading ${payload.name}/${payload.branch}`); + *loadRepo({payload}, {put, select}) { + toast.info(`loading ${payload.name}/${payload.branch}`) yield put({ type: 'loading/save', payload: { screen: true, }, - }); + }) - const { list, detail } = yield select((state) => state.workshop); + const {list, detail} = yield select((state) => state.workshop) - const url = `${apiUrl}/clone/${encodeURIComponent(payload.name)}/${ - payload.branch - }?${Math.random()}`; - console.log('loading ', url); - const { data } = yield axios.get(url); - console.log(data); - const repoId = `${payload.name}-${payload.branch}`; + const url = `${apiUrl}/clone/${encodeURIComponent(payload.name)}/${payload.branch}?${Math.random()}` + console.log('loading ', url) + const {data} = yield axios.get(url) + console.log(data) + const repoId = `${payload.name}-${payload.branch}` for (let i = 0; i < data.ids.length; i++) { const { steps, metadata: { - data: { steps: metadataSteps }, + data: {steps: metadataSteps}, }, - } = data.entities[data.ids[i]]; + } = data.entities[data.ids[i]] - let newSteps = []; + let newSteps = [] if (metadataSteps) { newSteps = metadataSteps.map((step: any) => { return { ...steps.find((item: any) => item.name === step.path), name: step.name, - }; - }); + } + }) } else { newSteps = steps.map((step: any) => ({ ...step, name: step.name.replace('_', ' '), - })); + })) } - const stepKeysWithFile = [ - 'markdown', - 'solidity', - 'test', - 'answer', - 'js', - 'vy', - ]; + const stepKeysWithFile = ['markdown', 'solidity', 'test', 'answer', 'js', 'vy'] for (let j = 0; j < newSteps.length; j++) { - const step = newSteps[j]; + const step = newSteps[j] for (let k = 0; k < stepKeysWithFile.length; k++) { - const key = stepKeysWithFile[k]; + const key = stepKeysWithFile[k] if (step[key]) { try { - step[key].content = (yield remixClient.call( - 'contentImport', - 'resolve', - step[key].file, - )).content; + step[key].content = (yield remixClient.call('contentImport', 'resolve', step[key].file)).content } catch (error) { - console.error(error); + console.error(error) } } } } - data.entities[data.ids[i]].steps = newSteps; + data.entities[data.ids[i]].steps = newSteps } const workshopState = { @@ -120,44 +107,42 @@ const Model: ModelType = { [repoId]: { ...data, group: groupBy( - data.ids.map((id: string) => - pick(data.entities[id], ['level', 'id']), - ), - (item: any) => item.level, + data.ids.map((id: string) => pick(data.entities[id], ['level', 'id'])), + (item: any) => item.level ), ...payload, }, }, list: detail[repoId] ? list : [...list, payload], selectedId: repoId, - }; + } yield put({ type: 'workshop/save', payload: workshopState, - }); - localStorage.setItem('workshop.state', JSON.stringify(workshopState)); + }) + localStorage.setItem('workshop.state', JSON.stringify(workshopState)) - toast.dismiss(); + toast.dismiss() yield put({ type: 'loading/save', payload: { screen: false, }, - }); + }) if (payload.id) { - const { detail, selectedId } = workshopState; - const { ids, entities } = detail[selectedId]; + const {detail, selectedId} = workshopState + const {ids, entities} = detail[selectedId] for (let i = 0; i < ids.length; i++) { - const entity = entities[ids[i]]; + const entity = entities[ids[i]] if (entity.metadata.data.id === payload.id || i + 1 === payload.id) { - yield router.navigate(`/list?id=${ids[i]}`); - break; + yield router.navigate(`/list?id=${ids[i]}`) + break } } } }, - *resetAll(_, { put }) { + *resetAll(_, {put}) { yield put({ type: 'workshop/save', payload: { @@ -165,15 +150,15 @@ const Model: ModelType = { detail: {}, selectedId: '', }, - }); + }) - localStorage.removeItem('workshop.state'); + localStorage.removeItem('workshop.state') yield put({ type: 'workshop/init', - }); + }) }, }, -}; +} -export default Model; +export default Model diff --git a/apps/learneth/src/redux/store.ts b/apps/learneth/src/redux/store.ts index 5bd2929a61..5092828cc6 100644 --- a/apps/learneth/src/redux/store.ts +++ b/apps/learneth/src/redux/store.ts @@ -1,117 +1,97 @@ -import { - configureStore, - createSlice, - type PayloadAction, - type Reducer, -} from '@reduxjs/toolkit'; -import createSagaMiddleware from 'redux-saga'; -import { - call, - put, - takeEvery, - delay, - select, - all, - fork, - type ForkEffect, -} from 'redux-saga/effects'; +import {configureStore, createSlice, type PayloadAction, type Reducer} from '@reduxjs/toolkit' +import createSagaMiddleware from 'redux-saga' +import {call, put, takeEvery, delay, select, all, fork, type ForkEffect} from 'redux-saga/effects' // @ts-expect-error -const context = require.context('./models', false, /\.ts$/); -const models = context.keys().map((key: any) => context(key).default); +const context = require.context('./models', false, /\.ts$/) +const models = context.keys().map((key: any) => context(key).default) -export type StateType = Record; +export type StateType = Record export interface ModelType { - namespace: string; - state: StateType; - reducers: Record< - string, - (state: StateType, action: PayloadAction) => StateType - >; + namespace: string + state: StateType + reducers: Record) => StateType> effects: Record< string, ( action: PayloadAction, effects: { - call: typeof call; - put: typeof put; - delay: typeof delay; - select: typeof select; - }, + call: typeof call + put: typeof put + delay: typeof delay + select: typeof select + } ) => Generator - >; + > } function createReducer(model: ModelType): Reducer { - const reducers = model.reducers; + const reducers = model.reducers Object.keys(model.effects).forEach((key) => { - reducers[key] = (state: StateType, action: PayloadAction) => state; - }); + reducers[key] = (state: StateType, action: PayloadAction) => state + }) const slice = createSlice({ name: model.namespace, initialState: model.state, reducers, - }); - return slice.reducer; + }) + return slice.reducer } const rootReducer = models.reduce((prev: any, model: ModelType) => { - return { ...prev, [model.namespace]: createReducer(model) }; -}, {}); + return {...prev, [model.namespace]: createReducer(model)} +}, {}) function watchEffects(model: ModelType): ForkEffect { return fork(function* () { for (const key in model.effects) { - const effect = model.effects[key]; - yield takeEvery( - `${model.namespace}/${key}`, - function* (action: PayloadAction) { - yield put({ - type: 'loading/save', - payload: { - [`${model.namespace}/${key}`]: true, - }, - }); - yield effect(action, { - call, - put, - delay, - select, - }); - yield put({ - type: 'loading/save', - payload: { - [`${model.namespace}/${key}`]: false, - }, - }); - }, - ); + const effect = model.effects[key] + yield takeEvery(`${model.namespace}/${key}`, function* (action: PayloadAction) { + yield put({ + type: 'loading/save', + payload: { + [`${model.namespace}/${key}`]: true, + }, + }) + yield effect(action, { + call, + put, + delay, + select, + }) + yield put({ + type: 'loading/save', + payload: { + [`${model.namespace}/${key}`]: false, + }, + }) + }) } - }); + }) } function* rootSaga(): Generator { - yield all(models.map((model: ModelType) => watchEffects(model))); + yield all(models.map((model: ModelType) => watchEffects(model))) } const configureAppStore = (initialState = {}) => { - const reduxSagaMonitorOptions = {}; - const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions); + const reduxSagaMonitorOptions = {} + const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions) - const middleware = [sagaMiddleware]; + const middleware = [sagaMiddleware] const store = configureStore({ reducer: rootReducer, middleware: (gDM) => gDM().concat([...middleware]), preloadedState: initialState, devTools: process.env.NODE_ENV !== 'production', - }); + }) - sagaMiddleware.run(rootSaga); - return store; -}; + sagaMiddleware.run(rootSaga) + return store +} -export const store = configureAppStore(); +export const store = configureAppStore() -export type AppDispatch = typeof store.dispatch; -export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch +export type RootState = ReturnType diff --git a/apps/learneth/src/remix-client.ts b/apps/learneth/src/remix-client.ts index fe25ef028a..4d4ab9844f 100644 --- a/apps/learneth/src/remix-client.ts +++ b/apps/learneth/src/remix-client.ts @@ -1,17 +1,17 @@ -import { PluginClient } from '@remixproject/plugin'; -import { createClient } from '@remixproject/plugin-webview'; -import { store } from './redux/store'; -import { router } from './App'; +import {PluginClient} from '@remixproject/plugin' +import {createClient} from '@remixproject/plugin-webview' +import {store} from './redux/store' +import {router} from './App' class RemixClient extends PluginClient { constructor() { - super(); - createClient(this); + super() + createClient(this) } startTutorial(name: any, branch: any, id: any): void { - console.log('start tutorial', name, branch, id); - void router.navigate('/home'); + console.log('start tutorial', name, branch, id) + void router.navigate('/home') store.dispatch({ type: 'workshop/loadRepo', payload: { @@ -19,20 +19,20 @@ class RemixClient extends PluginClient { branch, id, }, - }); + }) } addRepository(name: any, branch: any) { - console.log('add repo', name, branch); - void router.navigate('/home'); + console.log('add repo', name, branch) + void router.navigate('/home') store.dispatch({ type: 'workshop/loadRepo', payload: { name, branch, }, - }); + }) } } -export default new RemixClient(); +export default new RemixClient() diff --git a/apps/learneth/webpack.config.js b/apps/learneth/webpack.config.js index fecff4fa70..4db6b9fc00 100644 --- a/apps/learneth/webpack.config.js +++ b/apps/learneth/webpack.config.js @@ -1,7 +1,7 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') +const {composePlugins, withNx} = require('@nrwl/webpack') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // Nx plugins for webpack. module.exports = composePlugins(withNx(), (config) => { @@ -10,25 +10,24 @@ module.exports = composePlugins(withNx(), (config) => { // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "path": require.resolve("path-browserify"), - "http": require.resolve("stream-http"), - "https": require.resolve("https-browserify"), - "constants": require.resolve("constants-browserify"), - "os": false, //require.resolve("os-browserify/browser"), - "timers": false, // require.resolve("timers-browserify"), - "zlib": require.resolve("browserify-zlib"), - "fs": false, - "module": false, - "tls": false, - "net": false, - "readline": false, - "child_process": false, - "buffer": require.resolve("buffer/"), - "vm": require.resolve('vm-browserify'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify'), } - // add externals config.externals = { @@ -58,13 +57,12 @@ module.exports = composePlugins(withNx(), (config) => { // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre', }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings - // set minimizer config.optimization.minimizer = [ new TerserPlugin({ @@ -80,13 +78,13 @@ module.exports = composePlugins(withNx(), (config) => { extractComments: false, }), new CssMinimizerPlugin(), - ]; + ] config.watchOptions = { - ignored: /node_modules/ + ignored: /node_modules/, } config.experiments.syncWebAssembly = true - return config; -}); + return config +}) From 30a806ba2a3cf7639cbfbd9c457444a1d4858196 Mon Sep 17 00:00:00 2001 From: drafish Date: Fri, 2 Feb 2024 10:49:42 +0800 Subject: [PATCH 23/26] rm learneth assets folder --- apps/learneth/project.json | 2 +- apps/learneth/src/assets/learneth.webp | Bin 10900 -> 0 bytes apps/learneth/src/assets/logo-background.svg | 1 - apps/learneth/src/pages/Logo/index.css | 5 ----- apps/learneth/src/pages/Logo/index.tsx | 6 ++---- apps/learneth/src/profile.json | 2 +- 6 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 apps/learneth/src/assets/learneth.webp delete mode 100644 apps/learneth/src/assets/logo-background.svg delete mode 100644 apps/learneth/src/pages/Logo/index.css diff --git a/apps/learneth/project.json b/apps/learneth/project.json index 275fce9825..a4db7488a7 100644 --- a/apps/learneth/project.json +++ b/apps/learneth/project.json @@ -17,7 +17,7 @@ "main": "apps/learneth/src/main.tsx", "polyfills": "apps/learneth/src/polyfills.ts", "tsConfig": "apps/learneth/tsconfig.app.json", - "assets": ["apps/learneth/src/profile.json", "apps/learneth/src/assets/learneth.webp"], + "assets": ["apps/learneth/src/profile.json"], "styles": ["apps/learneth/src/index.css"], "scripts": [], "webpackConfig": "apps/learneth/webpack.config.js" diff --git a/apps/learneth/src/assets/learneth.webp b/apps/learneth/src/assets/learneth.webp deleted file mode 100644 index 526e58bdaa46dc26865f7445e77385473c279a17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10900 zcmeIYWm6qY6Rx{(3-0dj5Zv9}-Q9KJZb8DrJ-9mrcL+{!_u#s453uvR=X~A&V1MbF zx@+pHsp+1sxvN@TPFgyi0RYgE5?9q$te9M5+2l!uHr9DK*XuUiW2Lt( zTZ1f!_r4IC^E^~eM&V7bi)3h?9?zRqT+%vI5|V`_$$d`m95&!fXE-~8z9hZ3>19&~ zW{otz@o76>y_3)qG_(6cWo`X$5(D{qMgjqsr5}^Ch}u`iTu;;D6NZgLqcR+`og-m2 z)$xcKJdbN$xCKkXec&~L;xvOqnNMF{tr-MiBoJg1T;O^C*lsSFxKCxepNxyG!jb_I@7QU6INdJaKgHwkkVnLV zyt?KYg_PGD4N$=KR_F6G!C-3%?v&W`#DTCNtz>lt_d)8u4FJ4S_Tesigyq-o`5^JS z+j|}B0Wf$UK4BpI z0Gx&ZJsy0{S_rltU`Z6ad&rGZA!OMlN&hRH{dfi#JLJXXCkE?ub;$cw51o-UHw45N z#d&5}6!^jga(#CmNcK$vdOdkbvY7HS`1Cq#Q7o6QDU1>Sa83GoX zKQr1EVfdlUN}Q-qbxv&JJR(`|%DF7+U503giVOnk5DnR2&Sj?s4BFmH(>^=d$iC$0 zs!{&BxedD8=_5L;Zy)3~Ql*G~#oYls^X zW)?@}gUJPB{R1KhNMpQ8CP>j=8Ax$(p&(Qc_MwjK+BdPi1`W@D?sd1UHywA zmEAT<7{wbM+Cve%P~#W)w*WqN8m0C4Uh|>?jF`9Ic+8E6@PAR&&2uI9;qp5VxC zd5XOvNa5eb@!2_)&fbCu?NY4Gvh+iK zXjhpfN`(tZ4dvjV_cGuU!6>@U72=H;X!6Rl{nB<7v#K$E-liDBcPIZtPbjFMjwGVz z`CP1Pd$11`j9GhKEfsTKDlQO?9*-h#Rxb5zBVy14hu(Vu!C%j;T=B$t&Ri!AG>Rl3 zDb5pz*JT@FG}T~4;n|Wor>F+MQ8BPig{DuiY5H>>?wrZpkRCNT@M8BfgJ0KtZa=_H z^^RRcu&NNbw-KI0gCIhSO;RtD1J7E`vWjEuIHq~9piL@y<~-~-QxY>00kj^)sx0;b%6OR&)(te*w9#vJW39r-j>vTcW0s*Tn3{;{;FKGN z&G=?FEs>fl2{Ik#4jtKdpQBmjiS>7xdi+U(U9v znR3&Fq{^Byqhbgd$MI6u1UQ4oFahkw;OmjSolzX$ppfA6RSWFDr;KaG;u3vHIDwC% zebj$%xL+e*_6e^Ya{i#^W4_TqglSmlnVXan9I)L#Kx)})9OO)qkB_xQN~A;O z*Tzb?htwxX6*0THP{dK~ZA;_m#rRt>B}4fCW+HHk_oMW?QovE(>2I!MYFW##Xu zv?*qHfLyyEbwkyp(t3RpHRvGS2m2@F!#;ZI-PW06jyTqnp%6pmAILCy%}@#38(d{z+im&d7>vN~h* zePmls%Hyz|XyF>uXS}#BN%mg34wDSbZgsTP_k$fkT`RyevRPUvFHfYFx+|Da+ZW~- zr%9e*y4Eu7l=q3Tn(0@EQ%w`W@ngdTPOiWNL;l_-pY{vMF-!AAKJOE4HPK*)y!QA= zhd@now8xWPDcUhfV=UqEkEU3-Yu{9|>!!=POMIIX(Tj$^%2+UXXvG#p;s83qL2V>aHy znkbLaCWy=2|58kID@U>Z@Fyk6RwqX#*EafJF(|nP$0&L4ZMk#fC;orM;@2!^(jCXy z{);pm*gj3|4}aa# zu)6|~=u^ywitBR#2l3w*~vP`;?Px{j_VcqGpk>7}{O zA18GwG~xL;i4F3D@lSO)k*QuAlDhsR_wSAi{@=shC4F=qW%&!YO9jp>0PGCDQrk^>iA8xh~Q-9*J(87N!wX)?@ zKoD8Pg@eM2SIsL(VtmK2QHve`=^l}oVGUe5Kh>alN3f#F5HzyPK{W8y|Lcf=J0Eiv zNwaW(0`yrm9N5dOmh;ryI*7uB=AuF#E4Ch{Y)j7mq>%?wT}5BJ4BH9{Kw48 zDMaco8}1(4_$bP@q*ut&#cr6OqnT^?oFb_y5|5<>nRgj%bBcJsvh^zLw@h;k3EYGb zqwWS`ibg_KPc?)wi%7$f!;sT@DoA>9f)@BIP}FivXqF_M>Vl ztK7N`DE0N&-FvoV`q-cj04xw*HXQ7n9vY7(Pp;cGHVlzr48 z<*gn5l=STswL?j%K%dRtKd?jpRp!<9^%6;q@L-cxfyZ9Lg_{vn()GKLmz6bz@-uEW z7jlA^&2wTtC}#szt1*7Yl^QNzA}C%!)bCI9mzTgYoAawbbuj zU0Nigc zzEN$GRvvV&V~bhyuitBtc`vZ>CmOIDt}U?jSl(@ZP(y3sJil2@L7#2uLEUc{^j2-< z3qtU(O$=-AX@hmyx`GSbup^!3&-@ZueMjw<7TgI%vGPbNsI`jD&l9J#PrHDRQt5we zx2ZXgWY3c^xl6Tx4K*Ne1})q9N^V{ymrqPV{-1@ z?NI;&-SCFdTSvaub^j$(w_Ndbstl29=!4sS-Gc_S&_HD?iS;uj{8#aoyChk>Wnt>@P0( z)2D7B*jRW=e}@$%){rOSorXC$jJ8*)Q7rRVpd%)i-tD3K-?z)@(MHR?Bw)XN1no>) zW%p+;-HftAqgXvK@8bwa{{d+eOtgtMDAe|OSIznIYO`=GL|M4IZ=}NfJUOH23%&>L z6&_l=Qmd?{4T*JZ@PRw<#{9||?WRVAN{bVD0ZqIekuV0;{xYT#6qNrCQua#pIAao zF8gmEkt)J|pU+}OaZAb!9!8B`*G5kwuLt6vZ-h_8-#)PFVcKyLKRrFKUV-U?!iB)^ z7bkqar%|Mw*KsDbfJ&=QLrV`IH zl)?0vO(We6ryQF_T(o_Ny=@mTS5Ovj=~*WVYw1DzB)RW#+4?^#GXG3nSt;W-t3F1GE*P#8 z0iMLEZ0kOk%UQfFYKm|FxvD|*%Q;rQ(4MO!X{U*B6mJgHYSUr2{Wj;;##wfg_;SS!}9iTPm zZTS1ZF!tM2@8c1BCn2cXqFbpH&xO!$CO6W>ML0kWvO_Ofd-Q_8&KAIT&MMS$IqD+a zy{ltOLxYA@@8bZo>Ho%Z3;V zbIsdn>-F-Exy~d|5*{hN7btXZ&KgK}t!t%4uj#Cc(3-7Eq<=6-h~PAmW| zcB<;(MDi^cP@<+SNX>RO{Apk&nyKVClWw;PEPGZSJ2~JUWYLgbZ`l`2d~KdiX;hm| zACxTAiLe@vZ^787Q2Z;JaF;TQ{%%Sq(bB5FhM%$}KHdr%uJYakr%!MRc^5^s+Yp*R zTOY5HRaftdlnO@GR8KxI+8BFGlN|mrQ=q- zf87t0lD2=5-w8DEIn_mQHG9ao>fI&DtWRJh;5bY}MKy#l#PiWWqTILd|9;cZ-+B3> z-{M#uhY(SOu{-ke*kIR;^Gfp>EM*FkjBb~$USkvLpe~JF0Wt9uy(v< z{Zu^?OTi8DtAJoTPb!N#cSpH)tlGO9PI=AwDSsrk@X`Gz`s?o6e!`dKUdRS#27&{@ zM?>bM@gwUOJACSH>czNz^JCV$gILK3 z;0y8*Af{nr;r2myeYYS#(@MOYcnIJ-4Mo9mWJB?BTw3u8c~EIV{B{FC6TLE7h;CaT zA2_>-dk_T#H%0DQkwtw5@Y|buAj5eIm9y-aApN?2K=V`qh3EIMyb5vWoz3i-hjWSI zC>X%7LQ~z|whljS)h#pj1)qLr6r}*dIuU>-?;P?wICYFNc+&Mqq1^eXWRLRUrSCi= zp4RWHc&kTQxgpo4Vo|26Ma5lWa;x*QYiGw{9YP{{@lzjpV#a1hpz|pW00xZ4s(IyBHCjZ-NRR7xK2Z>JBusxz>08{cP9pja~ zq~C#(uL@P-EuY5Ejh1s%*|4)^?6fp6{7sImqx7Mw>C2eQut4IYy4>mORKOJ$Xs1zY ztWP>5TgS!6&oaG}eq+F~3W6hmqSgH_glr`)ms2Ls@+arOxhROVIu-1nyx1*vkjr;Q zQJjas1u)yL*E(`0n?vq0A^<) z{;gp)tyM8S?)9H`k;0Cx1hu#I?6RCxTF1WCA?paaCsb49bWrVkc|`kqy2#!Mfz-MT zfxcrbrbdbHV9e~(Rbe!-8G0u=)pK*G1lvS{+^(?5@S@D}#WK*;mlT~FAREnR^L_o7 zt&O;n=w?Q$MSM!z(SyJb{2HCOlW0L)c|a0tqcI23*!y9k5b+`@u}y#<%vj)+!VhYn z-;}wW3O!~G&1MKO9|{?cd}@a zoc+*E#A78&wv29-1O>l- zn?PY(T(V370Cq{I5|1^#s+bjoUC30?M{0cwvPbvc++WT{gKf~E0h)bpq9k^c!6)yN z1+jl0;l2YxBxf}wr`OwG_*E6^R%I~(Ae=yAS>126tMCjHN^e<^fcc^s@m6`E0UA{u zl3qz100=z`TvGM#e-nDv^vv1|0G#I7)Erb2dZA~#((noi_D&MAl~n%iohjB zqkEj93dnEk$2_*qfWC9xKQ7rKx%Q*^Lpw2CaHjXy^t%z%E0zb1eE@#;Z6P1 zvYlWwV%uW7WkURNuyXkwtxy*sh}**Ght;IEheYR;5S59oo8ZnuS`7wL_lha5%nEL4 zUOs#(%KK1GdWtq;{O_j=pgngM6cMKB?|%RgUBj;896CL8LUEWnk)NfGzsQSXek9S4 zFv4uZt46y(gZpW>+IdyKm4XzarHI4{PKIfZ4)##)F0Mk|1Ae;<;9q9qse)1hNDa*% zR-mZ)Fg^F+1@d9D-B&GsA^By%FCJ=eDn0k#ugVp0m{`VLi~hJGQq8INa7r^F*MQPI z<`3>@I`21zI`i1i22a#(WK*dYa*DfHStFN(5ac1CXd45s=?ml)2FNF>So2|DJ#91H z&sb$e%eNhMq#u7{%vMW;rzI+ZLhPAg;23g*0|+Ws@C!5CPcdYnumvdZRcZ1d=?koR zY8f<0h<9wEtGtDDYM5@b&PBJrH^WQ}9P~hIg6(Mx@bQGwL@$N+xyD5D-l$Z2hV~D) zV^~99iO*P%{SZWHc^bh7xgdu7pqo4LE=d{D9P|BYmGO-2@+8s$=2W zFP;Ld5NX|WCUlAJYp@0BqusDC#UA+(Rlcj_z^E8efec}~6i(vpl#npv(d>iRZ4Ic@ z`&g6l6mqzbA`+$yQtFQ{s!Qj(Dc!UF_92}?jwQKxe(<&z>SQJ?2MtQ1cJ(K;sD4Bc ze*W*CeAlzc1)XnRj{*1v-K0hDBzU02(7N zaMz1_g{AvQXYN>9j`T0Y1QH6&%=u#~E)rANE4w3ZBH_G5tEy>}a3uf8DgmCi7CQchL5b4_nl8>;f43zbzIY1PBhd+T}(8EmCl4jM-$Qs z)24>^F@>(rs|cy!=TrXY$Jv!Fyg=%xFg$gdNiq6f~L=AS- z5en#(d}y%GJu_Qxu8PjMQWx6Xk$RXt=U9?J=CAV}qh2rZUX{BqTsQkN_ii5z_l=;6 zSRX?zYNAk-vgnW@xdS4rta;SjZ_>K3RljZ$T?3KNtd|W6f+2?|aT775xuS z*dGStG>1$I8M{4qqW+Se-kJY9;=rs^m<8!Yg4V* zQ6r8o2b~)%!S1X}$V?A0gcnI${sNaT!faQMX98c+U@9#abu?ip$J-Z{pc%cOP8GDE zPf<9UoSOZ1yYM)?H9PHhZD{eg8r7JuEgDCIxZ5FwF?$0dlITSWP!Z2W{mXb;9BZtI>2-t2e1Cks^{k? zr%X$($YLt!_O(uV^L?`F+uvDoY^7@hz`E8F*m=w^OSdAa<_&*3fq6P&H%5Bi{u^XQw4yF2EJz~E^ccBR;|KQ0soAXMk@w;eX zK>IEA71Tal>M?nZUF#~5GwC_*FWHXDAdJQsx@W!o4YTGG^z;N-@crwqU9*mpfcHc1 zlyAVDCU_ktAKAa!V8}Ki!-GGu8@N5lHE$7M)wq!=76fL#%oV0ux)1ZF`^v- z-#Bg#D8VkN|#+E z_*Gge^p3w)S`ysc`Q86u2?*3FqemLY-1vO?yEunKtd44}muIXDKUx9z&*=H)X+x>A zX4fjS(nb(gK#kkd^|xQb$a2}8xUVRJ?<88VLKIATKW~2~5rgcTSHaehds<4yf=sR? z{^;u8a5lCS$*`8jhKC@}TXD&>>~9)Q6(WX^vs)(jHm2TNiAutly?yw|lb1nU(&4!) zYv`3uO4_)X@WWq?-PrrvonTAOn7ssh9sNs7I^;=S;@^h=oa(4Kj?UWfv|rU${=?#f z_}6T`*dZFVo3T*u;wP&l&TNcUb_Cz2+q|-ikOVSBggc=tYnhcvNu6i^8Y0~Z+rX9V zaqAm>A(eA*C!iGk=RHCEoB!ED$@!_TQsFflWin@X+!mkhM;ovS3XTFiE%oS?8_X=) zF|q`ynv$kQ#7XwOV}Bmv9>W3fP~RP6hlyR^e)hr!}(bZe?p zk~Y=k`}a?L)Na(t(<{t3z0l_uJz+ zBJQkFlWMo|6a>4%fBE1l|De?Z&SLM7oy<8l4b#ywP}_D`AZKnEI69oEtesB^DJQav zV+M;#s>>~X%dLjDOWEk+ZB#q-WFO;Il-p&8D*wzTWr=V9Hl07eN5o=NEJG z40($QDsj5=l4$xo=Qr3tWWk2BCec6tCM;|U@3o(v>BP{5%&`i5ntw?Y5P}hJaLe9M zz^1MXY6OL={gV%3Y{2)+pvZ*LBfs&&UrVg8du*>gY1lQpTbz~bl0^x~3RU4Ck#+5m>5aasKLf6 z>m^V#YiLFsqr)bYHuy=W-)&Q2qx)hbN~KKji*yKxKJF|T(eGPj78MBnlQp@Zg(72; z?JOt{=vjPj(X_g=!_l_kN$_9v>fJ5*M_tIx-q;%Mq{&pQ6P6m<06XzYR+GY=5X3akdrK4 zT!VQ1$$3Xv>68Ah4F9z%XtRrFEWFXh_G_yBcY(}gY8)KrvE<1GLa}=NfX^gSt6%0V zf7_4G?80qZ-m0yla-y3#hT0C_+30k_Q|dD?;e6pIV~g%PXX}UW633!heO9SRt8jis z#1gl@Mk(r!42f8VH6HJ?(X9~yWpTQPhA^870-P;Q)`T|?m#;`jz|QYqfPHAT>$%ZS zaxoG*W>#>S3g65&z&fl+4?!pz7gXbnX*1s=kA1?D$U1dF3R4vvpgb@dL;D@o0f$y+-n<|%CxOA*f`R>&g)lU?7p?#MpT65&hXJ{;=;*4Bhr+No z)+dezkS_7$!1y8?-Ji~@gG?hmPGkG_-_y-BFz&0ue^EUMrKWmqo!gFS#4#LrN^^9* z1$n*;(Re$FV|luj!x%SrrmS9Ga#lA>5YLVvOXsnb4*$Bg)j&M*j28VKc$WD>6th3} z*zzLi))FGyiu|%>sq96Qo`aRGD5b4LXSFgC^6mMGqUvx3q-pSizo z|JTPJvvBh|p?M3GE42Me2n{xOelc#^?qg>NVY20X_)Wi1*lY(wEV$wN+<<1E$PDxB( z-%1Vk8aW}<`OlM5cuWFdlN0KYcy_j~>_wFc%ZR$hh0j7PE&n*2=2SCK;w0-I^SfdO z3gL`T35R*!X_m@}>8NZ5rd+%sCl?lT%khk+&Hb5Ome{U*A0~K4mn~b@HhLQl6WDH% zFu@gU<$6IX5#Q#P9XV3o$$W;HS~wk7U5f&>HOXRA%t#Z!2baimXaX= diff --git a/apps/learneth/src/assets/logo-background.svg b/apps/learneth/src/assets/logo-background.svg deleted file mode 100644 index cbe3eaec20..0000000000 --- a/apps/learneth/src/assets/logo-background.svg +++ /dev/null @@ -1 +0,0 @@ -remix_logo1 \ No newline at end of file diff --git a/apps/learneth/src/pages/Logo/index.css b/apps/learneth/src/pages/Logo/index.css deleted file mode 100644 index 7a827cacb8..0000000000 --- a/apps/learneth/src/pages/Logo/index.css +++ /dev/null @@ -1,5 +0,0 @@ -.remixLogo { - position: absolute; - left: 0px; - right: 0px; -} diff --git a/apps/learneth/src/pages/Logo/index.tsx b/apps/learneth/src/pages/Logo/index.tsx index 3a787d7b23..6fcb816633 100644 --- a/apps/learneth/src/pages/Logo/index.tsx +++ b/apps/learneth/src/pages/Logo/index.tsx @@ -1,7 +1,5 @@ import React, {useEffect} from 'react' import {useAppDispatch} from '../../redux/hooks' -import logo from '../../assets/logo-background.svg' -import './index.css' const LogoPage: React.FC = () => { const dispatch = useAppDispatch() @@ -12,8 +10,8 @@ const LogoPage: React.FC = () => { return (
-
- +
+
) diff --git a/apps/learneth/src/profile.json b/apps/learneth/src/profile.json index 8ecee2911d..2eade4d42d 100644 --- a/apps/learneth/src/profile.json +++ b/apps/learneth/src/profile.json @@ -9,7 +9,7 @@ "addRepository" ], "kind": "none", - "icon": "plugins/learneth/assets/learneth.webp", + "icon": "assets/img/learnEthLogo.webp", "location": "sidePanel", "url": "plugins/learneth/index.html", "repo": "https://github.com/ethereum/remix-project/tree/master/apps/learneth", From 88184e7e63baec777f9c242bf485ad64a960909f Mon Sep 17 00:00:00 2001 From: drafish Date: Tue, 13 Feb 2024 13:30:48 +0800 Subject: [PATCH 24/26] update yarn.lock --- yarn.lock | 100 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/yarn.lock b/yarn.lock index a43b89d12f..6977032bbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2956,7 +2956,7 @@ "@fortawesome/fontawesome-common-types@6.5.1": version "6.5.1" - resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz#fdb1ec4952b689f5f7aa0bffe46180bb35490032" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz#fdb1ec4952b689f5f7aa0bffe46180bb35490032" integrity sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A== "@fortawesome/fontawesome-free@^5.8.1": @@ -2966,21 +2966,21 @@ "@fortawesome/fontawesome-svg-core@^6.5.1": version "6.5.1" - resolved "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz#9d56d46bddad78a7ebb2043a97957039fcebcf0a" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz#9d56d46bddad78a7ebb2043a97957039fcebcf0a" integrity sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ== dependencies: "@fortawesome/fontawesome-common-types" "6.5.1" "@fortawesome/free-solid-svg-icons@^6.5.1": version "6.5.1" - resolved "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz#737b8d787debe88b400ab7528f47be333031274a" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz#737b8d787debe88b400ab7528f47be333031274a" integrity sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ== dependencies: "@fortawesome/fontawesome-common-types" "6.5.1" "@fortawesome/react-fontawesome@^0.2.0": version "0.2.0" - resolved "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" + resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== dependencies: prop-types "^15.8.1" @@ -5370,7 +5370,7 @@ "@redux-saga/core@^1.3.0": version "1.3.0" - resolved "https://registry.npmjs.org/@redux-saga/core/-/core-1.3.0.tgz#2ce08b73d407fc6ea9e7f7d83d2e97d981a3a8b8" + resolved "https://registry.yarnpkg.com/@redux-saga/core/-/core-1.3.0.tgz#2ce08b73d407fc6ea9e7f7d83d2e97d981a3a8b8" integrity sha512-L+i+qIGuyWn7CIg7k1MteHGfttKPmxwZR5E7OsGikCL2LzYA0RERlaUY00Y3P3ZV2EYgrsYlBrGs6cJP5OKKqA== dependencies: "@babel/runtime" "^7.6.3" @@ -5383,19 +5383,19 @@ "@redux-saga/deferred@^1.2.1": version "1.2.1" - resolved "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz#aca373a08ccafd6f3481037f2f7ee97f2c87c3ec" + resolved "https://registry.yarnpkg.com/@redux-saga/deferred/-/deferred-1.2.1.tgz#aca373a08ccafd6f3481037f2f7ee97f2c87c3ec" integrity sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g== "@redux-saga/delay-p@^1.2.1": version "1.2.1" - resolved "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz#e72ac4731c5080a21f75b61bedc31cb639d9e446" + resolved "https://registry.yarnpkg.com/@redux-saga/delay-p/-/delay-p-1.2.1.tgz#e72ac4731c5080a21f75b61bedc31cb639d9e446" integrity sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w== dependencies: "@redux-saga/symbols" "^1.1.3" "@redux-saga/is@^1.1.3": version "1.1.3" - resolved "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz#b333f31967e87e32b4e6b02c75b78d609dd4ad73" + resolved "https://registry.yarnpkg.com/@redux-saga/is/-/is-1.1.3.tgz#b333f31967e87e32b4e6b02c75b78d609dd4ad73" integrity sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q== dependencies: "@redux-saga/symbols" "^1.1.3" @@ -5403,21 +5403,21 @@ "@redux-saga/symbols@^1.1.3": version "1.1.3" - resolved "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz#b731d56201719e96dc887dc3ae9016e761654367" + resolved "https://registry.yarnpkg.com/@redux-saga/symbols/-/symbols-1.1.3.tgz#b731d56201719e96dc887dc3ae9016e761654367" integrity sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg== "@redux-saga/types@^1.2.1": version "1.2.1" - resolved "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz#9403f51c17cae37edf870c6bc0c81c1ece5ccef8" + resolved "https://registry.yarnpkg.com/@redux-saga/types/-/types-1.2.1.tgz#9403f51c17cae37edf870c6bc0c81c1ece5ccef8" integrity sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA== "@reduxjs/toolkit@^2.0.1": - version "2.0.1" - resolved "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz#0a5233c1e35c1941b03aece39cceade3467a1062" - integrity sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.2.0.tgz#69b7d7933ea3e7f0cbbe182caa4850e09ea643ae" + integrity sha512-ZvPYKfu4kDnAqPhJ1bsis8QFbiQRz3Q2HxW3tw9tVGusPzYKRG7ju1FA+34PGcwCoemjGGv+f/7fEygcRZIwmA== dependencies: immer "^10.0.3" - redux "^5.0.0" + redux "^5.0.1" redux-thunk "^3.1.0" reselect "^5.0.1" @@ -6492,7 +6492,7 @@ "@types/parse5@^6.0.0": version "6.0.3" - resolved "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb" + resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb" integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g== "@types/pbkdf2@^3.0.0": @@ -6998,6 +6998,7 @@ version "2.11.1" resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.11.1.tgz#6e0174ec9026940eaadeedc53417e222eb45f5aa" integrity sha512-UfQH0ho24aa2M1xYmanbJv2ggQPebKmQytp2j20QEvURJ2R0v7YKWZ+0PfwOs6o6cuGw6gGxy/0WQXQRZSAsfg== + dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "^1.0.13" "@walletconnect/jsonrpc-types" "^1.0.3" @@ -10875,7 +10876,7 @@ clsx@^2.0.0: clsx@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== cluster-key-slot@^1.1.0: @@ -16210,7 +16211,7 @@ hasha@^3.0.0: hast-util-from-parse5@^7.0.0: version "7.1.2" - resolved "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz#aecfef73e3ceafdfa4550716443e4eb7b02e22b0" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz#aecfef73e3ceafdfa4550716443e4eb7b02e22b0" integrity sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw== dependencies: "@types/hast" "^2.0.0" @@ -16223,14 +16224,14 @@ hast-util-from-parse5@^7.0.0: hast-util-parse-selector@^3.0.0: version "3.1.1" - resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz#25ab00ae9e75cbc62cf7a901f68a247eade659e2" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz#25ab00ae9e75cbc62cf7a901f68a247eade659e2" integrity sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA== dependencies: "@types/hast" "^2.0.0" hast-util-raw@^7.2.0: version "7.2.3" - resolved "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz#dcb5b22a22073436dbdc4aa09660a644f4991d99" + resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-7.2.3.tgz#dcb5b22a22073436dbdc4aa09660a644f4991d99" integrity sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg== dependencies: "@types/hast" "^2.0.0" @@ -16247,7 +16248,7 @@ hast-util-raw@^7.2.0: hast-util-to-parse5@^7.0.0: version "7.1.0" - resolved "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz#c49391bf8f151973e0c9adcd116b561e8daf29f3" + resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz#c49391bf8f151973e0c9adcd116b561e8daf29f3" integrity sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw== dependencies: "@types/hast" "^2.0.0" @@ -16264,7 +16265,7 @@ hast-util-whitespace@^2.0.0: hastscript@^7.0.0: version "7.2.0" - resolved "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz#0eafb7afb153d047077fa2a833dc9b7ec604d10b" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-7.2.0.tgz#0eafb7afb153d047077fa2a833dc9b7ec604d10b" integrity sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw== dependencies: "@types/hast" "^2.0.0" @@ -16398,7 +16399,7 @@ html-react-parser@^3.0.4: html-void-elements@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" + resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A== html2canvas@^1.0.0-rc.5: @@ -16726,7 +16727,7 @@ immediate@~3.0.5: immer@^10.0.3: version "10.0.3" - resolved "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz#a8de42065e964aa3edf6afc282dfc7f7f34ae3c9" + resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.3.tgz#a8de42065e964aa3edf6afc282dfc7f7f34ae3c9" integrity sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A== immutable@^4.0.0: @@ -23232,7 +23233,7 @@ parse5@4.0.0: parse5@^6.0.0: version "6.0.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== parse5@^7.0.0: @@ -24000,6 +24001,7 @@ preact@^10.16.0: version "10.19.3" resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.3.tgz#7a7107ed2598a60676c943709ea3efb8aaafa899" integrity sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ== + prebuild-install@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" @@ -24788,7 +24790,7 @@ react-router@6.21.0: react-spinners@^0.13.8: version "0.13.8" - resolved "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz#5262571be0f745d86bbd49a1e6b49f9f9cb19acc" + resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.13.8.tgz#5262571be0f745d86bbd49a1e6b49f9f9cb19acc" integrity sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA== react-tabs@^6.0.2: @@ -24809,9 +24811,9 @@ react-textarea-autosize@~8.3.2: use-latest "^1.2.1" react-toastify@^10.0.3: - version "10.0.3" - resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.3.tgz#1b948fabf63393464eb2f82119485de58b9a9b2f" - integrity sha512-PBJwXjFKKM73tgb6iSld4GMs9ShBWGUvc9zPHmdDgT4CdSr32iqSNh6y/fFN/tosvkTS6/tBLptDxXiXgcjvuw== + version "10.0.4" + resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-10.0.4.tgz#6ecdbbf923a07fc45850e69b0566efc7bf733283" + integrity sha512-etR3RgueY8pe88SA67wLm8rJmL1h+CLqUGHuAoNsseW35oTGJEri6eBTyaXnFKNQ80v/eO10hBYLgz036XRGgA== dependencies: clsx "^2.1.0" @@ -25189,18 +25191,6 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" -redux-saga@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/redux-saga/-/redux-saga-1.3.0.tgz#a59ada7c28010189355356b99738c9fcb7ade30e" - integrity sha512-J9RvCeAZXSTAibFY0kGw6Iy4EdyDNW7k6Q+liwX+bsck7QVsU78zz8vpBRweEfANxnnlG/xGGeOvf6r8UXzNJQ== - dependencies: - "@redux-saga/core" "^1.3.0" - -redux-thunk@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3" - integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw== - redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" @@ -25213,6 +25203,18 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" +redux-saga@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-1.3.0.tgz#a59ada7c28010189355356b99738c9fcb7ade30e" + integrity sha512-J9RvCeAZXSTAibFY0kGw6Iy4EdyDNW7k6Q+liwX+bsck7QVsU78zz8vpBRweEfANxnnlG/xGGeOvf6r8UXzNJQ== + dependencies: + "@redux-saga/core" "^1.3.0" + +redux-thunk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3" + integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw== + redux@^4.0.0, redux@^4.0.4: version "4.1.2" resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" @@ -25220,9 +25222,9 @@ redux@^4.0.0, redux@^4.0.4: dependencies: "@babel/runtime" "^7.9.2" -redux@^5.0.0: +redux@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== regenerate-unicode-properties@^10.1.0: @@ -25425,7 +25427,7 @@ regjsparser@^0.9.1: rehype-raw@^6.0.0: version "6.1.1" - resolved "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz#81bbef3793bd7abacc6bf8335879d1b6c868c9d4" + resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-6.1.1.tgz#81bbef3793bd7abacc6bf8335879d1b6c868c9d4" integrity sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ== dependencies: "@types/hast" "^2.0.0" @@ -25607,7 +25609,7 @@ reselect@^4.0.0: reselect@^5.0.1: version "5.1.0" - resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz#c479139ab9dd91be4d9c764a7f3868210ef8cd21" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.0.tgz#c479139ab9dd91be4d9c764a7f3868210ef8cd21" integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg== reset@^0.1.0: @@ -28614,19 +28616,19 @@ typedarray@^0.0.6: typescript-compare@^0.0.2: version "0.0.2" - resolved "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz#7ee40a400a406c2ea0a7e551efd3309021d5f425" + resolved "https://registry.yarnpkg.com/typescript-compare/-/typescript-compare-0.0.2.tgz#7ee40a400a406c2ea0a7e551efd3309021d5f425" integrity sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA== dependencies: typescript-logic "^0.0.0" typescript-logic@^0.0.0: version "0.0.0" - resolved "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz#66ebd82a2548f2b444a43667bec120b496890196" + resolved "https://registry.yarnpkg.com/typescript-logic/-/typescript-logic-0.0.0.tgz#66ebd82a2548f2b444a43667bec120b496890196" integrity sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q== typescript-tuple@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz#7d9813fb4b355f69ac55032e0363e8bb0f04dad2" + resolved "https://registry.yarnpkg.com/typescript-tuple/-/typescript-tuple-2.2.1.tgz#7d9813fb4b355f69ac55032e0363e8bb0f04dad2" integrity sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q== dependencies: typescript-compare "^0.0.2" @@ -29383,7 +29385,7 @@ verror@1.3.6: vfile-location@^4.0.0: version "4.1.0" - resolved "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz#69df82fb9ef0a38d0d02b90dd84620e120050dd0" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-4.1.0.tgz#69df82fb9ef0a38d0d02b90dd84620e120050dd0" integrity sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw== dependencies: "@types/unist" "^2.0.0" @@ -29574,7 +29576,7 @@ web-encoding@^1.0.2, web-encoding@^1.0.6: web-namespaces@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" + resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== web-streams-polyfill@^3.1.0: From 87307b0c1c193c3b8c057542e591c8f6beed3008 Mon Sep 17 00:00:00 2001 From: drafish Date: Tue, 13 Feb 2024 13:45:12 +0800 Subject: [PATCH 25/26] fix learneth style --- apps/learneth/src/pages/Home/index.css | 3 ++- apps/learneth/src/pages/Home/index.tsx | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/learneth/src/pages/Home/index.css b/apps/learneth/src/pages/Home/index.css index 2375651475..70c6426ea4 100644 --- a/apps/learneth/src/pages/Home/index.css +++ b/apps/learneth/src/pages/Home/index.css @@ -13,10 +13,11 @@ .arrow-icon{ width: 12px; display: inline-block; + cursor: pointer; } .workshop-link { - text-decoration: none; + cursor: pointer; } .workshop-link:hover { text-decoration: underline; diff --git a/apps/learneth/src/pages/Home/index.tsx b/apps/learneth/src/pages/Home/index.tsx index 0823668695..503f056e11 100644 --- a/apps/learneth/src/pages/Home/index.tsx +++ b/apps/learneth/src/pages/Home/index.tsx @@ -45,24 +45,22 @@ function HomePage(): JSX.Element { {selectedRepo.group[level].map((item: any) => (
- { handleClick(item.id) }} > - - + { handleClick(item.id) }} > {selectedRepo.entities[item.id].name} - + From fd76c4e8306cb4b9a9fa53b45b3a7f6dd193dbcd Mon Sep 17 00:00:00 2001 From: drafish Date: Tue, 13 Feb 2024 19:12:43 +0800 Subject: [PATCH 26/26] rm @fortawesome/* packages --- .../src/components/BackButton/index.tsx | 10 +++---- .../src/components/RepoImporter/index.tsx | 8 +++--- apps/learneth/src/pages/Home/index.tsx | 6 ++--- package.json | 3 --- yarn.lock | 26 ------------------- 5 files changed, 9 insertions(+), 44 deletions(-) diff --git a/apps/learneth/src/components/BackButton/index.tsx b/apps/learneth/src/components/BackButton/index.tsx index d18e2efbe0..14f8112d4f 100644 --- a/apps/learneth/src/components/BackButton/index.tsx +++ b/apps/learneth/src/components/BackButton/index.tsx @@ -1,8 +1,6 @@ import React, {useState} from 'react' import {Link, useLocation, useNavigate} from 'react-router-dom' import {Button, Modal, Tooltip, OverlayTrigger} from 'react-bootstrap' -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' -import {faHome, faBars, faChevronLeft, faChevronRight} from '@fortawesome/free-solid-svg-icons' import './index.scss' function BackButton({entity}: any) { @@ -25,14 +23,14 @@ function BackButton({entity}: any) { role="button" > Leave tutorial}> - +
{isDetailPage && (
  • - +
  • )} @@ -41,13 +39,13 @@ function BackButton({entity}: any) {
    {stepId > 0 && ( - + )} {stepId + 1}/{entity &&
    {entity.steps.length}
    } {stepId < entity.steps.length - 1 && ( - + )} diff --git a/apps/learneth/src/components/RepoImporter/index.tsx b/apps/learneth/src/components/RepoImporter/index.tsx index 7bc3a7f90e..47c1f73705 100644 --- a/apps/learneth/src/components/RepoImporter/index.tsx +++ b/apps/learneth/src/components/RepoImporter/index.tsx @@ -1,7 +1,5 @@ import React, {useState, useEffect} from 'react' import {Button, Dropdown, Form, Tooltip, OverlayTrigger} from 'react-bootstrap' -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' -import {faQuestionCircle, faInfoCircle, faChevronRight, faChevronDown} from '@fortawesome/free-solid-svg-icons' import {useAppDispatch} from '../../redux/hooks' import './index.css' @@ -47,7 +45,7 @@ function RepoImporter({list, selectedRepo}: any): JSX.Element {
    - +
    Import another tutorial repo
    @@ -85,7 +83,7 @@ function RepoImporter({list, selectedRepo}: any): JSX.Element { REPO ie username/repository}> - + - how to setup your repo + how to setup your repo )} diff --git a/apps/learneth/src/pages/Home/index.tsx b/apps/learneth/src/pages/Home/index.tsx index 503f056e11..6835901900 100644 --- a/apps/learneth/src/pages/Home/index.tsx +++ b/apps/learneth/src/pages/Home/index.tsx @@ -1,7 +1,5 @@ import React, {useEffect} from 'react' import {Link} from 'react-router-dom' -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' -import {faChevronRight, faChevronDown, faPlayCircle} from '@fortawesome/free-solid-svg-icons' import Markdown from 'react-markdown' import rehypeRaw from 'rehype-raw' import remarkGfm from 'remark-gfm' @@ -51,7 +49,7 @@ function HomePage(): JSX.Element { handleClick(item.id) }} > - + - +
    diff --git a/package.json b/package.json index ddd68c6a00..80aa2b75a0 100644 --- a/package.json +++ b/package.json @@ -138,9 +138,6 @@ "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", "@ethersphere/bee-js": "^3.2.0", - "@fortawesome/fontawesome-svg-core": "^6.5.1", - "@fortawesome/free-solid-svg-icons": "^6.5.1", - "@fortawesome/react-fontawesome": "^0.2.0", "@isomorphic-git/lightning-fs": "^4.4.1", "@microlink/react-json-view": "^1.23.0", "@openzeppelin/contracts": "^5.0.0", diff --git a/yarn.lock b/yarn.lock index 6977032bbc..93a208eb2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2954,37 +2954,11 @@ intl-messageformat "10.1.0" tslib "2.4.0" -"@fortawesome/fontawesome-common-types@6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz#fdb1ec4952b689f5f7aa0bffe46180bb35490032" - integrity sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A== - "@fortawesome/fontawesome-free@^5.8.1": version "5.15.4" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz#ecda5712b61ac852c760d8b3c79c96adca5554e5" integrity sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg== -"@fortawesome/fontawesome-svg-core@^6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz#9d56d46bddad78a7ebb2043a97957039fcebcf0a" - integrity sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ== - dependencies: - "@fortawesome/fontawesome-common-types" "6.5.1" - -"@fortawesome/free-solid-svg-icons@^6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz#737b8d787debe88b400ab7528f47be333031274a" - integrity sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ== - dependencies: - "@fortawesome/fontawesome-common-types" "6.5.1" - -"@fortawesome/react-fontawesome@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" - integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== - dependencies: - prop-types "^15.8.1" - "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"