diff --git a/src/components/player/InputBox.js b/src/components/player/InputBox.js new file mode 100644 index 0000000..f76cdf7 --- /dev/null +++ b/src/components/player/InputBox.js @@ -0,0 +1,8 @@ +import { h } from 'preact' +// import { useState, useEffect } from 'preact/hooks' + +export default function ({ currentWindow, inputType, sendMessage }) { + return ( +
InputBox
+ ) +} diff --git a/src/components/player/Player.js b/src/components/player/Player.js index a12c869..c5cc299 100644 --- a/src/components/player/Player.js +++ b/src/components/player/Player.js @@ -3,6 +3,14 @@ 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') @@ -16,30 +24,22 @@ const runMachine = ({ Engine, file, handlers }) => { } const Handlers = ({ + setStatus, setCurrentWindow, setInputType, setInbox }) => ({ - onInit: () => {}, + onInit: _ => setStatus({ stage: 'ready' }), + /* */ onUpdateWindows: windows => { setCurrentWindow(windows .filter(x => x.type === 'buffer') .slice(-1)[0]) }, onUpdateInputs: setInputType, - onUpdateContent: messagesByWindow => { - const inbox = - messagesByWindow - .reduce((acc, {id, text}) => { - acc[id] = text - .map(({content}) => content || [null]) - .reduce((xs, x) => [...xs, ...x], []) - return acc - }, {}) - console.log(JSON.stringify(inbox, null, 1)) - setInbox(inbox) - }, - onDisable: () => setInputType(null), + onUpdateContent: setInbox, + onDisable: _ => setInputType(null), + /* */ onFileNameRequest: (tosave, usage, _, setFileName) => { setFileName({ filename: 'filename', usage }) }, @@ -47,10 +47,13 @@ const Handlers = ({ return 'content' }, onFileWrite: (filename, content) => {}, - onExit: () => setInputType(null) + /* */ + 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([]) @@ -62,6 +65,7 @@ export default function ({ vmParts: { file, engine } }) { useEffect(() => { const handlers = Handlers({ + setStatus, setCurrentWindow, setInputType, setInbox @@ -86,9 +90,13 @@ export default function ({ vmParts: { file, engine } }) { window.send = x => sendMessage(x, currentWindow) }, [sendMessage, currentWindow]) - return ( -
- Player -
- ) + return status.stage !== 'ready' + ? (
{status.details}
) + : (
+ + +
) } diff --git a/src/components/player/TextBuffer.js b/src/components/player/TextBuffer.js new file mode 100644 index 0000000..cded3cf --- /dev/null +++ b/src/components/player/TextBuffer.js @@ -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 ( +
+ {messages?.map(({text}) => + (
{text}
))} +
+ ) +}