Download src/app.js from abhid1234/branchjam: direct link, hf CLI and curl.
- Browser
- Download file 5.13 kB
-
https://huggingface.co/spaces/abhid1234/branchjam/resolve/main/src/app.js
- Command line
-
hf download hf://spaces/abhid1234/branchjam/src/app.js
-
curl -L -o app.js https://huggingface.co/spaces/abhid1234/branchjam/resolve/main/src/app.js
5.13 kB
| import { catalog, getArtifact, validateCatalog } from "./catalog.js"; | |
| import { | |
| createSession, selectConstraint, revealOutcomes, selectComparison, | |
| incrementVote, decrementVote, resolveVote, continueFromWinner, inspectNode | |
| } from "./domain.js"; | |
| import { createPersistence } from "./persistence.js"; | |
| import { mountSignalGarden } from "./artifact.js"; | |
| import { renderRound, renderHistory } from "./render.js"; | |
| import { focusControl } from "./focus.js"; | |
| const validation = validateCatalog(catalog); | |
| if (!validation.valid) throw new Error(`Catalog validation failed: ${validation.errors.join(" ")}`); | |
| const artifactView = document.querySelector("#artifact-view"); | |
| const roundView = document.querySelector("#round-view"); | |
| const historyView = document.querySelector("#history-view"); | |
| const polite = document.querySelector("#polite-status"); | |
| const assertive = document.querySelector("#assertive-status"); | |
| const storageSummary = document.querySelector("#storage-summary"); | |
| const resetSession = document.querySelector("#reset-session"); | |
| const resetConfirmation = document.querySelector("#reset-confirmation"); | |
| const cancelReset = document.querySelector("#cancel-reset"); | |
| const confirmReset = document.querySelector("#confirm-reset"); | |
| let browserStorage; | |
| try { | |
| browserStorage = window.localStorage; | |
| } catch { | |
| browserStorage = { | |
| getItem() { throw new Error("Storage unavailable"); }, | |
| setItem() { throw new Error("Storage unavailable"); }, | |
| removeItem() { throw new Error("Storage unavailable"); } | |
| }; | |
| } | |
| const persistence = createPersistence(browserStorage, catalog); | |
| const loaded = persistence.load(); | |
| let state = loaded.state ?? createSession(catalog); | |
| let runtime = null; | |
| if (loaded.notice) storageSummary.textContent = loaded.notice; | |
| if (loaded.recovered) announce(loaded.notice, true); | |
| function announce(message, urgent = false) { | |
| const region = urgent ? assertive : polite; | |
| region.textContent = ""; | |
| requestAnimationFrame(() => { region.textContent = message; }); | |
| } | |
| function focusAfterRender(selector) { | |
| requestAnimationFrame(() => document.querySelector(selector)?.focus()); | |
| } | |
| function focusedControlKey() { | |
| const key = document.activeElement?.dataset.focusKey; | |
| return typeof key === "string" ? key : null; | |
| } | |
| function restoreControlFocus(key, fallbackKey = null) { | |
| if (!key) return; | |
| requestAnimationFrame(() => focusControl(document, key, fallbackKey)); | |
| } | |
| function commit(next, message = "", preserveFocus = true, fallbackFocusKey = null) { | |
| const focusKey = preserveFocus ? focusedControlKey() : null; | |
| state = next; | |
| const result = persistence.save(state); | |
| storageSummary.textContent = result.notice; | |
| render(); | |
| restoreControlFocus(focusKey, fallbackFocusKey); | |
| if (message) announce(message); | |
| } | |
| function render() { | |
| runtime?.destroy(); | |
| runtime = mountSignalGarden(artifactView, getArtifact(catalog, state.nodesById[state.inspectedNodeId].artifactId)); | |
| renderRound(roundView, state, catalog, { | |
| selectConstraint: (id) => commit(selectConstraint(state, catalog, id)), | |
| reveal: () => { | |
| commit(revealOutcomes(state, catalog), "Two pre-authored outcomes are ready to compare.", false); | |
| focusAfterRender("#comparison-heading"); | |
| }, | |
| compare: (slot) => commit(selectComparison(state, slot), "", true, "artifact-heading"), | |
| vote: (slot, change) => { | |
| const next = change > 0 ? incrementVote(state, slot) : decrementVote(state, slot); | |
| const total = next.roundsById[next.currentRoundId].votes[slot]; | |
| const fallback = change < 0 && total === 0 ? `vote-${slot}-add` : null; | |
| commit(next, `Outcome ${slot.toUpperCase()} now has ${total} votes.`, true, fallback); | |
| }, | |
| resolve: () => { | |
| const next = resolveVote(state, catalog); | |
| commit(next, `Outcome ${next.roundsById[next.currentRoundId].winnerSlot.toUpperCase()} won the round.`, false); | |
| focusAfterRender("#result-heading"); | |
| }, | |
| continue: () => { | |
| const next = continueFromWinner(state, catalog); | |
| commit(next, next.phase === "complete" ? "This pre-authored branch is complete." : "", false); | |
| focusAfterRender("#round-heading"); | |
| } | |
| }); | |
| renderHistory(historyView, state, catalog, (nodeId) => commit(inspectNode(state, nodeId))); | |
| } | |
| function closeResetConfirmation({ restoreFocus = true } = {}) { | |
| resetConfirmation.hidden = true; | |
| resetSession.setAttribute("aria-expanded", "false"); | |
| if (restoreFocus) resetSession.focus(); | |
| } | |
| resetSession.addEventListener("click", () => { | |
| resetConfirmation.hidden = false; | |
| resetSession.setAttribute("aria-expanded", "true"); | |
| cancelReset.focus(); | |
| }); | |
| cancelReset.addEventListener("click", () => closeResetConfirmation()); | |
| resetConfirmation.addEventListener("keydown", (event) => { | |
| if (event.key !== "Escape") return; | |
| event.preventDefault(); | |
| closeResetConfirmation(); | |
| }); | |
| confirmReset.addEventListener("click", () => { | |
| closeResetConfirmation({ restoreFocus: false }); | |
| runtime?.destroy(); | |
| const result = persistence.reset(); | |
| state = result.state; | |
| storageSummary.textContent = result.notice; | |
| render(); | |
| focusAfterRender("#play-heading"); | |
| announce(result.notice); | |
| }); | |
| render(); | |