SOURCE / PINNED RELEASE
Made of little things.
Body Journal
- Release
- e8049f8da4e2…
- Author-recorded commit
- 61c04bf0e8aa…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6c4554844c7
Archive hash verified: 4369d778da046a8b…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { caseExamples, exampleSession } from './examples.js';
import { escape as esc, summary } from './case.js';
import { groupSummary } from './group-controls.js';
import type { SessionRecord } from './session-record.js';
export class ExampleControls {
constructor(private ui: { modal: (html: string) => void; populated: () => boolean; load: (record: SessionRecord) => void; reset: () => void }) { document.addEventListener('click', this.click); }
private open(): void {
this.ui.modal(`<span class="section-caption">FICTIONAL CASE LIBRARY</span><h2>What a detailed case can look like.</h2><p class="muted">These templates demonstrate how to describe observations, uncertainty and background. They are not diagnostic examples or recommendations. Preview before loading; no AI request is sent.</p><div class="example-list">${caseExamples.map(e => `<button class="example-card" data-example-preview="${e.id}"><strong>${esc(e.title)}</strong><span>${esc(e.description)}</span><small>${e.observations.length} observations · ${e.groups.length} group · Preview →</small></button>`).join('')}</div>`);
}
private preview(id: string): void {
const e = caseExamples.find(e => e.id === id); if (!e) return;
const r = exampleSession(id), p = r.draft.profile;
this.ui.modal(`<span class="section-caption">SYNTHETIC EXAMPLE · NOT A REAL PATIENT</span><h2>${esc(e.title)}</h2><p class="muted">${esc(e.learning)}</p><div class="example-preview"><h3>About this fictional person</h3><p>${esc(p.age)} years · ${esc(p.sex)} · ${p.height} cm · ${p.weight} kg</p>${Object.entries({ 'Health background': p.conditions, 'Medications': p.medications, 'Allergies': p.allergies, 'Smoking': p.smoking, 'Pregnancy context': p.pregnancy, 'Recent changes': p.recentChanges }).map(([label, value]) => `<p><strong>${label}:</strong> ${esc(value)}</p>`).join('')}<h3>Observations</h3>${r.draft.concerns.map(c => `<section><h4>${c.id}. ${esc(c.location)}</h4><p>${esc(summary(c))}</p></section>`).join('')}${groupSummary(r.draft.groups, r.draft.concerns)}<p class="field-hint">Locations are named in text. You can paint the areas on the body and add your own photos while exploring. No patient photos or diagnostic reports are supplied.</p></div><div class="dialog-actions"><button class="outline-button" data-example-list>All examples</button><button class="primary-button" data-example-load="${e.id}">Load this example</button></div>`);
}
private click = (event: Event): void => {
const el = (event.target as Element).closest<HTMLElement>('button'); if (!el) return;
if (el.id === 'examplesButton' || el.hasAttribute('data-example-list')) this.open();
if (el.dataset.examplePreview) this.preview(el.dataset.examplePreview);
if (el.dataset.exampleLoad) {
const id = el.dataset.exampleLoad;
if (this.ui.populated()) this.ui.modal(`<h2>Replace the current case with this example?</h2><p>This replaces your current observations, profile, photos and report, including the saved case. Your AI connections are kept.</p><div class="dialog-actions"><button class="outline-button" data-example-cancel>Keep my case</button><button class="primary-button" data-example-confirm="${esc(id)}">Replace with example</button></div>`);
else this.load(id);
}
if (el.dataset.exampleConfirm) this.load(el.dataset.exampleConfirm);
if (el.id === 'startOwnCase') this.ui.modal('<h2>Start your own case?</h2><p>This clears the fictional example and any edits or photos you added to it. Your AI connections are kept.</p><div class="dialog-actions"><button class="outline-button" data-example-cancel>Keep exploring</button><button class="primary-button" id="confirmOwnCase">Start a blank case</button></div>');
if (el.hasAttribute('data-example-cancel')) document.querySelector<HTMLDialogElement>('#modal')?.close();
if (el.id === 'confirmOwnCase') { this.ui.reset(); document.querySelector<HTMLDialogElement>('#modal')?.close(); }
};
private load(id: string): void { this.ui.load(exampleSession(id)); document.querySelector<HTMLDialogElement>('#modal')?.close(); }
dispose(): void { document.removeEventListener('click', this.click); }
}
