Files
shd.build/src/lib/components/MechanicLanguageHelp.svelte
T

90 lines
5.8 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
import PseudoScript from './PseudoScript.svelte';
let {
fullReferenceHref = '/isac/mechanic-reference',
buttonLabel = 'SCRIPT REFERENCE'
}: {
fullReferenceHref?: string;
buttonLabel?: string;
} = $props();
let dialog: HTMLDialogElement;
const example = [
'WHEN weapon_hit',
'IF same_target_hits >= 9 WITHIN 3s',
'ADD 1 STACK TO relentless',
'MAX 10 STACKS',
'REFRESH 10s ON STACK',
'APPLY weapon_damage += 3% PER STACK'
];
</script>
<button type="button" class="script-help-trigger" onclick={() => dialog.showModal()}>
<span aria-hidden="true">?</span>{buttonLabel}
</button>
<dialog bind:this={dialog} aria-labelledby="mechanic-language-help-title">
<div class="dialog-shell">
<header>
<div>
<p>ISAC SCRIPT LANGUAGE</p>
<h2 id="mechanic-language-help-title">How calculation scripts work</h2>
</div>
<button class="close" type="button" aria-label="Close script reference" onclick={() => dialog.close()}>×</button>
</header>
<div class="help-content">
<p>ISAC generates these scripts from structured controls. You review the script, while typed data remains the calculation source.</p>
<dl>
<div><dt>WHEN</dt><dd>The event that begins a mechanic branch.</dd></div>
<div><dt>IF</dt><dd>Conditions checked against the event, Agent, target, team, or encounter.</dd></div>
<div><dt>TRACK</dt><dd>A count, duration, scalar, mark, or stack pool shared by branches.</dd></div>
<div><dt>ADD / SET / CONSUME</dt><dd>How a matching branch changes tracked state.</dd></div>
<div><dt>FOR EVENT TARGET</dt><dd>Binds a target-scoped state change to the enemy named by the event.</dd></div>
<div><dt>APPLY</dt><dd>The Attribute or direct result and the phase when it takes effect.</dd></div>
<div><dt>UNTIL</dt><dd>The expiry, reset, or transfer policy for tracked state.</dd></div>
<div><dt>EVERY</dt><dd>An explicit periodic interval. ISAC does not infer a missing cadence.</dd></div>
<div><dt>PHASE</dt><dd>Whether an outcome runs before state changes, after them, while state remains active, or when state expires.</dd></div>
</dl>
<PseudoScript title="MECHANIC EXAMPLE" lines={example} compact />
<section class="calculation-language">
<h3>Combat calculation statements</h3>
<p><code>TAKE</code>, <code>ADD</code>, <code>APPLY</code>, <code>WEIGHT</code>, and <code>RETURN</code> explain the ordered deterministic damage pipeline.</p>
</section>
</div>
<footer>
<a class="secondary" href={fullReferenceHref} onclick={() => dialog.close()}>OPEN FULL REFERENCE →</a>
<button class="primary" type="button" onclick={() => dialog.close()}>RETURN TO EDITOR</button>
</footer>
</div>
</dialog>
<style>
.script-help-trigger{display:inline-flex;align-items:center;gap:7px;min-height:40px;padding:0 10px;border:1px solid var(--shd-border);background:transparent;color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.8px;cursor:pointer;transition:var(--shd-transition)}
.script-help-trigger>span{display:grid;place-items:center;width:18px;height:18px;border:1px solid currentColor;border-radius:50%;font-size:11px}
.script-help-trigger:hover,.script-help-trigger:focus-visible{border-color:var(--shd-orange);color:var(--shd-orange)}
.script-help-trigger:active{transform:translateY(1px);filter:brightness(.88)}
.script-help-trigger:focus-visible,.close:focus-visible{outline:2px solid var(--shd-focus-ring);outline-offset:2px}
dialog{width:min(780px,calc(100vw - 24px));max-height:calc(100vh - 24px);padding:0;border:1px solid var(--shd-border-strong);background:var(--shd-surface);color:var(--shd-text);box-shadow:10px 12px 34px rgb(0 0 0 / .48)}
dialog::backdrop{background:rgb(0 0 0 / .76)}
.dialog-shell{display:grid;max-height:calc(100vh - 26px)}
.dialog-shell>header{display:flex;align-items:start;justify-content:space-between;gap:var(--shd-gap-md);padding:var(--shd-gap-md);border-bottom:1px solid var(--shd-border);background:var(--shd-surface-raised)}
header p{margin:0 0 3px;color:var(--shd-orange);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:1.1px}
h2{margin:0;font-size:var(--shd-type-body);text-transform:uppercase}
.close{display:grid;place-items:center;width:40px;height:40px;border:1px solid var(--shd-border);background:transparent;color:var(--shd-text);font-size:24px;cursor:pointer}
.close:hover{border-color:var(--shd-orange);color:var(--shd-orange)}
.help-content{display:grid;gap:var(--shd-gap-md);padding:var(--shd-gap-md);overflow:auto}
.help-content>p,.calculation-language p{margin:0;color:var(--shd-text-muted);line-height:1.5}
dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;margin:0;background:var(--shd-border)}
dl>div{display:grid;grid-template-columns:100px 1fr;gap:8px;padding:9px;background:var(--shd-surface-raised)}
dt{color:var(--shd-success);font-family:var(--shd-font-mono);font-size:var(--shd-type-supporting);font-weight:900}
dd{margin:0;color:var(--shd-text-muted);font-size:var(--shd-type-supporting);line-height:1.4}
.calculation-language{padding:10px;border:1px solid var(--shd-border)}
.calculation-language h3{margin:0 0 5px;font-size:var(--shd-type-body);text-transform:uppercase}
.calculation-language code{color:var(--shd-success);font-family:var(--shd-font-mono);font-weight:900}
footer{display:flex;justify-content:flex-end;gap:var(--shd-gap-sm);padding:var(--shd-gap-md);border-top:1px solid var(--shd-border);background:var(--shd-surface-raised)}
footer a,footer button{display:inline-flex;align-items:center;justify-content:center;min-height:40px;padding:0 14px}
@media(max-width:620px){.script-help-trigger{min-height:44px}dl{grid-template-columns:1fr}footer{display:grid}footer a,footer button{width:100%;min-height:44px}}
@media(prefers-reduced-motion:reduce){.script-help-trigger{transition:none}}
</style>