import { FormButton, LinkButton } from './Button'; import { createContext, Fragment } from 'preact'; import { usePopup } from './usePopup'; import { useCallback, useContext } from 'preact/hooks'; import { ExportFormat, exportFormatToString } from '../rolltable'; import { GeneratedElement, type GeneratedElementProps, reconstituteGeneratedElement, } from './GeneratedElement'; import { IncludesResponses } from './ResponsesPage'; import { tableIdentifier } from './TableHeader'; export const IncludesGenerator = createContext(false) export interface GeneratorProps { generatorTargetUrl: string elements: GeneratedElementProps[] addToDiscordUrl: string|null editable: boolean } export enum GeneratorSelect { All = "all", None = "none", } export enum GeneratorReroll { All = "all", Selected = "selected", } export function reconstituteGenerator(element: HTMLDivElement, partial?: Partial): GeneratorProps { const addToDiscordUrl = partial?.addToDiscordUrl ?? element.querySelector("#addToDiscord")?.href ?? null const editable = partial?.editable ?? !!element.querySelector("#rollButtons") const elements = partial?.elements ?? Array.from(element.querySelector("#generatedScenario")!.children) .map(li => reconstituteGeneratedElement(li as HTMLLIElement, editable ? {} : {selected: null})) const generatorTargetUrl = partial?.generatorTargetUrl ?? element.querySelector("#generatorWindow")!.action return { addToDiscordUrl, editable, generatorTargetUrl, elements: elements, } } export interface GeneratorEvents { onCopy?: (format: ExportFormat) => Promise onReroll?: (which: GeneratorReroll) => Promise onSelect?: (which: GeneratorSelect) => void onSelectionChange?: (tableId: number, selected: boolean) => void } enum GeneratorSelectionState { All = "All", Partial = "Some", None = "None" } export function GeneratorPage({ editable, generatorTargetUrl, addToDiscordUrl, onSelectionChange, onSelect, onReroll, onCopy, elements }: GeneratorProps & GeneratorEvents) { const includesResponses = useContext(IncludesResponses); const [copyPopupHost, showCopyPopup] = usePopup() const [rerollPopupHost, showRerollPopup] = usePopup() const copyWrapper = useCallback((format: ExportFormat) => { if (!onCopy) { console.error("No copy handler") return showCopyPopup(`Failed to copy ${exportFormatToString(format)} to clipboard`, 'error') } onCopy(format).then(() => { return showCopyPopup(`Copied ${exportFormatToString(format)} to clipboard`) }).catch((ex: unknown) => { console.error(ex) return showCopyPopup(`Failed to copy ${exportFormatToString(format)} to clipboard`, 'error') }).catch((ex: unknown) => { console.error(ex) }) }, [showCopyPopup, onCopy]) const md = useCallback(() => copyWrapper(ExportFormat.Markdown), [copyWrapper]) const bb = useCallback(() => copyWrapper(ExportFormat.BBCode), [copyWrapper]) const emoji = useCallback(() => copyWrapper(ExportFormat.TextEmoji), [copyWrapper]) const text = useCallback(() => copyWrapper(ExportFormat.TextOnly), [copyWrapper]) const selected = elements.reduce((current, next) => { if (next.selected === null) { return current } switch (current) { case GeneratorSelectionState.Partial: return GeneratorSelectionState.Partial case GeneratorSelectionState.None: return next.selected ? GeneratorSelectionState.Partial : GeneratorSelectionState.None case GeneratorSelectionState.All: return next.selected ? GeneratorSelectionState.All : GeneratorSelectionState.Partial case null: return next.selected ? GeneratorSelectionState.All : GeneratorSelectionState.None } }, null) const selectAll = useCallback((ev: Event) => { if (!onSelect || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) { return } onSelect(GeneratorSelect.All) }, [onSelect, showRerollPopup]) const selectNone = useCallback((ev: Event) => { if (!onSelect || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) { return } onSelect(GeneratorSelect.None) }, [onSelect, showRerollPopup]) const rerollSelected = useCallback((ev: Event) => { if (!onReroll || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) { return } onReroll(GeneratorReroll.Selected).then(() => {}).catch((ex: unknown) => { console.error(ex) return showRerollPopup(`Failed to reroll`, 'error') }).catch((ex: unknown) => { console.error(ex) }) }, [onReroll, showRerollPopup]) const rerollAll = useCallback((ev: Event) => { if (!onReroll || (ev.currentTarget instanceof HTMLButtonElement && ev.currentTarget.disabled)) { return } onReroll(GeneratorReroll.All).then(() => {}).catch((ex: unknown) => { console.error(ex) return showRerollPopup(`Failed to reroll all`, 'error') }).catch((ex: unknown) => { console.error(ex) }) }, [onReroll, showRerollPopup]) return

Your generated scenario

    {elements.map(i => )}
Markdown BBCode Text + Emoji Text Only
{editable ?
Reroll {selected === GeneratorSelectionState.All ? 'All' : 'Selected'} Select All Select None
: null}
{editable ? New Scenario Get Scenario Link : Open in Generator }
{ addToDiscordUrl || includesResponses ? : null}
}