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.
103 lines
3.4 KiB
103 lines
3.4 KiB
import {
|
|
reconstituteTable,
|
|
TableEmoji,
|
|
TableHeaderDataset,
|
|
tableIdentifier,
|
|
type TableProps,
|
|
TableTitle
|
|
} from './TableHeader';
|
|
import {
|
|
GeneratedResult,
|
|
type GeneratedResultProps, type GeneratedResultPropsFull,
|
|
type PartialGeneratedResultProps, type PartialGeneratedResultPropsFull,
|
|
reconstituteGeneratedResult
|
|
} from './GeneratedResult';
|
|
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
|
|
import { pulseElement } from './pulseElement';
|
|
|
|
export type GeneratedElementPropsBase = {
|
|
table: TableProps
|
|
selected: boolean|null
|
|
} & GeneratedResultProps
|
|
|
|
export type GeneratedElementEditableProps = GeneratedElementPropsBase & { selected: boolean } & GeneratedResultPropsFull
|
|
export type GeneratedElementReadonlyProps = GeneratedElementPropsBase & { selected: null } & GeneratedResultProps
|
|
|
|
export type GeneratedElementProps = GeneratedElementEditableProps|GeneratedElementReadonlyProps
|
|
|
|
export type PartialGeneratedElementProps = PartialGeneratedElementEditableProps|PartialGeneratedElementReadonlyProps
|
|
|
|
export type PartialGeneratedElementEditableProps = {
|
|
table?: Partial<TableProps>
|
|
selected?: boolean
|
|
} & PartialGeneratedResultPropsFull
|
|
|
|
export type PartialGeneratedElementReadonlyProps = {
|
|
table?: Partial<TableProps>
|
|
selected?: null
|
|
} & PartialGeneratedResultProps
|
|
|
|
export function reconstituteGeneratedElement(element: HTMLLIElement, partial?: PartialGeneratedElementProps): GeneratedElementProps {
|
|
const result = reconstituteGeneratedResult(element.querySelector(".generatedResult")!, partial)
|
|
const selected = typeof partial?.selected !== 'undefined'
|
|
? partial.selected
|
|
: (element.querySelector<HTMLInputElement>('.generatedSelect')?.checked) ?? null
|
|
const table = reconstituteTable(element.querySelector(".tableHeader")!, partial?.table)
|
|
if (result.set) {
|
|
return {
|
|
...result,
|
|
table,
|
|
selected,
|
|
}
|
|
} else {
|
|
return {
|
|
...result,
|
|
table,
|
|
selected: null,
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface GeneratedElementEvents {
|
|
onSelectionChange?: (tableId: number, selected: boolean) => void
|
|
}
|
|
|
|
export function GeneratedElement({ onSelectionChange, ...props }: GeneratedElementProps & GeneratedElementEvents) {
|
|
const ref = useRef<HTMLInputElement>(null);
|
|
const selected = props.selected
|
|
const [lastSelected, setLastSelected] = useState(selected)
|
|
const tableId = tableIdentifier(props.table)
|
|
const checkId = `selected-${tableId}`
|
|
const changeCallback = useCallback((ev: Event) => {
|
|
if (onSelectionChange && typeof props.table.id === "number") {
|
|
onSelectionChange(props.table.id, (ev.currentTarget as HTMLInputElement).checked)
|
|
}
|
|
}, [onSelectionChange])
|
|
useEffect(() => {
|
|
if (selected !== lastSelected) {
|
|
setLastSelected(selected)
|
|
if (ref.current) {
|
|
pulseElement(ref.current)
|
|
}
|
|
}
|
|
}, [ref, selected, lastSelected, setLastSelected])
|
|
return <li class="generatedElement" id={`generated-${tableIdentifier(props.table)}`}>
|
|
<h2 class="generatedHead">
|
|
<label
|
|
class="generatedLabel tableHeader"
|
|
{...(props.selected !== null ? {"for": checkId} : {})}
|
|
{...TableHeaderDataset(props.table)}>
|
|
<TableEmoji {...props.table} />
|
|
{' '}
|
|
<TableTitle {...props.table} />
|
|
</label>
|
|
<input type="checkbox" class={`generatedSelect${props.selected === null ? " unselectable" : ""}`}
|
|
id={checkId}
|
|
name={checkId}
|
|
checked={props.selected ?? false}
|
|
onChange={changeCallback}
|
|
ref={ref} />
|
|
</h2>
|
|
<GeneratedResult {...props} />
|
|
</li>
|
|
}
|
|
|