All files / src/ui tutorialOffer.ts

100% Statements 29/29
93.75% Branches 15/16
100% Functions 2/2
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49                        2x 2x           2x 90x 90x 90x     2x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 3x 3x 3x 3x 3x 3x 3x 3x 3x  
/**
 * The guided tutorial's offer (ยง30): the buttons *About* and the landing page
 * both draw, so the two say the same thing about the same place kept.
 *
 * One invited answer at a time, filled: *play* for a reader who has not begun,
 * *resume* for one who has, *play again* for one who finished. Starting over
 * is offered beside a resume, quietly, rather than as a second filled button,
 * since a reader who left half way is far more often coming back than starting
 * again.
 */
 
import type { TourProgress } from '../state/tour'
import { el } from './dom'
import { icon } from './icons'
 
/** Where the tutorial is played from. */
export type TutorialStart = 'start' | 'resume'
 
/** What the filled button says, from what was kept. */
export function tutorialLabel(progress: TourProgress | null): string {
  if (progress !== null && !progress.finished) return `resume at step ${progress.index + 1} of ${progress.total}`
  return progress?.finished === true ? 'play the tutorial again' : 'play the tutorial'
}
 
/** The filled button, and *start over* beside it while there is a place to resume from. */
export function tutorialButtons(
  progress: TourProgress | null,
  play: (from: TutorialStart) => void,
  options: { class?: string } = {},
): HTMLElement[] {
  const resumable = progress !== null && !progress.finished
  const invited = el(
    'button',
    { class: `btn btn-primary${options.class === undefined ? '' : ` ${options.class}`}`, type: 'button' },
    icon('play', { size: 12 }),
    el('span', { text: tutorialLabel(progress) }),
  )
  invited.addEventListener('click', () => play(resumable ? 'resume' : 'start'))
  if (!resumable) return [invited]
  const over = el('button', {
    class: 'btn btn-quiet',
    type: 'button',
    text: 'start over',
    title: 'Begin again at the first step, in a tab of its own',
  })
  over.addEventListener('click', () => play('start'))
  return [invited, over]
}