Tick a guide's sections off as you work through it
Only checklist items could be ticked, which answers "what have I done" but not the question a long procedure actually raises: where was I. Somebody looks away to do the thing the guide asked for and looks back at a wall of text. Every step and every heading now carries a checkbox while reading. Ticking one strikes it through and fades it rather than hiding it, because somebody scanning back up the page has to still be able to read what they did. The number is struck through with it, but the step's own "Step 3" label is not - that is the address of the thing, not part of what was done. Headings count, not just steps. A guide converted from an HTML article often has fifty headings and no steps at all, and those are exactly the guides long enough to lose your place in. That also means the card's "N steps to tick" stops reading as a broken feature on a guide that is entirely tickable. Reading only, as the checklists already were: in the editor a tick would be an edit, and an author clicking around their own draft would quietly change what the next reader sees as done. Progress stays per browser and per version - shopfloor PCs share a login, so one technician's ticks must not greet the next person on that bay, and step 4 of version 3 is not step 4 of version 2.
This commit is contained in:
@@ -2,14 +2,36 @@
|
||||
<div class="gb-blocks" :class="{ 'gb-interactive': interactive }">
|
||||
<template v-for="(block, index) in blocks" :key="block.id || index">
|
||||
|
||||
<!--
|
||||
A heading and a step can be ticked off while reading, not just a
|
||||
checklist item. On a long procedure the question is not "what have I
|
||||
done" so much as "where was I" - somebody looks away to do the thing
|
||||
the guide asked for, and looks back at a wall of text. A struck-through
|
||||
section is where they were.
|
||||
|
||||
Reading only: in the editor a tick would be an edit.
|
||||
-->
|
||||
<h2 v-if="block.type === 'heading'" :id="anchorFor(block)" class="gb-heading"
|
||||
v-html="inline(block.text)"></h2>
|
||||
:class="{ 'gb-sectiondone': isTicked(block.id) }">
|
||||
<input v-if="interactive" type="checkbox" class="gb-sectiontick"
|
||||
:checked="isTicked(block.id)"
|
||||
:aria-label="'Mark this section done'"
|
||||
@change="toggle(block.id, $event.target.checked)">
|
||||
<span v-html="inline(block.text)"></span>
|
||||
</h2>
|
||||
|
||||
<p v-else-if="block.type === 'paragraph'" class="gb-para"
|
||||
v-html="inline(block.text)"></p>
|
||||
|
||||
<div v-else-if="block.type === 'step'" class="gb-step">
|
||||
<span class="gb-stepnum">Step {{ stepNumber(index) }}</span>
|
||||
<div v-else-if="block.type === 'step'" class="gb-step"
|
||||
:class="{ 'gb-sectiondone': isTicked(block.id) }">
|
||||
<label class="gb-stepnum">
|
||||
<input v-if="interactive" type="checkbox" class="gb-sectiontick"
|
||||
:checked="isTicked(block.id)"
|
||||
:aria-label="'Mark step ' + stepNumber(index) + ' done'"
|
||||
@change="toggle(block.id, $event.target.checked)">
|
||||
Step {{ stepNumber(index) }}
|
||||
</label>
|
||||
<h3 v-if="block.title" v-html="inline(block.title)"></h3>
|
||||
<div v-if="block.text" v-html="inline(block.text)"></div>
|
||||
</div>
|
||||
@@ -193,6 +215,20 @@ function select (block) {
|
||||
dark mode work with no dark-mode code. */
|
||||
.gb-blocks { line-height: 1.65; }
|
||||
.gb-heading { margin: 1.6rem 0 0.6rem; font-size: 1.35rem; color: var(--text); }
|
||||
|
||||
/* A ticked section is struck through and faded, not hidden: somebody scanning
|
||||
back up the page has to be able to read what they already did. */
|
||||
.gb-sectiondone { text-decoration: line-through; opacity: 0.55; }
|
||||
.gb-sectiondone .gb-stepnum { text-decoration: none; }
|
||||
.gb-sectiontick {
|
||||
/* Touch-sized: a guide is read on a shopfloor PC, often with gloves on. */
|
||||
width: 1.1rem;
|
||||
height: 1.1rem;
|
||||
margin-right: 0.5rem;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
.gb-heading .gb-sectiontick { text-decoration: none; }
|
||||
.gb-para { margin: 0 0 0.9rem; color: var(--text); }
|
||||
|
||||
.gb-step {
|
||||
|
||||
@@ -122,10 +122,14 @@ function resetProgress () {
|
||||
saveProgress()
|
||||
}
|
||||
|
||||
// Everything that can be ticked: checklist items, and the sections a reader
|
||||
// crosses off to keep their place - a step, or a heading on a guide that has
|
||||
// no steps at all (a converted article often has fifty headings and none).
|
||||
const totalChecks = computed(() => {
|
||||
let total = 0
|
||||
for (const block of guide.value?.blocks || []) {
|
||||
if (block.type === 'checklist') total += (block.items || []).length
|
||||
else if (block.type === 'step' || block.type === 'heading') total += 1
|
||||
}
|
||||
return total
|
||||
})
|
||||
|
||||
@@ -124,11 +124,21 @@ def plaintext(blocks):
|
||||
|
||||
|
||||
def checklistitemcount(blocks):
|
||||
"""How many tickable items a guide has, for the list and the progress bar."""
|
||||
"""How many tickable things a guide has, for the card and the progress bar.
|
||||
|
||||
Checklist items, plus the sections a reader crosses off to keep their place:
|
||||
a step, or a heading. A guide converted from an article often has fifty
|
||||
headings and no steps at all, and "0 steps to tick" on a card that is
|
||||
entirely tickable reads as a broken feature.
|
||||
"""
|
||||
total = 0
|
||||
for block in blocks or []:
|
||||
if isinstance(block, dict) and block.get('type') == 'checklist':
|
||||
if not isinstance(block, dict):
|
||||
continue
|
||||
if block.get('type') == 'checklist':
|
||||
total += len(block.get('items') or [])
|
||||
elif block.get('type') in ('step', 'heading'):
|
||||
total += 1
|
||||
return total
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user