/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import type { VisualInkLineOrCommand } from '@a-morphous/frontispiece-ink-processor/src/types' import { Fragment } from 'preact' import { useEffect, useRef, useState } from 'preact/hooks' import { html, useInkHookState } from '../bootstrap/bootstrap' import { useLayoutState } from '../state/layout-state' import { advanceMaximally } from '../utils/advance-maximally' import { LineViewer } from './line-viewer' // TODO: implement a version where it doesn't necessarily advance line by line export const InkStoryView = () => { const [showLog, setShowLog] = useState(false) const inkState = useInkHookState() const layoutState = useLayoutState() const ref = useRef<HTMLElement>() const advanceFunction = () => { if (layoutState.oneline.get()) { inkState.advance() // only hide older lines if we're in `oneline` mode if (layoutState.maxVisibleLines.get() > 0) { inkState.hideOlderLines(layoutState.maxVisibleLines.get()) } } else { advanceMaximally(inkState) } if (layoutState.scrollAfterAdvance.get()) { setTimeout(() => { document.querySelector('#story .active').scrollIntoView({ block: 'start', behavior: 'smooth', }) }, 10) } } const lines = inkState.getVisibleLines({ showHidden: showLog, showCommands: false, }) useEffect(() => { if (inkState.getCanAdvance()) { advanceFunction() } }, []) const renderStory = () => { const activeSection = inkState.getActiveSection() return html`<div id="story"> ${lines.map((line) => { let isActive = false // hackety hack hack if (layoutState.oneline.get()) { if (line === inkState.getActiveLine()) { isActive = true } } else { if (activeSection.lines.indexOf(line as VisualInkLineOrCommand) >= 0) { isActive = true } } return html`<${LineViewer} line=${line} isActive=${isActive} />` })} </div>` } const renderAdvanceButton = () => { if (inkState.getCanAdvance()) { return html`<button id="continue-button" onclick=${() => { advanceFunction() }} > Continue </button>` } return null } const renderChoices = () => { if (inkState.getCanAdvance()) { return null } return html`<div id="choices"> ${inkState.getChoices().map((choice) => { return html`<button class="choice" onclick=${() => { if (layoutState.clearAfterChoice.get()) { inkState.hideAllVisible() } inkState.makeChoice(choice.index) if (layoutState.oneline.get()) { advanceFunction() } else { inkState.advance() advanceFunction() } }} > ${choice.text} </button>` })} </div>` } const renderLogButton = () => { const logButtonText = showLog ? 'Hide Log' : 'Show Log' return html`<button onclick=${() => { setShowLog(!showLog) }} > ${logButtonText} </button>` } return html`<${Fragment}> <div id="story-view">${renderStory()} ${renderAdvanceButton()} ${renderChoices()}</div> <div ref=${ref} id="scroll-pointer"></div> <//>` }