Rename components files to JSX

This commit is contained in:
He4eT 2021-02-25 22:31:06 +05:00
commit 884c53d6ae
8 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,15 @@
import { h } from 'preact'
export default function ({ setTargetName, setTargetUrl }) {
const fileInputHandler = ({ target }) => {
const file = target.files[0]
setTargetName(file.name)
setTargetUrl(`${URL.createObjectURL(file)}#${file.name}`)
target.value = null
}
return (
<input
type='file'
onChange={fileInputHandler} />)
}

View file

@ -0,0 +1,16 @@
import { h } from 'preact'
export default function ({ themeEngine }) {
const options = themeEngine.themes.map(theme => (
<option value={theme}>
{theme}
</option>))
return (
<select
value={themeEngine.currentTheme}
onChange={({ target }) =>
themeEngine.setTheme(target.value)}>
{options}
</select>)
}

View file

@ -0,0 +1,23 @@
import { h } from 'preact'
export default function ({ setTargetName, setTargetUrl }) {
const urlRE = /^(http|https):\/\/[^ "]+$/
const emit = url => {
setTargetName(url)
setTargetUrl(url)
}
const urlInputHandler = ({ target }) => {
const url = target.value
emit(urlRE.test(url)
? url
: null)
}
return (
<input
type='text'
placeholder='https://...'
onInput={urlInputHandler} />)
}

View file

@ -0,0 +1,63 @@
import { h } from 'preact'
// import { useState, useEffect } from 'preact/hooks'
/* eslint-disable */
const keyCodes = {
KEY_BACKSPACE: 8,
KEY_TAB: 9,
KEY_RETURN: 13,
KEY_ESC: 27,
KEY_PAGEUP: 33,
KEY_PAGEDOWN: 34,
KEY_END: 35,
KEY_HOME: 36,
KEY_LEFT: 37,
KEY_UP: 38,
KEY_RIGHT: 39,
KEY_DOWN: 40}
const keyNames = {
[keyCodes.KEY_BACKSPACE]: 'delete',
[keyCodes.KEY_TAB]: 'tab',
[keyCodes.KEY_RETURN]: 'return',
[keyCodes.KEY_ESC]: 'escape',
[keyCodes.KEY_PAGEUP]: 'pageup',
[keyCodes.KEY_PAGEDOWN]: 'pagedown',
[keyCodes.KEY_END]: 'end',
[keyCodes.KEY_HOME]: 'home',
[keyCodes.KEY_LEFT]: 'left',
[keyCodes.KEY_UP]: 'up',
[keyCodes.KEY_RIGHT]: 'right',
[keyCodes.KEY_DOWN]: 'down'}
/* eslint-enable */
export default function ({ currentWindow, inputType, sendMessage }) {
const charHandler = event => {
event.preventDefault()
const key =
keyNames[event.keyCode] ||
event.key
sendMessage(key, currentWindow)
}
const lineHandler = ({ keyCode, target: { value } }) => {
if (keyCode === keyCodes.KEY_RETURN) {
sendMessage(value, currentWindow)
}
}
const inputHandlers = {
'char': {
onKeyDown: charHandler
},
'line': {
onKeyPress: lineHandler
}
}
return (
<input {...inputHandlers[inputType]}
type="text"/>
)
}

View file

@ -0,0 +1,100 @@
import { h } from 'preact'
import { useState, useEffect } from 'preact/hooks'
import CheapGlkOte from 'cheap-glkote'
import TextBuffer from './TextBuffer'
import InputBox from './InputBox'
const INITIAL_STATUS = {
stage: 'loading',
details: 'Preparing...'
}
const runMachine = ({ Engine, file, handlers }) => {
console.log('runMachine')
const vm = new Engine()
const { glkInterface, sendFn } = CheapGlkOte(handlers)
vm.prepare(file, glkInterface)
vm.start()
return { sendFn, instance: vm }
}
const Handlers = ({
setStatus,
setCurrentWindow,
setInputType,
setInbox
}) => ({
onInit: _ => setStatus({ stage: 'ready' }),
/* */
onUpdateWindows: windows => {
setCurrentWindow(windows
.filter(x => x.type === 'buffer')
.slice(-1)[0])
},
onUpdateInputs: setInputType,
onUpdateContent: setInbox,
onDisable: _ => setInputType(null),
/* */
onFileNameRequest: (tosave, usage, _, setFileName) => {
setFileName({ filename: 'filename', usage })
},
onFileRead: filename => {
return 'content'
},
onFileWrite: (filename, content) => {},
/* */
onExit: _ => setInputType(null)
})
export default function ({ vmParts: { file, engine } }) {
const [status, setStatus] = useState(INITIAL_STATUS)
const [currentWindow, setCurrentWindow] = useState(null)
const [inputType, setInputType] = useState(null)
const [inbox, setInbox] = useState([])
const [vm, setVm] = useState(null)
const [sendMessage, setSendMessage] = useState(null)
useEffect(() => {
const handlers = Handlers({
setStatus,
setCurrentWindow,
setInputType,
setInbox
})
const vm = runMachine({
Engine: engine,
file,
handlers
})
setVm(vm)
}, [file, engine])
useEffect(() => {
setSendMessage(_ => vm
? vm.sendFn
: null)
}, [vm])
return status.stage !== 'ready'
? (<div>{status.details}</div>)
: (<section>
<TextBuffer {...{
inbox,
currentWindow
}}/>
<InputBox {...{
currentWindow,
inputType,
sendMessage
}}/>
</section>)
}

View file

@ -0,0 +1,55 @@
import { h } from 'preact'
import { useState, useEffect } from 'preact/hooks'
const parseInbox = (inbox, currentWindow) => {
const currentInbox =
inbox.find(({id}) =>
id === currentWindow.id)
if (!currentInbox) return {
clear: false,
incoming: []}
const {clear, text: inboxMessagesRaw} =
currentInbox
const incoming =
inboxMessagesRaw
/* Normalize. */
.map(({content}) =>
content || [{ style: 'emptyLine' }])
/* Flatten. */
.reduce((acc, x) =>
acc.concat(x), [])
/* Collapse empty lines. */
.reduce((acc, x, i, xs) => {
if (x.style !== 'emptyLine') return [...acc, x]
const prev = xs[i - 1] || {}
return prev.style === 'emptyLine'
? acc
: [...acc, x]
}, [])
return {clear, incoming}
}
export default function ({ inbox, currentWindow }) {
const [messages, setMessages] = useState([])
useEffect(() => {
const {incoming, clear} =
parseInbox(inbox, currentWindow)
setMessages(clear
? incoming
: messages.concat(incoming))
}, [inbox])
return (
<div>
{messages?.map(({text}) =>
(<div>{text}</div>))}
</div>
)
}

View file

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

51
src/views/HomeView.jsx Normal file
View file

@ -0,0 +1,51 @@
import { h } from 'preact'
import { useState } from 'preact/hooks'
import { Link } from 'wouter-preact'
import FileSelector from '~/src/components/FileSelector'
import URLSelector from '~/src/components/URLSelector'
import ThemeSelector from '~/src/components/ThemeSelector'
import { buildPlayLinkHref } from '~/src/utils/utils.routing'
const playButton = (name, url, theme) => (
<Link href={buildPlayLinkHref(url, theme)}>
Play "{name}"
</Link>)
export default function ({ themeEngine }) {
const [targetName, setTargetName] = useState(null)
const [targetUrl, setTargetUrl] = useState(null)
return (
<main>
<p>
You can browse some <Link href='/top100'>
games from IFDB
</Link> or play a game from a file.
</p>
<ul>
<li>
<ThemeSelector {...{
themeEngine
}} />
</li>
<li>
<FileSelector {...{
setTargetName,
setTargetUrl
}} />
</li>
<li>
<URLSelector {...{
setTargetName,
setTargetUrl
}} />
</li>
</ul>
{ targetUrl
? playButton(targetName, targetUrl, themeEngine.currentTheme)
: null }
</main>)
}