parent
40a291b4e4
commit
41f441748a
@ -0,0 +1,115 @@ |
||||
import { RemixApp } from '@remix-ui/app' |
||||
import React, { useEffect, useRef, useState } from 'react' |
||||
import { render } from 'react-dom' |
||||
import * as packageJson from '../../../../../package.json' |
||||
import { fileSystems } from '../files/fileSystem' |
||||
import { indexedDBFileSystem } from '../files/filesystems/indexedDB' |
||||
import { localStorageFS } from '../files/filesystems/localStorage' |
||||
import { fileSystemUtility } from '../files/filesystems/migrateFileSystem' |
||||
|
||||
export const Preload = () => { |
||||
|
||||
const [supported, setSupported] = useState<boolean>(true) |
||||
const [error, setError] = useState<boolean>(false) |
||||
const [showDownloader, setShowDownloader] = useState<boolean>(false) |
||||
const remixFileSystems = useRef<fileSystems>(new fileSystems()) |
||||
|
||||
const logo = <svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100"> |
||||
<path d="M91.84,35a.09.09,0,0,1-.1-.07,41,41,0,0,0-79.48,0,.09.09,0,0,1-.1.07C9.45,35,1,35.35,1,42.53c0,8.56,1,16,6,20.32,2.16,1.85,5.81,2.3,9.27,2.22a44.4,44.4,0,0,0,6.45-.68.09.09,0,0,0,.06-.15A34.81,34.81,0,0,1,17,45c0-.1,0-.21,0-.31a35,35,0,0,1,70,0c0,.1,0,.21,0,.31a34.81,34.81,0,0,1-5.78,19.24.09.09,0,0,0,.06.15,44.4,44.4,0,0,0,6.45.68c3.46.08,7.11-.37,9.27-2.22,5-4.27,6-11.76,6-20.32C103,35.35,94.55,35,91.84,35Z" /> |
||||
<path d="M52,74,25.4,65.13a.1.1,0,0,0-.1.17L51.93,91.93a.1.1,0,0,0,.14,0L78.7,65.3a.1.1,0,0,0-.1-.17L52,74A.06.06,0,0,1,52,74Z" /> |
||||
<path d="M75.68,46.9,82,45a.09.09,0,0,0,.08-.09,29.91,29.91,0,0,0-.87-6.94.11.11,0,0,0-.09-.08l-6.43-.58a.1.1,0,0,1-.06-.18l4.78-4.18a.13.13,0,0,0,0-.12,30.19,30.19,0,0,0-3.65-6.07.09.09,0,0,0-.11,0l-5.91,2a.1.1,0,0,1-.12-.14L72.19,23a.11.11,0,0,0,0-.12,29.86,29.86,0,0,0-5.84-4.13.09.09,0,0,0-.11,0l-4.47,4.13a.1.1,0,0,1-.17-.07l.09-6a.1.1,0,0,0-.07-.1,30.54,30.54,0,0,0-7-1.47.1.1,0,0,0-.1.07l-2.38,5.54a.1.1,0,0,1-.18,0l-2.37-5.54a.11.11,0,0,0-.11-.06,30,30,0,0,0-7,1.48.12.12,0,0,0-.07.1l.08,6.05a.09.09,0,0,1-.16.07L37.8,18.76a.11.11,0,0,0-.12,0,29.75,29.75,0,0,0-5.83,4.13.11.11,0,0,0,0,.12l2.59,5.6a.11.11,0,0,1-.13.14l-5.9-2a.11.11,0,0,0-.12,0,30.23,30.23,0,0,0-3.62,6.08.11.11,0,0,0,0,.12l4.79,4.19a.1.1,0,0,1-.06.17L23,37.91a.1.1,0,0,0-.09.07A29.9,29.9,0,0,0,22,44.92a.1.1,0,0,0,.07.1L28.4,47a.1.1,0,0,1,0,.18l-5.84,3.26a.16.16,0,0,0,0,.11,30.17,30.17,0,0,0,2.1,6.76c.32.71.67,1.4,1,2.08a.1.1,0,0,0,.06,0L52,68.16H52l26.34-8.78a.1.1,0,0,0,.06-.05,30.48,30.48,0,0,0,3.11-8.88.1.1,0,0,0-.05-.11l-5.83-3.26A.1.1,0,0,1,75.68,46.9Z" /> |
||||
</svg> |
||||
|
||||
function loadAppComponent() { |
||||
import('../../app').then((AppComponent) => { |
||||
const appComponent = new AppComponent.default() |
||||
appComponent.run().then(() => { |
||||
render( |
||||
<> |
||||
<RemixApp app={appComponent} /> |
||||
</>, |
||||
document.getElementById('root') |
||||
) |
||||
}) |
||||
}).catch(err => { |
||||
console.log('Error loading Remix:', err) |
||||
setError(true) |
||||
}) |
||||
} |
||||
|
||||
|
||||
|
||||
const downloadBackup = async () =>{ |
||||
const migrator = new fileSystemUtility() |
||||
migrator.downloadBackup(remixFileSystems.current.fileSystems['localstorage']) |
||||
loadAppComponent() |
||||
} |
||||
|
||||
const skipBackup = async() => { |
||||
loadAppComponent() |
||||
} |
||||
|
||||
useEffect(() => { |
||||
|
||||
|
||||
async function loadStorage() { |
||||
const remixIndexedDB = new indexedDBFileSystem() |
||||
const localStorageFileSystem = new localStorageFS() |
||||
|
||||
|
||||
await remixFileSystems.current.addFileSystem(remixIndexedDB) |
||||
await remixFileSystems.current.addFileSystem(localStorageFileSystem) |
||||
|
||||
setShowDownloader(true) |
||||
|
||||
const migrator = new fileSystemUtility() |
||||
await migrator.migrate(localStorageFileSystem, remixIndexedDB) |
||||
const fsLoaded = await remixFileSystems.current.setFileSystem([remixIndexedDB, localStorageFileSystem]) |
||||
|
||||
if (fsLoaded) { |
||||
console.log(fsLoaded.name + ' activated') |
||||
console.log(localStorageFileSystem) |
||||
// migrator.downloadBackup(localStorageFileSystem)
|
||||
//loadAppComponent()
|
||||
} else { |
||||
console.log('No filesystem could be loaded') |
||||
setSupported(false) |
||||
// displayBrowserNotSupported()
|
||||
} |
||||
} |
||||
|
||||
loadStorage() |
||||
}, []) |
||||
|
||||
return <> |
||||
<div style={{ display: 'block' }} className='centered'> |
||||
{logo} |
||||
<div className="info-secondary splash"> |
||||
REMIX IDE |
||||
<br /> |
||||
<span className='version'> v{packageJson.version}</span> |
||||
</div> |
||||
{!supported ? |
||||
<div style={{ marginTop: '50%', textAlign: 'center' }}> |
||||
Your browser does not support any of the filesytems required by Remix. |
||||
Either change the settings in your browser or use a supported browser. |
||||
</div> : null} |
||||
{error ? |
||||
<div style={{ marginTop: '50%', textAlign: 'center' }}> |
||||
An unknown error has occured loading the application. |
||||
</div> : null} |
||||
{showDownloader ? |
||||
<div style={{ marginTop: '20%', textAlign: 'center' }}> |
||||
This app will be updated now. Please download a backup of your files now to make sure you don't lose your work. |
||||
<br></br> |
||||
You don't need to do anything else, your files will be available when the app loads. |
||||
<div onClick={async() => {await downloadBackup()}} className='btn btn-primary mt-1'>download backup</div> |
||||
<div onClick={async() => {await skipBackup()}}className='btn btn-primary mt-1'>skip backup</div> |
||||
</div> : null} |
||||
{(supported && !error && !showDownloader) ? |
||||
<div style={{ marginTop: '50%', textAlign: 'center' }}> |
||||
<i className="fas fa-spinner fa-spin fa-2x"></i> |
||||
</div> : null} |
||||
</div> |
||||
</> |
||||
} |
@ -0,0 +1,85 @@ |
||||
export class fileSystem { |
||||
name: string |
||||
enabled: boolean |
||||
available: boolean |
||||
fs: any |
||||
fsCallBack: any; |
||||
hasWorkSpaces: boolean |
||||
loaded: boolean |
||||
load: () => Promise<unknown> |
||||
test: () => Promise<unknown> |
||||
|
||||
constructor() { |
||||
this.available = false |
||||
this.enabled = false |
||||
this.hasWorkSpaces = false |
||||
this.loaded = false |
||||
} |
||||
ReadWriteTest = async () => { |
||||
try { |
||||
const str = 'Hello World' |
||||
await this.fs.writeFile('/test.txt', str, 'utf8') |
||||
if (await this.fs.readFile('/test.txt', 'utf8') === str) { |
||||
console.log('Read/Write Test Passed') |
||||
return true |
||||
} |
||||
await this.fs.remove('/test.txt', 'utf8') |
||||
} catch (e) { |
||||
console.log(e) |
||||
} |
||||
return false |
||||
} |
||||
|
||||
checkWorkspaces = async () => { |
||||
try { |
||||
await this.fs.stat('.workspaces') |
||||
this.hasWorkSpaces = true |
||||
} catch (e) { |
||||
|
||||
} |
||||
} |
||||
|
||||
set = async () => { |
||||
const w = (window as any) |
||||
if (!this.loaded) return false |
||||
w.remixFileSystem = this.fs |
||||
w.remixFileSystemCallback = this.fsCallBack |
||||
return true |
||||
} |
||||
} |
||||
|
||||
export class fileSystems { |
||||
fileSystems: Record<string, fileSystem> |
||||
constructor() { |
||||
this.fileSystems = {} |
||||
} |
||||
|
||||
addFileSystem = async (fs: fileSystem) => { |
||||
try { |
||||
this.fileSystems[fs.name] = fs |
||||
if (await fs.test()) await fs.load() |
||||
console.log(fs.name + ' is loaded...') |
||||
return true |
||||
} catch (e) { |
||||
console.log(fs.name + ' not available...') |
||||
return false |
||||
} |
||||
} |
||||
/** |
||||
* sets filesystem using list as fallback |
||||
* @param {string[]} names |
||||
* @returns {Promise} |
||||
*/ |
||||
setFileSystem = async (filesystems?: fileSystem[]): Promise<fileSystem> => { |
||||
for (const fs of filesystems) { |
||||
if (this.fileSystems[fs.name]) { |
||||
const result = await this.fileSystems[fs.name].set() |
||||
if (result) return this.fileSystems[fs.name] |
||||
} |
||||
} |
||||
return null |
||||
} |
||||
|
||||
|
||||
} |
||||
|
@ -0,0 +1,91 @@ |
||||
import LightningFS from "@isomorphic-git/lightning-fs" |
||||
import { fileSystem } from "../fileSystem" |
||||
|
||||
export class IndexedDBStorage extends LightningFS { |
||||
base: LightningFS.PromisifedFS |
||||
addSlash: (file: string) => string |
||||
extended: { exists: (path: string) => Promise<unknown>; rmdir: (path: any) => Promise<void>; readdir: (path: any) => Promise<string[]>; unlink: (path: any) => Promise<void>; mkdir: (path: any) => Promise<void>; readFile: (path: any, options: any) => Promise<Uint8Array>; rename: (from: any, to: any) => Promise<void>; writeFile: (path: any, content: any, options: any) => Promise<void>; stat: (path: any) => Promise<import("fs").Stats>; init(name: string, opt?: LightningFS.FSConstructorOptions): void; activate(): Promise<void>; deactivate(): Promise<void>; lstat(filePath: string): Promise<import("fs").Stats>; readlink(filePath: string): Promise<string>; symlink(target: string, filePath: string): Promise<void> } |
||||
constructor(name: string) { |
||||
super(name) |
||||
this.addSlash = (file) => { |
||||
if (!file.startsWith('/')) file = '/' + file |
||||
return file |
||||
} |
||||
this.base = this.promises |
||||
this.extended = { |
||||
...this.promises, |
||||
exists: async (path: string) => { |
||||
return new Promise((resolve) => { |
||||
this.base.stat(this.addSlash(path)).then(() => resolve(true)).catch(() => resolve(false)) |
||||
}) |
||||
}, |
||||
rmdir: async (path) => { |
||||
return this.base.rmdir(this.addSlash(path)) |
||||
}, |
||||
readdir: async (path) => { |
||||
return this.base.readdir(this.addSlash(path)) |
||||
}, |
||||
unlink: async (path) => { |
||||
return this.base.unlink(this.addSlash(path)) |
||||
}, |
||||
mkdir: async (path) => { |
||||
return this.base.mkdir(this.addSlash(path)) |
||||
}, |
||||
readFile: async (path, options) => { |
||||
return this.base.readFile(this.addSlash(path), options) |
||||
}, |
||||
rename: async (from, to) => { |
||||
return this.base.rename(this.addSlash(from), this.addSlash(to)) |
||||
}, |
||||
writeFile: async (path, content, options) => { |
||||
return this.base.writeFile(this.addSlash(path), content, options) |
||||
}, |
||||
stat: async (path) => { |
||||
return this.base.stat(this.addSlash(path)) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
export class indexedDBFileSystem extends fileSystem { |
||||
constructor() { |
||||
super() |
||||
this.name = 'indexedDB' |
||||
} |
||||
|
||||
load = async () => { |
||||
return new Promise((resolve, reject) => { |
||||
try { |
||||
const fs = new IndexedDBStorage('RemixFileSystem') |
||||
fs.init('RemixFileSystem') |
||||
this.fs = fs.extended |
||||
this.fsCallBack = fs |
||||
this.loaded = true |
||||
resolve(true) |
||||
} catch (e) { |
||||
reject(e) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
test = async () => { |
||||
return new Promise((resolve, reject) => { |
||||
if (!window.indexedDB) { |
||||
this.available = false |
||||
reject('No indexedDB on window') |
||||
} |
||||
const request = window.indexedDB.open("RemixTestDataBase", 3); |
||||
request.onerror = () => { |
||||
this.available = false |
||||
reject('Error creating test database') |
||||
}; |
||||
request.onsuccess = () => { |
||||
window.indexedDB.deleteDatabase("RemixTestDataBase"); |
||||
this.available = true |
||||
resolve(true) |
||||
}; |
||||
}) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,58 @@ |
||||
import { fileSystem } from "../fileSystem"; |
||||
|
||||
export class localStorageFS extends fileSystem { |
||||
|
||||
constructor() { |
||||
super() |
||||
this.name = 'localstorage' |
||||
} |
||||
load = async () => { |
||||
const me = this |
||||
return new Promise((resolve, reject) => { |
||||
try { |
||||
// eslint-disable-next-line no-undef
|
||||
BrowserFS.install(window) |
||||
// eslint-disable-next-line no-undef
|
||||
BrowserFS.configure({ |
||||
fs: 'LocalStorage' |
||||
}, async function (e) { |
||||
if (e) { |
||||
console.log('BROWSEFS Error: ' + e) |
||||
reject(e) |
||||
} else { |
||||
me.fs = { ...window.require('fs') } |
||||
me.fsCallBack = window.require('fs') |
||||
me.fs.readdir = me.fs.readdirSync |
||||
me.fs.readFile = me.fs.readFileSync |
||||
me.fs.writeFile = me.fs.writeFileSync |
||||
me.fs.stat = me.fs.statSync |
||||
me.fs.unlink = me.fs.unlinkSync |
||||
me.fs.rmdir = me.fs.rmdirSync |
||||
me.fs.mkdir = me.fs.mkdirSync |
||||
me.fs.rename = me.fs.renameSync |
||||
me.fs.exists = me.fs.existsSync |
||||
me.loaded = true |
||||
resolve(true) |
||||
} |
||||
}) |
||||
} catch (e) { |
||||
console.log('BrowserFS is not ready!') |
||||
reject(e) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
test = async () => { |
||||
return new Promise((resolve, reject) => { |
||||
const test = 'test'; |
||||
try { |
||||
localStorage.setItem(test, test); |
||||
localStorage.removeItem(test); |
||||
resolve(true) |
||||
} catch(e) { |
||||
reject(e) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,189 @@ |
||||
import { hashMessage } from "ethers/lib/utils" |
||||
import JSZip from "jszip" |
||||
import { fileSystem } from "../fileSystem" |
||||
|
||||
export class fileSystemUtility { |
||||
migrate = async (fsFrom: fileSystem, fsTo: fileSystem) => { |
||||
try { |
||||
await fsFrom.checkWorkspaces() |
||||
await fsTo.checkWorkspaces() |
||||
|
||||
if (fsTo.hasWorkSpaces) { |
||||
console.log(`${fsTo.name} already has files`) |
||||
return true |
||||
} |
||||
|
||||
if (!fsFrom.hasWorkSpaces) { |
||||
console.log('no files to migrate') |
||||
return true |
||||
} |
||||
|
||||
await this.populateWorkspace(testData, fsFrom.fs) |
||||
const fromFiles = await this.copyFolderToJson('/', null, null, fsFrom.fs) |
||||
console.log(fsFrom.name, hashMessage(JSON.stringify(fromFiles)), fromFiles) |
||||
await this.populateWorkspace(fromFiles, fsTo.fs) |
||||
const toFiles = await this.copyFolderToJson('/', null, null, fsTo.fs) |
||||
|
||||
if (hashMessage(JSON.stringify(toFiles)) === hashMessage(JSON.stringify(fromFiles))) { |
||||
console.log('file migration successful') |
||||
return true |
||||
} else { |
||||
console.log('file migration failed falling back to ' + fsFrom.name) |
||||
fsTo.loaded = false |
||||
return false |
||||
} |
||||
} catch (e) { |
||||
console.log(e) |
||||
console.log('file migration failed falling back to ' + fsFrom.name) |
||||
fsTo.loaded = false |
||||
return false |
||||
} |
||||
} |
||||
|
||||
downloadBackup = async (fs: fileSystem) => { |
||||
try { |
||||
const zip = new JSZip() |
||||
await fs.checkWorkspaces() |
||||
await this.copyFolderToJson('/', null, null, fs.fs, ({ path, content }) => { |
||||
zip.file(path, content) |
||||
}) |
||||
const blob = await zip.generateAsync({ type: 'blob' }) |
||||
const today = new Date() |
||||
const date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate() |
||||
const time = today.getHours() + 'h' + today.getMinutes() + 'min' |
||||
this.saveAs(blob, `remix-backup-at-${time}-${date}.zip`) |
||||
|
||||
} catch (e) { |
||||
console.log(e) |
||||
} |
||||
} |
||||
|
||||
populateWorkspace = async (json, fs) => { |
||||
for (const item in json) { |
||||
const isFolder = json[item].content === undefined |
||||
if (isFolder) { |
||||
await this.createDir(item, fs) |
||||
await this.populateWorkspace(json[item].children, fs) |
||||
} else { |
||||
await fs.writeFile(item, json[item].content, 'utf8') |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* copy the folder recursively |
||||
* @param {string} path is the folder to be copied over |
||||
* @param {Function} visitFile is a function called for each visited files |
||||
* @param {Function} visitFolder is a function called for each visited folders |
||||
*/ |
||||
copyFolderToJson = async (path, visitFile, visitFolder, fs, cb = null) => { |
||||
visitFile = visitFile || (() => { }) |
||||
visitFolder = visitFolder || (() => { }) |
||||
return await this._copyFolderToJsonInternal(path, visitFile, visitFolder, fs, cb) |
||||
} |
||||
|
||||
/** |
||||
* copy the folder recursively (internal use) |
||||
* @param {string} path is the folder to be copied over |
||||
* @param {Function} visitFile is a function called for each visited files |
||||
* @param {Function} visitFolder is a function called for each visited folders |
||||
*/ |
||||
async _copyFolderToJsonInternal(path, visitFile, visitFolder, fs, cb) { |
||||
visitFile = visitFile || function () { /* do nothing. */ } |
||||
visitFolder = visitFolder || function () { /* do nothing. */ } |
||||
|
||||
const json = {} |
||||
// path = this.removePrefix(path)
|
||||
if (await fs.exists(path)) { |
||||
const items = await fs.readdir(path) |
||||
visitFolder({ path }) |
||||
if (items.length !== 0) { |
||||
for (const item of items) { |
||||
const file: any = {} |
||||
const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}` |
||||
if ((await fs.stat(curPath)).isDirectory()) { |
||||
file.children = await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder, fs, cb) |
||||
} else { |
||||
file.content = await fs.readFile(curPath, 'utf8') |
||||
if (cb) cb({ path: curPath, content: file.content }) |
||||
visitFile({ path: curPath, content: file.content }) |
||||
|
||||
} |
||||
json[curPath] = file |
||||
} |
||||
} |
||||
} |
||||
return json |
||||
} |
||||
|
||||
createDir = async (path, fs) => { |
||||
const paths = path.split('/') |
||||
if (paths.length && paths[0] === '') paths.shift() |
||||
let currentCheck = '' |
||||
for (const value of paths) { |
||||
currentCheck = currentCheck + (currentCheck ? '/' : '') + value |
||||
if (!await fs.exists(currentCheck)) { |
||||
await fs.mkdir(currentCheck) |
||||
} |
||||
} |
||||
} |
||||
|
||||
saveAs = (blob, name) => { |
||||
const node = document.createElement('a') |
||||
node.download = name |
||||
node.rel = 'noopener' |
||||
node.href = URL.createObjectURL(blob) |
||||
setTimeout(function () { URL.revokeObjectURL(node.href) }, 4E4) // 40s
|
||||
setTimeout(function () { |
||||
try { |
||||
node.dispatchEvent(new MouseEvent('click')) |
||||
} catch (e) { |
||||
const evt = document.createEvent('MouseEvents') |
||||
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, |
||||
20, false, false, false, false, 0, null) |
||||
node.dispatchEvent(evt) |
||||
} |
||||
}, 0) // 40s
|
||||
} |
||||
} |
||||
|
||||
|
||||
/* eslint-disable no-template-curly-in-string */ |
||||
const testData = { |
||||
'.workspaces': { |
||||
children: { |
||||
'.workspaces/default_workspace': { |
||||
children: { |
||||
'.workspaces/default_workspace/README.txt': { |
||||
content: 'TEST README' |
||||
} |
||||
} |
||||
}, |
||||
'.workspaces/emptyspace': { |
||||
|
||||
}, |
||||
'.workspaces/workspace_test': { |
||||
children: { |
||||
'.workspaces/workspace_test/TEST_README.txt': { |
||||
content: 'TEST README' |
||||
}, |
||||
'.workspaces/workspace_test/test_contracts': { |
||||
children: { |
||||
'.workspaces/workspace_test/test_contracts/1_Storage.sol': { |
||||
content: 'testing' |
||||
}, |
||||
'.workspaces/workspace_test/test_contracts/artifacts': { |
||||
children: { |
||||
'.workspaces/workspace_test/test_contracts/artifacts/Storage_metadata.json': { |
||||
content: '{ "test": "data" }' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,45 +1,29 @@ |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React from 'react' |
||||
import React, { useState } from 'react' |
||||
import { render } from 'react-dom' |
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { RemixApp } from '@remix-ui/app' |
||||
import * as packageJson from '../../../package.json' |
||||
import './index.css' |
||||
import { ThemeModule } from './app/tabs/theme-module' |
||||
import { Preload } from './app/components/preload' |
||||
import Config from './config' |
||||
import Registry from './app/state/registry' |
||||
import { Storage } from '@remix-project/remix-lib' |
||||
|
||||
(async function () { |
||||
|
||||
// load app config
|
||||
const configStorage = new Storage('config-v0.8:') |
||||
const config = new Config(configStorage) |
||||
Registry.getInstance().put({ api: config, name: 'config' }) |
||||
const theme = new ThemeModule() |
||||
theme.initTheme() |
||||
|
||||
(function () { |
||||
render( |
||||
<React.StrictMode> |
||||
<div style={{ display: 'block' }} className='centered'> |
||||
<svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100"> |
||||
<path d="M91.84,35a.09.09,0,0,1-.1-.07,41,41,0,0,0-79.48,0,.09.09,0,0,1-.1.07C9.45,35,1,35.35,1,42.53c0,8.56,1,16,6,20.32,2.16,1.85,5.81,2.3,9.27,2.22a44.4,44.4,0,0,0,6.45-.68.09.09,0,0,0,.06-.15A34.81,34.81,0,0,1,17,45c0-.1,0-.21,0-.31a35,35,0,0,1,70,0c0,.1,0,.21,0,.31a34.81,34.81,0,0,1-5.78,19.24.09.09,0,0,0,.06.15,44.4,44.4,0,0,0,6.45.68c3.46.08,7.11-.37,9.27-2.22,5-4.27,6-11.76,6-20.32C103,35.35,94.55,35,91.84,35Z"/> |
||||
<path d="M52,74,25.4,65.13a.1.1,0,0,0-.1.17L51.93,91.93a.1.1,0,0,0,.14,0L78.7,65.3a.1.1,0,0,0-.1-.17L52,74A.06.06,0,0,1,52,74Z"/> |
||||
<path d="M75.68,46.9,82,45a.09.09,0,0,0,.08-.09,29.91,29.91,0,0,0-.87-6.94.11.11,0,0,0-.09-.08l-6.43-.58a.1.1,0,0,1-.06-.18l4.78-4.18a.13.13,0,0,0,0-.12,30.19,30.19,0,0,0-3.65-6.07.09.09,0,0,0-.11,0l-5.91,2a.1.1,0,0,1-.12-.14L72.19,23a.11.11,0,0,0,0-.12,29.86,29.86,0,0,0-5.84-4.13.09.09,0,0,0-.11,0l-4.47,4.13a.1.1,0,0,1-.17-.07l.09-6a.1.1,0,0,0-.07-.1,30.54,30.54,0,0,0-7-1.47.1.1,0,0,0-.1.07l-2.38,5.54a.1.1,0,0,1-.18,0l-2.37-5.54a.11.11,0,0,0-.11-.06,30,30,0,0,0-7,1.48.12.12,0,0,0-.07.1l.08,6.05a.09.09,0,0,1-.16.07L37.8,18.76a.11.11,0,0,0-.12,0,29.75,29.75,0,0,0-5.83,4.13.11.11,0,0,0,0,.12l2.59,5.6a.11.11,0,0,1-.13.14l-5.9-2a.11.11,0,0,0-.12,0,30.23,30.23,0,0,0-3.62,6.08.11.11,0,0,0,0,.12l4.79,4.19a.1.1,0,0,1-.06.17L23,37.91a.1.1,0,0,0-.09.07A29.9,29.9,0,0,0,22,44.92a.1.1,0,0,0,.07.1L28.4,47a.1.1,0,0,1,0,.18l-5.84,3.26a.16.16,0,0,0,0,.11,30.17,30.17,0,0,0,2.1,6.76c.32.71.67,1.4,1,2.08a.1.1,0,0,0,.06,0L52,68.16H52l26.34-8.78a.1.1,0,0,0,.06-.05,30.48,30.48,0,0,0,3.11-8.88.1.1,0,0,0-.05-.11l-5.83-3.26A.1.1,0,0,1,75.68,46.9Z"/> |
||||
</svg> |
||||
<div className="info-secondary splash"> |
||||
REMIX IDE |
||||
<br /> |
||||
<span className='version'> v{ packageJson.version }</span> |
||||
</div> |
||||
<div style={{ marginTop: '50%', textAlign: 'center' }}> |
||||
<i className="fas fa-spinner fa-spin fa-2x"></i> |
||||
</div> |
||||
</div> |
||||
<Preload></Preload> |
||||
</React.StrictMode>, |
||||
document.getElementById('root') |
||||
) |
||||
|
||||
})() |
||||
|
||||
import ('./app').then((AppComponent) => { |
||||
const appComponent = new AppComponent.default() |
||||
appComponent.run().then(() => { |
||||
render( |
||||
<> |
||||
<RemixApp app={appComponent} /> |
||||
</>, |
||||
document.getElementById('root') |
||||
) |
||||
}) |
||||
}).catch(err => { |
||||
console.log('Error on loading Remix:', err) |
||||
}) |
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue