// The confirmation dialog for copying a scenario's current content. // // The dialog shows exactly what the update changes, and collects any // `${Placeholder}` answers the adventure has no stored value for. An adventure // started before those were saved has none, and so does one whose author added // a placeholder since. The update overwrites plot text and scenario-derived // cards, so nothing happens until you press Update. import { useState } from 'react' import { createPortal } from 'react-dom' import { FIELD_LABELS, clip } from './format' function RefreshModal({ plan, onConfirm, onCancel }) { const [values, setValues] = useState( Object.fromEntries((plan.placeholders_needed || []).map((n) => [n, ''])), ) const [busy, setBusy] = useState(false) const { added = [], updated = [], removed = [] } = plan.cards || {} const world = plan.world_state || {} const fields = Object.entries(plan.fields || {}) const submit = (e) => { e.preventDefault() setBusy(true) onConfirm(values).finally(() => setBusy(false)) } // Portalled to : this modal is opened from inside .side-panel, whose // panel-in animation (fill mode `both`) makes it the containing block for // position:fixed children — an overlay rendered in place would be trapped in // the 420px panel and clipped by its overflow. Same trap for any future modal // opened from a drawer or panel. return createPortal(
e.stopPropagation()} onSubmit={submit}>

Update from scenario

{!plan.has_changes ? (

This adventure already matches “{plan.scenario_title}”. Nothing to update.

) : ( <>

Pull the current content of “{plan.scenario_title}” down over this adventure. Your story, its title, summary and your own story cards are untouched — but the plot text below is overwritten, including any edits you made here.

{fields.map(([field, diff]) => (
{FIELD_LABELS[field] || field}
− {clip(diff.old)}
+ {clip(diff.new)}
))} {added.length > 0 && (
Story cards added: {added.join(', ')}
)} {updated.length > 0 && (
Story cards overwritten: {updated.join(', ')}
)} {removed.length > 0 && (
Story cards removed: {removed.join(', ')}
)} {world.added?.length > 0 && (
New stats (at their starting value): {world.added.join(', ')}
)} {world.removed?.length > 0 && (
Stats removed: {world.removed.join(', ')}
)}
{(plan.placeholders_needed || []).length > 0 && ( <>

This scenario asks a few questions, and this adventure has no saved answers for them. They'll be remembered from now on.

{plan.placeholders_needed.map((name) => ( ))} )} )}
{plan.has_changes && ( )}
, document.body, ) } export { RefreshModal }