Update help #34
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
gtfs.zone/coloring-book#34
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The current Help tab is cluttered with emojis, brightly-colored alert boxes, and inaccurate content (wrong shortcuts, non-existent tabs). This plan removes the Help tab entirely, replaces it with a
?icon button in the navbar that opens a dismissable, scrollable modal combining an "about this app" section with accurate, runtime-generated content. The modal is themed, emoji-free, and low-maintenance — external links are kept to a minimum (GTFS spec reference and TransitLand, both already used in the app).Tradeoff: The keyboard shortcut list is generated at runtime from
KeyboardShortcuts.getShortcutsList(), so it always stays accurate without needing manual updates. The changelog is a link to the repo rather than embedded content, avoiding build-time complexity and keeping the modal short.Relevant Context
src/index.html— Lines 523–779: the Help tab radio input + content div to remove. Navbarnavbar-enddiv (lines 63–305) is where the?button goes, alongside existing icon-only ghost buttons (undo/redo, theme toggle).src/modules/modal-utils.ts—showModal()currently takes{ title, body: string (HTML), actions, onMount? }. No dismissable/Escape/scroll support. No closing mechanism besides action buttons.src/modules/about-modal.ts— Does not exist yet. Will build the HTML body and callshowModal.src/modules/keyboard-shortcuts.ts—showHelp()(line 290) currently tries to click[data-tab="help"], which doesn't actually work with the radio tab system.ctrl+5shortcut (line 178) switches to help tab.getShortcutsList()(line 344) returnsArray<{ key: string; description: string }>— the source of truth for accurate shortcut display.src/index.ts—this.keyboardShortcuts = new KeyboardShortcuts(this)(line 81). Post-init wiring happens ininit().__APP_VERSION__is available as a global const (declared line 33).max-h-[80vh] flex flex-colonmodal-box, make the body divflex-1 overflow-y-auto, keep title and action bar outside the scroll region.Phase 1: Extend
modal-utils.tsfor dismissable + scrollable modalsThe generic modal utility needs two new capabilities before the about modal can use it: (1) an optional Escape-to-close behavior with an X button, and (2) a scrollable body region so tall content doesn't overflow the viewport.
dismissable?: booleanto theshowModaloptions interfacedismissable: true, inject an X button into the modal header:<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>— clicking it closes the modal and resolves the promisekeydownlistener ondocumentforEscapewhen the modal is open; on Escape, close and resolve (same cleanup path as X button). Remove the listener when the modal closes.modal-boxclass tomodal-box max-h-[80vh] flex flex-col(always, not just when dismissable — overflow can't hurt non-scrolling modals)<div class="py-4">to<div class="flex-1 overflow-y-auto py-4">so it scrolls independently of the title/actionsrelativeto themodal-boxso the absolute X button positions correctlyGotcha: The Escape listener must be removed on close regardless of how the modal is dismissed (X button, Escape key, or an action button). Use a shared
close()helper insideshowModalthat handles both DOM removal and listener cleanup.Phase 2: Create
src/modules/about-modal.tsA standalone module that assembles the modal HTML and calls
showModal. Acceptsversion: stringandshortcuts: Array<{ key: string; description: string }>so it has no dependency on theKeyboardShortcutsclass itself.Create
src/modules/about-modal.tsexportingfunction showAboutModal(version: string, shortcuts: Array<{ key: string; description: string }>): Promise<void>Build the modal body HTML with the following sections (no emojis, no colored alert boxes — use
dividerortext-sm font-semibold opacity-60headings between sections):About
Version & Source
<code class="font-mono">${version}</code>https://git.kcfam.us/gtfs.zone/coloring-bookhttps://git.kcfam.us/gtfs.zone/coloring-book/raw/branch/main/CHANGELOG.mdKeyboard Shortcuts
shortcutsas a<table class="table table-xs w-full">with columns Key / Action<kbd class="kbd kbd-xs">per token split on+, joined with+Resources
https://gtfs.org/reference/— "Official file format and field reference"https://www.transit.land/— "Real-world GTFS feeds (used by the Load → From TransitLand Atlas feature)"target="_blank" rel="noopener noreferrer"Call
showModal({ title: 'edit.gtfs.zone', body: html, actions: [{ label: 'Close' }], dismissable: true })Phase 3: HTML, keyboard shortcuts, and wiring
Remove the Help tab from the right panel, add the
?button to the navbar, and wire F1 to the new modal.src/index.html<input ... id="help-tab-radio" ...>) and its associated<div class="tab-content ...">block (lines 523–779)?button tonavbar-end, after the theme toggle swap label and before the undo/redo group:src/modules/keyboard-shortcuts.tsctrl+5shortcut block (lines 178–184) — there is no Help tab to switch tosetShowHelpHandler(fn: () => void): voidmethod that storesfnin a private fieldprivate showHelpHandler?: () => voidshowHelp()to callthis.showHelpHandler?.()instead of the broken tab-click codesrc/index.tsImport
showAboutModalfrom./modules/about-modalAfter
this.keyboardShortcuts.initialize(), call:Unrelated cleanup: added
dismissable: trueto Reset Database, New Stop, Failed to load feed, and Load from URL modals. Left Database Error and Database update required blocking (no Cancel path — forcing action is intentional).Original Issue