Add status component

This commit is contained in:
He4eT 2021-03-02 19:29:42 +05:00
commit f02ec6925f
7 changed files with 66 additions and 21 deletions

View file

@ -10,10 +10,10 @@
<body> <body>
<div id="root"> <div id="root">
<div class="app"> <div class="app play">
<main> <main>
<div class="status"> <div class="status loading">
Loading... <div>Loading</div>
</div> </div>
</main> </main>
</div> </div>

View file

@ -9,12 +9,13 @@ import CheapGlkOte from 'cheap-glkote'
import TextBuffer from './TextBuffer' import TextBuffer from './TextBuffer'
import InputBox from './InputBox' import InputBox from './InputBox'
import Status from './Status'
import './player.css' import './player.css'
const INITIAL_STATUS = { const INITIAL_STATUS = {
stage: 'loading', stage: 'loading',
details: 'Preparing...' details: ['Preparing']
} }
const runMachine = ({ Engine, file, handlers }) => { const runMachine = ({ Engine, file, handlers }) => {
@ -104,7 +105,7 @@ export default function ({ vmParts: { file, engine } }) {
}, [vm]) }, [vm])
return status.stage !== 'ready' return status.stage !== 'ready'
? (<div>{status.details}</div>) ? (<Status {...status} />)
: ( : (
<section className='ifplayer'> <section className='ifplayer'>
<TextBuffer {...{ <TextBuffer {...{

View file

@ -0,0 +1,23 @@
import { h } from 'preact'
const INITIAL_STATUS = {
stage: 'loading',
details: 'Loading...'
}
const fail = details => (
<div class="status fail">
<h1>Error</h1>
{details.map(x => (<p>{x}</p>))}
<hr />
</div>
)
const loading = details => (
<div class="status loading">
{details.map(x => (<div>{x}</div>))}
</div>
)
export default ({ stage, details }) =>
({fail, loading})[stage](details)

View file

@ -4,33 +4,34 @@ import { useState, useEffect } from 'preact/hooks'
import { engineByFilename } from './common/engines' import { engineByFilename } from './common/engines'
import Player from './Player' import Player from './Player'
import Status from './Status'
const INITIAL_STATUS = { const INITIAL_STATUS = {
stage: 'loading', stage: 'loading',
details: 'Loading...' details: ['Loading']
} }
const prepareVM = ({ url, setStatus, setParts }) => { const prepareVM = ({ url, setStatus, setParts }) => {
const st = (stage, details) => args => { const st = (stage, details) => args => {
setStatus({ stage, details }) setStatus({ stage, details: [details] })
return args return args
} }
return Promise.resolve() return Promise.resolve()
.then(st('loading', 'Downloading file...')) .then(st('loading', 'Downloading file'))
.then(_ => fetch(url)) .then(_ => fetch(url))
.then(st('loading', 'Processing file...')) .then(st('loading', 'Processing file'))
.then(response => response.arrayBuffer()) .then(response => response.arrayBuffer())
.then(arrayBuffer => new Uint8Array(arrayBuffer)) .then(arrayBuffer => new Uint8Array(arrayBuffer))
.then(st('loading', 'Downloading engine...')) .then(st('loading', 'Downloading engine'))
.then(file => setParts({ .then(file => setParts({
file, file,
engine: engineByFilename(url) engine: engineByFilename(url)
})) }))
.then(st('loading', 'Running...')) .then(st('loading', 'Running'))
.catch(e => { .catch(e => {
console.error(e) console.error(e)
setStatus({ stage: 'fail', details: e.message }) setStatus({ stage: 'fail', details: [e.message, url] })
}) })
} }
@ -47,5 +48,5 @@ export default function ({ url }) {
return vmParts return vmParts
? (<Player vmParts={vmParts} />) ? (<Player vmParts={vmParts} />)
: (<div>{status.details}</div>) : (<Status {...status} />)
} }

View file

@ -33,6 +33,6 @@ export const engineByFilename = filename => {
if (format) { if (format) {
return format.engine return format.engine
} else { } else {
throw new Error(`Unsupported file type: ${filename}`) throw new Error('Unsupported file type')
} }
} }

View file

@ -9,7 +9,7 @@
padding: var(--outer-padding); padding: var(--outer-padding);
} }
.inputBox { .ifplayer .inputBox {
flex: 0 1 auto; flex: 0 1 auto;
font: inherit; font: inherit;
@ -22,7 +22,7 @@
margin-top: var(--input-box-margin); margin-top: var(--input-box-margin);
} }
.textBuffer { .ifplayer .textBuffer {
flex: 2 1 auto; flex: 2 1 auto;
overflow-y: scroll; overflow-y: scroll;
box-sizing: border-box; box-sizing: border-box;
@ -34,19 +34,35 @@
scrollbar-width: thin; scrollbar-width: thin;
} }
.textBuffer::-webkit-scrollbar { .ifplayer .textBuffer::-webkit-scrollbar {
width: 8px; width: 8px;
} }
.textBuffer::-webkit-scrollbar-thumb { .ifplayer .textBuffer::-webkit-scrollbar-thumb {
background-color: var(--main-color); background-color: var(--main-color);
border: 4px solid var(--bg-color); border: 4px solid var(--bg-color);
border-left-width: 0px; border-left-width: 0px;
} }
.textBuffer > br:first-child, .ifplayer .textBuffer > br:first-child,
.textBuffer > br:last-child, .ifplayer .textBuffer > br:last-child,
.textBuffer > br + br + br { .ifplayer .textBuffer > br + br + br {
display: none; display: none;
} }
.status {
padding: var(--inner-padding);
}
.status.loading > div:after {
animation: dots0123 1s infinite;
content: '';
}
@keyframes dots0123 {
0% { content: ''; }
33% { content: '.'; }
66% { content: '..'; }
100% { content: '...'; }
}

View file

@ -67,3 +67,7 @@ summary:hover {
ul { ul {
list-style: square; list-style: square;
} }
.status {
padding: 8px;
}