Scenario generator for vore roleplay and story ideas.
https://scenario-generator.deliciousreya.net/responses
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
3.2 KiB
93 lines
3.2 KiB
import { GeneratorPage, GeneratorSelect, IncludesGenerator } from './GeneratorPage';
|
|
import { PageFooter } from './PageFooter';
|
|
import type { GeneratedElementProps } from './GeneratedElement';
|
|
import { useCallback, useMemo, useState } from 'preact/hooks';
|
|
import { ExportFormat, exportScenario, RollSelections, type RollTable, type RollTableResult } from '../rolltable';
|
|
|
|
export interface GeneratorMainProps {
|
|
editable: boolean
|
|
|
|
generatorTargetUrl: string
|
|
addToDiscordUrl: string
|
|
creditsUrl: string
|
|
|
|
initialResults: ReadonlyMap<RollTable, RollTableResult>
|
|
initialSelected?: ReadonlySet<RollTable>
|
|
}
|
|
|
|
export interface GeneratorMainEvents {
|
|
copyText?: (text: string) => Promise<void>
|
|
}
|
|
|
|
// TODO: add a "reconstitute" function for MainGeneratorOnly
|
|
// TODO: add the other two top-level pages (MainResponsesOnly, MainGeneratorResponses) with "reconstitute" functions
|
|
// TODO: add the entry points that reconstitute and hydrate each of the respective top-level pages
|
|
|
|
function MainGeneratorOnly({
|
|
editable, generatorTargetUrl, addToDiscordUrl,
|
|
creditsUrl, initialResults, initialSelected, copyText}: GeneratorMainProps & GeneratorMainEvents) {
|
|
const [results, ] =
|
|
useState<ReadonlyMap<RollTable, RollTableResult>>(initialResults)
|
|
const [selected, setSelected] =
|
|
useState<ReadonlySet<RollTable>|null>(initialSelected ?? null)
|
|
const onCopy = useCallback(async (format: ExportFormat) => {
|
|
if (!copyText) {
|
|
return Promise.reject(Error("Copy functionality is not implemented"))
|
|
}
|
|
return copyText(exportScenario(Array.from(results.values()), format))
|
|
}, [copyText, results])
|
|
const onSelectionChange = useCallback((tableId: number, state: boolean) => {
|
|
const table = Array.from(initialResults.keys()).find(table => table.full && table.id === tableId)
|
|
if (!table) {
|
|
return
|
|
}
|
|
const newSelection = new RollSelections(selected)
|
|
if (state) {
|
|
newSelection.add(table)
|
|
} else {
|
|
newSelection.delete(table)
|
|
}
|
|
setSelected(newSelection)
|
|
}, [initialResults, selected, setSelected])
|
|
const onSelect = useCallback((select: GeneratorSelect) => {
|
|
switch (select) {
|
|
case GeneratorSelect.All:
|
|
setSelected(new RollSelections(initialResults.keys()));
|
|
break;
|
|
case GeneratorSelect.None:
|
|
setSelected(new RollSelections());
|
|
break;
|
|
}
|
|
}, [initialResults, setSelected])
|
|
const elements = useMemo(() => {
|
|
const output: GeneratedElementProps[] = []
|
|
for (const result of results.values()) {
|
|
if (result.full) {
|
|
output.push({
|
|
...result,
|
|
selected: selected === null ? null : selected.has(result.table)
|
|
})
|
|
} else {
|
|
output.push({
|
|
...result,
|
|
selected: null,
|
|
})
|
|
}
|
|
}
|
|
return output
|
|
}, [results, selected])
|
|
return <IncludesGenerator.Provider value={true}>
|
|
<GeneratorPage
|
|
generatorTargetUrl={generatorTargetUrl}
|
|
elements={elements}
|
|
addToDiscordUrl={addToDiscordUrl}
|
|
editable={editable}
|
|
onCopy={onCopy}
|
|
// TODO: implement onReroll using JSON fetch
|
|
// specifically: POST to the target URL as if you're submitting the form,
|
|
// _but_ add Accept: text/json to indicate you want it for API purposes and not as a page
|
|
onSelect={selected ? onSelect : undefined}
|
|
onSelectionChange={selected ? onSelectionChange : undefined} />
|
|
<PageFooter creditsUrl={creditsUrl} />
|
|
</IncludesGenerator.Provider>
|
|
}
|
|
|