Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 92 additions & 84 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,49 +19,56 @@ <h1>Touchwright</h1>
</p>
</header>

<main id="main">
<section aria-labelledby="load-heading">
<h2 id="load-heading">Load your layout</h2>
<p>
Export your layout from the MoErgo Layout Editor and choose the file here. Nothing is
uploaded anywhere; the file is read in your browser.
</p>
<p>
<label class="field">
<span>Layout export (JSON)</span>
<input id="layout-file" type="file" accept="application/json,.json" />
</label>
</p>
<p id="layout-status" role="status" aria-live="polite"></p>
<div id="layout-error" role="alert" hidden></div>
</section>
<nav id="section-nav" class="section-nav" aria-label="Sections" hidden>
<ul>
<li><a href="#drill-section">Practise</a></li>
<li><a href="#sprint-section">Sprint</a></li>
<li><a href="#ladder-section">Ladder</a></li>
<li><a href="#stats-section">Statistics</a></li>
<li><a href="#progress-section">Saving</a></li>
</ul>
</nav>

<section id="summary" aria-labelledby="summary-heading" hidden>
<h2 id="summary-heading">What that layout looks like</h2>
<dl id="summary-list"></dl>
</section>

<!--
The diagram is decorative reinforcement and is marked aria-hidden, so
everything it shows is stated here in text as well: the highlighted key in
#board-next, the finger colours in #board-legend, and every cap's hand,
finger and row in #board-key-list.
-->
<section id="board-section" aria-labelledby="board-heading" hidden>
<h2 id="board-heading">Where those keys are</h2>
<p id="board-next"></p>
<div id="board-figure"></div>
<p id="board-legend-intro">
Each cap is outlined in the colour of the finger that owns it.
</p>
<ul id="board-legend" class="board-legend"></ul>
<details id="board-key-detail" class="board-key-detail">
<summary>Every key on the board, in words</summary>
<ul id="board-key-list" class="board-key-list"></ul>
</details>
</section>
<main id="main">
<div class="setup">
<section aria-labelledby="load-heading" class="setup-load">
<h2 id="load-heading">Load your layout</h2>
<p id="load-intro">
Export your layout from the MoErgo Layout Editor and choose the file here. Nothing is
uploaded anywhere; the file is read in your browser.
</p>
<p>
<label class="field">
<span>Layout export (JSON)</span>
<input id="layout-file" type="file" accept="application/json,.json" />
</label>
</p>
<p id="layout-status" role="status" aria-live="polite"></p>
<div id="layout-error" role="alert" hidden></div>
</section>

<section id="summary" aria-labelledby="summary-heading" hidden>
<h2 id="summary-heading">What that layout looks like</h2>
<dl id="summary-list"></dl>
</section>
</div>

<div class="workspace">
<section id="board-section" aria-labelledby="board-heading" hidden>
<h2 id="board-heading">Where those keys are</h2>
<p id="board-next"></p>
<div id="board-figure"></div>
<p id="board-legend-intro">
Each cap is outlined in the colour of the finger that owns it.
</p>
<ul id="board-legend" class="board-legend"></ul>
<details id="board-key-detail" class="board-key-detail">
<summary>Every key on the board, in words</summary>
<ul id="board-key-list" class="board-key-list"></ul>
</details>
</section>

<!--
<!--
The drill surface.

How to escape the keyboard capture is stated here in visible text, not in
Expand All @@ -70,20 +77,20 @@ <h2 id="board-heading">Where those keys are</h2>
row in words and is the primary channel; the board highlight above only
reinforces it.
-->
<section id="drill-section" aria-labelledby="drill-heading" hidden>
<h2 id="drill-heading">Practise</h2>
<p id="drill-how">
Choose <em>Start drill</em> and type what you see.
<strong>Press Escape at any time to give the keyboard back.</strong> The page then works
as usual, and <em>Resume drill</em> picks up exactly where you left off. Tab always moves
focus, even while the drill has the keyboard.
</p>
<p class="drill-controls">
<button id="drill-start" type="button" class="button button-solid">Start drill</button>
<button id="drill-reset" type="button" class="button button-outline">Start over</button>
</p>
<p id="drill-next" class="drill-next"></p>
<!--
<section id="drill-section" aria-labelledby="drill-heading" hidden>
<h2 id="drill-heading">Practise</h2>
<p id="drill-how">
Choose <em>Start drill</em> and type what you see.
<strong>Press Escape at any time to give the keyboard back.</strong> The page then works
as usual, and <em>Resume drill</em> picks up exactly where you left off. Tab always
moves focus, even while the drill has the keyboard.
</p>
<p class="drill-controls">
<button id="drill-start" type="button" class="button button-solid">Start drill</button>
<button id="drill-reset" type="button" class="button button-outline">Start over</button>
</p>
<p id="drill-next" class="drill-next"></p>
<!--
The sprint countdown.

