From 88eeb772725c2740765e768011ea751120ce641e Mon Sep 17 00:00:00 2001 From: drafish Date: Wed, 17 Jan 2024 13:59:10 +0800 Subject: [PATCH 01/15] 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 +
+
+ )} + +
+ {open && ( +
+ + + REPO + + ie username/repository + } + > + + + { + setName(e.target.value); + }} + value={name} + /> + BRANCH + { + setBranch(e.target.value); + }} + value={branch} + /> + + + + how to setup your repo + +
+ )} +
+
+ + ); +} + +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 02/15] 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 03/15] 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 04/15] 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 05/15] 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 06/15] 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 12/15] 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 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 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 13/15] 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 14/15] 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 15/15] 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"