It sits here, directly above the text, because that is where the eyes
Expand All @@ -94,36 +101,37 @@ <h2 id="drill-heading">Practise</h2>
would be unusable. The other channel is #sprint-warning below, a polite
region written only at a handful of milestones.
-->
<p id="sprint-countdown" class="sprint-countdown" role="timer" hidden></p>
<div
id="drill-surface"
class="drill-surface"
tabindex="0"
role="group"
aria-label="Drill text"
aria-describedby="drill-next drill-escape"
>
<p id="drill-text" class="drill-text"></p>
</div>
<p id="drill-escape" class="drill-hint">
Escape releases the keyboard from anywhere in the drill.
</p>
<p id="drill-capture" class="drill-hint" role="status" aria-live="polite"></p>
<p id="sprint-warning" class="drill-hint" role="status" aria-live="polite"></p>
<p id="drill-progress" class="drill-progress" role="status" aria-live="polite"></p>
<p id="drill-error" class="drill-error" role="alert" hidden></p>

<div id="drill-result" class="drill-result" hidden>
<h3>How that went</h3>
<p id="drill-result-summary" class="drill-result-summary" role="alert"></p>
<dl id="drill-result-detail"></dl>
<p id="drill-result-why"></p>
<p class="drill-controls">
<button id="drill-continue" type="button" class="button button-solid"></button>
<span class="drill-hint">Or press any key to start the next drill.</span>
<p id="sprint-countdown" class="sprint-countdown" role="timer" hidden></p>
<div
id="drill-surface"
class="drill-surface"
tabindex="0"
role="group"
aria-label="Drill text"
aria-describedby="drill-next drill-escape"
>
<p id="drill-text" class="drill-text"></p>
</div>
<p id="drill-escape" class="drill-hint">
Escape releases the keyboard from anywhere in the drill.
</p>
</div>
</section>
<p id="drill-capture" class="drill-hint" role="status" aria-live="polite"></p>
<p id="sprint-warning" class="drill-hint" role="status" aria-live="polite"></p>
<p id="drill-progress" class="drill-progress" role="status" aria-live="polite"></p>
<p id="drill-error" class="drill-error" role="alert" hidden></p>

<div id="drill-result" class="drill-result" hidden>
<h3>How that went</h3>
<p id="drill-result-summary" class="drill-result-summary" role="alert"></p>
<dl id="drill-result-detail"></dl>
<p id="drill-result-why"></p>
<p class="drill-controls">
<button id="drill-continue" type="button" class="button button-solid"></button>
<span class="drill-hint">Or press any key to start the next drill.</span>
</p>
</div>
</section>
</div>

<!--
Sprint mode.
Expand Down
6 changes: 5 additions & 1 deletion src/ui/drill-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,11 @@ export function createDrillView(options: DrillViewOptions): DrillView {
if (current.isFinished) {
if (!current.requestContinue(event.key).accepted) return;
event.preventDefault();
startDrill();
// Through onContinue, not straight to startDrill: the result card may be
// offering the next lesson or a repair drill, and a keyboard learner must
// get the same thing the button offers. Going direct silently threw the
// offer away and started this drill again.
onContinue();
return;
}

Expand Down
7 changes: 7 additions & 0 deletions src/ui/load-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ export function wireUp(root: ParentNode = document, options: WireUpOptions = {})
const legend = required('#board-legend', HTMLElement, root);
const keyList = required('#board-key-list', HTMLElement, root);
const drillSection = required('#drill-section', HTMLElement, root);
const sectionNav = required('#section-nav', HTMLElement, root);
const loadIntro = required('#load-intro', HTMLElement, root);
const sprintSection = required('#sprint-section', HTMLElement, root);
const ladderSection = required('#ladder-section', HTMLElement, root);
const statsSection = required('#stats-section', HTMLElement, root);
Expand Down Expand Up @@ -458,6 +460,11 @@ export function wireUp(root: ParentNode = document, options: WireUpOptions = {})
// The ladder comes before the drill: it decides which lesson the drill is
// for, and a drill with no lesson could not write its stars anywhere.
showProgress(keymap);
// There is somewhere to go now, and the instructions have been followed,
// so one appears and the other stands down. The file input stays: a
// learner may want to load a different layout.
sectionNav.hidden = false;
loadIntro.hidden = true;
status.textContent = `Loaded ${keymap.title}.`;
} catch (cause) {
// Surfaced, never swallowed: a parse failure is the user's problem to
Expand Down
Loading
Loading